[
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@2.0.1/schema.json\",\n  \"changelog\": \"@changesets/cli/changelog\",\n  \"commit\": false,\n  \"fixed\": [[\"nextra\", \"nextra-theme-docs\", \"nextra-theme-blog\"]],\n  \"linked\": [],\n  \"access\": \"public\",\n  \"baseBranch\": \"main\",\n  \"updateInternalDependencies\": \"patch\",\n  \"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH\": {\n    \"onlyUpdatePeerDependentsWhenOutOfRange\": true\n  },\n  \"ignore\": [\n    \"@nextra/tsdoc\",\n    \"example-blog\",\n    \"example-docs\",\n    \"swr-site\",\n    \"docs\",\n    \"@nextra/prettier-config\",\n    \"@nextra/eslint-config\"\n  ]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "[*]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n- Demonstrating empathy and kindness toward other people\n- Being respectful of differing opinions, viewpoints, and experiences\n- Giving and gracefully accepting constructive feedback\n- Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n- Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n- The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n- Trolling, insulting or derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n- Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at g@shud.in. All\ncomplaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n---\n\n**Describe the bug** A clear and concise description of what the bug is.\n\n**To Reproduce** Steps to reproduce the behavior:\n\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior** A clear and concise description of what you expected to\nhappen.\n\n**Screenshots** If applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n\n- OS: [e.g. iOS]\n- Browser [e.g. chrome, safari]\n- Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n\n- Device: [e.g. iPhone6]\n- OS: [e.g. iOS8.1]\n- Browser [e.g. stock browser, safari]\n- Version [e.g. 22]\n\n**Additional context** Add any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n---\n\n**Is your feature request related to a problem? Please describe.** A clear and\nconcise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like** A clear and concise description of what you\nwant to happen.\n\n**Describe alternatives you've considered** A clear and concise description of\nany alternative solutions or features you've considered.\n\n**Additional context** Add any other context or screenshots about the feature\nrequest here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nThank you for contributing to this project! You must fill out the information below before we can\nreview this pull request. By explaining why you're making a change (or linking to an issue) and\nwhat changes you've made, we can triage your pull request to the best possible team for review.\n-->\n\n## Why:\n\nCloses:\n\n<!-- If there's an existing issue for your change, please link to it above. -->\n\n## What's being changed (if available, include any code snippets, screenshots, or gifs):\n\n<!-- Let us know what you are changing. Share anything that could provide the most context. -->\n\n## Check off the following:\n\n- [ ] I have reviewed my changes in staging, available via the **View\n      deployment** link in this PR's timeline (this link will be available after\n      opening the PR).\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Lint\n\non:\n  pull_request:\n    branches: [main, v4-v2]\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Cancel Previous Runs\n        uses: styfle/cancel-workflow-action@0.12.1\n        with:\n          access_token: ${{ github.token }}\n\n      - name: Check out code\n        uses: actions/checkout@v4\n\n      - name: Cache turbo build setup\n        uses: actions/cache@v4\n        with:\n          path: .turbo\n          key: ${{ runner.os }}-turbo-${{ github.sha }}\n          restore-keys: |\n            ${{ runner.os }}-turbo-\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v4\n\n      - name: Install Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version-file: .node-version\n          cache: pnpm\n\n      - name: Install Dependencies\n        run: pnpm i\n\n      - name: Lint Prettier\n        run: pnpm lint:prettier\n\n      - name: Lint ESLint\n        run: pnpm lint\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches: [main, v4-v2]\n\njobs:\n  release:\n    if: github.repository == 'shuding/nextra'\n\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Cancel Previous Runs\n        uses: styfle/cancel-workflow-action@0.12.1\n        with:\n          access_token: ${{ github.token }}\n\n      - name: Check out code\n        uses: actions/checkout@v4\n\n      - name: Cache turbo build setup\n        uses: actions/cache@v4\n        with:\n          path: .turbo\n          key: ${{ runner.os }}-turbo-${{ github.sha }}\n          restore-keys: |\n            ${{ runner.os }}-turbo-\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v4\n\n      - name: Install Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version-file: .node-version\n          cache: pnpm\n\n      - name: Install Dependencies\n        run: pnpm i\n\n      - name: Clean\n        run: pnpm clean\n\n      - name: Build\n        run: pnpm build\n\n      - name: Type Check\n        run: pnpm types:check\n\n      - name: Create Release Pull Request or Publish to npm\n        uses: changesets/action@v1\n        with:\n          publish: pnpm release\n          version: pnpm run version # should be `pnpm run`\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  pull_request:\n    branches: [main, v4-v2]\n\njobs:\n  test:\n    name: Test (${{matrix.os}})\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-latest]\n\n    steps:\n      - name: Cancel Previous Runs\n        uses: styfle/cancel-workflow-action@0.12.1\n        with:\n          access_token: ${{ github.token }}\n\n      - name: Check out code\n        uses: actions/checkout@v4\n\n      - name: Cache turbo build setup\n        uses: actions/cache@v4\n        with:\n          path: .turbo\n          key: ${{ runner.os }}-turbo-${{ github.sha }}\n          restore-keys: |\n            ${{ runner.os }}-turbo-\n\n      - name: Install pnpm\n        uses: pnpm/action-setup@v4\n\n      - name: Install Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version-file: .node-version\n          cache: pnpm\n\n      - run: pnpm i\n\n      - run: pnpm build:all\n\n      - run: pnpm test\n\n      - run: pnpm clean\n\n      - run: pnpm types:check\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.next/\n.tsup/\nnode_modules/\n*.log\ndist/\n.turbo/\nout/\n\n.vercel/\n.idea/\n.eslintcache\n.env\n\ntsup.config.bundled*\ntsconfig.tsbuildinfo\ntsconfig.vitest-temp.json\n\n_pagefind/\ndocs/public/sitemap.xml\nnext-env.d.ts\n"
  },
  {
    "path": ".node-version",
    "content": "22\n"
  },
  {
    "path": ".npmrc",
    "content": "strict-peer-dependencies=false\nshell-emulator=true\nenable-pre-post-scripts=true\n"
  },
  {
    "path": ".prettierignore",
    "content": "pnpm-lock.yaml\n.changeset/*.md\nCHANGELOG.md\ngenerated-page-map.ts\npackages/tsdoc/src/__tests__/snapshots\n\nexamples/swr-site/nextra-remote-filepaths/*.json\n\nexamples/docs/src/content/features/mdx.mdx\ndocs/app/docs/guide/ssg/page.mdx\ndocs/app/docs/guide/syntax-highlighting/page.mdx\n\n# contains mdx comments\ndocs/app/docs/blog-theme/start/page.mdx\ntypes.generated.ts\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Shu Ding\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.\n"
  },
  {
    "path": "README.md",
    "content": "# Nextra\n\nSimple, powerful and flexible site generation framework with everything you love\nfrom Next.js.\n\n## Documentation\n\nhttps://nextra.site\n\n## Development\n\n### Installation\n\nThe Nextra repository uses [PNPM Workspaces](https://pnpm.io/workspaces) and\n[Turborepo](https://github.com/vercel/turborepo).\n\n1. Run `corepack enable` to enable Corepack.\n\n   > If the command above fails, run `npm install -g corepack@latest` to install\n   > the latest version of\n   > [Corepack](https://github.com/nodejs/corepack?tab=readme-ov-file#manual-installs).\n\n2. Run `pnpm install` to install the project's dependencies.\n\n### Build `nextra`\n\n```bash\npnpm --filter nextra build\n```\n\nWatch mode: `pnpm --filter nextra dev`\n\n### Build `nextra-theme-docs`\n\n```bash\npnpm --filter nextra-theme-docs build\n```\n\n### Development\n\nYou can also debug them together with a website locally. For instance, to start\n`examples/docs` locally, run\n\n```bash\npnpm --filter example-docs dev\n```\n\nAny change to `example/docs` will be re-rendered instantly.\n\nIf you update the core or theme packages, a rebuild is required. Or you can use\nthe watch mode for both Nextra and the theme in separated terminals.\n\n## Sponsors\n\n<div>\n <a href=\"https://inkeep.com?utm_source=github&utm_campaign=nextra&utm_content=logolink\">\n   <img src=\"/docs/app/showcase/_logos/inkeep.png\" alt=\"Inkeep - AI Agents that get real work done\" width=\"256\">\n </a>\n <a href=\"https://xyflow.com?utm_source=github&utm_campaign=nextra&utm_content=logolink\">\n   <img src=\"/docs/app/showcase/_logos/xyflow.png\" alt=\"xyflow preview\" width=\"256\">\n </a>\n</div>\n"
  },
  {
    "path": "docs/app/_components/features/index.tsx",
    "content": "import { ArrowRightIcon } from '@components/icons'\nimport cn from 'clsx'\nimport Link from 'next/link'\nimport type { ComponentProps, FC, ReactNode } from 'react'\nimport { MotionDiv } from '../framer-motion'\nimport styles from './style.module.css'\n\nexport const Feature: FC<\n  {\n    large?: boolean\n    centered?: boolean\n    children: ReactNode\n    lightOnly?: boolean\n    href?: string\n    index: number\n  } & ComponentProps<typeof MotionDiv>\n> = ({\n  large,\n  centered,\n  children,\n  lightOnly,\n  className,\n  href,\n  index,\n  ...props\n}) => {\n  return (\n    <MotionDiv\n      initial={{ opacity: 0 }}\n      whileInView={{ opacity: 1 }}\n      viewport={{ once: true, margin: '-20px' }}\n      transition={{ duration: Math.min(0.25 + index * 0.2, 0.8) }}\n      className={cn(\n        styles.feature,\n        large && styles.large,\n        centered && styles.centered,\n        lightOnly && styles['light-only'],\n        className\n      )}\n      {...props}\n    >\n      {children}\n      {href && (\n        <Link\n          className={cn('x:focus-visible:nextra-focus', styles.link)}\n          href={href}\n          target=\"_blank\"\n          rel=\"noreferrer\"\n        >\n          <ArrowRightIcon height=\"24\" />\n        </Link>\n      )}\n    </MotionDiv>\n  )\n}\n\nexport const Features: FC<{ children: ReactNode }> = ({ children }) => {\n  return <div className={styles.features}>{children}</div>\n}\n"
  },
  {
    "path": "docs/app/_components/features/style.module.css",
    "content": ".feature {\n  position: relative;\n  padding: 1.5rem 1.75rem;\n  color: #000;\n  background-color: white;\n  overflow: hidden;\n  border-radius: 1.78em;\n}\n.feature.large {\n  grid-column: span 2;\n}\n.feature.centered {\n  text-align: center;\n}\n.feature h3 {\n  position: relative;\n  font-size: 34px;\n  font-size: min(34px, max(4vw, 24px));\n  font-weight: 600;\n  line-height: 1.25;\n  letter-spacing: -0.02rem;\n  z-index: 2;\n}\n:global(.dark) .feature:not(.light-only) {\n  color: #fff;\n  background-color: #202020;\n}\n.feature {\n  box-shadow:\n    0 8px 16px rgb(0 0 0 / 8%),\n    0 1px 2px rgb(0 0 0 / 4%),\n    0 0 0 1px rgb(0 0 0 / 3%);\n  transition: box-shadow 0.3s ease;\n}\n:global(.dark) .feature {\n  box-shadow: 0 0 0 1px rgb(82 82 82 / 60%);\n}\n.feature .link {\n  position: absolute;\n  right: 1em;\n  bottom: 1em;\n  z-index: 2;\n  width: 2.5em;\n  height: 2.5em;\n  background-color: rgb(0 0 0 / 39%);\n  backdrop-filter: blur(10px);\n  border-radius: 50%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  color: rgba(255, 255, 255, 0.9);\n  box-shadow:\n    0 0 0 2px rgb(154 154 154 / 56%),\n    0 0 30px rgb(0 0 0 / 10%);\n  transition: all 0.2s ease;\n  -webkit-user-drag: none;\n}\n@media (hover: hover) {\n  .feature .link {\n    opacity: 0;\n  }\n  .feature:hover .link {\n    opacity: 1;\n  }\n  .feature .link:hover,\n  .link:focus {\n    transform: scale(1.05);\n    color: rgba(255, 255, 255, 1);\n    background-color: rgba(64, 64, 64, 0.39);\n    box-shadow:\n      0 0 0 2px rgba(220, 220, 220, 0.56),\n      0 0 30px rgb(0 0 0 / 10%);\n  }\n  .feature .link:active {\n    transform: scale(1);\n    color: rgba(255, 255, 255, 0.8);\n    background-color: rgba(22, 22, 22, 0.39);\n    box-shadow:\n      0 0 0 2px rgba(178, 178, 178, 0.56),\n      0 0 30px rgb(0 0 0 / 10%);\n  }\n}\n\n.features {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  grid-gap: 2em;\n  font-feature-settings: initial;\n}\n\n.feature :global(.show-on-mobile) {\n  display: none;\n}\n\n@media screen and (max-width: 1024px) {\n  .feature {\n    max-width: 80vw;\n    width: 100%;\n  }\n  .feature.large {\n    grid-column: span 1;\n  }\n  .features {\n    grid-template-columns: 1fr;\n    grid-gap: 3em;\n    justify-items: center;\n  }\n  .feature h3 {\n    font-size: 28px;\n    font-size: min(28px, max(4vw, 22px));\n    text-align: center;\n  }\n}\n\n@media screen and (max-width: 640px) {\n  .feature {\n    max-width: 460px;\n    width: 100%;\n  }\n  .feature.large {\n    grid-column: span 1;\n  }\n  .features {\n    grid-template-columns: 1fr;\n    grid-gap: 3em;\n    justify-items: center;\n  }\n  .feature h3 {\n    font-size: 34px;\n    font-size: min(34px, max(4vw, 22px));\n    text-align: center;\n  }\n  .feature :global(.show-on-mobile) {\n    display: block;\n  }\n}\n"
  },
  {
    "path": "docs/app/_components/features/themes-animation.tsx",
    "content": "import type { FC } from 'react'\n\nexport const ThemesAnimation: FC = props => {\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      fill=\"none\"\n      viewBox=\"-50 0 268 250\"\n      {...props}\n    >\n      <circle\n        cx=\"83.4\"\n        cy=\"142.4\"\n        r=\"48.84\"\n        fill=\"#DDD\"\n        fillOpacity=\"0.2\"\n        stroke=\"#E6E6E6\"\n        strokeWidth=\"3\"\n      />\n      <path\n        fill=\"#000\"\n        d=\"M61.88 146.8v-7.13h.07l4.74 7.13h1.75v-10.67h-1.97v7.1h-.07l-4.73-7.1h-1.76v10.67h1.97zm12.14.15c2.22 0 3.3-1.32 3.5-2.65H75.6c-.17.67-.75 1.08-1.57 1.08-1.05 0-1.76-.8-1.76-2.06v-.22h5.31v-.82c0-2.38-1.4-3.92-3.65-3.92-2.18 0-3.67 1.44-3.67 3.87v.76c0 2.54 1.48 3.96 3.75 3.96zm-1.74-5.16v-.01c0-1.07.67-1.89 1.67-1.89 1 0 1.65.82 1.65 1.89v.01h-3.32zm11.7 5h2.32l-2.69-4.14 2.71-4.14h-2.27l-1.64 2.82h-.06l-1.64-2.82h-2.38l2.65 4.14-2.63 4.15h2.2l1.69-2.82h.05l1.7 2.82zm4.46-8.28h-1.21v1.6h1.17v4.35c0 1.7.68 2.39 2.74 2.39.42 0 .78-.04.94-.07v-1.53l-.44.02c-.85 0-1.2-.25-1.2-1.08v-4.09h1.6v-1.59h-1.6v-1.98h-2v1.98zm5.4 7.24c0 .67.55 1.22 1.22 1.22a1.22 1.22 0 000-2.43c-.67 0-1.22.55-1.22 1.21zm4.26-9.3c0 .65.53 1.08 1.17 1.08.64 0 1.16-.43 1.16-1.07 0-.65-.52-1.09-1.16-1.09-.64 0-1.17.44-1.17 1.09zm2.19 2.06h-2.05v8.44c0 .89-.34 1.25-1.07 1.25-.16 0-.35-.01-.47-.03v1.48c.15.02.57.06.86.06 1.64 0 2.73-.83 2.73-2.74v-8.46zm1.84 2.46c0 1.53 1.2 2.09 2.7 2.4 1.06.21 2.05.33 2.05 1.13 0 .54-.45 1-1.42 1-.88 0-1.41-.42-1.5-1.03h-1.99c0 1.48 1.24 2.48 3.38 2.48 2.19 0 3.53-1.01 3.53-2.71 0-1.53-1.12-2.06-2.64-2.33-.95-.17-2.14-.31-2.14-1.13 0-.61.51-.99 1.32-.99 1 0 1.33.58 1.39 1.1h1.82c0-1.54-1.2-2.53-3.18-2.53-1.74 0-3.32.77-3.32 2.61z\"\n      />\n      <path\n        fill=\"#888\"\n        d=\"M84.48 35.77h2.8v-.97h-2.8v-2.88h-.97v2.88h-2.78v.97h2.78v3.05h.97v-3.05z\"\n      />\n      <path\n        className=\"dash-ring\"\n        stroke=\"#E6E6E6\"\n        strokeDasharray=\"7 7\"\n        strokeLinecap=\"round\"\n        strokeWidth=\"3\"\n        d=\"M166 143a82 82 0 11-164 0 82 82 0 01164 0z\"\n      />\n      <path\n        fill=\"#fff\"\n        fillOpacity=\"0.82\"\n        d=\"M64.77 67v3h3v-3h-3zm0-6.24v-3h-3v3h3zm.05 0l2.5-1.66-.89-1.34h-1.6v3zM68.97 67l-2.5 1.66.9 1.34h1.6v-3zm1.53 0v3h3v-3h-3zm0-9.33h3v-3h-3v3zm-1.72 0v-3h-3v3h3zm0 6.2v3h3v-3h-3zm-.06 0l-2.5 1.67.9 1.34h1.6v-3zm-4.14-6.2l2.5-1.66-.9-1.34h-1.6v3zm-1.53 0v-3h-3v3h3zm0 9.33h-3v3h3v-3zm4.72 0v-6.24h-6V67h6zm-3-3.24h.05v-6h-.05v6zm-2.45-1.34l4.15 6.24 5-3.32-4.15-6.24-5 3.32zM68.97 70h1.53v-6h-1.53v6zm4.53-3v-9.33h-6V67h6zm-3-12.33h-1.72v6h1.72v-6zm-4.72 3v6.2h6v-6.2h-6zm3 3.2h-.06v6h.06v-6zm2.44 1.34l-4.14-6.2-5 3.32 4.14 6.2 5-3.32zm-6.64-7.54h-1.53v6h1.53v-6zm-4.53 3V67h6v-9.33h-6zm3 12.33h1.72v-6h-1.72v6zm15.68-5.19l2.96.44.51-3.44h-3.47v3zm-1.67 0v-3h-2.33l-.58 2.26 2.9.74zm-2.91-1.05v-3h-3v3h3zm4.64 0v3h3v-3h-3zm-4.64-1.14h-3v3h3v-3zm2.9 0v3h3v-3h-3zm-1.38 7.51c1.6 0 3.04-.49 4.16-1.46a5.6 5.6 0 001.86-3.42l-5.93-.87a.4.4 0 01.14-.24c.04-.04.07-.05.06-.04-.02 0-.1.03-.29.03v6zm3.06-8.32h-1.67v6h1.67v-6zm-4.58 2.26c.1-.38.35-.77.73-1.03.36-.25.67-.28.8-.28v6c1.8 0 3.73-1.03 4.28-3.2l-5.8-1.5zm1.53-1.31c.36 0 .82.16 1.16.55.3.35.3.65.3.65h-6c0 1.1.32 2.3 1.16 3.27a4.43 4.43 0 003.38 1.53v-6zm1.47 1.2v-.2h-6v.2h6zm-3 2.8h4.64v-6h-4.64v6zm7.64-3v-.71h-6v.71h6zm0-.71a6.6 6.6 0 00-1.65-4.54 6.08 6.08 0 00-4.54-1.9v6a.91.91 0 01.2.03l-.02-.01a.26.26 0 01-.05-.04c-.06-.08.06 0 .06.46h6zm-6.2-6.43c-1.62 0-3.25.55-4.47 1.8A6.45 6.45 0 0069.38 63h6c0-.22.04-.35.05-.4.02-.04.02-.03 0 0-.04.04-.06.05-.06.04.01 0 .08-.02.23-.02v-6zM69.4 63v.66h6V63h-6zm0 .66c0 1.7.5 3.39 1.74 4.66a6.22 6.22 0 004.54 1.81v-6a.89.89 0 01-.3-.04s.02 0 .06.05c.04.03.03.05.01 0a1.54 1.54 0 01-.06-.48h-6zm7.76-1.04v-.02h-6v.02h6zm0-.02c0 .15-.05.47-.33.8a1.7 1.7 0 01-1.21.56v-6c-2.94 0-4.46 2.48-4.46 4.64h6zm-1.54 1.36c-.44 0-.91-.2-1.23-.58a1.23 1.23 0 01-.33-.78h6c0-1.05-.32-2.2-1.1-3.12a4.34 4.34 0 00-3.34-1.52v6zm-1.56-1.36v.02h6v-.02h-6zm3-2.98h-2.9v6h2.9v-6zM84.67 67l-2.57 1.55.87 1.45h1.7v-3zm2.02 0v3h5.52l-3-4.63L86.69 67zm-2.35-3.63l-2.51-1.64-1.07 1.63L81.82 65l2.52-1.63zm2.37-3.62l2.51 1.64 3.04-4.64h-5.55v3zm-1.99 0v-3H83l-.87 1.49 2.6 1.5zM83.3 62.2v3H85l.87-1.49-2.6-1.5zm-.05 0l-2.6 1.51.87 1.5h1.73v-3zm-1.44-2.46l2.6-1.51-.87-1.5H81.8v3zm-2.08 0v-3h-5.48l2.95 4.61 2.53-1.61zm2.31 3.62l2.54 1.6 1.02-1.6-1.03-1.62-2.53 1.62zM79.73 67l-2.53-1.6-2.9 4.6h5.45v-3zm1.94 0v3h1.7l.87-1.46L81.67 67zm1.47-2.47v-3h-1.71L80.56 63l2.58 1.53zm.04 0L85.75 63l-.87-1.46h-1.7v3zM84.67 70h2.02v-6h-2.02v6zm4.54-4.63l-2.35-3.63L81.82 65l2.35 3.63 5.04-3.26zM86.85 65l2.37-3.62-5.02-3.29-2.37 3.63L86.85 65zm-.14-8.26h-1.99v6h2v-6zm-4.58 1.49l-1.44 2.47 5.19 3.01 1.43-2.46-5.18-3.02zm1.16.97h-.05v6h.05v-6zm2.54 1.5l-1.43-2.47-5.2 3.02 1.44 2.46 5.2-3.01zm-4.03-3.96h-2.08v6h2.08v-6zm-4.61 4.61L79.51 65l5.05-3.24-2.32-3.62-5.05 3.23zm2.31.4l-2.3 3.64 5.07 3.2 2.3-3.63-5.07-3.2zm.24 8.24h1.93v-6h-1.93v6zm4.5-1.46l1.47-2.47L80.56 63l-1.47 2.46 5.15 3.08zm-1.1-1h.04v-6h-.04v6zm-2.53-1.46l1.49 2.47 5.14-3.1L85.75 63l-5.14 3.09zm8.23-6.33v3h3v-3h-3zm-1.06 0v-3h-3v3h3zm0 1.4h-3v3h3v-3zm1.03 0h3v-3h-3v3zm3.22 5.83l.59 2.94 2.4-.48v-2.46h-3zm0-1.33h3v-3.26l-3.25.27.25 2.99zm-1.44-4.5v-3h-3v3h3zm1.41 0v3h3v-3h-3zm0-1.4h3v-3h-3v3zm-1.4 0h-3v3h3v-3zm0-1.74h3v-3h-3v3zm-1.76 0v-3h-3v3h3zm0-1.26h-1.06v6h1.06v-6zm-4.06 3v1.4h6v-1.4h-6zm3 4.4h1.03v-6h-1.03v6zm-1.97-3v3.8h6v-3.8h-6zm0 3.8c0 1.04.19 2.64 1.51 3.83a5.64 5.64 0 003.89 1.26v-6c-.3 0-.4-.03-.39-.02a1.59 1.59 0 01.97.98c.04.13.02.14.02-.05h-6zm5.4 5.1c.5 0 1.02-.05 1.4-.13l-1.17-5.88.06-.01h.01-.06l-.24.01v6zm3.82-3.07v-1.33h-6v1.33h6zm-3.25-4.32c.01 0 .01 0 0 0a1.5 1.5 0 01-.13 0v6c.22 0 .45 0 .63-.02l-.5-5.98zm-.13 0c-.06 0 .03 0 .21.04a2.37 2.37 0 011.64 1.53c.1.28.1.48.1.49h-6c0 .68.12 2.02 1.3 3.02 1.03.89 2.25.92 2.75.92v-6zm1.94 2.06v-3.58h-6v3.58h6zm-3-.58H92v-6h-1.4v6zm4.41-3v-1.4h-6v1.4h6zm-3-4.4h-1.4v6H92v-6zm1.6 3V58h-6v1.74h6zm-3-4.73h-1.76v6h1.75v-6zm-4.76 3v1.74h6V58h-6zm8 8.99h-3v3h3v-3zm1.85 0v3h3v-3h-3zm2.3-5.76l-.82 2.89 3.82 1.1v-3.99h-3zm0-1.55h3V57.2l-2.44-.46-.56 2.95zm-2.27 1.06v3h2.12l.7-2-2.82-1zm-.08 0h-3v3h3v-3zm0-1h3v-3h-3v3zm-1.8 0v-3h-3v3h3zm0 10.25h1.85v-6h-1.84v6zm4.85-3v-4.14h-6V67h6zm0-4.14c0-.13.03.26-.35.73a1.78 1.78 0 01-.96.58.64.64 0 01-.1.01v-6a4.5 4.5 0 00-3.54 1.55 4.81 4.81 0 00-1.05 3.13h6zm-1.41 1.32a2.67 2.67 0 01.16 0h-.03a1.59 1.59 0 01-.24-.05l1.64-5.77a5.91 5.91 0 00-1.53-.18v6zm3.7-2.94V59.7h-6v1.55h6zm-2.43-4.5c-.34-.07-.72-.1-1.13-.1v6h.05-.04l1.12-5.9zm-1.13-.1a4.74 4.74 0 00-4.53 3.1l5.66 2c-.1.29-.26.5-.44.64-.23.18-.5.26-.7.26v-6zm-1.7 1.1h-.08v6h.08v-6zm2.92 3v-1h-6v1h6zm-3-4h-1.8v6h1.8v-6zm-4.8 3V67h6v-7.25h-6zm12.5 6.38v-3h-1.79l-.85 1.58 2.64 1.42zm.08 0h3v-3h-3v3zm0 .88h-3v3h3v-3zm1.7 0v3h3v-3h-3zm-5.87-5.04l-3-.13-.13 3.13h3.13v-3zm1.69 0v3h2.76l.22-2.75-2.98-.25zm2.4.82v3h3v-3h-3zm0 1.08h3v-3h-3v3zm-1.97 6.25c2.04 0 3.74-.96 4.61-2.57l-5.28-2.84c.12-.22.29-.4.48-.5.2-.1.3-.1.2-.1v6zm1.97-1h.08v-6h-.08v6zm-2.92-3v.9h6v-.88h-6zm3 3.89h1.7v-6h-1.7v6zm4.7-3v-4.9h-6V67h6zm0-4.9a5.2 5.2 0 00-2.01-4.24 6.39 6.39 0 00-3.93-1.23v6c.19 0 .3.02.35.04.05.01 0 0-.09-.06a.93.93 0 01-.26-.34c-.07-.14-.06-.21-.06-.17h6zm-5.94-5.47a6.1 6.1 0 00-4.27 1.52 5.3 5.3 0 00-1.65 3.68l6 .27-.05.13a.9.9 0 01-.35.4l-.05.04s.11-.04.37-.04v-6zm-2.93 8.33h1.69v-6h-1.69v6zm4.67-2.75a2 2 0 01-.72 1.35c-.46.39-.9.43-1.06.43v-6a4.3 4.3 0 00-2.78.96 3.99 3.99 0 00-1.41 2.77l5.97.49zm-1.78 1.78a1.8 1.8 0 01-1.16-.52c-.55-.5-.64-1.1-.64-1.35h6c0-.98-.3-2.13-1.26-3.03a4.24 4.24 0 00-2.94-1.1v6zm-1.8-1.87v.66h6v-.66h-6zm3-2.34h-1.77v6h1.77v-6zm-1.77 0a5.9 5.9 0 00-3.87 1.29 4.95 4.95 0 00-1.7 3.85h6c0 .02 0 .13-.07.3a1.2 1.2 0 01-.33.43c-.27.23-.4.14-.02.14v-6zM96 64.9a5.1 5.1 0 001.65 3.84 5.51 5.51 0 003.73 1.36v-6c-.13 0 .05-.03.3.19.11.1.2.24.26.37.05.13.06.22.06.24h-6zm5.96-2.11c.2 0 .6.04 1 .36a2.1 2.1 0 01.83 1.63h-6c0 1.3.6 2.43 1.54 3.14.86.65 1.83.87 2.63.87v-6zm1.83 2c0 .46-.2 1.13-.78 1.61-.51.44-1 .45-1.04.45v-6c-.84 0-1.9.2-2.82.96a3.84 3.84 0 00-1.36 2.97h6zm-1.82 2.06h1.38v-6h-1.38v6zm-1.62-3v.76h6v-.76h-6zm0 .76c0-.6.29-1.13.7-1.46.35-.3.7-.36.91-.36v6c1.86 0 4.4-1.3 4.4-4.18h-6z\"\n      />\n      <path\n        fill=\"#000\"\n        d=\"M64.77 67v-6.24h.05L68.97 67h1.53v-9.33h-1.72v6.2h-.06l-4.14-6.2h-1.53V67h1.72zm10.9.13c1.94 0 2.89-1.16 3.06-2.32h-1.67c-.15.59-.66.95-1.38.95-.91 0-1.53-.7-1.53-1.8v-.2h4.64v-.71c0-2.09-1.22-3.43-3.2-3.43-1.9 0-3.2 1.26-3.2 3.38v.66c0 2.23 1.3 3.47 3.28 3.47zm-1.52-4.51v-.02c0-.93.58-1.64 1.46-1.64.87 0 1.44.7 1.44 1.64v.02h-2.9zM84.67 67h2.02l-2.35-3.63 2.37-3.62h-1.99L83.3 62.2h-.05l-1.44-2.46h-2.08l2.31 3.62-2.3 3.63h1.94l1.47-2.47h.04L84.67 67zm4.17-7.25h-1.06v1.4h1.03v3.8c0 1.48.6 2.1 2.4 2.1.36 0 .68-.04.82-.07v-1.33l-.38.01c-.75 0-1.06-.22-1.06-.94v-3.58H92v-1.4h-1.4v-1.73h-1.76v1.74zm5 7.25h1.85v-4.14c0-.97.4-1.68 1.59-1.68.28 0 .57.02.7.06V59.7a3.05 3.05 0 00-.56-.05c-1 0-1.54.64-1.7 1.1h-.08v-1h-1.8V67zm7.53.1c1.07 0 1.68-.45 1.97-.98h.08V67h1.7v-4.9c0-1.69-1.27-2.47-2.94-2.47-2.1 0-2.87 1.12-2.93 2.33h1.69c.04-.58.47-.97 1.2-.97.76 0 1.2.4 1.2 1.13v.66h-1.77c-1.68 0-2.58.83-2.58 2.13 0 1.37.97 2.2 2.38 2.2zm.58-1.3c-.6 0-1.17-.33-1.17-1 0-.56.39-.94 1.18-.94h1.38v.76c0 .7-.61 1.18-1.39 1.18z\"\n      />\n      <path\n        className=\"theme-1\"\n        fill=\"#000\"\n        d=\"M53.13 6.53c0-1.63.7-2.54 1.92-2.54 1.04 0 1.74.7 1.75 1.7h1.3V5.6c0-1.62-1.29-2.76-3.06-2.76-2.06 0-3.25 1.4-3.25 3.69v.98c0 2.28 1.2 3.65 3.25 3.65 1.77 0 3.06-1.1 3.06-2.65v-.09h-1.3c-.01.94-.7 1.6-1.75 1.6-1.22 0-1.92-.9-1.92-2.5v-1zM64.58 4.8h-1.3v3.74c0 .92-.58 1.42-1.36 1.42-.7 0-1.31-.32-1.31-1.4V4.8h-1.3v4.12c0 1.43.87 2.16 2.15 2.16 1 0 1.58-.46 1.78-.95h.06V11h1.28V4.8zM66 6.6c0 1.14.92 1.52 2.05 1.76.83.17 1.55.27 1.55.92 0 .46-.38.85-1.2.85-.74 0-1.18-.34-1.25-.85h-1.27c0 1.11.94 1.82 2.43 1.82 1.56 0 2.56-.73 2.56-1.98 0-1.18-.9-1.53-2.06-1.74-.7-.13-1.56-.25-1.56-.9 0-.52.45-.82 1.11-.82.85 0 1.12.48 1.16.91h1.17c0-1.1-.83-1.88-2.3-1.88-1.25 0-2.39.58-2.39 1.92zm6.58-1.8h-.88v1.04h.86v3.41c0 1.24.41 1.78 1.92 1.78.26 0 .51-.02.62-.04v-1c-.08.02-.19.02-.3.02-.7 0-.95-.2-.95-.87v-3.3h1.21V4.81h-1.2V3.3h-1.28v1.5zm6.3-.1c-1.77 0-2.75 1.25-2.75 2.93v.5c0 1.75.97 2.97 2.76 2.97 1.78 0 2.74-1.22 2.74-2.97v-.5c0-1.68-.96-2.94-2.74-2.94zm0 1.03c.97 0 1.45.79 1.45 1.92v.47c0 1.12-.47 1.93-1.44 1.93-.98 0-1.45-.82-1.45-1.93v-.47c0-1.12.48-1.92 1.45-1.92zM83.06 11h1.3V7.17c0-.9.53-1.34 1.2-1.34.73 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.45-1.35 1.23-1.35.75 0 1.19.49 1.19 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.05-2.07-1.03 0-1.67.5-1.9 1.03h-.04c-.23-.62-.8-1.03-1.76-1.03-.88 0-1.42.49-1.6.93h-.07V4.8h-1.27V11zM93.3 3.3c0 .42.36.73.78.73.42 0 .77-.3.77-.74a.74.74 0 00-.77-.73c-.42 0-.78.3-.78.73zm.13 7.7h1.3V4.8h-1.3V11zm2.73 0h4.78V9.94H97.8v-.05l3.08-4.2v-.88H96.2v1.06h3.08v.04l-3.13 4.25V11zm8.52.1c1.53 0 2.34-.88 2.52-1.88h-1.23c-.16.53-.61.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.65-2.9-1.62 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.72 2.93zm-1.43-3.8v-.02c0-.88.54-1.57 1.38-1.57.83 0 1.37.69 1.37 1.57v.01h-2.75zm7.59-2.58c-1.52 0-2.42 1.18-2.42 2.91v.54c0 1.76.86 2.91 2.42 2.91.83 0 1.48-.39 1.8-1.02h.04V11h1.27V2.58h-1.3v3.11h-.05c-.3-.56-.94-.97-1.76-.97zm.32 1.08c.92 0 1.5.72 1.5 1.88v.46c0 1.2-.57 1.88-1.48 1.88-.84 0-1.44-.63-1.44-1.89v-.45c0-1.26.6-1.88 1.42-1.88z\"\n      />\n      <path\n        className=\"theme-2\"\n        fill=\"#000\"\n        d=\"M50.34 11V5.47h.04l2.08 4.68h.95l2.07-4.68h.05V11h1.2V3H55.4l-2.44 5.63h-.04L50.48 3h-1.34v8h1.2zm8.08-7.7c0 .42.35.73.77.73.42 0 .77-.3.77-.74a.74.74 0 00-.77-.73c-.42 0-.77.3-.77.73zm.12 7.7h1.3V4.8h-1.3V11zm6.59 0h1.48l-2.05-3.1 2.04-3.1h-1.45L63.8 7.04h-.02L62.41 4.8H60.9l2 3.1-2.02 3.1h1.41l1.4-2.21h.03l1.4 2.21zm4.83.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.15.53-.6.86-1.27.86-.88 0-1.44-.7-1.44-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.71 2.93zm-1.42-3.8v-.02c0-.88.54-1.57 1.38-1.57.82 0 1.37.69 1.37 1.57v.01h-2.75zm7.58-2.58c-1.51 0-2.42 1.18-2.42 2.91v.54c0 1.76.86 2.91 2.42 2.91.84 0 1.49-.39 1.8-1.02h.05V11h1.26V2.58h-1.3v3.11h-.04c-.3-.56-.94-.97-1.77-.97zm.33 1.08c.92 0 1.5.72 1.5 1.88v.46c0 1.2-.57 1.88-1.49 1.88-.83 0-1.43-.63-1.43-1.89v-.45c0-1.26.6-1.88 1.42-1.88zm9.78 5.2V4.14h2.35V3h-6.02v1.14h2.35V11h1.32zm3.3 0h1.3V7.3c0-.8.45-1.46 1.37-1.46.77 0 1.34.45 1.34 1.45V11h1.3V7.02c0-1.51-.92-2.3-2.18-2.3-1.01 0-1.57.54-1.78.95h-.05V2.58h-1.3V11zm9.33.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.6.86-1.27.86-.88 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.39-1.57.82 0 1.37.69 1.37 1.57v.01h-2.76zm5.42 3.7h1.3V7.17c0-.9.53-1.34 1.2-1.34.73 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.45-1.35 1.23-1.35.75 0 1.19.49 1.19 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.05-2.07-1.03 0-1.67.5-1.89 1.03h-.05c-.23-.62-.8-1.03-1.76-1.03-.88 0-1.42.49-1.6.93h-.06V4.8h-1.28V11zm12.77.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.6.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.38-1.57.83 0 1.38.69 1.38 1.57v.01h-2.76z\"\n      />\n      <path\n        className=\"theme-3\"\n        fill=\"#000\"\n        d=\"M52.3 3v8h2.75c2.38 0 3.56-1.44 3.56-4.01C58.6 4.4 57.44 3 55.05 3H52.3zm1.33 1.12h1.28c1.64 0 2.32 1.06 2.32 2.88 0 2.06-.83 2.88-2.32 2.88h-1.28V4.12zm8.79.58c-1.78 0-2.76 1.26-2.76 2.94v.5c0 1.75.97 2.97 2.76 2.97 1.79 0 2.75-1.22 2.75-2.97v-.5c0-1.68-.97-2.94-2.75-2.94zm0 1.04c.97 0 1.44.79 1.44 1.92v.47c0 1.12-.47 1.93-1.44 1.93s-1.45-.82-1.45-1.93v-.47c0-1.12.48-1.92 1.45-1.92zm3.9 2.41c0 1.74 1 2.96 2.68 2.96 1.44 0 2.34-.74 2.5-1.98h-1.23c-.09.48-.47.9-1.2.9-.88 0-1.44-.73-1.44-1.88v-.53c0-1.14.54-1.84 1.44-1.84.62 0 1.06.46 1.17.98h1.23C71.42 5.67 70.5 4.7 69 4.7c-1.68 0-2.67 1.2-2.67 2.9v.55zm6.24-1.53c0 1.13.92 1.51 2.05 1.75.83.17 1.55.27 1.55.92 0 .46-.38.85-1.2.85-.74 0-1.18-.34-1.25-.85h-1.26c0 1.11.93 1.82 2.42 1.82 1.56 0 2.56-.73 2.56-1.98 0-1.18-.9-1.53-2.06-1.74-.7-.13-1.56-.25-1.56-.9 0-.52.45-.82 1.11-.82.85 0 1.12.48 1.16.91h1.17c0-1.1-.83-1.88-2.3-1.88-1.24 0-2.39.58-2.39 1.92zM84.06 11V4.14h2.34V3h-6.02v1.14h2.35V11h1.32zm3.3 0h1.3V7.3c0-.8.44-1.46 1.36-1.46.77 0 1.35.45 1.35 1.45V11h1.29V7.02c0-1.51-.91-2.3-2.17-2.3-1.02 0-1.58.54-1.8.95h-.04V2.58h-1.3V11zm9.33.1c1.52 0 2.33-.88 2.52-1.88h-1.24c-.15.53-.6.86-1.27.86-.88 0-1.44-.7-1.44-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.06 2.93 2.72 2.93zm-1.43-3.8v-.02c0-.88.54-1.57 1.38-1.57.82 0 1.37.69 1.37 1.57v.01h-2.75zm5.41 3.7h1.3V7.17c0-.9.53-1.34 1.2-1.34.73 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.46-1.35 1.23-1.35.75 0 1.19.49 1.19 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.05-2.07-1.03 0-1.67.5-1.89 1.03h-.05c-.23-.62-.8-1.03-1.76-1.03-.88 0-1.42.49-1.6.93h-.06V4.8h-1.28V11zm12.77.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.6.86-1.27.86-.88 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.39-1.57.82 0 1.37.69 1.37 1.57v.01H112z\"\n      />\n      <path\n        className=\"theme-4\"\n        fill=\"#000\"\n        d=\"M53.09 11h3.13c1.67 0 2.79-.83 2.79-2.25 0-1.16-.75-1.85-1.76-1.96v-.06a1.7 1.7 0 001.32-1.76c0-1.22-.9-1.97-2.3-1.97H53.1v8zm1.32-6.94h1.6c.78 0 1.25.42 1.25 1.13 0 .8-.53 1.2-1.72 1.2H54.4V4.05zm0 3.32h1.7c.99 0 1.54.5 1.54 1.32 0 .85-.56 1.25-1.96 1.25H54.4V7.38zM60.34 11h1.3V2.58h-1.3V11zm5.5-6.3c-1.78 0-2.76 1.26-2.76 2.94v.5c0 1.75.97 2.97 2.76 2.97 1.79 0 2.75-1.22 2.75-2.97v-.5c0-1.68-.97-2.94-2.75-2.94zm0 1.04c.97 0 1.44.79 1.44 1.92v.47c0 1.12-.47 1.93-1.44 1.93s-1.45-.82-1.45-1.93v-.47c0-1.12.48-1.92 1.45-1.92zm6.69 6.53c-.75 0-1.24-.39-1.35-.85H69.9c.12 1.03.94 1.85 2.62 1.85 1.4 0 2.76-.72 2.76-2.36V4.8H74v.9h-.04c-.27-.55-.94-.99-1.79-.99-1.43 0-2.41 1.02-2.41 2.88v.44c0 1.88.99 2.89 2.41 2.89.86 0 1.52-.44 1.76-.98h.05v.9c0 .9-.56 1.42-1.45 1.42zm.02-6.48c.87 0 1.43.7 1.43 1.87v.37c0 1.18-.53 1.87-1.43 1.87-.92 0-1.47-.69-1.47-1.87v-.37c0-1.2.55-1.87 1.47-1.87zm9.7 5.21V4.14h2.36V3h-6.02v1.14h2.35V11h1.32zm3.3 0h1.3V7.3c0-.8.45-1.46 1.37-1.46.78 0 1.35.45 1.35 1.45V11h1.3V7.02c0-1.51-.92-2.3-2.18-2.3-1.01 0-1.57.54-1.79.95h-.04V2.58h-1.3V11zm9.34.1c1.53 0 2.34-.88 2.53-1.88h-1.24c-.16.53-.61.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.03v-.6c0-1.74-1-2.9-2.65-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.71 2.93zm-1.43-3.8v-.02c0-.88.55-1.57 1.38-1.57.83 0 1.37.69 1.37 1.57v.01h-2.75zm5.42 3.7h1.29V7.17c0-.9.54-1.34 1.21-1.34.72 0 1.2.43 1.2 1.35V11h1.27V7.18c0-.82.45-1.35 1.22-1.35.76 0 1.2.49 1.2 1.27V11h1.3V6.78c0-1.25-.76-2.07-2.06-2.07-1.02 0-1.67.5-1.88 1.03h-.06c-.22-.62-.8-1.03-1.75-1.03-.88 0-1.42.49-1.6.93h-.07V4.8h-1.28V11zm12.77.1c1.53 0 2.34-.88 2.52-1.88h-1.23c-.16.53-.61.86-1.27.86-.89 0-1.45-.7-1.45-1.73V8.2h4.02v-.6c0-1.74-1-2.9-2.64-2.9-1.63 0-2.66 1.12-2.66 2.85v.63c0 1.83 1.05 2.93 2.7 2.93zm-1.43-3.8v-.02c0-.88.54-1.57 1.38-1.57.83 0 1.37.69 1.37 1.57v.01h-2.75z\"\n      />\n      <style jsx>{`\n        svg {\n          opacity: 0.8;\n          pointer-events: none;\n        }\n        .theme-1,\n        .theme-2,\n        .theme-3,\n        .theme-4 {\n          will-change: opacity, transform;\n          animation: switching 8s ease infinite;\n        }\n        .theme-2 {\n          animation-delay: -2s;\n        }\n        .theme-3 {\n          animation-delay: -4s;\n        }\n        .theme-4 {\n          animation-delay: -6s;\n        }\n        @keyframes switching {\n          0% {\n            opacity: 0;\n            transform: translate3d(-80%, 0, 0);\n          }\n          25% {\n            opacity: 0.2;\n            transform: translate3d(-40%, 0, 0);\n          }\n          50% {\n            opacity: 1;\n            transform: translate3d(0%, 0, 0);\n          }\n          75% {\n            opacity: 0.2;\n            transform: translate3d(40%, 0, 0);\n          }\n          100% {\n            opacity: 0;\n            transform: translate3d(80%, 0, 0);\n          }\n        }\n        .dash-ring {\n          animation: rotation 3s linear infinite;\n        }\n        @keyframes rotation {\n          0% {\n            stroke-dashoffset: 0;\n          }\n          100% {\n            stroke-dashoffset: -14;\n          }\n        }\n      `}</style>\n    </svg>\n  )\n}\n"
  },
  {
    "path": "docs/app/_components/framer-motion.ts",
    "content": "'use client'\n\nimport { motion } from 'framer-motion'\n\nexport const MotionDiv = motion.div\nexport const MotionH3 = motion.h3\n"
  },
  {
    "path": "docs/app/_components/i18n-demo.tsx",
    "content": "'use client'\n\nimport { ArrowRightIcon } from '@components/icons'\nimport cn from 'clsx'\nimport type { FC } from 'react'\nimport { useState } from 'react'\nimport styles from '../page.module.css'\n\nconst LANGUAGES = [\n  { lang: 'en', name: 'English' },\n  { lang: 'de', name: 'Deutsch' },\n  { lang: 'ja', name: '日本語' }\n]\n\nexport const I18n: FC = () => {\n  const [active, setActive] = useState('')\n\n  return (\n    <div className={styles.comparison}>\n      <div style={{ display: 'flex', flexDirection: 'column', gap: '.5rem' }}>\n        {LANGUAGES.map(({ lang }) => (\n          <span\n            key={lang}\n            onPointerOver={() => setActive(lang)}\n            className={cn(styles.file, active === lang && styles.active)}\n          >\n            /{lang}/hello.mdx\n          </span>\n        ))}\n      </div>\n      <ArrowRightIcon width=\"1.2em\" />\n      <div className=\"overflow-auto rounded-md bg-white py-1 text-sm shadow-lg ring-1 ring-black/5 dark:bg-neutral-800 dark:ring-white/20\">\n        {LANGUAGES.map(({ lang, name }) => (\n          <div\n            key={lang}\n            onPointerOver={() => setActive(lang)}\n            className={cn(\n              'relative cursor-default px-4 py-1.5 whitespace-nowrap select-none',\n              active === lang\n                ? 'x:text-primary-600 x:bg-primary-50 x:dark:bg-primary-500/10'\n                : 'text-gray-800 dark:text-gray-100'\n            )}\n          >\n            {name}\n          </div>\n        ))}\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "docs/app/_components/overview-page.tsx",
    "content": "import { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'\nimport type { PageMapItem } from 'nextra'\nimport { Cards } from 'nextra/components'\nimport { getIndexPageMap, getPageMap } from 'nextra/page-map'\nimport type { FC } from 'react'\n\nexport const OverviewPage: FC<{\n  filePath: string\n  icons?: Record<string, FC>\n  pageMap?: PageMapItem[]\n}> = async ({ filePath, icons, pageMap: $pageMap }) => {\n  const { h2: H2 } = getMDXComponents()\n  const currentRoute = filePath.replace('app', '').replace('/page.mdx', '')\n  const pageMap = $pageMap ?? (await getPageMap(currentRoute))\n\n  return getIndexPageMap(pageMap).map((pageItem, index) => {\n    if (!Array.isArray(pageItem)) {\n      return <H2 key={index}>{pageItem.title}</H2>\n    }\n    return (\n      <Cards key={index}>\n        {pageItem.map(item => {\n          const icon = item.frontMatter?.icon\n          const Icon = icons?.[icon]\n          if (icon && !Icon) {\n            throw new Error(\n              `Icon \"${icon}\" is defined in front matter but isn't provided`\n            )\n          }\n          return (\n            // @ts-expect-error -- fixme\n            <Cards.Card\n              key={item.name}\n              // @ts-expect-error -- fixme\n              title={item.title}\n              // @ts-expect-error -- fixme\n              href={item.route || item.href}\n              icon={Icon && <Icon />}\n            />\n          )\n        })}\n      </Cards>\n    )\n  })\n}\n"
  },
  {
    "path": "docs/app/_meta.global.tsx",
    "content": "import type { MetaRecord } from 'nextra'\nimport { LinkArrowIcon } from 'nextra/icons'\nimport type { FC, ReactNode } from 'react'\nimport { useMDXComponents } from '../mdx-components'\n\n// eslint-disable-next-line react-hooks/rules-of-hooks -- isn't react hook\nconst { code: Code } = useMDXComponents()\n\nconst ExternalLink: FC<{ children: ReactNode }> = ({ children }) => {\n  return (\n    <>\n      {children}&thinsp;\n      <LinkArrowIcon\n        // based on font-size\n        height=\"1em\"\n        className=\"x:inline x:align-baseline x:shrink-0\"\n      />\n    </>\n  )\n}\n\nconst FILE_CONVENTIONS: MetaRecord = {\n  _: {\n    type: 'separator',\n    title: 'Files'\n  },\n  'page-file': 'page.mdx',\n  'meta-file': '_meta.js',\n  _2: {\n    href: 'https://nextjs.org/docs/app/api-reference/file-conventions/page',\n    title: <ExternalLink>page.jsx</ExternalLink>\n  },\n  _3: {\n    href: 'https://nextjs.org/docs/app/api-reference/file-conventions/layout',\n    title: <ExternalLink>layout.jsx</ExternalLink>\n  },\n  _4: {\n    type: 'separator',\n    title: 'Top-Level Files'\n  },\n  'mdx-components-file': 'mdx-components.js',\n  _5: {\n    type: 'separator',\n    title: 'Top-Level Folders'\n  },\n  'content-directory': 'content',\n  'src-directory': 'src',\n  _6: {\n    href: 'https://nextjs.org/docs/app/getting-started/installation?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar#create-the-app-directory',\n    title: <ExternalLink>app</ExternalLink>\n  },\n  _7: {\n    href: 'https://nextjs.org/docs/app/building-your-application/optimizing/static-assets?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar',\n    title: <ExternalLink>public</ExternalLink>\n  }\n}\n\nconst GUIDE: MetaRecord = {\n  markdown: '',\n  'syntax-highlighting': '',\n  link: '',\n  image: '',\n  ssg: '',\n  i18n: '',\n  'custom-css': '',\n  'static-exports': '',\n  search: {\n    items: {\n      index: '',\n      ai: {\n        title: <span className=\"badge-new\">Ask AI</span>\n      }\n    },\n    theme: {\n      collapsed: false\n    }\n  },\n  'github-alert-syntax': '',\n  turbopack: '',\n  _: {\n    title: 'Deploying',\n    href: 'https://nextjs.org/docs/app/building-your-application/deploying?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar'\n  }\n}\n\nconst ADVANCED: MetaRecord = {\n  npm2yarn: '',\n  mermaid: '',\n  'tailwind-css': '',\n  latex: '',\n  table: '',\n  typescript: '',\n  remote: ''\n}\n\nconst BLOG_THEME: MetaRecord = {\n  start: '',\n  'get-posts-and-tags': '',\n  // prettier-ignore\n  posts: <><Code>/posts</Code>&nbsp;Page</>,\n  // prettier-ignore\n  tags: <><Code>/tags/:id</Code>&nbsp;Page</>,\n  // prettier-ignore\n  rss: <><Code>/rss.xml</Code>&nbsp;Route</>\n}\n\nexport default {\n  index: {\n    type: 'page',\n    display: 'hidden'\n  },\n  docs: {\n    type: 'page',\n    title: 'Documentation',\n    items: {\n      index: '',\n      'file-conventions': { items: FILE_CONVENTIONS },\n      guide: { items: GUIDE },\n      advanced: { items: ADVANCED },\n      'built-ins': '',\n      _: {\n        type: 'separator',\n        title: 'Themes'\n      },\n      'docs-theme': {\n        items: {\n          start: '',\n          'built-ins': {\n            items: {\n              layout: ''\n            }\n          }\n        }\n      },\n      'blog-theme': { items: BLOG_THEME },\n      'custom-theme': '',\n      __: {\n        type: 'separator',\n        title: 'More'\n      },\n      'about-link': {\n        title: 'About Nextra',\n        href: '/about'\n      },\n      'next.js-link': {\n        title: 'Next.js Docs',\n        href: 'https://nextjs.org?utm_source=nextra.site&utm_medium=referral&utm_campaign=sidebar'\n      },\n      'migration-from-v3': {\n        title: 'Migration from Nextra v3',\n        href: 'https://the-guild.dev/blog/nextra-4?utm_source=nextra.site&utm_campaign=sidebar&utm_content=sidebar_link#nextra-theme-docs-changes'\n      }\n    }\n  },\n  api: {\n    type: 'page'\n  },\n  versions: {\n    type: 'menu',\n    title: 'Versions',\n    items: {\n      _3: {\n        title: 'Nextra v3 Docs',\n        href: 'https://nextra-v2-7hslbun8z-shud.vercel.app'\n      },\n      _2: {\n        title: 'Nextra v2 Docs',\n        href: 'https://nextra-v2-oe0zrpzjp-shud.vercel.app'\n      }\n    }\n  },\n  blog: {\n    type: 'page',\n    theme: {\n      typesetting: 'article',\n      toc: false\n    }\n  },\n  about: {\n    type: 'page',\n    theme: {\n      typesetting: 'article'\n    }\n  },\n  showcase: {\n    type: 'page',\n    theme: {\n      copyPage: false,\n      typesetting: 'article',\n      layout: 'full',\n      timestamp: false,\n      toc: false\n    }\n  },\n  sponsors: {\n    type: 'page',\n    theme: {\n      copyPage: false,\n      typesetting: 'article',\n      layout: 'full',\n      timestamp: false,\n      toc: false\n    }\n  }\n}\n"
  },
  {
    "path": "docs/app/about/page.mdx",
    "content": "---\nsidebarTitle: About\ndescription:\n  Learn about Nextra's history, team, and contributors, and explore how\n  open-source technologies power Nextra's features.\n---\n\nimport { Image } from 'nextra/components'\nimport { cloneElement } from 'react'\n\nexport default function MdxLayout(props) {\n  return cloneElement(props.children, {\n    components: {\n      img: props => <Image {...props} className=\"inline\" />\n    }\n  })\n}\n\n# About Nextra\n\nNextra was initially created by [Vercel](https://vercel.com) members\n[Shu Ding](https://twitter.com/shuding_) and\n[Paco Coursey](https://twitter.com/pacocoursey) in 2020. Since 2021,\n[Yixuan Xu](https://twitter.com/yixuanxu94) contributed tremendously to the\nproject.\n\nIn 2022, [Dimitri Postolov](https://twitter.com/dimaMachina_) from\n[The Guild](https://the-guild.dev) joined the core team to help with the\ndevelopment of Nextra 2.\n\nIn 2024 Nextra 3 was released, current primary maintainer Dimitri Postolov fully\ndeveloped it, and [Oscar Xie](https://github.com/87xie)\n[actively contributed](https://github.com/shuding/nextra/pulls?q=sort%3Aupdated-desc+is%3Apr+author%3A87xie+is%3Aclosed+created%3A%3C2024-10-03)\nto this release.\n\nIn 2025 Nextra 4 with [App Router](https://nextjs.org/docs/app) support was\nreleased, Dimitri Postolov fully developed it too.\n\n## Team\n\nCurrently, the project is maintained by Dimitri Postolov. You can check out\n[the full list of contributors](https://github.com/shuding/nextra/graphs/contributors)\non GitHub.\n\n## Credits\n\nNextra is powered by these incredible open source projects:\n\n- https://reactjs.org\n- https://nextjs.org\n- https://turbo.build\n- https://mdxjs.com\n- https://pnpm.io\n- https://tailwindcss.com\n- https://github.com/pacocoursey/next-themes\n- https://github.com/shikijs/shiki\n- https://github.com/cloudcannon/pagefind\n- https://github.com/atomiks/rehype-pretty-code\n- https://github.com/Brooooooklyn/simple-git\n- https://github.com/francoismassart/eslint-plugin-tailwindcss\n\n## Design assets\n\nFeel free to use the Nextra logo and other assets in your project. But please\ndon't modify the logo, and don't use the logo to represent your project or\nproduct.\n\n|    Name     |                   Description                    |                Preview                |\n| :---------: | :----------------------------------------------: | :-----------------------------------: |\n|    Icon     | Useful for favicons, app icons, link icons, etc. |      ![Nextra icon](../icon.svg)      |\n|    Logo     |                 Full Nextra logo                 |       ![Nextra logo](/logo.svg)       |\n| Social Card |              The Nextra social card              | ![Nextra card](/opengraph-image.jpeg) |\n\n## License\n\nThe Nextra project and themes are licensed under\n[the MIT license](https://github.com/shuding/nextra/blob/main/LICENSE).\n"
  },
  {
    "path": "docs/app/api/[name]/page.tsx",
    "content": "import path from 'node:path'\nimport { generateApiReference } from '@components/generate-api-reference'\nimport type { ApiReference } from '@components/generate-api-reference'\nimport { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'\nimport type { MdxFile } from 'nextra'\nimport { generateDefinition } from 'nextra/tsdoc'\nimport type { FC } from 'react'\n\ntype AllApiReference = ApiReference & { filePath?: string }\n\nconst API_REFERENCE: (\n  | AllApiReference\n  | { type: 'separator'; title: string; name: string }\n)[] = [\n  { type: 'separator', title: 'Types', name: '_' },\n  {\n    name: 'NextraConfig',\n    packageName: 'nextra',\n    isFlattened: false,\n    filePath: 'packages/nextra/src/server/schemas.ts'\n  },\n  {\n    name: 'MdxOptions',\n    code: `import type { NextraConfig } from 'nextra'\ntype $ = NonNullable<NextraConfig['mdxOptions']>\nexport default $`,\n    isFlattened: false,\n    filePath: 'packages/nextra/src/server/schemas.ts'\n  },\n  { type: 'separator', title: 'Functions', name: '_2' },\n  {\n    name: 'nextra',\n    code: \"export { default } from 'nextra'\",\n    isFlattened: false\n  },\n  {\n    name: 'useMDXComponents',\n    packageName: 'nextra/mdx-components',\n    isFlattened: false\n  },\n  { name: 'getPageMap', packageName: 'nextra/page-map' },\n  { name: 'generateStaticParamsFor', packageName: 'nextra/pages' },\n  { name: 'importPage', packageName: 'nextra/pages' },\n  { name: 'compileMdx', packageName: 'nextra/compile' },\n  { name: 'generateDefinition', packageName: 'nextra/tsdoc' },\n  { name: 'proxy', packageName: 'nextra/locales' },\n  { name: 'evaluate', packageName: 'nextra/evaluate' },\n  { name: 'normalizePages', packageName: 'nextra/normalize-pages' }\n]\n\nconst routes = API_REFERENCE.filter((o): o is AllApiReference => !('type' in o))\n\nconst separatorIndex = API_REFERENCE.findIndex(\n  o => 'title' in o && o.title === 'Functions'\n)\nconst functionsIndex = routes.indexOf(\n  API_REFERENCE[separatorIndex + 1] as AllApiReference\n)\n\nexport const generateStaticParams = () =>\n  routes.map(o => ({ name: o.name.toLowerCase() }))\n\n// @ts-expect-error -- fixme\nexport const pageMap: (MdxFile & { title: string })[] = API_REFERENCE.map(o =>\n  'type' in o\n    ? o\n    : {\n        name: o.name.toLowerCase(),\n        route: `/api/${o.name.toLowerCase()}`,\n        title: o.name\n      }\n)\n\nconst Wrapper = getMDXComponents().wrapper\n\nasync function getReference(props: PageProps) {\n  const params = await props.params\n  const apiRefIndex = routes.findIndex(\n    o => o.name.toLowerCase() === params.name\n  )\n  const apiRef = routes[apiRefIndex]\n  if (!apiRef) {\n    throw new Error(`API reference not found for \"${params.name}\"`)\n  }\n  const isType = functionsIndex > apiRefIndex\n\n  const definition = generateDefinition({\n    code:\n      apiRef.code ??\n      `export { ${apiRef.name} as default } from '${apiRef.packageName}'`,\n    flattened: apiRef.isFlattened !== false\n  })\n\n  const result = await generateApiReference(apiRef, {\n    title: isType ? 'Type' : 'Function',\n    subtitle: isType ? 'Fields' : 'Signature',\n    definition\n  })\n  const filePath =\n    definition.filePath &&\n    path\n      .relative('..', definition.filePath)\n      .replace(/\\.d.ts$/, '.ts')\n      .replace('/dist/', '/src/')\n  // Add edit on GitHub link to points on a source file\n  result.metadata.filePath = `https://github.com/shuding/nextra/tree/main/${apiRef.filePath ?? filePath}`\n  return result\n}\n\nexport async function generateMetadata(props: PageProps) {\n  const { metadata } = await getReference(props)\n  return metadata\n}\n\ntype PageProps = Readonly<{\n  params: Promise<{ name: string }>\n}>\n\nconst Page: FC<PageProps> = async props => {\n  const {\n    default: MDXContent,\n    toc,\n    metadata,\n    sourceCode\n  } = await getReference(props)\n  return (\n    <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>\n      <MDXContent />\n    </Wrapper>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "docs/app/api/page.mdx",
    "content": "import { Callout, Cards } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\nimport { createIndexPage } from 'nextra/page-map'\nimport { pageMap } from './[name]/page'\n\n# API\n\n<Callout type=\"info\">\n  This API reference is automatically generated from the catch-all route file\n  `/api/[name]/page.tsx` using the new [Nextra `<TSDoc />`\n  component](/docs/built-ins/tsdoc).\n</Callout>\n\n<MDXRemote\n  compiledSource={await createIndexPage(pageMap)}\n  components={{\n    Cards\n  }}\n/>\n"
  },
  {
    "path": "docs/app/blog/page.mdx",
    "content": "---\nasIndexPage: true\ndescription:\n  Stay updated with the latest news and updates from the Nextra team, including\n  new releases, features, and community highlights.\n---\n\nimport { Link } from 'nextra-theme-docs'\n\n# Blog\n\n<BlogPage />\n\nexport function BlogPage() {\n  return [\n    {\n      route:\n        'https://the-guild.dev/blog/nextra-4?utm_source=nextra.site&utm_campaign=blog_page&utm_content=blog_link',\n      title: 'Nextra 4',\n      description:\n        'App Router support, Turbopack support, compiled by React Compiler, new Rust-powered search Pagefind, RSC i18n, server/client components, smallest bundle size EVER for a Nextra-powered website, GitHub Alert Syntax, new _meta.global file and more.',\n      date: '2024-01-13'\n    },\n    {\n      route:\n        'https://the-guild.dev/blog/nextra-3?utm_source=nextra.site&utm_campaign=blog_page&utm_content=blog_link',\n      title: 'Nextra 3 – Your Favourite MDX Framework, Now on 🧪 Steroids',\n      description:\n        'MDX 3, new i18n, new _meta files with JSX support, more powerful TOC, remote MDX, better bundle size, MathJax, new code block styles, shikiji, ESM-only and more.',\n      date: '2023-12-12'\n    },\n    {\n      route:\n        'https://the-guild.dev/blog/nextra-2?utm_source=nextra.site&utm_campaign=blog_page&utm_content=blog_link',\n      title: 'Nextra 2 – Next.js Static Site Generator',\n      description:\n        'Here are what the new version of Nextra 2 Framework includes.',\n      date: '2023-01-24'\n    }\n  ].map(page => (\n    <div key={page.route} className=\"mt-12\">\n      <h3 className=\"text-2xl font-semibold\">{page.title}</h3>\n      <p className=\"my-6 leading-7 opacity-80\">\n        {page.description}{' '}\n        {page.date && <Link href={page.route}>Read more</Link>}\n      </p>\n      {page.date ? (\n        <time\n          dateTime={new Date(page.date).toISOString()}\n          className=\"text-sm opacity-50\"\n        >\n          {new Date(page.date).toLocaleDateString('en', {\n            month: 'long',\n            day: 'numeric',\n            year: 'numeric'\n          })}\n        </time>\n      ) : (\n        <span className=\"text-sm opacity-50\">Coming soon!</span>\n      )}\n    </div>\n  ))\n}\n"
  },
  {
    "path": "docs/app/docs/advanced/customize-the-cascade-layers/page.mdx",
    "content": "---\nsidebarTitle: Customize Cascade Layers\n---\n\nimport { Steps } from 'nextra/components'\n\n# Customize the Cascade Layers\n\nIn some scenarios, you may need more control over the Nextra predefined CSS to\navoid unintended overrides of styles within cascade layers. Below is an example\nof how `nextra-theme-docs` uses\n[postcss-import](https://github.com/postcss/postcss-import) to place predefined\nCSS into a specified cascade layer:\n\n<Steps>\n\n## Install `postcss-import`\n\nInstall `postcss-import` and add it to `postcss.config.mjs`:\n\n```js filename=\"postcss.config.mjs\"\nexport default {\n  plugins: {\n    'postcss-import': {}\n    // ... your other PostCSS plugins (e.g., `autoprefixer`, `cssnano`)\n  }\n}\n```\n\n## Set up the cascade layers\n\nIn your CSS file (e.g. `styles.css`), import the `nextra-docs-theme` CSS and\nspecify the layers:\n\n```css filename=\"styles.css\"\n@layer nextra, my-base;\n\n@import 'nextra-theme-docs/dist/style.css' layer(nextra);\n\n@layer my-base {\n  /* my base styles */\n}\n```\n\n## Import your CSS file\n\nImport your CSS file at the top-level layout of your application (e.g.\n`app/layout.jsx`) to apply the styles.\n\n```jsx filename=\"app/layout.jsx\"\nimport '../path/to/your/styles.css'\n\nexport default async function RootLayout({ children }) {\n  // ... Your layout logic here\n}\n```\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/advanced/latex/page.mdx",
    "content": "---\nicon: FormulaIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport {\n  Callout,\n  MathJax,\n  MathJaxContext,\n  Steps,\n  Tabs\n} from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n{/* <link rel=\"stylesheet\"> is unsupported in Metadata API https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata */}\n\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/katex/dist/katex.css\"\n/>\n\n# LaTeX\n\nNextra can use [KaTeX](https://katex.org) to pre-render LaTeX expressions\ndirectly in MDX or [MathJax](https://mathjax.org) to dynamically render math in\nthe browser.\n\n## Setup\n\n<Steps>\n\n### Enable the `latex` option\n\nBy default, LaTeX is disabled. To enable it, you need to set the `latex` option\nin your `next.config.mjs` file:\n\n```js filename=\"next.config.mjs\" {4}\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  latex: true\n})\n\nexport default withNextra()\n```\n\nA value of `true{:js}` will use KaTeX as the math renderer. To explicitly\nspecify the renderer, you may instead provide an object\n`{ renderer: 'katex' }{:js}` or `{ renderer: 'mathjax' }{:js}` as the value to\n`latex: ...`.\n\nWhen enabled, the required CSS and fonts will be automatically included in your\nsite, and you can start writing math expressions by enclosing inline math in\n`$...$` or display math in a `math`-labeled fenced code block:\n\n````mdx\n```math\n\\int x^2\n```\n````\n\n### Apply styles\n\n<Callout type=\"warning\">\n  This is applicable only to KaTeX as the math renderer.\n</Callout>\n\n<Tabs items={['Import CSS from `katex` package', 'Load CSS from CDN']}>\n<Tabs.Tab>\n1. Install the `katex` package\n\n```bash npm2yarn\nnpm i katex\n```\n\n2. Import CSS in the root layout\n\n```js filename=\"app/layout.jsx\"\nimport 'katex/dist/katex.min.css'\n```\n\n</Tabs.Tab>\n<Tabs.Tab>\nAdd `<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/katex/dist/katex.css\" />{:jsx}`\ninside `<head>` element in your root `layout` file since `<link rel=\"stylesheet\" />{:jsx}`\n[isn't supported with Next.js Metadata API](https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata).\n\nAlternatively, you can include `<link rel=\"stylesheet\" />{:jsx}` directly in\nyour MDX file:\n\n````mdx filename=\"katex.mdx\"\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/katex/dist/katex.css\"\n/>\n\n# My page with single usage of KaTeX\n\n```math\n\\int_2^3x^3\\,\\mathrm{d}x\n```\n````\n\n</Tabs.Tab>\n</Tabs>\n</Steps>\n\n## Example\n\nFor example, the following Markdown code:\n\n````md filename=\"page.md\"\nThe **Pythagorean equation** is $a=\\sqrt{b^2 + c^2}$ and the quadratic formula:\n\n```math\nx=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}\n```\n````\n\nwill be rendered as:\n\n<div className=\"mt-6 rounded-xl border p-4 nextra-border\">\nThe **Pythagorean equation** is $a=\\sqrt{b^2 + c^2}$ and the quadratic formula:\n\n```math\nx=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}\n```\n\n</div>\n\nYou can still use [Markdown and MDX syntax](../guide/markdown) in the same line\nas your LaTeX expression.\n\n> [!TIP]\n>\n> If you want to display `$` in your content instead of rendering it as an\n> equation, you can escape it with a backslash (`\\`). For example `\\$e = mc^2\\$`\n> will be rendered as \\$e = mc^2\\$.\n\n## API\n\n### KaTeX\n\n`rehype-katex` is used to pre-render LaTeX expressions in your content. You can\npass supported [KaTeX options](https://katex.org/docs/options) via the `options`\nkey in your Nextra config. For example, to add a macro `\\RR` that renders as\n`\\mathbb{R}` you could use the following configuration.\n\n```js filename=\"next.config.mjs\" {4-8}\nconst withNextra = nextra({\n  latex: {\n    renderer: 'katex',\n    options: {\n      macros: {\n        '\\\\RR': '\\\\mathbb{R}'\n      }\n    }\n  }\n})\n```\n\nSee [KaTeX's documentation](https://katex.org/docs/supported) for a list of\nsupported commands.\n\n### MathJax\n\nWhen MathJax is enabled (by setting `latex: { renderer: 'mathjax' }{:js}`) math\nis rendered on page load via\n[`better-react-mathjax`](https://github.com/fast-reflexes/better-react-mathjax)\ninstead of being pre-rendered. By default, **MathJax is served via the MathJax\nCDN** instead of the files being directly included in your site.[^1]\n\n[^1]:\n    This can be changed by setting\n    [`{ options: { src: ... } }{:js}`](https://github.com/fast-reflexes/better-react-mathjax#src-string--undefined)\n    in the Nextra config.\n\nMathJax rendering is enabled by setting `renderer: 'mathjax'{:js}` in your\nNextra config.\n\n```js filename=\"next.config.mjs\" {3}\nconst withNextra = nextra({\n  latex: {\n    renderer: 'mathjax'\n  }\n})\n```\n\nYou can pass additional options to `better-react-mathjax` via the `options` key\nin your Nextra config. The `config: ...` option sets the\n[MathJax configuration](https://docs.mathjax.org/en/latest/options/index.html).\nHowever, note that you can only pass serializable options to\n`better-react-mathjax` via the `options` key in your Nextra config.[^2]\n\n[^2]:\n    To pass non-serializable objects like Functions, you must use the\n    `<MathJaxContext config={...} />{:jsx}` component directly in your source.\n\nFor example, to configure MathJax to render `\\RR` as `\\mathbb{R}` you could use\nthe following configuration.\n\n```js filename=\"next.config.mjs\" {4-12}\nconst withNextra = nextra({\n  latex: {\n    renderer: 'mathjax',\n    options: {\n      config: {\n        tex: {\n          macros: {\n            RR: '\\\\mathbb{R}'\n          }\n        }\n      }\n    }\n  }\n})\n```\n\n#### MathJax CDN\n\nBy default, MathJax is served via the MathJax CDN. To serve files from another\nlocation (including locally in your project), you must pass the `src: ...`\noption to the latex config. See the\n[better-react-mathjax documentation](https://github.com/fast-reflexes/better-react-mathjax#src-string--undefined)\nfor details about the `src` option. Additionally, you may need to copy the\nMathJax distribution into your `/public` folder for it to be served locally.\n\n## KaTeX vs. MathJax\n\nWith KaTeX, math is pre-rendered which means flicker-free and faster page loads.\nHowever, KaTeX does not support all the features of MathJax, especially features\nrelated to accessibility.\n\nThe following two examples show the same formula rendered with KaTeX (first) and\nMathJax (second).\n\n```math\n\\int_2^3x^3\\,\\mathrm{d}x\n```\n\n<MathJaxExample />\n\nBecause of MathJax's accessibility features, the second formula is\ntab-accessible and has a context menu that helps screen readers reprocess math\nfor the visually impaired.\n\nexport async function MathJaxExample() {\n  const rawMdx = `~~~math\n\\\\int_2^3x^3\\\\,\\\\mathrm{d}x\n~~~`\n  const rawJs = await compileMdx(rawMdx, {\n    latex: {\n      renderer: 'mathjax',\n      options: {\n        config: {\n          tex: {\n            macros: {\n              RR: '\\\\mathbb{R}'\n            }\n          }\n        }\n      }\n    }\n  })\n  return (\n    <MDXRemote\n      compiledSource={rawJs}\n      components={{ MathJax, MathJaxContext }}\n    />\n  )\n}\n"
  },
  {
    "path": "docs/app/docs/advanced/mermaid/page.mdx",
    "content": "---\nicon: DiagramIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport { Mermaid } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n# Mermaid\n\nNextra supports [mermaid](https://mermaid.js.org) diagrams. Like in GitHub you\ncan use it in your Markdown files by using the `mermaid` code block language.\nOut of the box, Nextra uses\n[`@theguild/remark-mermaid`](https://npmjs.com/package/@theguild/remark-mermaid)\npackage that replaces the code block with the `<Mermaid>` component.\n\n## Example\n\n<Demo />\n\nexport async function Demo() {\n  const mermaidCodeblock = `\\`\\`\\`mermaid\ngraph TD;\nsubgraph AA [Consumers]\nA[Mobile app];\nB[Web app];\nC[Node.js client];\nend\nsubgraph BB [Services]\nE[REST API];\nF[GraphQL API];\nG[SOAP API];\nend\nZ[GraphQL API];\nA --> Z;\nB --> Z;\nC --> Z;\nZ --> E;\nZ --> F;\nZ --> G;\n\\`\\`\\``\n  const rawJs = await compileMdx(`${mermaidCodeblock}\n## Usage\n~~~md filename=\"Markdown\"\n${mermaidCodeblock}\n~~~\n`)\n  return <MDXRemote compiledSource={rawJs} components={{ Mermaid }} />\n}\n"
  },
  {
    "path": "docs/app/docs/advanced/npm2yarn/page.mdx",
    "content": "---\nicon: TerminalIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport { Tabs } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n# Npm2Yarn\n\nNextra uses\n[`@theguild/remark-npm2yarn`](https://npmjs.com/package/@theguild/remark-npm2yarn)\npackage that replaces the code block that has `npm2yarn` metadata with\n[`<Tabs>` and `<Tabs.Tab>` components](/docs/built-ins/tabs) from\n`nextra/components`.\n\nThe chosen tab is saved in the local storage, which will be chosen in future\npage renders.\n\n## Example\n\n<Page />\n\nexport async function Page() {\n  const codeBlock = `\\`\\`\\`sh npm2yarn\nnpm i -D @graphql-eslint/eslint-plugin\n\\`\\`\\``\n  const rawJs = await compileMdx(`${codeBlock}\n## Usage\n~~~md filename=\"Markdown\" /npm2yarn/\n${codeBlock}\n~~~`)\n  return <MDXRemote compiledSource={rawJs} components={{ $Tabs: Tabs }} />\n}\n"
  },
  {
    "path": "docs/app/docs/advanced/page.mdx",
    "content": "---\nasIndexPage: true\n---\n\nimport {\n  CloudIcon,\n  DiagramIcon,\n  FormulaIcon,\n  TableIcon,\n  TailwindIcon\n} from '@components/icons'\nimport { TerminalIcon, TypeScriptIcon } from 'nextra/icons'\nimport { OverviewPage } from '../../_components/overview-page'\n\n# Advanced\n\n<OverviewPage\n  filePath={metadata.filePath}\n  icons={{\n    TerminalIcon,\n    DiagramIcon,\n    TailwindIcon,\n    FormulaIcon,\n    TableIcon,\n    TypeScriptIcon,\n    CloudIcon\n  }}\n/>\n"
  },
  {
    "path": "docs/app/docs/advanced/remote/page.mdx",
    "content": "---\nicon: CloudIcon\n---\n\nimport fs from 'node:fs/promises'\nimport { compileMdx } from 'nextra/compile'\nimport { Steps } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\nexport async function Example() {\n  const filename = '/graphql-eslint/[[...slug]]/page.tsx'\n  const pageContent = await fs.readFile(\n    `../examples/swr-site/app/[lang]/${filename}`,\n    'utf8'\n  )\n  const rawJs = await compileMdx(\n    `~~~jsx filename=\"app${filename}\" {27} showLineNumbers\n${pageContent\n  .replace(\n    \"lang: 'en',\\n    ...(route && { slug: route.split('/') })\",\n    \"slug: route.split('/')\"\n  )\n  .trimEnd()}\n~~~`,\n    { defaultShowCopyCode: true }\n  )\n  return <MDXRemote compiledSource={rawJs} />\n}\n\n# Remote Content\n\n> [!NOTE]\n>\n> You can check out the\n> [SWR i18n example](https://github.com/shuding/nextra/blob/main/examples/swr-site/app/%5Blang%5D/graphql-eslint/%5B%5B...slug%5D%5D/page.tsx)\n> source code.\n\n<Steps>\n\n## Create `[[...slug]]/page.tsx` file\n\nCreate `[[...slug]]/page.tsx` file in `app/` directory with the following\ncontent:\n\n<Example />\n\n## Enhance `pageMap`\n\nYou need to modify `pageMap` list in `layout` file, to properly display sidebar\nand mobile navigation.\n\n```tsx filename=\"app/layout.tsx\"\nimport { getPageMap } from 'nextra/page-map'\nimport { pageMap as graphqlEslintPageMap } from './graphql-eslint/[[...slug]]/page'\n\n// ...\n\nconst pageMap = [...(await getPageMap()), graphqlEslintPageMap]\n```\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/advanced/table/page.mdx",
    "content": "---\nicon: TableIcon\n---\n\n# Rendering Tables\n\nThis guide covers different ways to render tables in MDX, including GFM syntax\nand literal HTML tag.\n\n## GFM syntax\n\nIn Markdown, it is preferable to write tables via\n[GFM syntax](https://github.github.com/gfm/#tables-extension-).\n\n```mdx filename=\"MDX\"\n| left   | center | right |\n| :----- | :----: | ----: |\n| foo    |  bar   |   baz |\n| banana | apple  |  kiwi |\n```\n\nwill be rendered as:\n\n| left   | center | right |\n| :----- | :----: | ----: |\n| foo    |  bar   |   baz |\n| banana | apple  |  kiwi |\n\n## Literal HTML tables\n\nIf you try to render table with literal HTML elements `<table>{:js}`,\n`<thead>{:js}`, `<tbody>{:js}`, `<tr>{:js}`, `<th>{:js}` and `<td>{:js}` – your\ntable will be unstyled because\n[MDX](https://mdxjs.com/docs/using-mdx/#components) doesn't replace literal HTML\nelements with components provided by `useMDXComponents(){:js}`[^1].\n\n> [!TIP]\n>\n> Instead, use the [built-in `<Table>` component](/docs/built-ins/table)\n> available via `nextra/components`.\n\n## Changing default behaviour\n\nIf you want to use standard HTML elements for your tables but have them styled\nwith components provided by `useMDXComponents(){:js}`[^1], you can do this by\nconfiguring Nextra.\n\nTo achieve this, pass the `whiteListTagsStyling` option to the Nextra function,\nincluding an array of tags you want to replace.\n\nHere's an example configuration in your `next.config.mjs` file:\n\n```js filename=\"next.config.mjs\" {4}\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  whiteListTagsStyling: ['table', 'thead', 'tbody', 'tr', 'th', 'td']\n})\n\nexport default withNextra()\n```\n\nIn this example, the tags `<table>`, `<thead>`, `<tbody>`, `<tr>`, `<th>`, and\n`<td>` will be replaced with corresponding MDX components, allowing for\ncustomized styling.\n\n[^1]: https://mdxjs.com/packages/react/#usemdxcomponentscomponents\n"
  },
  {
    "path": "docs/app/docs/advanced/tailwind-css/page.mdx",
    "content": "---\nicon: TailwindIcon\n---\n\nimport { Steps } from 'nextra/components'\n\n# Tailwind CSS\n\nTailwind CSS is a CSS framework that provides a set of pre-defined CSS classes\nto quickly style elements.\n\n<Steps>\n\n## Follow the official guide\n\nFollow the official\n[Tailwind CSS guide for Next.js](https://tailwindcss.com/docs/guides/nextjs) to\nset up Tailwind CSS for your project.\n\n## Create the `globals.css` file\n\nImport Tailwind CSS into `globals.css`:\n\n```css filename=\"globals.css\"\n@import 'tailwindcss';\n\n/* Optional: import Nextra theme styles */\n@import 'nextra-theme-docs/style.css'; /* or nextra-theme-blog/style.css */\n\n@variant dark (&:where(.dark *));\n```\n\n## Import styles in the root layout\n\nTo apply the styles globally, import the `globals.css` file in your root layout\nfile:\n\n```jsx filename=\"app/layout.jsx\"\nimport '../path/to/your/globals.css'\n\nexport default async function RootLayout({ children }) {\n  // ... Your layout logic here\n}\n```\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/advanced/twoslash/page.mdx",
    "content": "# Twoslash Support\n\nTwoslash provides an inline type hove inside the code block.\n\n## Basic usage\n\nYou can enable twoslash to your code blocks by adding a `twoslash` metadata:\n\n{/* prettier-ignore */}\n````md copy=false filename=\"Markdown\"\n```ts twoslash\n// @errors: 2540\ninterface Todo {\n  title: string\n}\n\nconst todo: Readonly<Todo> = {\n  title: 'Delete inactive users'.toUpperCase()\n  //  ^?\n}\n\ntodo.title = 'Hello'\n\nNumber.parseInt('123', 10)\n//      ^|\n               // Just comments, so Popup will be\n               // not behind the viewport of `<code>`\n               // element due his `position: absolute` style\n               //\n```\n````\n\nRenders:\n\n{/* prettier-ignore */}\n```ts twoslash\n// @errors: 2540\ninterface Todo {\n  title: string\n}\n\nconst todo: Readonly<Todo> = {\n  title: 'Delete inactive users'.toUpperCase()\n  //  ^?\n}\n\ntodo.title = 'Hello'\n\nNumber.parseInt('123', 10)\n//      ^|\n\n\n\n\n```\n\n## Custom log message\n\nYou can add log message to your code by adding:\n\n- `@log: <message>` Custom log message\n- `@error: <message>` Custom error message\n- `@warn: <message>` Custom warn message\n- `@annotate: <message>` Custom annotate message\n\n```ts twoslash\n// @log: Custom log message\nconst a = 1\n// @error: Custom error message\nconst b = 1\n// @warn: Custom warning message\nconst c = 1\n// @annotate: Custom annotation message\n```\n"
  },
  {
    "path": "docs/app/docs/advanced/typescript/page.mdx",
    "content": "---\nicon: TypeScriptIcon\n---\n\nimport { Steps } from 'nextra/components'\n\n# TypeScript\n\nNextra is built with TypeScript and provides excellent TypeScript support out of\nthe box. This guide will help you leverage TypeScript in your Nextra project.\n\n## Getting started\n\nTo use TypeScript in your Nextra project, you need to:\n\n<Steps>\n### Install TypeScript and types packages as `devDependencies`\n\n```sh npm2yarn\nnpm i -D typescript @types/react @types/node\n```\n\n### `tsconfig.json`\n\nYou can manually create a `tsconfig.json` file in the root of your project or\nrename the extension of some of the existing files to `.ts` or `.tsx` and then\nNext.js will detect TypeScript in your project and create a `tsconfig.json` file\nfor you.\n\n</Steps>\n\n## Type definitions\n\nNextra provides type definitions for distribution code for its components and\nconfigurations. You can leverage these types by renaming your theme\nconfiguration file to `.ts` or `.tsx` extension and importing a theme config\ntype, e.g. for `nextra-theme-docs`:\n\n```tsx filename=\"theme.config.tsx\"\nimport type { DocsThemeConfig } from 'nextra-theme-docs'\n\nconst config: DocsThemeConfig = {\n  // Your theme configuration\n}\nexport default config\n```\n\nBy leveraging TypeScript in your Nextra project, you can catch errors early,\nimprove code quality, and enhance the developer experience with better\nautocompletion and type inference.\n"
  },
  {
    "path": "docs/app/docs/blog-theme/get-posts-and-tags/page.mdx",
    "content": "---\nicon: FilesIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Get Posts and Their Tags\n\nThe following code snippet demonstrates how to retrieve all posts along with\ntheir associated tags.\n\n<ExampleCode\n  example=\"blog\"\n  filePath=\"app/posts/get-posts.js\"\n  metadata=\"/getPageMap/\"\n/>\n"
  },
  {
    "path": "docs/app/docs/blog-theme/page.mdx",
    "content": "---\nasIndexPage: true\nsidebarTitle: Blog Theme\n---\n\nimport {\n  ChevronRightIcon,\n  FilesIcon,\n  RSSIcon,\n  TagsIcon\n} from '@components/icons'\nimport { FileIcon } from 'nextra/icons'\nimport { OverviewPage } from '../../_components/overview-page'\n\n# Nextra Blog Theme\n\n<OverviewPage\n  filePath={metadata.filePath}\n  icons={{\n    ChevronRightIcon,\n    FilesIcon,\n    FileIcon,\n    TagsIcon,\n    RSSIcon\n  }}\n/>\n"
  },
  {
    "path": "docs/app/docs/blog-theme/posts/page.mdx",
    "content": "---\nicon: FileIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Posts Page\n\nThe following code snippet demonstrates how to create `/posts` page.\n\n<ExampleCode\n  example=\"blog\"\n  filePath=\"app/posts/page.jsx\"\n  metadata=\"/getPosts/ /getTags/\"\n/>\n"
  },
  {
    "path": "docs/app/docs/blog-theme/rss/page.mdx",
    "content": "---\nicon: RSSIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Generate RSS feed\n\nThe following code snippet demonstrates how to create `/rss.xml` route.\n\n<ExampleCode\n  example=\"blog\"\n  filePath=\"app/rss.xml/route.js\"\n  metadata=\"/getPosts/\"\n/>\n"
  },
  {
    "path": "docs/app/docs/blog-theme/start/page.mdx",
    "content": "---\nicon: ChevronRightIcon\n---\n\nimport InstallNextraTheme from '@components/install-nextra-theme.mdx'\nimport ReadyToGo from '@components/ready-to-go.mdx'\nimport { ExampleCode } from '@components/example-code'\nimport { Steps } from 'nextra/components'\n\n# Get Started\n\n> [!NOTE]\n>\n> An example of the blog theme can be found [here](https://demo.vercel.blog),\n> with source code [here](https://github.com/shuding/nextra/tree/main/examples/blog).\n\nSimilar to the [Docs Theme](/docs/docs-theme/start), you can install the blog\ntheme with the following commands:\n\n## Start as a new project\n\n<Steps>\n### Install\n\nTo create a Nextra Blog site manually, you have to install **Next.js**,\n**React**, **Nextra**, and **Nextra Blog Theme**. In your project directory, run\nthe following command to install the dependencies:\n\n```sh npm2yarn\nnpm i next react react-dom nextra nextra-theme-blog\n```\n\n> [!NOTE]\n>\n> If you already have Next.js installed in your project, you only need to\n> install `nextra` and `nextra-theme-blog` as the add-ons.\n\n<InstallNextraTheme />\n\n<ExampleCode example=\"blog\" filePath=\"app/layout.jsx\" />\n\n{/*\n\n### Create Blog Theme Config\n\nLastly, create the corresponding `theme.config.jsx` file in your project's root\ndirectory. This will be used to configure the Nextra Blog theme:\n\n```jsx filename=\"theme.config.jsx\"\nexport default {\n  footer: <p>MIT 2023 © Nextra.</p>,\n  head: ({ title, meta }) => (\n    <>\n      {meta.description && (\n        <meta name=\"description\" content={meta.description} />\n      )}\n      {meta.tag && <meta name=\"keywords\" content={meta.tag} />}\n      {meta.author && <meta name=\"author\" content={meta.author} />}\n    </>\n  ),\n  readMore: 'Read More →',\n  postFooter: null,\n  darkMode: false,\n  navs: [\n    {\n      url: 'https://github.com/shuding/nextra',\n      name: 'Nextra'\n    }\n  ]\n}\n```\n\n*/}\n\n<ReadyToGo />\n\n</Steps>\n\n## Layout Props\n\n<APIDocs\n  componentName=\"Layout\"\n  packageName=\"../packages/nextra-theme-blog\"\n/>\n"
  },
  {
    "path": "docs/app/docs/blog-theme/tags/page.mdx",
    "content": "---\nicon: TagsIcon\n---\n\nimport { ExampleCode } from 'components/example-code'\n\n# Tags Page\n\nThe following code snippet demonstrates how to create `/tags/:id` pages.\n\n<ExampleCode\n  example=\"blog\"\n  filePath=\"app/tags/[tag]/page.jsx\"\n  metadata=\"/getPosts/ /getTags/\"\n/>\n"
  },
  {
    "path": "docs/app/docs/built-ins/[name]/page.tsx",
    "content": "import path from 'node:path'\nimport { generateApiReference } from '@components/generate-api-reference'\nimport type { ApiReference } from '@components/generate-api-reference'\nimport { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'\nimport type { MdxFile } from 'nextra'\nimport { generateDefinition } from 'nextra/tsdoc'\nimport type { FC } from 'react'\n\ntype ComponentApiReference = ApiReference & { groupKeys?: string }\n\nconst API_REFERENCE: (\n  | ComponentApiReference\n  | { type: 'separator'; title: string; name: string }\n)[] = [\n  { type: 'separator', title: 'Layout Components', name: '_' },\n  {\n    name: 'Banner',\n    packageName: 'nextra/components',\n    groupKeys: 'HTMLAttributes<HTMLDivElement>'\n  },\n  {\n    name: 'Head',\n    packageName: 'nextra/components',\n    isFlattened: true\n  },\n  {\n    name: 'Search',\n    packageName: 'nextra/components',\n    isFlattened: false,\n    groupKeys:\n      \"Omit<ComboboxInputProps, 'className' | 'onChange' | 'onFocus' | 'onBlur' | 'value' | 'placeholder'>\"\n  },\n  { type: 'separator', title: 'Content Components', name: '_2' },\n  {\n    name: 'Bleed',\n    packageName: 'nextra/components',\n    groupKeys: 'HTMLAttributes<HTMLDivElement>'\n  },\n  {\n    name: 'Callout',\n    packageName: 'nextra/components',\n    groupKeys: 'HTMLAttributes<HTMLDivElement>'\n  },\n  {\n    // TODO: add\n    // <APIDocs componentName=\"Cards.Card\" />\n    name: 'Cards',\n    packageName: 'nextra/components',\n    groupKeys: 'HTMLAttributes<HTMLDivElement>'\n  },\n  {\n    // TODO: add\n    // <APIDocs componentName=\"FileTree.Folder\" />\n    // <APIDocs componentName=\"FileTree.File\" />\n    name: 'FileTree',\n    packageName: 'nextra/components',\n    groupKeys: 'HTMLAttributes<HTMLUListElement>'\n  },\n  {\n    name: 'Steps',\n    packageName: 'nextra/components',\n    groupKeys: 'HTMLAttributes<HTMLDivElement>'\n  },\n  {\n    // TODO: add\n    // <APIDocs componentName=\"Table.Tr\" groupKeys=\"ComponentProps<'tr'>\" />\n    // <APIDocs componentName=\"Table.Th\" groupKeys=\"ComponentProps<'th'>\" />\n    // <APIDocs componentName=\"Table.Td\" groupKeys=\"ComponentProps<'td'>\" />\n    name: 'Table',\n    packageName: 'nextra/components',\n    groupKeys: 'HTMLAttributes<HTMLTableElement>'\n  },\n  { name: 'Tabs', packageName: 'nextra/components' },\n  { type: 'separator', title: 'Other Components', name: '_3' },\n  { name: 'MDXRemote', packageName: 'nextra/mdx-remote' },\n  { name: 'Playground', packageName: 'nextra/components' },\n  { name: 'TSDoc', packageName: 'nextra/tsdoc' }\n]\n\nconst routes = API_REFERENCE.filter(\n  (o): o is ComponentApiReference => !('type' in o)\n)\n\nexport const generateStaticParams = () =>\n  routes.map(o => ({ name: o.name.toLowerCase() }))\n\n// @ts-expect-error -- fixme\nexport const pageMap: (MdxFile & { title: string })[] = API_REFERENCE.map(o =>\n  'type' in o\n    ? o\n    : {\n        name: o.name.toLowerCase(),\n        route: `/docs/built-ins/${o.name.toLowerCase()}`,\n        title:\n          o.name === 'TSDoc' ? (\n            <span className=\"badge-new\">{o.name}</span>\n          ) : (\n            o.name\n          )\n      }\n)\n\nconst Wrapper = getMDXComponents().wrapper\n\nasync function getReference(props: PageProps) {\n  const params = await props.params\n  const apiRefIndex = routes.findIndex(\n    o => o.name.toLowerCase() === params.name\n  )\n  const apiRef = routes[apiRefIndex]\n  if (!apiRef) {\n    throw new Error(`API reference not found for \"${params.name}\"`)\n  }\n  const { name, packageName, groupKeys, isFlattened } = apiRef\n  const result = groupKeys\n    ? `Omit<MyProps, keyof ${groupKeys}> & { '...props': ${groupKeys} }>`\n    : 'MyProps'\n  const code =\n    apiRef.code ??\n    `\nimport type { ComponentProps, HTMLAttributes } from 'react'\nimport type { ComboboxInputProps } from '../packages/nextra/node_modules/@headlessui/react'\nimport { ${name} as MyComponent } from '${packageName}'\n\ntype MyProps = ComponentProps<typeof MyComponent>\ntype $ = ${result}\n\nexport default $`\n  const flattened = isFlattened !== false\n  const fcPropsDefinition = generateDefinition({ code, flattened })\n  const {\n    // @ts-expect-error -- exist\n    signatures: _signatures,\n    ...fcDefinition\n  } = generateDefinition({\n    code: `export { ${name} as default } from '${packageName}'`,\n    flattened\n  })\n  const definition = {\n    ...fcPropsDefinition,\n    ...fcDefinition\n  }\n  const res = await generateApiReference(apiRef, {\n    title: 'Component',\n    subtitle: 'Props',\n    definition\n    //     bottomMdxContent: `<Callout type=\"default\">\n    // **Tip for TypeScript users:**<br/>\n    // You can retrieve the props type for the \\`<${name}>\\` component using \\`React.ComponentProps<typeof ${name}>\\`.\n    // </Callout>`\n  })\n  const filePath =\n    fcDefinition.filePath &&\n    path\n      .relative('..', fcDefinition.filePath)\n      .replace(/\\.d.ts$/, '.tsx')\n      .replace('/dist/', '/src/')\n  // Add edit on GitHub link to points on a source file\n  res.metadata.filePath = `https://github.com/shuding/nextra/tree/main/${filePath}`\n\n  return res\n}\n\nexport async function generateMetadata(props: PageProps) {\n  const { metadata } = await getReference(props)\n  return metadata\n}\n\ntype PageProps = Readonly<{\n  params: Promise<{ name: string }>\n}>\n\nconst Page: FC<PageProps> = async props => {\n  const {\n    default: MDXContent,\n    toc,\n    metadata,\n    sourceCode\n  } = await getReference(props)\n  return (\n    <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>\n      <MDXContent />\n    </Wrapper>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "docs/app/docs/built-ins/page.mdx",
    "content": "---\nasIndexPage: true\nsidebarTitle: Built-In Components\n---\n\nimport {\n  CardsIcon,\n  FolderTreeIcon,\n  IdCardIcon,\n  OneIcon,\n  TableIcon\n} from '@components/icons'\nimport { Callout } from 'nextra/components'\nimport { GitHubWarningIcon } from 'nextra/icons'\nimport { OverviewPage } from '../../_components/overview-page'\nimport { getEnhancedPageMap } from '../../../components/get-page-map'\n\n# Built-Ins\n\n<Callout type=\"info\">\n  This API reference is automatically generated from the catch-all route file\n  `/docs/built-ins/[name]/page.tsx` using the new [Nextra `<TSDoc />`\n  component](/docs/built-ins/tsdoc).\n</Callout>\n\nNextra includes a couple of built-in components that you can use to better style\nyour content:\n\n{/* `pageMap` prop will be removed once Nextra will add dynamic routes in pageMap */}\n\n<OverviewPage\n  filePath={metadata.filePath}\n  pageMap={\n    (await getEnhancedPageMap())\n      .find(o => o.name === 'docs')\n      .children.find(o => o.name === 'built-ins').children\n  }\n  icons={{\n    WarningIcon: GitHubWarningIcon,\n    IdCardIcon,\n    FolderTreeIcon,\n    OneIcon,\n    TableIcon,\n    CardsIcon\n  }}\n/>\n"
  },
  {
    "path": "docs/app/docs/custom-theme/old.mdx",
    "content": "### Render metadata for the active page\n\n> [!WARNING]\n>\n> Docs from Nextra 3\n\nOther than `children`, some other useful props are passed to the theme layout\ntoo. With the `pageOpts` props, the theme can access the page's meta\ninformation.\n\nFor example, let's implement these features:\n\n- Render the page title in `<title>`\n- Show a simple Table of Contents via MDX `<Wrapper>` component\n- Add a meta tag for `og:image` via the front matter\n\n```tsx filename=\"theme.tsx\" /pageOpts/\nimport Head from 'next/head'\nimport type { NextraThemeLayoutProps } from 'nextra'\nimport { MDXProvider } from 'nextra/mdx'\n\nexport default function Layout({ children, pageOpts }: NextraThemeLayoutProps) {\n  const { title, frontMatter } = pageOpts\n\n  return (\n    <>\n      <Head>\n        <title>{title}</title>\n        <meta name=\"og:image\" content={frontMatter.image} />\n      </Head>\n      <MDXProvider components={{ wrapper: MyWrapper }}>{children}</MDXProvider>\n    </>\n  )\n}\n\nfunction MyWrapper({ children, toc }) {\n  return (\n    <>\n      <h1>My Theme</h1>\n      Table of Contents:\n      <ul>\n        {toc.map(heading => (\n          <li key={heading.value}>{heading.value}</li>\n        ))}\n      </ul>\n      <div style={{ border: '1px solid' }}>{children}</div>\n    </>\n  )\n}\n```\n\n### Use page map of the entire site\n\n> [!WARNING]\n>\n> Docs from Nextra 3\n\nNow, if you want to render something like a sidebar or a navigation bar, which\nrelies on information of not only the current page but also other pages, you can\nuse the `pageMap` value.\n\nFor example, we can render a simple navigation list with all the pages in the\ntop level:\n\n```tsx filename=\"theme.tsx\" /pageMap/\nimport Link from 'next/link'\nimport type { NextraThemeLayoutProps } from 'nextra'\n\nexport default function Layout({ children, pageOpts }: NextraThemeLayoutProps) {\n  const { pageMap } = pageOpts\n\n  return (\n    <div>\n      <h1>My Theme</h1>\n      {pageMap.map(item => {\n        if ('route' in item && !('children' in item)) {\n          return (\n            <Link key={item.name} href={item.route}>\n              {item.route}\n            </Link>\n          )\n        }\n      })}\n      <div style={{ border: '1px solid' }}>{children}</div>\n    </div>\n  )\n}\n```\n\nThere are other item kinds such as `Folder` (for directories) and `Meta` (for\n`_meta` files). All the items are typed so you can easily know the properties.\n"
  },
  {
    "path": "docs/app/docs/custom-theme/page.mdx",
    "content": "import { ExampleCode } from 'components/example-code'\nimport { Steps } from 'nextra/components'\nimport OldDocs from './old.mdx'\n\n# Custom Theme\n\nA theme in Nextra works like a layout, that will be rendered as a wrapper for\nall pages. This docs will walk you through the process of creating a custom\ntheme.\n\n> [!NOTE]\n>\n> Source code for the following custom theme can be found\n> [here](https://github.com/shuding/nextra/tree/main/examples/custom-theme).\n\n## Create a custom theme\n\n<Steps>\n### Create a root layout\n\n<ExampleCode example=\"custom-theme\" filePath=\"app/layout.tsx\" />\n\n### Create [`mdx-components` file](/docs/file-conventions/mdx-components-file)\n\n<ExampleCode\n  example=\"custom-theme\"\n  filePath=\"mdx-components.jsx\"\n  metadata=\"/toc/2 {9}\"\n/>\n<ExampleCode\n  example=\"custom-theme\"\n  filePath=\"app/_components/toc.tsx\"\n  metadata=\"/toc/\"\n/>\n\n### Create a basic theme\n\nYou can now start working on your theme! Create the `nextra-theme.tsx` file, it\naccepts a `children` prop, which is the MDX content of the current page, and\nwraps some other elements around the content:\n\n<ExampleCode\n  example=\"custom-theme\"\n  filePath=\"app/_components/nextra-theme.tsx\"\n  metadata=\"/children/\"\n/>\n\n### Create navbar and footer\n\n<ExampleCode example=\"custom-theme\" filePath=\"app/_components/footer.tsx\" />\n<ExampleCode\n  example=\"custom-theme\"\n  filePath=\"app/_components/navbar.tsx\"\n  metadata=\"/topLevelNavbarItems/\"\n/>\n\n### Create sidebar\n\n<ExampleCode\n  example=\"custom-theme\"\n  filePath=\"app/_components/sidebar.tsx\"\n  metadata=\"/docsDirectories/\"\n/>\n\n### Add first MDX page\n\nAfter creating the theme, you can simply add a MDX file as `app/page.mdx` and\nsee the result:\n\n![Custom theme](/assets/docs/custom-theme.png)\n\n<br />\n\nInside your theme layout, you can use CSS imports or other ways to style it.\nNext.js hooks such as `usePathname` are also available.\n\n{process.env.NODE_ENV !== 'production' && <OldDocs />}\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/docs-theme/api/page.mdx",
    "content": "# API\n\n## `useThemeConfig` hook\n\nThe `useThemeConfig` hook returns values of your\n[theme configuration](/docs/docs-theme/theme-configuration) and is made to\ndynamically configure your project.\n\n```js\nimport { useThemeConfig } from 'nextra-theme-docs'\n```\n\n<APIDocs\n  code=\"export type { useThemeConfig as default } from 'nextra-theme-docs'\"\n  flattened\n/>\n\n## `useConfig` hook\n\n```js\nimport { useConfig } from 'nextra-theme-docs'\n```\n\nThe `useConfig` hook returns data from your current page context.\n\n<APIDocs\n  code=\"export type { useConfig as default } from 'nextra-theme-docs'\"\n  flattened\n/>\n"
  },
  {
    "path": "docs/app/docs/docs-theme/built-ins/footer/page.mdx",
    "content": "---\nsidebarTitle: Footer\n---\n\nimport { ToggleVisibilitySection } from 'components/toggle-visibility-section'\n\n# Footer Component\n\nThe footer area of the website. You can specify content for your default footer.\n\n## Props\n\n<APIDocs\n  componentName=\"Footer\"\n  packageName=\"nextra-theme-docs\"\n  groupKeys=\"ComponentProps<'footer'>\"\n/>\n\n## Example\n\nYou can add content, such as copyright information by passing it as `children`\nof the `Footer` component:\n\n```jsx filename=\"app/layout.jsx\"\nimport { Footer, Layout } from 'nextra-theme-docs'\n\nexport default function MyLayout({ children, ...props }) {\n  return (\n    <Layout>\n      {children}\n      <Footer>\n        MIT {new Date().getFullYear()} ©{' '}\n        <a href=\"https://nextra.site\" target=\"_blank\">\n          Nextra\n        </a>\n        .\n      </Footer>\n      {children}\n    </Layout>\n  )\n}\n```\n\n<ToggleVisibilitySection element=\"`<Footer>`\" property=\"footer\" />\n"
  },
  {
    "path": "docs/app/docs/docs-theme/built-ins/layout/old.mdx",
    "content": "## MDX Components [!TODO]\n\nProvide custom [MDX components](https://mdxjs.com/table-of-components) to render\nthe content. For example, you can use a custom `pre` component to render code\nblocks.\n"
  },
  {
    "path": "docs/app/docs/docs-theme/built-ins/layout/page.mdx",
    "content": "---\nsidebarTitle: Layout\n---\n\nimport { ToggleVisibilitySection } from 'components/toggle-visibility-section'\n\nexport function PartialTSDoc({ flattened, props }) {\n  return (\n    <APIDocs\n      flattened={flattened}\n      code={`\nimport { Layout } from 'nextra-theme-docs'\ntype $ = Pick<React.ComponentProps<typeof Layout>, ${props.map(prop => JSON.stringify(prop)).join('|')}>\nexport default $`}\n    />\n  )\n}\n\n# Layout Component\n\nThe theme is configured with the `<Layout>` component. You should pass your\nconfig options as Layout's `props`, for example:\n\n```jsx filename=\"app/layout.jsx\" {8-9}\nimport { Layout } from 'nextra-theme-docs'\n\nexport default function MyLayout({ children, ...props }) {\n  return (\n    <html lang=\"en\">\n      <body>\n        <Layout\n          sidebar={{ autoCollapse: true }}\n          docsRepositoryBase=\"https://github.com/shuding/nextra/tree/main/docs\"\n        >\n          {children}\n        </Layout>\n      </body>\n    </html>\n  )\n}\n```\n\nDetailed information for each option is listed below.\n\n## Props\n\n## Page Map\n\n<PartialTSDoc props={['pageMap']} />\n\n## Banner\n\n<PartialTSDoc props={['banner']} />\n\n## Navbar\n\n<PartialTSDoc props={['navbar']} />\n\n<ToggleVisibilitySection element=\"`<Navbar>`\" property=\"navbar\" />\n\n## Footer\n\n<PartialTSDoc props={['footer']} />\n\n<ToggleVisibilitySection element=\"`<Footer>`\" property=\"footer\" />\n\n## Search\n\n<PartialTSDoc props={['search']} />\n\n## Docs Repository\n\nSet the repository URL of the documentation. It's used to generate the\n\"[Edit this page](#edit-link)\" link, the \"[Feedback](#feedback-link)\" link and\n\"[Report of broken link](./not-found)\" on\n[not found page](https://nextjs.org/docs/app/api-reference/file-conventions/not-found).\n\n<PartialTSDoc props={['docsRepositoryBase']} />\n\n### Specify a Path\n\nIf the documentation is inside a monorepo, a subfolder, or a different branch of\nthe repository, you can simply set the `docsRepositoryBase` to the root path of\nthe `app/` (App Router) folder of your docs. For example:\n\n```jsx filename=\"app/layout.jsx\"\n<Layout docsRepositoryBase=\"https://github.com/shuding/nextra/tree/main/docs\">\n  {children}\n</Layout>\n```\n\nThen Nextra will automatically generate the correct file path for all pages.\n\n## Dark Mode and Themes\n\nCustomize the theme behavior of the website.\n\n<PartialTSDoc props={['darkMode', 'nextThemes']} />\n\nimport Old from './old.mdx'\n\n{process.env.NODE_ENV !== 'production' && <Old />}\n\n## Edit Link\n\nShow an \"Edit this page\" link on the page that points to the file URL on GitHub\n(or other places).\n\n<PartialTSDoc props={['editLink']} />\n\n> [!TIP]\n>\n> To disable it, you can set `editLink` to `null`.\n\n## Feedback Link\n\nThe built-in feedback link provides a way for users to submit feedback about the\ndocumentation.\n\n<PartialTSDoc props={['feedback']} flattened />\n\n> [!TIP]\n>\n> To disable it, you can set `feedback.content` to `null`.\n\n## I18n\n\n<PartialTSDoc props={['i18n']} />\n\n## Last Updated Date\n\nShow the last updated date of a page. It's useful for showing the freshness of\nthe content.\n\n<PartialTSDoc props={['lastUpdated']} />\n\n<ToggleVisibilitySection element=\"last update date\" property=\"timestamp\" />\n\n## Navigation\n\nShow previous and next page links on the bottom of the content. It's useful for\nnavigating between pages.\n\n<PartialTSDoc props={['navigation']} />\n\n![Navigation](/assets/docs/navigation.png)\n\n```jsx filename=\"app/layout.jsx\"\n<Layout\n  navigation={{\n    prev: true,\n    next: true\n  }}\n>\n  {children}\n</Layout>\n```\n\nThe above is also equivalent to `navigation: true{:js}`.\n\n<ToggleVisibilitySection element=\"navigation\" property=\"pagination\" />\n\n## Sidebar\n\n<PartialTSDoc props={['sidebar']} flattened />\n\n### Menu Collapse Level\n\nBy default, the sidebar menu is collapsed at level `2`. You can change it by\nsetting `sidebar.defaultMenuCollapseLevel` to a different number. For example,\nwhen set to `1`, every folder will be collapsed by default and when set to\n`Infinity`, all nested folders will be expanded by default.\n\nIf `sidebar.autoCollapse` is set to `true`, then all folders that do not contain\nan active/focused route will automatically collapse up to the level set by\n`sidebar.defaultMenuCollapseLevel`. e.g. if `defaultMenuCollapseLevel` is `2`,\nthen top-level folders will not auto-collapse.\n\n### Customize Sidebar Content\n\nTogether with the [Separators](/docs/docs-theme/page-configuration#separators)\nitem, you can customize how the sidebar content is rendered by using JSX\nelements:\n\n```jsx filename=\"_meta.jsx\" {5-10}\nexport default {\n  index: 'Intro',\n  '--': {\n    type: 'separator',\n    title: (\n      <div className=\"flex items-center gap-2\">\n        <MyLogo />\n        {children}\n      </div>\n    )\n  },\n  frameworks: 'JS Frameworks & Libs',\n  about: 'About'\n}\n```\n\n![Customized Sidebar](/assets/docs/sidebar-customized.png)\n\n<ToggleVisibilitySection element=\"`<Sidebar>`\" property=\"sidebar\" />\n\n### Customize Sidebar with Front Matter\n\nIn addition, you can customize the sidebar title using the `sidebarTitle`\nproperty in your front matter:\n\n```mdx filename=\"getting-started.mdx\"\n---\nsidebarTitle: Getting Started 🚀\n---\n```\n\nThe priority of the sidebar title is as follows:\n\n1. A non-empty title from the `_meta` file.\n1. `sidebarTitle` in the front matter.\n1. `title` in the front matter.\n1. The title derived from the first `h1` Markdown heading (e.g.\n   `# Dima Machina`).\n1. If none of the above are available, it falls back to the filename of the\n   page, formatted according to [The Chicago Manual of Style](https://title.sh).\n\n## Theme Switch\n\n<PartialTSDoc props={['themeSwitch']} />\n\nYou are able to customize the option names for localization or other purposes:\n\n```jsx filename=\"app/layout.jsx\"\n<Layout\n  themeSwitch={{\n    dark: 'Темный',\n    light: 'Светлый',\n    system: 'Системный'\n  }}\n>\n  {children}\n</Layout>\n```\n\n## Table of Contents (TOC)\n\nShow a table of contents on the right side of the page. It's useful for\nnavigating between headings.\n\n<PartialTSDoc props={['toc']} flattened />\n\n### Floating TOC\n\nWhen enabled, the TOC will be displayed on the right side of the page, and it\nwill be sticky when scrolling. If it's disabled, the TOC will be displayed\ndirectly on the page sidebar.\n\n<ToggleVisibilitySection element=\"`<TOC>`\" property=\"toc\" />\n"
  },
  {
    "path": "docs/app/docs/docs-theme/built-ins/navbar/page.mdx",
    "content": "---\nsidebarTitle: Navbar\n---\n\nimport { ToggleVisibilitySection } from 'components/toggle-visibility-section'\nimport { generateTsFromZod } from 'nextra/tsdoc'\n\n# Navbar Component\n\n## Props\n\n<APIDocs componentName=\"Navbar\" packageName=\"nextra-theme-docs\" />\n\n### Logo\n\nThe logo of the website rendered on the navbar.\n\n<figure>\n  <>![Customized Logo](/assets/docs/logo.png)</>\n  {/* prettier-ignore */}\n  <figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-yrlccm?file=theme.config.jsx)</figcaption>\n</figure>\n\n```jsx filename=\"app/layout.jsx\"\n<Navbar\n  logo={\n    <>\n      <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n        <path\n          fill=\"currentColor\"\n          d=\"M14.683 14.828a4.055 4.055 0 0 1-1.272.858a4.002 4.002 0 0 1-4.875-1.45l-1.658 1.119a6.063 6.063 0 0 0 1.621 1.62a5.963 5.963 0 0 0 2.148.903a6.035 6.035 0 0 0 3.542-.35a6.048 6.048 0 0 0 1.907-1.284c.272-.271.52-.571.734-.889l-1.658-1.119a4.147 4.147 0 0 1-.489.592z M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10s10-4.486 10-10S17.514 2 12 2zm0 2c2.953 0 5.531 1.613 6.918 4H5.082C6.469 5.613 9.047 4 12 4zm0 16c-4.411 0-8-3.589-8-8c0-.691.098-1.359.264-2H5v1a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2h2a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2v-1h.736c.166.641.264 1.309.264 2c0 4.411-3.589 8-8 8z\"\n        />\n      </svg>\n      <span style={{ marginLeft: '.4em', fontWeight: 800 }}>\n        My Cool Project\n      </span>\n    </>\n  }\n/>\n```\n\n### Project link\n\nShow a button that links to your project's homepage on the navbar. By default,\nit links to Nextra's GitHub repository.\n\nYou can configure `projectLink` and `projectIcon` to customize the project link,\nfor example make it link to your GitLab repository:\n\n![Project link](/assets/docs/project-link.png)\n\n```jsx filename=\"app/layout.jsx\"\n<Navbar\n  projectLink=\"https://gitlab.com/inkscape/inkscape\"\n  projectIcon={\n    <svg width=\"24\" height=\"24\" fill=\"currentColor\" viewBox=\"0 0 256 256\">\n      <path d=\"m231.9 169.8l-94.8 65.6a15.7 15.7 0 0 1-18.2 0l-94.8-65.6a16.1 16.1 0 0 1-6.4-17.3L45 50a12 12 0 0 1 22.9-1.1L88.5 104h79l20.6-55.1A12 12 0 0 1 211 50l27.3 102.5a16.1 16.1 0 0 1-6.4 17.3Z\" />\n    </svg>\n  }\n/>\n```\n\n### Chat link\n\nShow a button that links to your project's forum or other social media on the\nnavbar.\n\nYou can configure `chatLink` and `chatIcon` to customize the chat link, for\nexample make it link to your Twitter account:\n\n```jsx filename=\"app/layout.jsx\"\n<Navbar\n  chatLink=\"https://twitter.com/shuding_\"\n  chatIcon={\n    <svg width=\"24\" height=\"24\" viewBox=\"0 0 248 204\">\n      <path\n        fill=\"currentColor\"\n        d=\"M221.95 51.29c.15 2.17.15 4.34.15 6.53 0 66.73-50.8 143.69-143.69 143.69v-.04c-27.44.04-54.31-7.82-77.41-22.64 3.99.48 8 .72 12.02.73 22.74.02 44.83-7.61 62.72-21.66-21.61-.41-40.56-14.5-47.18-35.07a50.338 50.338 0 0 0 22.8-.87C27.8 117.2 10.85 96.5 10.85 72.46v-.64a50.18 50.18 0 0 0 22.92 6.32C11.58 63.31 4.74 33.79 18.14 10.71a143.333 143.333 0 0 0 104.08 52.76 50.532 50.532 0 0 1 14.61-48.25c20.34-19.12 52.33-18.14 71.45 2.19 11.31-2.23 22.15-6.38 32.07-12.26a50.69 50.69 0 0 1-22.2 27.93c10.01-1.18 19.79-3.86 29-7.95a102.594 102.594 0 0 1-25.2 26.16z\"\n      />\n    </svg>\n  }\n/>\n```\n\n### Menu and custom links\n\nCheck out [Page Configuration](/docs/docs-theme/page-configuration#navbar-items)\nto learn how to add custom menus or links to the navbar.\n\n<ToggleVisibilitySection element=\"`<Navbar>`\" property=\"navbar\" />\n"
  },
  {
    "path": "docs/app/docs/docs-theme/built-ins/not-found/page.mdx",
    "content": "---\nsidebarTitle: NotFoundPage\n---\n\n# NotFoundPage Component\n\nOptions to configure report of broken link on not found page.\n\n## Props\n\n<APIDocs componentName=\"NotFoundPage\" packageName=\"nextra-theme-docs\" />\n\n## Example\n\n```jsx filename=\"app/not-found.jsx\"\nimport { NotFoundPage } from 'nextra-theme-docs'\n\nexport default function NotFound() {\n  return (\n    <NotFoundPage content=\"Submit an issue\" labels=\"broken-link\">\n      <h1>The page is not found</h1>\n    </NotFoundPage>\n  )\n}\n```\n"
  },
  {
    "path": "docs/app/docs/docs-theme/built-ins/page.mdx",
    "content": "---\nasIndexPage: true\nsidebarTitle: Built-In Components\nicon: BoxIcon\n---\n\nimport { OverviewPage } from '../../../_components/overview-page'\n\n# Built-Ins\n\n<OverviewPage filePath={metadata.filePath} />\n"
  },
  {
    "path": "docs/app/docs/docs-theme/page.mdx",
    "content": "---\nasIndexPage: true\nsidebarTitle: Docs Theme\n---\n\n# Nextra Docs Theme\n\nimport { BoxIcon, ChevronRightIcon } from '@components/icons'\nimport { OverviewPage } from '../../_components/overview-page'\n\n<OverviewPage\n  filePath={metadata.filePath}\n  icons={{\n    ChevronRightIcon,\n    BoxIcon\n  }}\n/>\n"
  },
  {
    "path": "docs/app/docs/docs-theme/start/page.mdx",
    "content": "---\nsidebarTitle: Get Started\nicon: ChevronRightIcon\n---\n\nimport InstallNextraTheme from '@components/install-nextra-theme.mdx'\nimport ReadyToGo from '@components/ready-to-go.mdx'\n\nimport { Steps } from 'nextra/components'\n\n# Docs Theme\n\nNextra Docs Theme is a theme that includes almost everything you need to build a\nmodern documentation website. It includes:\n\n- a top navigation bar\n- a search bar\n- a pages sidebar\n- a table of contents (TOC)\n- and other built-in components\n\n> [!TIP]\n>\n> This website itself is built with the Nextra Docs Theme.\n\n## Start as a New Project\n\n<Steps>\n### Install\n\nTo create a Nextra Docs site manually, you have to install **Next.js**,\n**React**, **Nextra**, and **Nextra Docs Theme**. In your project directory, run\nthe following command to install the dependencies:\n\n```sh npm2yarn\nnpm i next react react-dom nextra nextra-theme-docs\n```\n\n> [!NOTE]\n>\n> If you already have Next.js installed in your project, you only need to\n> install `nextra` and `nextra-theme-docs` as the add-ons.\n\n<InstallNextraTheme />\n\n```jsx filename=\"app/layout.jsx\"\nimport { Footer, Layout, Navbar } from 'nextra-theme-docs'\nimport { Banner, Head } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-map'\nimport 'nextra-theme-docs/style.css'\n\nexport const metadata = {\n  // Define your metadata here\n  // For more information on metadata API, see: https://nextjs.org/docs/app/building-your-application/optimizing/metadata\n}\n\nconst banner = <Banner storageKey=\"some-key\">Nextra 4.0 is released 🎉</Banner>\nconst navbar = (\n  <Navbar\n    logo={<b>Nextra</b>}\n    // ... Your additional navbar options\n  />\n)\nconst footer = <Footer>MIT {new Date().getFullYear()} © Nextra.</Footer>\n\nexport default async function RootLayout({ children }) {\n  return (\n    <html\n      // Not required, but good for SEO\n      lang=\"en\"\n      // Required to be set\n      dir=\"ltr\"\n      // Suggested by `next-themes` package https://github.com/pacocoursey/next-themes#with-app\n      suppressHydrationWarning\n    >\n      <Head\n      // ... Your additional head options\n      >\n        {/* Your additional tags should be passed as `children` of `<Head>` element */}\n      </Head>\n      <body>\n        <Layout\n          banner={banner}\n          navbar={navbar}\n          pageMap={await getPageMap()}\n          docsRepositoryBase=\"https://github.com/shuding/nextra/tree/main/docs\"\n          footer={footer}\n          // ... Your additional layout options\n        >\n          {children}\n        </Layout>\n      </body>\n    </html>\n  )\n}\n```\n\n<ReadyToGo />\n\n</Steps>\n\nSee the [File Conventions](/docs/file-conventions) for more details on\norganizing your documentation structure, and check out the\n[Layout Component](/docs/docs-theme/built-ins/layout) for configuring the docs\nsite's theme.\n"
  },
  {
    "path": "docs/app/docs/file-conventions/content-directory/page.mdx",
    "content": "---\nicon: FolderIcon\nsidebarTitle: content\ndescription:\n  The `content` directory in Nextra allows you to organize your Markdown files\n  without adhering to the `page` filename convention, simplifying the migration\n  from Next.js `pages` router.\n---\n\nimport fs from 'node:fs/promises'\nimport { compileMdx } from 'nextra/compile'\nimport { FileTree, Steps } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\nexport async function MDXPathPage() {\n  const filename = '[[...mdxPath]]/page.jsx'\n  const rawMdx = `~~~jsx filename=\"${filename}\" showLineNumbers\n${(await fs.readFile(`../examples/docs/src/app/docs/${filename}`, 'utf8')).trimEnd()}\n~~~`\n  const rawJs = await compileMdx(rawMdx, { defaultShowCopyCode: true })\n  return <MDXRemote compiledSource={rawJs} />\n}\n\n# `content` Directory\n\nThe `content` directory is designed to:\n\n1. Migrate your existing Next.js `pages` router with minimal changes, you just\n   need to rename your `pages` directory to `content`.\n1. Avoid having `page` filename convention, e.g. `app/configuration/page.mdx` ->\n   `content/configuration.mdx`\n\n## Setup\n\n<Steps>\n\n### Create your first MDX page as `content/index.mdx`:\n\n```mdx filename=\"content/index.mdx\"\n# Welcome to Nextra\n\nHello, world!\n```\n\n> [!TIP]\n>\n> You can keep `content` directory in root of your project, or in\n> [`src` directory](./src-directory).\n\n### Set `contentDirBasePath` option in `next.config` file (_optional_)\n\nIf you want to serve your content from a different path, you can set\n`contentDirBasePath` option:\n\n```js filename=\"next.config.mjs\" {4}\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  contentDirBasePath: '/docs' // Or even nested e.g. `/docs/advanced`\n})\n```\n\n### Add `[[...mdxPath]]/page.jsx` file\n\nPlace this file in `app` directory with the following content:\n\n<MDXPathPage />\n\nyou should get the following structure:\n\n<FileTree>\n  <FileTree.Folder name=\"app\" open>\n    <FileTree.File name=\"layout.jsx\" />\n    <FileTree.Folder name=\"[[...mdxPath]]\" open active>\n      <FileTree.File name=\"page.jsx\" active />\n    </FileTree.Folder>\n  </FileTree.Folder>\n  <FileTree.Folder name=\"content\" open>\n    <FileTree.File name=\"index.mdx\" />\n  </FileTree.Folder>\n  <FileTree.File name=\"next.config.js\" />\n  <FileTree.File name=\"package.json\" />\n</FileTree>\n\n> [!TIP]\n>\n> Consider the single catch-all route `[[...mdxPath]]/page.jsx` as a gateway to\n> your `content` directory.\n>\n> If you set `contentDirBasePath` option in `next.config` file, you should put\n> `[[...mdxPath]]/page.jsx` in the corresponding directory.\n\n### You are ready to go!\n\n> [!NOTE]\n>\n> Many existing solutions such as\n> [Refreshing the Next.js App Router When Your Markdown Content Changes](https://steveruiz.me/posts/nextjs-refresh-content)\n> rely on extra dependencies like `concurrently` and `ws`. These approaches\n> include\n> [Dan Abramov workaround with `<AutoRefresh>` component and dev web socket server](https://github.com/hashicorp/next-remote-watch/issues/42#issuecomment-1794052655).\n>\n> Nextra's `content` directory delivers a streamlined solution right out of the\n> box:\n>\n> - you don't need to install unnecessary dependencies\n> - you don't need to restart your server on changes in `content` directory\n> - hot reloading works out of the box\n> - you can use `import` statements in MDX files and\n>   [static images](/docs/guide/image#static-image) works as well\n>\n> Checkout Nextra's\n> [docs website](https://github.com/shuding/nextra/tree/main/examples/docs) and\n> [i18n website example](https://github.com/shuding/nextra/tree/main/examples/swr-site).\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/file-conventions/mdx-components-file/page.mdx",
    "content": "---\nicon: MdxIcon\nsidebarTitle: mdx-components.js\ndescription:\n  The `mdx-components` file in Nextra is essential for customizing styles via\n  the `useMDXComponents` function, allowing you to define and override MDX\n  components globally.\n---\n\n# `mdx-components.js` File\n\nThe `mdx-components` file is **required**, you use it to customize styles via\n`useMDXComponents` function.\n\n## Example\n\nThe `mdx-components.js` file must export\n[a single function named `useMDXComponents`](/api/usemdxcomponents).\n\n```ts filename=\"mdx-components.js\"\nimport { useMDXComponents as getThemeComponents } from 'nextra-theme-docs' // nextra-theme-blog or your custom theme\n\n// Get the default MDX components\nconst themeComponents = getThemeComponents()\n\n// Merge components\nexport function useMDXComponents(components) {\n  return {\n    ...themeComponents,\n    ...components\n  }\n}\n```\n\n## Errors\n\n### Module not found: Can't resolve `'next-mdx-import-source-file'`\n\nTo fix this, update the `turbopack.resolveAlias` section in your `next.config`\nfile:\n\n> [!NOTE]\n>\n> - If you're using Next.js < 15.3, use `experimental.turbopack.resolveAlias`\n> - If you're using Next.js ≥ 15.3, use `turbopack.resolveAlias`\n\n```diff filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\nconst withNextra = nextra()\n\nexport default withNextra({\n+ turbopack: {\n+   resolveAlias: {\n+     // Path to your `mdx-components` file with extension\n+     'next-mdx-import-source-file': './src/mdx-components.tsx'\n+   }\n+ }\n})\n```\n\n> [!TIP]\n>\n> - You can keep `mdx-components` file in root of your project, or in\n>   [`src` directory](./src-directory).\n> - The `.js`, `.jsx`, or `.tsx` file extensions can be used for\n>   `mdx-components` file.\n> - When importing `useMDXComponents`, alias it as `getMDXComponents` to avoid a\n>   false positive error from the ESLint React Hooks plugin.\n>\n> ```bash filename=\"react-hooks/rules-of-hooks\"\n> React Hook \"useMDXComponents\" cannot be called at the top level.\n> React Hooks must be called in a React function component or a custom React Hook function.\n> ```\n"
  },
  {
    "path": "docs/app/docs/file-conventions/meta-file/page.mdx",
    "content": "---\nicon: FileIcon\nsidebarTitle: _meta.js\ndescription:\n  The `_meta` file in Nextra allows you to customize page sidebar titles, order,\n  and theme visibility, enhancing site organization and user experience.\n---\n\nimport { ContentAndAppFileTee } from 'components/content-and-app-file-tree'\nimport { Video } from 'components/video'\nimport { FileTree } from 'nextra/components'\nimport { generateTsFromZod } from 'nextra/tsdoc'\nimport { pageThemeSchema } from 'private-next-root-dir/../packages/nextra/dist/server/schemas'\n\nexport function Block({ children }) {\n  return (\n    <div className=\"flex gap-2 *:last:w-full *:last:min-w-0 max-lg:flex-wrap\">\n      {children}\n    </div>\n  )\n}\n\n# `_meta.js` File\n\nIn Nextra, the site and individual page structure can be configured via the\nco-located `_meta` files. Those configurations affect the overall layout of your\nNextra theme, especially the navigation bar and the sidebar:\n\n<figure>\n  <>![Example of Nextra Theme Docs](/assets/routing@1x.png)</>\n  {/* prettier-ignore */}\n  <figcaption>Example: [Nextra Docs Theme](/docs/docs-theme) has sidebar and navbar generated automatically from Markdown files.</figcaption>\n</figure>\n\n{/* It's very common to customize each page's title, rather than just relying on filenames. Having a page titled \"Index\" lacks clarity. It is preferable to assign a meaningful title that accurately represents the content, such as \"Home\". */}\n{/* That's where `_meta` files comes in. You can have an `_meta` file in each directory, and it will be used to override the default configuration of each page. */}\n\n## Organizing files\n\nNextra allows you to organize files in the following ways:\n\n- **In Next.js'\n  [`app` directory](https://nextjs.org/docs/app/getting-started/project-structure#top-level-folders):**<br />Nextra\n  gathers all `page` files, including\n  [`page.md` and `page.mdx` files](/docs/file-conventions/page-file) as well as\n  `_meta` files.\n\n- **In Nextra's\n  [`content` directory](/docs/file-conventions/content-directory):**<br/>Nextra\n  collects all `.md` and `.mdx` files, along with `_meta` files.\n\nBelow the same file-based routing structure is represented for `content` and\n`app`-only directories:\n\n<ContentAndAppFileTee>\n  <FileTree.Folder name=\"about\" defaultOpen>\n    <FileTree.File name=\"_meta.js\" active />\n    <FileTree.File name=\"index.mdx\" />\n    <FileTree.File name=\"legal.md\" />\n  </FileTree.Folder>\n  <FileTree.File name=\"_meta.js\" active />\n  <FileTree.File name=\"contact.md\" />\n  <FileTree.File name=\"index.mdx\" />\n</ContentAndAppFileTee>\n\n> [!NOTE]\n>\n> You can combine both organizational ways for your project:\n>\n> - [x] the `content` directory with `.mdx` files\n> - [x] the `app` directory with `page` files\n\n### `pageMap` structure\n\nAfterward, Nextra generates a `pageMap` array containing information about your\nentire site's routes and directories structure. Features such as the navigation\nbar and sidebar can be generated based on the `pageMap` information.\n\nThe generated `pageMap` will be:\n\n```jsonc filename=\"pageMap\" copy=false\n[\n  // content/_meta.js\n  { \"data\": {} },\n  {\n    // content/index.mdx\n    \"name\": \"index\",\n    \"route\": \"/\",\n    \"title\": \"Index\",\n    \"frontMatter\": {}\n  },\n  {\n    // content/contact.md\n    \"name\": \"contact\",\n    \"route\": \"/contact\",\n    \"title\": \"Contact\",\n    \"frontMatter\": {}\n  },\n  {\n    // content/about\n    \"name\": \"about\",\n    \"route\": \"/about\",\n    \"title\": \"About\",\n    \"children\": [\n      // content/about/_meta.js\n      { \"data\": {} },\n      {\n        // content/about/index.mdx\n        \"name\": \"index\",\n        \"route\": \"/about\",\n        \"title\": \"Index\",\n        \"frontMatter\": {}\n      },\n      {\n        // content/about/legal.md\n        \"name\": \"legal\",\n        \"route\": \"/about/legal\",\n        \"title\": \"Legal\",\n        \"frontMatter\": {}\n      }\n    ]\n  }\n]\n```\n\nAnd the global `pageMap` will be imported to each page by Nextra. Then,\nconfigured theme will render the actual UI with that `pageMap`.\n\n## API\n\nThe title and order of a page shown in the sidebar/navbar can be configured in\nthe `_meta` file as key-value pairs.\n\n```ts filename=\"_meta.ts\"\nimport type { MetaRecord } from 'nextra'\n\n/**\n * type MetaRecordValue =\n *  | TitleSchema\n *  | PageItemSchema\n *  | SeparatorSchema\n *  | MenuSchema\n *\n * type MetaRecord = Record<string, MetaRecordValue>\n **/\nconst meta: MetaRecord = {\n  // ...\n}\n\nexport default meta\n```\n\n### `title` type\n\nWhen specifying a `title` in `_meta` file, you can define it as either a simple\nstring or a JSX element.\n\n```ts copy=false\ntype TitleSchema = string | ReactElement\n```\n\nFor the below file structure:\n\n<ContentAndAppFileTee className=\"shrink-0\">\n  <FileTree.File name=\"_meta.js\" active />\n  <FileTree.File name=\"about.mdx\" />\n  <FileTree.File name=\"contact.mdx\" />\n  <FileTree.File name=\"index.mdx\" />\n</ContentAndAppFileTee>\n\nThe following `_meta` file defines pages titles:\n\n```jsx filename=\"_meta.jsx\"\nimport { GitHubIcon } from 'nextra/icons'\n\nexport default {\n  index: 'My Homepage',\n  // You can use JSX elements to change the look of titles in the sidebar, e.g. insert icons\n  contact: (\n    <Italic className=\"my-class\">\n      <GitHubIcon height=\"20\" />\n      Contact Us\n    </Italic>\n  ),\n  about: {\n    // Alternatively, you can set title with `title` property\n    title: 'About Us'\n    // ... and provide extra configurations\n  }\n}\n\n// Custom component for italicized text\nfunction Italic({ children, ...props }) {\n  return <i {...props}>{children}</i>\n}\n```\n\n### Pages\n\nIn `_meta` file you can define how the pages are shown in the sidebar, e.g. for\nthe following file structure:\n\n<Block>\n<ContentAndAppFileTee className='shrink-0'>\n  <FileTree.File name=\"_meta.js\" active />\n  <FileTree.File name=\"about.mdx\" />\n  <FileTree.File name=\"contact.mdx\" />\n  <FileTree.File name=\"index.mdx\" />\n</ContentAndAppFileTee>\n```js filename=\"_meta.js\" copy=false\nexport default {\n  index: 'My Homepage',\n  contact: 'Contact Us',\n  about: 'About Us'\n}\n```\n</Block>\n\n> [!NOTE]\n>\n> If any routes are not listed in the `_meta` file, they will be appended to the\n> end of the sidebar and sorted alphabetically (except for `index` key which\n> comes first if it's not specified in `_meta` file).\n\n```ts\ntype PageItemSchema = {\n  type: 'page' | 'doc' // @default 'doc'\n  display: 'normal' | 'hidden' | 'children' // @default 'normal'\n  title?: TitleSchema\n  theme?: PageThemeSchema\n}\n```\n\n#### `type: 'page'` option\n\nBy defining a top-level page or folder as `type: 'page'{:js}`, it will be shown\nas a special page on the navigation bar, instead of the sidebar. With this\nfeature, you can have multiple \"sub docs\", and special pages or links such as\n\"Contact Us\" that are always visible.\n\nFor example, you can have 2 docs folders `frameworks` and `fruits` in your\nproject. In your top-level `_meta` file, you can set everything as a page,\ninstead of a normal sidebar item:\n\n<Block>\n<ContentAndAppFileTee className='shrink-0'>\n  <FileTree.Folder name=\"frameworks\" defaultOpen active>\n    <FileTree.File name=\"react.mdx\" />\n    <FileTree.File name=\"svelte.mdx\" />\n    <FileTree.File name=\"vue.mdx\" />\n  </FileTree.Folder>\n  <FileTree.Folder name=\"fruits\" defaultOpen active>\n    <FileTree.File name=\"apple.mdx\" />\n    <FileTree.File name=\"banana.mdx\" />\n  </FileTree.Folder>\n  <FileTree.File name=\"_meta.js\" active />\n  <FileTree.File name=\"about.mdx\" />\n  <FileTree.File name=\"index.mdx\" />\n</ContentAndAppFileTee>\n```js filename=\"_meta.js\" copy=false {4,8,12,16}\nexport default {\n  index: {\n    title: 'Home',\n    type: 'page'\n  },\n  frameworks: {\n    title: 'Frameworks',\n    type: 'page'\n  },\n  fruits: {\n    title: 'Fruits',\n    type: 'page'\n  },\n  about: {\n    title: 'About',\n    type: 'page'\n  }\n}\n```\n</Block>\n\nAnd it will look like this:\n\n<figure>\n  <Video src=\"/assets/docs/sub-docs.mp4\" />\n  {/* prettier-ignore */}\n  <figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-eszspq?file=pages%2F_meta.js)</figcaption>\n</figure>\n\n> [!TIP]\n>\n> You can also hide links like `Home` from the navbar with the\n> [`display: 'hidden'{:js}`](#display-hidden-option) option.\n>\n> You can have external links in the navbar, similar to the\n> [links section](#links):\n>\n> ```js filename=\"_meta.js\" {4-5}\n> export default {\n>   contact: {\n>     title: 'Contact Us',\n>     type: 'page',\n>     href: 'https://example.com/contact'\n>   }\n> }\n> ```\n\n#### `display: 'hidden'` option\n\nBy default, all MDX routes in the filesystem will be shown on the sidebar. But\nyou can hide a specific pages or folders by using the `display: 'hidden'{:ts}`\nconfiguration:\n\n```js filename=\"_meta.js\" {3}\nexport default {\n  contact: {\n    display: 'hidden'\n  }\n}\n```\n\n> [!NOTE]\n>\n> The page will still be accessible via the `/contact` URL, but it will not be\n> shown in the sidebar.\n\n#### `theme` option\n\nYou can configure the theme for each page using the `theme` option. For example,\nyou can disable or enable specific components for specific pages:\n\n```js filename=\"_meta.js\" {4}\nexport default {\n  about: {\n    theme: {\n      sidebar: false\n    }\n  }\n}\n```\n\n> [!WARNING]\n>\n> This option will be inherited by all child pages if set to a folder.\n\n<APIDocs\n  code={`type $ = ${generateTsFromZod(pageThemeSchema)}\nexport default $`}\n/>\n\n##### Layouts\n\nBy default, each page has `layout: 'default'{:js}` in their theme config, which\nis the default behavior. You might want to render some page with the full\ncontainer width and height, but keep all the other styles. You can use the\n`'full'{:js}` layout to do that:\n\n```js filename=\"_meta.js\" {4}\nexport default {\n  about: {\n    theme: {\n      layout: 'full'\n    }\n  }\n}\n```\n\n##### Typesetting [#typesetting-section]\n\nThe `typesetting` option controls typesetting details like font features,\nheading styles and components like `<li>` and `<code>`. There are\n`'default'{:js}` and `'article'{:js}` typesettings available in the docs theme.\n\nThe default one is suitable for most cases like documentation, but you can use\nthe `'article'{:js}` typesetting to make it look like an elegant article page:\n\n<figure>\n```js filename=\"_meta.js\" {4}\nexport default {\n  about: {\n    theme: {\n      typesetting: 'article'\n    }\n  }\n}\n```\n  <figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-hg77h3?file=pages%2F_meta.js,pages%2Findex.mdx)</figcaption>\n</figure>\n### Folders\n\nFolders can be configured in the same way as pages.\n\nFor example, the following top-level `_meta` file contains the meta information\nfor the top-level pages and folders.<br/> The nested `_meta` file contains the\nmeta information for pages in the same folder:\n\n<Block>\n<ContentAndAppFileTee className='shrink-0'>\n  <FileTree.Folder name=\"fruits\" defaultOpen>\n    <FileTree.File name=\"_meta.js\" active />\n    <FileTree.File name=\"apple.mdx\" />\n    <FileTree.File name=\"banana.mdx\" />\n  </FileTree.Folder>\n  <FileTree.File name=\"_meta.js\" active />\n  <FileTree.File name=\"about.mdx\" />\n  <FileTree.File name=\"contact.mdx\" />\n  <FileTree.File name=\"index.mdx\" />\n</ContentAndAppFileTee>\n<div className='mt-6'>\n```js filename=\"_meta.js\" copy=false\nexport default {\n  index: 'My Homepage',\n  contact: 'Contact Us',\n  fruits: 'Delicious Fruits',\n  about: 'About Us'\n}\n```\n```js filename=\"fruits/_meta.js\" copy=false\nexport default {\n  apple: 'Apple',\n  banana: 'Banana'\n}\n```\n</div>\n</Block>\n\n> [!NOTE]\n>\n> You can move directories around without having to change the `_meta` file\n> since information for pages are grouped together in directories.\n\n#### With `/index` page\n\nTo create a folder with an index page, add `asIndexPage: true{:js}` to its front\nmatter.\n\nFor example, to create a `/fruits` route, setting `asIndexPage: true{:js}` tells\nNextra that `/fruits` is a folder with an index page. Clicking the folder in the\nsidebar will expand it and display the MDX page.\n\n<Block>\n<ContentAndAppFileTee className=\"shrink-0\">\n  <FileTree.Folder name=\"fruits\" defaultOpen active>\n    <FileTree.File name=\"_meta.js\" />\n    <FileTree.File name=\"apple.mdx\" />\n    <FileTree.File name=\"banana.mdx\" />\n    <FileTree.File name=\"index.mdx\" active />\n  </FileTree.Folder>\n  <FileTree.File name=\"_meta.js\" />\n  <FileTree.File name=\"about.mdx\" />\n  <FileTree.File name=\"contact.mdx\" />\n  <FileTree.File name=\"index.mdx\" />\n</ContentAndAppFileTee>\n```mdx filename=\"content/fruits/index.mdx or app/fruits/page.mdx\" copy=false {4}\n---\ntitle: All Fruits\nsidebarTitle: 🍒 Fruits\nasIndexPage: true\n---\n```\n\n</Block>\n\n### Links\n\n```ts\ntype LinkSchema = {\n  href: string\n  title?: TitleSchema\n}\n```\n\nYou can add external links to the sidebar by adding an item with `href` in\n`_meta` file:\n\n```js filename=\"_meta.js\" {2-5}\nexport default {\n  github_link: {\n    title: 'Nextra',\n    href: 'https://github.com/shuding/nextra'\n  }\n}\n```\n\n> [!TIP]\n>\n> You can use this option to link to relative internal links too.\n\n### Separators\n\n```ts\ntype SeparatorSchema = {\n  type: 'separator'\n  title?: TitleSchema\n}\n```\n\nYou can use a \"placeholder\" item with `type: 'separator'{:js}` to create a\nseparator line between items in the sidebar:\n\n```js filename=\"_meta.js\" {3-4}\nexport default {\n  '###': {\n    type: 'separator',\n    title: 'My Items' // Title is optional\n  }\n}\n```\n\n### Menus\n\nYou can also add menus to the navbar using `type: 'menu'{:js}` and the `items`\noption:\n\n<figure>\n  <>![Navbar menu](/assets/docs/menu.png)</>\n  {/* prettier-ignore */}\n  <figcaption>[Live example on StackBlitz](https://stackblitz.com/edit/nextra-2-docs-2qopvp?file=pages%2F_meta.js)</figcaption>\n</figure>\n\n```ts\ntype MenuItemSchema =\n  | TitleSchema\n  | { title: TitleSchema }\n  | (LinkSchema & { type?: 'page' | 'doc' })\n  | SeparatorSchema\n\ntype MenuSchema = {\n  type: 'menu'\n  title?: TitleSchema\n  items: Record<string, MenuItemSchema>\n}\n```\n\n```js filename=\"_meta.js\"\nexport default {\n  company: {\n    title: 'Company',\n    type: 'menu',\n    items: {\n      about: {\n        title: 'About',\n        href: '/about'\n      },\n      contact: {\n        title: 'Contact Us',\n        href: 'mailto:hi@example.com'\n      }\n    }\n  }\n}\n```\n\n### Fallbacks\n\nIn the [`type: 'page'{:js}` option](#type-page-option) above, we have to define\nthe `type: 'page'{:js}` option for every page. To make it easier, you can use\nthe `'*'` key to define the fallback configuration for all items in this folder:\n\n```js filename=\"_meta.js\" {2-4}\nexport default {\n  '*': {\n    type: 'page'\n  },\n  index: 'Home',\n  frameworks: 'Frameworks',\n  fruits: 'Fruits',\n  about: 'About'\n}\n```\n\nThey are equivalent where all items have `type: 'page'{:js}` set.\n\n### `_meta.global` file\n\nYou can also define all your pages in a single `_meta` file, suffixed with\n`.global`. The API remains the same as for folder-specific `_meta` files, with 1\nexception: **folder items must include an `items` field**.\n\nFor the following structure, you might use the following `_meta` files:\n\n<Block>\n\n<ContentAndAppFileTee className='shrink-0'>\n  <FileTree.Folder name=\"fruits\" open>\n    <FileTree.File name=\"_meta.js\" active />\n    <FileTree.File name=\"apple.mdx\" />\n    <FileTree.File name=\"banana.mdx\" />\n  </FileTree.Folder>\n  <FileTree.File name=\"_meta.js\" active />\n  <FileTree.File name=\"index.mdx\" />\n</ContentAndAppFileTee>\n<div className='mt-6'>\n```js filename=\"_meta.js\" copy=false\nexport default {\n  fruits: {\n    type: 'page',\n    title: '✨ Fruits'\n  }\n}\n```\n```js filename=\"fruits/_meta.js\" copy=false\nexport default {\n  apple: '🍎 Apple',\n  banana: '🍌 BaNaNa'\n}\n```\n</div>\n</Block>\n\nWith single `_meta.global` file it can be defined as below:\n\n```js filename=\"_meta.global.js\" copy=false\nexport default {\n  fruits: {\n    type: 'page',\n    title: '✨ Fruits',\n    items: {\n      apple: '🍎 Apple',\n      banana: '🍌 BaNaNa'\n    }\n  }\n}\n```\n\n> [!WARNING]\n>\n> You can't use both `_meta.global` and `_meta` files in your project.\n\n## Good to know\n\n### Sorting pages\n\nYou can use ESLint's built-in `sort-keys` rule, append\n`/* eslint sort-keys: error */` comment at the top of your `_meta` file, and you\nwill receive ESLint's errors about incorrect order.\n\n### Type of `_meta` keys\n\nThe type of your `_meta` keys should always **be a string** and **not a number**\nbecause\n[numbers are always ordered first](https://dev.to/frehner/the-order-of-js-object-keys-458d)\nin JavaScript objects.\n\nFor example, consider the following:\n\n```js filename=\"_meta.js\" copy=false\nexport default {\n  foo: '',\n  1992_10_21: '',\n  1: ''\n}\n```\n\nwill be converted to:\n\n{/* prettier-ignore */}\n```js filename=\"_meta.js\" copy=false\nexport default {\n  '1': '',\n  '19921021': '',\n  foo: ''\n}\n```\n\n> [!TIP]\n>\n> The `.js`, `.jsx`, or `.tsx` file extensions can be used for `_meta` file.\n"
  },
  {
    "path": "docs/app/docs/file-conventions/page-file/page.mdx",
    "content": "---\nicon: FileIcon\nsidebarTitle: page.mdx\ndescription:\n  The `page.mdx` file in Nextra is a special Next.js App Router convention file\n  that allows you to define UI unique to a route. By default, `.js`, `.jsx`, or\n  `.tsx` file extensions can be used for `page`, and Nextra enhances them with\n  `.md` and `.mdx` extensions.\n---\n\nimport { FileTree } from 'nextra/components'\n\n# `page.mdx` File\n\n[`page` file](https://nextjs.org/docs/app/api-reference/file-conventions/page)\nis a special\n[Next.js App Router convention file](https://nextjs.org/docs/app/getting-started/project-structure#routing-files)\nwhich allows you to define UI that is unique to a route:\n\n<FileTree>\n  <FileTree.Folder name=\"app\" open>\n    <FileTree.File name=\"layout.jsx\" />\n    <FileTree.File name=\"page.jsx\" active />\n    <FileTree.Folder name=\"docs\" open>\n      <FileTree.File name=\"page.mdx\" active />\n      <FileTree.Folder name=\"getting-started\" open>\n        <FileTree.File name=\"page.mdx\" active />\n      </FileTree.Folder>\n    </FileTree.Folder>\n  </FileTree.Folder>\n</FileTree>\n\n> [!TIP]\n>\n> By default, the `.js`, `.jsx`, or `.tsx` file extensions can be used for\n> `page`.<br/> Nextra enhance them with `.md` and `.mdx` extensions.\n"
  },
  {
    "path": "docs/app/docs/file-conventions/page.mdx",
    "content": "---\nasIndexPage: true\ndescription:\n  Nextra's File Conventions guide details the structure and organization of\n  files and directories within a Nextra project, including the use of\n  `page.mdx`, `_meta.js`, and `mdx-components.js` files, as well as the\n  `content` and `src` directories.\n---\n\nimport { FileIcon, FolderIcon, MdxIcon } from 'nextra/icons'\nimport { OverviewPage } from '../../_components/overview-page'\n\n# File Conventions\n\n<OverviewPage\n  filePath={metadata.filePath}\n  icons={{ FileIcon, FolderIcon, MdxIcon }}\n/>\n"
  },
  {
    "path": "docs/app/docs/file-conventions/src-directory/page.mdx",
    "content": "---\nicon: FolderIcon\nsidebarTitle: src\ndescription:\n  The `src` directory in Nextra allows you to organize your application code\n  separately from project configuration files, enhancing code structure and\n  maintainability.\n---\n\nimport { FileTree } from 'nextra/components'\n\n# `src` Directory\n\nAs an alternative to having the special Nextra `content` directory and\n`mdx-components` file in the root of your project, Nextra also supports the\ncommon pattern of placing application code under the `src` directory.\n\nThis separates application code from project configuration files which mostly\nlive in the root of a project, which is preferred by some individuals and teams.\n\nTo use the `src` directory, move the `content` directory and `mdx-components`\nfile to `src/content` or `src/mdx-components` respectively.\n\nexport const nextConfigPackageJson = (\n  <>\n    <FileTree.File name=\"next.config.js\" />\n    <FileTree.File name=\"package.json\" />\n  </>\n)\n\nexport const folders = (\n  <>\n    <FileTree.Folder name=\"app\" open>\n      <FileTree.Folder name=\"[[...mdxPath]]\" open>\n        <FileTree.File name=\"page.jsx\" />\n      </FileTree.Folder>\n      <FileTree.File name=\"layout.jsx\" />\n    </FileTree.Folder>\n    <FileTree.Folder name=\"content\" open active>\n      <FileTree.File name=\"index.mdx\" active />\n    </FileTree.Folder>\n    <FileTree.File name=\"mdx-components.js\" active />\n  </>\n)\n\n<FileTree>\n  **Without `src` directory**\n  <FileTree.Folder name=\"your-project\" open>\n    {folders}\n    {nextConfigPackageJson}\n  </FileTree.Folder>\n</FileTree>\n\n<FileTree>\n  **With `src` directory**\n  <FileTree.Folder name=\"your-project\" open>\n    <FileTree.Folder name=\"src\" open active>\n      {folders}\n    </FileTree.Folder>\n    {nextConfigPackageJson}\n  </FileTree.Folder>\n</FileTree>\n"
  },
  {
    "path": "docs/app/docs/guide/custom-css/page.mdx",
    "content": "---\nsidebarTitle: Custom CSS\nicon: BrushIcon\n---\n\n# Custom CSS Support\n\nNextra is 100% compatible with the\n[built-in CSS support of Next.js](https://nextjs.org/docs/app/getting-started/css),\nincluding `.css`, `.module.css`, and Sass (`.scss`, `.sass`, `.module.scss`,\n`.module.sass`) files.\n\nFor example, consider the following stylesheet named `styles.css`:\n\n```css filename=\"styles.css\"\nbody {\n  font-family:\n    'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', 'Helvetica', 'Arial',\n    sans-serif;\n  padding: 20px 20px 60px;\n  max-width: 680px;\n  margin: 0 auto;\n}\n```\n\nTo apply your global styles, import your CSS file in the root layout file:\n\n```jsx filename=\"app/layout.jsx\"\nimport '../path/to/your/styles.css'\n\nexport default async function RootLayout({ children }) {\n  // ... Your layout logic here\n}\n```\n\nFor more information on how to use CSS in Next.js, check out the\n[Next.js CSS Support documentation](https://nextjs.org/docs/app/getting-started/css).\n"
  },
  {
    "path": "docs/app/docs/guide/github-alert-syntax/page.mdx",
    "content": "---\nicon: InformationCircleIcon\n---\n\n# GitHub Alert Syntax\n\n`nextra-theme-docs` and `nextra-theme-blog` support replacing\n[GitHub alert syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)\nwith `<Callout>` component for `.md`/`.mdx` files.\n\n## Usage\n\n```md filename=\"Markdown\"\n> [!NOTE]\n>\n> Useful information that users should know, even when skimming content.\n\n> [!TIP]\n>\n> Helpful advice for doing things better or more easily.\n\n> [!IMPORTANT]\n>\n> Key information users need to know to achieve their goal.\n\n> [!WARNING]\n>\n> Urgent info that needs immediate user attention to avoid problems.\n\n> [!CAUTION]\n>\n> Advises about risks or negative outcomes of certain actions.\n```\n\n## Example\n\n> [!NOTE]\n>\n> Useful information that users should know, even when skimming content.\n\n> [!TIP]\n>\n> Helpful advice for doing things better or more easily.\n\n> [!IMPORTANT]\n>\n> Key information users need to know to achieve their goal.\n\n> [!WARNING]\n>\n> Urgent info that needs immediate user attention to avoid problems.\n\n> [!CAUTION]\n>\n> Advises about risks or negative outcomes of certain actions.\n\n## Usage with your own theme\n\nIf you want to benefit this feature with your own theme and your own `<Callout>`\ncomponent:\n\nimport { Steps } from 'nextra/components'\n\n<Steps>\n\n### Create a `<Blockquote>` component\n\nTo create a `<Blockquote>` component, start by importing `withGitHubAlert` from\n`nextra/components`. You should then create the `<Blockquote>` component by\ninvoking the `withGitHubAlert` function.\n\nThe first argument should be a React HOC component that handles the GitHub alert\nsyntax, and the second argument should be your standard `<blockquote>`\ncomponent.\n\nThe `type` prop can be one of the following:\n`'note' | 'tip' | 'important' | 'warning' | 'caution'{:ts}`.\n\n```jsx\nimport { withGitHubAlert } from 'nextra/components'\n\nconst Blockquote = withGitHubAlert(({ type, ...props }) => {\n  return <MyCalloutComponent type={type} {...props} />\n}, MyBlockquoteComponent)\n```\n\n### Provide `<Blockquote>` to `useMDXComponents`\n\nTo make the `<Blockquote>` component available, you should integrate it into the\n`useMDXComponents` function:\n\n```jsx filename=\"mdx-components.jsx\"\nexport function useMDXComponents(components) {\n  return {\n    blockquote: Blockquote,\n    ...components\n  }\n}\n```\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/guide/i18n/page.mdx",
    "content": "---\nicon: GlobeIcon\n---\n\nimport { ExampleCode } from '@components/example-code'\nimport { Steps } from 'nextra/components'\n\n# Next.js I18n\n\n> [!WARNING]\n>\n> This feature is only available in `nextra-theme-docs`.\n\nNextra supports\n[Next.js Internationalized Routing](https://nextjs.org/docs/advanced-features/i18n-routing)\nout of the box. These docs explain how to configure and use it.\n\n<Steps>\n## Add i18n config\n\nTo add multi-language pages to your Nextra application, you need to config\n`i18n` in `next.config.mjs` first:\n\n```js filename=\"next.config.mjs\" {8-11}\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  // ... other Nextra config options\n})\n\nexport default withNextra({\n  i18n: {\n    locales: ['en', 'zh', 'de'],\n    defaultLocale: 'en'\n  }\n})\n```\n\n> [!NOTE]\n>\n> You can use any format of\n> [UTS Locale Identifiers](https://www.unicode.org/reports/tr35/tr35-59/tr35.html#Identifiers)\n> for defining your locales in the `next.config` file, e.g. language with region\n> format `en-US` (English as spoken in the United States).\n\n## Configure the docs theme\n\nAdd the `i18n` option to your `theme.config.jsx` to configure the language\ndropdown:\n\n```js filename=\"theme.config.jsx\"\ni18n: [\n  { locale: 'en', name: 'English' },\n  { locale: 'zh', name: '中文' },\n  { locale: 'de', name: 'Deutsch' },\n  { locale: 'ar', name: 'العربية', direction: 'rtl' }\n]\n```\n\n## Automatically detect and redirect to user-selected language (_optional_)\n\nYou can automatically detect the user's preferred language and redirect them to\nthe corresponding version of the site. To achieve this, create a `proxy.ts` or\n`proxy.js` file in the root of your project and export Nextra's middleware\nfunction from `nextra/locales`:\n\n<ExampleCode example=\"swr-site\" filePath=\"proxy.ts\" metadata=\"{1}\" />\n\n> [!WARNING]\n>\n> This approach will not work for i18n sites that are statically exported with\n> `output: 'export'` in `nextConfig`.\n\n## Custom 404 page (_optional_)\n\nYou can have a custom `not-found.jsx` with translations for an i18n website that\nuses a shared theme layout. For guidance on implementing this, you can check out\nthe\n[SWR i18n example](https://github.com/shuding/nextra/blob/c9d0ffc8687644401412b8adc34af220cccddf82/examples/swr-site/app/%5Blang%5D/not-found.ts).\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/guide/image/page.mdx",
    "content": "---\nicon: PictureIcon\n---\n\n# Next.js Image\n\nThe standard way to use\n[Next.js Image](https://nextjs.org/docs/app/getting-started/images) inside MDX\nis to directly import the component:\n\n```mdx filename=\"MDX\"\nimport Image from 'next/image'\n\n<Image src=\"/demo.png\" alt=\"Hello\" width={500} height={500} />\n```\n\n## Static image\n\n> [!NOTE]\n>\n> This feature is enabled via `staticImage: true` in the Nextra config by\n> default.\n\nNextra supports automatically optimizing your static image imports with the\nMarkdown syntax. You do not need to specify the width and height of the image,\njust use the `![]()` Markdown syntax:\n\n```md filename=\"Markdown\"\n![Hello](/demo.png)\n```\n\nThis loads the `demo.png` file inside the `public` folder, and automatically\nwraps it with Next.js `<Image>`.\n\n> [!TIP]\n>\n> You can also use `![](../public/demo.png)` to load the image from a relative\n> path, if you don't want to host it via `public`.\n\nWith Next.js Image, there will be no layout shift, and a beautiful blurry\nplaceholder will be shown by default when loading the images:\n\n![Nextra](/opengraph-image.jpeg)\n\n## Image zoom\n\n> [!NOTE]\n>\n> The image zoom feature is enabled globally by default.\n\nIn the default configuration, if you want to use this feature, simply insert\nimages using `![]()` Markdown syntax.\n\n### Disable image zoom\n\nFor `nextra-docs-theme` and `nextra-blog-theme`, you can disable image zoom by\nreplacing the `img` component used in MDX.\n\n```jsx filename=\"theme.config.jsx\"\nimport { Image } from 'nextra/components'\n\nexport default {\n  // ... your other configurations\n  components: {\n    img: props => <Image {...props} />\n  }\n}\n```\n\n### Enable/disable image zoom for specific images\n\nWhen zoom is **disabled globally**, but you want to enable it for specific\nimages, you can do so by using the `<ImageZoom>` component:\n\n```mdx\nimport { ImageZoom } from 'nextra/components'\n\n<ImageZoom src=\"/demo.png\" />\n```\n\nWhen zoom is **enabled globally**, and you want to disable zoom for a specific\nimage, you can simply use the `<Image>` component:\n\n```mdx\nimport { Image } from 'nextra/components'\n\n<Image src=\"/demo.png\" />\n```\n"
  },
  {
    "path": "docs/app/docs/guide/link/page.mdx",
    "content": "---\nicon: LinkIcon\n---\n\n# Next.js Link\n\nAll relative Markdown links are automatically converted into\n[Next.js links](https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating).\nThis means that the target page will be prefetched. When you click on a link,\nthe page will be loaded on the client-side like a\n[Single-Page Application (SPA)](https://en.wikipedia.org/wiki/Single-page_application),\nwithout making a full page load. For example:\n\n```md filename=\"Markdown\"\nClick [here](/about) to read more.\n```\n\nWill be equivalent to:\n\n```mdx filename=\"MDX\"\nimport Link from 'next/link'\n\nClick <Link href=\"/about\">here</Link> to read more.\n```\n\nThis feature makes navigation between Nextra pages fast and seamless.\n"
  },
  {
    "path": "docs/app/docs/guide/markdown/_counter.tsx",
    "content": "'use client'\n\nimport type { FC, ReactNode } from 'react'\nimport { useState } from 'react'\n\nexport const Counter: FC<{ children: ReactNode }> = ({ children }) => {\n  const [count, setCount] = useState(0)\n  return (\n    <button onClick={() => setCount(prev => prev + 1)}>\n      {children}\n      {count}\n    </button>\n  )\n}\n"
  },
  {
    "path": "docs/app/docs/guide/markdown/page.mdx",
    "content": "---\nicon: MarkdownIcon\n---\n\nimport { Shadow } from '@components/shadow'\nimport { Counter } from './_counter'\n\n# Markdown\n\n## MDX\n\nWith Nextra, all your `.mdx` files under the `content` directory will be\nrendered with [MDX](https://mdxjs.com/about), it's an advanced Markdown format\nwith React component support.\n\nFor example, you can use import and use React components inside your MDX files\nlike this:\n\n```mdx filename=\"MDX\"\n## Hello MDX\n\nimport { useState } from 'react'\n\nexport function Counter({ children }) {\n  const [count, setCount] = useState(0)\n  return (\n    <button onClick={() => setCount(prev => prev + 1)}>\n      {children}\n      {count}\n    </button>\n  )\n}\n\n<Counter>**Clicks**: </Counter>\n```\n\nGenerates:\n\n<Shadow mode=\"open\" className=\"nextra-border mt-6 rounded-xl border p-4\">\n  <h2>Hello MDX</h2>\n  <Counter>**Clicks**: </Counter>\n</Shadow>\n\nBesides basic MDX, Nextra also has some advanced Markdown features built-in.\n\n## GitHub Flavored Markdown\n\n[GFM](https://github.github.com/gfm) is an extension of Markdown, created by\nGitHub, that adds support for strikethrough, task lists, tables, and more.\n\n### Strikethrough\n\n~~removed~~\n\n```md filename=\"Markdown\"\n~~removed~~\n```\n\n### Task list\n\n- [x] Write the press release\n- [ ] Update the website\n- [ ] Contact the media\n\n```md filename=\"Markdown\"\n- [x] Write the press release\n- [ ] Update the website\n- [ ] Contact the media\n```\n\n### Table\n\n| Syntax        | Description |   Test Text |\n| :------------ | :---------: | ----------: |\n| Header        |    Title    | Here's this |\n| Paragraph     |    Text     |    And more |\n| Strikethrough |             |    ~~Text~~ |\n\n```md filename=\"Markdown\"\n| Syntax        | Description |   Test Text |\n| :------------ | :---------: | ----------: |\n| Header        |    Title    | Here's this |\n| Paragraph     |    Text     |    And more |\n| Strikethrough |             |    ~~Text~~ |\n```\n\n### Autolinks\n\nVisit https://nextjs.org.\n\n```md\nVisit https://nextjs.org.\n```\n\n### Custom heading id\n\nYou can specify custom heading id using the format `## My heading [#custom-id]`.\nFor example:\n\n```md filename=\"Markdown\"\n## Long heading about Nextra [#about-nextra]\n```\n\nIn this example, `#about-nextra` will be used as the heading link, replacing the\ndefault `#long-heading-about-nextra`.\n"
  },
  {
    "path": "docs/app/docs/guide/page.mdx",
    "content": "---\nasIndexPage: true\n---\n\nimport {\n  BrushIcon,\n  GlobeIcon,\n  LightningIcon,\n  PictureIcon,\n  StarsIcon\n} from '@components/icons'\nimport { InformationCircleIcon, LinkIcon, MarkdownIcon } from 'nextra/icons'\nimport { OverviewPage } from '../../_components/overview-page'\n\n# Guide\n\nThe following features are configured via the Next.js configuration and are\navailable in all themes.\n\n<OverviewPage\n  filePath={metadata.filePath}\n  icons={{\n    MarkdownIcon,\n    StarsIcon,\n    LinkIcon,\n    PictureIcon,\n    LightningIcon,\n    GlobeIcon,\n    BrushIcon,\n    InformationCircleIcon\n  }}\n/>\n"
  },
  {
    "path": "docs/app/docs/guide/search/ai/page.mdx",
    "content": "import { Steps } from 'nextra/components'\n\n# Ask AI\n\nEnhance your Nextra documentation site with AI-powered chat assistance using\n[Inkeep](https://docs.inkeep.com/cloud). This integration allows users to get\ninstant help and answers directly within your documentation, improving user\nexperience and reducing support burden.\n\n## Setup\n\n<Steps>\n### Get an API key\n\nFollow\n[these steps](https://docs.inkeep.com/cloud/projects/overview#create-a-web-assistant)\nto create an API key for your web assistant.\n\nCopy and add the API key to your environment variables:\n\n```dotenv filename=\".env\"\nNEXT_PUBLIC_INKEEP_API_KEY=\"your_actual_api_key_here\"\n```\n\n### Install the component library\n\nInstall the Inkeep React component library:\n\n```sh npm2yarn\nnpm i @inkeep/cxkit-react\n```\n\n### Create the chat button component\n\nCreate a new file `inkeep-chat-button.tsx`:\n\n```tsx filename=\"inkeep-chat-button.tsx\"\n'use client'\n\nimport { InkeepChatButton } from '@inkeep/cxkit-react'\nimport type { FC } from 'react'\n\nexport const ChatButton: FC = () => {\n  return (\n    <InkeepChatButton\n      aiChatSettings={{\n        apiKey: process.env.NEXT_PUBLIC_INKEEP_API_KEY!,\n        // Customize your AI assistant's appearance\n        aiAssistantAvatar: '/icon.svg', // Path to your assistant's avatar\n        aiAssistantName: 'Nextra Assistant' // Name shown to users\n      }}\n      baseSettings={{\n        // Match your site's brand colors\n        primaryBrandColor: '#238aff',\n        // Sync with your site's dark/light mode\n        colorMode: {\n          sync: {\n            target: 'html',\n            attributes: ['class'],\n            isDarkMode(attrs) {\n              return attrs.class === 'dark'\n            }\n          }\n        }\n      }}\n    />\n  )\n}\n```\n\n### Add to your root layout\n\nImport and add the `ChatButton` component to your root layout file:\n\n```tsx filename=\"app/layout.tsx\"\nimport { Layout } from 'nextra-theme-docs' // or nextra-theme-blog or your custom theme\nimport { Head } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-map'\nimport type { FC } from 'react'\nimport { ChatButton } from '../path/to/your/inkeep-chat-button'\n\nconst RootLayout: FC<LayoutProps<'/'>> = async ({ children }) => {\n  const pageMap = await getPageMap()\n\n  return (\n    <html lang=\"en\" dir=\"ltr\" suppressHydrationWarning>\n      <Head />\n      <body>\n        <ChatButton />\n        <Layout\n          pageMap={pageMap}\n          // ... other layout props\n        >\n          {children}\n        </Layout>\n      </body>\n    </html>\n  )\n}\n\nexport default RootLayout\n```\n\n> [!IMPORTANT]\n>\n> The chat button will appear on all pages of your documentation site.\n\n</Steps>\n\n## Additional resources\n\n- [Inkeep's official Nextra integration guide](https://docs.inkeep.com/cloud/integrations/nextra)\n- [Inkeep React component documentation](https://docs.inkeep.com/cloud/ui-components/react/chat-button)\n- [Inkeep Dashboard](https://portal.inkeep.com) for configuration and analytics\n"
  },
  {
    "path": "docs/app/docs/guide/search/page.mdx",
    "content": "import { Steps, Tabs } from 'nextra/components'\n\n# Search Engine\n\nNextra includes a full-page search feature that makes it easy for users to find\nrelevant content across your entire documentation site.\n\n> [!TIP]\n>\n> Check the\n> [migration guide](https://the-guild.dev/blog/nextra-4#new-search-engine--pagefind)\n> for more information.\n\n## Setup\n\nNextra integrates with [Pagefind](https://pagefind.app), a static search library\nthat indexes your HTML files and provides lightning-fast, client-side full-text\nsearch — all with no server required.\n\n<Steps>\n### Install `pagefind` as a dev dependency\n\n```sh npm2yarn\nnpm i -D pagefind\n```\n\n### Add a `postbuild` script\n\nPagefind indexes `.html` files, so the indexing must happen **after building**\nyour application.\n\nAdd a `postbuild` script to your `package.json`:\n\n<Tabs items={['Server builds', 'Static exports']}>\n  <Tabs.Tab>\n    ```json filename=\"package.json\"\n    \"scripts\": {\n      \"postbuild\": \"pagefind --site .next/server/app --output-path public/_pagefind\"\n    }\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```json filename=\"package.json\"\n    \"scripts\": {\n      \"postbuild\": \"pagefind --site .next/server/app --output-path out/_pagefind\"\n    }\n    ```\n  </Tabs.Tab>\n</Tabs>\n\n### Ignore generated files\n\nAdd `_pagefind/` to your `.gitignore` file to avoid committing generated index\nfiles.\n\n### Verify indexing output\n\nAfter building and running the `postbuild` script, check that a `_pagefind/`\ndirectory exists in `public/` or `out/`. Start your app and test the search bar\nto confirm everything is working.\n\n</Steps>\n\n## Configuration\n\nSearch is enabled by default. You can disable it entirely by setting\n`search: false{:js}` in your `next.config.mjs` file:\n\n```js filename=\"next.config.mjs\" {4}\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  search: false\n})\nexport default withNextra()\n```\n\nTo disable code block indexing while keeping search enabled set\n`search: { codeblocks: false }{:js}`:\n\n```js filename=\"next.config.mjs\" {4}\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  search: { codeblocks: false }\n})\nexport default withNextra()\n```\n"
  },
  {
    "path": "docs/app/docs/guide/ssg/page.mdx",
    "content": "---\nicon: LightningIcon\n---\n\nimport { compileMdx } from 'nextra/compile'\nimport { Callout } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n# Next.js Static Rendering\n\n[Static Rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#static-rendering-default)\nis default server rendering strategy, where routes are rendered at **build\ntime** or in the background after\n[data revalidation](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration).\nThe result is cached and can be distributed via a\n[Content Delivery Network (CDN)](https://developer.mozilla.org/docs/Glossary/CDN)\nfor optimal performance.\n\nStatic rendering is ideal for routes with non-personalized data that can be\ndetermined at build time, such as blog posts or product pages.\n\n<SSGPage />\n\nexport async function SSGPage() {\n  const starsComponent = `{/* Via async components */}\nexport async function Stars() {\n  const response = await fetch('https://api.github.com/repos/shuding/nextra')\n  const repo = await response.json()\n  const stars = repo.stargazers_count\n  return <b>{stars}</b>\n}\n\n{/* Via async functions */}\nexport async function getUpdatedAt() {\n  const response = await fetch('https://api.github.com/repos/shuding/nextra')\n  const repo = await response.json()\n  const updatedAt = repo.updated_at\n  return new Date(updatedAt).toLocaleDateString()\n}\n\n<Callout emoji=\"🏆\">\n  Nextra has <Stars /> stars on GitHub!\n\n  Last repository update _{await getUpdatedAt()}_.\n</Callout>`\n  const mdx = `${starsComponent}\n\nThe number above was generated at build time via MDX server components. With\n[Incremental Static Regeneration](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration)\nenabled, it will be kept up to date.\n\n## Example\n\nHere's the MDX code for the example above:\n\n~~~mdx filename=\"MDX\"\n${starsComponent}\n~~~\n`\n  const rawJs = await compileMdx(mdx)\n  return <MDXRemote compiledSource={rawJs} components={{ Callout }} />\n}\n"
  },
  {
    "path": "docs/app/docs/guide/static-exports/page.mdx",
    "content": "import { Steps } from 'nextra/components'\n\n# Static Exports\n\nExport your pages statically, and deploy with [Nginx](https://nginx.org),\n[GitHub Pages](https://pages.github.com) and more.\n\n## Getting started\n\n<Steps>\n\n### Configuration\n\nTo enable a static export, update the options in `next.config.mjs` file as\nfollows:\n\n```js filename=\"next.config.mjs\" {7-10}\nimport nextra from 'nextra'\n\n/**\n * @type {import('next').NextConfig}\n */\nconst nextConfig = {\n  output: 'export',\n  images: {\n    unoptimized: true // mandatory, otherwise won't export\n  }\n  // Optional: Change the output directory `out` -> `dist`\n  // distDir: \"build\"\n}\nconst withNextra = nextra({\n  // ... other Nextra config options\n})\n\nexport default withNextra(nextConfig)\n```\n\n### Update `postbuild` script\n\nUpdate the Pagefind [search engine setup](./search#add-a-postbuild-script) to\nset the correct output path:\n\n```json filename=\"package.json\"\n\"scripts\": {\n  \"postbuild\": \"pagefind --site .next/server/app --output-path out/_pagefind\"\n}\n```\n\n### Building\n\nRun the `build` command according to your package manager:\n\n```sh npm2yarn\nnpm run build\n```\n\nBy default, static export will be stored in `out` directory in the root of your\nproject.\n\nFor more in detail documentation for static export visit\n[Next.js docs](https://nextjs.org/docs/app/building-your-application/deploying/static-exports).\n\n</Steps>\n"
  },
  {
    "path": "docs/app/docs/guide/syntax-highlighting/_dynamic-code.tsx",
    "content": "'use client'\n\nimport { Button } from 'nextra/components'\nimport type { FC, ReactNode } from 'react'\nimport { useEffect, useRef } from 'react'\n\nexport const DynamicCode: FC<{ children: ReactNode }> = ({ children }) => {\n  const ref = useRef<HTMLDivElement>(null!)\n  const tokenRef = useRef<HTMLSpanElement>(undefined)\n  // Find the corresponding token from the DOM\n  useEffect(() => {\n    tokenRef.current = [\n      ...ref.current.querySelectorAll<HTMLSpanElement>('code > span > span')\n    ].find(el => el.textContent === '1')\n  }, [])\n  return (\n    <>\n      <div ref={ref} className=\"mt-6\">\n        {children}\n      </div>\n      <div className=\"mt-3 flex justify-center gap-3 text-sm\">\n        <Button\n          variant=\"outline\"\n          onClick={() => {\n            const token = tokenRef.current!\n            const prev = token.textContent\n            token.textContent = String((+prev || 0) + 1)\n          }}\n        >\n          Increase the number\n        </Button>\n        <Button\n          variant=\"outline\"\n          onClick={() => {\n            tokenRef.current!.textContent = '1 + 1'\n          }}\n        >\n          Change to `1 + 1`\n        </Button>\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "docs/app/docs/guide/syntax-highlighting/page.mdx",
    "content": "---\nicon: StarsIcon\n---\n\nimport { OptionTable } from 'components/_table'\nimport { compileMdx } from 'nextra/compile'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n# Syntax Highlighting\n\nNextra uses [Shiki](https://shiki.style) to do syntax highlighting at build\ntime. It's very reliable and performant. For example, adding this in your\nMarkdown file:\n\n````md copy=false filename=\"Markdown\"\n```js\nconsole.log('hello, world')\n```\n````\n\nResults in:\n\n```js copy=false\nconsole.log('hello, world')\n```\n\n## Features\n\n### Inlined code\n\nInlined syntax highlighting like `let x = 1{:jsx}` is also supported via the\n`{:}` syntax:\n\n```md copy=false filename=\"Markdown\"\nInlined syntax highlighting is also supported `let x = 1{:jsx}` via:\n```\n\n### Highlighting lines\n\nYou can highlight specific lines of code by adding a `{}` attribute to the code\nblock:\n\n````md copy=false filename=\"Markdown\"\n```js {1,4-5}\nimport { useState } from 'react'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  return <button onClick={() => setCount(count + 1)}>{count}</button>\n}\n```\n````\n\nResult:\n\n```js copy=false {1,4-5}\nimport { useState } from 'react'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  return <button onClick={() => setCount(count + 1)}>{count}</button>\n}\n```\n\n### Highlighting substrings\n\nYou can highlight specific substrings of code by adding a `//` attribute to the\ncode block:\n\n````md copy=false filename=\"Markdown\"\n```js /useState/\nimport { useState } from 'react'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  return <button onClick={() => setCount(count + 1)}>{count}</button>\n}\n```\n````\n\n```js copy=false /useState/\nimport { useState } from 'react'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  return <button onClick={() => setCount(count + 1)}>{count}</button>\n}\n```\n\nYou can highlight only a part of the occurrences of that substring by adding a\nnumber it: `/str/1`, or multiple: `/str/1-3`, `/str/1,3`.\n\n### Copy button\n\nBy adding a `copy` attribute, a copy button will be added to the code block when\nthe user hovers over it:\n\n````md copy=false filename=\"Markdown\"\n```js copy\nconsole.log('hello, world')\n```\n````\n\nRenders:\n\n```js copy\nconsole.log('hello, world')\n```\n\n> [!NOTE]\n>\n>  You can enable this feature globally by setting `defaultShowCopyCode: true` in\n>  your Nextra configuration (`next.config.mjs` file). Once it's enabled\n>  globally, you can disable it via the `copy=false` attribute.\n\n### Line numbers\n\nYou can add line numbers to your code blocks by adding a `showLineNumbers`\nattribute:\n\n````md copy=false filename=\"Markdown\"\n```js showLineNumbers\nimport { useState } from 'react'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  return <button onClick={() => setCount(count + 1)}>{count}</button>\n}\n```\n````\n\nRenders:\n\n```js copy=false showLineNumbers\nimport { useState } from 'react'\n\nfunction Counter() {\n  const [count, setCount] = useState(0)\n  return <button onClick={() => setCount(count + 1)}>{count}</button>\n}\n```\n\n### Filenames and titles\n\nYou can add a filename or a title to your code blocks by adding a `filename`\nattribute:\n\n````md copy=false filename=\"Markdown\"\n```js filename=\"example.js\"\nconsole.log('hello, world')\n```\n````\n\nRenders:\n\n```js copy=false filename=\"example.js\"\nconsole.log('hello, world')\n```\n\n### ANSI highlighting\n\nYou can highlight ANSI escape codes:\n\n<ANSI />\n\nexport async function ANSI() {\n  const rawAnsi = `\\`\\`\\`ansi\n\u001b[0m \u001b[0;32m✓\u001b[0m \u001b[0;2msrc/\u001b[0mindex\u001b[0;2m.test.ts (1)\u001b[0m\n  \u001b[0;2m Test Files \u001b[0m \u001b[0;1;32m1 passed\u001b[0;98m (1)\u001b[0m\n  \u001b[0;2m      Tests \u001b[0m \u001b[0;1;32m1 passed\u001b[0;98m (1)\u001b[0m\n  \u001b[0;2m   Start at \u001b[0m 23:32:41\n  \u001b[0;2m   Duration \u001b[0m 11ms\n  \u001b[42;1;39;0m PASS \u001b[0;32m Waiting for file changes...\u001b[0m\n         \u001b[0;2mpress \u001b[0;1mh\u001b[0;2m to show help, press \u001b[0;1mq\u001b[0;2m to quit\n\\`\\`\\``\n  const rawJs = await compileMdx(`~~~md filename=\"Markdown\"\n${rawAnsi}\n~~~\n\nRenders:\n\n${rawAnsi}\n`)\n  return <MDXRemote compiledSource={rawJs} />\n}\n\n## Supported languages\n\nCheck [this list](https://github.com/shikijs/shiki/blob/main/docs/languages.md)\nfor all supported languages.\n\n{/* ## Customize the Theme */}\n\n{/* Nextra uses CSS variables to define the colors for tokens. */}\n\n## With dynamic content\n\nSince syntax highlighting is done at build time, you can't use dynamic content\nin your code blocks. However, since MDX is very powerful there is a workaround\nvia client JS. For example:\n\nimport { DynamicCode } from './_dynamic-code'\n\n<DynamicCode>\n```js copy=false filename=\"dynamic-code.js\"\nfunction hello() {\n  const x = 2 + 3\n  console.log(1)\n}\n```\n</DynamicCode>\n\nThis workaround has a limitation that updated content won't be re-highlighted.\nFor example if we update the number to `1 + 1`, it will be incorrectly\nhighlighted.\n\nCheck out the\n[code](https://github.com/shuding/nextra/blob/main/docs/app/docs/guide/syntax-highlighting/_dynamic-code.tsx)\nto see how it works.\n\n## Disable syntax highlighting\n\nYou can opt out of syntax highlighting for using one of your own. You can\ndisable syntax highlighting globally by setting `codeHighlight: false` in your\nNextra configuration (`next.config.mjs` file).\n\n<OptionTable\n  options={[\n    [\n      'codeHighlight',\n      'boolean',\n      'Enable or disable syntax highlighting. Defaults to `true`.'\n    ]\n  ]}\n/>\n\n## Custom grammar\n\nShiki accepts a\n[VSCode TextMate Grammar](https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide)\nfor syntax highlighting with custom language grammars.\n\nYou can provide these grammars by overriding the `getHighlighter` function in\n`mdxOptions.rehypePrettyCodeOptions` option in your Nextra config inside\n`next.config.mjs`:\n\n```js copy=false filename=\"next.config.mjs\" {13-18}\nimport { BUNDLED_LANGUAGES } from 'shiki'\n\nnextra({\n  // ... other Nextra config options\n  mdxOptions: {\n    rehypePrettyCodeOptions: {\n      getHighlighter: options =>\n        getHighlighter({\n          ...options,\n          langs: [\n            ...BUNDLED_LANGUAGES,\n            // custom grammar options, see the Shiki documentation for how to provide these options\n            {\n              id: 'my-lang',\n              scopeName: 'source.my-lang',\n              aliases: ['mylang'], // Along with id, aliases will be included in the allowed names you can use when writing Markdown\n              path: '../../public/syntax/grammar.tmLanguage.json'\n            }\n          ]\n        })\n    }\n  }\n})\n```\n\n## Custom themes\n\nWithin `mdxOptions.rehypePrettyCodeOptions` you may also provide custom themes\ninstead of [relying on CSS Variables](/docs/guide/syntax-highlighting):\n\n```js copy=false filename=\"next.config.mjs\" {4}\nnextra({\n  // ... other Nextra config options\n  mdxOptions: {\n    rehypePrettyCodeOptions: {\n      // VSCode theme or built-in Shiki theme, see Shiki documentation for more information\n      theme: JSON.parse(\n        readFileSync('./public/syntax/arctis_light.json', 'utf8')\n      )\n    }\n  }\n})\n```\n\n### Multiple themes (dark and light mode)\n\nPass your themes to `theme`, where the keys represent the color mode:\n\n```js copy=false filename=\"next.config.mjs\" {5-8}\nnextra({\n  // ... other Nextra config options\n  mdxOptions: {\n    rehypePrettyCodeOptions: {\n      theme: {\n        dark: 'nord',\n        light: 'min-light'\n      }\n    }\n  }\n})\n```\n"
  },
  {
    "path": "docs/app/docs/guide/turbopack/page.mdx",
    "content": "# Usage with Turbopack\n\nTo use [Turbopack](https://nextjs.org/docs/architecture/turbopack), simple\nappend the `--turbopack` flag to your development command:\n\n```diff filename=\"package.json\"\n\"scripts\": {\n-  \"dev\": \"next dev\"\n+  \"dev\": \"next dev --turbopack\"\n}\n```\n\n> [!NOTE]\n>\n> Without `--turbopack` flag Next.js under the hood uses\n> [Webpack](https://github.com/webpack/webpack), written in JavaScript.\n\n## Only serializable options are supported\n\nFor this moment only JSON serializable values can be passed in `nextra`\nfunction. This mean that with Turbopack enabled you can't pass custom\n`remarkPlugins`, `rehypePlugins` or `recmaPlugins` since they are functions.\n\nThe following options could be passed only without Turbopack or only while\nbuilding your app with `next build`\n([since Turbopack isn't support `next build` for now](https://nextjs.org/docs/architecture/turbopack#unsupported-features)\nand Webpack is used instead).\n\n```js filename=\"next.config.js\" {5-7}\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  mdxOptions: {\n    remarkPlugins: [myRemarkPlugin],\n    rehypePlugins: [myRehypePlugin],\n    recmaPlugins: [myRecmaPlugin]\n  }\n})\n```\n\nIf you try to pass them, you'll get an error from Turbopack:\n\n```text copy=false\nError: loader nextra/loader for match \"./{src/app,app}/**/page.{md,mdx}\" does not have serializable options.\nEnsure that options passed are plain JavaScript objects and values.\n```\n"
  },
  {
    "path": "docs/app/docs/page.mdx",
    "content": "---\ndescription:\n  Nextra is a framework built on top of Next.js that enables the creation of\n  content-focused websites. It combines the robust features of Next.js with\n  enhanced capabilities for crafting Markdown-based content.\n---\n\nimport { Cards, Image } from 'nextra/components'\nimport { cloneElement } from 'react'\n\nexport default function MdxLayout(props) {\n  return cloneElement(props.children, {\n    components: {\n      img: Image\n    }\n  })\n}\n\n# Introduction\n\n**Nextra** is a framework on top of Next.js, that lets you build content focused\nwebsites. It has all the great features from Next.js, plus extra power to create\nMarkdown-based content with ease.\n\n## Quick start\n\nTo start using Nextra, you need to select a theme first:\n\n<Cards num={2}>\n  <Cards.Card arrow title=\"Documentation theme\" href=\"/docs/docs-theme/start\">\n    <>![Documentation theme screenshot](/assets/docs-theme.png)</>\n  </Cards.Card>\n  <Cards.Card arrow title=\"Blog theme\" href=\"/docs/blog-theme/start\">\n    <>![Blog theme screenshot](/assets/blog-theme.png)</>\n  </Cards.Card>\n</Cards>\n\nIf you want to use Nextra without using these built-in themes, you can follow\nthe [Custom Theme](/docs/custom-theme) docs.\n\n## FAQ\n\nThe Nextra FAQ is a collection of useful questions and answers about the\nproject. If you have a question that isn't answered here, please\n[open a discussion](https://github.com/shuding/nextra/discussions).\n\n<details>\n  {/* prettier-ignore */}\n  <summary>Can I use Nextra with Next.js `pages` router?</summary>\nNextra 4 only works with the `app` router. Only Nextra 1/2/3 supports the\n`pages` router.\n\n</details>\n\n<details>\n  <summary>Can I use X with Nextra?</summary>\nThe answer is \"yes\" for most things. Since Nextra is just a Next.js plugin, almost all the things\nthat can be done with React can be done with Nextra. Here are some examples and guides:\n\n- [Use Tailwind CSS](/docs/guide/tailwind-css)\n- [Use custom CSS and Sass](/docs/guide/custom-css)\n- [Use custom fonts](https://nextjs.org/docs/basic-features/font-optimization)\n\n</details>\n\n<details>\n  {/* prettier-ignore */}\n  <summary>How can I add a live coding component in Nextra?</summary>\nThere are libraries like [Sandpack](https://sandpack.codesandbox.io) and\n[react-live](https://github.com/FormidableLabs/react-live) that can help you\nadd live coding components to your MDX.\n\n</details>\n"
  },
  {
    "path": "docs/app/env.d.ts",
    "content": "declare module '*.svg?svgr' {\n  import type { FC, SVGProps } from 'react'\n  const ReactComponent: FC<SVGProps<SVGElement>>\n\n  export default ReactComponent\n}\n\ndeclare module '*.mdx' {\n  import type { FC } from 'react'\n  import type { MDXComponents } from 'nextra/mdx-components'\n  const ReactComponent: FC<{\n    components?: MDXComponents\n  }>\n  export default ReactComponent\n}\n"
  },
  {
    "path": "docs/app/globals.css",
    "content": "@import 'nextra-theme-docs/style.css';\n@import 'tailwindcss';\n/* Whitelist Tailwind CSS classes from <Bleed> TSDoc examples */\n@source inline('aspect-video');\n@source inline('py-10');\n\n@variant dark (&:where(.dark *));\n\n@theme {\n}\n\nbody {\n  font-feature-settings:\n    'rlig' 1,\n    'calt' 1;\n}\n\n.home-content p {\n  margin-top: 1.5em;\n  line-height: 1.75em;\n}\n\ncode.text-\\[\\.9em\\] {\n  font-size: 14px;\n}\n\n@media screen and (max-width: 1200px) {\n  .home-content .hide-medium {\n    display: none;\n  }\n}\n\n@media screen and (max-width: 720px) {\n  .home-content p {\n    font-size: 0.9rem;\n  }\n\n  .home-content .hide-small {\n    display: none;\n  }\n}\n\n/* adds labels to the sidebar links */\n.badge-new {\n  @apply dark:after:border-blue-200/30 dark:after:bg-blue-900/30 dark:after:text-blue-200;\n  &:after {\n    @apply ms-1.5 rounded-full border border-blue-200 bg-blue-100 px-1.5 text-xs font-bold text-blue-900 content-[\"New\"];\n  }\n}\n"
  },
  {
    "path": "docs/app/layout.tsx",
    "content": "import { getEnhancedPageMap } from '@components/get-page-map'\nimport { NextraLogo, VercelLogo } from '@components/icons'\nimport { ChatButton } from '@components/inkeep-chat-button'\nimport cn from 'clsx'\nimport type { Metadata } from 'next'\nimport NextImage from 'next/image'\nimport { Footer, Layout, Link, Navbar } from 'nextra-theme-docs'\nimport { Anchor, Banner, Head } from 'nextra/components'\nimport type { FC } from 'react'\nimport inkeep from './showcase/_logos/inkeep.png'\nimport xyflow from './showcase/_logos/xyflow.png'\nimport './globals.css'\n\nexport const metadata: Metadata = {\n  description: 'Make beautiful websites with Next.js & MDX.',\n  metadataBase: new URL('https://nextra.site'),\n  keywords: [\n    'Nextra',\n    'Next.js',\n    'React',\n    'JavaScript',\n    'MDX',\n    'Markdown',\n    'Static Site Generator'\n  ],\n  generator: 'Next.js',\n  applicationName: 'Nextra',\n  appleWebApp: {\n    title: 'Nextra'\n  },\n  title: {\n    default: 'Nextra – Next.js Static Site Generator',\n    template: '%s | Nextra'\n  },\n  openGraph: {\n    // https://github.com/vercel/next.js/discussions/50189#discussioncomment-10826632\n    url: './',\n    siteName: 'Nextra',\n    locale: 'en_US',\n    type: 'website'\n  },\n  other: {\n    'msapplication-TileColor': '#fff'\n  },\n  twitter: {\n    site: 'https://nextra.site'\n  },\n  alternates: {\n    // https://github.com/vercel/next.js/discussions/50189#discussioncomment-10826632\n    canonical: './'\n  }\n}\n\nconst banner = (\n  <Banner>\n    🎉 Nextra 4.0 has been released.{' '}\n    <Link href=\"https://the-guild.dev/blog/nextra-4\" className=\"text-current!\">\n      Read blogpost\n    </Link>\n  </Banner>\n)\nconst navbar = (\n  <Navbar\n    logo={\n      <NextraLogo\n        height=\"20\"\n        className={cn(\n          'hover:transition-all hover:duration-1000 motion-reduce:hover:transition-none',\n          '[mask-image:linear-gradient(60deg,#000_25%,rgba(0,0,0,.2)_50%,#000_75%)] [mask-size:400%] [mask-position:0]',\n          'hover:[mask-position:100%]'\n        )}\n      />\n    }\n    projectLink=\"https://github.com/shuding/nextra\"\n  />\n)\nconst footer = (\n  <Footer className=\"flex-col items-center md:items-start\">\n    <a\n      className=\"x:focus-visible:nextra-focus flex items-center gap-1\"\n      target=\"_blank\"\n      rel=\"noreferrer\"\n      title=\"vercel.com homepage\"\n      href=\"https://vercel.com?utm_source=nextra.site\"\n    >\n      Powered by\n      <VercelLogo height=\"20\" />\n    </a>\n    <p className=\"mt-6 text-xs\">\n      © {new Date().getFullYear()} The Nextra Project.\n    </p>\n  </Footer>\n)\n\nconst RootLayout: FC<LayoutProps<'/'>> = async ({ children }) => {\n  const pageMap = await getEnhancedPageMap()\n  return (\n    <html lang=\"en\" dir=\"ltr\" suppressHydrationWarning>\n      <Head />\n      <body>\n        <ChatButton />\n        <Layout\n          banner={banner}\n          navbar={navbar}\n          pageMap={pageMap}\n          docsRepositoryBase=\"https://github.com/shuding/nextra/tree/main/docs\"\n          editLink=\"Edit this page on GitHub\"\n          sidebar={{ defaultMenuCollapseLevel: 1 }}\n          footer={footer}\n          toc={{\n            extraContent: (\n              <>\n                <b className=\"mt-2 text-xs\">Sponsored by:</b>\n                {[\n                  {\n                    url: 'https://inkeep.com',\n                    alt: 'AI Agents that get real work done',\n                    img: inkeep\n                  },\n                  {\n                    url: 'https://xyflow.com',\n                    alt: 'Wire your ideas with xyflow!',\n                    img: xyflow\n                  }\n                ].map(o => (\n                  <Anchor\n                    key={o.url}\n                    href={`${o.url}?utm_source=nextra.site&utm_campaign=nextra&utm_content=sidebarLink`}\n                  >\n                    <NextImage\n                      src={o.img}\n                      title={o.alt}\n                      alt={o.alt}\n                      className=\"nextra-border rounded-sm border\"\n                    />\n                  </Anchor>\n                ))}\n              </>\n            )\n          }}\n        >\n          {children}\n        </Layout>\n      </body>\n    </html>\n  )\n}\n\nexport default RootLayout\n"
  },
  {
    "path": "docs/app/not-found.ts",
    "content": "export { NotFoundPage as default } from 'nextra-theme-docs'\n"
  },
  {
    "path": "docs/app/og/route.tsx",
    "content": "/* eslint react/no-unknown-property: ['error', { ignore: ['tw'] }] */\nimport { NextraLogo } from '@components/icons'\nimport { ImageResponse } from 'next/og'\n\nexport const runtime = 'edge'\n\n// eslint-disable-next-line unicorn/prefer-top-level-await -- this will break og image\nconst font = fetch(new URL('Inter-SemiBold.otf', import.meta.url)).then(res =>\n  res.arrayBuffer()\n)\n\nexport async function GET(req: Request): Promise<Response> {\n  try {\n    const { searchParams } = new URL(req.url)\n\n    // ?title=<title>\n    const title =\n      searchParams.get('title')?.slice(0, 75) || 'Nextra Documentation'\n\n    return new ImageResponse(\n      <div\n        tw=\"text-white px-20 py-[70px] bg-[#030303] h-full w-full flex justify-between flex-col\"\n        style={{\n          backgroundImage:\n            'radial-gradient(circle at 25px 25px, #333 2%, transparent 0%), radial-gradient(circle at 75px 75px, #333 2%, transparent 0%)',\n          backgroundSize: '100px 100px',\n          backgroundPosition: '-30px -10px'\n        }}\n      >\n        <NextraLogo height=\"40\" />\n        <h1\n          tw=\"text-transparent text-[82px] m-0 mb-10 tracking-tighter leading-[1.1]\"\n          style={{\n            textShadow: '0 2px 30px #000',\n            backgroundImage: 'linear-gradient(90deg, #fff 40%, #aaa)',\n            backgroundClip: 'text',\n            // To preserve new line\n            whiteSpace: 'pre'\n          }}\n        >\n          {title}\n        </h1>\n        <p tw=\"m-0 text-3xl tracking-tight\">\n          Create beautiful websites with Next.js & MDX.\n        </p>\n      </div>,\n      {\n        width: 1200,\n        height: 630,\n        fonts: [\n          {\n            name: 'inter',\n            data: await font,\n            style: 'normal'\n          }\n        ]\n      }\n    )\n  } catch (error) {\n    console.error(error)\n    return new Response('Failed to generate the image', { status: 500 })\n  }\n}\n"
  },
  {
    "path": "docs/app/page.css",
    "content": ".content-container {\n  max-width: var(--nextra-content-width);\n  padding-left: max(env(safe-area-inset-left), 1.5rem);\n  padding-right: max(env(safe-area-inset-right), 1.5rem);\n  margin: 0 auto;\n}\n.features-container {\n  margin: 8rem 0 0;\n  padding: 4rem 0;\n  background-color: #f3f4f6;\n}\n.features-container .content-container {\n  margin-top: -8rem;\n}\n.dark .features-container {\n  background-color: #000;\n}\n.headline {\n  display: inline-flex;\n  font-size: 3.125rem;\n  font-size: min(4.375rem, max(8vw, 2.5rem));\n  font-weight: 700;\n  font-feature-settings: initial;\n  letter-spacing: -0.12rem;\n  margin-left: -0.2rem;\n  margin-top: 3.4rem;\n  line-height: 1.1;\n  background-image: linear-gradient(146deg, #000, #757a7d);\n  -webkit-background-clip: text;\n  -webkit-text-fill-color: transparent;\n  background-clip: text;\n}\n.dark .headline {\n  background-image: linear-gradient(146deg, #fff, #757a7d);\n}\n.subtitle {\n  font-size: 1.3rem;\n  font-size: min(1.3rem, max(3.5vw, 1.2rem));\n  font-feature-settings: initial;\n  line-height: 1.6;\n}\n#docs-card {\n  color: #fff;\n  text-shadow: 0 0 1rem rgba(0, 0, 0, 0.1);\n}\n\n#docs-card img {\n  object-fit: cover;\n  object-position: left;\n  position: absolute;\n  left: 0;\n  right: 0;\n  top: 0;\n  bottom: 0;\n  height: 100%;\n  z-index: 0;\n  user-select: none;\n  pointer-events: none;\n}\n#docs-card img:nth-child(2) {\n  display: none;\n}\n.dark #docs-card img:nth-child(2) {\n  display: initial;\n}\n.dark #docs-card img:nth-child(1) {\n  display: none;\n}\n#highlighting-card {\n  min-height: 300px;\n  background-image:\n    linear-gradient(to top, transparent, #fff 50%),\n    url(/assets/syntax-highlighting.svg);\n  background-size: 634px;\n  background-position: -6px calc(100% + 4px);\n  background-repeat: no-repeat;\n}\n.dark #highlighting-card {\n  background-image:\n    linear-gradient(to top, transparent, #202020 50%),\n    url(/assets/syntax-highlighting.svg);\n}\n.feat-darkmode {\n  min-height: 300px;\n}\n.feat-darkmode h3 {\n  font-size: 48px;\n}\n#search-card {\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n}\n#search-card p {\n  max-width: 320px;\n}\n#search-card video {\n  position: absolute;\n  right: 0;\n  top: 24px;\n  height: 430px;\n  pointer-events: none;\n  max-width: 60%;\n}\n#fs-card {\n  min-height: 240px;\n}\n#fs-card h3 {\n  text-align: left;\n  width: min(300px, 41%);\n  min-width: 155px;\n}\n#a11y-card {\n  background-image: url(/assets/high-contrast.png);\n  background-position: -160px 160px;\n}\n@media screen and (max-width: 1300px) {\n  #a11y-card {\n    background-image:\n      linear-gradient(to bottom, white, transparent),\n      url(/assets/high-contrast.png);\n  }\n}\n@media screen and (max-width: 1200px) {\n  #highlighting-card {\n    aspect-ratio: auto;\n  }\n  .feat-darkmode h3 {\n    font-size: 4vw;\n    font-size: min(48px, max(4vw, 30px));\n  }\n  #search-card video {\n    aspect-ratio: 787/623;\n    height: auto;\n  }\n  .headline {\n    letter-spacing: -0.08rem;\n  }\n}\n@media screen and (max-width: 1024px) {\n  #docs-card {\n    aspect-ratio: 135/86;\n  }\n  #search-card {\n    aspect-ratio: 8/3;\n  }\n  #search-card h3 {\n    text-align: left;\n  }\n  #highlighting-card {\n    background-size: 136%;\n  }\n  #a11y-card {\n    background-image: url(/assets/high-contrast.png);\n    background-position: center 160px;\n  }\n}\n@media screen and (max-width: 768px) {\n  #docs-card {\n    min-height: 348px;\n    width: 100%;\n    aspect-ratio: auto;\n  }\n  #docs-card img {\n    object-position: -26px 0;\n    width: 250%;\n    max-width: initial;\n  }\n}\n@media screen and (max-width: 640px) {\n  #search-card {\n    aspect-ratio: 2.5/2;\n    justify-content: flex-start;\n    align-items: stretch;\n    min-height: 350px;\n  }\n  #search-card h3 {\n    text-align: center;\n  }\n  #search-card p {\n    max-width: 100%;\n  }\n  #search-card video {\n    position: relative;\n    margin: 0.75em -1.75em 0;\n    max-width: calc(100% + 3.5em);\n  }\n  .dark #search-card video {\n    mix-blend-mode: lighten;\n  }\n}\n"
  },
  {
    "path": "docs/app/page.module.css",
    "content": ".file {\n  display: inline-block;\n  font-size: 0.9em;\n  padding: 1px 6px;\n  border-radius: 0.375rem;\n  border: 1px solid #0077ff;\n  color: #0077ff;\n  font-weight: 600;\n  cursor: default;\n  user-select: none;\n}\n.file.active {\n  background-color: #0077ff;\n  color: white;\n}\n\n.comparison {\n  display: flex;\n  justify-content: space-evenly;\n  align-items: center;\n}\n.comparison > svg {\n  opacity: 0.3;\n}\n\n.optimization {\n  display: flex;\n  justify-content: center;\n  margin: 0;\n  padding: 1.5rem 1rem;\n  background: linear-gradient(27deg, #3d3d3d, #000000);\n  color: #e3e3e3;\n  border-radius: 0.375rem;\n  font-weight: 300;\n}\n\n:global(.dark) .optimization {\n  background: linear-gradient(27deg, #3d3d3d, #252525);\n}\n\na.cta {\n  display: inline-block;\n  background: linear-gradient(to bottom, #238aff, #0077ff);\n  text-decoration: none;\n  border-radius: 9999px;\n  color: white;\n  padding: 0.75rem 1.5rem;\n  margin-top: 0.5rem;\n  text-shadow: 0 1px 1px #00387838;\n  box-shadow: 0 1px 2px #00295738;\n  transition: all 0.2s ease;\n  -webkit-user-drag: none;\n  user-select: none;\n  -webkit-tap-highlight-color: transparent;\n}\na.cta span {\n  display: inline-block;\n  transition: all 0.2s ease;\n}\na.cta:hover span {\n  transform: translateX(3px);\n}\na.cta:hover {\n  box-shadow: 0 5px 30px -10px #0078ffab;\n  filter: brightness(1.05);\n}\na.cta:active {\n  box-shadow: 0 1px 3px #00295738;\n  filter: brightness(0.95);\n}\na.cta:active span {\n  transform: translateX(5px);\n}\na.cta:focus-visible {\n  outline: 2px solid\n    hsl(var(--nextra-primary-hue) var(--nextra-primary-saturation) 77%);\n  outline-offset: 2px;\n}\na.cta:focus-visible span {\n  transform: translateX(3px);\n}\n"
  },
  {
    "path": "docs/app/page.tsx",
    "content": "import { ArrowRightIcon } from '@components/icons'\nimport type { Metadata } from 'next'\nimport Image from 'next/image'\nimport { Link } from 'nextra-theme-docs'\nimport { MdxIcon } from 'nextra/icons'\nimport docsCardDark from 'public/assets/card-1.dark.png'\nimport docsCard from 'public/assets/card-1.png'\nimport { Feature, Features } from './_components/features'\nimport { MotionDiv, MotionH3 } from './_components/framer-motion'\nimport { I18n } from './_components/i18n-demo'\nimport styles from './page.module.css'\nimport './page.css'\nimport type { FC } from 'react'\n\nexport const metadata: Metadata = {\n  description:\n    'Build fast, customizable, and content-rich websites with Nextra. Powered by Next.js, it offers seamless Markdown support, customizable themes, file conventions, and easy integration with MDX, making it perfect for documentation, blogs, and static websites.'\n}\n\nconst IndexPage: FC = () => {\n  return (\n    <div className=\"home-content\">\n      <div className=\"content-container\">\n        <h1 className=\"headline\">\n          Make beautiful websites <br className=\"max-sm:hidden\" />\n          with Next.js & MDX\n        </h1>\n        <p className=\"subtitle\">\n          Simple, powerful and flexible site generation framework{' '}\n          <br className=\"max-md:hidden\" />\n          with everything you love from{' '}\n          <Link href=\"https://nextjs.org\" className=\"text-current\">\n            Next.js\n          </Link>\n          .\n        </p>\n        <p className=\"subtitle\">\n          <Link className={styles.cta} href=\"/docs\">\n            Get started <span>→</span>\n          </Link>\n        </p>\n      </div>\n      <div className=\"features-container x:border-b nextra-border\">\n        <div className=\"content-container\">\n          <Features>\n            <Feature\n              index={0}\n              large\n              centered\n              id=\"docs-card\"\n              href=\"/docs/docs-theme/start\"\n            >\n              <Image src={docsCard} alt=\"Background\" loading=\"eager\" />\n              <Image\n                src={docsCardDark}\n                alt=\"Background (Dark)\"\n                loading=\"eager\"\n              />\n              <h3>\n                Full-power documentation <br className=\"show-on-mobile\" />\n                in minutes\n              </h3>\n            </Feature>\n            <Feature index={1} centered href=\"/docs/guide/image\">\n              <h3>\n                Links and images are <br className=\"show-on-mobile\" />\n                always <span className=\"font-light\">optimized</span>\n              </h3>\n              <p className=\"mb-8 text-start\">\n                Nextra automatically converts Markdown links and images to use{' '}\n                <Link href=\"https://nextjs.org/docs/routing/introduction#linking-between-pages\">\n                  Next.js Link\n                </Link>{' '}\n                and{' '}\n                <Link href=\"https://nextjs.org/docs/app/getting-started/images#local-images\">\n                  Next.js Image\n                </Link>{' '}\n                when possible. No slow navigation or layout shift.\n              </p>\n              <div>\n                <div className={styles.optimization}>\n                  <div style={{ fontSize: '.9rem' }} className=\"leading-8\">\n                    <code>[Learn more](/more)</code>\n                    <br />\n                    <code>![Hero](/hero.png)</code>\n                  </div>\n                </div>\n                <ArrowRightIcon\n                  width=\"1.2em\"\n                  className=\"mx-auto my-6 rotate-90 text-neutral-600 dark:text-neutral-400\"\n                />\n                <div className={styles.optimization}>\n                  <div style={{ fontSize: '.9rem' }} className=\"leading-8\">\n                    <code>{'<Link .../>'}</code>\n                    <br />\n                    <code>{'<Image .../>'}</code>\n                  </div>\n                </div>\n              </div>\n            </Feature>\n            <Feature\n              index={2}\n              id=\"highlighting-card\"\n              href=\"/docs/guide/syntax-highlighting\"\n            >\n              <h3>\n                Advanced syntax <br className=\"show-on-mobile\" />\n                highlighting solution\n              </h3>\n              <p>\n                Performant and reliable build-time syntax highlighting powered\n                by <Link href=\"https://shiki.style\">Shiki</Link>.\n              </p>\n            </Feature>\n            <Feature index={3} href=\"/docs/guide/i18n\">\n              <h3>\n                I18n as easy as <br className=\"show-on-mobile\" />\n                creating new files\n              </h3>\n              <p className=\"mb-4\">\n                Place your page files in folders specific to each locale, Nextra\n                and Next.js will handle the rest for you.\n              </p>\n              <I18n />\n            </Feature>\n            <Feature\n              index={4}\n              centered\n              className=\"flex flex-col items-center justify-center bg-[url(/assets/gradient-bg.jpeg)] bg-cover bg-center text-white\"\n              href=\"/docs/guide/markdown\"\n            >\n              <MdxIcon className=\"w-4/6 [filter:drop-shadow(0_2px_10px_rgba(0,0,0,.1))]\" />\n              <p style={{ textShadow: '0 2px 4px rgb(0 0 0 / 20%)' }}>\n                <Link\n                  href=\"https://mdxjs.com/blog/v3\"\n                  className=\"!text-current\"\n                >\n                  MDX 3\n                </Link>{' '}\n                lets you use Components inside Markdown,{' '}\n                <br className=\"hide-medium\" />\n                with huge performance boost since v1.\n              </p>\n            </Feature>\n            <Feature\n              index={5}\n              centered\n              className=\"feat-darkmode flex items-center justify-center\"\n            >\n              <MotionDiv\n                animate={{\n                  backgroundPosition: [\n                    '0% 0%',\n                    '50% 40%',\n                    '50% 40%',\n                    '100% 100%'\n                  ],\n                  backgroundImage: [\n                    'radial-gradient(farthest-corner, #e2e5ea, #e2e5ea)',\n                    'radial-gradient(farthest-corner, #06080a, #e2e5ea)',\n                    'radial-gradient(farthest-corner, #06080a, #e2e5ea)',\n                    'radial-gradient(farthest-corner, #e2e5ea, #e2e5ea)'\n                  ]\n                }}\n                transition={{\n                  backgroundPosition: {\n                    times: [0, 0.5, 0.5, 1],\n                    repeat: Infinity,\n                    duration: 10,\n                    delay: 1\n                  },\n                  backgroundImage: {\n                    times: [0, 0.2, 0.8, 1],\n                    repeat: Infinity,\n                    duration: 10,\n                    delay: 1\n                  }\n                }}\n                style={{\n                  position: 'absolute',\n                  top: 0,\n                  left: 0,\n                  width: '100%',\n                  height: '100%',\n                  backgroundImage:\n                    'radial-gradient(farthest-corner, #06080a, #e2e5ea)',\n                  backgroundSize: '400% 400%',\n                  backgroundRepeat: 'no-repeat'\n                }}\n              />\n              <MotionH3\n                animate={{\n                  color: ['#dae5ff', '#fff', '#fff', '#dae5ff']\n                }}\n                transition={{\n                  color: {\n                    times: [0.25, 0.35, 0.7, 0.8],\n                    repeat: Infinity,\n                    duration: 10,\n                    delay: 1\n                  }\n                }}\n                style={{\n                  position: 'relative',\n                  mixBlendMode: 'difference'\n                }}\n              >\n                Dark <br />\n                mode <br />\n                included\n              </MotionH3>\n            </Feature>\n            <Feature\n              index={6}\n              large\n              id=\"search-card\"\n              href=\"/docs/docs-theme/theme-configuration#search\"\n            >\n              <h3>\n                Full-text search,\n                <br />\n                zero-config needed\n              </h3>\n              <p className=\"z-2\">\n                Nextra indexes your content automatically at build-time and\n                performs incredibly fast full-text search via{' '}\n                <Link href=\"https://github.com/cloudcannon/pagefind\">\n                  Pagefind\n                </Link>\n                .\n              </p>\n              <div className=\"absolute inset-0 z-1 size-full bg-[linear-gradient(to_right,white_250px,_transparent)] max-sm:hidden dark:bg-[linear-gradient(to_right,#202020_250px,_transparent)]\" />\n              <video\n                autoPlay\n                loop\n                muted\n                playsInline\n                className=\"x:focus-visible:nextra-focus block dark:hidden\"\n              >\n                <source src=\"/assets/search.mp4\" type=\"video/mp4\" />\n              </video>\n              <video\n                autoPlay\n                loop\n                muted\n                playsInline\n                className=\"x:focus-visible:nextra-focus hidden -translate-x-4 dark:block\"\n              >\n                <source src=\"/assets/search-dark.mp4\" type=\"video/mp4\" />\n              </video>\n            </Feature>\n            <Feature\n              index={7}\n              large\n              id=\"fs-card\"\n              style={{\n                color: 'white',\n                backgroundImage:\n                  'url(/assets/routing.png), url(/assets/gradient-bg.jpeg)',\n                backgroundSize: '140%, 180%',\n                backgroundPosition: '130px -8px, top',\n                backgroundRepeat: 'no-repeat',\n                textShadow: '0 1px 6px rgb(38 59 82 / 18%)',\n                aspectRatio: '1.765'\n              }}\n              href=\"/docs/docs-theme/page-configuration\"\n            >\n              <h3>\n                Organize pages intuitively, <br />\n                with file-system routing from Next.js\n              </h3>\n            </Feature>\n            <Feature\n              index={8}\n              id=\"a11y-card\"\n              style={{\n                backgroundSize: 750,\n                backgroundRepeat: 'no-repeat',\n                minHeight: 288\n              }}\n            >\n              <h3>A11y as a top priority</h3>\n              <p>\n                Nextra respects system options <br className=\"show-on-mobile\" />\n                such as <b>Increase Contrast</b> and <b>Reduce Motion</b>.\n              </p>\n            </Feature>\n            <Feature index={9} href=\"/docs/guide/ssg\">\n              <h3>\n                Hybrid rendering, <br />\n                next generation\n              </h3>\n              <p className=\"mr-6\">\n                You can leverage the hybrid rendering power from Next.js with\n                your Markdown content including{' '}\n                <Link href=\"https://nextjs.org/docs/app/building-your-application/rendering/server-components\">\n                  Server Components\n                </Link>\n                ,{' '}\n                <Link href=\"https://nextjs.org/docs/app/building-your-application/rendering/client-components\">\n                  Client Components\n                </Link>\n                , and{' '}\n                <Link href=\"https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration\">\n                  Incremental Static Regeneration (ISR)\n                </Link>\n                .\n              </p>\n            </Feature>\n            <Feature index={10} large>\n              <h3>And more...</h3>\n              <p>\n                SEO / RTL Layout / Pluggable Themes / Built-in Components / Last\n                Git Edit Time / Multi-Docs...\n                <br />A lot of new possibilities to be explored.\n              </p>\n              <p className=\"subtitle\">\n                <Link className=\"no-underline\" href=\"/docs\">\n                  Start using Nextra →\n                </Link>\n              </p>\n            </Feature>\n          </Features>\n        </div>\n      </div>\n    </div>\n  )\n}\n\nexport default IndexPage\n"
  },
  {
    "path": "docs/app/showcase/page.mdx",
    "content": "---\ndescription:\n  Explore projects powered by Nextra, showcasing a diverse range of websites and\n  applications built with this powerful Next.js framework, from GraphQL tools to\n  JavaScript resources.\n---\n\nimport { Cards, Image } from 'nextra/components'\nimport { cloneElement } from 'react'\n\n# Showcase\n\nProjects powered by Nextra\n\n{/* prettier-ignore */}\n<Cards>\n<>[![React Flow preview](./_logos/react-flow.jpg)](https://reactflow.dev)</>\n<>[![Svelte Flow preview](./_logos/svelte-flow.jpg)](https://svelteflow.dev)</>\n<>[![Speakeasy preview](./_logos/speakeasy.png)](https://speakeasy.com/docs)</>\n<>[![The Graph preview](./_logos/thegraph.jpeg)](https://thegraph.com/docs/en)</>\n<>[![GraphQL preview](./_logos/graphql.png)](https://graphql.org)</>\n<>[![GraphQL Hive preview](./_logos/graphql-hive.png)](https://the-guild.dev/graphql/hive)</>\n<>[![SWR preview](./_logos/swr.png)](https://swr.vercel.app)</>\n<>[![COBE preview](./_logos/cobe.png)](https://cobe.vercel.app)</>\n<>[![JavaScript Patterns preview](./_logos/javascript-patterns.jpg)](https://javascriptpatterns.vercel.app)</>\n<>[![CodeSandbox preview](./_logos/codesandbox.jpg)](https://codesandbox.io/docs/learn/introduction/overview)</>\n<>[![DocsGPT preview](./_logos/docsgpt.png)](https://docs.docsgpt.co.uk)</>\n<>[![CloudQuery preview](./_logos/cloudquery.svg)](https://cloudquery.io)</>\n<>[![Edge Runtime preview](./_logos/edge-runtime.jpeg)](https://edge-runtime.vercel.app)</>\n<>[![Sound.xyz preview](./_logos/sound.xyz.png)](https://docs.sound.xyz)</>\n<>[![Panda preview](./_logos/panda.png)](https://panda-css.com)</>\n<>[![Kuma UI preview](./_logos/kuma-ui.png)](https://kuma-ui.com)</>\n<>[![Langfuse Open Source LLM Engineering Platform](./_logos/langfuse.png)](https://langfuse.com)</>\n<>[![The Guild Blog preview](./_logos/the-guild.png)](https://the-guild.dev)</>\n<>[![GraphQL Yoga preview](./_logos/graphql-yoga.png)](https://the-guild.dev/graphql/yoga-server)</>\n<>[![GraphQL Envelop preview](./_logos/graphql-envelop.png)](https://the-guild.dev/graphql/envelop)</>\n<>[![GraphQL Inspector preview](./_logos/graphql-inspector.png)](https://the-guild.dev/graphql/inspector)</>\n<>[![GraphQL Code Generator preview](./_logos/graphql-codegen.png)](https://the-guild.dev/graphql/codegen)</>\n<>[![GraphQL Mesh preview](./_logos/graphql-mesh.png)](https://the-guild.dev/graphql/mesh)</>\n<>[![GraphQL Tools preview](./_logos/graphql-tools.png)](https://the-guild.dev/graphql/tools)</>\n<>[![GraphQL Modules preview](./_logos/graphql-modules.png)](https://the-guild.dev/graphql/modules)</>\n<>[![GraphQL ESLint preview](./_logos/graphql-eslint.png)](https://the-guild.dev/graphql/eslint)</>\n<>[![GraphQL Config preview](./_logos/graphql-config.png)](https://the-guild.dev/graphql/config)</>\n<>[![GraphQL Scalars preview](./_logos/graphql-scalars.png)](https://the-guild.dev/graphql/scalars)</>\n<>[![GraphQL Shield preview](./_logos/graphql-shield.png)](https://the-guild.dev/graphql/shield)</>\n<>[![GraphQL SOFA preview](./_logos/graphql-sofa.png)](https://the-guild.dev/graphql/sofa-api)</>\n<>[![Apollo Angular preview](./_logos/apollo-angular.png)](https://the-guild.dev/graphql/apollo-angular)</>\n<>[![GraphQL SSE preview](./_logos/graphql-sse.png)](https://the-guild.dev/graphql/sse)</>\n<>[![GraphQL WS preview](./_logos/graphql-ws.png)](https://the-guild.dev/graphql/ws)</>\n<>[![feTS preview](./_logos/fets.png)](https://the-guild.dev/openapi/fets)</>\n<>[![JavaScript Code Challenges preview](./_logos/jscodechallenges.png)](https://jscodechallenges.vercel.app)</>\n<>[![React Cosmos preview](./_logos/react-cosmos.png)](https://reactcosmos.org)</>\n<>[![Typia preview](./_logos/typia.png)](https://typia.io)</>\n<>[![Nestia preview](./_logos/nestia.png)](https://nestia.io)</>\n<>[![Safe preview](./_logos/safe-core.png)](https://docs.safe.global)</>\n<>[![Auth.js preview](./_logos/authjs.png)](https://authjs.dev)</>\n<>[![imgix preview](./_logos/imgix.png)](https://docs.imgix.com)</>\n<>[![AnythingLLM preview](./_logos/anythingllm.png)](https://anythingllm.com)</>\n<>[![Redbrick preview](./_logos/redbrick.jpg)](https://wiki.redbrick.land)</>\n<>[![Makeform preview](./_logos/makeform.png)](https://www.makeform.ai/help)</>\n<>[![EmbedPDF preview](./_logos/embedpdf.png)](https://www.embedpdf.com)</>\n<>[![Reactylon preview](./_logos/reactylon.png)](https://www.reactylon.com/docs)</>\n</Cards>\n\nexport default function MdxLayout(props) {\n  return cloneElement(props.children, {\n    components: {\n      img: props => (\n        <Image {...props} className=\"[aspect-ratio:12/6.3] object-cover\" />\n      ),\n      a({ children, href }) {\n        const { alt } = children.props\n        return (\n          <Cards.Card\n            href={href}\n            title={alt.replace(/ preview$/i, '')}\n            target=\"_blank\"\n            rel=\"noreferrer\"\n            arrow\n            className=\"!no-underline\"\n          >\n            {children}\n          </Cards.Card>\n        )\n      },\n      p(props) {\n        return (\n          <p\n            {...props}\n            className=\"mt-4 mb-16 text-center text-lg text-gray-600 dark:text-gray-400\"\n          />\n        )\n      }\n    }\n  })\n}\n"
  },
  {
    "path": "docs/app/sponsors/page.mdx",
    "content": "---\ndescription:\n  Support Nextra by exploring its sponsors. Learn how they contribute to the\n  development and success of the Nextra framework\n---\n\nimport { Button, Cards, Image } from 'nextra/components'\nimport { cloneElement } from 'react'\n\n# Sponsors\n\n<div className=\"mb-12 text-center\">\n  <Button\n    className=\"mt-3 inline-block !px-6 hover:!no-underline\"\n    variant=\"outline\"\n    href=\"https://github.com/sponsors/dimaMachina\"\n    as=\"a\"\n    target=\"_blank\"\n    rel=\"noreferrer\"\n  >\n    {'Become a Sponsor'}\n  </Button>\n</div>\n\n{/* prettier-ignore */}\n<Cards num={3}>\n<>[![Inkeep - AI Agents that get real work done](../showcase/_logos/inkeep.png)](https://inkeep.com)</>\n<>[![xyflow preview](../showcase/_logos/xyflow.png)](https://xyflow.com)</>\n</Cards>\n\nexport default function MdxLayout(props) {\n  return cloneElement(props.children, {\n    components: {\n      img: props => (\n        <Image {...props} className=\"[aspect-ratio:12/6.3] object-cover\" />\n      ),\n      a({ children, href }) {\n        const { alt } = children.props\n        return (\n          <Cards.Card\n            href={`${href}?utm_source=nextra.site&utm_campaign=nextra&utm_content=logolink`}\n            title={alt.replace(/ preview$/i, '')}\n            target=\"_blank\"\n            rel=\"noreferrer\"\n            arrow\n            className=\"!no-underline\"\n          >\n            {children}\n          </Cards.Card>\n        )\n      }\n    }\n  })\n}\n"
  },
  {
    "path": "docs/components/_slider.tsx",
    "content": "'use client'\n\nimport type { ComponentProps, FC } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\n\nexport const Slider: FC<{\n  cssVar: string\n  max: number\n}> = ({ cssVar, max }) => {\n  const handleChange: NonNullable<ComponentProps<'input'>['onChange']> =\n    useCallback(\n      e => {\n        const value = `${e.target.value}${max === 360 ? 'deg' : '%'}`\n        e.target.nextSibling!.textContent = value\n        document.documentElement.style.setProperty(cssVar, value)\n      },\n      [cssVar, max]\n    )\n\n  return (\n    <div className=\"flex h-6 items-center gap-2\">\n      <input\n        type=\"range\"\n        className=\"w-28\"\n        onChange={handleChange}\n        step=\"1\"\n        min=\"0\"\n        max={max}\n      />\n      <label className=\"w-14 text-sm text-gray-600 dark:text-gray-400\" />\n    </div>\n  )\n}\n\nfunction hexToRgb(hex: `#${string}`): string {\n  const bigint = Number.parseInt(hex.slice(1), 16)\n  const r = (bigint >> 16) & 255\n  const g = (bigint >> 8) & 255\n  const b = bigint & 255\n  return `${r},${g},${b}`\n}\n\nexport const BackgroundColor: FC = () => {\n  const [value, setValue] = useState('')\n  useEffect(() => {\n    const color = getComputedStyle(document.body).getPropertyValue(\n      '--nextra-bg'\n    )\n    setValue(color)\n  }, [])\n\n  return (\n    <div className=\"flex h-6 items-center gap-2\">\n      <input\n        type=\"color\"\n        value={value}\n        onChange={e => {\n          const { value } = e.target\n          e.target.nextSibling!.textContent = value\n          document.documentElement.style.setProperty(\n            '--nextra-bg',\n            hexToRgb(value as `#${string}`)\n          )\n        }}\n      />\n      <label className=\"w-20 text-sm text-gray-600 dark:text-gray-400\" />\n    </div>\n  )\n}\n"
  },
  {
    "path": "docs/components/_table/index.tsx",
    "content": "import type { FC } from 'react'\nimport styles from './style.module.css'\n\nexport const OptionTable: FC<{ options: [string, string, any] }> = ({\n  options\n}) => {\n  return (\n    <div\n      className={\n        '-mx-6 mt-6 mb-4 overflow-x-auto overscroll-x-contain px-6 pb-4 ' +\n        styles.container\n      }\n    >\n      <table className=\"w-full border-collapse text-sm\">\n        <thead>\n          <tr className=\"border-b py-4 text-start dark:border-neutral-700\">\n            <th className=\"py-2 font-semibold\">Option</th>\n            <th className=\"py-2 pl-6 font-semibold\">Type</th>\n            <th className=\"px-6 py-2 font-semibold\">Description</th>\n          </tr>\n        </thead>\n        <tbody className=\"align-baseline text-gray-900 dark:text-gray-100\">\n          {options.map(([option, type, description]) => (\n            <tr\n              key={option}\n              className=\"border-b border-gray-100 dark:border-neutral-700/50\"\n            >\n              <td className=\"py-2 font-mono text-xs leading-6 font-semibold whitespace-pre text-violet-600 dark:text-violet-500\">\n                {option}\n              </td>\n              <td className=\"py-2 pl-6 font-mono text-xs leading-6 font-semibold whitespace-pre text-slate-500 dark:text-slate-400\">\n                {type}\n              </td>\n              <td className=\"py-2 pl-6\">{description}</td>\n            </tr>\n          ))}\n        </tbody>\n      </table>\n    </div>\n  )\n}\n"
  },
  {
    "path": "docs/components/_table/style.module.css",
    "content": ".container {\n  mask-image: linear-gradient(\n    to right,\n    transparent 0.8em,\n    white 1.5em,\n    white calc(100% - 1.5em),\n    transparent calc(100% - 0.8em)\n  );\n}\n\n.container::-webkit-scrollbar {\n  appearance: none;\n}\n"
  },
  {
    "path": "docs/components/content-and-app-file-tree.tsx",
    "content": "import path from 'node:path'\nimport { FileTree } from 'nextra/components'\nimport type { FC, ReactNode } from 'react'\nimport { Children } from 'react'\nimport { useMDXComponents } from '../mdx-components'\n\n// @ts-expect-error -- fixme\nfunction mapChildren(children) {\n  return Children.map(children, child => {\n    const { name, ext } = path.parse(child.props.name)\n    if (name === '_meta') {\n      return child\n    }\n    if (ext === '.md' || ext === '.mdx') {\n      const file = <FileTree.File {...child.props} name={`page${ext}`} />\n      if (name === 'index') {\n        return file\n      }\n      return <FileTree.Folder name={name}>{file}</FileTree.Folder>\n    }\n    if (!ext) {\n      return (\n        <FileTree.Folder {...child.props}>\n          {mapChildren(child.props.children)}\n        </FileTree.Folder>\n      )\n    }\n    return child\n    // @ts-expect-error -- fixme\n  }).sort((a, b) => {\n    const aName = a.props.name\n    const bName = b.props.name\n    const isAFolder = a.props.children\n    const isBFolder = b.props.children\n    if (isAFolder && !isBFolder) return -1\n    if (isBFolder && !isAFolder) return 1\n    return aName.localeCompare(bName)\n  })\n}\n\nexport const ContentAndAppFileTee: FC<{\n  children: ReactNode\n  className: string\n}> = ({ children, className }) => {\n  const { a: Link, code: Code } = useMDXComponents()\n  const layout = <FileTree.File name=\"layout.jsx\" />\n  return (\n    <>\n      <FileTree className={className}>\n        <b>\n          Using{' '}\n          <Link href=\"/docs/file-conventions/content-directory\">\n            <Code>content</Code> directory\n          </Link>\n        </b>\n        <FileTree.Folder name=\"app\" defaultOpen>\n          <FileTree.Folder name=\"[[...mdxPath]]\">\n            <FileTree.File name=\"page.jsx\" />\n          </FileTree.Folder>\n          {layout}\n        </FileTree.Folder>\n        <FileTree.Folder name=\"content\" defaultOpen>\n          {children}\n        </FileTree.Folder>\n      </FileTree>{' '}\n      <FileTree className={className}>\n        <b>\n          Using{' '}\n          <Link href=\"/docs/file-conventions/page-file\">\n            <Code>page.mdx</Code> files\n          </Link>\n        </b>\n        <FileTree.Folder name=\"app\" defaultOpen>\n          {/* @ts-expect-error -- fixme */}\n          {mapChildren([layout, ...children])}\n        </FileTree.Folder>\n      </FileTree>\n    </>\n  )\n}\n"
  },
  {
    "path": "docs/components/example-code.tsx",
    "content": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { compileMdx } from 'nextra/compile'\nimport type { FC } from 'react'\nimport { MDXRemote } from '../../packages/nextra/dist/client/mdx-remote'\n\nexport const ExampleCode: FC<{\n  filePath: string\n  metadata: string\n  example: string\n}> = async ({ filePath, metadata, example }) => {\n  const pageContent = await fs.readFile(\n    `../examples/${example}/${filePath}`,\n    'utf8'\n  )\n  const ext = path.extname(filePath).slice(1)\n\n  const rawJs = await compileMdx(\n    `~~~${ext} filename=\"${filePath}\" showLineNumbers ${metadata}\n${pageContent.trim()}\n~~~`,\n    { defaultShowCopyCode: true }\n  )\n  return <MDXRemote compiledSource={rawJs} />\n}\n"
  },
  {
    "path": "docs/components/example-tsdoc.mdx",
    "content": "```ts\ntype Example = {\n  /**\n   * **Foo** description.\n   * @default \"dimaMachina\"\n   * @remarks `\"not dimaMachina\"`\n   */\n  foo: string\n}\n```\n\nIn this example, while the actual type of the property `foo` is `string`, the\ndisplayed type will be `\"not dimaMachina\"` as per the `@remarks` tag.\n\n<APIDocs\n  code={`\ntype Example = {\n  /**\n   * **Foo** description.\n   * @default \"dimaMachina\"\n   * @remarks \\`\"not dimaMachina\"\\`\n   */\n  foo: string\n}\nexport default Example`}\n/>\n"
  },
  {
    "path": "docs/components/generate-api-reference.ts",
    "content": "import { BoxIcon, CardsIcon, OneIcon, WarningIcon } from '@components/icons'\nimport { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'\nimport { compileMdx } from 'nextra/compile'\nimport {\n  Bleed,\n  Callout,\n  Cards,\n  FileTree,\n  Steps,\n  Table,\n  Tabs\n} from 'nextra/components'\nimport { evaluate } from 'nextra/evaluate'\nimport type { generateDefinition } from 'nextra/tsdoc'\nimport { BackgroundColor, Slider } from './_slider'\nimport ExampleTSDoc from './example-tsdoc.mdx'\nimport { PlaygroundDemo } from './playground-demo'\n\nconst { wrapper: _Wrapper, ...components } = getMDXComponents({\n  Callout,\n  Steps,\n  Bleed,\n  PlaygroundDemo,\n  ExampleTSDoc,\n  Tabs,\n  FileTree,\n  Table,\n  Cards,\n  BoxIcon,\n  CardsIcon,\n  OneIcon,\n  WarningIcon,\n  BackgroundColor,\n  Slider\n})\n\nexport interface ApiReference {\n  name: string\n  isFlattened?: boolean\n  code?: string\n  packageName?: string\n}\n\ninterface Options {\n  title: string\n  subtitle: string\n  definition: ReturnType<typeof generateDefinition>\n  bottomMdxContent?: string\n}\n\nexport async function generateApiReference(\n  apiRef: ApiReference,\n  { title, subtitle, definition, bottomMdxContent }: Options\n) {\n  const { description, tags = {} } = definition\n  const result = [\n    description &&\n      // og:description\n      `export const metadata = { description: ${JSON.stringify(description.split('\\n', 1)[0])} }`,\n    // Title\n    `# \\`${apiRef.name}\\` ${title}`,\n    // Page description\n    description,\n    apiRef.packageName && `Exported from \\`${apiRef.packageName}\\`.`,\n    // Signature\n    `## ${subtitle}`,\n    '<APIDocs definition={definition} />',\n    // Warnings\n    tags.throws &&\n      `> [!WARNING]\n>\n> Throws an ${tags.throws.replaceAll('{', '`').replaceAll('}', '`')}`,\n    // Tips\n    tags.see &&\n      `<Callout>\n**See**\n\n${tags.see}\n</Callout>`,\n    // Examples\n    tags.example &&\n      `## Example\n\n${tags.example}`,\n    // Usage\n    tags.usage &&\n      `## Usage\n\n${tags.usage}`,\n    bottomMdxContent\n  ].filter(Boolean)\n\n  const rawJs = await compileMdx(result.join('\\n\\n'))\n  return evaluate(rawJs, components, { definition })\n}\n"
  },
  {
    "path": "docs/components/get-page-map.ts",
    "content": "import type { MetaJsonFile, PageMapItem } from 'nextra'\nimport { getPageMap } from 'nextra/page-map'\nimport { pageMap as apiPageMap } from '../app/api/[name]/page'\nimport { pageMap as builtInsPageMap } from '../app/docs/built-ins/[name]/page'\n\ntype PageMapVisitor = (item: PageMapItem) => PageMapItem\n\nfunction visitPageMap(\n  pageMap: PageMapItem,\n  visitor: PageMapVisitor\n): PageMapItem\nfunction visitPageMap(\n  pageMap: PageMapItem[],\n  visitor: PageMapVisitor\n): PageMapItem[]\nfunction visitPageMap(\n  pageMap: PageMapItem[] | PageMapItem,\n  visitor: PageMapVisitor\n): PageMapItem[] | PageMapItem {\n  if (Array.isArray(pageMap)) {\n    return pageMap.map(item => visitPageMap(item, visitor))\n  }\n  if ('children' in pageMap) {\n    return visitor({\n      ...pageMap,\n      children: visitPageMap(pageMap.children, visitor)\n    })\n  }\n  return visitor(pageMap)\n}\n\nfunction createMetaItem(pageMap: typeof apiPageMap): MetaJsonFile {\n  return {\n    data: Object.fromEntries(\n      pageMap.map(o => {\n        if ('type' in o && o.type === 'separator') {\n          return [o.name, { type: 'separator', title: o.title }]\n        }\n        return [o.name, '']\n      })\n    )\n  }\n}\n\nexport const getEnhancedPageMap: typeof getPageMap = async (...args) => {\n  const rootPageMap = await getPageMap(...args)\n  const modifiedPageMap = visitPageMap(rootPageMap, item => {\n    if ('route' in item) {\n      if (item.route === '/api') {\n        return {\n          ...item,\n          children: [\n            createMetaItem(apiPageMap),\n            {\n              route: '/api',\n              name: 'index',\n              title: 'Overview'\n            },\n            ...apiPageMap\n          ]\n        }\n      }\n      if (item.route === '/docs/built-ins') {\n        return {\n          ...item,\n          children: [createMetaItem(builtInsPageMap), ...builtInsPageMap]\n        }\n      }\n    }\n    return item\n  })\n\n  return modifiedPageMap\n}\n"
  },
  {
    "path": "docs/components/icons/index.ts",
    "content": "export { default as FilesIcon } from './files.svg?svgr'\nexport { default as TailwindIcon } from './tailwind.svg?svgr'\nexport { default as LightningIcon } from './lightning.svg?svgr'\nexport { default as GlobeIcon } from './globe.svg?svgr'\nexport { default as PictureIcon } from './picture.svg?svgr'\nexport { default as CodeIcon } from './code.svg?svgr'\nexport { default as BrushIcon } from './brush.svg?svgr'\nexport { default as DropperIcon } from './dropper.svg?svgr'\nexport { default as StarsIcon } from './stars.svg?svgr'\nexport { default as FormulaIcon } from './formula.svg?svgr'\nexport { default as WarningIcon } from './warning.svg?svgr'\nexport { default as ChevronRightIcon } from './chevron-right.svg?svgr'\nexport { default as BoxIcon } from './box.svg?svgr'\nexport { default as GearIcon } from './gear.svg?svgr'\nexport { default as RowsIcon } from './rows.svg?svgr'\nexport { default as CardsIcon } from './cards.svg?svgr'\nexport { default as OneIcon } from './one.svg?svgr'\nexport { default as CloudIcon } from './cloud.svg?svgr'\nexport { default as TableIcon } from './table.svg?svgr'\nexport { default as FileIcon } from './file.svg?svgr'\nexport { default as NewsletterIcon } from './newsletter.svg?svgr'\nexport { default as ArrowRightIcon } from './arrow-right.svg?svgr'\nexport { default as SwitchIcon } from './switch.svg?svgr'\nexport { default as DiagramIcon } from './diagram.svg?svgr'\nexport { default as FolderTreeIcon } from './folder-tree.svg?svgr'\nexport { default as IdCardIcon } from './id-card.svg?svgr'\nexport { default as VercelLogo } from './vercel.svg?svgr'\nexport { default as NextraLogo } from './nextra.svg?svgr'\nexport { default as TagsIcon } from './tags.svg?svgr'\nexport { default as RSSIcon } from './rss.svg?svgr'\n"
  },
  {
    "path": "docs/components/inkeep-chat-button.tsx",
    "content": "'use client'\n\nimport { InkeepChatButton } from '@inkeep/cxkit-react'\nimport type { FC } from 'react'\n\nexport const ChatButton: FC = () => {\n  return (\n    <InkeepChatButton\n      aiChatSettings={{\n        aiAssistantAvatar: '/icon.svg',\n        aiAssistantName: 'Inkeep'\n      }}\n      baseSettings={{\n        apiKey: process.env.NEXT_PUBLIC_INKEEP_API_KEY!,\n        primaryBrandColor: '#238aff',\n        colorMode: {\n          sync: {\n            target: 'html',\n            attributes: ['class'],\n            isDarkMode(attrs) {\n              return attrs.class === 'dark'\n            }\n          }\n        },\n        theme: {\n          styles: [\n            {\n              key: 'custom-theme',\n              type: 'style',\n              // Fix icon on light theme\n              value: `\n                [data-theme=light] .ikp-chat-button__avatar-content {\n                  filter: invert(1);\n                }\n              `\n            }\n          ]\n        }\n      }}\n    />\n  )\n}\n"
  },
  {
    "path": "docs/components/install-nextra-theme.mdx",
    "content": "Add the following scripts to your `package.json`:\n\n```json filename=\"package.json\"\n\"scripts\": {\n  \"dev\": \"next\",\n  \"build\": \"next build\",\n  \"start\": \"next start\"\n},\n```\n\n> [!TIP]\n>\n> You can enable Turbopack in development by appending the `--turbopack` flag to\n> the `dev` command:\n>\n> ```diff filename=\"package.json\"\n> - \"dev\": \"next\",\n> + \"dev\": \"next --turbopack\",\n> ```\n\nYou can start the server in development mode with the following command\naccording to your package manager:\n\n```sh npm2yarn\nnpm run dev\n```\n\nor in production mode:\n\n```sh npm2yarn\nnpm run build\nnpm run start\n```\n\n> [!NOTE]\n>\n> If you're not familiar with Next.js, note that development mode is\n> significantly slower since Next.js compiles every page you navigate to.\n\n### Add Next.js config\n\nCreate a `next.config.mjs` file in your project's root directory with the\nfollowing content:\n\n```js filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\n// Set up Nextra with its configuration\nconst withNextra = nextra({\n  // ... Add Nextra-specific options here\n})\n\n// Export the final Next.js config with Nextra included\nexport default withNextra({\n  // ... Add regular Next.js options here\n})\n```\n\nWith this configuration, Nextra will handle Markdown files in your Next.js\nproject. For more Nextra configuration options, check out the\n[Guide](/docs/guide).\n\n### Add [`mdx-components` file](/docs/file-conventions/mdx-components-file)\n\n### Setup search\n\nTo set up search, follow the instructions on the\n[Search Engine](/docs/guide/search#setup) page.\n\n### Create the root layout\n\nNext, create the root layout of your application inside the `app` folder. This\nlayout will be used to configure your Nextra Theme:\n"
  },
  {
    "path": "docs/components/playground-demo.tsx",
    "content": "'use client'\n\n// NOTE: We have intentionally omitted a local mdx-components file because it\n// includes the server-only `<TSDoc>` component\nimport { useMDXComponents } from 'nextra-theme-docs'\nimport { Code, Mermaid, Playground, Pre, Tabs } from 'nextra/components'\nimport { MdxIcon } from 'nextra/icons'\nimport type { ComponentProps, FC } from 'react'\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\nconst DEFAULT_MDX = `Playground component lets you write Nextra-compatible MDX that renders only on the client. It's modeled after the functionality found in [MDX Playground](https://mdxjs.com/playground).\n\nIn some instances where remote loading MDX is not an option, this may work as a great alternative.\n\nHere's an example of a code block.\n\n\\`\\`\\`ts\nconsole.log(\"Hello world, this is a playground component!\");\n\\`\\`\\`\n\n## Caveats\n\nDue to the purely client-side nature of this component, features \"Table of Contents\" and \"Front matter\" will not work.\n\n## Mermaid Example\n\n\\`\\`\\`mermaid\ngraph TD\nsubgraph AA [Consumers]\nA[Mobile App]\nB[Web App]\nC[Node.js Client]\nend\nsubgraph BB [Services]\nE[REST API]\nF[GraphQL API]\nG[SOAP API]\nend\nZ[GraphQL API]\nA --> Z\nB --> Z\nC --> Z\nZ --> E\nZ --> F\nZ --> G\n\\`\\`\\``\n\nexport const PlaygroundDemo: FC = () => {\n  const [rawMdx, setRawMdx] = useState(DEFAULT_MDX)\n  const handleInput: NonNullable<ComponentProps<'span'>['onInput']> =\n    useCallback(e => {\n      setRawMdx(e.currentTarget.textContent)\n    }, [])\n\n  const spanRef = useRef<HTMLSpanElement>(null!)\n  const initialRender = useRef(false)\n\n  useEffect(() => {\n    if (!initialRender.current) {\n      initialRender.current = true\n      spanRef.current.textContent = rawMdx\n    }\n  }, []) // eslint-disable-line react-hooks/exhaustive-deps -- only on mount\n\n  return (\n    <div className=\"mt-6 grid grid-cols-1 gap-2 lg:grid-cols-2\">\n      <Pre\n        data-filename=\"MDX\"\n        icon={<MdxIcon height=\"1em\" className=\"shrink-0\" />}\n      >\n        <Code>\n          <span\n            ref={spanRef}\n            contentEditable\n            suppressContentEditableWarning\n            className=\"outline-none\"\n            onInput={handleInput}\n          />\n        </Code>\n      </Pre>\n      <div>\n        <Playground\n          fallback={\n            <div className=\"flex h-full items-center justify-center text-4xl\">\n              Loading playground...\n            </div>\n          }\n          source={rawMdx}\n          components={useMDXComponents({ Mermaid, $Tabs: Tabs })}\n        />\n      </div>\n    </div>\n  )\n}\n"
  },
  {
    "path": "docs/components/ready-to-go.mdx",
    "content": "### Render MDX files\n\nThere are two ways to render MDX files using file-based routing, add your MDX\nfiles via [`page` files](/docs/file-conventions/page-file) or\n[`content` directory](/docs/file-conventions/content-directory) convention.\n\n### Run the project\n\nRun the `dev` command specified in `package.json` to start developing the\nproject! 🎉\n\n```sh npm2yarn\nnpm run dev\n```\n"
  },
  {
    "path": "docs/components/shadow.jsx",
    "content": "'use client'\n\n// https://gist.github.com/janily/04d7fb0861e053d4679b38743ffc05a7\nimport { Component } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport class Shadow extends Component {\n  componentDidMount() {\n    if (this.shadowAttached) {\n      return\n    }\n    this.shadowAttached = true\n    this.shadowRoot = this.node.attachShadow({ mode: this.props.mode })\n    this.forceUpdate()\n  }\n\n  render() {\n    const { children, ...props } = this.props\n    return (\n      <div {...props} ref={node => (this.node = node)}>\n        {this.shadowRoot && createPortal(children, this.shadowRoot)}\n      </div>\n    )\n  }\n}\n"
  },
  {
    "path": "docs/components/toggle-visibility-section.tsx",
    "content": "import { compileMdx } from 'nextra/compile'\nimport { MDXRemote } from 'nextra/mdx-remote'\nimport type { FC } from 'react'\n\nexport const ToggleVisibilitySection: FC<{\n  element: string\n  property: string\n}> = async ({ element, property }) => {\n  const rawJs =\n    await compileMdx(`### Toggle Visibility [#toggle-visibility-for-${property}]\n\nYou can toggle visibility of the ${element} on the specific pages by setting \\`theme.${property}\\` property in the \\`_meta.js\\` file:\n\n~~~js filename=\"_meta.js\"\nexport default {\n  'my-page': {\n    theme: {\n      ${property}: false // Hide ${property} on this page\n    }\n  }\n}\n~~~`)\n  return <MDXRemote compiledSource={rawJs} />\n}\n"
  },
  {
    "path": "docs/components/video.tsx",
    "content": "import type { FC } from 'react'\n\nexport const Video: FC<{ src: string }> = ({ src }) => {\n  return (\n    <video\n      muted\n      autoPlay\n      playsInline\n      loop\n      controls\n      className=\"x:focus-visible:nextra-focus mt-6 rounded-xl border dark:border-zinc-800\"\n    >\n      <source src={src} type=\"video/mp4\" />\n    </video>\n  )\n}\n"
  },
  {
    "path": "docs/mdx-components.tsx",
    "content": "import { getEnhancedPageMap } from '@components/get-page-map'\nimport type { Folder } from 'nextra'\nimport { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'\nimport type { UseMDXComponents } from 'nextra/mdx-components'\nimport { generateDefinition, TSDoc } from 'nextra/tsdoc'\nimport type { ComponentProps } from 'react'\n\ntype TSDocProps = ComponentProps<typeof TSDoc>\ntype GenerateDefinitionArgs = Parameters<typeof generateDefinition>[0]\n\ninterface APIDocsProps\n  extends\n    Partial<TSDocProps>,\n    Pick<GenerateDefinitionArgs, 'code' | 'flattened'> {\n  componentName?: string\n  groupKeys?: string\n  packageName?: string\n}\n\nconst { img: Image, ...docsComponents } = getDocsMDXComponents({\n  // @ts-expect-error -- FIXME\n  figure: props => <figure className=\"mt-[1.25em]\" {...props} />,\n  // @ts-expect-error -- FIXME\n  figcaption: props => (\n    <figcaption className=\"mt-2 text-center text-sm\" {...props} />\n  ),\n  async APIDocs({\n    componentName,\n    groupKeys,\n    packageName = 'nextra/components',\n    code: $code,\n    flattened,\n    definition: $definition,\n    ...props\n  }: APIDocsProps) {\n    if (Object.keys(props).length) {\n      throw new Error(`Unexpected props: ${Object.keys(props)}`)\n    }\n    let code: string\n\n    if (componentName) {\n      const result = groupKeys\n        ? `Omit<MyProps, keyof ${groupKeys}> & { '...props': ${groupKeys} }>`\n        : 'MyProps'\n\n      code = `\nimport type { ComponentProps } from 'react'\nimport type { ${componentName.split('.')[0]} } from '${packageName}'\ntype MyProps = ComponentProps<typeof ${componentName}>\ntype $ = ${result}\n\nexport default $`\n    } else {\n      code = $code\n    }\n    const definition =\n      $definition ??\n      generateDefinition(\n        // @ts-expect-error -- exist\n        { code, flattened }\n      )\n\n    // TODO pass `'/api'` as first argument\n    const pageMap = await getEnhancedPageMap()\n    const apiPageMap = pageMap.find(\n      (o): o is Folder => 'name' in o && o.name === 'api'\n    )!.children\n\n    return (\n      <TSDoc\n        definition={definition}\n        typeLinkMap={{\n          ...Object.fromEntries(\n            apiPageMap\n              .filter(o => 'route' in o && o.name !== 'index')\n              // @ts-expect-error -- fixme\n              .map(o => [o.title, o.route])\n          ),\n          NextConfig:\n            'https://nextjs.org/docs/pages/api-reference/config/next-config-js',\n          RehypePrettyCodeOptions: 'https://rehype-pretty.pages.dev/#options',\n          PluggableList: 'https://github.com/unifiedjs/unified#pluggablelist',\n          GitHubIcon:\n            'https://github.com/shuding/nextra/blob/main/packages/nextra/src/client/icons/github.svg',\n          DiscordIcon:\n            'https://github.com/shuding/nextra/blob/main/packages/nextra/src/client/icons/discord.svg',\n          PagefindSearchOptions:\n            'https://github.com/CloudCannon/pagefind/blob/248f81d172316a642a83527fa92180abbb7f9c49/pagefind_web_js/types/index.d.ts#L72-L82',\n          ReactNode:\n            'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/51fcf2a1c5da6da885c1f8c11224917bbc011493/types/react/index.d.ts#L426-L439',\n          ReactElement:\n            'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d44fce6cd8765acbdb0256195e5f16f67471430d/types/react/index.d.ts#L315-L322',\n          TabItem:\n            'https://github.com/shuding/nextra/blob/fb376a635de7fa287d5ffec9dbb5f40f1cfdb0f6/packages/nextra/src/client/components/tabs/index.client.tsx#L21',\n          TabObjectItem:\n            'https://github.com/shuding/nextra/blob/fb376a635de7fa287d5ffec9dbb5f40f1cfdb0f6/packages/nextra/src/client/components/tabs/index.client.tsx#L23',\n          PageMapItem:\n            'https://github.com/shuding/nextra/blob/fb376a635de7fa287d5ffec9dbb5f40f1cfdb0f6/packages/nextra/src/types.ts#L66',\n          // ThemeProviderProps:\n          //   'https://github.com/pacocoursey/next-themes/blob/c89d0191ce0f19215d7ddfa9eb28e1e4f94d37e5/next-themes/src/types.ts#L34-L57',\n          LastUpdated:\n            'https://github.com/shuding/nextra/blob/main/packages/nextra-theme-docs/src/components/last-updated.tsx',\n          MDXRemote:\n            'https://github.com/shuding/nextra/blob/main/packages/nextra/src/client/mdx-remote.tsx',\n          MDXComponents:\n            'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/4c3811099cbe9ee60151c11a679b780d0ba785bf/types/mdx/types.d.ts#L65',\n          ComboboxInputProps:\n            'https://github.com/tailwindlabs/headlessui/blob/0933dd5e5f563675c8a36e4520905bf9b58df00e/packages/%40headlessui-react/src/components/combobox/combobox.tsx#L506'\n        }}\n      />\n    )\n  }\n})\n\nexport const useMDXComponents: UseMDXComponents<typeof docsComponents> = <T,>(\n  components?: T\n) => ({\n  ...docsComponents,\n  // @ts-expect-error -- FIXME\n  img: props => (\n    <Image\n      {...props}\n      className=\"nextra-border rounded-xl border drop-shadow-sm\"\n    />\n  ),\n  ...components\n})\n"
  },
  {
    "path": "docs/next-sitemap.config.js",
    "content": "/** @type {import('next-sitemap').IConfig} */\nexport default {\n  siteUrl: 'https://nextra.site',\n  changefreq: 'weekly',\n  priority: '0.5',\n  generateIndexSitemap: false,\n  exclude: ['/icon.svg']\n}\n"
  },
  {
    "path": "docs/next.config.ts",
    "content": "import nextra from 'nextra'\n\n// @ts-expect-error -- fixme\nfunction isExportNode(node, varName: string) {\n  if (node.type !== 'mdxjsEsm') return false\n  const [n] = node.data.estree.body\n\n  if (n.type !== 'ExportNamedDeclaration') return false\n\n  const name = n.declaration?.declarations?.[0].id.name\n  if (!name) return false\n\n  return name === varName\n}\n\nconst DEFAULT_PROPERTY_PROPS = {\n  type: 'Property',\n  kind: 'init',\n  method: false,\n  shorthand: false,\n  computed: false\n}\n\n// @ts-expect-error -- fixme\nexport function createAstObject(obj) {\n  return {\n    type: 'ObjectExpression',\n    properties: Object.entries(obj).map(([key, value]) => ({\n      ...DEFAULT_PROPERTY_PROPS,\n      key: { type: 'Identifier', name: key },\n      value:\n        value && typeof value === 'object' ? value : { type: 'Literal', value }\n    }))\n  }\n}\n\ntype NextraParams = Parameters<typeof nextra>[0]\ntype MdxOptions = NonNullable<NextraParams['mdxOptions']>\ntype RehypePlugin = NonNullable<MdxOptions['rehypePlugins']>[0]\n\n// eslint-disable-next-line unicorn/consistent-function-scoping\nconst rehypeOpenGraphImage: RehypePlugin = () => (ast: any) => {\n  // @ts-expect-error -- fixme\n  const frontMatterNode = ast.children.find(node =>\n    isExportNode(node, 'metadata')\n  )\n  if (!frontMatterNode) {\n    return\n  }\n  const { properties } =\n    frontMatterNode.data.estree.body[0].declaration.declarations[0].init\n  // @ts-expect-error -- fixme\n  const title = properties.find(o => o.key.value === 'title')?.value.value\n  if (!title) {\n    return\n  }\n  const [prop] = createAstObject({\n    openGraph: createAstObject({\n      images: `https://nextra.site/og?title=${title}`\n    })\n  }).properties\n  properties.push(prop)\n}\n\nconst withNextra = nextra({\n  latex: true,\n  defaultShowCopyCode: true,\n  mdxOptions: {\n    rehypePlugins: [\n      // Provide only on `build` since turbopack on `dev` supports only serializable values\n      process.env.NODE_ENV === 'production' && rehypeOpenGraphImage\n    ].filter(v => !!v)\n  },\n  whiteListTagsStyling: ['figure', 'figcaption']\n})\n\nconst nextConfig = withNextra({\n  reactStrictMode: true,\n  env: {\n    NEXT_PUBLIC_INKEEP_API_KEY:\n      'dee399c7f7ac40b9de0d0b85ca32959953b9ff7c9fc8d96c'\n  },\n  redirects: () => [\n    {\n      source: '/docs/guide/:slug(typescript|latex|tailwind-css|mermaid)',\n      destination: '/docs/advanced/:slug',\n      permanent: true\n    },\n    {\n      source: '/docs/docs-theme/built-ins/:slug(callout|steps|tabs|bleed)',\n      destination: '/docs/built-ins/:slug',\n      permanent: true\n    },\n    {\n      source: '/docs/docs-theme/api/use-config',\n      destination: '/docs/docs-theme/api',\n      permanent: true\n    },\n    {\n      source: '/docs/guide/advanced/:slug',\n      destination: '/docs/advanced/:slug',\n      permanent: true\n    },\n    {\n      source: '/docs/docs-theme/theme-configuration',\n      destination: '/docs/docs-theme/built-ins/layout',\n      permanent: true\n    },\n    {\n      source: '/docs/docs-theme/page-configuration',\n      destination: '/docs/file-conventions/meta-file',\n      permanent: true\n    },\n    {\n      source: '/docs/guide/organize-files',\n      destination: '/docs/file-conventions',\n      permanent: true\n    },\n    {\n      source: '/docs/advanced/playground',\n      destination: '/docs/built-ins/playground',\n      permanent: true\n    }\n  ],\n  webpack(config) {\n    // rule.exclude doesn't work starting from Next.js 15\n    const { test: _test, ...imageLoaderOptions } = config.module.rules.find(\n      // @ts-expect-error -- fixme\n      rule => rule.test?.test?.('.svg')\n    )\n    config.module.rules.push({\n      test: /\\.svg$/,\n      oneOf: [\n        {\n          resourceQuery: /svgr/,\n          use: ['@svgr/webpack']\n        },\n        imageLoaderOptions\n      ]\n    })\n    return config\n  },\n  turbopack: {\n    rules: {\n      './components/icons/*.svg': {\n        loaders: ['@svgr/webpack'],\n        as: '*.js'\n      }\n    }\n  },\n  experimental: {\n    optimizePackageImports: ['@components/icons']\n  }\n})\n\nexport default nextConfig\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"docs\",\n  \"author\": \"Shu Ding\",\n  \"license\": \"MIT\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"next build --webpack\",\n    \"dev\": \"next\",\n    \"postbuild\": \"next-sitemap && pagefind --site .next/server/app --output-path public/_pagefind\",\n    \"start\": \"next start\"\n  },\n  \"dependencies\": {\n    \"@inkeep/cxkit-react\": \"^0.5.98\",\n    \"clsx\": \"^2.1.0\",\n    \"framer-motion\": \"^12.0.0\",\n    \"next\": \"^16.0.7\",\n    \"nextra\": \"workspace:*\",\n    \"nextra-theme-docs\": \"workspace:*\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\"\n  },\n  \"devDependencies\": {\n    \"@svgr/webpack\": \"^8.0.1\",\n    \"@tailwindcss/postcss\": \"4.1.10\",\n    \"@types/node\": \"^22.0.0\",\n    \"@types/react\": \"^19.1.8\",\n    \"next-sitemap\": \"^4.2.3\",\n    \"pagefind\": \"^1.3.0\",\n    \"tailwindcss\": \"4.1.10\"\n  },\n  \"browserslist\": [\n    \">= .25%\",\n    \"not dead\"\n  ]\n}\n"
  },
  {
    "path": "docs/postcss.config.mjs",
    "content": "// If you want to use other PostCSS plugins, see the following:\n// https://tailwindcss.com/docs/using-with-preprocessors\n/** @type {import('postcss').Postcss} */\nexport default {\n  plugins: {\n    '@tailwindcss/postcss': {}\n  }\n}\n"
  },
  {
    "path": "docs/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"target\": \"es2022\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"exactOptionalPropertyTypes\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"incremental\": true,\n    \"esModuleInterop\": true,\n    \"isolatedModules\": true,\n    \"moduleResolution\": \"bundler\",\n    \"jsx\": \"react-jsx\",\n    \"module\": \"esnext\",\n    \"resolveJsonModule\": true,\n    \"paths\": {\n      \"@components/*\": [\"components/*\"],\n      // These work at runtime due to Next.js internal resolution or custom config,\n      // but we include them here so TypeScript doesn't complain.\n      \"private-next-root-dir/*\": [\"./*\"],\n      \"next-mdx-import-source-file\": [\"./mdx-components.tsx\"]\n    },\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ],\n    \"strictNullChecks\": true,\n    \"noUncheckedIndexedAccess\": true\n  },\n  \"include\": [\n    \"next-env.d.ts\",\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \".next/types/**/*.ts\",\n    \".next/dev/types/**/*.ts\"\n  ],\n  \"exclude\": [\"node_modules\", \".next\"]\n}\n"
  },
  {
    "path": "docs/vercel.json",
    "content": "{\n  \"public\": true\n}\n"
  },
  {
    "path": "examples/blog/app/_meta.global.js",
    "content": "export default {\n  index: {\n    type: 'page'\n  },\n  posts: {\n    type: 'page',\n    items: {\n      draft: {\n        display: 'hidden'\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "examples/blog/app/layout.jsx",
    "content": "import { Footer, Layout, Navbar, ThemeSwitch } from 'nextra-theme-blog'\nimport { Banner, Head, Search } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-map'\nimport 'nextra-theme-blog/style.css'\n\nexport const metadata = {\n  title: 'Blog Example'\n}\n\nexport default async function RootLayout({ children }) {\n  const banner = (\n    <Banner storageKey=\"4.0-release\">\n      🎉 Nextra 4.0 is released.{' '}\n      <a\n        href=\"#\"\n        style={{\n          textDecoration: 'underline',\n          textUnderlinePosition: 'from-font'\n        }}\n      >\n        Read more →\n      </a>\n    </Banner>\n  )\n\n  return (\n    <html lang=\"en\" suppressHydrationWarning>\n      <Head backgroundColor={{ dark: '#0f172a', light: '#fefce8' }} />\n      <body>\n        <Layout banner={banner}>\n          <Navbar pageMap={await getPageMap()}>\n            <Search />\n            <ThemeSwitch />\n          </Navbar>\n\n          {children}\n\n          <Footer>\n            <abbr\n              title=\"This site and all its content are licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.\"\n              style={{ cursor: 'help' }}\n            >\n              CC BY-NC 4.0\n            </abbr>{' '}\n            {new Date().getFullYear()} © Dimitri POSTOLOV.\n            <a href=\"/feed.xml\" style={{ float: 'right' }}>\n              RSS\n            </a>\n          </Footer>\n        </Layout>\n      </body>\n    </html>\n  )\n}\n"
  },
  {
    "path": "examples/blog/app/page.mdx",
    "content": "---\ntitle: About\n---\n\nHey there!\n\n![Mountain](../public/img.jpeg)\n\nThis Markdown image is automatically converted into a\n[Next.js Image](https://nextjs.org/docs/api-reference/next/image).\n"
  },
  {
    "path": "examples/blog/app/posts/(with-comments)/aaron-swartz-a-programmable-web/page.mdx",
    "content": "---\ntitle: Notes on A Programmable Web by Aaron Swartz\ndate: 2016-05-21\ndescription:\n  At the time when I was getting into web development, I had the chance to read\n  one of the most inspiring book about the web, Aaron Swartz's A Programmable\n  Web. And it completely changed my mind.\ntags: [web development]\nauthor: Shu\n---\n\nAt the time when I was getting into web development, I had the chance to read\none of the most inspiring book about the web, Aaron Swartz's A Programmable Web.\nAnd it completely changed my mind.\n\n**Updated in\n2017**: [@tommyjtl](https://github.com/tommyjtl), [@zimine](https://github.com/zimine) and\nI are currently helping translate this post into Simplified Chinese.\nAny [contributions](https://github.com/tommyjtl/the-programmable-web/tree/translation) are\nwelcomed :)\n\n---\n\n> Sure, it sounds a little bit crazy. But it paid off the last time they made\n> that gamble: we ended up with a little thing called the World Wide Web. Let's\n> see if they can do it again.\n\n— Aaron\n\nRead Aaron's original post:\n[Building Programmable Web Sites by Aaron Swartz, 2009](http://www.cs.rpi.edu/~hendler/ProgrammableWebSwartz2009.html).\n\n## Quotes About WWW\n\n1. \"(the Internet) It should be kept open. It should be kept free.\" – Steve Jobs\n2. \"The third reason it's very exciting is that Microsoft doesn't own it and I\n   don't think they can. It's the one thing in the industry that Microsoft can\n   probably never own. I think one of the things that's essential is that the\n   government continue to fund the Internet as a public trust, as a public\n   facility and remove any of these ridiculous notions of privatizing it that\n   have been brought up. I don't think they're going to fly, thankfully.\" –\n   Steve Jobs\n3. Jacques Mattheij wrote an article, about the web in 2050, which feels like\n   the *New Speak* in George Orwell's _1984_.\n\n## Quotes from Aaron's Post\n\nAbout API\n\n> APIs only let you look at the data in a **particular way**, typically the way\n> that the hosting site looks at it\n\nAbout API, II (Q: differences between data, protocol, API?)\n\n> pass the noun to the verb: /share?v=1234 pass the verb to the noun:\n> /v/1234?m=share\n\nThen he describes the interesting hybrid that the Web adopted, which he terms\n\"Representational State Transfer\" or REST.\n\nAbout \"standard\" vs \"design\"\n\n> And instead of spending time building things, they've convinced people\n> interested in these ideas that the first thing we need to do is write\n> standards. (**To engineers, this is absurd from the start -- standards are\n> things you write after you've got something working, not before!**)\n\nFortunately for us, the Web was designed with this future in mind. The protocols\nthat underpin it are not designed simply to provide pages for human consumption,\nbut also to easily accommodate the menagerie of spiders, bots, and scripts that\nexplore its fertile soil. ...for applications.\n\nThen we'll look into what it means for your application to be not just another\ntool for people and software to use, but **part of the ecology** -- a section of\nthe programmable web. This means exposing your data to be queried and copied and\nintegrated, even without explicit permission, into the larger software\necosystem, while protecting users' freedom.\n\nThe more likely option is, of course, to break away from the Web altogether, and\nforce people to download special software to use your application. ... If that's\na choice you want to make, you probably shouldn't be reading this book.\n\nThis is one of the secrets of success on the Web: the more you send people away,\nthe more they come back\n\nAbout URL and URI\n\n> Moreover, URLs do not just exist as isolated entities\n\nURLs shouldn't change (and if they do change, the old ones should redirect to\nthe new ones) so they should only contain information about the page that never\nchanges. This leads to some obvious requirements.\n\nFirst, URLs shouldn't include technical details of the software you used to\nbuild your website, since that could change at any moment\n\nAbout TBL\n\n> And even then, they're far more limited than the wide-reaching interactivity\n> that Berners-Lee imagined.\n\nInstead, they used the clone created by a team at the University of Illinois\nUrbana-Champaign (UIUC), which never supported editing because programmer Marc\nAndreesen was too dumb to figure out how to do page editing with inline\npictures, something Tim Berners-Lee's version had no problem with.\n\n(related: http://www.aaronsw.com/weblog/mylifewithtim)\n\n## External links\n\n1. [Steve Jobs interview: One-on-one in 1995](http://computerworld.com/article/2498543/it-management/steve-jobs-interview--one-on-one-in-1995.html?page=8)\n2. [Solid: Re-decentralizing the web](https://solid.mit.edu)\n3. [Aaron's public links & notes tagged with \"web\" on Pinboard](https://pinboard.in/u:aaronsw/t:web)\n4. [\"URLs shouldn't include technical details\": 天猫首页](https://zhihu.com/question/54777923/answer/141058259)\n5. [Semantic Web – W3C](https://w3.org/standards/semanticweb)\n6. [Tim Berners-Lee: The next web](https://ted.com/talks/tim_berners_lee_on_the_next_web)\n7. [The Web in 2050 · Jacques Mattheij](https://jacquesmattheij.com/the-web-in-2050):\n   \"reboot the web\"\n"
  },
  {
    "path": "examples/blog/app/posts/(with-comments)/code-blocks/page.mdx",
    "content": "---\ntitle: Code blocks\ndate: 2022-07-29\ndescription: En example of using code blocks in your blog.\ntags:\n  [\n    web development,\n    JavaScript,\n    GraphQL,\n    C++,\n    Java,\n    React,\n    Next.js,\n    The Guild,\n    MacBook Pro\n  ]\nauthor: Dimitri POSTOLOV\n---\n\n## Test `filename`, line highlighting and empty lines\n\n```js filename=\"test.js\" {1}\nconsole.log('hello world')\n\nconsole.log('goodbye world')\n```\n\n## Test `showLineNumbers` and word highlighting\n\n```scala showLineNumbers {2-4} /println/\nobject Hello {\n  def main(args: Array[String]) = {\n    println(\"hello, world\")\n  }\n}\n\nobject Hello {\n  def main(args: Array[String]) = {\n    println(\"hello, world\")\n  }\n}\n```\n\n## Test highlighting inline code\n\n`import React from 'react'{:js}`\n\n## Test without specified language\n\n```text /hello/\nhello world\n```\n\n## Test with code block default language\n\n```\nconst links = [\n  { href: '/settings', label: 'Settings' },\n  { href: '/support', label: 'Support' },\n  { href: '/license', label: 'License' },\n]\n```\n\n## Test link in code\n\nLink to [`google`](https://google.com)\n\nLink to [GitHub](https://github.com)\n"
  },
  {
    "path": "examples/blog/app/posts/(with-comments)/draft/page.mdx",
    "content": "---\ntitle: Draft\ndate: 2023-06-28\ndescription: An example of a draft post.\ntags: [web development]\nauthor: Ada Lovelace\n---\n\nBecause this post has `display: 'hidden'` defined in `_meta.global.js`, it won't\nshow up in the [list of posts](/posts) or\n[list of posts by tag](/tags/web%20development) but can be access directly by\nits url at [/posts/draft](/posts/draft).\n"
  },
  {
    "path": "examples/blog/app/posts/(with-comments)/layout.jsx",
    "content": "import { Comments } from 'nextra-theme-blog'\n\nexport default function CommentsLayout({ children }) {\n  return (\n    <>\n      {children}\n      <Comments lang=\"en\" appId=\"a2d11511-7012-4254-9483-cb49c8f4dfe8\" />\n    </>\n  )\n}\n"
  },
  {
    "path": "examples/blog/app/posts/(with-comments)/lists/page.mdx",
    "content": "---\ntitle: Lists\ndate: 2024-07-11\ndescription: Example of ordered/unordered nested lists.\ntags: [web development]\nauthor: Dimitri POSTOLOV\n---\n\n- **foo**\n  - bar\n  - **baz**\n    - qux\n    - **qwe**\n      1. he\n      1. **be**\n         1. wo\n         1. **be** da\n            - da\n            - ba\n"
  },
  {
    "path": "examples/blog/app/posts/(with-comments)/nextra-components/page.mdx",
    "content": "---\ntitle: Nextra Components\ndate: 2023-05-15\ndescription: En example of using the Callout component in your blog.\ntags: [web development]\nauthor: Tristan Dubbeld\n---\n\nimport { Bleed, Callout, Cards, FileTree, Steps, Tabs } from 'nextra/components'\nimport { CopyIcon, GitHubIcon, MenuIcon } from 'nextra/icons'\n\n## `<Callout>`\n\n### Default\n\n<Callout>This is a default callout.</Callout>\n\n### Error\n\n<Callout type=\"error\">This is an error callout.</Callout>\n\n### Info\n\n<Callout type=\"info\">This is an info callout. [^2]</Callout>\n\n### Warning\n\n<Callout type=\"warning\">This is a warning callout.</Callout>\n\n### With custom emoji [^1]\n\n<Callout emoji=\"🚀\">This is a callout with a custom emoji.</Callout>\n\n## `<Steps>`\n\n<Steps>\n\n### Step 1\n\nContent for step 1.\n\n### Step 2\n\nContents for step 2.\n\n</Steps>\n\n<Steps>\n  ## Test\n  Run pnpm test\n\n  <Steps>\n    ### nextra:test\n\n    ### nextra-theme-docs:test\n\n    <Steps>\n      #### more\n\n      #### more more\n\n      #### more more more\n\n    </Steps>\n\n    ### nextra-theme-blog:test\n\n  </Steps>\n\n## Lint\n\n</Steps>\n\n## `<Tabs>`\n\n{/* prettier-ignore */}\n<Tabs items={['pnpm', 'npm', 'yarn']}>\n  <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n  <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n  <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n</Tabs>\n\n## `<FileTree>`\n\n<FileTree>\n  <FileTree.Folder name=\"pages\" defaultOpen>\n    <FileTree.Folder name=\"fruits\" defaultOpen>\n      <FileTree.File name=\"_meta.js\" />\n      <FileTree.File name=\"apple.mdx\" />\n      <FileTree.File name=\"banana.mdx\" />\n    </FileTree.Folder>\n    <FileTree.File name=\"_meta.js\" />\n    <FileTree.File name=\"about.mdx\" />\n    <FileTree.File name=\"contact.mdx\" />\n    <FileTree.File name=\"index.mdx\" />\n  </FileTree.Folder>\n</FileTree>\n\n<FileTree>\n  <FileTree.Folder name=\"users-service\" defaultOpen>\n    <FileTree.File name=\"schema.graphql\" />\n  </FileTree.Folder>\n  <FileTree.Folder name=\"posts-service\" defaultOpen>\n    <FileTree.File name=\"schema.graphql\" />\n  </FileTree.Folder>\n</FileTree>\n\n## `<Cards>`\n\n<Cards num={2}>\n  <Cards.Card arrow title=\"Documentation theme\" href=\"/docs/docs-theme/start\">\n    <>![Documentation theme](https://nextra.site/assets/docs-theme.png)</>\n  </Cards.Card>\n  <Cards.Card arrow title=\"Blog theme\" href=\"/docs/blog-theme/start\">\n    <>![Blog theme](https://nextra.site/assets/blog-theme.png)</>\n  </Cards.Card>\n</Cards>\n\n<Cards>\n  <Cards.Card icon={<CopyIcon />} title=\"Callout\" href=\"/foo\" />\n  <Cards.Card icon={<GitHubIcon />} title=\"Tabs\" href=\"/bar\" />\n  <Cards.Card icon={<MenuIcon />} title=\"Steps\" href=\"/baz\" />\n</Cards>\n\n## `<details>` and `<summary>`\n\n<details>\n  <summary>Summary</summary>\n  Details\n  <details>\n    <summary>Summary 2</summary>\n    Details 2\n  </details>\n</details>\n\n## `<Bleed>`\n\n<Bleed>![Mountain](/img.jpeg)</Bleed>\n\n## GitHub Alert Syntax\n\n> [!NOTE]\n>\n> Useful information that users should know, even when skimming content.\n\n> [!TIP]\n>\n> Helpful advice for doing things better or more easily.\n\n> [!IMPORTANT]\n>\n> Key information users need to know to achieve their goal.\n\n> [!WARNING]\n>\n> Urgent info that needs immediate user attention to avoid problems.\n\n> [!CAUTION]\n>\n> Advises about risks or negative outcomes of certain actions.\n\n[^1]: With custom emoji\n\n[^2]: This is an info callout.\n"
  },
  {
    "path": "examples/blog/app/posts/(with-comments)/table/page.mdx",
    "content": "---\ntitle: Table\ndate: 2022-08-28\ndescription: En example of using table.\ntags: [web development]\nauthor: Dimitri POSTOLOV\n---\n\n## Test table\n\n| Left | Center | Right | Right | Right | Right | Right | Right | Right | Right |\n| ---- | :----: | ----: | ----: | ----: | ----: | ----: | ----: | ----: | ----: |\n| ss2  |  333   |  3232 |  3232 |  3232 |  3232 |  3232 |  3232 |  3232 |  3232 |\n|      |  222   |  3232 |  3232 |  3232 |  3232 |  3232 |  3232 |  3232 |  3232 |\n|      |   23   |       |       |       |       |       |       |       |       |\n"
  },
  {
    "path": "examples/blog/app/posts/get-posts.js",
    "content": "import { normalizePages } from 'nextra/normalize-pages'\nimport { getPageMap } from 'nextra/page-map'\n\nexport async function getPosts() {\n  const { directories } = normalizePages({\n    list: await getPageMap('/posts'),\n    route: '/posts'\n  })\n  return directories\n    .filter(post => post.name !== 'index')\n    .sort((a, b) => new Date(b.frontMatter.date) - new Date(a.frontMatter.date))\n}\n\nexport async function getTags() {\n  const posts = await getPosts()\n  const tags = posts.flatMap(post => post.frontMatter.tags)\n  return tags\n}\n"
  },
  {
    "path": "examples/blog/app/posts/page.jsx",
    "content": "import Link from 'next/link'\nimport { PostCard } from 'nextra-theme-blog'\nimport { getPosts, getTags } from './get-posts'\n\nexport const metadata = {\n  title: 'Posts'\n}\n\nexport default async function PostsPage() {\n  const tags = await getTags()\n  const posts = await getPosts()\n  const allTags = Object.create(null)\n\n  for (const tag of tags) {\n    allTags[tag] ??= 0\n    allTags[tag] += 1\n  }\n  return (\n    <div data-pagefind-ignore=\"all\">\n      <h1>{metadata.title}</h1>\n      <div\n        className=\"not-prose\"\n        style={{ display: 'flex', flexWrap: 'wrap', gap: '.5rem' }}\n      >\n        {Object.entries(allTags).map(([tag, count]) => (\n          <Link key={tag} href={`/tags/${tag}`} className=\"nextra-tag\">\n            {tag} ({count})\n          </Link>\n        ))}\n      </div>\n      {posts.map(post => (\n        <PostCard key={post.route} post={post} />\n      ))}\n    </div>\n  )\n}\n"
  },
  {
    "path": "examples/blog/app/rss.xml/route.js",
    "content": "import { getPosts } from '../posts/get-posts.js'\n\nconst CONFIG = {\n  title: 'My Blog',\n  siteUrl: 'https://your-domain.com',\n  description: 'Latest blog posts',\n  lang: 'en-us'\n}\n\nexport async function GET() {\n  const allPosts = await getPosts()\n  const posts = allPosts\n    .map(\n      post => `    <item>\n        <title>${post.title}</title>\n        <description>${post.frontMatter.description}</description>\n        <link>${CONFIG.siteUrl}${post.route}</link>\n        <pubDate>${new Date(post.frontMatter.date).toUTCString()}</pubDate>\n    </item>`\n    )\n    .join('\\n')\n  const xml = `<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<rss version=\"2.0\">\n  <channel>\n    <title>${CONFIG.title}</title>\n    <link>${CONFIG.siteUrl}</link>\n    <description>${CONFIG.description}</description>\n    <language>${CONFIG.lang}</language>\n${posts}\n  </channel>\n</rss>`\n\n  return new Response(xml, {\n    headers: {\n      'Content-Type': 'application/rss+xml'\n    }\n  })\n}\n"
  },
  {
    "path": "examples/blog/app/tags/[tag]/page.jsx",
    "content": "import { PostCard } from 'nextra-theme-blog'\nimport { getPosts, getTags } from '../../posts/get-posts'\n\nexport async function generateMetadata(props) {\n  const params = await props.params\n  return {\n    title: `Posts Tagged with “${decodeURIComponent(params.tag)}”`\n  }\n}\n\nexport async function generateStaticParams() {\n  const allTags = await getTags()\n  return [...new Set(allTags)].map(tag => ({ tag }))\n}\n\nexport default async function TagPage(props) {\n  const params = await props.params\n  const { title } = await generateMetadata({ params })\n  const posts = await getPosts()\n  return (\n    <>\n      <h1>{title}</h1>\n      {posts\n        .filter(post =>\n          post.frontMatter.tags.includes(decodeURIComponent(params.tag))\n        )\n        .map(post => (\n          <PostCard key={post.route} post={post} />\n        ))}\n    </>\n  )\n}\n"
  },
  {
    "path": "examples/blog/mdx-components.jsx",
    "content": "import { useMDXComponents as getBlogMDXComponents } from 'nextra-theme-blog'\n\nconst blogComponents = getBlogMDXComponents({\n  h1: ({ children }) => (\n    <h1\n      style={{\n        WebkitBackgroundClip: 'text',\n        WebkitTextFillColor: 'transparent',\n        backgroundClip: 'text',\n        backgroundImage: 'linear-gradient(90deg,#7928CA,#FF0080)'\n      }}\n    >\n      {children}\n    </h1>\n  ),\n  DateFormatter: ({ date }) =>\n    `Last updated at ${date.toLocaleDateString('en', {\n      day: 'numeric',\n      month: 'long',\n      year: 'numeric'\n    })}`\n})\n\nexport function useMDXComponents(components) {\n  return {\n    ...blogComponents,\n    ...components\n  }\n}\n"
  },
  {
    "path": "examples/blog/next.config.js",
    "content": "import nextra from 'nextra'\n\nconst withNextra = nextra({\n  defaultShowCopyCode: true,\n  readingTime: true\n})\n\nexport default withNextra({\n  reactStrictMode: true,\n  cleanDistDir: true\n})\n"
  },
  {
    "path": "examples/blog/package.json",
    "content": "{\n  \"name\": \"example-blog\",\n  \"type\": \"module\",\n  \"license\": \"MIT\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"next build\",\n    \"dev\": \"next\",\n    \"postbuild\": \"pagefind --site .next/server/app --output-path public/_pagefind\",\n    \"start\": \"next start\"\n  },\n  \"dependencies\": {\n    \"next\": \"^16.0.7\",\n    \"nextra\": \"workspace:*\",\n    \"nextra-theme-blog\": \"workspace:*\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\"\n  },\n  \"devDependencies\": {\n    \"pagefind\": \"^1.3.0\"\n  }\n}\n"
  },
  {
    "path": "examples/custom-theme/app/_components/footer.tsx",
    "content": "import type { FC } from 'react'\n\nexport const Footer: FC = () => {\n  return (\n    <footer style={{ background: 'lightsalmon', padding: 20 }}>\n      Powered by Nextra {new Date().getFullYear()}\n    </footer>\n  )\n}\n"
  },
  {
    "path": "examples/custom-theme/app/_components/navbar.tsx",
    "content": "'use client'\n\nimport { usePathname } from 'next/navigation'\nimport type { PageMapItem } from 'nextra'\nimport { Anchor } from 'nextra/components'\nimport { normalizePages } from 'nextra/normalize-pages'\nimport type { FC } from 'react'\n\nexport const Navbar: FC<{ pageMap: PageMapItem[] }> = ({ pageMap }) => {\n  const pathname = usePathname()\n  const { topLevelNavbarItems } = normalizePages({\n    list: pageMap,\n    route: pathname\n  })\n\n  return (\n    <ul\n      style={{\n        display: 'flex',\n        listStyleType: 'none',\n        padding: 20,\n        gap: 20,\n        background: 'lightcoral',\n        margin: 0\n      }}\n    >\n      {topLevelNavbarItems.map(item => {\n        const route = item.route || ('href' in item ? item.href! : '')\n        return (\n          <li key={route}>\n            <Anchor href={route} style={{ textDecoration: 'none' }}>\n              {item.title}\n            </Anchor>\n          </li>\n        )\n      })}\n    </ul>\n  )\n}\n"
  },
  {
    "path": "examples/custom-theme/app/_components/nextra-theme.tsx",
    "content": "import type { PageMapItem } from 'nextra'\nimport { version } from 'nextra/package.json'\nimport type { FC, ReactNode } from 'react'\nimport { Footer } from './footer'\nimport { Navbar } from './navbar'\nimport { Sidebar } from './sidebar'\n\nexport const NextraTheme: FC<{\n  children: ReactNode\n  pageMap: PageMapItem[]\n}> = ({ children, pageMap }) => {\n  return (\n    <>\n      <h1\n        style={{\n          margin: 0,\n          padding: 20,\n          background: 'lightslategray',\n          fontWeight: 'normal'\n        }}\n      >\n        Custom theme demo for <strong>Nextra {version}</strong>\n      </h1>\n      <Navbar pageMap={pageMap} />\n      <div style={{ display: 'flex' }}>\n        <Sidebar pageMap={pageMap} />\n        {children}\n      </div>\n      <Footer />\n    </>\n  )\n}\n"
  },
  {
    "path": "examples/custom-theme/app/_components/sidebar.tsx",
    "content": "'use client'\n\nimport { usePathname } from 'next/navigation'\nimport type { PageMapItem } from 'nextra'\nimport { Anchor } from 'nextra/components'\nimport { normalizePages } from 'nextra/normalize-pages'\nimport type { FC } from 'react'\n\nexport const Sidebar: FC<{ pageMap: PageMapItem[] }> = ({ pageMap }) => {\n  const pathname = usePathname()\n  const { docsDirectories } = normalizePages({\n    list: pageMap,\n    route: pathname\n  })\n\n  return (\n    <div\n      style={{\n        background: 'lightgreen',\n        padding: 20\n      }}\n    >\n      <h3>Sidebar</h3>\n      <ul\n        style={{\n          margin: 0,\n          display: 'flex',\n          flexDirection: 'column',\n          listStyleType: 'none',\n          padding: 0,\n          gap: 20\n        }}\n      >\n        {docsDirectories.map(function renderItem(item) {\n          const route =\n            item.route || ('href' in item ? (item.href as string) : '')\n          const { title } = item\n          return (\n            <li\n              key={route}\n              style={{ padding: '4px 4px 4px 10px', border: '1px solid' }}\n            >\n              {'children' in item ? (\n                <details>\n                  <summary>{title}</summary>\n                  {item.children.map(child => renderItem(child))}\n                </details>\n              ) : (\n                <Anchor href={route} style={{ textDecoration: 'none' }}>\n                  {title}\n                </Anchor>\n              )}\n            </li>\n          )\n        })}\n      </ul>\n    </div>\n  )\n}\n"
  },
  {
    "path": "examples/custom-theme/app/_components/toc.tsx",
    "content": "import type { Heading } from 'nextra'\nimport type { FC } from 'react'\n\nexport const TOC: FC<{ toc: Heading[] }> = ({ toc }) => {\n  return (\n    <div style={{ background: 'lightblue', padding: 20 }}>\n      <h3>Table of Contents</h3>\n      <ul>\n        {toc.map(heading => (\n          <li key={heading.id}>{heading.value}</li>\n        ))}\n      </ul>\n    </div>\n  )\n}\n"
  },
  {
    "path": "examples/custom-theme/app/_meta.global.ts",
    "content": "export default {\n  index: {\n    type: 'page'\n  },\n  docs: {\n    title: 'Documentation',\n    type: 'page',\n    items: {\n      'one-level': ''\n    }\n  },\n  _: {\n    type: 'page',\n    href: 'https://nextra.site',\n    title: 'Nextra Docs'\n  }\n}\n"
  },
  {
    "path": "examples/custom-theme/app/docs/nested-level/bar/page.mdx",
    "content": "# Nexted Page\n"
  },
  {
    "path": "examples/custom-theme/app/docs/one-level/page.mdx",
    "content": "# One level page\n"
  },
  {
    "path": "examples/custom-theme/app/docs/page.mdx",
    "content": "# Getting Started\n"
  },
  {
    "path": "examples/custom-theme/app/layout.tsx",
    "content": "import type { Metadata } from 'next'\nimport { Head } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-map'\nimport type { FC, ReactNode } from 'react'\nimport { NextraTheme } from './_components/nextra-theme'\n\nexport const metadata: Metadata = {\n  title: {\n    absolute: '',\n    template: '%s - Nextra'\n  }\n}\n\nconst RootLayout: FC<{ children: ReactNode }> = async ({ children }) => {\n  const pageMap = await getPageMap()\n  return (\n    <html lang=\"en\" dir=\"ltr\">\n      <Head faviconGlyph=\"✦\" />\n      <body style={{ margin: 0 }}>\n        <NextraTheme pageMap={pageMap}>{children}</NextraTheme>\n      </body>\n    </html>\n  )\n}\n\nexport default RootLayout\n"
  },
  {
    "path": "examples/custom-theme/app/page.mdx",
    "content": "# Home\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n"
  },
  {
    "path": "examples/custom-theme/mdx-components.jsx",
    "content": "import { useMDXComponents as getNextraComponents } from 'nextra/mdx-components'\nimport { TOC } from './app/_components/toc'\n\nconst defaultComponents = getNextraComponents({\n  wrapper({ children, toc }) {\n    return (\n      <>\n        <div style={{ flexGrow: 1, padding: 20 }}>{children}</div>\n        <TOC toc={toc} />\n      </>\n    )\n  }\n})\n\nexport const useMDXComponents = components => ({\n  ...defaultComponents,\n  ...components\n})\n"
  },
  {
    "path": "examples/custom-theme/next.config.ts",
    "content": "import nextra from 'nextra'\n\nconst withNextra = nextra({})\n\nexport default withNextra({\n  reactStrictMode: true\n})\n"
  },
  {
    "path": "examples/custom-theme/package.json",
    "content": "{\n  \"name\": \"example-custom-theme\",\n  \"type\": \"module\",\n  \"license\": \"MIT\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"next build\",\n    \"dev\": \"next\",\n    \"postbuild\": \"pagefind --site .next/server/app --output-path public/_pagefind\",\n    \"start\": \"next start\"\n  },\n  \"dependencies\": {\n    \"next\": \"^16.0.7\",\n    \"nextra\": \"workspace:*\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^19.1.8\",\n    \"pagefind\": \"^1.3.0\",\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "examples/custom-theme/public/.gitkeep",
    "content": ""
  },
  {
    "path": "examples/custom-theme/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2017\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"incremental\": true,\n    \"module\": \"esnext\",\n    \"esModuleInterop\": true,\n    \"moduleResolution\": \"bundler\",\n    \"strictNullChecks\": true,\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"react-jsx\",\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ]\n  },\n  \"include\": [\n    \"next-env.d.ts\",\n    \".next/types/**/*.ts\",\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \".next/dev/types/**/*.ts\"\n  ],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "examples/docs/mdx-components.js",
    "content": "import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'\n\nconst docsComponents = getDocsMDXComponents()\n\nexport const useMDXComponents = components => ({\n  ...docsComponents,\n  ...components\n})\n"
  },
  {
    "path": "examples/docs/next.config.mjs",
    "content": "import nextra from 'nextra'\n\nconst withNextra = nextra({\n  latex: true,\n  search: {\n    codeblocks: false\n  },\n  contentDirBasePath: '/docs'\n})\n\nexport default withNextra({\n  reactStrictMode: true\n})\n"
  },
  {
    "path": "examples/docs/package.json",
    "content": "{\n  \"name\": \"example-docs\",\n  \"license\": \"MIT\",\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"next build --webpack\",\n    \"dev\": \"next\",\n    \"postbuild\": \"pagefind --site .next/server/app --output-path public/_pagefind\",\n    \"start\": \"next start\"\n  },\n  \"dependencies\": {\n    \"next\": \"^16.0.7\",\n    \"nextra\": \"workspace:*\",\n    \"nextra-theme-docs\": \"workspace:*\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\"\n  },\n  \"devDependencies\": {\n    \"pagefind\": \"^1.3.0\"\n  }\n}\n"
  },
  {
    "path": "examples/docs/src/app/_ignored/_meta.js",
    "content": "// This file will be NOT treated as `_meta` file, since directory starts with underscore\nexport default {}\n"
  },
  {
    "path": "examples/docs/src/app/_ignored/page.mdx",
    "content": "This file will be NOT treated as page, since directory starts with underscore\n"
  },
  {
    "path": "examples/docs/src/app/_meta.js",
    "content": "export default {\n  index: {\n    display: 'hidden'\n  },\n  docs: {\n    type: 'page',\n    title: 'Documentation'\n  },\n  blog: {\n    type: 'page',\n    title: 'Blog'\n  }\n}\n"
  },
  {
    "path": "examples/docs/src/app/blog/page.jsx",
    "content": "export default function BlogPage() {\n  return (\n    <h1\n      style={{\n        textAlign: 'center',\n        fontSize: 64,\n        margin: '25vh 0',\n        fontWeight: 'bold'\n      }}\n    >\n      Blog page\n    </h1>\n  )\n}\n"
  },
  {
    "path": "examples/docs/src/app/docs/[[...mdxPath]]/page.jsx",
    "content": "import { generateStaticParamsFor, importPage } from 'nextra/pages'\nimport { useMDXComponents as getMDXComponents } from '../../../../mdx-components'\n\nexport const generateStaticParams = generateStaticParamsFor('mdxPath')\n\nexport async function generateMetadata(props) {\n  const params = await props.params\n  const { metadata } = await importPage(params.mdxPath)\n  return metadata\n}\n\nconst Wrapper = getMDXComponents().wrapper\n\nexport default async function Page(props) {\n  const params = await props.params\n  const {\n    default: MDXContent,\n    toc,\n    metadata,\n    sourceCode\n  } = await importPage(params.mdxPath)\n  return (\n    <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>\n      <MDXContent {...props} params={params} />\n    </Wrapper>\n  )\n}\n"
  },
  {
    "path": "examples/docs/src/app/layout.jsx",
    "content": "/* eslint-env node */\nimport { Footer, Layout, Navbar } from 'nextra-theme-docs'\nimport { Banner, Head } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-map'\nimport 'nextra-theme-docs/style.css'\n\nexport const metadata = {\n  metadataBase: new URL('https://nextra.site'),\n  title: {\n    template: '%s - Nextra'\n  },\n  description: 'Nextra: the Next.js site builder',\n  applicationName: 'Nextra',\n  generator: 'Next.js',\n  appleWebApp: {\n    title: 'Nextra'\n  },\n  other: {\n    'msapplication-TileImage': '/ms-icon-144x144.png',\n    'msapplication-TileColor': '#fff'\n  },\n  twitter: {\n    site: 'https://nextra.site'\n  }\n}\n\nexport default async function RootLayout({ children }) {\n  const navbar = (\n    <Navbar\n      logo={\n        <div>\n          <b>Nextra</b>{' '}\n          <span style={{ opacity: '60%' }}>The Next Docs Builder</span>\n        </div>\n      }\n      // Next.js discord server\n      chatLink=\"https://discord.gg/hEM84NMkRv\"\n    />\n  )\n  const pageMap = await getPageMap()\n  return (\n    <html lang=\"en\" dir=\"ltr\" suppressHydrationWarning>\n      <Head faviconGlyph=\"✦\" />\n      <body>\n        <Layout\n          banner={<Banner storageKey=\"Nextra 2\">Nextra 2 Alpha</Banner>}\n          navbar={navbar}\n          footer={<Footer>MIT {new Date().getFullYear()} © Nextra.</Footer>}\n          editLink=\"Edit this page on GitHub\"\n          docsRepositoryBase=\"https://github.com/shuding/nextra/blob/main/examples/docs\"\n          sidebar={{ defaultMenuCollapseLevel: 1 }}\n          pageMap={pageMap}\n        >\n          {children}\n        </Layout>\n      </body>\n    </html>\n  )\n}\n"
  },
  {
    "path": "examples/docs/src/app/page.jsx",
    "content": "export default function IndexPage() {\n  return (\n    <h1\n      style={{\n        textAlign: 'center',\n        fontSize: 64,\n        margin: '25vh 0',\n        fontWeight: 'bold'\n      }}\n    >\n      Index page\n    </h1>\n  )\n}\n"
  },
  {
    "path": "examples/docs/src/app/showcase/(overview)/page.jsx",
    "content": "export default function Page() {\n  return (\n    <h1\n      style={{\n        textAlign: 'center',\n        fontSize: 64,\n        margin: '25vh 0',\n        fontWeight: 'bold'\n      }}\n    >\n      Showcase\n    </h1>\n  )\n}\n"
  },
  {
    "path": "examples/docs/src/content/_meta.js",
    "content": "export default {\n  index: '',\n  'get-started': '',\n  features: '',\n  themes: '',\n  advanced: {\n    theme: {\n      copyPage: false\n    }\n  }\n}\n"
  },
  {
    "path": "examples/docs/src/content/advanced/code-highlighting.mdx",
    "content": "# Code Highlighting\n\nNextra uses [Shiki](https://shiki.style) and\n[Rehype Pretty Code](https://github.com/FormidableLabs/prism-react-renderer) to\nhighlight the code blocks. This section covers how you can customize it.\n\n## Meta strings\n\n### Highlight lines\n\n````mdx\n```jsx {1,3-5}\nimport 'nextra-theme-docs/style.css'\n\nexport default function Nextra({ Component, pageProps }) {\n  const getLayout = Component.getLayout || (page => page)\n  return getLayout(<Component {...pageProps} />)\n}\n```\n````\n\n```jsx {1,4-5}\nimport 'nextra-theme-docs/style.css'\n\nexport default function Nextra({ Component, pageProps }) {\n  const getLayout = Component.getLayout || (page => page)\n  return getLayout(<Component {...pageProps} />)\n}\n```\n\n### Title\n\n````mdx\n```jsx filename=\"_app.js\"\nimport 'nextra-theme-docs/style.css'\n\nexport default function Nextra({ Component, pageProps }) {\n  const getLayout = Component.getLayout || (page => page)\n  return getLayout(<Component {...pageProps} />)\n}\n```\n````\n\n```jsx filename=\"_app.js\"\nimport 'nextra-theme-docs/style.css'\n\nexport default function Nextra({ Component, pageProps }) {\n  const getLayout = Component.getLayout || (page => page)\n  return getLayout(<Component {...pageProps} />)\n}\n```\n\n## Supported Languages\n\nYou can find a list of supported languages\n[here](https://github.com/shikijs/shiki/blob/main/docs/languages.md).\n"
  },
  {
    "path": "examples/docs/src/content/features/_meta.js",
    "content": "export default {\n  mdx: '',\n  ssg: '',\n  i18n: '',\n  image: '',\n  themes: '',\n  latex: ''\n}\n"
  },
  {
    "path": "examples/docs/src/content/features/i18n.mdx",
    "content": "# Next.js I18n\n\n> [!NOTE]\n>\n> This feature is only available in the docs theme.\n\nNextra supports\n[Next.js Internationalized Routing](https://nextjs.org/docs/advanced-features/i18n-routing)\nout of the box.\n\nTo add multi-language pages to your Nextra application, just need to config\n`i18n` in `next.config.mjs`:\n\n```js filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  theme: 'nextra-theme-docs',\n  themeConfig: './theme.config.js'\n})\n\nexport default withNextra({\n  i18n: {\n    locales: ['en', 'zh', 'de'],\n    defaultLocale: 'en'\n  }\n})\n```\n\nThen, add the locale codes to your file extensions (required for the default\nlocale too):\n\n```text\n/pages\n  index.en.md\n  index.zh.md\n  index.de.md\n  meta.en.json\n  meta.zh.json\n  meta.de.json\n  ...\n```\n\nFinally, add the `i18n` option to your `theme.config.js` to configure the\nlanguage dropdown:\n\n```jsx filename=\"theme.config.js\"\ni18n: [\n  { locale: 'en', text: 'English' },\n  { locale: 'zh', text: '中文' },\n  { locale: 'de', text: 'Deutsch' },\n  { locale: 'ar', text: 'العربية', direction: 'rtl' }\n]\n```\n"
  },
  {
    "path": "examples/docs/src/content/features/image.mdx",
    "content": "# Next.js Image\n\nYou can use [Next.js Image](https://nextjs.org/docs/app/getting-started/images)\ndirectly in MDX.\n\nIf the `demo.png` file is located at `/public/demo.png`, you can use the code\nbelow to display it:\n\n```mdx\nimport Image from 'next/image'\n\n<Image src=\"/demo.png\" alt=\"Hello\" width={500} height={500} />\n```\n\n## Static Image\n\n> [!NOTE]\n>\n> This feature is enabled via `staticImage: true` in the Nextra config by\n> default.\n\nNextra also supports automatic static image imports, you no longer need to\nspecify the width and height of the image manually, and you can directly use the\nMarkdown syntax to display the same image:\n\n```mdx\n![Hello](/demo.png)\n```\n\nWith Next.js Image, there will be no layout shift, and a beautiful blurry\nplaceholder will be shown by default when loading the images:\n\n![Nextra](../../app/opengraph-image.png)\n"
  },
  {
    "path": "examples/docs/src/content/features/latex.mdx",
    "content": "{/* <link rel=\"stylesheet\"> is unsupported in Metadata API https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata */}\n\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/katex/dist/katex.css\"\n/>\n\n# LaTeX\n\nNextra uses [KaTeX](https://katex.org) to render LaTeX expressions directly in\nMDX. To enable LaTeX support, you must add the following to your\n`next.config.mjs`:\n\n```js filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  latex: true\n})\n\nexport default withNextra()\n```\n\nUsing LaTeX within MDX is as simple as wrapping your expression in `$$` or `$`.\nFor example, the following code\n\n```latex\n$\\sqrt{a^2 + b^2}$\n```\n\nwill be rendered as: $\\sqrt{a^2 + b^2}$\n\nTo learn more about KaTeX and its supported functions, visit their\n[documentation](https://katex.org/docs/supported.html).\n"
  },
  {
    "path": "examples/docs/src/content/features/mdx.mdx",
    "content": "import { compileMdx } from 'nextra/compile'\nimport { Callout } from 'nextra/components'\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n# MDX\n\nWith Nextra, all your `.md` and `.mdx` files under the pages directory will be\nrendered with [MDX](https://mdxjs.com/about), it's an advanced Markdown format\nwith React component support.\n\nYou can use import and use React components inside your Markdown files like\nthis:\n\nexport async function Demo() {\n  const mdx = `import { Callout } from 'nextra/components'\n\n**Markdown With React Components**\n\n<Callout emoji=\"✅\">\n  **MDX** (the library), at its core, transforms MDX (the syntax) to JSX. It\n  receives an MDX string and outputs a _JSX string_. It does this by parsing the\n  MDX document to a syntax tree and then generates a JSX document from that\n  tree.\n</Callout>`\n  const rawJs = await compileMdx(`~~~mdx filename=\"example.mdx\"\n${mdx}\n~~~\n\nGenerates:\n\n${mdx}`)\n  return <MDXRemote compiledSource={rawJs} components={{ Callout }} />\n}\n\n<Demo />\n\n## Headings\n\n# **Hello**, This Is a _Title_ Inside `h1`\n\n## **Hello**, This Is a _Title_ Inside `h2`\n\n### **Hello**, This Is a _Title_ Inside `h3`\n\n#### **Hello**, This Is a _Title_ Inside `h4`\n\n##### **Hello**, This Is a _Title_ Inside `h5`\n\n###### **Hello**, This Is a _Title_ Inside `h6`\n\n## List\n\n1. one\n1. two\n1. three\n\n- one\n- two\n- three\n\n## Task List\n\n```mdx\n- [x] Write the press release\n- [ ] Update the website\n- [ ] Contact the media\n```\n\nRenders\n\n- [x] Write the press release\n- [ ] Update the website\n- [ ] Contact the media\n\n## Syntax Highlighting\n\nAutomatic syntax highlighting\n\n````mdx\n```js\nconsole.log('hello, world')\n```\n````\n\nRenders:\n\n```js\nconsole.log('hello, world')\n```\n\nYou can also add the `{line|range}` modifier to highlight specific lines:\n\n````mdx\n```jsx {4,6-8}\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user', fetcher)\n\n  if (error) return <div>failed to load</div>\n  if (!data) return <div>loading...</div>\n  return <div>hello {data.name}!</div>\n}\n```\n````\n\n```jsx {4,6-8}\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user', fetcher)\n\n  if (error) return <div>failed to load</div>\n  if (!data) return <div>loading...</div>\n  return <div>hello {data.name}!</div>\n}\n```\n\n## Inline Code\n\nYou can use \\`content\\` to wrap inline code content like: `let x = 1`.\n\n## Blockquote\n\n> Where some people measure progress in answers-right per test or tests-passed\n> per year, we are more interested in Sistine-Chapel-Ceilings per Lifetime.\n>\n> — Alan Kay, A Personal Computer for Children of All Ages\n\nNested quotes:\n\n> > Where some people measure progress in answers-right per test or tests-passed\n> > per year, we are more interested in Sistine-Chapel-Ceilings per Lifetime.\n> >\n> > — Alan Kay, A Personal Computer for Children of All Ages\n>\n> This is **great**.\n>\n> — Shu Ding.\n\n## Table\n\n| Syntax        | Description |   Test Text |\n| :------------ | :---------: | ----------: |\n| Header        |    Title    | Here's this |\n| Paragraph     |    Text     |    And more |\n| Strikethrough |             |    ~~Text~~ |\n\n## React Components\n\nReact components and Markdown can be **mixed together**, for instance:\n\n```mdx\n<Callout>Give [**Nextra**](https://github.com/shuding/nextra) a star!</Callout>\n```\n\nRenders:\n\n<Callout>Give [**Nextra**](https://github.com/shuding/nextra) a star!</Callout>\n"
  },
  {
    "path": "examples/docs/src/content/features/ssg.mdx",
    "content": "# Next.js Static Rendering\n\n[Static Rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#static-rendering-default)\nis default server rendering strategy, where routes are rendered at **build\ntime** or in the background after\n[data revalidation](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration).\nThe result is cached and can be distributed via a\n[Content Delivery Network (CDN)](https://developer.mozilla.org/docs/Glossary/CDN)\nfor optimal performance.\n\nStatic rendering is ideal for routes with non-personalized data that can be\ndetermined at build time, such as blog posts or product pages.\n\nexport async function Stars() {\n  let stars = 0\n  try {\n    const response = await fetch('https://api.github.com/repos/shuding/nextra')\n    const repo = await response.json()\n    stars = repo.stargazers_count\n  } catch {\n    /* Ignore if there is an error, due rate limiting on CI */\n  }\n  return <b>{stars}</b>\n}\n\n> Nextra has <Stars /> stars on GitHub!\n\nThe number above was generated at build time via MDX server components. With\n[Incremental Static Regeneration](https://nextjs.org/docs/app/building-your-application/data-fetching/incremental-static-regeneration)\nenabled, it will be kept up to date.\n\n---\n\nHere's the MDX code for the example above:\n\n```js filename=\"ssg.mdx\"\nexport async function Stars() {\n  const response = await fetch(`https://api.github.com/repos/shuding/nextra`)\n  const repo = await response.json()\n  const stars = repo.stargazers_count || 0\n  return <b>{stars}</b>\n}\n\n> Nextra has <Stars /> stars on GitHub!\n```\n"
  },
  {
    "path": "examples/docs/src/content/features/themes.mdx",
    "content": "# Themes\n\nNextra itself is basically a plugin that normalizes your Markdown routes in\nNext.js into structural data, and it doesn't handle any styling related thing. A\n**theme** is what renders your actual pages, it works like a layout component in\nReact.\n\nNextra has 2 official themes that you can use:\n\n- [Docs Theme](/themes/docs)\n- [Blog Theme](/themes/blog)\n\nYou can also extend your own themes. Here's a great starter example by\n[@jaredpalmer](https://github.com/jaredpalmer):\n\n- [Nextra Blank Custom Theme/Boilerplate Example](https://github.com/jaredpalmer/nextra-blank-custom-theme)\n"
  },
  {
    "path": "examples/docs/src/content/get-started.mdx",
    "content": "import { Steps } from 'nextra/components'\n\n# Get Started\n\n## Quick start with Vercel\n\nYou can start by creating your own Nextra site and deploying to Vercel by\nclicking the link:\n\n[![](https://vercel.com/button)](https://vercel.com/new/clone?demo-description=Markdown%20powered%20docs%20site.%20Built%20with%20Next.js.&demo-image=https%3A%2F%2Fnextra.vercel.app%2Fdemo.png&demo-title=Documentation%20Starter%20Kit&demo-url=https%3A%2F%2Fnextra.vercel.app%2F&project-name=nextjs-docs&repository-name=nextjs-docs&s=https%3A%2F%2Fgithub.com%2Fshuding%2Fnextra&from=templates)\n\nVercel will create the Nextra repository and deploy the site for you with just a\nfew clicks. Once done, every change in the repository will be deployed\nautomatically.\n\n## Create manually\n\nNextra works like a Next.js plugin, and it accepts a theme config (layout) to\nrender the page. To start: [^3]\n\n<Steps>\n### Install Next.js, Nextra and React [^1]\n\n```sh npm2yarn\nnpm i react react-dom next nextra\n```\n\n### Install the docs theme [^2]\n\n```sh npm2yarn\nnpm i nextra-theme-docs\n```\n\n### Create the following Next.js config and theme config under the root directory\n\n```js filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  theme: 'nextra-theme-blog',\n  themeConfig: './theme.config.js'\n})\nexport default withNextra()\n```\n\n### Create a `theme.config.js` file for the docs theme\n\n```js filename=\"theme.config.js\"\nexport default {\n  project: {\n    link: 'https://github.com/shuding/nextra' // GitHub link in the navbar\n  },\n  docsRepositoryBase: 'https://github.com/shuding/nextra/blob/master', // base URL for the docs repository\n  getNextSeoProps: () => ({ titleTemplate: '%s – Nextra' }),\n  navigation: true,\n  darkMode: true,\n  footer: {\n    text: `MIT ${new Date().getFullYear()} © Shu Ding.`\n  },\n  editLink: {\n    text: 'Edit this page on GitHub'\n  },\n  logo: (\n    <>\n      <svg>...</svg>\n      <span>Next.js Static Site Generator</span>\n    </>\n  ),\n  head: (\n    <>\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n      <meta name=\"description\" content=\"Nextra: the next docs builder\" />\n      <meta name=\"og:title\" content=\"Nextra: the next docs builder\" />\n    </>\n  ),\n  primaryHue: {\n    dark: 204,\n    light: 212\n  }\n}\n```\n\n> [!NOTE]\n>\n> More configuration options for the docs theme can be found\n> [here](/themes/docs/configuration).\n\n### You are good to go! Run `next dev` to start\n\n</Steps>\n\n---\n\n<span id=\"sidebar-and-anchor-links\" />\n\n> [!NOTE]\n>\n> Any `.md` or `.mdx` file will turn into a doc page and be displayed in\n> sidebar. You can also create a `_meta.js` file to customize the page order and\n> title. <br /> Check the source code: https://github.com/shuding/nextra for\n> more information.\n\n> [!TIP]\n>\n> You can also use [`<style jsx>`](https://nextjs.org/docs/app/guides/css-in-js)\n> to style elements inside `theme.config.js`.\n\n[^1]: Install Next.js, Nextra and React.\n\n[^2]: Install the docs theme.\n\n[^3]: To start.\n"
  },
  {
    "path": "examples/docs/src/content/index.mdx",
    "content": "import { Bleed } from 'nextra/components'\n\n# Introduction\n\n**Nextra** is a [Next.js](https://nextjs.org) based static site generator.\n\nIt supports Markdown and React components ([MDX](/features/mdx)), automatically\ngenerated [sidebar and anchor links](/get-started#sidebar-and-anchor-links),\nfile-system based routing, built-in syntax highlighting, image optimization,\ncustom layouts, i18n, and all the features you love about Next.js.\n\nHere's what you will get in 1 minute:\n\n<Bleed>![Nextra Example](/demo.png)</Bleed>\n"
  },
  {
    "path": "examples/docs/src/content/mermaid.mdx",
    "content": "# Mermaid\n\n```mermaid\ngraph TD;\n  subgraph AA [Consumers]\n    A[Mobile app];\n    B[Web app];\n    C[Node.js client];\n  end\n  subgraph BB [Services]\n    E[REST API];\n    F[GraphQL API];\n    G[SOAP API];\n  end\n  Z[GraphQL API];\n  A --> Z;\n  B --> Z;\n  C --> Z;\n  Z --> E;\n  Z --> F;\n  Z --> G;\n```\n"
  },
  {
    "path": "examples/docs/src/content/page.mdx",
    "content": "# Just Page\n\n{/* this file should not be treated as App Router page */}\n"
  },
  {
    "path": "examples/docs/src/content/themes/_meta.js",
    "content": "export default {\n  docs: 'Docs Theme',\n  blog: 'Blog Theme'\n}\n"
  },
  {
    "path": "examples/docs/src/content/themes/blog/_meta.js",
    "content": "export default {\n  index: ''\n}\n"
  },
  {
    "path": "examples/docs/src/content/themes/blog/index.mdx",
    "content": "---\nsidebarTitle: Installation\n---\n\n# Get Started\n\nimport { Steps } from 'nextra/components'\n\n## Configurations\n\nSimilar to the docs theme, you can install the blog theme with the following\ncommands:\n\n<Steps>\n\n### Install Next.js, Nextra and React\n\n```sh npm2yarn\nnpm i next nextra react react-dom\n```\n\n### Install the blog theme\n\n```sh npm2yarn\nnpm i nextra-theme-blog\n```\n\n### Create the following Next.js config and theme config under the root directory:\n\n```js filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  theme: 'nextra-theme-blog',\n  themeConfig: './theme.config.js'\n})\nexport default withNextra()\n```\n\n```jsx filename=\"theme.config.js\"\nexport default {\n  footer: <p>MIT 2021 © Nextra.</p>,\n  head: ({ title, meta }) => (\n    <>\n      {meta.description && (\n        <meta name=\"description\" content={meta.description} />\n      )}\n      {meta.tag && <meta name=\"keywords\" content={meta.tag} />}\n      {meta.author && <meta name=\"author\" content={meta.author} />}\n    </>\n  ),\n  readMore: 'Read More →',\n  titleSuffix: null,\n  postFooter: null,\n  cusdis: {\n    appId: 'your_app_id',\n    host: 'your_host(optional)',\n    lang: 'your_lang'\n  },\n  darkMode: false,\n  navs: [\n    {\n      url: 'https://github.com/shuding/nextra',\n      name: 'Nextra'\n    }\n  ]\n}\n```\n\n### Create `pages/_app.js` and include the theme stylesheet:\n\n```jsx filename=\"_app.js\"\nimport 'nextra-theme-blog/style.css'\n\nexport default function Nextra({ Component, pageProps }) {\n  const getLayout = Component.getLayout || (page => page)\n  return <Component {...pageProps} />\n}\n```\n\n### You are good to go!\n\n</Steps>\n\n---\n\n> [!TIP]\n>\n> You can also use [`<style jsx>`](https://nextjs.org/docs/app/guides/css-in-js)\n> to style elements inside `theme.config.js`.\n\n> [!NOTE]\n>\n> An example of the blog theme can be found\n> [here](https://github.com/vercel-solutions/nextjs-portfolio-starter).\n"
  },
  {
    "path": "examples/docs/src/content/themes/docs/_meta.js",
    "content": "export default {\n  index: '',\n  configuration: '',\n  callout: '',\n  bleed: ''\n}\n"
  },
  {
    "path": "examples/docs/src/content/themes/docs/bleed.mdx",
    "content": "---\nsidebarTitle: Bleed\n---\n\n# Bleed Component\n\nA built-in component provided by `nextra-theme-docs`.\n\n## Example\n\nWhen wrapping your content with `<Bleed>`, it will be slightly wider than the\ncontainer and will overflow on both sides.\n\nimport { Bleed } from 'nextra/components'\n\n<Bleed>\n  <div style={{ border: '1px solid #888', padding: '4rem 2.5rem', textAlign: 'center' }}>\n    _There is nothing to writing. All you do is sit down at a typewriter and **bleed**._\n\n    — Ernest Hemingway\n\n  </div>\n</Bleed>\n\nIt provides a better reading experience when you want to present some graphical\ninformation, which normally looks nicer in a larger size.\n\nFor example, you can put text, image, video or any component inside:\n\n<Bleed>\n  <iframe\n    width=\"100%\"\n    height=\"430\"\n    src=\"https://youtube.com/embed/3hccXiXI0u8\"\n    allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n    allowFullScreen\n  />\n</Bleed>\n\nYou can even make it full-bleed using `<Bleed full>`:\n\n<Bleed full>![Nextra](../../../app/opengraph-image.png)</Bleed>\n\n## Usage\n\n### MDX component\n\n```mdx filename=\"bleed.mdx\"\n<Bleed>Hey, I can use **Markdown** syntax here.</Bleed>\n\n<Bleed full>![Nextra](https://nextra.site/og.jpeg)</Bleed>\n\n<Bleed full>\n  <iframe\n    src=\"https://codesandbox.io/embed/swr-states-4une7\"\n    width=\"100%\"\n    height=\"500px\"\n    title=\"SWR-States\"\n  />\n</Bleed>\n```\n\n### React Component\n\n```jsx filename=\"bleed.jsx\"\nimport { Bleed } from 'nextra/components'\n\n<Bleed>Hey, I can use **Markdown** syntax here.</Bleed>\n\n<Bleed full>\n  ![Nextra](https://nextra.site/og.jpeg)\n</Bleed>\n\n<Bleed full>\n  <iframe\n    src=\"https://codesandbox.io/embed/swr-states-4une7\"\n    width=\"100%\"\n    height=\"500px\"\n    title=\"SWR-States\"\n  />\n</Bleed>\n```\n"
  },
  {
    "path": "examples/docs/src/content/themes/docs/callout.mdx",
    "content": "---\nsidebarTitle: Callout\n---\n\n# Callout Component\n\nA built-in component provided by `nextra/components`.\n\n## Example\n\nimport { Callout } from 'nextra/components'\n\n<Callout>\n  A **callout** is a short piece of text intended to attract attention.\n</Callout>\n\n## Usage\n\n### Default\n\n<Callout emoji=\"👾\">\n  **Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro\n  Nishikado.\n</Callout>\n\n```mdx\n<Callout emoji=\"👾\">\n  **Space Invaders** is a 1978 shoot 'em up arcade game developed by Tomohiro\n  Nishikado.\n</Callout>\n```\n\n### Warning\n\n<Callout type=\"warning\">This API will be deprecated soon.</Callout>\n\n```mdx\n<Callout type=\"warning\">This API will be deprecated soon.</Callout>\n```\n\n### Error\n\n<Callout type=\"error\">\n  This is a dangerous feature that can cause everything to explode.\n</Callout>\n\n```mdx\n<Callout type=\"error\">\n  This is a dangerous feature that can cause everything to explode.\n</Callout>\n```\n\n### React Component\n\n```jsx filename=\"callout.jsx\"\nimport { Callout } from 'nextra/components'\n\nconst Component = () => {\n  return (\n    <Callout emoji=\"👾\">\n      **Space Invaders** is a 1978 shoot 'em up arcade game developed by\n      Tomohiro Nishikado.\n    </Callout>\n  )\n}\n```\n"
  },
  {
    "path": "examples/docs/src/content/themes/docs/configuration.mdx",
    "content": "# Configuration\n\nTo configure the theme, edit or create the `theme.config.js` file in the root\ndirectory. The file looks something like this:\n\n```js filename=\"theme.config.js\"\nexport default {\n  projectLink: 'https://gitlab.com/librewolf-community/browser',\n  titleSuffix: ' – Nextra',\n  footerText: `MIT ${new Date().getFullYear()} © Nextra.`\n}\n```\n\n## `projectLink`\n\nThe URL that the button in the top right will point to.\n\n**Type:** `string`\n\n**Default:** `https://github.com/shuding/nextra`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  projectLink: 'https://gitlab.com/librewolf-community/browser'\n}\n```\n\n## `projectLinkIcon`\n\nChanges the icon that is shown in the top right.\n\n**Type:** `ReactNode | React.FC<{ locale: string }>{:ts}`\n\n**Default:** GitHub icon\n\n**Example:**\n\n```jsx filename=\"theme.config.jsx\"\nimport Gitlab from '@geist-ui/react-icons/gitlab'\n\nexport default {\n  projectLinkIcon: ({ locale }) => <Gitlab />\n}\n```\n\n## `docsRepositoryBase`\n\nThe base URL of the GitHub repository the docs are located in. This will be used\nfor the `Edit this Page on GitHub` button.\n\n**Type:** `string`\n\n**Default:** `https://github.com/shuding/nextra`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  docsRepositoryBase: 'https://github.com/shuding/nextra'\n}\n```\n\n## `titleSuffix`\n\nSuffix that will be added to page titles in the URL bar.\n\n**Type:** `string`\n\n**Default:** `– Nextra`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  titleSuffix: '– Nextra'\n}\n```\n\n## `nextLinks` and `prevLinks`\n\nSpecifies if arrows are being shown at the bottom of a page showing the next and\nprevious page, like the ones at the bottom of this page.\n\n**Type:** `boolean`\n\n**Default:** `true`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  nextLinks: true,\n  prevLinks: true\n}\n```\n\n## `search`\n\nSpecifies if a search box should be shown in the top right.\n\n**Type:** `boolean`\n\n**Default:** `true`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  search: true\n}\n```\n\n## `searchPlaceholder`\n\nSpecifies if a search box should be shown in the top right.\n\n**Type:** `string | ((props: { locale: string }) => string){:ts}`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  searchPlaceholder({ locale }) {\n    if (locale === 'zh-CN') return '搜索文档...'\n    return 'Search documentation...'\n  }\n}\n```\n\n## `customSearch`\n\nA custom component to display instead of the search bar in the top right, for\nexample Algolia.\n\n**Type:** `ReactNode`\n\n**Example:**\n\n```jsx filename=\"theme.config.jsx\"\nimport Search from 'your-search'\n\nexport default {\n  customSearch: <Search />\n}\n```\n\n## `darkMode`\n\nSpecifies if the user can select a dark mode.\n\n**Type:** `boolean`\n\n**Default:** `true`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  darkMode: true\n}\n```\n\n## `defaultMenuCollapseLevel`\n\nSpecifies the folder level at which the menu on the left is collapsed by\ndefault.\n\n**Type:** `number`\n\n**Default:** `2`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  defaultMenuCollapseLevel: 2\n}\n```\n\n## `footer`\n\nSpecifies if the footer should be shown.\n\n**Type:** `boolean`\n\n**Default:** `true`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  footer: true\n}\n```\n\n## `footerText`\n\nThe text that is shown on the left of the footer.\n\n**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  footerText: ({ locale }) => `MIT ${new Date().getFullYear()} © Nextra.`\n}\n```\n\n## `footerEditLink`\n\nThe components that should be shown on the link that leads to the editable page\non the repository.\n\n**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`\n\n**Default:** `Edit this page`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  footerEditLink: ({ locale }) => 'Edit this page on GitHub'\n}\n```\n\n## `feedbackLink`\n\nThe components that should be shown on the link that leads to the issues or\ndiscussions of the repository.\n\n**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`\n\n**Default:** ``\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  feedbackLink: ({ locale }) => 'Question? Give us feedback →'\n}\n```\n\n## `feedbackLabels`\n\nLabel used for create issue or discussion.\n\n**Type:** `string`\n\n**Default:** ``\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  feedbackLabels: 'feedbacks'\n}\n```\n\n## `logo`\n\nThe logo in the top left.\n\n**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`\n\n**Example:**\n\n```jsx filename=\"theme.config.jsx\"\nexport default {\n  logo: ({ locale }) => (\n    <>\n      <span className=\"mr-2 hidden font-extrabold md:inline\">Nextra</span>\n      <span className=\"hidden font-normal text-gray-600 md:inline\">\n        The Next Docs Builder\n      </span>\n    </>\n  )\n}\n```\n\n## `logoLink`\n\nEnable automaticaly linking the logo to root, or provide a custom url.\n\n**Type:** `string` | `boolean`\n\n**Default:** `true` (links to `/` by default)\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  logoLink: '/about'\n}\n```\n\nOr to disable the logo link:\n\n```js filename=\"theme.config.js\"\nexport default {\n  logoLink: false\n}\n```\n\n## `head`\n\nThe head that should be inserted into the html document.\n\n**Type:**\n`ReactNode | React.FC<PropsWithChildren<{ locale: string; config: DocsThemeConfig; title: string; meta: Record<string, any> }>>{:ts}`\n\n**Example:**\n\n```jsx filename=\"theme.config.jsx\"\nexport default {\n  head: (\n    <>\n      <meta name=\"msapplication-TileColor\" content=\"#fff\" />\n      <meta httpEquiv=\"Content-Language\" content=\"en\" />\n      <meta name=\"description\" content=\"Nextra: the next docs builder\" />\n      <meta name=\"twitter:card\" content=\"summary_large_image\" />\n      <meta name=\"twitter:site\" content=\"@shuding_\" />\n      <meta property=\"og:title\" content=\"Nextra: the next docs builder\" />\n      <meta property=\"og:description\" content=\"Nextra: the next docs builder\" />\n      <meta name=\"apple-mobile-web-app-title\" content=\"Nextra\" />\n    </>\n  )\n}\n```\n\n## `direction`\n\nThe direction of the text on the page\n\n**Type:** `'ltr' | 'rtl'`\n\n**Default:** `'ltr'`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  direction: 'ltr'\n}\n```\n\n## `floatTOC`\n\nSpecifies if the table of contents of a page (the headings) should be displayed\nfloating on the right instead of being integrated in the menu on the left.\n\n**Type:** `boolean`\n\n**Default:** `false`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  floatTOC: false\n}\n```\n\n## `projectChatLink`\n\nThe URL that the chat button in the top right will point to.\n\n**Type:** `string`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  projectChatLink: 'https://discord.gg/hEM84NMkRv'\n}\n```\n\n## `projectChatLinkIcon`\n\nThe icon component that is used as the chat button\n\n**Type:** `ReactNode`\n\n**Example:**\n\n```jsx filename=\"theme.config.jsx\"\nexport default {\n  projectChatLinkIcon: <Discord />\n}\n```\n\n## `banner`\n\nThe banner content that will display at top of the page.\n\n**Type:** `ReactNode | React.FC<PropsWithChildren<{ locale: string }>>{:ts}`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  banner: ({ locale }) => 'Nextra 2'\n}\n```\n\n## `bannerKey`\n\nThe key that is used to control the display of banner in localStorage.\n\n**Type:** `string`\n\n**Default:** `'nextra-banner'`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  bannerKey: 'Nextra-banner'\n}\n```\n\n## `gitTimestamp`\n\nThe component that is used to display timestamp of the last commit of current\npage.\n\n**Type:**\n`string | React.FC<PropsWithChildren<{ locale: string; timestamp: Date }>>{:ts}`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  gitTimestamp: 'Last updated on'\n}\n```\n\n## `tocExtraContent`\n\nThe extra content that is displayed under the table of contents.\n\n**Type:** `ReactNode | React.FC<PropsWithChildren<unknown>>{:ts}`\n\n**Example:**\n\n```jsx filename=\"theme.config.jsx\"\nexport default {\n  tocExtraContent() {\n    return <img src=\"https://placecats.com/300/200\" alt=\"\" />\n  }\n}\n```\n\n## `i18n`\n\nThe internationalization (i18n) config. See more [here](/features/i18n).\n\n## `faviconGlyph`\n\nA glyph that should be used as a favicon.\n\n**Type:** `char`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  faviconGlyph: '🐱'\n}\n```\n\n## `search`\n\nEnable Nextra built-in search\n\n**Type:** `boolean | { codeblocks: boolean }`\n\n**Example:**\n\n```js filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  theme: 'nextra-theme-blog',\n  themeConfig: './theme.config.js',\n  search: {\n    codeblocks: false\n  }\n})\nexport default withNextra()\n```\n\n## `searchResultEmpty`\n\nEmpty component for search result.\n\n**Type:** `boolean | { codeblocks: boolean }`\n\n**Example:**\n\n```js filename=\"theme.config.js\"\nexport default {\n  searchResultEmpty({ locale }) {\n    if (locale === 'zh-CN') return '未查找到结果'\n    return 'No results found'\n  }\n}\n```\n"
  },
  {
    "path": "examples/docs/src/content/themes/docs/index.mdx",
    "content": "---\nsidebarTitle: Installation\n---\n\n# Docs Theme\n\nimport { Steps } from 'nextra/components'\n\n> [!NOTE]\n>\n> This website is built with the docs theme.\n\nyou can install the blog theme with the following commands:\n\n## Getting start\n\n<Steps>\n\n### Install Next.js, Nextra and React\n\n```sh npm2yarn\nnpm i react react-dom next nextra\n```\n\n### Install the docs theme\n\n```sh npm2yarn\nnpm i nextra-theme-docs\n```\n\n### Create the following Next.js config and theme config under the root directory:\n\n```jsx filename=\"next.config.mjs\"\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  theme: 'nextra-theme-blog',\n  themeConfig: './theme.config.js'\n})\nexport default withNextra()\n```\n\n```jsx filename=\"theme.config.js\"\nexport default {\n  projectLink: 'https://github.com/shuding/nextra', // GitHub link in the navbar\n  docsRepositoryBase: 'https://github.com/shuding/nextra/blob/master', // base URL for the docs repository\n  titleSuffix: ' – Nextra',\n  nextLinks: true,\n  prevLinks: true,\n  search: true,\n  customSearch: null, // customizable, you can use algolia for example\n  darkMode: true,\n  footer: true,\n  footerText: `MIT ${new Date().getFullYear()} © Shu Ding.`,\n  footerEditLink: `Edit this page on GitHub`,\n  logo: (\n    <>\n      <svg>...</svg>\n      <span>Next.js Static Site Generator</span>\n    </>\n  ),\n  head: (\n    <>\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n      <meta name=\"description\" content=\"Nextra: the next docs builder\" />\n      <meta name=\"og:title\" content=\"Nextra: the next docs builder\" />\n    </>\n  )\n}\n```\n\n### You are good to go!\n\n</Steps>\n\n---\n\n> [!TIP]\n>\n> You can also use [`<style jsx>`](https://nextjs.org/docs/app/guides/css-in-js)\n> to style elements inside `theme.config.js`.\n"
  },
  {
    "path": "examples/docs/src/content/themes/docs/tabs.mdx",
    "content": "---\nsidebarTitle: Tabs\n---\n\n# Tabs Component\n\nA built-in component provided by `nextra-theme-docs`.\n\n## Example\n\nimport { Tabs } from 'nextra/components'\n\n<Tabs items={['JavaScript', 'C++', {label:'C', disabled: true}, 'Python']} defaultIndex={1}>\n  <Tabs.Tab>\n    ```js filename=\"hi.js\"\n    import { useState, useEffect } from 'react';\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```cpp filename=\"hi.cpp\"\n    #include <iostream>\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```c filename=\"hi.c\"\n    #include <stdio.h>\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n     ```python filename=\"hello.py\"\n    print('Hello, world!')\n    ```\n  </Tabs.Tab>\n</Tabs>\n\n## Usage\n\n### MDX component\n\n````mdx filename=\"tabs.mdx\"\n<Tabs items={['JavaScript', 'C++', {label:'C', disabled: true}, 'Python']} defaultIndex={1}>\n  <Tabs.Tab>\n    ```js filename=\"hi.js\"\n    import { useState, useEffect } from 'react';\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```cpp filename=\"hi.cpp\"\n    #include <iostream>\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```c filename=\"hi.c\"\n    #include <stdio.h>\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```python filename=\"hello.py\"\n    print('Hello, world!')\n    ```\n  </Tabs.Tab>\n</Tabs>\n````\n\n### React Component\n\n```jsx filename=\"tabs.jsx\"\nimport { Tabs } from 'nextra/components'\n\nconst items = ['1', '2', '3', '4']\nconst defaultIndex = 1\nconst Component = () => (\n  <Tabs items={items} defaultIndex={defaultIndex}>\n    <Tabs.Tab>1</Tab>\n    <Tabs.Tab>2</Tab>\n    <Tabs.Tab>3</Tab>\n    <Tabs.Tab>4</Tab>\n  </Tabs>\n)\nexport default Component\n```\n"
  },
  {
    "path": "examples/swr-site/README.md",
    "content": "# SWR i18n Example Website\n"
  },
  {
    "path": "examples/swr-site/app/[lang]/[[...mdxPath]]/page.tsx",
    "content": "import { generateStaticParamsFor, importPage } from 'nextra/pages'\nimport type { FC } from 'react'\nimport { useMDXComponents as getMDXComponents } from '../../../mdx-components'\n\nexport const generateStaticParams = generateStaticParamsFor('mdxPath')\n\nexport async function generateMetadata(props: PageProps) {\n  const params = await props.params\n  const { metadata } = await importPage(params.mdxPath, params.lang)\n  return metadata\n}\n\ntype PageProps = Readonly<{\n  params: Promise<{\n    mdxPath: string[]\n    lang: string\n  }>\n}>\n\nconst Wrapper = getMDXComponents().wrapper\n\nconst Page: FC<PageProps> = async props => {\n  const params = await props.params\n  const result = await importPage(params.mdxPath, params.lang)\n  const { default: MDXContent, toc, metadata, sourceCode } = result\n  return (\n    <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>\n      <MDXContent {...props} params={params} />\n    </Wrapper>\n  )\n}\n\nexport default Page\n"
  },
  {
    "path": "examples/swr-site/app/[lang]/graphql-eslint/[[...slug]]/page.tsx",
    "content": "import { notFound } from 'next/navigation'\nimport { compileMdx } from 'nextra/compile'\nimport { Callout, Tabs } from 'nextra/components'\nimport { evaluate } from 'nextra/evaluate'\nimport {\n  convertToPageMap,\n  mergeMetaWithPageMap,\n  normalizePageMap\n} from 'nextra/page-map'\nimport { useMDXComponents as getMDXComponents } from '../../../../mdx-components'\n\nconst user = 'graphql-hive'\nconst repo = 'graphql-eslint'\nconst branch = '34b722a2a520599ce06a4ddcccc9623b76434089'\nconst docsPath = 'website/src/pages/docs/'\nconst filePaths = [\n  'configs.mdx',\n  'custom-rules.mdx',\n  'getting-started.mdx',\n  'getting-started/parser-options.mdx',\n  'getting-started/parser.mdx',\n  'index.mdx'\n]\n\nconst { mdxPages, pageMap: _pageMap } = convertToPageMap({\n  filePaths,\n  basePath: 'graphql-eslint'\n})\n\n// `mergeMetaWithPageMap` is used to change sidebar order and title\nconst eslintPageMap = mergeMetaWithPageMap(_pageMap[0]!, {\n  index: 'Introduction',\n  'getting-started': {\n    items: {\n      index: 'Overview',\n      'parser-options': '',\n      parser: ''\n    }\n  },\n  configs: '',\n  'custom-rules': ''\n})\n\nexport const pageMap = normalizePageMap(eslintPageMap)\n\nconst { wrapper: Wrapper, ...components } = getMDXComponents({\n  $Tabs: Tabs,\n  Callout\n})\n\ntype PageProps = Readonly<{\n  params: Promise<{\n    slug?: string[]\n  }>\n}>\n\nexport default async function Page(props: PageProps) {\n  const params = await props.params\n  const route = params.slug?.join('/') ?? ''\n  const filePath = mdxPages[route]\n\n  if (!filePath) {\n    notFound()\n  }\n  const response = await fetch(\n    `https://raw.githubusercontent.com/${user}/${repo}/${branch}/${docsPath}${filePath}`\n  )\n  const data = await response.text()\n  const rawJs = await compileMdx(data, { filePath })\n  const { default: MDXContent, toc, metadata } = evaluate(rawJs, components)\n\n  return (\n    <Wrapper toc={toc} metadata={metadata} sourceCode={rawJs}>\n      <MDXContent />\n    </Wrapper>\n  )\n}\n\nexport function generateStaticParams() {\n  const params = Object.keys(mdxPages).map(route => ({\n    lang: 'en',\n    ...(route && { slug: route.split('/') })\n  }))\n\n  return params\n}\n"
  },
  {
    "path": "examples/swr-site/app/[lang]/layout.tsx",
    "content": "/* eslint-env node */\nimport { SwrIcon, VercelIcon } from '@app/_icons'\nimport type { Metadata } from 'next'\nimport {\n  Footer,\n  LastUpdated,\n  Layout,\n  Link,\n  LocaleSwitch,\n  Navbar\n} from 'nextra-theme-docs'\nimport { Banner, Head } from 'nextra/components'\nimport { getPageMap } from 'nextra/page-map'\nimport type { FC, ReactNode } from 'react'\nimport { getDictionary, getDirection } from '../_dictionaries/get-dictionary'\nimport { pageMap as graphqlEslintPageMap } from './graphql-eslint/[[...slug]]/page'\nimport { pageMap as graphqlYogaPageMap } from './remote/graphql-yoga/[[...slug]]/page'\nimport './styles.css'\n\nexport const metadata: Metadata = {\n  description:\n    'SWR is a React Hooks library for data fetching. SWR first returns the data from cache (stale), then sends the fetch request (revalidate), and finally comes with the up-to-date data again.',\n  title: {\n    absolute: '',\n    template: '%s | SWR'\n  },\n  metadataBase: new URL('https://swr.vercel.app'),\n  openGraph: {\n    images:\n      'https://assets.vercel.com/image/upload/v1572282926/swr/twitter-card.jpg'\n  },\n  twitter: {\n    site: '@vercel'\n  },\n  appleWebApp: {\n    title: 'SWR'\n  },\n  other: {\n    'msapplication-TileColor': '#fff'\n  }\n}\n\ntype LayoutProps = Readonly<{\n  children: ReactNode\n  params: Promise<{\n    lang: string\n  }>\n}>\n\nconst RootLayout: FC<LayoutProps> = async ({ children, params }) => {\n  const { lang } = await params\n  const dictionary = await getDictionary(lang)\n  let pageMap = await getPageMap(`/${lang}`)\n\n  if (lang === 'en') {\n    pageMap = [\n      ...pageMap,\n      {\n        name: 'remote',\n        route: '/remote',\n        children: [graphqlYogaPageMap],\n        title: 'Remote'\n      },\n      graphqlEslintPageMap\n    ]\n  }\n  const banner = (\n    <Banner storageKey=\"swr-2\">\n      SWR 2.0 is out! <Link href=\"#\">Read more →</Link>\n    </Banner>\n  )\n  const navbar = (\n    <Navbar\n      logo={\n        <>\n          <SwrIcon height=\"12\" />\n          <span\n            className=\"ms-2 font-extrabold select-none max-md:hidden\"\n            title={`SWR: ${dictionary.logo.title}`}\n          >\n            SWR\n          </span>\n        </>\n      }\n      projectLink=\"https://github.com/vercel/swr\"\n      chatLink=\"https://discord.com\"\n    >\n      <LocaleSwitch lite />\n    </Navbar>\n  )\n  const footer = (\n    <Footer>\n      <a\n        rel=\"noreferrer\"\n        target=\"_blank\"\n        className=\"x:focus-visible:nextra-focus flex items-center gap-2 font-semibold\"\n        href={dictionary.link.vercel}\n      >\n        {dictionary.poweredBy} <VercelIcon height=\"20\" />\n      </a>\n    </Footer>\n  )\n  return (\n    <html lang={lang} dir={getDirection(lang)} suppressHydrationWarning>\n      <Head\n        backgroundColor={{\n          dark: 'rgb(15,23,42)',\n          light: 'rgb(254, 252, 232)'\n        }}\n        color={{\n          hue: { dark: 120, light: 0 },\n          saturation: { dark: 100, light: 100 }\n        }}\n      />\n      <body>\n        <Layout\n          banner={banner}\n          navbar={navbar}\n          footer={footer}\n          docsRepositoryBase=\"https://github.com/shuding/nextra/blob/main/examples/swr-site\"\n          i18n={[\n            { locale: 'en', name: 'English' },\n            { locale: 'es', name: 'Español RTL' },\n            { locale: 'ru', name: 'Русский' }\n          ]}\n          sidebar={{\n            defaultMenuCollapseLevel: 1,\n            autoCollapse: true\n          }}\n          toc={{\n            backToTop: dictionary.backToTop,\n            extraContent: (\n              // eslint-disable-next-line @next/next/no-img-element -- we can't use with external urls\n              <img alt=\"placeholder cat\" src=\"https://placecats.com/300/200\" />\n            )\n          }}\n          editLink={dictionary.editPage}\n          pageMap={pageMap}\n          nextThemes={{ defaultTheme: 'dark' }}\n          lastUpdated={<LastUpdated>{dictionary.lastUpdated}</LastUpdated>}\n          themeSwitch={{\n            dark: dictionary.dark,\n            light: dictionary.light,\n            system: dictionary.system\n          }}\n        >\n          {children}\n        </Layout>\n      </body>\n    </html>\n  )\n}\n\nexport default RootLayout\n"
  },
  {
    "path": "examples/swr-site/app/[lang]/not-found.ts",
    "content": "export { NotFoundPage as default } from 'nextra-theme-docs'\n"
  },
  {
    "path": "examples/swr-site/app/[lang]/remote/graphql-yoga/[[...slug]]/page.tsx",
    "content": "import { notFound } from 'next/navigation'\nimport { useMDXComponents as getMDXComponents } from 'nextra-theme-docs'\nimport { compileMdx } from 'nextra/compile'\nimport { Callout, Tabs } from 'nextra/components'\nimport { evaluate } from 'nextra/evaluate'\nimport {\n  convertToPageMap,\n  mergeMetaWithPageMap,\n  normalizePageMap\n} from 'nextra/page-map'\nimport json from '../../../../../nextra-remote-filepaths/graphql-yoga.json'\n\nconst { branch, docsPath, filePaths, repo, user } = json\n\nconst { mdxPages, pageMap: _pageMap } = convertToPageMap({\n  filePaths,\n  basePath: 'remote/graphql-yoga'\n})\n\n// @ts-expect-error -- fixme\nconst [yogaPage] = _pageMap[0].children\n\nconst yogaPageMap = mergeMetaWithPageMap(yogaPage, {\n  index: 'Quick Start',\n  features: {\n    items: {\n      graphiql: '',\n      context: 'GraphQL Context',\n      'error-masking': '',\n      subscriptions: '',\n      'file-uploads': '',\n      'envelop-plugins': '',\n      testing: '',\n      'apollo-federation': '',\n      cors: ''\n    }\n  },\n  integrations: {\n    items: {\n      'integration-with-aws-lambda': 'AWS Lambda',\n      'integration-with-cloudflare-workers': 'Cloudflare Workers',\n      'integration-with-deno': 'Deno',\n      'integration-with-express': 'Express',\n      'integration-with-fastify': 'Fastify',\n      'integration-with-koa': 'Koa',\n      'integration-with-nestjs': 'NestJS',\n      'integration-with-nextjs': 'Next.js',\n      'integration-with-sveltekit': 'SvelteKit',\n      'z-other-environments': 'Other Environments'\n    }\n  },\n  migration: {\n    items: {\n      'migration-from-apollo-server': 'Apollo Server',\n      'migration-from-express-graphql': 'Express GraphQL',\n      'migration-from-yoga-v1': 'Yoga v1'\n    }\n  }\n})\n\nexport const pageMap = normalizePageMap(yogaPageMap)\n\nconst { wrapper: Wrapper, ...components } = getMDXComponents({\n  Callout,\n  Tabs,\n  Tab: Tabs.Tab,\n  PackageCmd: () => null\n})\n\ntype PageProps = Readonly<{\n  params: Promise<{\n    slug?: string[]\n  }>\n}>\n\nexport default async function Page(props: PageProps) {\n  const params = await props.params\n  const route = params.slug?.join('/') ?? ''\n  const filePath = mdxPages[route]\n\n  if (!filePath) {\n    notFound()\n  }\n  const response = await fetch(\n    `https://raw.githubusercontent.com/${user}/${repo}/${branch}/${docsPath}${filePath}`\n  )\n  const data = await response.text()\n  const rawJs = await compileMdx(data, { filePath })\n\n  const { default: MDXContent, toc, metadata } = evaluate(rawJs, components)\n  return (\n    <Wrapper toc={toc} metadata={metadata} sourceCode={rawJs}>\n      <MDXContent />\n    </Wrapper>\n  )\n}\n\nexport function generateStaticParams() {\n  const params = Object.keys(mdxPages).map(route => ({\n    lang: 'en',\n    ...(route && { slug: route.split('/') })\n  }))\n\n  return params\n}\n"
  },
  {
    "path": "examples/swr-site/app/[lang]/styles.css",
    "content": "@import 'tailwindcss';\n@import 'nextra-theme-docs/style.css';\n@import '../_components/features.css';\n\n@theme {\n}\n\nbody {\n  --bg-dot-color: #d1d1d1;\n\n  .dark & {\n    --bg-dot-color: #313131;\n  }\n\n  background:\n    linear-gradient(to bottom, transparent, rgb(var(--nextra-bg)) 300px),\n    fixed 0 0 / 20px 20px\n      radial-gradient(var(--bg-dot-color) 1px, transparent 0),\n    fixed 10px 10px / 20px 20px\n      radial-gradient(var(--bg-dot-color) 1px, transparent 0);\n}\n"
  },
  {
    "path": "examples/swr-site/app/_components/authors.tsx",
    "content": "import { getDictionary } from '@app/_dictionaries/get-dictionary'\nimport type { Locale } from '@app/_dictionaries/i18n-config'\nimport type { FC } from 'react'\n\nexport const TopContent: FC<{\n  title: string\n  date: string\n  authors: {\n    name: string\n    link: string\n  }[]\n  lang: Locale\n}> = async ({ title, date, authors, lang }) => {\n  const dictionary = await getDictionary(lang)\n  const dateObj = new Date(date)\n  return (\n    <>\n      <h1>{title}</h1>\n      <div className=\"mt-8 mb-16 text-sm text-gray-400\">\n        <time dateTime={dateObj.toISOString()}>\n          {dateObj.toLocaleDateString(lang, {\n            month: 'long',\n            day: 'numeric',\n            year: 'numeric'\n          })}\n        </time>{' '}\n        {dictionary.by}{' '}\n        {authors.map(author => (\n          <span key={author.name} className=\"not-last:after:content-[',_']\">\n            <a\n              href={author.link}\n              target=\"_blank\"\n              rel=\"noreferrer\"\n              className=\"text-gray-800 dark:text-gray-100\"\n            >\n              {author.name}\n            </a>\n          </span>\n        ))}\n      </div>\n    </>\n  )\n}\n"
  },
  {
    "path": "examples/swr-site/app/_components/blog.tsx",
    "content": "import type { MdxFile } from 'nextra'\nimport { Link } from 'nextra-theme-docs'\nimport { getPageMap } from 'nextra/page-map'\nimport type { FC } from 'react'\n\nexport const Blog: FC<{ lang: string }> = async ({ lang }) => {\n  const pageMap = (await getPageMap(`/${lang}/blog`)) as unknown as MdxFile[]\n  return pageMap.map(page => {\n    if (page.name === 'index') return\n    const { title, description, date } = page.frontMatter!\n\n    return (\n      <div key={page.route} className=\"mt-12\">\n        <h3 className=\"text-2xl font-semibold\">{title}</h3>\n        <p className=\"my-6 leading-7 opacity-80\">\n          {description}{' '}\n          <Link href={page.route} className=\"after:content-['_→']\">\n            Read more\n          </Link>\n        </p>\n        <time\n          dateTime={new Date(date).toISOString()}\n          className=\"text-sm opacity-50\"\n        >\n          {new Date(date).toLocaleDateString(lang, {\n            month: 'long',\n            day: 'numeric',\n            year: 'numeric'\n          })}\n        </time>\n      </div>\n    )\n  })\n}\n"
  },
  {
    "path": "examples/swr-site/app/_components/example-dynamic-markdown-import.tsx",
    "content": "'use client'\n\nimport dynamic from 'next/dynamic'\nimport { useState } from 'react'\n\nexport function ExampleDynamicMarkdownImport() {\n  const [pageOne, setPageOne] = useState(true)\n  const Page = dynamic(\n    () => {\n      if (pageOne) {\n        return import('../../content/en/docs/advanced/more/tree/one.mdx')\n      }\n      return import('../../content/en/docs/advanced/more/tree/two.mdx')\n    },\n    { loading: () => <p>Loading...</p> }\n  )\n  return (\n    <>\n      <Page />\n      <button onClick={() => setPageOne(!pageOne)}>Toggle Content</button>\n    </>\n  )\n}\n"
  },
  {
    "path": "examples/swr-site/app/_components/external.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n<Callout type=\"info\" emoji=\"💣\">\n  This `<Callout>` comes from `external.mdx`\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/app/_components/features.css",
    "content": ".features {\n  display: grid;\n  grid-template-columns: 1fr 1fr 1fr 1fr;\n  gap: 1rem 2rem;\n  margin: 2.5rem 0 2rem;\n}\n.feature {\n  @apply inline-flex items-center gap-2 max-sm:justify-center;\n}\n.feature h4 {\n  font-weight: 700;\n  font-size: 1.1rem;\n  white-space: nowrap;\n}\n@media (max-width: 860px) {\n  .features {\n    gap: 1rem 0.5rem;\n  }\n  .feature h4 {\n    font-size: 0.9rem;\n  }\n}\n@media (max-width: 660px) {\n  .features {\n    grid-template-columns: 1fr 1fr;\n  }\n}\n@media (max-width: 370px) {\n  .feature h4 {\n    font-size: 0.8rem;\n  }\n  .feature svg {\n    width: 16px;\n    stroke-width: 2.5px;\n  }\n}\n"
  },
  {
    "path": "examples/swr-site/app/_components/features.tsx",
    "content": "import type { FC } from 'react'\nimport { getDictionary } from '../_dictionaries/get-dictionary'\nimport type { Locale } from '../_dictionaries/i18n-config'\nimport {\n  BoxIcon,\n  DotsVerticalIcon,\n  FeatherIcon,\n  LayersIcon,\n  LightningIcon,\n  PauseIcon,\n  PulseIcon,\n  RainIcon\n} from '../_icons'\n\nexport const Features: FC<{\n  lang: Locale\n  title: string\n}> = async ({ lang, title }) => {\n  const dictionary = await getDictionary(lang)\n\n  return (\n    <div className=\"mx-auto mb-10 w-[880px] max-w-full px-4 text-center\">\n      <p className=\"mb-2 text-lg text-gray-600 md:!text-2xl\">{title}</p>\n      <ul className=\"features\">\n        {[\n          {\n            name: dictionary.lightweight,\n            icon: FeatherIcon\n          },\n          {\n            name: dictionary.realtime,\n            icon: LightningIcon\n          },\n          {\n            name: dictionary.suspense,\n            icon: PauseIcon\n          },\n          {\n            name: dictionary.pagination,\n            icon: DotsVerticalIcon\n          },\n          {\n            name: dictionary.backendAgnostic,\n            icon: RainIcon\n          },\n          {\n            name: dictionary.renderingStrategies,\n            icon: LayersIcon\n          },\n          {\n            name: dictionary.typescript,\n            icon: BoxIcon\n          },\n          {\n            name: dictionary.remoteLocal,\n            icon: PulseIcon\n          }\n        ].map(({ name, icon: Icon }) => (\n          <li key={name} className=\"feature\">\n            <Icon height=\"24\" />\n            <h4>{name}</h4>\n          </li>\n        ))}\n      </ul>\n    </div>\n  )\n}\n"
  },
  {
    "path": "examples/swr-site/app/_components/video.tsx",
    "content": "'use client'\n\nimport type { FC, ReactNode } from 'react'\nimport { useCallback, useEffect, useRef } from 'react'\nimport { useInView } from 'react-intersection-observer'\n\nexport const Video: FC<{ src: string; caption?: ReactNode; ratio: number }> = ({\n  src,\n  caption,\n  ratio\n}) => {\n  const [inViewRef, inView] = useInView({ threshold: 1 })\n  const videoRef = useRef<HTMLVideoElement>(null)\n\n  const setRefs = useCallback(\n    // @ts-expect-error -- fixme\n    node => {\n      // Ref's from useRef needs to have the node assigned to `current`\n      videoRef.current = node\n      // Callback refs, like the one from `useInView`, is a function that takes the node as an argument\n      inViewRef(node)\n\n      node.addEventListener('click', function (this: HTMLVideoElement) {\n        if (this.paused) {\n          this.play()\n        } else {\n          this.pause()\n        }\n      })\n    },\n    [inViewRef]\n  )\n\n  useEffect(() => {\n    if (!videoRef.current) {\n      return\n    }\n\n    if (inView) {\n      videoRef.current.play()\n    } else {\n      videoRef.current.pause()\n    }\n  }, [inView])\n\n  return (\n    <div style={{ position: 'relative', margin: '2rem 1rem' }}>\n      <div style={{ paddingBottom: ratio * 100 + '%' }} />\n      <video\n        style={{ position: 'absolute', top: 0, left: 0 }}\n        loop\n        muted\n        autoPlay\n        playsInline\n        ref={setRefs}\n      >\n        <source src={src} type=\"video/mp4\" />\n      </video>\n      {caption && (\n        <figcaption style={{ fontSize: '.9rem', textAlign: 'center' }}>\n          {caption}\n        </figcaption>\n      )}\n    </div>\n  )\n}\n"
  },
  {
    "path": "examples/swr-site/app/_dictionaries/en.ts",
    "content": "export default {\n  dark: 'Dark',\n  light: 'Light',\n  system: 'System',\n  backToTop: 'Scroll to top',\n  lastUpdated: 'Last updated on',\n  logo: {\n    title: 'React Hooks for Data Fetching'\n  },\n  // notFound: 'This page could not be found',\n  poweredBy: 'Powered by',\n  link: {\n    vercel: 'https://vercel.com/?utm_source=swr'\n  },\n  lightweight: 'Lightweight',\n  realtime: 'Realtime',\n  suspense: 'Suspense',\n  pagination: 'Pagination',\n  backendAgnostic: 'Backend Agnostic',\n  renderingStrategies: 'SSR / SSG Ready',\n  typescript: 'TypeScript Ready',\n  remoteLocal: 'Remote + Local',\n  editPage: 'Edit this page on GitHub',\n  by: 'by'\n}\n"
  },
  {
    "path": "examples/swr-site/app/_dictionaries/es.ts",
    "content": "import type { Dictionary } from './i18n-config'\n\nexport default {\n  dark: 'Oscuro',\n  light: 'Luz',\n  system: 'Sistema',\n  backToTop: 'Desplazarse hacia arriba',\n  lastUpdated: 'Última actualización el',\n  logo: {\n    title: 'Biblioteca React Hooks para la obtención de datos'\n  },\n  // notFound: 'Esta pagina no se pudo encontrar',\n  poweredBy: 'Desarrollado por',\n  link: {\n    vercel: 'https://vercel.com/?utm_source=swr_es-es'\n  },\n  lightweight: 'Ligero',\n  realtime: 'Tiempo real',\n  suspense: 'Suspenso',\n  pagination: 'Paginación',\n  backendAgnostic: 'Agnóstico del Backend',\n  renderingStrategies: 'SSR / SSG',\n  typescript: 'TypeScript',\n  remoteLocal: 'Remoto + Local',\n  editPage: 'Edite esta página en GitHub',\n  by: 'por'\n} satisfies Dictionary\n"
  },
  {
    "path": "examples/swr-site/app/_dictionaries/get-dictionary.ts",
    "content": "import 'server-only'\nimport type { Dictionaries, Dictionary } from './i18n-config'\n\n// We enumerate all dictionaries here for better linting and TypeScript support\n// We also get the default import for cleaner types\nconst dictionaries: Dictionaries = {\n  en: () => import('./en'),\n  es: () => import('./es'),\n  ru: () => import('./ru')\n}\n\nexport async function getDictionary(locale: string): Promise<Dictionary> {\n  const { default: dictionary } = await // @ts-expect-error -- fixme\n  (dictionaries[locale] || dictionaries.en)()\n\n  return dictionary\n}\n\nexport function getDirection(locale: string): 'ltr' | 'rtl' {\n  return locale === 'es' ? 'rtl' : 'ltr'\n}\n"
  },
  {
    "path": "examples/swr-site/app/_dictionaries/i18n-config.ts",
    "content": "import type EnglishLocale from './en'\n\nexport const i18n = {\n  defaultLocale: 'en',\n  locales: ['en', 'es', 'ru']\n} as const\n\nexport type Locale = (typeof i18n)['locales'][number]\n\nexport type Dictionary = typeof EnglishLocale\n\nexport type Dictionaries = Record<\n  Locale,\n  () => Promise<{ default: Dictionary }>\n>\n"
  },
  {
    "path": "examples/swr-site/app/_dictionaries/ru.ts",
    "content": "import type { Dictionary } from './i18n-config'\n\nexport default {\n  dark: 'Темный',\n  light: 'Светлый',\n  system: 'Системный',\n  backToTop: 'Перейти наверх',\n  lastUpdated: 'Последнее обновление',\n  logo: {\n    title: 'React хуки для выборки данных'\n  },\n  // notFound: 'Эта страница не может быть найдена',\n  poweredBy: 'Работает на',\n  link: {\n    vercel: 'https://vercel.com/?utm_source=swr_ru'\n  },\n  lightweight: 'Лёгкий',\n  realtime: 'В реальном времени',\n  suspense: 'Задержка',\n  pagination: 'Пагинация',\n  backendAgnostic: 'Бэкэнд-независимый',\n  renderingStrategies: 'SSR / SSG',\n  typescript: 'TypeScript',\n  remoteLocal: 'Удалённо + Локально',\n  editPage: 'Редактировать на GitHub',\n  by: 'от'\n} satisfies Dictionary\n"
  },
  {
    "path": "examples/swr-site/app/_icons/index.ts",
    "content": "export { default as FeatherIcon } from './feather.svg?svgr'\nexport { default as LightningIcon } from './lightning.svg?svgr'\nexport { default as PauseIcon } from './pause.svg?svgr'\nexport { default as DotsVerticalIcon } from './dots-vertical.svg?svgr'\nexport { default as BoxIcon } from './box.svg?svgr'\nexport { default as LayersIcon } from './layers.svg?svgr'\nexport { default as PulseIcon } from './pulse.svg?svgr'\nexport { default as RainIcon } from './rain.svg?svgr'\nexport { default as SwrIcon } from './swr.svg?svgr'\nexport { default as VercelIcon } from './vercel.svg?svgr'\n\nexport { default as CacheImage } from './image.cache.svg?svgr'\nexport { default as InfiniteImage } from './image.infinite.svg?svgr'\nexport { default as PaginationImage } from './image.pagination.svg?svgr'\nexport { default as WelcomeImage } from './image.welcome.svg?svgr'\n"
  },
  {
    "path": "examples/swr-site/app/env.d.ts",
    "content": "declare module '*.mdx' {\n  import type { FC } from 'react'\n  import type { MDXComponents } from 'nextra/mdx-components'\n  const ReactComponent: FC<{\n    components?: MDXComponents\n  }>\n  export default ReactComponent\n}\n\ndeclare module '*.svg?svgr' {\n  import type { FC, SVGProps } from 'react'\n  const ReactComponent: FC<SVGProps<SVGElement>>\n\n  export default ReactComponent\n}\n"
  },
  {
    "path": "examples/swr-site/app/manifest.ts",
    "content": "import type { MetadataRoute } from 'next'\n\nexport default function manifest(): MetadataRoute.Manifest {\n  return {\n    name: 'SWR',\n    short_name: 'SWR',\n    icons: [\n      {\n        src: '/android-chrome-192x192.png',\n        sizes: '192x192',\n        type: 'image/png'\n      },\n      {\n        src: '/android-chrome-512x512.png',\n        sizes: '512x512',\n        type: 'image/png'\n      }\n    ],\n    theme_color: '#fff',\n    background_color: '#fff',\n    display: 'standalone'\n  }\n}\n"
  },
  {
    "path": "examples/swr-site/content/en/_meta.ts",
    "content": "export default {\n  index: {\n    type: 'page',\n    display: 'hidden',\n    theme: {\n      typesetting: 'article',\n      toc: false\n    }\n  },\n  docs: {\n    type: 'page',\n    title: 'Documentation'\n  },\n  about: {\n    type: 'menu',\n    title: 'About',\n    items: {\n      contributors: {\n        href: 'https://github.com/vercel/swr/graphs/contributors'\n      },\n      team: '',\n      acknowledgement: '',\n      'a-page': '',\n      changelog: ''\n    }\n  },\n  examples: {\n    type: 'page',\n    title: 'Examples',\n    theme: {\n      layout: 'full'\n    }\n  },\n  blog: {\n    type: 'page',\n    title: 'Blog',\n    theme: {\n      sidebar: false,\n      typesetting: 'article'\n    }\n  },\n  nextra_link: {\n    type: 'page',\n    title: 'Nextra',\n    href: 'https://github.com/shuding/nextra'\n  }\n}\n"
  },
  {
    "path": "examples/swr-site/content/en/about/_meta.ts",
    "content": "export default {\n  team: '👥 Team',\n  acknowledgement: '🧩 Acknowledgement',\n  'a-page': ''\n}\n"
  },
  {
    "path": "examples/swr-site/content/en/about/a-page.mdx",
    "content": "# This Is A Page\n"
  },
  {
    "path": "examples/swr-site/content/en/about/acknowledgement.mdx",
    "content": "# Acknowledgement\n"
  },
  {
    "path": "examples/swr-site/content/en/about/team.mdx",
    "content": "# Team\n\nSWR is made by the team behind Next.js.\n"
  },
  {
    "path": "examples/swr-site/content/en/blog/swr-v1.mdx",
    "content": "---\ntitle: Announcing SWR 1.0\nimage: https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\ndescription:\n  'Almost 2 years ago we open sourced SWR, the tiny data-fetching React library\n  that people love. Today we are reaching another milestone: the 1.0 version of\n  SWR!'\ndate: 2021-08-27\nauthors:\n  - name: Shu Ding\n    link: https://twitter.com/shuding_\n  - name: Jiachi Liu\n    link: https://twitter.com/huozhi\n---\n\nimport { TopContent } from '@app/_components/authors'\n\n<TopContent lang={props.params.lang} {...metadata} />\n\nAlmost 2 years ago we\n[open sourced](https://twitter.com/vercel/status/1188911002626097157) SWR, the\ntiny data-fetching React library that people love. Today we are reaching another\nmilestone: the 1.0 version of SWR!\n\n## What's New\n\n### Smaller Size\n\n[Performance](/docs/advanced/performance) is one of the most important features\nof SWR. In 1.0, we made the library significantly smaller **without removing any\nexisting features**:\n\n- 41% smaller core (24% smaller when gzipped, **3.9 kB**)\n- 52% smaller package install size\n- Improved tree-shaking\n\nThere are many reasons to make the library lightweight: your application will\nhave a smaller bundle, a leaner runtime, and a smaller `node_modules` directory.\n\nWe've also improved the bundling of the package, and it now supports path\nimports:\n\n```js\nimport useSWR from 'swr'\nimport useSWRInfinite from 'swr/infinite'\n```\n\nIf you are not using `useSWRInfinite`, it will not be included in your\napplication.\n\n### Fallback Data\n\nIn 1.0, there's a new `fallback` option that you can provide any pre-fetched\ndata as the initial value of all SWR hooks with specific keys:\n\n```jsx\n<SWRConfig\n  value={{\n    fallback: {\n      '/api/user': {\n        name: 'Bob'\n        // ...\n      },\n      '/api/items': {\n        // ...\n      }\n      // ...\n    }\n  }}\n>\n  <App />\n</SWRConfig>\n```\n\nThis is very helpful for scenarios such as SSG, SSR, and data mockup for\ntesting. Check the docs [Next.js SSG and SSR](/docs/with-nextjs) for more\ndetails.\n\nFor better consistency and to avoid confusion, the old `initialData` is now\nrenamed to `fallbackData`, which still provides a single fallback value for the\ngiven hook.\n\n### Immutable Mode\n\nSometimes you want to mark a resource as **immutable** if it will never change.\nIt's better to disable automatic revalidations for it and only make the request\nonce. There is now a helper hook to make this easier:\n\n```jsx\nimport useSWRImmutable from 'swr/immutable'\n\n// ...\n\nuseSWRImmutable(key, fetcher, options)\n```\n\nIt has the exact same API as the `useSWR` hook, but it will never revalidate\nupon tab focus or network recovery. There's also a new option,\n`revalidateIfStale`, you can use to control the behavior precisely. More\ninformation can be found\n[here](/docs/revalidation#disable-automatic-revalidations).\n\n### Custom Cache Provider\n\nBy default, SWR uses a single global cache to store all the data. In 1.0, you\nare able to customize it with the new `provider` option:\n\n```jsx\n<SWRConfig\n  value={{\n    provider: () => myCache\n  }}\n>\n  <App />\n</SWRConfig>\n```\n\nYou can use this new feature to do many powerful things. We have a couple of\nexamples here:\n[_Mutate Multiple Keys with RegEx_](/docs/advanced/cache#mutate-multiple-keys-from-regex),\n[_LocalStorage Based Persistent Cache_](/docs/advanced/cache#localstorage-based-persistent-cache),\n[_Reset Cache Between Tests_](/docs/advanced/cache#reset-cache-between-test-cases).\n\nThis new cache provider API is also more compatible with concurrent rendering of\nReact 18. If you are adding a cache provider, make sure to use the global\n`mutate` function returned from `useSWRConfig()`.\n\nYou can read the docs [Cache Provider](/docs/advanced/cache) for more details.\n\n### useSWRConfig()\n\nThere is a new Hook API to return all global configurations, including the\ncurrent cache provider and global `mutate` function:\n\n```jsx\nimport { useSWRConfig } from 'swr'\n\nfunction Foo() {\n  const { refreshInterval, cache, mutate, ...restConfig } = useSWRConfig()\n\n  // ...\n}\n```\n\nMore information can be found\n[here](/docs/global-configuration#access-to-global-configurations).\n\n### Middleware\n\nSWR Middlewares provide a new way for you to build and reuse abstractions on top\nof SWR hooks:\n\n```jsx\n<SWRConfig value={{ use: [...middleware] }}>\n\n// ... or directly in `useSWR`:\nuseSWR(key, fetcher, { use: [...middleware] })\n```\n\nA lot of new ideas can be implemented with this feature, and we've built some\nexamples: [_Request Logger_](/docs/middleware#request-logger),\n[_Keep Previous Data When Changing the Key_](/docs/middleware#keep-previous-result),\nand [_Serialize Object Keys_](/docs/middleware#serialize-object-keys).\n\nCheck the [Middleware API](/docs/middleware) for more details.\n\n### Improvements and Better Test Coverage\n\nSince 0.x, we've made hundreds of small improvements and bugfixes. SWR now has\n157 tests that cover most of the edge cases in data fetching. Read the\n[Changelog](https://github.com/vercel/swr/releases) for more details.\n\n### Docs Translations\n\nThanks to our\n[contributors](https://github.com/vercel/swr-site/graphs/contributors) and\nNextra's [i18n feature](https://nextra.site/docs/guide/i18n), we now offer SWR\ndocumentation in six different languages:\n\n- [English](https://swr.vercel.app)\n- [Spanish](https://swr.vercel.app/es-ES)\n- [Simplified Chinese](https://swr.vercel.app/zh-CN)\n- [Japanese](https://swr.vercel.app/ja)\n- [Korean](https://swr.vercel.app/ko)\n- [Russian](https://swr.vercel.app/ru)\n\n## Migration Guide\n\n### Update `useSWRInfinite` Imports\n\n`useSWRInfinite` needs to be imported from `swr/infinite`:\n\n```diff\n- import { useSWRInfinite } from 'swr'\n+ import useSWRInfinite from 'swr/infinite'\n```\n\nIf you are using the corresponding types, update the import path too:\n\n```diff\n- import { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr'\n+ import { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr/infinite'\n```\n\n### Change `revalidate` to `mutate`\n\n`useSWR` no longer returns the `revalidate` method, change to `mutate` instead:\n\n```diff\n- const { revalidate } = useSWR(key, fetcher, options)\n+ const { mutate } = useSWR(key, fetcher, options)\n\n\n  // ...\n\n\n- revalidate()\n+ mutate()\n```\n\n### Rename `initialData` to `fallbackData`\n\n```diff\n- useSWR(key, fetcher, { initialData: ... })\n+ useSWR(key, fetcher, { fallbackData: ... })\n```\n\n### No More Default Fetcher\n\nSWR no longer provides the default fetcher (a `fetch` call that parses the data\nas JSON). The easiest way to migrate the change is to use the `<SWRConfig>`\ncomponent:\n\n```jsx\n;<SWRConfig value={{ fetcher: url => fetch(url).then(res => res.json()) }}>\n  <App />\n</SWRConfig>\n\n// ... or\nuseSWR(key, url => fetch(url).then(res => res.json()))\n```\n\n### Recommend to Use the Hook-Returned `mutate`\n\nThis is **not** a breaking change, but we will now _recommend_ to always use the\n`mutate` returned from the `useSWRConfig` hook:\n\n```diff\n- import { mutate } from 'swr'\n+ import { useSWRConfig } from 'swr'\n\n\n  function Foo () {\n+   const { mutate } = useSWRConfig()\n\n    return <button onClick={() => mutate('key')}>\n      Mutate Key\n    </button>\n  }\n```\n\nIf you are not using a cache provider, the current global import\n`import { mutate } from 'swr'` still works.\n\n### Renamed Types\n\nIf you are using TypeScript, the following type names have been changed for\nconsistency:\n\n| 0.x (deprecated)               | 1.0                        | Note                    |\n| ------------------------------ | -------------------------- | ----------------------- |\n| `ConfigInterface`              | `SWRConfiguration`         |                         |\n| `keyInterface`                 | `Key`                      |                         |\n| `responseInterface`            | `SWRResponse`              |                         |\n| `RevalidateOptionInterface`    | `RevalidatorOptions`       |                         |\n| `revalidateType`               | `Revalidator`              |                         |\n| `SWRInfiniteResponseInterface` | `SWRInfiniteResponse`      | moved to `swr/infinite` |\n| `SWRInfiniteConfigInterface`   | `SWRInfiniteConfiguration` | moved to `swr/infinite` |\n\n### Beta and Unofficial Feature Users\n\nIf you are using a beta version of SWR, or using any undocumented APIs, please\nbe aware of the following changes:\n\n- `import { cache } from 'swr'` is removed; use the new\n  [`useSWRConfig` API](#useswrconfig) instead.\n- `import { createCache } from 'swr'` is removed; use the new\n  [Cache Provider API](/docs/advanced/cache) instead.\n- `revalidateWhenStale` is renamed to `revalidateIfStale`.\n- `middlewares` is renamed to `use`.\n\n### Changelog\n\nRead the full Changelog [on GitHub](https://github.com/vercel/swr/releases).\n\n## What's Next\n\nIn future releases, we will keep improving the library while maintaining the\nstability. We are also aiming to embrace future React versions, as several new\nfeatures and improvements in 1.0 are already preparing for that. In addition, we\nare also working on new features to improve the experience of doing data\nfetching in React and the experience of using this library.\n\nIf you have any feedback about this release, please\n[let us know](https://github.com/vercel/swr/discussions).\n\n## Thank You!\n\nSpecial thanks to [Toru Kobayashi](https://twitter.com/koba04) and\n[Yixuan Xu](https://twitter.com/yixuanxu94) for their contributions to the\nlibrary, and [Paco Coursey](https://twitter.com/pacocoursey),\n[uttk](https://github.com/uttk), [Tomohiro SHIOYA](https://github.com/shioyang),\n[Markoz Peña](https://github.com/markozxuu),\n[SeulGi Choi](https://github.com/cs09g),\n[Fang Lu](https://github.com/huzhengen),\n[Valentin Politov](https://github.com/valentinpolitov) for their work on the\ntranslations and docs. This release can't happen without them.\n\nWe also want to thank the entire community, our\n[110 contributors](https://github.com/vercel/swr/graphs/contributors) (+\n[45 docs contributors](https://github.com/vercel/swr-site/graphs/contributors)),\nand everyone who helped and gave us feedback!\n"
  },
  {
    "path": "examples/swr-site/content/en/blog.mdx",
    "content": "---\nsearchable: false\n---\n\nimport { Blog } from '@app/_components/blog'\n\n# SWR Blog\n\n<Blog lang={props.params.lang} />\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/_meta.tsx",
    "content": "import { SwrIcon } from '@app/_icons'\nimport type { FC, ReactNode } from 'react'\n\nexport const Separator: FC<{ children: ReactNode }> = ({ children }) => {\n  return (\n    <div className=\"flex items-center gap-2\">\n      <SwrIcon height=\"6\" className=\"shrink-0\" />\n      {children}\n    </div>\n  )\n}\n\nexport default {\n  _: {\n    title: <Separator>Getting Started</Separator>,\n    type: 'separator'\n  },\n  'getting-started': '',\n  options: '',\n  'global-configuration': '',\n  'data-fetching': '',\n  'error-handling': {\n    display: 'hidden'\n  },\n  revalidation: 'Auto Revalidation',\n  'conditional-fetching': 'Conditional Data Fetching',\n  arguments: '',\n  mutation: '',\n  pagination: '',\n  _2: {\n    title: <Separator>Advanced</Separator>,\n    type: 'separator'\n  },\n  prefetching: '',\n  'with-nextjs': 'Next.js SSG and SSR',\n  typescript: 'TypeScript :)',\n  suspense: '',\n  middleware: '',\n  advanced: '',\n  'change-log': {\n    theme: {\n      sidebar: false\n    }\n  },\n  github_link: {\n    title: 'GitHub 🐙',\n    href: 'https://github.com/shuding/nextra'\n  },\n  'wrap-toc-items': 'Wrap Table of Content Items',\n  'custom-header-ids': 'Custom Header IDs'\n}\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/_meta.tsx",
    "content": "import { Separator } from '../_meta'\n\nexport default {\n  '*': {\n    theme: {\n      footer: false\n    }\n  },\n  '--- yoo': {\n    title: <Separator>Do Not Use</Separator>,\n    type: 'separator'\n  },\n  more: 'More: A Super Super Super Super Long Directory',\n  'file-name.with.DOTS': 'Filenames with Dots'\n}\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/cache.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Cache\n\n<Callout>Upgrade to the latest version (≥ 1.0.0) to use this feature.</Callout>\n\n<Callout type=\"warning\">\n  In most cases, you shouldn't directly _write_ to the cache, which might cause\n  undefined behaviors of SWR. If you need to manually mutate a key, please\n  consider using the SWR APIs.\n\nSee also: [Mutation](/docs/mutation),\n[Reset Cache Between Test Cases](#reset-cache-between-test-cases).\n\n</Callout>\n\nBy default, SWR uses a global cache to store and share data across all\ncomponents. But you can also customize this behavior with the `provider` option\nof `SWRConfig`.\n\nCache providers are intended to enable SWR with more customized storages.\n\n## Cache Provider\n\nA cache provider is Map-like object which matches the following TypeScript\ndefinition (which can be imported from `swr`):\n\n```typescript\ninterface Cache<Data> {\n  get(key: string): Data | undefined\n  set(key: string, value: Data): void\n  delete(key: string): void\n}\n```\n\nFor example, a\n[JavaScript Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)\ninstance can be directly used as the cache provider for SWR.\n\n## Create Cache Provider\n\nThe `provider` option of `SWRConfig` receives a function that returns a\n[cache provider](#cache-provider). The provider will then be used by all SWR\nhooks inside that `SWRConfig` boundary. For example:\n\n```jsx\nimport useSWR, { SWRConfig } from 'swr'\n\nfunction App() {\n  return (\n    <SWRConfig value={{ provider: () => new Map() }}>\n      <Page />\n    </SWRConfig>\n  )\n}\n```\n\nAll SWR hooks inside `<Page>` will read and write from that Map instance. You\ncan also use other cache provider implementations as well for your specific use\ncase.\n\n<Callout>\n  In the example above, when the `<App>` component is re-mounted, the provider\n  will also be re-created. Cache providers should be put higher in the component\n  tree, or outside of render.\n</Callout>\n\nimport { CacheImage } from '@app/_icons'\n\n<CacheImage className=\"mt-6 dark:invert\" />\n\nWhen nested, SWR hooks will use the upper-level cache provider. If there is no\nupper-level cache provider, it fallbacks to the default cache provider, which is\nan empty `Map`.\n\n<Callout type=\"warning\">\n   If a cache provider is used, the global `mutate` will **not** work for SWR hooks under that `<SWRConfig>` boundary. Please use [this](#access-current-cache-provider) instead.\n</Callout>\n\n## Access Current Cache Provider\n\nWhen inside a React component, you need to use the\n[`useSWRConfig`](/docs/global-configuration#access-to-global-configurations)\nhook to get access to the current cache provider as well as other configurations\nincluding `mutate`:\n\n```jsx\nimport { useSWRConfig } from 'swr'\n\nfunction Avatar() {\n  const { cache, mutate, ...extraConfig } = useSWRConfig()\n  // ...\n}\n```\n\nIf it's not under any `<SWRConfig>`, it will return the default configurations.\n\n## Experimental: Extend Cache Provider\n\n<Callout emoji=\"🧪\">\n  This is an experimental feature, the behavior might change in future upgrades.\n</Callout>\n\nWhen multiple `<SWRConfig>` components are nested, cache provider can be\nextended.\n\nThe first argument for the `provider` function is the cache provider of the\nupper-level `<SWRConfig>` (or the default cache if there's no parent\n`<SWRConfig>`), you can use it to extend the cache provider:\n\n```jsx\n<SWRConfig value={{ provider: cache => newCache }}>...</SWRConfig>\n```\n\n## Examples\n\n### Mutate Multiple Keys from RegEx\n\nWith the flexibility of the cache provider API, you can even build a \"partial\nmutation\" helper.\n\nIn the example below, `matchMutate` can receive a regex expression as key, and\nbe used to mutate the ones who matched this pattern.\n\n```js\nfunction useMatchMutate() {\n  const { cache, mutate } = useSWRConfig()\n  return (matcher, ...args) => {\n    if (!(cache instanceof Map)) {\n      throw new Error(\n        'matchMutate requires the cache provider to be a Map instance'\n      )\n    }\n\n    const keys = []\n\n    for (const key of cache.keys()) {\n      if (matcher.test(key)) {\n        keys.push(key)\n      }\n    }\n\n    const mutations = keys.map(key => mutate(key, ...args))\n    return Promise.all(mutations)\n  }\n}\n```\n\nThen inside your component:\n\n```jsx\nfunction Button() {\n  const matchMutate = useMatchMutate()\n  return (\n    <button onClick={() => matchMutate(/^\\/api\\//)}>\n      Revalidate all keys start with \"/api/\"\n    </button>\n  )\n}\n```\n\n<Callout>\n  Note that this example requires the cache provider to be a Map instance.\n</Callout>\n\n### LocalStorage Based Persistent Cache\n\nYou might want to sync your cache to `localStorage`. Here's an example\nimplementation:\n\n```jsx\nfunction localStorageProvider() {\n  // When initializing, we restore the data from `localStorage` into a map.\n  const map = new Map(JSON.parse(localStorage.getItem('app-cache') || '[]'))\n\n  // Before unloading the app, we write back all the data into `localStorage`.\n  window.addEventListener('beforeunload', () => {\n    const appCache = JSON.stringify(Array.from(map.entries()))\n    localStorage.setItem('app-cache', appCache)\n  })\n\n  // We still use the map for write & read for performance.\n  return map\n}\n```\n\nThen use it as a provider:\n\n```jsx\n<SWRConfig value={{ provider: localStorageProvider }}>\n  <App />\n</SWRConfig>\n```\n\n<Callout>\n  As an improvement, you can also use the memory cache as a buffer, and write to\n  `localStorage` periodically. You can also implement a similar layered cache\n  with IndexedDB or WebSQL.\n</Callout>\n\n### Reset Cache Between Test Cases\n\nWhen testing your application, you might want to reset the SWR cache between\ntest cases. You can simply wrap your application with an empty cache provider.\nHere's an example with Jest:\n\n```jsx\ndescribe('test suite', async () => {\n  it('test case', async () => {\n    render(\n      <SWRConfig value={{ provider: () => new Map() }}>\n        <App />\n      </SWRConfig>\n    )\n  })\n})\n```\n\n### Access to the Cache\n\nAlert: you should not write to the cache directly, it might cause undefined\nbehavior.\n\n```jsx\nconst { cache } = useSWRConfig()\n\ncache.get(key) // Get the current data for a key.\ncache.clear() // ⚠️ Clear all the cache. SWR will revalidate upon re-render.\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/code-highlighting.mdx",
    "content": "# Code highlighting\n\n## Test `filename`, line highlighting and empty lines\n\n```js filename=\"test.js\" {1}\nconsole.log('hello world')\n\nconsole.log('goodbye world')\n```\n\n## Test `showLineNumbers` and word highlighting\n\n```scala showLineNumbers {2-4} /println/\nobject Hello {\n  def main(args: Array[String]) = {\n    println(\"hello, world\")\n  }\n}\n\nobject Hello {\n  def main(args: Array[String]) = {\n    println(\"hello, world\")\n  }\n}\n```\n\n## Test highlighting inline code\n\n`import React from 'react'{:js}`\n\n## Test without specified language\n\n```text /hello/\nhello world\n```\n\n## Test link in code\n\nLink to [`google`](https://google.com)\n\nLink to [GitHub](https://github.com)\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/dynamic-markdown-import.mdx",
    "content": "import { ExampleDynamicMarkdownImport } from '@app/_components/example-dynamic-markdown-import.tsx'\n\n# Dynamic Markdown Import!\n\n<ExampleDynamicMarkdownImport />\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/file-name.with.DOTS.mdx",
    "content": "# You can add dots in your file names\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/images.mdx",
    "content": "## SVG\n\n![SWR logo transparent](../../../../app/icon.svg)\n\n## Link Definition\n\n![SWR logo][link-def]\n\n[link-def]: /favicon/android-chrome-192x192.png\n\n## Absolute Import\n\n![SWR logo](/favicon/android-chrome-192x192.png)\n\n## Relative Import\n\n![SWR logo](../../../../public/favicon/android-chrome-192x192.png)\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/markdown-import.mdx",
    "content": "import External from '@app/_components/external.mdx'\n\n# Markdown import\n\n## Import of markdown file\n\n```mdx\nimport External from '@app/_components/external.mdx'\n\n<External />\n```\n\n<External />\n\n## Import of another page\n\nYou can also import complete pages:\n\n```mdx filename=\"not-index.md\"\nimport IndexPage from '../../index.mdx'\n\n<IndexPage params={props.params} />\n```\n\nimport IndexPage from '../../index.mdx'\n\n<IndexPage params={props.params} />\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/more/loooooooooooooooooooong-title.mdx",
    "content": "# loooooooooooooooooooong-title\n\n## loooooooooooooooooooong Heading 2\n\n### loooooooooooooooooooong Heading 3\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/more/tree/one.mdx",
    "content": "# One\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/more/tree/three.mdx",
    "content": "# Three\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/more/tree/two.mdx",
    "content": "# Two\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/performance.mdx",
    "content": "# Performance\n\nSWR provides critical functionality in all kinds of web apps, so **performance**\nis a top priority.\n\nSWR's built-in **caching** and **[deduplication](#deduplication)** skips\nunnecessary network requests, but the performance of the `useSWR` hook itself\nstill matters. In a complex app, there could be hundreds of `useSWR` calls in a\nsingle page render.\n\nSWR ensures that your app has:\n\n- _no unnecessary requests_\n- _no unnecessary re-renders_\n- _no unnecessary code imported_\n\nwithout any code changes from you.\n\n## Deduplication\n\nIt's very common to reuse SWR hooks in your app. For example, an app that\nrenders the current user's avatar 5 times:\n\n```jsx\nfunction useUser() {\n  return useSWR('/api/user', fetcher)\n}\n\nfunction Avatar() {\n  const { data, error } = useUser()\n\n  if (error) return <Error />\n  if (!data) return <Spinner />\n\n  return <img src={data.avatar_url} />\n}\n\nfunction App() {\n  return (\n    <>\n      <Avatar />\n      <Avatar />\n      <Avatar />\n      <Avatar />\n      <Avatar />\n    </>\n  )\n}\n```\n\nEach `<Avatar>` component has a `useSWR` hook inside. Since they have the same\nSWR key and are rendered at the almost same time, **only 1 network request will\nbe made**.\n\nYou can reuse your data hooks (like `useUser` in the example above) everywhere,\nwithout worrying about performance or duplicated requests.\n\nThere is also a [`dedupingInterval` option](/docs/options) for overriding the\ndefault deduplication interval.\n\n## Deep Comparison\n\nSWR **deep compares** data changes by default. If the `data` value isn't\nchanged, a re-render will not be triggered.\n\nYou can also customize the comparison function via the\n[`compare` option](/docs/options) if you want to change the behavior. For\nexample, some API responses return a server timestamp that you might want to\nexclude from the data diff.\n\n## Dependency Collection\n\n`useSWR` returns 3 **stateful** values: `data`, `error` and `isValidating`, each\none can be updated independently. For example, if we print those values within a\nfull data-fetching lifecycle, it will be something like this:\n\n```jsx\nfunction App() {\n  const { data, error, isValidating } = useSWR('/api', fetcher)\n  console.log(data, error, isValidating)\n  return null\n}\n```\n\nIn the worst case (the first request failed, then the retry was successful), you\nwill see 4 lines of logs:\n\n```js\n// console.log(data, error, isValidating)\nundefined undefined true  // => start fetching\nundefined Error false     // => end fetching, got an error\nundefined Error true      // => start retrying\nData undefined false      // => end retrying, get the data\n```\n\nThe state changes make sense. But that also means our component **rendered 4\ntimes**.\n\nIf we change our component to only use `data`:\n\n```jsx\nfunction App() {\n  const { data } = useSWR('/api', fetcher)\n  console.log(data)\n  return null\n}\n```\n\nThe magic happens — there are only **2 re-renders** now:\n\n```js\n// console.log(data)\nundefined // => hydration / initial render\nData // => end retrying, get the data\n```\n\nThe exact same process has happened internally, there was an error from the\nfirst request, then we got the data from the retry. However, **SWR only updates\nthe states that are used by the component**, which is only `data` now.\n\nIf you are not always using all these 3 states, you are already benefitting from\nthis feature. At [Vercel](https://vercel.com), this optimization results in ~60%\nfewer re-renders.\n\n## Tree Shaking\n\nThe SWR package is [tree-shakeable](https://webpack.js.org/guides/tree-shaking)\nand side-effect free. That means if you are only importing the core `useSWR`\nAPI, unused APIs like `useSWRInfinite` won't be bundled in your application.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/react-native.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# React Native\n\n<Callout>\n  Upgrade to the latest version (≥ 1.0.0) to experience this customization.\n</Callout>\n\nUnlike React running inside the browsers, React Native has a very different user\nexperience. For example there is no \"tab focus\", switching from the background\nto the app is considered as a \"focus\" instead. To customize these behaviors, you\ncan replace the default browser `focus` and `online` events listeners with React\nNative's app state detection and other native ported API, and configure SWR to\nuse them.\n\n## Example\n\n### Global Setup\n\nYou can wrap your app under `SWRConfig` and preconfig all configurations there\n\n```jsx\n<SWRConfig\n  value={{\n    // ...\n  }}\n>\n  <App>\n</SWRConfig>\n```\n\n### Customize `focus` and `reconnect` Events\n\nThere're few configurations you need to take care of such as `isOnline`,\n`isVisible`, `initFocus` and `initReconnect`.\n\n`isOnline` and `isVisible` are functions that return a boolean, to determine if\nthe application is \"active\". By default, SWR will bail out a revalidation if\nthese conditions are not met.\n\nWhen using `initFocus` and `initReconnect`, it's required to also set up a\n[custom cache provider](/docs/advanced/cache). You can use an empty `Map()` or\nany storage you prefer.\n\n```jsx\n<SWRConfig\n  value={{\n    provider: () => new Map(),\n    isOnline() {\n      /* Customize the network state detector */\n      return true\n    },\n    isVisible() {\n      /* Customize the visibility state detector */\n      return true\n    },\n    initFocus(callback) {\n      /* Register the listener with your state provider */\n    },\n    initReconnect(callback) {\n      /* Register the listener with your state provider */\n    }\n  }}\n>\n  <App />\n</SWRConfig>\n```\n\nLet's take `initFocus` as example:\n\n```jsx\nimport { AppState } from 'react-native'\n\n// ...\n\n<SWRConfig\n  value={{\n    provider: () => new Map(),\n    isVisible: () => { return true },\n    initFocus(callback) {\n      let appState = AppState.currentState\n\n      const onAppStateChange = (nextAppState) => {\n        /* If it's resuming from background or inactive mode to active one */\n        if (appState.match(/inactive|background/) && nextAppState === 'active') {\n          callback()\n        }\n        appState = nextAppState\n      }\n\n      // Subscribe to the app state change events\n      const subscription = AppState.addEventListener('change', onAppStateChange)\n\n      return () => {\n        subscription.remove()\n      }\n    }\n  }}\n>\n  <App>\n</SWRConfig>\n```\n\nFor `initReconnect`, it requires some 3rd party libraries such as\n[NetInfo](https://github.com/react-native-netinfo/react-native-netinfo) to\nsubscribe to the network status. The implementation will be similar to the\nexample above: receiving a `callback` function and trigger it when the network\nrecovers from offline, so SWR can start a revalidation to keep your data\nup-to-date.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced/scrollbar-x.mdx",
    "content": "import { Tabs } from 'nextra/components'\n\n| **Student ID** | **First Name** | **Last Name** | **Major**         | **GPA** | **Graduation Year** | **Email**                    | **Phone Number** | **Address**               | **Date of Birth** | **Gender** | **Class Standing** | **Enrollment Status** | **Enrollment Date** | **Graduation Date** | **Advisor ID** |\n| :------------- | :------------- | :------------ | :---------------- | :------ | :------------------ | :--------------------------- | :--------------- | :------------------------ | :---------------- | :--------- | :----------------- | :-------------------- | :------------------ | :------------------ | :------------- |\n| 12345          | John           | Doe           | Computer Science  | 3.5     | 2024                | johndoe@example.com          | 555-555-5555     | 123 Main St, Anytown USA  | 01/01/2000        | M          | Junior             | Full-time             | 01/01/2022          | 05/01/2024          | 54321          |\n| 67890          | Jane           | Smith         | Biology           | 3.2     | 2023                | janesmith@example.com        | 555-555-5555     | 456 Park Ave, Anytown USA | 02/02/1999        | F          | Senior             | Full-time             | 01/01/2019          | 12/01/2022          | 56789          |\n| 11111          | Bob            | Johnson       | Mathematics       | 3.7     | 2022                | bobjohnson@example.com       | 555-555-5555     | 789 Elm St, Anytown USA   | 03/03/1998        | M          | Senior             | Part-time             | 01/01/2021          | 05/01/2022          | 98765          |\n| 22222          | Samantha       | Williams      | Chemistry         | 3.3     | 2024                | samanthawilliams@example.com | 555-555-5555     | 321 Oak St, Anytown USA   | 04/04/1997        | F          | Junior             | Full-time             | 01/01/2022          | 05/01/2024          | 54321          |\n| 33333          | Michael        | Brown         | Political Science | 3.0     | 2023                | michaelbrown@example.com     | 555-555-5555     | 159 Pine St, Anytown USA  | 05/05/1996        | M          | Senior             | Full-time             | 01/01/2019          | 12/01/2022          | 56789          |\n| 44444          | Ashley         | Moore         | Business          | 3.5     | 2022                | ashleymoore@example.com      | 555-555-5555     | 753 Birch St, Anytown USA | 06/06/1995        | F          | Senior             | Part-time             | 01/01/2021          | 05/01/2022          | 98765          |\n| 55555          | David          | Taylor        | Engineering       | 3.9     | 2024                | davidtaylor@example.com      | 555-555-5555     | 964 Maple St, Anytown USA | 07/07/1994        | M          | Junior             | Full-time             | 01/01/2022          | 05/01/2024          | 54321          |\n| 77777          | Jessica        | Anderson      | Communications    | 3.6     | 2023                | jessicaanderson@example.com  | 555-555-5555     | 111 Cedar St, Anytown USA | 08/08/1993        | F          | Senior             | Full-time             | 01/01/2019          | 12/01/2022          | 56789          |\n\n<Tabs\n  items={[\n    'name',\n    'version',\n    'private',\n    'dependencies',\n    'scripts',\n    'eslintConfig',\n    'browserslist',\n    'development',\n    'name',\n    'version',\n    'private'\n  ]}\n>\n  <Tabs.Tab className=\"bg-red-500\">dada</Tabs.Tab>\n  <Tabs.Tab>dadasd</Tabs.Tab>\n</Tabs>\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/advanced.mdx",
    "content": "---\nasIndexPage: true\n---\n\n# Advanced features!\n\nYou can create this index page now!\n\n<details>\n  <summary>**Version History**</summary>\n\n| Version   | Changes                                                             |\n| --------- | ------------------------------------------------------------------- |\n| `v10.0.0` | `locale`, `locales`, `defaultLocale`, and `notFound` options added. |\n| `v9.3.0`  | `getServerSideProps` introduced.                                    |\n\n  <details open>\n    <summary>**Second Level Details**</summary>\n\n    Hello!\n\n  </details>\n\n  <details>\n    <summary>Second _Level_ Details</summary>\n\n    Hello!\n\n  </details>\n</details>\n\nhey!!\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/arguments.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Arguments\n\nBy default, `key` will be passed to `fetcher` as the argument. So the following\n3 expressions are equivalent:\n\n```js\nuseSWR('/api/user', () => fetcher('/api/user'))\nuseSWR('/api/user', url => fetcher(url))\nuseSWR('/api/user', fetcher)\n```\n\n## Multiple Arguments\n\nIn some scenarios, it's useful to pass multiple arguments (can be any value or\nobject) to the `fetcher` function. For example an authorized fetch request:\n\n```js\nuseSWR('/api/user', url => fetchWithToken(url, token))\n```\n\nThis is **incorrect**. Because the identifier (also the cache key) of the data\nis `'/api/user'`, even if `token` changes, SWR will still use the same key and\nreturn the wrong data.\n\nInstead, you can use an **array** as the `key` parameter, which contains\nmultiple arguments of `fetcher`:\n\n```js\nconst { data: user } = useSWR(['/api/user', token], fetchWithToken)\n```\n\nThe function `fetchWithToken` still accepts the same 2 arguments, but the cache\nkey will also be associated with `token` now.\n\n## Passing Objects\n\n<Callout>\n  Since SWR 1.1.0, object-like keys will be serialized under the hood\n  automatically.\n</Callout>\n\nSay you have another function that fetches data with a user scope:\n`fetchWithUser(api, user)`. You can do the following:\n\n```js\nconst { data: user } = useSWR(['/api/user', token], fetchWithToken)\n\n// ...and then pass it as an argument to another useSWR hook\nconst { data: orders } = useSWR(\n  user ? ['/api/orders', user] : null,\n  fetchWithUser\n)\n```\n\nYou can directly pass an object as the key, and `fetcher` will receive that\nobject too:\n\n```js\nconst { data: orders } = useSWR({ url: '/api/orders', args: user }, fetcher)\n```\n\n<Callout type=\"warning\">\n  In older versions (< 1.1.0), SWR **shallowly** compares the arguments on every render, and triggers revalidation if any of them has changed.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/callout.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Callout Component\n\n<Callout>\n  `<Callout>…`\n</Callout>\n\n<Callout type=\"info\">\n  `<Callout type=\"info\">…`\n</Callout>\n\n<Callout type=\"warning\">\n  `<Callout type=\"warning\">…`\n</Callout>\n\n<Callout type=\"error\">\n  `<Callout type=\"error\">…`\n</Callout>\n\n<Callout type=\"info\" emoji=\"🇫🇷\">\n  `<Callout type=\"info\" emoji=\"🇫🇷\">…`\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/change-log.mdx",
    "content": "# Change Log\n\nThis page should not have the sidebar because it has\n\n```json\n\"theme\": {\n  \"sidebar\": false\n}\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/code-block-without-language.mdx",
    "content": "# Code blocks without language have `Copy Code` button\n\n```\nhello world\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/conditional-fetching.md",
    "content": "# Conditional Fetching\n\n## Conditional\n\nUse `null` or pass a function as `key` to conditionally fetch data. If the\nfunction throws or returns a falsy value, SWR will not start the request.\n\n```js\n// conditionally fetch\nconst { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)\n\n// ...or return a falsy value\nconst { data } = useSWR(() => (shouldFetch ? '/api/data' : null), fetcher)\n\n// ...or throw an error when user.id is not defined\nconst { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)\n```\n\n## Dependent\n\nSWR also allows you to fetch data that depends on other data. It ensures the\nmaximum possible parallelism (avoiding waterfalls), as well as serial fetching\nwhen a piece of dynamic data is required for the next data fetch to happen.\n\n```js\nfunction MyProjects() {\n  const { data: user } = useSWR('/api/user')\n  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)\n  // When passing a function, SWR will use the return\n  // value as `key`. If the function throws or returns\n  // falsy, SWR will know that some dependencies are not\n  // ready. In this case `user.id` throws when `user`\n  // isn't loaded.\n\n  if (!projects) return 'loading...'\n  return 'You have ' + projects.length + ' projects'\n}\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/custom-header-ids.mdx",
    "content": "# Custom Header Ids\n\nYou can specify custom header ids using the format, `## Header [#custom-id]`.\nFor example:\n\n```markdown\n## Foo [#bar]\n```\n\n## This Has a Custom Id [#custom-id-example]\n\nYou can see the custom header id in the header above. Note both by hovering over\nthe header, as well as in the table of contents, the `custom-id-example` href is\nin use.\n\n## This Has No Custom Id\n\nThis header has no custom id. The id is generated from the header text.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/data-fetching.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Data Fetching\n\n```js\nconst { data, error } = useSWR(key, fetcher)\n```\n\nThis is the very fundamental API of SWR. The `fetcher` here is an async function\nthat **accepts the `key`** of SWR, and returns the data.\n\nThe returned value will be passed as `data`, and if it throws, it will be caught\nas `error`.\n\n<Callout>\n  Note that `fetcher` can be omitted from the parameters if it's [provided\n  globally](/docs/global-configuration).\n</Callout>\n\n## Fetch\n\nYou can use any library to handle data fetching, for example a `fetch` polyfill\n[developit/unfetch](https://github.com/developit/unfetch):\n\n```js\nimport fetch from 'unfetch'\n\nconst fetcher = url => fetch(url).then(r => r.json())\n\nfunction App() {\n  const { data, error } = useSWR('/api/data', fetcher)\n  // ...\n}\n```\n\n<Callout>\n  If you are using **Next.js**, you don't need to import this\n  polyfill:\n\n[New Built-In Polyfills: fetch(), URL, and Object.assign](https://nextjs.org/blog/next-9-1-7#new-built-in-polyfills-fetch-url-and-objectassign)\n\n</Callout>\n\n## Axios\n\n```js\nimport axios from 'axios'\n\nconst fetcher = url => axios.get(url).then(res => res.data)\n\nfunction App() {\n  const { data, error } = useSWR('/api/data', fetcher)\n  // ...\n}\n```\n\n## GraphQL\n\nOr using GraphQL with libs like\n[graphql-request](https://github.com/prisma-labs/graphql-request):\n\n```js\nimport { request } from 'graphql-request'\n\nconst fetcher = query => request('/api/graphql', query)\n\nfunction App() {\n  const { data, error } = useSWR(\n    /* GraphQL */ `\n      {\n        Movie(title: \"Inception\") {\n          releaseDate\n          actors {\n            name\n          }\n        }\n      }\n    `,\n    fetcher\n  )\n  // ...\n}\n```\n\n_If you want to pass variables to a GraphQL query, check out\n[Multiple Arguments](/docs/arguments)._\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/error-handling.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Error Handling\n\nIf an error is thrown inside [`fetcher`](/docs/data-fetching), it will be\nreturned as `error` by the hook.\n\n```js\nconst fetcher = url => fetch(url).then(r => r.json())\n\n// ...\nconst { data, error } = useSWR('/api/user', fetcher)\n```\n\nThe `error` object will be defined if the fetch promise is rejected.\n\n## Status Code and Error Object\n\nSometimes we want an API to return an error object alongside the status code.\nBoth of them are useful for the client.\n\nWe can customize our `fetcher` to return more information. If the status code is\nnot `2xx`, we consider it an error even if it can be parsed as JSON:\n\n```js\nconst fetcher = async url => {\n  const res = await fetch(url)\n\n  // If the status code is not in the range 200-299,\n  // we still try to parse and throw it.\n  if (!res.ok) {\n    const error = new Error('An error occurred while fetching the data.')\n    // Attach extra info to the error object.\n    error.info = await res.json()\n    error.status = res.status\n    throw error\n  }\n\n  return res.json()\n}\n\n// ...\nconst { data, error } = useSWR('/api/user', fetcher)\n// error.info === {\n//   message: \"You are not authorized to access this resource.\",\n//   documentation_url: \"...\"\n// }\n// error.status === 403\n```\n\n<Callout>\n  Note that `data` and `error` can exist at the same time. So the UI can display\n  the existing data, while knowing the upcoming request has failed.\n</Callout>\n\n[Here](/examples/error-handling) we have an example.\n\n## Error Retry\n\nSWR uses the\n[exponential backoff algorithm](https://en.wikipedia.org/wiki/Exponential_backoff)\nto retry the request on error. The algorithm allows the app to recover from\nerrors quickly, but not waste resources retrying too often.\n\nYou can also override this behavior via the\n[onErrorRetry](/docs/options#options) option:\n\n```js\nuseSWR('/api/user', fetcher, {\n  onErrorRetry: (error, key, config, revalidate, { retryCount }) => {\n    // Never retry on 404.\n    if (error.status === 404) return\n\n    // Never retry for a specific key.\n    if (key === '/api/user') return\n\n    // Only retry up to 10 times.\n    if (retryCount >= 10) return\n\n    // Retry after 5 seconds.\n    setTimeout(() => revalidate({ retryCount }), 5000)\n  }\n})\n```\n\nThis callback gives you the flexibility to retry based on various conditions.\nYou can also disable it by setting `shouldRetryOnError: false`.\n\nIt's also possible to provide it via the\n[Global Configuration](/docs/global-configuration) context.\n\n## Global Error Report\n\nYou can always get the `error` object inside the component reactively. But in\ncase you want to handle the error globally, to notify the UI to show a\n[toast](https://vercel.com/design/toast) or a\n[snackbar](https://material.io/components/snackbars), or report it somewhere\nsuch as [Sentry](https://sentry.io), there's an\n[`onError`](/docs/options#options) event:\n\n```jsx\n<SWRConfig\n  value={{\n    onError: (error, key) => {\n      if (error.status !== 403 && error.status !== 404) {\n        // We can send the error to Sentry,\n        // or show a notification UI.\n      }\n    }\n  }}\n>\n  <MyApp />\n</SWRConfig>\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/getting-started.mdx",
    "content": "import { Link } from 'nextra-theme-docs'\nimport { Callout, FileTree, Steps } from 'nextra/components'\n\nexport const metadata = {\n  sidebarTitle: (\n    <>\n      <i>Getting</i>&nbsp;<s>Started</s>\n    </>\n  )\n}\n\n# Getting Started\n\nhttps://google.com/da;djaldhksagfugsufgasuyfgyuasgfuasgdjasbdjasdjkasfuydfasyrdyafsdygasjdgasgdsafgdhjfasgjdfsahjdfsahjgdasgdjkasgdkjasgdkjasgdkagdkjasgdkjagdkjagdkagdkagdkjagdkagdkagdkagda\n\n- **foo**\n  - bar\n  - **baz**\n    - qux\n    - **qwe**\n      1. he\n      1. **be**\n         1. wo\n         1. **be** da\n            - da\n            - ba\n\n<details>\n  <summary>**111** 111</summary>\n  content line 1 some more content\n  <details>\n    <summary>**222** 222</summary>\n    content line 2 some more content\n    <details>\n      <summary>**333** 333</summary>\n      content line 3 some more content\n    </details>\n  </details>\n</details>\n\n<Steps>\n  ## Step 1\n  <Steps>\n    ### Step 1.1\n\n    ### Step 1.2\n\n  </Steps>\n  ## Step 2\n\n  <Steps>\n    ### Step 2.1\n\n    ### Step 2.2\n\n  </Steps>\n</Steps>\n\n## Development\n\n<Steps>\n### Install Dependencies\n\nRun `pnpm install` in the project root directory.\n\n### Lint\n\n  <Steps>\n    #### Lint ESLint\n\n    run `pnpm lint`\n\n    #### Lint Prettier\n\n    run `pnpm lint:prettier --write` to format the entire project.\n\n  </Steps>\n\n### Test\n\nRun `pnpm test`\n\n</Steps>\n\n```css filename=\"CSS\" word-wrap=false\nhtml {\n  background: red;\n}\n```\n\n```graphql filename=\"GraphQL\"\ntype Character {\n  name: String\n}\n```\n\n```python filename=\"Python\"\n# type Character {\nclass Character:\n  # name: String\n  def name(self):\n    return self._name\n```\n\n```csharp filename=\"C#\"\n// type Character {\npublic class Character {\n  // name: String\n  public String Name { get; }\n}\n```\n\n`__esModule`\n\n`Docs theme box-decoration-theme: clone can create confusing output over line breaks`\n\n---\n\n<Link href=\"https://google.com\">Link</Link>\n\nexport const myVar = '\"I am from export const\"'\n\n## Foo {myVar}\n\n### Bar `code`\n\n#### Latex $latex^2$\n\n###### <strong>Da</strong>\n\n###### _Ma_**Chi**<s>na</s>\n\nexport const Test = props => <b>{props.someProp}</b>\n\n#### Qux <Test someProp=\"someVal\" />\n\n##### My file is `<MyFile />{:js}`\n\n```math\nx^2\n```\n\n```math\n\\int_1^2x^2\n```\n\nInside your React project directory, run the following:\n\n```sh npm2yarn\nnpm i swr __esModule\n```\n\n## Quick Start $latex$\n\nFor normal RESTful APIs with JSON data, first you need to create a `fetcher`\nfunction, which is just a wrapper of the native `fetch`:\n\n```jsx\nconst fetcher = (...args) => fetch(...args).then(res => res.json())\n```\n\n<Callout>\n  If you want to use GraphQL API or libs like Axios, you can create your own\n  fetcher function. Check [here](/docs/data-fetching) for more examples.\n</Callout>\n\n<FileTree>\n  <FileTree.Folder name=\"users-service\" defaultOpen>\n    <FileTree.File name=\"schema.graphql\" />\n  </FileTree.Folder>\n  <FileTree.Folder name=\"posts-service\" defaultOpen>\n    <FileTree.File name=\"schema.graphql\" />\n  </FileTree.Folder>\n</FileTree>\n\n<FileTree>\n  <FileTree.Folder name=\"users-service\" defaultOpen>\n    <FileTree.File name=\"schema.graphql\" />\n    <FileTree.Folder name=\"posts-service\" defaultOpen>\n      <FileTree.File name=\"schema.graphql\" />\n    </FileTree.Folder>\n  </FileTree.Folder>\n</FileTree>\n\n<details>\n  <summary>Renders properly</summary>\n  <div className=\"flex justify-center\">content</div>\n</details>\n\n<details>\n  <summary>Renders on next line</summary>\n  <div className=\"flex justify-center\">content</div>\n</details>\n\nThen you can import `useSWR` and start using it inside any function components:\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user/123', fetcher)\n\n  if (error) return <div>failed to load</div>\n  if (!data) return <div>loading...</div>\n\n  // render data\n  return <div>hello {data.name}!</div>\n}\n```\n\nNormally, there're 3 possible states of a request: \"loading\", \"ready\", or\n\"error\". You can use the value of `data` and `error` to determine the current\nstate of the request, and return the corresponding UI.\n\n## Make It Reusable\n\nHere's a JavaScript expression: `const a = 1 + 2{:js}`.\n\nWhen building a web app, you might need to reuse the data in many places of the\nUI. It is incredibly easy to create reusable data hooks on top of SWR:\n\n```jsx /data/\nfunction useUser(id) {\n  const { data, error } = useSWR(`/api/user/${id}`, fetcher)\n\n  return {\n    user: data,\n    isLoading: !error && !data,\n    isError: error\n  }\n}\n```\n\nAnd use it in your components:\n\n```jsx\nfunction Avatar({ id }) {\n  const { user, isLoading, isError } = useUser(id)\n\n  if (isLoading) return <Spinner />\n  if (isError) return <Error />\n  return <img src={user.avatar} />\n}\n```\n\nBy adopting this pattern, you can forget about **fetching** data in the\nimperative way: start the request, update the loading state, and return the\nfinal result. Instead, your code is more declarative: you just need to specify\nwhat data is used by the component.\n\n## Example\n\nIn a real-world example, our website shows a navbar and the content, both depend\non `user`:\n\nimport { WelcomeImage } from '@app/_icons'\n\n<WelcomeImage className=\"mt-6 dark:invert\" />\n\nTraditionally, we fetch data once using `useEffect` in the top level component,\nand pass it to child components via props (notice that we don't handle error\nstate for now):\n\n```jsx {7-11,17,18,27}\n// page component\n\nfunction Page() {\n  const [user, setUser] = useState(null)\n\n  // fetch data\n  useEffect(() => {\n    fetch('/api/user')\n      .then(res => res.json())\n      .then(data => setUser(data))\n  }, [])\n\n  // global loading state\n  if (!user) return <Spinner />\n\n  return (\n    <div>\n      <Navbar user={user} />\n      <Content user={user} />\n    </div>\n  )\n}\n\n// child components\n\nfunction Navbar({ user }) {\n  return (\n    <div>\n      ...\n      <Avatar user={user} />\n    </div>\n  )\n}\n\nfunction Content({ user }) {\n  return <h1>Welcome back, {user.name}</h1>\n}\n\nfunction Avatar({ user }) {\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\nUsually, we need to keep all the data fetching in the top level component and\nadd props to every component deep down the tree. The code will become harder to\nmaintain if we add more data dependency to the page.\n\nAlthough we can avoid passing props using\n[Context](https://reactjs.org/docs/context.html), there's still the dynamic\ncontent problem: components inside the page content can be dynamic, and the top\nlevel component might not know what data will be needed by its child components.\n\nSWR solves the problem perfectly. With the `useUser` hook we just created, the\ncode can be refactored to:\n\n```jsx {20,26}\n// page component\nfunction Page() {\n  return (\n    <div>\n      <Navbar />\n      <Content />\n    </div>\n  )\n}\n\n// child components\nfunction Navbar() {\n  return (\n    <div>\n      ...\n      <Avatar />\n    </div>\n  )\n}\n\nfunction Content() {\n  const { user, isLoading } = useUser()\n  if (isLoading) return <Spinner />\n  return <h1>Welcome back, {user.name}</h1>\n}\n\nfunction Avatar() {\n  const { user, isLoading } = useUser()\n  if (isLoading) return <Spinner />\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\nData is now **bound** to the components which need the data, and all components\nare **independent** to each other. All the parent components don't need to know\nanything about the data or passing data around. They just render. The code is\nmuch simpler and easier to maintain now.\n\nThe most beautiful thing is that there will be only **1 request** sent to the\nAPI, because they use the same SWR key and the request is **deduped**,\n**cached** and **shared** automatically.\n\nAlso, the application now has the ability to refetch the data on\n[user focus or network reconnect](/docs/revalidation)! That means, when the\nuser's laptop wakes from sleep or they switch between browser tabs, the data\nwill be refreshed automatically.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/global-configuration.md",
    "content": "# Global Configuration\n\nThe context `SWRConfig` can provide global configurations\n([options](/docs/options)) for all SWR hooks.\n\n```jsx\n<SWRConfig value={options}>\n  <Component />\n</SWRConfig>\n```\n\nIn this example, all SWR hooks will use the same fetcher provided to load JSON\ndata, and refresh every 3 seconds by default:\n\n```jsx\nimport useSWR, { SWRConfig } from 'swr'\n\nfunction Dashboard() {\n  const { data: events } = useSWR('/api/events')\n  const { data: projects } = useSWR('/api/projects')\n  const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // override\n\n  // ...\n}\n\nfunction App() {\n  return (\n    <SWRConfig\n      value={{\n        refreshInterval: 3000,\n        fetcher: (resource, init) =>\n          fetch(resource, init).then(res => res.json())\n      }}\n    >\n      <Dashboard />\n    </SWRConfig>\n  )\n}\n```\n\n## Extra APIs\n\n### Cache Provider\n\nBesides, all the [options](/docs/options) listed, `SWRConfig` also accepts an\noptional `provider` function. Please refer to the [Cache](/docs/cache) section\nfor more details.\n\n```jsx\n<SWRConfig value={{ provider: () => new Map() }}>\n  <Dashboard />\n</SWRConfig>\n```\n\n### Access To Global Configurations\n\nYou can use the `useSWRConfig` hook to get the global configurations, as well as\n[`mutate`](/docs/mutation) and [`cache`](/docs/advanced/cache):\n\n```jsx\nimport { useSWRConfig } from 'swr'\n\nfunction Component() {\n  const { refreshInterval, mutate, cache, ...restConfig } = useSWRConfig()\n\n  // ...\n}\n```\n\nNested configurations will be extended. If no `<SWRConfig>` is used, it will\nreturn the default ones.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/middleware.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Middleware\n\n<Callout>Upgrade to the latest version (≥ 1.0.0) to use this feature.</Callout>\n\nThe middleware feature is a new addition in SWR 1.0 that enables you to execute\nlogic before and after SWR hooks.\n\n## Usage\n\nMiddleware receive the SWR hook and can execute logic before and after running\nit. If there are multiple middleware, each middleware wraps the next middleware.\nThe last middleware in the list will receive the original SWR hook `useSWR`.\n\n### API\n\n```jsx\nfunction myMiddleware(useSWRNext) {\n  return (key, fetcher, config) => {\n    // Before hook runs...\n\n    // Handle the next middleware, or the `useSWR` hook if this is the last one.\n    const swr = useSWRNext(key, fetcher, config)\n\n    // After hook runs...\n    return swr\n  }\n}\n```\n\nYou can pass an array of middleware as an option to `SWRConfig` or `useSWR`:\n\n```jsx\n<SWRConfig value={{ use: [myMiddleware] }}>\n\n// or...\n\nuseSWR(key, fetcher, { use: [myMiddleware] })\n```\n\n### Extend\n\nMiddleware will be extended like regular options. For example:\n\n```jsx\nfunction Bar() {\n  useSWR(key, fetcher, { use: [c] })\n  // ...\n}\n\nfunction Foo() {\n  return (\n    <SWRConfig value={{ use: [a] }}>\n      <SWRConfig value={{ use: [b] }}>\n        <Bar />\n      </SWRConfig>\n    </SWRConfig>\n  )\n}\n```\n\nis equivalent to:\n\n```js\nuseSWR(key, fetcher, { use: [a, b, c] })\n```\n\n### Multiple Middleware\n\nEach middleware wraps the next middleware, and the last one just wraps the SWR\nhook. For example:\n\n```jsx\nuseSWR(key, fetcher, { use: [a, b, c] })\n```\n\nThe order of middleware executions will be `a → b → c`, as shown below:\n\n```js\nenter a\n  enter b\n    enter c\n      useSWR()\n    exit  c\n  exit  b\nexit  a\n```\n\n## Examples\n\n### Request Logger\n\nLet's build a simple request logger middleware as an example. It prints out all\nthe fetcher requests sent from this SWR hook. You can also use this middleware\nfor all SWR hooks by adding it to `SWRConfig`.\n\n```jsx\nfunction logger(useSWRNext) {\n  return (key, fetcher, config) => {\n    // Add logger to the original fetcher.\n    const extendedFetcher = (...args) => {\n      console.log('SWR Request:', key)\n      return fetcher(...args)\n    }\n\n    // Execute the hook with the new fetcher.\n    return useSWRNext(key, extendedFetcher, config)\n  }\n}\n\n// ... inside your component\nuseSWR(key, fetcher, { use: [logger] })\n```\n\nEvery time the request is fired, it outputs the SWR key to the console:\n\n```plaintext\nSWR Request: /api/user1\nSWR Request: /api/user2\n```\n\n### Keep Previous Result\n\nSometimes you want the data returned by `useSWR` to be \"laggy\". Even if the key\nchanges, you still want it to return the previous result until the new data has\nloaded.\n\nThis can be built as a laggy middleware together with `useRef`. In this example,\nwe are also going to extend the returned object of the `useSWR` hook:\n\n```jsx\nimport { useCallback, useEffect, useRef } from 'react'\n\n// This is a SWR middleware for keeping the data even if key changes.\nfunction laggy(useSWRNext) {\n  return (key, fetcher, config) => {\n    // Use a ref to store previous returned data.\n    const laggyDataRef = useRef()\n\n    // Actual SWR hook.\n    const swr = useSWRNext(key, fetcher, config)\n\n    useEffect(() => {\n      // Update ref if data is not undefined.\n      if (swr.data !== undefined) {\n        laggyDataRef.current = swr.data\n      }\n    }, [swr.data])\n\n    // Expose a method to clear the laggy data, if any.\n    const resetLaggy = useCallback(() => {\n      laggyDataRef.current = undefined\n    }, [])\n\n    // Fallback to previous data if the current data is undefined.\n    const dataOrLaggyData =\n      swr.data === undefined ? laggyDataRef.current : swr.data\n\n    // Is it showing previous data?\n    const isLagging =\n      swr.data === undefined && laggyDataRef.current !== undefined\n\n    // Also add a `isLagging` field to SWR.\n    return Object.assign({}, swr, {\n      data: dataOrLaggyData,\n      isLagging,\n      resetLaggy\n    })\n  }\n}\n```\n\nWhen you need a SWR hook to be laggy, you can then use this middleware:\n\n```js\nconst { data, isLagging, resetLaggy } = useSWR(key, fetcher, { use: [laggy] })\n```\n\n### Serialize Object Keys\n\n<Callout>\n  Since SWR 1.1.0, object-like keys will be serialized under the hood\n  automatically.\n</Callout>\n\n<Callout type=\"warning\">\n  In older versions (< 1.1.0), SWR **shallowly** compares the arguments on every render, and triggers revalidation if any of them has changed.\n  If you are passing serializable objects as the key. You can serialize object keys to ensure its stability, a simple middleware can help:\n</Callout>\n\n```jsx\nfunction serialize(useSWRNext) {\n  return (key, fetcher, config) => {\n    // Serialize the key.\n    const serializedKey = Array.isArray(key) ? JSON.stringify(key) : key\n\n    // Pass the serialized key, and unserialize it in fetcher.\n    return useSWRNext(serializedKey, (k) => fetcher(...JSON.parse(k)), config)\n  }\n}\n\n// ...\nuseSWR(['/api/user', { id: '73' }], fetcher, { use: [serialize] })\n\n// ... or enable it globally with\n<SWRConfig value={{ use: [serialize] }}>\n```\n\nYou don't need to worry that object might change between renders. It's always\nserialized to the same string, and the fetcher will still receive those object\narguments.\n\n<Callout>\n  Furthermore, you can use libs like\n  [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify)\n  instead of `JSON.stringify` — faster and stabler.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/mutation.md",
    "content": "# Mutation\n\n## Revalidate\n\nYou can get the `mutate` function from the `useSWRConfig()` hook, and broadcast\na revalidation message globally to other SWR hooks<sup>\\*</sup> using the same\nkey by calling `mutate(key)`.\n\nThis example shows how to automatically refetch the login info (e.g. inside\n`<Profile>`) when the user clicks the \"Logout\" button.\n\n```jsx\nimport useSWR, { useSWRConfig } from 'swr'\n\nfunction App() {\n  const { mutate } = useSWRConfig()\n\n  return (\n    <div>\n      <Profile />\n      <button\n        onClick={() => {\n          // set the cookie as expired\n          document.cookie =\n            'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'\n\n          // tell all SWRs with this key to revalidate\n          mutate('/api/user')\n        }}\n      >\n        Logout\n      </button>\n    </div>\n  )\n}\n```\n\n\\*: _It broadcasts to SWR hooks under the same [cache provider](/docs/cache)\nscope. If no cache provider exists, it will broadcast to all SWR hooks._\n\n## Mutation and POST Request\n\nIn many cases, applying local mutations to data is a good way to make changes\nfeel faster — no need to wait for the remote source of data.\n\nWith `mutate`, you can update your local data programmatically, while\nrevalidating and finally replace it with the latest data.\n\n```jsx\nimport useSWR, { useSWRConfig } from 'swr'\n\nfunction Profile() {\n  const { mutate } = useSWRConfig()\n  const { data } = useSWR('/api/user', fetcher)\n\n  return (\n    <div>\n      <h1>My name is {data.name}.</h1>\n      <button\n        onClick={async () => {\n          const newName = data.name.toUpperCase()\n\n          // update the local data immediately, but disable the revalidation\n          mutate('/api/user', { ...data, name: newName }, false)\n\n          // send a request to the API to update the source\n          await requestUpdateUsername(newName)\n\n          // trigger a revalidation (refetch) to make sure our local data is correct\n          mutate('/api/user')\n        }}\n      >\n        Uppercase my name!\n      </button>\n    </div>\n  )\n}\n```\n\nClicking the button in the example above will locally update the client data,\nsend a POST request to modify the remote data and try to fetch the latest one\n(revalidate).\n\nBut many POST APIs will just return the updated data directly, so we don't need\nto revalidate again. Here's an example showing the \"local mutate - request -\nupdate\" usage:\n\n```jsx\nmutate('/api/user', newUser, false) // use `false` to mutate without revalidation\nmutate('/api/user', updateUser(newUser), false) // `updateUser` is a Promise of the request,\n// which returns the updated document\n```\n\n## Mutate Based on Current Data\n\nSometimes, you want to update a part of your data based on the current data.\n\nWith `mutate`, you can pass an async function which will receive the current\ncached value, if any, and returns an updated document.\n\n```jsx\nmutate('/api/todos', async todos => {\n  // let's update the todo with ID `1` to be completed,\n  // this API returns the updated data\n  const updatedTodo = await fetch('/api/todos/1', {\n    method: 'PATCH',\n    body: JSON.stringify({ completed: true })\n  })\n\n  // filter the list, and return it with the updated item\n  const filteredTodos = todos.filter(todo => todo.id !== '1')\n  return [...filteredTodos, updatedTodo]\n})\n```\n\n## Returned Data from Mutate\n\nMost probably, you need some data to update the cache. The data is resolved or\nreturned from the promise or async function you passed to `mutate`.\n\nThe function passed to `mutate` will return an updated document which is used to\nupdate the corresponding cache value. If there is an error thown while executing\nthe function, the error will be thrown so it can be handled appropriately.\n\n```jsx\ntry {\n  const user = await mutate('/api/user', updateUser(newUser))\n} catch (error) {\n  // Handle an error while updating the user here\n}\n```\n\n## Bound Mutate\n\nThe SWR object returned by `useSWR` also contains a `mutate()` function that is\npre-bound to the SWR's key.\n\nIt is functionally equivalent to the global `mutate` function but does not\nrequire the `key` parameter.\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, mutate } = useSWR('/api/user', fetcher)\n\n  return (\n    <div>\n      <h1>My name is {data.name}.</h1>\n      <button\n        onClick={async () => {\n          const newName = data.name.toUpperCase()\n          // send a request to the API to update the data\n          await requestUpdateUsername(newName)\n          // update the local data immediately and revalidate (refetch)\n          // NOTE: key is not required when using useSWR's mutate as it's pre-bound\n          mutate({ ...data, name: newName })\n        }}\n      >\n        Uppercase my name!\n      </button>\n    </div>\n  )\n}\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/options.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# API Options\n\n```js\nconst { data, error, isValidating, mutate } = useSWR(key, fetcher, options)\n```\n\n## Parameters\n\n- `key`: a unique key string for the request (or a function / array / null)\n  [(advanced usage)](/docs/conditional-fetching)\n- `fetcher`: (_optional_) a Promise returning function to fetch your data\n  [(details)](/docs/data-fetching)\n- `options`: (_optional_) an object of options for this SWR hook\n\n## Return Values\n\n- `data`: data for the given key resolved by `fetcher` (or undefined if not\n  loaded)\n- `error`: error thrown by `fetcher` (or undefined)\n- `isValidating`: if there's a request or revalidation loading\n- `mutate(data?, shouldRevalidate?)`: function to mutate the cached data\n  [(details)](/docs/mutation)\n\n## Options\n\n- `suspense = false`: enable React Suspense mode [(details)](/docs/suspense)\n- `fetcher(args)`: the fetcher function\n- `revalidateIfStale = true`: automatic revalidation on mount even if there is\n  stale data [(details)](/docs/revalidation#disable-automatic-revalidations)\n- `revalidateOnMount`: enable or disable automatic revalidation when component\n  is mounted\n- `revalidateOnFocus = true`: automatically revalidate when window gets focused\n  [(details)](/docs/revalidation)\n- `revalidateOnReconnect = true`: automatically revalidate when the browser\n  regains a network connection (via `navigator.onLine`)\n  [(details)](/docs/revalidation)\n- `refreshInterval` [(details)](/docs/revalidation):\n  - Disabled by default: `refreshInterval = 0`\n  - If set to a number, polling interval in milliseconds\n  - If set to a function, the function will receive the latest data and should\n    return the interval in milliseconds\n- `refreshWhenHidden = false`: polling when the window is invisible (if\n  `refreshInterval` is enabled)\n- `refreshWhenOffline = false`: polling when the browser is offline (determined\n  by `navigator.onLine`)\n- `shouldRetryOnError = true`: retry when fetcher has an error\n- `dedupingInterval = 2000`: dedupe requests with the same key in this time span\n  in milliseconds\n- `focusThrottleInterval = 5000`: only revalidate once during a time span in\n  milliseconds\n- `loadingTimeout = 3000`: timeout to trigger the onLoadingSlow event in\n  milliseconds\n- `errorRetryInterval = 5000`: error retry interval in milliseconds\n- `errorRetryCount`: max error retry count\n- `fallback`: a key-value object of multiple fallback data\n  [(example)](/docs/with-nextjs)\n- `fallbackData`: initial data to be returned (note: This is per-hook)\n- `onLoadingSlow(key, config)`: callback function when a request takes too long\n  to load (see `loadingTimeout`)\n- `onSuccess(data, key, config)`: callback function when a request finishes\n  successfully\n- `onError(err, key, config)`: callback function when a request returns an error\n- `onErrorRetry(err, key, config, revalidate, revalidateOps)`: handler for error\n  retry\n- `compare(a, b)`: comparison function used to detect when returned data has\n  changed, to avoid spurious rerenders. By default,\n  [dequal](https://github.com/lukeed/dequal) is used.\n- `isPaused()`: function to detect whether pause revalidations, will ignore\n  fetched data and errors when it returns `true`. Returns `false` by default.\n- `use`: array of middleware functions [(details)](/docs/middleware)\n\n<Callout>\n  When under a slow network (2G, {'<='} 70Kbps), `errorRetryInterval` will be\n  10s, and `loadingTimeout` will be 5s by default.\n</Callout>\n\nYou can also use [global configuration](/docs/global-configuration) to provide\ndefault options.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/pagination.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Pagination\n\n<Callout emoji=\"✅\">\n  Please update to the latest version (≥ 0.3.0) to use this API. The previous\n  `useSWRPages` API is now deprecated.\n</Callout>\n\nSWR provides a dedicated API `useSWRInfinite` to support common UI patterns such\nas **pagination** and **infinite loading**.\n\n## When to Use `useSWR`\n\n### Pagination\n\nFirst of all, we might **NOT** need `useSWRInfinite` but can use just `useSWR`\nif we are building something like this:\n\nimport { PaginationImage } from '@app/_icons'\n\n<PaginationImage className=\"mt-6 dark:invert\" />\n\n...which is a typical pagination UI. Let's see how it can be easily implemented\nwith `useSWR`:\n\n```jsx {5}\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  // The API URL includes the page index, which is a React state.\n  const { data } = useSWR(`/api/data?page=${pageIndex}`, fetcher)\n\n  // ... handle loading and error states\n\n  return (\n    <div>\n      {data.map(item => (\n        <div key={item.id}>{item.name}</div>\n      ))}\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>\n    </div>\n  )\n}\n```\n\nFurthermore, we can create an abstraction for this \"page component\":\n\n```jsx {13}\nfunction Page({ index }) {\n  const { data } = useSWR(`/api/data?page=${index}`, fetcher)\n\n  // ... handle loading and error states\n\n  return data.map(item => <div key={item.id}>{item.name}</div>)\n}\n\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  return (\n    <div>\n      <Page index={pageIndex} />\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>\n    </div>\n  )\n}\n```\n\nBecause of SWR's cache, we get the benefit to preload the next page. We render\nthe next page inside a hidden div, so SWR will trigger the data fetching of the\nnext page. When the user navigates to the next page, the data is already there:\n\n```jsx {6}\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  return (\n    <div>\n      <Page index={pageIndex} />\n      <div style={{ display: 'none' }}>\n        <Page index={pageIndex + 1} />\n      </div>\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>\n    </div>\n  )\n}\n```\n\nWith just 1 line of code, we get a much better UX. The `useSWR` hook is so\npowerful, that most scenarios are covered by it.\n\n### Infinite Loading\n\nSometimes we want to build an **infinite loading** UI, with a \"Load More\" button\nthat appends data to the list (or done automatically when you scroll):\n\nimport { InfiniteImage } from '@app/_icons'\n\n<InfiniteImage className=\"mt-6 dark:invert\" />\n\nTo implement this, we need to make **dynamic number of requests** on this page.\nReact Hooks have [a couple of rules](https://reactjs.org/docs/hooks-rules.html),\nso we **CANNOT** do something like this:\n\n```jsx {5-9}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const list = []\n  for (let i = 0; i < cnt; i++) {\n    // 🚨 This is wrong! Commonly, you can't use hooks inside a loop.\n    const { data } = useSWR(`/api/data?page=${i}`)\n    list.push(data)\n  }\n\n  return (\n    <div>\n      {list.map((data, i) => (\n        <div key={i}>\n          {data.map(item => (\n            <div key={item.id}>{item.name}</div>\n          ))}\n        </div>\n      ))}\n      <button onClick={() => setCnt(cnt + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\nInstead, we can use the `<Page>` abstraction that we created to achieve it:\n\n```jsx {5,6,7}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const pages = []\n  for (let i = 0; i < cnt; i++) {\n    pages.push(<Page index={i} key={i} />)\n  }\n\n  return (\n    <div>\n      {pages}\n      <button onClick={() => setCnt(cnt + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\n### Advanced Cases\n\nHowever, in some advanced use cases, the solution above doesn't work.\n\nFor example, we are still implementing the same \"Load More\" UI, but also need to\ndisplay a number about how many items are there in total. We can't use the\n`<Page>` solution anymore because the top level UI (`<App>`) needs the data\ninside each page:\n\n```jsx {10}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const pages = []\n  for (let i = 0; i < cnt; i++) {\n    pages.push(<Page index={i} key={i} />)\n  }\n\n  return (\n    <div>\n      <p>??? items</p>\n      {pages}\n      <button onClick={() => setCnt(cnt + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\nAlso, if the pagination API is **cursor based**, that solution doesn't work\neither. Because each page needs the data from the previous page, they're not\nisolated.\n\nThat's how this new `useSWRInfinite` Hook can help.\n\n## useSWRInfinite\n\n`useSWRInfinite` gives us the ability to trigger a number of requests with one\nHook. This is how it looks:\n\n```jsx\nimport useSWRInfinite from 'swr/infinite'\n\n// ...\nconst { data, error, isValidating, mutate, size, setSize } = useSWRInfinite(\n  getKey, fetcher?, options?\n)\n```\n\nSimilar to `useSWR`, this new Hook accepts a function that returns the request\nkey, a fetcher function, and options. It returns all the values that `useSWR`\nreturns, including 2 extra values: the page size and a page size setter, like a\nReact state.\n\nIn infinite loading, one _page_ is one request, and our goal is to fetch\nmultiple pages and render them.\n\n<Callout type=\"warning\">\n  If you are using SWR 0.x versions, `useSWRInfinite` needs to be imported from\n  `swr`:\n\n`import {useSWRInfinite} from 'swr'`\n\n</Callout>\n\n### API\n\n#### Parameters\n\n- `getKey`: a function that accepts the index and the previous page data,\n  returns the key of a page\n- `fetcher`: same as `useSWR`'s [fetcher function](/docs/data-fetching)\n- `options`: accepts all the options that `useSWR` supports, with 3 extra\n  options:\n  - `initialSize = 1`: number of pages should be loaded initially\n  - `revalidateAll = false`: always try to revalidate all pages\n  - `revalidateFirstPage = true`: always try to revalidate the first page\n  - `persistSize = false`: don't reset the page size to 1 (or `initialSize` if\n    set) when the first page's key changes\n\n<Callout>\n  Note that the `initialSize` option is not allowed to change in the lifecycle.\n</Callout>\n\n#### Return Values\n\n- `data`: an array of fetch response values of each page\n- `error`: same as `useSWR`'s `error`\n- `isValidating`: same as `useSWR`'s `isValidating`\n- `mutate`: same as `useSWR`'s bound mutate function but manipulates the data\n  array\n- `size`: the number of pages that _will_ be fetched and returned\n- `setSize`: set the number of pages that need to be fetched\n\n### Example 1: Index Based Paginated API\n\nFor normal index based APIs:\n\n```\nGET /users?page=0&limit=10\n[\n  { name: 'Alice', ... },\n  { name: 'Bob', ... },\n  { name: 'Cathy', ... },\n  ...\n]\n```\n\n```jsx {4-7,10}\n// A function to get the SWR key of each page,\n// its return value will be accepted by `fetcher`.\n// If `null` is returned, the request of that page won't start.\nconst getKey = (pageIndex, previousPageData) => {\n  if (previousPageData && !previousPageData.length) return null // reached the end\n  return `/users?page=${pageIndex}&limit=10` // SWR key\n}\n\nfunction App() {\n  const { data, size, setSize } = useSWRInfinite(getKey, fetcher)\n  if (!data) return 'loading'\n\n  // We can now calculate the number of all users\n  let totalUsers = 0\n  for (let i = 0; i < data.length; i++) {\n    totalUsers += data[i].length\n  }\n\n  return (\n    <div>\n      <p>{totalUsers} users listed</p>\n      {data.map(users => {\n        // `data` is an array of each page's API response.\n        return users.map(user => <div key={user.id}>{user.name}</div>)\n      })}\n      <button onClick={() => setSize(size + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\nThe `getKey` function is the major difference between `useSWRInfinite` and\n`useSWR`. It accepts the index of the current page, as well as the data from the\nprevious page. So both index based and cursor based pagination API can be\nsupported nicely.\n\nAlso `data` is no longer just one API response. It's an array of multiple API\nresponses:\n\n```js\n// `data` will look like this\n[\n  [\n    { name: 'Alice', ... },\n    { name: 'Bob', ... },\n    { name: 'Cathy', ... },\n    ...\n  ],\n  [\n    { name: 'John', ... },\n    { name: 'Paul', ... },\n    { name: 'George', ... },\n    ...\n  ],\n  ...\n]\n```\n\n### Example 2: Cursor or Offset Based Paginated API\n\nLet's say the API now requires a cursor and returns the next cursor alongside\nwith the data:\n\n```plaintext\nGET /users?cursor=123&limit=10\n{\n  data: [\n    { name: 'Alice' },\n    { name: 'Bob' },\n    { name: 'Cathy' },\n    ...\n  ],\n  nextCursor: 456\n}\n```\n\nWe can change our `getKey` function to:\n\n```jsx\nconst getKey = (pageIndex, previousPageData) => {\n  // reached the end\n  if (previousPageData && !previousPageData.data) return null\n\n  // first page, we don't have `previousPageData`\n  if (pageIndex === 0) return `/users?limit=10`\n\n  // add the cursor to the API endpoint\n  return `/users?cursor=${previousPageData.nextCursor}&limit=10`\n}\n```\n\n### Advanced Features\n\n[Here is an example](/examples/infinite-loading) showing how you can implement\nthe following features with `useSWRInfinite`:\n\n- loading states\n- show a special UI if it's empty\n- disable the \"Load More\" button if reached the end\n- changeable data source\n- refresh the entire list\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/prefetching.md",
    "content": "# Prefetching Data\n\n## Top-Level Page Data\n\nThere're many ways to prefetch the data for SWR. For top level requests,\n[`rel=\"preload\"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content)\nis highly recommended:\n\n```html\n<link rel=\"preload\" href=\"/api/data\" as=\"fetch\" crossorigin=\"anonymous\" />\n```\n\nJust put it inside your HTML `<head>`. It's easy, fast and native.\n\nIt will prefetch the data when the HTML loads, even before JavaScript starts to\ndownload. All your incoming fetch requests with the same URL will reuse the\nresult (including SWR, of course).\n\n## Programmatically Prefetch\n\nSometimes, you want to preload a resource conditionally. For example, preloading\nthe data when the user is\n[hovering](https://github.com/GoogleChromeLabs/quicklink)\n[a](https://github.com/guess-js/guess) [link](https://instant.page). The most\nintuitive way is to have a function to refetch and set the cache via the global\n[mutate](/docs/mutation):\n\n```js\nimport { mutate } from 'swr'\n\nfunction prefetch() {\n  mutate(\n    '/api/data',\n    fetch('/api/data').then(res => res.json())\n  )\n  // the second parameter is a Promise\n  // SWR will use the result when it resolves\n}\n```\n\nTogether with techniques like\n[page prefetching](https://nextjs.org/docs/api-reference/next/router#routerprefetch)\nin Next.js, you will be able to load both next page and data instantly.\n\n## Pre-fill Data\n\nIf you want to pre-fill existing data into the SWR cache, you can use the\n`fallbackData` option. For example:\n\n```jsx\nuseSWR('/api/data', fetcher, { fallbackData: prefetchedData })\n```\n\nIf SWR hasn't fetched the data yet, this hook will return `prefetchedData` as a\nfallback.\n\nYou can also configure this for all SWR hooks and multiple keys with\n`<SWRConfig>` and the `fallback` option. Check\n[Next.js SSG and SSR](/docs/with-nextjs) for more details.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/revalidation.mdx",
    "content": "import { Video } from '@app/_components/video'\nimport { Bleed, Callout } from 'nextra/components'\n\n# Automatic Revalidation\n\n<Callout>\n  If you want to manually revalidate the data, check [mutation](/docs/mutation).\n</Callout>\n\n## Revalidate on Focus\n\nWhen you re-focus a page or switch between tabs, SWR automatically revalidates\ndata.\n\nThis can be useful to immediately synchronize to the latest state. This is\nhelpful for refreshing data in scenarios like stale mobile tabs, or laptops that\n**went to sleep**.\n\n<Bleed>\n  <Video\n    src=\"https://raw.githubusercontent.com/vercel/swr-site/master/.github/videos/focus-revalidate.mp4\"\n    caption=\"Video: using focus revalidation to automatically sync login state between pages.\"\n    ratio={307 / 768}\n  />\n</Bleed>\n\nThis feature is enabled by default. You can disable it via the\n[`revalidateOnFocus`](/docs/options) option.\n\n## Revalidate on Interval\n\nIn many cases, data changes because of multiple devices, multiple users,\nmultiple tabs. How can we over time update the data on screen?\n\nSWR will give you the option to automatically refetch data. It's **smart** which\nmeans refetching will only happen if the component associated with the hook is\n**on screen**.\n\n<Bleed>\n  <Video\n    src=\"https://raw.githubusercontent.com/vercel/swr-site/master/.github/videos/refetch-interval.mp4\"\n    caption=\"Video: when a user makes a change, both sessions will eventually render the same data.\"\n    ratio={307 / 768}\n  />\n</Bleed>\n\nYou can enable it by setting a [`refreshInterval`](/docs/options) value:\n\n```js\nuseSWR('/api/todos', fetcher, { refreshInterval: 1000 })\n```\n\nThere're also options such as `refreshWhenHidden` and `refreshWhenOffline`. Both\nare disabled by default so SWR won't fetch when the webpage is not on screen, or\nthere's no network connection.\n\n## Revalidate on Reconnect\n\nIt's useful to also revalidate when the user is back online. This scenario\nhappens a lot when the user unlocks their computer, but the internet is not yet\nconnected at the same moment.\n\nTo make sure the data is always up-to-date, SWR automatically revalidates when\nnetwork recovers.\n\nThis feature is enabled by default. You can disable it via the\n[`revalidateOnReconnect`](/docs/options) option.\n\n## Disable Automatic Revalidations\n\nIf the resource is **immutable**, that will never change if we revalidate again,\nwe can disable all kinds of automatic revalidations for it.\n\nSince version 1.0, SWR provides a helper hook `useSWRImmutable` to mark the\nresource as immutable:\n\n```js\nimport useSWRImmutable from 'swr/immutable'\n\n// ...\nuseSWRImmutable(key, fetcher, options)\n```\n\nIt has the same API interface as the normal `useSWR` hook. You can also do the\nsame thing by disable the following revalidation options:\n\n```js\nuseSWR(key, fetcher, {\n  revalidateIfStale: false,\n  revalidateOnFocus: false,\n  revalidateOnReconnect: false\n})\n\n// equivalent to\nuseSWRImmutable(key, fetcher)\n```\n\nThe `revalidateIfStale` controls if SWR should revalidate when it mounts and\nthere is stale data.\n\nThese 2 hooks above do the **exact same** thing. Once the data is cached, they\nwill never request it again.\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/suspense.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Suspense\n\n<Callout emoji=\"🚨\" type=\"error\">\n  Suspense is currently an **experimental** feature of React. These\n  APIs may change significantly and without a warning before they become a part\n  of React.\n\n[More information](https://reactjs.org/docs/concurrent-mode-suspense.html)\n\n</Callout>\n\n<Callout>Note that React Suspense is not yet supported in SSR mode.</Callout>\n\nYou can enable the `suspense` option to use SWR with React Suspense:\n\n```jsx\nimport { Suspense } from 'react'\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data } = useSWR('/api/user', fetcher, { suspense: true })\n  return <div>hello, {data.name}</div>\n}\n\nfunction App() {\n  return (\n    <Suspense fallback={<div>loading...</div>}>\n      <Profile />\n    </Suspense>\n  )\n}\n```\n\n<Callout>\n  Note that the `suspense` option is not allowed to change in the lifecycle.\n</Callout>\n\nIn Suspense mode, `data` is always the fetch response (so you don't need to\ncheck if it's `undefined`). But if an error occurred, you need to use an\n[error boundary](https://reactjs.org/docs/concurrent-mode-suspense.html#handling-errors)\nto catch it:\n\n```jsx\n<ErrorBoundary fallback={<h2>Could not fetch posts.</h2>}>\n  <Suspense fallback={<h1>Loading posts...</h1>}>\n    <Profile />\n  </Suspense>\n</ErrorBoundary>\n```\n\n---\n\n### Note: With Conditional Fetching\n\nNormally, when you enabled `suspense` it's guaranteed that `data` will always be\nready on render:\n\n```jsx\nfunction Profile() {\n  const { data } = useSWR('/api/user', fetcher, { suspense: true })\n\n  // `data` will never be `undefined`\n}\n```\n\nHowever, when using it together with conditional fetching or dependent fetching,\n`data` will be `undefined` if the request is **paused**:\n\n```jsx\nfunction Profile() {\n  const { data } = useSWR(isReady ? '/api/user' : null, fetcher, {\n    suspense: true\n  })\n\n  // `data` will be `undefined` if `isReady` is false\n}\n```\n\nIf you want to read more technical details about this restriction, check\n[the discussion here](https://github.com/vercel/swr/pull/357#issuecomment-627089889).\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/typescript.mdx",
    "content": "# TypeScript\n\nSWR is friendly for apps written in TypeScript, with type safety out of the box.\n\n## Basic Usage\n\nBy default, SWR will also infer the argument types of `fetcher` from `key`, so\nyou can have the preferred types automatically.\n\n### useSWR\n\n```typescript\n// `key` is inferred to be `string`\nuseSWR('/api/user', key => {})\nuseSWR(() => '/api/user', key => {})\n\n// `key` will be inferred as { a: string; b: { c: string; d: number } }\nuseSWR({ a: '1', b: { c: '3', d: 2 } }, key => {})\nuseSWR(() => { a: '1', b: { c: '3', d: 2 } }, key => {})\n\n// `arg0` will be inferred as string.  `arg1` will be inferred as number\nuseSWR(['user', 8], (arg0, arg1) => {})\nuseSWR(() => ['user', 8], (arg0, arg1) => {})\n```\n\nYou can also explicitly specify the types for `key` and `fetcher`'s arguments.\n\n```typescript\nimport useSWR, { Fetcher, Key } from 'swr'\n\nconst uid: Key = '<user_id>'\nconst fetcher: Fetcher<string, User> = id => getUserById(id)\n\nconst { data } = useSWR(uid, fetcher)\n// `data` will be `User | undefined`.\n```\n\n### useSWRInfinite\n\nSame for `swr/inifite`, you can either rely on the automatic type inference or\nexplicitly sepicify the types by yourself.\n\n```typescript\nimport { SWRInfiniteKeyLoader } from 'swr/infinite'\n\nconst getKey: SWRInfiniteKeyLoader = (index, previousPageData) => {\n  // ...\n}\n\nconst { data } = useSWRInfinite(getKey, fetcher)\n```\n\n## Generics\n\nSpeicifying the type of `data` is easy. By default, it will use the return type\nof `fetcher` (with `undefined` for the non-ready state) as the `data` type, but\nyou can also pass it as a parameter:\n\n```typescript\n// 🔹 A. Use a typed fetcher:\n// `getUser` is `(endpoint: string) => User`.\nconst { data } = useSWR('/api/user', getUser)\n\n// 🔹 B. Specify the data type:\n// `fetcher` is generally returning `any`.\nconst { data } = useSWR<User>('/api/user', fetcher)\n```\n\nIf you want to add types for other options of SWR, you can also import those\ntypes directly:\n\n```typescript\nimport { useSWR } from 'swr'\nimport type { SWRConfiguration } from 'swr'\n\nconst config: SWRConfiguration = {\n  fallbackData: 'fallback',\n  revalidateOnMount: false\n  // ...\n}\n\nconst { data } = useSWR<string[]>('/api/data', fetcher, config)\n```\n\n## Middleware Types\n\nThere're some extra type definitions you can import to help adding types to your\ncustom middleware.\n\n```typescript\nimport useSWR, { Middleware, SWRHook } from 'swr'\n\nconst swrMiddleware: Middleware =\n  (useSWRNext: SWRHook) => (key, fetcher, config) => {\n    // ...\n    return useSWRNext(key, fetcher, config)\n  }\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/understanding.mdx",
    "content": "import { Video } from '@app/_components/video'\nimport { Callout } from 'nextra/components'\n\n# Understanding SWR\n\n## State Machine\n\n`useSWR` returns `data`, `error`, `isLoading`, and `isValidating` depending on\nthe state of the `fetcher` function. This diagrams describe how SWR returns\nvalues in some scenarios.\n\n### Fetch and Revalidate\n\nThis pattern is to fetch data and revalidate it later.\n\n![A pattern for fetch and revalidate](/img/understanding/fetch-and-revalidate.svg)\n\n### Key Change\n\nThis pattern is to fetch data and change the key and revalidate it later.\n\n![A pattern for key change](/img/understanding/key-change.svg)\n\n### Key Change + Previous Data\n\nThis pattern is to fetch data and change the key and revalidate it later with\nthe `keepPreviousData` option.\n\n![A pattern for key change + previous data](/img/understanding/key-change-previous-data.svg)\n\n### Fallback\n\nThis pattern is to fetch data and revalidate it later with fallback data.\n\n![A pattern for fallback](/img/understanding/fallback.svg)\n\n### Key Change + Fallback\n\nThis pattern is to fetch data and change the key and revalidate it later with\nfallback data.\n\n![A pattern for key change + fallback](/img/understanding/key-change-fallback.svg)\n\n### Key Change + Previous Data + Fallback\n\nThis pattern is to fetch data and change the key and revalidate it later with\nthe `keepPreviousData` option and fallback data.\n\n![A pattern for key change + previous data + fallback](/img/understanding/key-change-previous-data-fallback.svg)\n\n## Combining with isLoading and isValidating for better UX\n\nComparing to the existing `isValidating` value, `isLoading` is a new property\nthat can help you for the more general loading cases for UX.\n\n- `isValidating` becomes `true` whenever there is an ongoing request **whatever\n  the the data is loaded or not**\n- `isLoading` becomes `true` when there is an ongoing request and **data is not\n  loaded yet**.\n\nSimply saying you can use `isValidating` for indicating everytime there is an\nongoing revalidation, and `isLoading` for indicating that SWR is revalidating\nbut there is no data yet to display.\n\n<Callout emoji=\"📝\">\n  Fallback data and previous data are not considered \"loaded data,\" so when you\n  use fallback data or enable the keepPreviousData option, you might have data\n  to display.\n</Callout>\n\n```jsx\nfunction Stock() {\n  const { data, isLoading, isValidating } = useSWR(STOCK_API, fetcher, {\n    refreshInterval: 3000\n  })\n\n  // If it's still loading the initial data, there is nothing to display.\n  // We return a skeleton here.\n  if (isLoading) return <div className=\"skeleton\" />\n\n  // Otherwise, display the data and a spinner that indicates a background\n  // revalidation.\n  return (\n    <>\n      <div>${data}</div>\n      {isValidating ? <div className=\"spinner\" /> : null}\n    </>\n  )\n}\n```\n\n![An example of using the isLoading state](/img/understanding/isloading.gif)\n\nYou can find the code example\n[here](https://codesandbox.io/s/swr-isloading-jtopow)\n\n## Return previous data for better UX\n\nWhen doing data fetching based on continuous user actions, e.g. real-time search\nwhen typing, keeping the previous fetched data can improve the UX a lot.\n`keepPreviousData` is an option to enable that behavior. Here's a simple search\nUI:\n\n```jsx\nfunction Search() {\n  const [search, setSearch] = React.useState('');\n\n  const { data, isLoading } = useSWR(`/search?q=${search}`, fetcher, {\n    keepPreviousData: true\n  });\n\n  return (\n    <div>\n      <input\n        type=\"text\"\n        value={search}\n        onChange={(e) => setSearch(e.target.value)}\n        placeholder=\"Search...\"\n      />\n\n      <div className={isLoading ? \"loading\" : \"\"}>\n        {data?.products.map(item => <Product key={item.id} name={item.name} />)\n      </div>\n    </div>\n  );\n}\n```\n\nWith `keepPreviousData` enabled, you will still get the previous data even if\nyou change the SWR key and the data for the new key starts loading again.\n\n<Video\n  src=\"https://user-images.githubusercontent.com/3676859/163695903-a3eb1259-180e-41e0-821e-21c320201194.mp4\"\n  caption=\"Keep previous search results when keepPreviousData has been enabled\"\n  ratio={640 / 730}\n/>\n\nYou can find the full code for this example here:\nhttps://codesandbox.io/s/swr-keeppreviousdata-fsjz3m.\n\n## Dependency Collection for performance\n\nSWR only triggers re-rendering when the states used in the component have been\nupdated. If you only use `data` in the component, SWR ignores the updates of\nother properties like `isValidating`, and `isLoading`. This reduces rendering\ncounts a lot. More information can be found\n[here](/docs/advanced/performance#dependency-collection).\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/with-nextjs.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Usage with Next.js\n\n## Client Side Data Fetching\n\nIf your page contains frequently updating data, and you don't need to pre-render\nthe data, SWR is a perfect fit and no special setup needed: just import `useSWR`\nand use the hook inside any components that use the data.\n\nHere's how it works:\n\n- First, immediately show the page without data. You can show loading states for\n  missing data.\n- Then, fetch the data on the client side and display it when ready.\n\nThis approach works well for user dashboard pages, for example. Because a\ndashboard is a private, user-specific page, SEO is not relevant and the page\ndoesn't need to be pre-rendered. The data is frequently updated, which requires\nrequest-time data fetching.\n\n## Pre-rendering with Default Data\n\nIf the page must be pre-rendered, Next.js supports\n[2 forms of pre-rendering](https://nextjs.org/docs/basic-features/data-fetching):\n**Static Generation (SSG)** and **Server-side Rendering (SSR)**.\n\nTogether with SWR, you can pre-render the page for SEO, and also have features\nsuch as caching, revalidation, focus tracking, refetching on interval on the\nclient side.\n\nYou can use the `fallback` option of [`SWRConfig`](/docs/global-configuration)\nto pass the pre-fetched data as the initial value of all SWR hooks. For example\nwith `getStaticProps`:\n\n```jsx\nexport async function getStaticProps() {\n  // `getStaticProps` is executed on the server side.\n  const article = await getArticleFromAPI()\n  return {\n    props: {\n      fallback: {\n        '/api/article': article\n      }\n    }\n  }\n}\n\nfunction Article() {\n  // `data` will always be available as it's in `fallback`.\n  const { data } = useSWR('/api/article', fetcher)\n  return <h1>{data.title}</h1>\n}\n\nexport default function Page({ fallback }) {\n  // SWR hooks inside the `SWRConfig` boundary will use those values.\n  return (\n    <SWRConfig value={{ fallback }}>\n      <Article />\n    </SWRConfig>\n  )\n}\n```\n\nThe page is still pre-rendered. It's SEO friendly, fast to response, but also\nfully powered by SWR on the client side. The data can be dynamic and\nself-updated over time.\n\n<Callout>\n  The `Article` component will render the pre-generated data first, and after\n  the page is hydrated, it will fetch the latest data again to keep it refresh.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/en/docs/wrap-toc-items.mdx",
    "content": "# Wrap Table of Content Items Properly\n\nTests whether long table of content items are wrapped properly for alignment.\n\n## First Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Second Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n#### Third Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n## Fourth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Fifth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n## No Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Sixth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n"
  },
  {
    "path": "examples/swr-site/content/en/examples/_meta.ts",
    "content": "export default {\n  basic: 'Basic Usage',\n  auth: 'Authentication',\n  'infinite-loading': '',\n  'error-handling': '',\n  ssr: 'Next.js SSR'\n}\n"
  },
  {
    "path": "examples/swr-site/content/en/examples/auth.mdx",
    "content": "---\ntitle: Authentication\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-auth-tuqtf?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Authentication\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/en/examples/basic.mdx",
    "content": "---\ntitle: Basic Usage\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-basic-p7dg6?codemirror=1&fontsize=14&autoresize=1\"\n  className=\"mt-6 h-[calc(100dvh-var(--nextra-navbar-height))] w-full\"\n  title=\"SWR - Basic Usage\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/en/examples/error-handling.mdx",
    "content": "---\ntitle: Error Handling\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-states-4une7?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Error Handling\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/en/examples/full.mdx",
    "content": "<iframe\n  src=\"https://codesandbox.io/embed/swr-basic-p7dg6?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Basic Usage\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/en/examples/infinite-loading.mdx",
    "content": "---\ntitle: Infinite Loading\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-infinite-z6r0r?file=/src/App.js?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Infinite Loading\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/en/examples/ssr.mdx",
    "content": "---\ntitle: Next.js SSR\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-ssr-j9b2y?file=/pages/index.js?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Next.js SSR\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/en/foo.md",
    "content": "## before\n\n<details>\n  <summary>Details</summary>\n  <p>Something small enough to escape casual notice.</p>\n</details>\n\n## after\n\n```sh npm2yarn\nnpm i @graphql-eslint/eslint-plugin\n```\n"
  },
  {
    "path": "examples/swr-site/content/en/index.mdx",
    "content": "---\ntitle: React Hooks for Data Fetching\nsearchable: false\n---\n\nimport { Features } from '@app/_components/features'\nimport { Callout, Tabs } from 'nextra/components'\n\n# SWR\n\n<Features lang={props.params.lang} title={metadata.title} />\n\n<Tabs items={['JavaScript', 'C++', {label:'C', disabled: true}, 'Python', 'TypeScript', 'GraphQL', 'Rust', 'C#', 'Go', 'HTML', 'CSS', 'plaintext', 'bash']} defaultIndex={1}>\n  <Tabs.Tab>\n    ```js filename=\"hi.js\"\n    import { useState, useEffect } from 'react';\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```cpp filename=\"hi.cpp\"\n    #include <iostream>\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```c filename=\"hi.c\"\n    #include <stdio.h>\n    ```\n  </Tabs.Tab>\n  <Tabs.Tab>\n    ```c filename=\"hi.c\"\n    #include <stdio.h>\n    ```\n  </Tabs.Tab>\n</Tabs>\n\nThe name \"SWR\" is derived from `stale-while-revalidate`, a HTTP cache\ninvalidation strategy popularized by\n[HTTP RFC 5861](https://tools.ietf.org/html/rfc5861). SWR is a strategy to first\nreturn the data from cache (stale), then send the fetch request (revalidate),\nand finally come with the up-to-date data.\n\n<Callout emoji=\"✅\">\n  With SWR, components will get a stream of data updates **constantly** and\n  **automatically**.\n\nAnd the UI will be always **fast** and **reactive**.\n\n</Callout>\n\n<div className=\"mt-16 mb-20 text-center\">\n  [Get Started](/docs/getting-started) · [Examples](/examples/basic) ·\n  [Blog](/blog) · [GitHub Repository](https://github.com/vercel/swr)\n</div>\n\n## Overview\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user', fetcher)\n\n  if (error) return <div>failed to load</div>\n  if (!data) return <div>loading...</div>\n  return <div>hello {data.name}!</div>\n}\n```\n\n```diff\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user', fetcher)\n\n-  if (error) return <div>failed to load</div>\n+  if (!data) return <div>loading...</div>\n  return <div>hello {data.name}!</div>\n}\n```\n\nIn this example, the `useSWR` hook accepts a `key` string and a `fetcher`\nfunction. `key` is a unique identifier of the data (normally the API URL) and\nwill be passed to `fetcher`. `fetcher` can be any asynchronous function which\nreturns the data, you can use the native fetch or tools like Axios.\n\nThe hook returns 2 values: `data` and `error`, based on the status of the\nrequest.\n\n## Features\n\nWith just one single line of code, you can simplify the logic of data fetching\nin your project, and also have all these amazing features out-of-the-box:\n\n- **Fast**, **lightweight** and **reusable** data fetching\n- Built-in **cache** and request deduplication\n- **Real-time** experience\n- Transport and protocol agnostic\n- SSR / ISR / SSG support\n- TypeScript ready\n- React Native\n\nSWR has you covered in all aspects of speed, correctness, and stability to help\nyou build better experiences:\n\n- Fast page navigation\n- Polling on interval\n- Data dependency\n- Revalidation on focus\n- Revalidation on network recovery\n- Local mutation (Optimistic UI)\n- Smart error retry\n- Pagination and scroll position recovery\n- React Suspense\n\nAnd a lot [more](/docs/getting-started).\n\n## Community\n\n<p className=\"mt-6 flex h-6 gap-2\">\n  <img alt=\"stars\" src=\"https://badgen.net/github/stars/vercel/swr\" />\n  <img alt=\"downloads\" src=\"https://badgen.net/npm/dt/swr\" />\n  <img alt=\"license\" src=\"https://badgen.net/npm/license/swr\" />\n</p>\n\nSWR is created by the same team behind [Next.js](https://nextjs.org), the React\nframework. Follow [@vercel](https://twitter.com/vercel) on Twitter for future\nproject updates.\n\nFeel free to join the\n[discussions on GitHub](https://github.com/vercel/swr/discussions)!\n"
  },
  {
    "path": "examples/swr-site/content/en/test.md",
    "content": "# Hello!\n\nThis is an MD file instead of MDX, which means you can use syntax like this:\n\n```md\n<!-- this is a comment -->\n```\n\n<!-- this is a comment -->\n\nHowever, no JSX is allowed here.\n"
  },
  {
    "path": "examples/swr-site/content/es/_meta.ts",
    "content": "import meta from '../en/_meta'\n\nexport default {\n  index: meta.index,\n  docs: {\n    ...meta.docs,\n    title: 'Documentación'\n  },\n  examples: {\n    ...meta.examples,\n    title: 'Ejemplos'\n  },\n  about: meta.about\n}\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/_meta.ts",
    "content": "export default {\n  'getting-started': 'Comienza',\n  options: 'Opciones',\n  'global-configuration': 'Configuración Global',\n  'data-fetching': 'Obtención De Datos',\n  'error-handling': 'Gestión De Errores',\n  revalidation: 'Revalidación Automática',\n  'conditional-fetching': 'Obtención De Datos Condicional',\n  arguments: 'Argumentos',\n  mutation: 'Mutación',\n  pagination: 'Paginación',\n  prefetching: 'Prefetching',\n  'with-nextjs': 'Next.js SSG and SSR',\n  suspense: 'Suspense',\n  advanced: 'Avanzado',\n  'change-log': 'Registro de cambios',\n  'wrap-toc-items': 'Ajustar elementos de la tabla de contenido'\n}\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/advanced/_meta.ts",
    "content": "export default {\n  performance: 'Rendimiento',\n  'file-name.with.DOTS': 'Nombres de archivos con puntos'\n}\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/advanced/file-name.with.DOTS.mdx",
    "content": "# Puede agregar puntos en los nombres de sus archivos\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/advanced/performance.mdx",
    "content": "# Rendimiento\n\nSWR proporciona una funcionalidad crítica en todo tipo de aplicaciónes web, por\nlo que el **rendimiento** es una prioridad absoluta.\n\nSWR's tiene **caché** incorporado y la\n**[deduplicación](/advanced/performance#deduplication)** evitan las solicitudes\nde red innecesarias, pero el rendimiento del propio hook `useSWR` sigue siendo\nimportante. En una aplicación compleja, puede haber cientos de llamadas `useSWR`\nen una solo página.\n\nSWR asegura que su aplicación tiene:\n\n- _no hay peticiones de red innecesarias_\n- _no hay renderizado innecesarios_\n- _no se importa código innecesario_\n\nsin ningún cambio de código por su parte.\n\n## Deduplicación\n\nEs muy común reutilizar los hooks SWR en tu aplicación. Por ejemplo, una\naplicación que muestra el avatar del usuario actual 5 veces:\n\n```jsx\nfunction useUser() {\n  return useSWR('/api/user', fetcher)\n}\n\nfunction Avatar() {\n  const { data, error } = useUser()\n  if (error) return <Error />\n  if (!data) return <Spinner />\n\n  return <img src={data.avatar_url} />\n}\n\nfunction App() {\n  return (\n    <>\n      <Avatar />\n      <Avatar />\n      <Avatar />\n      <Avatar />\n      <Avatar />\n    </>\n  )\n}\n```\n\nCada componente `<Avatar>` tiene un hook `useSWR` en su interior. Dado que\ntienen el mismo key SWR y que se renderizan casi al mismo tiempo, **sólo se hará\n1 solicitud de red**.\n\nSe pueden reutilizar los hooks de datos (como `useUser` en el ejemplo anterior)\nen todas partes, sin preocuparse por el rendimiento o las peticiones duplicadas.\n\nTambién existe la [opción `dedupingInterval`](/docs/options) para anular el\nintervalo de deduplicación por defecto.\n\n## Comparación profunda\n\nSWR por defecto tiene **deep compares** al cambio de datos. Si el valor de\n`data` no ha cambiado, no se activará una nueva renderización.\n\nTambién puede personalizar la función de comparación mediante la\n[opción `compare`](/docs/options) si quieres cambiar el comportamiento. Por\nejemplo, algunas respuestas de la API devuelven una marca de tiempo del servidor\nque tal vez quiera excluir de la difusión de datos.\n\n## Colección de dependencias\n\n`useSWR` devuelve 3 valores de **estado**: `data`, `error` y `isValidating` cada\nuno de ellos puede actualizarse de forma independientemente. Por ejemplo, si\nimprimimos esos valores dentro de un ciclo de vida completo de obtención de\ndatos, será algo como esto:\n\n```jsx\nfunction App() {\n  const { data, error, isValidating } = useSWR('/api', fetcher)\n  console.log(data, error, isValidating)\n  return null\n}\n```\n\nEn el peor de los casos (si la primera solicitud falló, entonces el reintento\nfue exitoso). Se verán 4 líneas de registros:\n\n```js\n// console.log(data, error, isValidating)\n\nundefined undefined true  // => start fetching\nundefined Error false     // => end fetching, got an error\nundefined Error true      // => start retrying\nData undefined false      // => end retrying, get the data\n```\n\nLos cambios de estado tienen sentido. Pero eso también significa que nuestro\ncomponente se **renderizo 4 veces.**\n\nSi cambiamos nuestro componente para usar solo `data`:\n\n```jsx\nfunction App() {\n  const { data } = useSWR('/api', fetcher)\n  console.log(data)\n  return null\n}\n```\n\nLa magia ocurre - ahora solo hay **2 rederizaciones**:\n\n```js\n// console.log(data)\nundefined // => hydration / initial render\nData // => end retrying, get the data\n```\n\nEl mismo proceso ha ocurrido internamente, hubo un error de la primera\nsolicitud, entonces tenemos los datos del reintento. Sin embargo, **SWR sólo\nactualiza los estados que utiliza el componente**, que ahora sólo es `data`.\n\nSi no se utilizan siempre estos 3 estados, ya se está beneficiando de esta\nfunción. En [Vercel](https://vercel.com), esta optimización se traduce en un 60%\nmenos de repeticiones.\n\n## Tree Shaking\n\nEl paquete SWR es [tree-shakeable](https://webpack.js.org/guides/tree-shaking) y\nno tiene efectos secundarios. Esto significa que si sólo se importa `useSWR`\ncore API, las APIs no utilizadas, como `useSWRInfinite`, no se incluirán en la\naplicación.\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/arguments.mdx",
    "content": "# Argumentos\n\nPor defecto, `key` se pasará a `fetcher` como argumento. Así que las siguientes\n3 expresiones son equivalentes:\n\n```js\nuseSWR('/api/user', () => fetcher('/api/user'))\nuseSWR('/api/user', url => fetcher(url))\nuseSWR('/api/user', fetcher)\n```\n\n## Argumentos múltiples\n\nEn algunos escenarios, es útil pasar múltiples argumentos (puede pasar cualquier\nvalor u objeto) a la función `fetcher`. Por ejemplo una solicitud de obtención\nautorizada:\n\n```js\nuseSWR('/api/user', url => fetchWithToken(url, token))\n```\n\nEsto es **incorrecto**. Dado que el identificador (también la key del caché) de\nlos datos es `'/api/user'`, incluso si el token cambia, SWR seguirá utilizando\nla misma key y devolverá los datos incorrectos.\n\nEn su lugar, puedes utilizar un **array** como parámetro `key`, que contiene\nmúltiples argumentos de `fetcher`:\n\n```js\nconst { data: user } = useSWR(['/api/user', token], fetchWithToken)\n```\n\nLa función `fetchWithToken` sigue aceptando los mismo 2 argumentos, pero ahora\nla key del caché también estará asociada al `token`.\n\n## Pasar objectos\n\nimport { Callout } from 'nextra/components'\n\n<Callout>\n  Since SWR 1.1.0, object-like keys will be serialized under the hood\n  automatically.\n</Callout>\n\nSay you have another function that fetches data with a user scope:\n`fetchWithUser(api, user)`. You can do the following:\n\n```js\nconst { data: user } = useSWR(['/api/user', token], fetchWithToken)\n\n// ...and then pass it as an argument to another useSWR hook\nconst { data: orders } = useSWR(\n  user ? ['/api/orders', user] : null,\n  fetchWithUser\n)\n```\n\nYou can directly pass an object as the key, and `fetcher` will receive that\nobject too:\n\n```js\nconst { data: orders } = useSWR({ url: '/api/orders', args: user }, fetcher)\n```\n\n<Callout type=\"warning\">\n  In older versions (< 1.1.0), SWR **shallowly** compares the arguments on every render, and triggers revalidation if any of them has changed.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/change-log.mdx",
    "content": "import Markdown from 'markdown-to-jsx'\n\nexport async function ReleasesRenderer() {\n  const releases = await fetch(\n    `https://api.github.com/repos/vercel/swr/releases`\n  ).then(res => res.json())\n  return (\n    <Markdown>\n      {releases\n        // we keep the most recent 5 releases here\n        .slice(0, 5)\n        .map(release => {\n          const body = release.body\n            .replace(/&#39;/g, \"'\")\n            .replace(\n              /@([a-zA-Z0-9_-]+)(?=(,| ))/g,\n              '<a href=\"https://github.com/$1\" target=\"_blank\" rel=\"noopener\">@$1</a>'\n            )\n          return `## <a href=\"${\n            release.html_url\n          }\" target=\"_blank\" rel=\"noopener\">${release.tag_name}</a>\nPublicado en ${new Date(release.published_at).toLocaleDateString(\n            'es'\n          )}.\\n\\n${body}`\n        })\n        .join('\\n\\n')}\n    </Markdown>\n  )\n}\n\n# Registro de cambios\n\nSe puede visitar [SWR release page](https://github.com/vercel/swr/releases) para\nver todo el historial de lanzamientos.\n\n<ReleasesRenderer />\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/conditional-fetching.md",
    "content": "# Búsqueda Condicional\n\n## Condicional\n\nUtilice `null` o pase una función como `key` para obtener datos de forma\ncondicional. Si la función lanza o devuelve un falsy value, SWR no iniciará la\npetición.\n\n```js\n// conditionally fetch\nconst { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)\n\n// ...o devuelve un falsy value\nconst { data } = useSWR(() => (shouldFetch ? '/api/data' : null), fetcher)\n\n// ...o lanza un error cuando user.id no está definifo\nconst { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)\n```\n\n## Dependiente\n\nSWR también permite obtener datos que dependen de otros datos. Garantiza el\nmáximo paralelismo posible (evitando las cascadas), así como la obtención en\nserie cuando se necesita un dato dinámico para que se produzca la siguiente\nobtención de datos.\n\n```js\nfunction MyProjects() {\n  const { data: user } = useSWR('/api/user')\n  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)\n  // Al pasar una función, SWR utilizará el valor devuelto\n  // como `key`. Si la función lanza o devuelve\n  // falsy, SWR sabrá que algunas dependencias no estan\n  // ready. En este caso `user.id` lanza cuando `user`\n  // no este cargado.\n\n  if (!projects) return 'loading...'\n  return 'You have ' + projects.length + ' projects'\n}\n```\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/data-fetching.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Obtención De Datos\n\n```js\nconst { data, error } = useSWR(key, fetcher)\n```\n\nEsta es la API fundamental de SWR. El `fetcher` aquí es una función asíncrona\nque **acepta el `key`** de SWR, y devuelve los datos.\n\nEl valor devuelto será pasado como `data`, y si lanza, será capturado como\n`error`.\n\n<Callout>\n  Tenga en cuenta que el `fetcher` puede ser omitido de los parámetros si se\n  [proporciona globalmente](/docs/global-configuration).\n</Callout>\n\n## Fetch\n\nPuedes utilizar cualquier librería para manejar data fetching, por ejemplo un\n`fetch` polyfill [developit/unfetch](https://github.com/developit/unfetch):\n\n```js\nimport fetch from 'unfetch'\n\nconst fetcher = url => fetch(url).then(r => r.json())\n\nfunction App() {\n  const { data, error } = useSWR('/api/data', fetcher)\n  // ...\n}\n```\n\n<Callout>\n  Si estás usando **Next.js**, no necesita importar este polyfill:\n\n[Nuevos Polyfills Incorporados: fetch(), URL, y Object.assign](https://nextjs.org/blog/next-9-1-7#new-built-in-polyfills-fetch-url-and-objectassign)\n\n</Callout>\n\n## Axios\n\n```js\nimport axios from 'axios'\n\nconst fetcher = url => axios.get(url).then(res => res.data)\n\nfunction App() {\n  const { data, error } = useSWR('/api/data', fetcher)\n  // ...\n}\n```\n\n## GraphQL\n\nO utilizando GraphQL con librerías como\n[graphql-request](https://github.com/prisma-labs/graphql-request):\n\n```js\nimport { request } from 'graphql-request'\n\nconst fetcher = query => request('/api/graphql', query)\n\nfunction App() {\n  const { data, error } = useSWR(\n    /* GraphQL */ `\n      {\n        Movie(title: \"Inception\") {\n          releaseDate\n          actors {\n            name\n          }\n        }\n      }\n    `,\n    fetcher\n  )\n  // ...\n}\n```\n\n_Si quiere pasar variables a una query GraphQL, consulte\n[Argumentos múltiples](/docs/arguments)._\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/error-handling.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Gestión De Errores\n\nSi se lanza un error dentro del [`fetcher`](/docs/data-fetching), será devuelto\ncomo `error` por el hook.\n\n```js\nconst fetcher = url => fetch(url).then(r => res.json())\n\n// ...\nconst { data, error } = useSWR('/api/user', fetcher)\n```\n\nEl objeto `error` será definido si la promise de fetch es rechazada.\n\n## Código de estado y objeto de error\n\nA veces queremos que una API devuelva un objeto de error junto con el status\ncode. Ambos son útiles para el cliente.\n\nPodemos personanilizar nuestro `fetcher` para que devuelve más información. Si\nel status code no es `2xx`, lo consideramos un error aunque se pueda analizar\ncomo JSON:\n\n```js\nconst fetcher = async url => {\n  const res = await fetch(url)\n\n  // Si el status code no esta en el rango 200-299,\n  // seguimos intentando analizarlo y lanzarlo.\n  if (!res.ok) {\n    const error = new Error('An error occurred while fetching the data.')\n    // Adjunta información extra al objeto de error.\n    error.info = await res.json()\n    error.status = res.status\n    throw error\n  }\n\n  return res.json()\n}\n\n// ...\nconst { data, error } = useSWR('/api/user', fetcher)\n// error.info === {\n//   message: \"You are not authorized to access this resource.\",\n//   documentation_url: \"...\"\n// }\n// error.status === 403\n```\n\n<Callout>\n  Tenga en cuenta que `data` y `error` pueden existir al mismo tiempo. Por lo\n  tanto la UI puede mostrar data existente, mientras se sabe que la próxima\n  solicitud ha fallado.\n</Callout>\n\n[Aquí](/examples/error-handling) tenemos un ejemplo.\n\n## Reintento de error\n\nSWR utiliza el\n[exponential backoff algorithm](https://en.wikipedia.org/wiki/Exponential_backoff)\npara reintentar la solicitud en el error. El algoritmo permite que la aplicación\nse recupere de los errores rápidamente, pero si malgastar recursos reintentando\ncon demasiada frecuencia.\n\nTambién podemos anular este comportamiento mediante la opción\n[onErrorRetry](/docs/options#options):\n\n```js\nuseSWR('/api/user', fetcher, {\n  onErrorRetry: (error, key, config, revalidate, { retryCount }) => {\n    // Never retry on 404.\n    if (error.status === 404) return\n\n    // Never retry for a specific key.\n    if (key === '/api/user') return\n\n    // Only retry up to 10 times.\n    if (retryCount >= 10) return\n\n    // Retry after 5 seconds.\n    setTimeout(() => revalidate({ retryCount }), 5000)\n  }\n})\n```\n\nEste callback le da flexibilidad de reintentar basado en varias condiciones.\nTambién puede desactivar estableciendo `shouldRetryOnError: false`.\n\nTambién es posible propocionar a través del\n[Global Configuration](/docs/global-configuration) context.\n\n## Informe global de errores\n\nSiempre puedes obtener el objeto de `error` dentro del componente de forma\nreactiva. Pero en caso de que quieras manejar el error de forma global, para\nnotificar a la UI que muestre un [toast](https://vercel.com/design/toast) o un\n[snackbar](https://material.io/components/snackbars), o reportarlo en algún\nlugar como [Sentry](https://sentry.io), hay un evento\n[`onError`](/docs/options#options):\n\n```jsx\n<SWRConfig\n  value={{\n    onError: (error, key) => {\n      if (error.status !== 403 && error.status !== 404) {\n        // Podemos enviar el error a Sentry\n        // o mostrarlo una notificación UI.\n      }\n    }\n  }}\n>\n  <MyApp />\n</SWRConfig>\n```\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/getting-started.mdx",
    "content": "import { Callout, Steps } from 'nextra/components'\n\n# Comienza\n\n<details>\n  <summary>**111** 111</summary>\n  content line 1 some more content\n  <details>\n    <summary>**222** 222</summary>\n    content line 2 some more content\n    <details>\n      <summary>**333** 333</summary>\n      content line 3 some more content\n    </details>\n  </details>\n</details>\n\n## Instalación\n\n<Steps>\n\n### Dentro del directorio de su proyecto React, ejecute lo siguiente:\n\n```sh npm2yarn\nnpm i swr\n```\n\n</Steps>\n\n## Inicio rápido\n\nPara APIs RESTFul normales con datos JSON, primero necesita crear una función\n`fethcer`, que no es más que una envoltura del `fetch` nativo:\n\n```jsx\nconst fetcher = (...args) => fetch(...args).then(res => res.json())\n```\n\n<Callout>\n  Si tu quieres usar API GraphQL o librerías como Axios, puedes crear tu propia\n  función fetcher. Consulta [aqui](/docs/data-fetching) para ver más ejemplos.\n</Callout>\n\nLuego puede importar `useSWR` y empezar a usarlo dentro de cualquier componente\nde la función:\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user/123', fetcher)\n\n  if (error) return <div>failed to load</div>\n  if (!data) return <div>loading...</div>\n\n  // renderizar datos\n  return <div>hello {data.name}!</div>\n}\n```\n\nNormalmente, hay 3 estados posibles de una solicitud: \"loading\", \"ready\", o\n\"error\". Puedes utilizar el valor `data` y `error` para determinar el estadado\nactual de la solicitud, y devolver la UI correspondiente.\n\n## Hágalo reutilizable\n\nCuando construye una aplicación web, es posible que haya que reutilizar los\ndatos en muchos lugares de la UI. Es increíblemente fácil crear hooks de datos\nreutilizables sobre SWR:\n\n```jsx\nfunction useUser(id) {\n  const { data, error } = useSWR(`/api/user/${id}`, fetcher)\n\n  return {\n    user: data,\n    isLoading: !error && !data,\n    isError: error\n  }\n}\n```\n\nY utilícelo en sus componentes:\n\n```jsx\nfunction Avatar({ id }) {\n  const { user, isLoading, isError } = useUser(id)\n\n  if (isLoading) return <Spinner />\n  if (isError) return <Error />\n  return <img src={user.avatar} />\n}\n```\n\nAl adoptar este patrón, puede olvidarse del **fetching** de datos de forma\nimperativa: inicie la solicitud, actualice el estado de carga, y devuelve el\nresultado final. En cambio, su código es más declarativo: solo hay que\nespecificar qué datos utiliza el componente.\n\n## Ejemplo\n\nEn un ejemplo del mundo real, nuestro sitio web muestra una barra de navegación\ny el contenido, ambos dependen del `user`:\n\nimport { WelcomeImage } from '@app/_icons'\n\n<WelcomeImage className=\"mt-6 dark:invert\" />\n\nTradicionalmente, obtenemos los datos una vez utilizando `useEffect` en el\ncomponente de nivel superiror, y pasarlo a los componentes hijos a través de\nprops (fíjate que por ahora no manejamos el estado de error):\n\n```jsx {7-11,17,18,27}\n// componente de la página\n\nfunction Page() {\n  const [user, setUser] = useState(null)\n\n  // obtener datos\n  useEffect(() => {\n    fetch('/api/user')\n      .then(res => res.json())\n      .then(data => setUser(data))\n  }, [])\n\n  // estado de carga global\n  if (!user) return <Spinner />\n\n  return (\n    <div>\n      <Navbar user={user} />\n      <Content user={user} />\n    </div>\n  )\n}\n\n// componentes hijos\n\nfunction Navbar({ user }) {\n  return (\n    <div>\n      ...\n      <Avatar user={user} />\n    </div>\n  )\n}\n\nfunction Content({ user }) {\n  return <h1>Welcome back, {user.name}</h1>\n}\n\nfunction Avatar({ user }) {\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\nPor lo general, necesitamos mantener todos los datos que se obtienen en el\ncomponente de nivel superiror y añadir las props a cada componente dentro del\nárbol. El código será más difícil de mantener si añadimos más dependencia de\ndatos a la página.\n\nAunque podamos evitar pasar props usando\n[Context](https://reactjs.org/docs/context.html), sigue existiendo problema con\nel contenido dinámico: Los componentes dentro del contenido de la página pueden\nser dinámicos, y componente de nivel superiror puede no saber qué datos\nnecesitarán sus componentes hijos.\n\nSWR resuelve el problema perfectamente, Con el hook `useUser` que acabamos de\ncrear, el código puede ser refactorizado a:\n\n```jsx {20,26}\n// componente de la página\n\nfunction Page() {\n  return (\n    <div>\n      <Navbar />\n      <Content />\n    </div>\n  )\n}\n\n// componentes hijos\n\nfunction Navbar() {\n  return (\n    <div>\n      ...\n      <Avatar />\n    </div>\n  )\n}\n\nfunction Content() {\n  const { user, isLoading } = useUser()\n  if (isLoading) return <Spinner />\n  return <h1>Welcome back, {user.name}</h1>\n}\n\nfunction Avatar() {\n  const { user, isLoading } = useUser()\n  if (isLoading) return <Spinner />\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\nLos datos ahora estan vinculados a los componentes que los necesitan, y todos\nlos componentes son independientes entre sí. Todo los componentes padre no\nnecesitan saber nada sobre los datos o el paso del mismo. Sólo se renderizaran.\nEl código es mucho más sencillo y fácil de mantener ahora.\n\nLo más bonito es que sólo se enviará **1 request** a la API, porque utilizan la\nmisma clave de SWR y la solicitud se **desduplica**, se almacena en **caché** y\nse **comparte** automáticamente.\n\nTambién, la aplicación tiene ahora la capacidad de volver a obtener los datos\ncuando [el usuario se centra o se reconecta a la red!](/docs/revalidation) Esto\nsignifica que, cuando el laptop del usuario se despierte de la suspeción o\ncambie de pestaña del navegador, los datos se actualizarán automáticamente.\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/global-configuration.md",
    "content": "# Configuración Global\n\nEl contexto `SWRConfig` puede proporcionar configuraciones globales\n([opciones](/docs/options)) para todos los hooks de SWR.\n\n```jsx\n<SWRConfig value={options}>\n  <Component />\n</SWRConfig>\n```\n\nEn este ejemplo, todos los hooks de SWR utilizarán el mismo fetcher\nproporcionando para cargar datos JSON, y se actualizarán cada 3 segundos por\ndefecto:\n\n```jsx\nimport useSWR, { SWRConfig } from 'swr'\n\nfunction Dashboard() {\n  const { data: events } = useSWR('/api/events')\n  const { data: projects } = useSWR('/api/projects')\n  const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // override\n\n  // ...\n}\n\nfunction App() {\n  return (\n    <SWRConfig\n      value={{\n        refreshInterval: 3000,\n        fetcher: (resource, init) =>\n          fetch(resource, init).then(res => res.json())\n      }}\n    >\n      <Dashboard />\n    </SWRConfig>\n  )\n}\n```\n\n## Extra APIs\n\n### Cache Provider\n\nBesides all the [options](/docs/options) listed, `SWRConfig` also accepts an\noptional `provider` function. Please refer to the [Cache](/docs/cache) section\nfor more details.\n\n```jsx\n<SWRConfig value={{ provider: () => new Map() }}>\n  <Dashboard />\n</SWRConfig>\n```\n\n### Access To Global Configurations\n\nYou can use the `useSWRConfig` hook to get the global configurations, as well as\n[`mutate`](/docs/mutation) and [`cache`](/docs/advanced/cache):\n\n```jsx\nimport { useSWRConfig } from 'swr'\n\nfunction Component() {\n  const { refreshInterval, mutate, cache, ...restConfig } = useSWRConfig()\n\n  // ...\n}\n```\n\nNested configurations will be extended. If no `<SWRConfig>` is used, it will\nreturn the default ones.\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/mutation.md",
    "content": "# Mutación\n\n## Revalidar\n\nYou can get the `mutate` function from the `useSWRConfig()` hook, and broadcast\na revalidation message globally to other SWR hooks<sup>\\*</sup> using the same\nkey by calling `mutate(key)`.\n\nEste ejemplo muestra cómo recuperar automáticamente la información de login (por\nejemplo, dentro de `<Profile>`) cuando el usuario hace clic en el botón\n\"Logout\".\n\n```jsx\nimport useSWR, { useSWRConfig } from 'swr'\n\nfunction App() {\n  const { mutate } = useSWRConfig()\n\n  return (\n    <div>\n      <Profile />\n      <button\n        onClick={() => {\n          // establecer la cookie como caduca\n          document.cookie =\n            'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'\n\n          // indicar a todos SWRs con esta key que se revaliden\n          mutate('/api/user')\n        }}\n      >\n        Logout\n      </button>\n    </div>\n  )\n}\n```\n\n## Mutación y solicitud POST\n\nEn muchos casos, la aplicación de mutations locales a los datos es una buena\nforma de agilizar los cambios, sin necesidad de esperar a la fuente de datos\nremota.\n\nCon `mutate`, puedes actualizar tus datos locales mediante programación,\nmientras los revalidas y finalmente los sustituyes por los datos más recientes.\n\n```jsx\nimport useSWR, { useSWRConfig } from 'swr'\n\nfunction Profile() {\n  const { mutate } = useSWRConfig()\n  const { data } = useSWR('/api/user', fetcher)\n\n  return (\n    <div>\n      <h1>My name is {data.name}.</h1>\n      <button\n        onClick={async () => {\n          const newName = data.name.toUpperCase()\n\n          // actualiza los datos locales inmediatamente, pero desactiva la revalidación\n          mutate('/api/user', { ...data, name: newName }, false)\n\n          // envía una solicitud a la API para actualizar la fuente\n          await requestUpdateUsername(newName)\n\n          // activar una revalidación (refetch) para asegurarse de que nuestros datos locales son correctos\n          mutate('/api/user')\n        }}\n      >\n        Uppercase my name!\n      </button>\n    </div>\n  )\n}\n```\n\nAl hacer click en el botón del ejemplo anterior, se actualizarán localmente los\ndatos del cliente, se enviará una solicitud POST para modificar los datos\nremotos y se intentará obtener la última (revalidar).\n\nPero muchas APIs POST simplemente devolverán los datos actualizados\ndirectamente, por lo que no necesitamos revalidar de nuevo. Aquí hay un ejemplo\nque muestra el uso de \"local mutate - request - update\":\n\n```jsx\nmutate('/api/user', newUser, false) // utilice `false` para mutate sin revalidar\nmutate('/api/user', updateUser(newUser), false) // `updateUser` es una Promise de la solicitud,\n// que devuelve el update document\n```\n\n## Mutar basándose en los datos actuales\n\nA veces, se desea actualizar una parte de los datos en función de los datos\nactuales.\n\nCon `mutate`, puedes pasar una función asíncrona que recibirá el valor actual de\nla caché, si lo hay, y devolverá un updated document.\n\n```jsx\nmutate('/api/todos', async todos => {\n  // actualicemos la tarea con ID `1` para que se complete,\n  // esta API devuelve los datos acutualizado\n  const updatedTodo = await fetch('/api/todos/1', {\n    method: 'PATCH',\n    body: JSON.stringify({ completed: true })\n  })\n\n  // filtrar la lista y devolverla con el item actualizado\n  const filteredTodos = todos.filter(todo => todo.id !== '1')\n  return [...filteredTodos, updatedTodo]\n})\n```\n\n## Datos devueltos por Mutate\n\nLo más probable es que necesites algunos datos para actualizar la caché. Los\ndatos se resuelven o se devuelven desde la promise o función asíncrona que\npasaste para `mutate`.\n\nLa función devolverá update document para que `mutate` actualice el valor de la\ncaché correspondiente. Podría arrojar un error de alguna manera, cada vez que se\nllame.\n\n```jsx\ntry {\n  const user = await mutate('/api/user', updateUser(newUser))\n} catch (error) {\n  // Manejar un error al actualizar el user aquí\n}\n```\n\n## Bound Mutate\n\nEl objeto SWR devuelto por `useSWR` también contiene una función `mutate()` que\nestá atada a la key del SWR.\n\nEs funcionalmente equivalente a la función global `mutate` pero no requiere el\nparámetro `key`.\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, mutate } = useSWR('/api/user', fetcher)\n\n  return (\n    <div>\n      <h1>My name is {data.name}.</h1>\n      <button\n        onClick={async () => {\n          const newName = data.name.toUpperCase()\n          // enviar una solicitud a la API para actualizar los datos\n          await requestUpdateUsername(newName)\n          // actualizar los datos locales inmediatamente y revalidar (refetch)\n          // NOTA: la key no es necesaria cuando se utiliza el mutate de useSWR, es pre-bound\n          mutate({ ...data, name: newName })\n        }}\n      >\n        Uppercase my name!\n      </button>\n    </div>\n  )\n}\n```\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/options.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# API Options\n\n```js\nconst { data, error, isValidating, mutate } = useSWR(key, fetcher, options)\n```\n\n## Parámetros\n\n- `key`: un string key único para la solicitud (o una función / array / null)\n  [(uso avanzado)](/docs/conditional-fetching)\n- `fetcher`: (_opcional_) una función que devuelve una Promise para recuperar\n  sus datos [(detalles)](/docs/data-fetching)\n- `options`: (_opcional_) un objecto de opciónes para el hook useSWR\n\n## Valores devueltos\n\n- `data`: data de la key dada resueltos por el `fetcher` (o undefined si no está\n  cargado)\n- `error`: error lanzado por el `fetcher` (o undefined)\n- `isValidating`: si hay una solicitud o carga de revalidación\n- `mutate(data?, shouldRevalidate?`: función para mutar los datos en caché\n  [(detalles)](/docs/mutation)\n\n## Opciónes\n\n- `suspense = false`: activar el modo React Suspense\n  [(detalles)](/docs/suspense)\n- `fetcher(args)`: la fetcher función\n- `revalidateIfStale = true`: automatic revalidation on mount even if there is\n  stale data [(details)](/docs/revalidation#disable-automatic-revalidations)\n- `revalidateOnMount`: activar o desactivar la revalidación automática cuando se\n  monta el componente\n- `revalidateOnFocus = true`: revalidación automática cuanto window gets focused\n  [(detalles)](/docs/revalidation)\n- `revalidateOnReconnect = true`: revalidación automática cuando el navegador\n  recupera la conexión a la red (a través de `navigator.onLine`)\n  [(detalles)](/docs/revalidation)\n- `refreshInterval` [(detalles)](/docs/revalidation):\n  - desactivado por defecto: `refreshInterval = 0`\n  - If set to a number, polling interval\n  - If set to a function, the function will receive the latest data and should\n    return the interval in milliseconds\n- `refreshWhenHidden = false`: polling cuando window es invisible (si\n  `refreshInterval` está activado)\n- `refreshWhenOffline = false`: polling cuando el navegador está desconectado\n  (determinado por `navigator.onLine`)\n- `shouldRetryOnError = true`: reitentar cuando el fetcher tiene un error\n- `dedupingInterval = 2000`: solicitudes de deduplicación con la misma key en\n  este lapso de tiempo\n- `focusThrottleInterval = 5000`: sólo revalidar una vez durante un periodo de\n  tiempo\n- `loadingTimeout = 3000`: tiempo de espera para activar el evento onLoadingSlow\n- `errorRetryInterval = 5000`: error retry interval\n- `errorRetryCount`: número máximo de reintentos de error\n- `fallback`: a key-value object of multiple fallback data\n  [(example)](/docs/with-nextjs)\n- `fallbackData`: datos iniciales a devolver (nota: Esto es por un hook)\n- `onLoadingSlow(key, config)`: función callback cuando una petición tarda\n  demasiado en cargase (véase: `loadingTimeout`)\n- `onSuccess(data, key, config)`: función callback cuando una petición termina\n  con éxito\n- `onError(err, key, config)`: función callback cuando una petición devuelve un\n  error\n- `onErrorRetry(err, key, config, revalidate, revalidateOps)`: manejador para el\n  reintento de error\n- `compare(a, b)`: función de comparación utilizada para detectar cuando los\n  datos devueltos han cambiado, para evitar spurious rerenders. Por defecto, se\n  utiliza [dequal](https://github.com/lukeed/dequal).\n- `isPaused()`: para detectar si pause revalidations, ignorará los datos\n  obtenidos y los errores cuando devuelva `true`. Devuelve `false` por defecto.\n- `use`: array of middleware functions [(details)](/docs/middleware)\n\n<Callout>\n  Cuando una red lenta (2G, {'<='} 70Kbps), `errorRetryInterval` serian 10\n  segundos, y `loadingTimeout` serian 5 segundos por defecto.\n</Callout>\n\nTambién puede utilizar la [configuración global](/docs/global-configuration)\npara proporcionar opciónes por defecto.\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/pagination.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Paginación\n\n<Callout emoji=\"✅\">\n  Por favor, actualice a la última versión (≥ 0.3.0) para utilizar esta API. La\n  anterior API `useSWRPages` ha quedado obsoleta.\n</Callout>\n\nSWR proporciona una API dedicada `useSWRInfinite` para admitir patrones de UI\ncomunes como la **paginación** y la **carga infinita**.\n\n## Cuándo utilizar `useSWR`\n\n### Paginación\n\nEn primer lugar, es posible que **NO** necesitemos `useSWRInfinite`, sino que\npodemos utilizar simplemente `useSWR` si estamos construyendo algo como esto:\n\nimport { PaginationImage } from '@app/_icons'\n\n<PaginationImage className=\"mt-6 dark:invert\" />\n\n...que es un típico UI de paginación. Veamos cómo se puede implementar\nfácilmente con `useSWR`:\n\n```jsx {5}\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  // La URL de la API incluye el índice de la página, que es un React state.\n  const { data } = useSWR(`/api/data?page=${pageIndex}`, fetcher)\n\n  // ... manejar los estados de carga y error\n\n  return (\n    <div>\n      {data.map(item => (\n        <div key={item.id}>{item.name}</div>\n      ))}\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>\n    </div>\n  )\n}\n```\n\nAdemás, podemos crear una abstracción para este \"page component\":\n\n```jsx {13}\nfunction Page({ index }) {\n  const { data } = useSWR(`/api/data?page=${index}`, fetcher)\n\n  // ... manejar los estados de carga y error\n\n  return data.map(item => <div key={item.id}>{item.name}</div>)\n}\n\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  return (\n    <div>\n      <Page index={pageIndex} />\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>\n    </div>\n  )\n}\n```\n\nGracias a la caché de SWR, tenemos la ventaja de precargar la siguiente página.\nLa página siguiente se presenta dentro de un hidden div, por lo que SWR activará\nla obtención de datos de la página siguiente. Cuando el usuario navega a la\nsiguiente página, los datos ya están allí:\n\n```jsx {6}\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  return (\n    <div>\n      <Page index={pageIndex} />\n      <div style={{ display: 'none' }}>\n        <Page index={pageIndex + 1} />\n      </div>\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>\n    </div>\n  )\n}\n```\n\nCon sólo 1 línea de código, conseguimos una UX mucho mejor. El hook `useSWR` es\ntan potente, que la mayoría de los escenarios están cubiertos por él.\n\n### Carga infinita\n\nA veces queremos construir una UI de **carga infinita**, con un botón \"Load\nMore\" que añada datos a la lista (o que lo haga automáticamente al desplazarse):\n\nimport { InfiniteImage } from '@app/_icons'\n\n<InfiniteImage className=\"mt-6 dark:invert\" />\n\nPara implementar esto, necesitamos hacer **número de peticiones dinámicas** en\nesta página. Los React Hooks tienen\n[un par de reglas](https://reactjs.org/docs/hooks-rules.html), por lo que **NO\nPODEMOS** hacer algo así:\n\n```jsx {5-9}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const list = []\n  for (let i = 0; i < cnt; i++) {\n    // 🚨 Esto es un error. Comúnmente, no se pueden usar hooks dentro de un bucle.\n    const { data } = useSWR(`/api/data?page=${i}`)\n    list.push(data)\n  }\n\n  return (\n    <div>\n      {list.map((data, i) => (\n        <div key={i}>\n          {data.map(item => (\n            <div key={item.id}>{item.name}</div>\n          ))}\n        </div>\n      ))}\n      <button onClick={() => setCnt(cnt + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\nEn su lugar, podemos utilizar la abstracción `<Page>` que hemos creado para\nconseguirlo:\n\n```jsx {5,6,7}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const pages = []\n  for (let i = 0; i < cnt; i++) {\n    pages.push(<Page index={i} key={i} />)\n  }\n\n  return (\n    <div>\n      {pages}\n      <button onClick={() => setCnt(cnt + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\n### Casos avanzados\n\nSin embargo, en algunos casos de uso avanzado, la solución anterior no funciona.\n\nPor ejemplo, seguimos implementando la misma UI \"Load More\", pero también\nnecesitamos mostrar un número sobre cuántos item hay en total. No podemos\nutilizar la solución `<Page>` porque la UI de nivel superior (`<App>`) necesita\nlos datos dentro de cada página:\n\n```jsx {10}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const pages = []\n  for (let i = 0; i < cnt; i++) {\n    pages.push(<Page index={i} key={i} />)\n  }\n\n  return (\n    <div>\n      <p>??? items</p>\n      {pages}\n      <button onClick={() => setCnt(cnt + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\nAdemás, si la API de paginación es **cursor based**, esa solución tampoco\nfunciona. Porque cada página necesita los datos de la página anterior, no están\naisladas.\n\nAsí es como este nuevo hook `useSWRInfinite` puede ayudar.\n\n## useSWRInfinite\n\n`useSWRInfinite` nos da la posibilidad de lanzar un número de peticiones con un\nsolo Hook. Así es como se ve:\n\n```jsx\nimport useSWRInfinite from 'swr/infinite'\n\n// ...\nconst { data, error, isValidating, mutate, size, setSize } = useSWRInfinite(\n  getKey, fetcher?, options?\n)\n```\n\nAl igual que `useSWR`, este nuevo hook acepta una función que devuelve la key de\nla solicitud, un fetcher función y options. Devuelve todos los valores que\ndevuelve `useSWR`, incluyendo 2 valores extra: page size y page size setter,\ncomo un React state.\n\nEn la carga infinita, una _page_ es una petición, y nuestro objetivo es obtener\nvarias páginas y renderizarlas.\n\n<Callout type=\"warning\">\n  If you are using SWR 0.x versions, `useSWRInfinite` needs to be imported from\n  `swr`:\n\n`import {useSWRInfinite} from 'swr'`\n\n</Callout>\n\n### API\n\n#### Parametrós\n\n- `getKey`: una función que acepta el índice y los datos de la página anterior,\n  devuelve la key de una página\n- `fetcher`: igual que la función [fetcher](/docs/data-fetching) de `useSWR`\n- `options`: acepta todas las opciones que soporta `useSWR`, con 3 opciones\n  adicionales:\n  - `initialSize = 1`: número de páginas que deben cargarse inicialmente\n  - `revalidateAll = false`: intentar siempre revalidar todas las páginas\n  - `revalidateFirstPage = true`: always try to revalidate the first page\n  - `persistSize = false`: no restablecer el page size a 1 (o `initialSize` si\n    está establecido) cuando la key de la primera página cambia\n\n<Callout>\n  Tenga en cuenta que la opción `InitialSize` no puede cambiar en el ciclo de\n  vida.\n</Callout>\n\n#### Valores de retorno\n\n- `data`: una array de valores de respuesta fetch de cada página\n- `error`: El mismo valor devuelto de `error` que `useSWR`\n- `isValidating`: El mismo valor devuelto de `isValidating` que `useSWR`\n- `mutate`: same as `useSWR`'s bound mutate function but manipulates the data\n  array\n- `size`: el número de páginas que _se obtendrán_ y devolverán\n- `setSize`: establecer el número de páginas que deben ser recuperadas\n\n### Ejemplo 1: API paginada basada en índices\n\nPara las APIs normales basadas en índices:\n\n```\nGET /users?page=0&limit=10\n[\n  { name: 'Alice', ... },\n  { name: 'Bob', ... },\n  { name: 'Cathy', ... },\n  ...\n]\n```\n\n```jsx {4-7,10}\n// Una función para obtener la key de SWR de cada página,\n// su valor de retorno será aceptado por `fetcher`.\n// Si se devuelve `null`, la petición de esa página no se iniciará.\nconst getKey = (pageIndex, previousPageData) => {\n  if (previousPageData && !previousPageData.length) return null // reached the end\n  return `/users?page=${pageIndex}&limit=10` // SWR key\n}\n\nfunction App() {\n  const { data, size, setSize } = useSWRInfinite(getKey, fetcher)\n  if (!data) return 'loading'\n\n  // Ahora podemos calcular el número de todos los usuarios\n  let totalUsers = 0\n  for (let i = 0; i < data.length; i++) {\n    totalUsers += data[i].length\n  }\n\n  return (\n    <div>\n      <p>{totalUsers} users listed</p>\n      {data.map(users => {\n        // `data` es un array con la respuesta de la API de cada página.\n        return users.map(user => <div key={user.id}>{user.name}</div>)\n      })}\n      <button onClick={() => setSize(size + 1)}>Load More</button>\n    </div>\n  )\n}\n```\n\nLa función `getKey` es la mayor diferencia entre `useSWRInfinite` y `useSWR`.\nAcepta el índice de la página actual, así como los datos de la página anterior.\nAsí que tanto la API de paginación basada en el índice como la basada en el\ncursor pueden ser soportadas de forma adecuada.\n\nAdemás, la `data` ya no son sólo es una respuesta de la API. Es una array de\nmúltiples respuestas de la API:\n\n```js\n// `data` tendrá el siguiente aspecto\n[\n  [\n    { name: 'Alice', ... },\n    { name: 'Bob', ... },\n    { name: 'Cathy', ... },\n    ...\n  ],\n  [\n    { name: 'John', ... },\n    { name: 'Paul', ... },\n    { name: 'George', ... },\n    ...\n  ],\n  ...\n]\n```\n\n### Ejemplo 2: Cursor or Offset Based Paginated API\n\nDigamos que la API ahora requiere un cursor y devuelve el siguiente cursor junto\ncon los datos:\n\n```plaintext\nGET /users?cursor=123&limit=10\n{\n  data: [\n    { name: 'Alice' },\n    { name: 'Bob' },\n    { name: 'Cathy' },\n    ...\n  ],\n  nextCursor: 456\n}\n```\n\nPodemos cambiar nuestra función `getKey` por:\n\n```jsx\nconst getKey = (pageIndex, previousPageData) => {\n  // reached the end\n  if (previousPageData && !previousPageData.data) return null\n\n  // la primera página, no tenemos `previousPageData`.\n  if (pageIndex === 0) return `/users?limit=10`\n\n  // añadir el cursor al punto final de la API\n  return `/users?cursor=${previousPageData.nextCursor}&limit=10`\n}\n```\n\n### Características avanzadas\n\n[Aquí hay un ejemplo](/examples/infinite-loading) que muestra cómo se pueden\nimplementar las siguientes características con `useSWRInfinite`:\n\n- estados de carga\n- mostrar una UI especial si está vacía\n- desactivar el botón \"Load More\" si reached the end\n- fuente de datos modificable\n- actualizar toda la lista\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/prefetching.md",
    "content": "# Prefetching Data\n\n## Top-Level Page Data\n\nHay muchas formas de precargar los datos para SWR. Para las solicitudes de nivel\nsuperior,\n[`rel=\"preload\"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content)\nes muy recomendable:\n\n```html\n<link rel=\"preload\" href=\"/api/data\" as=\"fetch\" crossorigin=\"anonymous\" />\n```\n\nSólo tienes que ponerlo dentro de tu HTML `<head>`. Es fácil, rápido y nativo.\n\nSe precargarán los datos cuando se cargue el HTML, incluso antes de que el\nJavaScript comience a descargarse. Todas las solicitudes de fetch entrantes con\nla misma URL reutilizarán el resultado (incluyendo SWR, por supuesto).\n\n## Programmatically Prefetch\n\nA veces, se quiere precargar un recurso de forma condicional. Por ejemplo,\nprecargar los datos cuando el usuario está\n[hovering](https://github.com/GoogleChromeLabs/quicklink)\n[a](https://github.com/guess-js/guess) [link](https://instant.page). La forma\nmás intuitiva es tener una función que recupere y fije la caché a través de la\nfunción global [mutate](/docs/mutation):\n\n```js\nimport { mutate } from 'swr'\n\nfunction prefetch() {\n  mutate(\n    '/api/data',\n    fetch('/api/data').then(res => res.json())\n  )\n  // el segundo parametró es una Promise\n  // SWR utilizará el resultado cuando resuelva\n}\n```\n\nJunto con técnicas como\n[page prefetching](https://nextjs.org/docs/api-reference/next/router#routerprefetch)\nen Next.js, podrás cargar tanto la siguiente página como los datos al instante.\n\n## Pre-fill Data\n\nIf you want to pre-fill existing data into the SWR cache, you can use the\n`fallbackData` option. For example:\n\n```jsx\nuseSWR('/api/data', fetcher, { fallbackData: prefetchedData })\n```\n\nIf SWR hasn't fetched the data yet, this hook will return `prefetchedData` as a\nfallback.\n\nYou can also configure this for all SWR hooks and multiple keys with\n`<SWRConfig>` and the `fallback` option. Check\n[Next.js SSG and SSR](/docs/with-nextjs) for more details.\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/revalidation.mdx",
    "content": "import { Video } from '@app/_components/video'\nimport { Bleed, Callout } from 'nextra/components'\n\n# Revalidación Automática\n\n<Callout>\n  Si quiere revalidar manualmente los datos, compruebe\n  [mutation](/docs/mutation).\n</Callout>\n\n## Revalidar on focus\n\nAl reenfocar una pagina o cambiar entre tabs, SWR revalida automáticamente los\ndatos.\n\nEsto puede ser útil para sincronizar inmediatamente a el último estado. Esto es\nútil para refrescar los datos en escenarios como stale mobile tabs, o laptops\nque están **suspendida**.\n\n<Bleed>\n  <Video\n    src=\"https://raw.githubusercontent.com/vercel/swr-site/master/.github/videos/focus-revalidate.mp4\"\n    caption=\"Vídeo: uso de la revalidación focus para sincronizar automáticamente el estado login entre páginas.\"\n    ratio={307 / 768}\n  />\n</Bleed>\n\nEsta caracteristica está activada por defecto. Puede desactivarla mediante de la\nopción [`revalidateOnFocus`](/docs/options).\n\n## Revalidar on interval\n\nEn muchos casos, los datos cambian debido a los múltiples dispositivos, los\nmúltiples usuarios, los múltiples tabs. ¿Cómo podemos con el tiempo actualizar\nlos datos en pantalla?\n\nSWR le dará la opción de recuperar los datos automáticamente. Es\n**inteligente**, lo que significa que el refetching sólo se producirá si el\ncomponente asociado al hook está **en la pantalla**.\n\n<Bleed>\n  <Video\n    src=\"https://raw.githubusercontent.com/vercel/swr-site/master/.github/videos/refetch-interval.mp4\"\n    caption=\"Vídeo: cuando un usuario realiza un cambio, ambas sesiones acabarán por mostrar los mismo datos.\"\n    ratio={307 / 768}\n  />\n</Bleed>\n\nPuede activarlo estableciendo un valor de [`refreshInterval`](/docs/options).\n\n```js\nuseSWR('/api/todos', fetcher, { refreshInterval: 1000 })\n```\n\nTambién hay opciones como `refreshWhenHidden` y `refreshWhenOffline`. Ambas\nestán deshabilitadas por defecto, para que SWR no recupere la información cuando\nla página web no esté en pantalla o no haya conexión de red.\n\n## Revalidar on reconnect\n\nTambién es útil revalidar cuando el usuario vuelve a estar conectado. Este\nescenario se da con frecuencia cuando el usuario desbloquea su ordenador, pero\nen ese mismo momento no está conectado a Internet.\n\nPara asegurarse de que los datos están siempre actualizados, SWR revalida\nautomáticamente cuando la red se recupera.\n\nEsta función está activada por defecto. Puede desactivarla mediante la opción\n[`revalidateOnReconnect`](/docs/options).\n\n## Disable Automatic Revalidations\n\nIf the resource is **immutable**, that will never change if we revalidate again,\nwe can disable all kinds of automatic revalidations for it.\n\nSince version 1.0, SWR provides a helper hook `useSWRImmutable` to mark the\nresource as immutable:\n\n```js\nimport useSWRImmutable from 'swr/immutable'\n\n// ...\nuseSWRImmutable(key, fetcher, options)\n```\n\nIt has the same API interface as the normal `useSWR` hook. You can also do the\nsame thing by disable the following revalidation options:\n\n```js\nuseSWR(key, fetcher, {\n  revalidateIfStale: false,\n  revalidateOnFocus: false,\n  revalidateOnReconnect: false\n})\n\n// equivalent to\nuseSWRImmutable(key, fetcher)\n```\n\nThe `revalidateIfStale` controls if SWR should revalidate when it mounts and\nthere is stale data.\n\nThese 2 hooks above do the **exact same** thing. Once the data is cached, they\nwill never request it again.\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/suspense.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Suspense\n\n<Callout emoji=\"🚨\" type=\"error\">\n  Suspense es actualmente una característica **experimental** de\n  React. Estas APIs pueden cambiar significativamente y sin previo aviso antes\n  de que se conviertan en parte de React.\n\n[Más información](https://reactjs.org/docs/concurrent-mode-suspense.html)\n\n</Callout>\n\n<Callout>\n  Tenga en cuenta que React Suspense aún no es compatible con el modo SSR.\n</Callout>\n\nPuede activar la opción `suspense` para utilizar SWR con React Suspense:\n\n```jsx\nimport { Suspense } from 'react'\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data } = useSWR('/api/user', fetcher, { suspense: true })\n  return <div>hello, {data.name}</div>\n}\n\nfunction App() {\n  return (\n    <Suspense fallback={<div>loading...</div>}>\n      <Profile />\n    </Suspense>\n  )\n}\n```\n\n<Callout>\n  Tenga en cuenta que la opción `suspense` no puede cambiar en el ciclo de vida.\n</Callout>\n\nEn el modo Suspense, `data` es siempre la respuesta fetch (por lo que no es\nnecesario comprobar si es `undefined`). Pero si se produce un error, es\nnecesario utilizar un\n[error boundary](https://reactjs.org/docs/concurrent-mode-suspense.html#handling-errors)\npara atraparlo:\n\n```jsx\n<ErrorBoundary fallback={<h2>Could not fetch posts.</h2>}>\n  <Suspense fallback={<h1>Loading posts...</h1>}>\n    <Profile />\n  </Suspense>\n</ErrorBoundary>\n```\n\n---\n\n### Note: With Conditional Fetching\n\nNormalmente, cuando se habilita `suspense` se garantiza que `data` siempre\nestarán lista al renderizar:\n\n```jsx\nfunction Profile() {\n  const { data } = useSWR('/api/user', fetcher, { suspense: true })\n\n  // `data` nunca sera `undefined`\n  // ...\n}\n```\n\nSin embargo, cuando se utiliza junto con el conditional fetching o dependent\nfetching, `data` estará `undefined` si la solicitud está **paused**:\n\n```jsx\nfunction Profile() {\n  const { data } = useSWR(isReady ? '/api/user' : null, fetcher, {\n    suspense: true\n  })\n\n  // `data` será `undefined` si `isReady` es false\n  // ...\n}\n```\n\nSi quiere leer más detalles técnicos sobre esta restricción, consulte\n[la discusión aquí](https://github.com/vercel/swr/pull/357#issuecomment-627089889).\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/understanding.mdx",
    "content": "import { Video } from '@app/_components/video'\nimport { Callout } from 'nextra/components'\n\n# Understanding SWR\n\n## State Machine\n\n`useSWR` returns `data`, `error`, `isLoading`, and `isValidating` depending on\nthe state of the `fetcher` function. This diagrams describe how SWR returns\nvalues in some scenarios.\n\n### Fetch and Revalidate\n\nThis pattern is to fetch data and revalidate it later.\n\n![A pattern for fetch and revalidate](/img/understanding/fetch-and-revalidate.svg)\n\n### Key Change\n\nThis pattern is to fetch data and change the key and revalidate it later.\n\n![A pattern for key change](/img/understanding/key-change.svg)\n\n### Key Change + Previous Data\n\nThis pattern is to fetch data and change the key and revalidate it later with\nthe `keepPreviousData` option.\n\n![A pattern for key change + previous data](/img/understanding/key-change-previous-data.svg)\n\n### Fallback\n\nThis pattern is to fetch data and revalidate it later with fallback data.\n\n![A pattern for fallback](/img/understanding/fallback.svg)\n\n### Key Change + Fallback\n\nThis pattern is to fetch data and change the key and revalidate it later with\nfallback data.\n\n![A pattern for key change + fallback](/img/understanding/key-change-fallback.svg)\n\n### Key Change + Previous Data + Fallback\n\nThis pattern is to fetch data and change the key and revalidate it later with\nthe `keepPreviousData` option and fallback data.\n\n![A pattern for key change + previous data + fallback](/img/understanding/key-change-previous-data-fallback.svg)\n\n## Combining with isLoading and isValidating for better UX\n\nComparing to the existing `isValidating` value, `isLoading` is a new property\nthat can help you for the more general loading cases for UX.\n\n- `isValidating` becomes `true` whenever there is an ongoing request **whatever\n  the the data is loaded or not**\n- `isLoading` becomes `true` when there is an ongoing request and **data is not\n  loaded yet**.\n\nSimply saying you can use `isValidating` for indicating everytime there is an\nongoing revalidation, and `isLoading` for indicating that SWR is revalidating\nbut there is no data yet to display.\n\n<Callout emoji=\"📝\">\n  Fallback data and previous data are not considered \"loaded data,\" so when you\n  use fallback data or enable the keepPreviousData option, you might have data\n  to display.\n</Callout>\n\n```jsx\nfunction Stock() {\n  const { data, isLoading, isValidating } = useSWR(STOCK_API, fetcher, {\n    refreshInterval: 3000\n  })\n\n  // If it's still loading the initial data, there is nothing to display.\n  // We return a skeleton here.\n  if (isLoading) return <div className=\"skeleton\" />\n\n  // Otherwise, display the data and a spinner that indicates a background\n  // revalidation.\n  return (\n    <>\n      <div>${data}</div>\n      {isValidating ? <div className=\"spinner\" /> : null}\n    </>\n  )\n}\n```\n\n![An example of using the isLoading state](/img/understanding/isloading.gif)\n\nYou can find the code example\n[here](https://codesandbox.io/s/swr-isloading-jtopow)\n\n## Return previous data for better UX\n\nWhen doing data fetching based on continuous user actions, e.g. real-time search\nwhen typing, keeping the previous fetched data can improve the UX a lot.\n`keepPreviousData` is an option to enable that behavior. Here's a simple search\nUI:\n\n```jsx\nfunction Search() {\n  const [search, setSearch] = React.useState('');\n\n  const { data, isLoading } = useSWR(`/search?q=${search}`, fetcher, {\n    keepPreviousData: true\n  });\n\n  return (\n    <div>\n      <input\n        type=\"text\"\n        value={search}\n        onChange={(e) => setSearch(e.target.value)}\n        placeholder=\"Search...\"\n      />\n\n      <div className={isLoading ? \"loading\" : \"\"}>\n        {data?.products.map(item => <Product key={item.id} name={item.name} />)\n      </div>\n    </div>\n  );\n}\n```\n\nWith `keepPreviousData` enabled, you will still get the previous data even if\nyou change the SWR key and the data for the new key starts loading again.\n\n<Video\n  src=\"https://user-images.githubusercontent.com/3676859/163695903-a3eb1259-180e-41e0-821e-21c320201194.mp4\"\n  caption=\"Keep previous search results when keepPreviousData has been enabled\"\n  ratio={640 / 730}\n/>\n\nYou can find the full code for this example here:\nhttps://codesandbox.io/s/swr-keeppreviousdata-fsjz3m.\n\n## Dependency Collection for performance\n\nSWR only triggers re-rendering when the states used in the component have been\nupdated. If you only use `data` in the component, SWR ignores the updates of\nother properties like `isValidating`, and `isLoading`. This reduces rendering\ncounts a lot. More information can be found\n[here](/docs/advanced/performance#dependency-collection).\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/with-nextjs.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Uso con Next.js\n\n## Obtención de datos del lado del cliente\n\nSi su página contiene datos que son actualizados frecuentemente y no necesita\nrenderizar previamente los datos, SWR se adapta perfectamente y no se necesita\nuna configuración especial: solo importe `useSWR` y use el hook dentro de\ncualquier componente que use los datos.\n\nAsí es como funciona:\n\n- En primer lugar, muestre inmediatamente la página sin datos. Puede mostrar un\n  loading state para los datos que faltan.\n\n- A continuación, se obtienen los datos en el lado del cliente y se muestran\n  cuando están listos.\n\nEste enfoque funciona bien, por ejemplo, para páginas que son dashboard. Dado\nque un dashboard es una página privada y específica del usuario, el SEO no es\nrelevante y la página no necesita ser pre-renderizado. Los datos se actualizan\ncon frecuencia, lo que requiere la obtención de datos en el momento de la\nsolicitud.\n\n## Pre-rendering with Default Data\n\nIf the page must be pre-rendered, Next.js supports\n[2 forms of pre-rendering](https://nextjs.org/docs/basic-features/data-fetching):  \n**Static\nGeneration (SSG)** and **Server-side Rendering (SSR)**.\n\nTogether with SWR, you can pre-render the page for SEO, and also have features\nsuch as caching, revalidation, focus tracking, refetching on interval on the\nclient side.\n\nYou can use the `fallback` option of [`SWRConfig`](/docs/global-configuration)\nto pass the pre-fetched data as the initial value of all SWR hooks. For example\nwith `getStaticProps`:\n\n```jsx\nexport async function getStaticProps() {\n  // `getStaticProps` is executed on the server side.\n  const article = await getArticleFromAPI()\n  return {\n    props: {\n      fallback: {\n        '/api/article': article\n      }\n    }\n  }\n}\n\nfunction Article() {\n  // `data` will always be available as it's in `fallback`.\n  const { data } = useSWR('/api/article', fetcher)\n  return <h1>{data.title}</h1>\n}\n\nexport default function Page({ fallback }) {\n  // SWR hooks inside the `SWRConfig` boundary will use those values.\n  return (\n    <SWRConfig value={{ fallback }}>\n      <Article />\n    </SWRConfig>\n  )\n}\n```\n\nThe page is still pre-rendered. It's SEO friendly, fast to response, but also\nfully powered by SWR on the client side. The data can be dynamic and\nself-updated over time.\n\n<Callout>\n  The `Article` component will render the pre-generated data first, and after\n  the page is hydrated, it will fetch the latest data again to keep it refresh.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/es/docs/wrap-toc-items.mdx",
    "content": "# Wrap Table of Content Items Properly\n\nTests whether long table of content items are wrapped properly for alignment.\n\n## First Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Second Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n#### Third Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n## Fourth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Fifth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n## No Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Sixth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n"
  },
  {
    "path": "examples/swr-site/content/es/examples/_meta.ts",
    "content": "export default {\n  basic: 'Uso Básico',\n  auth: 'Autenticación',\n  'infinite-loading': 'Carga Infinita',\n  'error-handling': 'Manejo De Errores'\n}\n"
  },
  {
    "path": "examples/swr-site/content/es/examples/auth.mdx",
    "content": "---\ntitle: Autenticación\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-auth-tuqtf?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Autenticación\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/es/examples/basic.mdx",
    "content": "---\ntitle: Uso Básico\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-basic-p7dg6?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Uso Básico\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/es/examples/error-handling.mdx",
    "content": "---\ntitle: Manejo De Errores\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-states-4une7?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Manejo De Errores\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/es/examples/infinite-loading.mdx",
    "content": "---\ntitle: Carga Infinita\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-infinite-z6r0r?file=/src/App.js?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Carga Infinita\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/es/index.mdx",
    "content": "---\ntitle: Biblioteca React Hooks para la obtención de datos\nsearchable: false\n---\n\nimport { Features } from '@app/_components/features'\nimport { Callout } from 'nextra/components'\n\n# SWR\n\n<Features lang={props.params.lang} title={metadata.title} />\n\nEl nombre \"SWR\" es derivado de `stale-while-revalidate`, una estrategia de\ninvalidación de caché HTTP popularizada por\n[HTTP RFC 5861](https://tools.ietf.org/html/rfc5861). SWR es una estrategia para\ndevolver primero los datos en caché (obsoletos), luego envíe la solicitud de\nrecuperación (revalidación), y finalmente entrege los datos actualizados.\n\n<Callout emoji=\"✅\">\n  Con SWR, el componente obtendrá **constante** y **automáticamente** el último flujo de datos.\n\nY la interfaz de usuario será siempre **rápida** y **reactiva**.\n\n</Callout>\n\n<div className=\"mt-16 mb-20 text-center\">\n  [Get Started](/docs/getting-started) · [Examples](/examples/basic) ·\n  [Blog](/blog) · [GitHub Repository](https://github.com/vercel/swr)\n</div>\n\n## Resumen\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user', fetcher)\n\n  if (error) return <div>failed to load</div>\n  if (!data) return <div>loading...</div>\n  return <div>hello {data.name}!</div>\n}\n```\n\nEn este ejemplo, el hook `useSWR` acepta una `key` que es un cadena y una\nfunción `fetcher`. `key` es un indentificador único de los datos (normalmente la\nURL de la API) y pasará al `fetcher`. El `fetcher` puede ser cualquier función\nasíncrona que devuelve datos, puedes utilizar el fetch nativo o herramientas\ncomo Axios.\n\nEl hook devuelve 2 valores: `data` y `error`, basados en el estado de la\nsolicitud.\n\n## Características\n\nCon una sola línea de código, puede simplificar la obtención de datos en su\nproyecto, y tambien tiene todas estas increíbles características fuera de caja:\n\n- Obtención de datos **rápida**, **ligera** y **reutilizable**\n- Caché integrada y deduplicación de solicitudes\n- Experiencia en **tiempo real**\n- Agnóstico al transporte y al protocolo\n- SSR / ISR / SSG support\n- TypeScript ready\n- React Native\n\nSWR le cubre en todos los aspectos de velocidad, correción, y estabilidad para\nayudarle a construir mejores experiencias:\n\n- Navegación rápida por la página\n- Polling on interval\n- Dependencia de los datos\n- Revalidation on focus\n- Revalidation on network recovery\n- Mutación local (Optimistic UI)\n- Smart error retry\n- Pagination and scroll position recovery\n- React Suspense\n\nAnd lot [more](/docs/getting-started).\n\n## Comunidad\n\n<p className=\"mt-6 flex h-6 gap-2\">\n  <img alt=\"stars\" src=\"https://badgen.net/github/stars/vercel/swr\" />\n  <img alt=\"downloads\" src=\"https://badgen.net/npm/dt/swr\" />\n  <img alt=\"license\" src=\"https://badgen.net/npm/license/swr\" />\n</p>\n\nSWR es creado por el mismo equipo que esta detrás de\n[Next.js](https://nextjs.org), el framework de React. Sigan\n[@vercel](https://twitter.com/vercel) en Twitter para futuras actualizaciones\ndel proyecto.\n\nSientase libre de unirse a\n[discusiones en GitHub](https://github.com/vercel/swr/discussions)!\n"
  },
  {
    "path": "examples/swr-site/content/ru/_meta.ts",
    "content": "import meta from '../en/_meta'\n\nexport default {\n  index: meta.index,\n  docs: {\n    ...meta.docs,\n    title: 'Документация'\n  },\n  examples: {\n    ...meta.examples,\n    title: 'Примеры'\n  },\n  blog: {\n    ...meta.blog,\n    title: 'Блог'\n  }\n}\n"
  },
  {
    "path": "examples/swr-site/content/ru/blog/swr-v1.mdx",
    "content": "---\ntitle: Представляем SWR 1.0\nimage: https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\ndescription:\n  'Почти 2 года назад мы сделали SWR — крошечную React библиотеку с открытым\n  исходным кодом для выборки данных, которую люди полюбили. Сегодня мы\n  приближаемся к еще одной вехе: версии 1.0 SWR!'\ndate: 2021-08-27\nauthors:\n  - name: Shu Ding\n    link: https://twitter.com/shuding_\n  - name: Jiachi Liu\n    link: https://twitter.com/huozhi\n---\n\nimport { TopContent } from '@app/_components/authors'\n\n<TopContent lang={props.params.lang} {...metadata} />\n\nПочти 2 года назад мы сделали SWR — крошечную React библиотеку с\n[открытым исходным кодом](https://twitter.com/vercel/status/1188911002626097157)\nдля выборки данных, которую люди полюбили. Сегодня мы приближаемся к еще одной\nвехе: версии 1.0 SWR!\n\n## Что нового\n\n### Уменьшенный размер\n\n[Производительность](/docs/advanced/performance) — одна из важнейших\nхарактеристик SWR. В версии 1.0 мы значительно уменьшили размер библиотеки, при\nэтом **не удалив никаких существующих функций**:\n\n- Ядро меньше на 41% (на 24% меньше при сжатии gzip, **3,9 КБ**)\n- Размер установленного пакета на 52% меньше\n- Улечшен tree-shaking\n\nЕсть много причин сделать библиотеку облегченной: ваше приложение будет иметь\nменьший пакет, более компактную среду выполнения и меньший каталог\n`node_modules`.\n\nМы также улучшили бандлинг пакета, и теперь он поддерживает импорт путей:\n\n```js\nimport useSWR from 'swr'\nimport useSWRInfinite from 'swr/infinite'\n```\n\nЕсли вы не используете `useSWRInfinite`, он не будет включен в ваше приложение.\n\n### Резервные данные\n\nВ версии 1.0 появилась новая опция `fallback`, которой вы можете предоставить\nлюбые предварительно выбранные данные в качестве начального значения всех хуков\nSWR с определенными ключами:\n\n```jsx\n<SWRConfig value={{\n  fallback: {\n    '/api/user': { name: 'Иван', ... },\n    '/api/items': ...,\n    ...\n  }\n}}>\n  <App/>\n</SWRConfig>\n```\n\nЭто очень полезно для таких сценариев, как SSG, SSR и макетирования данных для\nтестирования. Подробности смотрите в документации\n[Next.js SSG и SSR](/docs/with-nextjs).\n\nДля большей согласованности и во избежание путаницы старый `initialData` теперь\nпереименован в `fallbackData`, который по-прежнему предоставляет единое\nрезервное значение для заданного хука.\n\n### Неизменяемый режим\n\nИногда вы хотите пометить ресурс как **неизменный**, если он никогда не\nизменится. Лучше отключить для него автоматическую ревалидацию и сделать запрос\nтолько один раз. Теперь есть вспомогательный хук, чтобы упростить эту задачу:\n\n```jsx\nimport useSWRImmutable from 'swr/immutable'\n\n// ...\n\nuseSWRImmutable(key, fetcher, options)\n```\n\nОн имеет тот же API, что и хук `useSWR`, но он никогда не будет ревалидировать\nпри фокусировке вкладки или восстановлении сети. Также есть новая опция\n`revalidateIfStale`, которую можно использовать для точного управления\nповедением. Более подробную информацию можно найти\n[здесь](/docs/revalidation#отключение-автоматических-ревалидаций).\n\n### Пользовательский поставщик кеша\n\nПо умолчанию SWR использует единый глобальный кеш для хранения всех данных. В\nверсии 1.0 вы можете настроить его с помощью новой опции `provider`:\n\n```jsx\n<SWRConfig\n  value={{\n    provider: () => myCache\n  }}\n>\n  <App />\n</SWRConfig>\n```\n\nВы можете использовать эту новую функцию для множества полезных вещей. У нас\nесть пара примеров:\n[_Изменение нескольких ключей с помощью RegEx,_](/docs/advanced/cache#мутация-множества-ключей-из-регулярных-выражений-regex),\n[_Постоянный кеш на основе локального хранилища_](/docs/advanced/cache#постоянный-кеш-на-основе-localstorage),\n[_Сброс кеша между тестами_](/docs/advanced/cache#сброс-кеша-между-тестами).\n\nЭтот новый API кеш-провайдера также более совместим с параллельным рендерингом\nReact 18. Если вы добавляете кеш-провайдера, обязательно используйте глобальную\nфункцию `mutate`, возвращаемую из `useSWRConfig()`.\n\nВы можете прочитать документацию [Cache Provider](/docs/advanced/cache) для\nболее подробной информации.\n\n### useSWRConfig()\n\nПоявился новый Hook API для возврата всех глобальных конфигураций, включая\nтекущего поставщика кеша и глобальной функции `mutate`:\n\n```jsx\nimport { useSWRConfig } from 'swr'\n\nfunction Foo() {\n  const { refreshInterval, cache, mutate, ...restConfig } = useSWRConfig()\n\n  // ...\n}\n```\n\nБолее подробно можно почитать\n[здесь](/docs/global-configuration#доступ-к-глобальным-конфигурациям).\n\n### Промежуточное программное обеспечение (ППО) (Middleware)\n\nSWR промежуточное ПО предоставляет вам новый способ создания и повторного\nиспользования абстракций поверх хуков SWR:\n\n```jsx\n<SWRConfig value={{ use: [...middleware] }}>\n\n// ... или напрямую в `useSWR`:\nuseSWR(key, fetcher, { use: [...middleware] })\n```\n\nС помощью этой функции можно реализовать множество новых идей, и мы создали\nнесколько примеров:\n[_Регистратор запросов_](/docs/middleware#регистратор-запросов),\n[_Сохранение предыдущих данных при изменении ключа_](/docs/middleware#сохранение-предыдущего-результата)\nи [_Сериализация ключей объекта_](/docs/middleware#сериализация-ключей-объекта).\n\nСмотрите [ППО API](/docs/middleware) для более подробной информации.\n\n### Улучшения и лучший охват тестов\n\nНачиная с версии 0.x мы внесли сотни небольших улучшений и исправлений. SWR\nтеперь имеет 157 тестов, которые охватывают большинство крайних случаев при\nвыборке данных. Прочтите\n[журнал изменений](https://github.com/vercel/swr/releases) для более подробной\nинформации.\n\n### Перевод документации\n\nБлагодаря нашим\n[контрибютерам](https://github.com/vercel/swr-site/graphs/contributors) и\n[функции i18n](https://nextra.site/docs/guide/i18n) от Nextra, теперь мы\nпредлагаем документацию по SWR на шести разных языках:\n\n- [Английский](https://swr.vercel.app)\n- [Испанский](https://swr.vercel.app/es-ES)\n- [Упрощенный китайский](https://swr.vercel.app/zh-CN)\n- [Японский](https://swr.vercel.app/ja)\n- [Корейский](https://swr.vercel.app/ko)\n- [Русский](https://swr.vercel.app/ru)\n\n## Руководство по миграции\n\n### Обновите импорты `useSWRInfinite`\n\n`useSWRInfinite` должен быть импортирован из `swr/infinite`:\n\n```diff\n- import { useSWRInfinite } from 'swr'\n+ import useSWRInfinite from 'swr/infinite'\n```\n\nЕсли вы используете соответствующие типы, обновите и путь импорта:\n\n```diff\n- import { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr'\n+ import { SWRInfiniteConfiguration, SWRInfiniteResponse } from 'swr/infinite'\n```\n\n### Измените `revalidate` на `mutate`\n\n`useSWR` больше не возвращает метод `revalidate`, вместо этого измените его на\n`mutate`:\n\n```diff\n- const { revalidate } = useSWR(key, fetcher, options)\n+ const { mutate } = useSWR(key, fetcher, options)\n\n\n  // ...\n\n\n- revalidate()\n+ mutate()\n```\n\n### Переименуйте `initialData` на `fallbackData`\n\n```diff\n- useSWR(key, fetcher, { initialData: ... })\n+ useSWR(key, fetcher, { fallbackData: ... })\n```\n\n### Больше нет Fetcher'a по умолчанию\n\nSWR больше не предоставляет fetcher по умолчанию (вызов `fetch`, который\nанализирует данные как JSON). Самый простой способ перенести изменение —\nиспользовать компонент `<SWRConfig>`:\n\n```jsx\n;<SWRConfig value={{ fetcher: url => fetch(url).then(res => res.json()) }}>\n  <App />\n</SWRConfig>\n\n// ... или\nuseSWR(key, url => fetch(url).then(res => res.json()))\n```\n\n### Рекомендуем использовать `mutate` возвращаемый хуком\n\nЭто **не** критическое изменение, но теперь мы _рекомендуем_ всегда использовать\n`mutate`, возвращаемый хуком `useSWRConfig`:\n\n```diff\n- import { mutate } from 'swr'\n+ import { useSWRConfig } from 'swr'\n\n\n  function Foo () {\n+   const { mutate } = useSWRConfig()\n\n    return <button onClick={() => mutate('key')}>\n      Ключ мутации\n    </button>\n  }\n```\n\nЕсли вы не используете кеш-провайдер, текущий глобальный импорт\n`import { mutate } from 'swr'` по-прежнему работает.\n\n### Переименованные типы\n\nЕсли вы используете TypeScript, следующие имена типов были изменены для\nсогласованности:\n\n| 0.x (устаревшие)               | 1.0                        | Заметки                    |\n| ------------------------------ | -------------------------- | -------------------------- |\n| `ConfigInterface`              | `SWRConfiguration`         |                            |\n| `keyInterface`                 | `Key`                      |                            |\n| `responseInterface`            | `SWRResponse`              |                            |\n| `RevalidateOptionInterface`    | `RevalidatorOptions`       |                            |\n| `revalidateType`               | `Revalidator`              |                            |\n| `SWRInfiniteResponseInterface` | `SWRInfiniteResponse`      | перенесён в `swr/infinite` |\n| `SWRInfiniteConfigInterface`   | `SWRInfiniteConfiguration` | перенесён в `swr/infinite` |\n\n### Пользователям бета-версии и неофициальных функций\n\nЕсли вы используете бета-версию SWR или какие-либо недокументированные API,\nобратите внимание на следующие изменения:\n\n- `import { cache } from 'swr'` удалено; используйте новое\n  [`useSWRConfig` API](#useswrconfig) вместо него.\n- `import { createCache } from 'swr'` удалено; используйте новое\n  [Cache Provider API](/docs/advanced/cache) вместо него.\n- `revalidateWhenStale` переименовано в `revalidateIfStale`.\n- `middlewares` переименовано в `use`.\n\n### Журнал изменений\n\nПрочитайте весь журнал изменений\n[на GitHub](https://github.com/vercel/swr/releases).\n\n## Что дальше\n\nВ будущих релизах мы продолжим улучшать библиотеку, сохраняя при этом\nстабильность. Мы также стремимся охватить будущие версии React, поскольку для\nэтого уже готовятся несколько новых функций и улучшений в 1.0. Кроме того, мы\nтакже работаем над новыми функциями, чтобы улучшить получение данных в React и\nудобство использования этой библиотеки.\n\nЕсли у вас есть какие-либо отзывы об этом выпуске, пожалуйста,\n[сообщите нам об этом](https://github.com/vercel/swr/discussions).\n\n## Спасибо!\n\nОсобая благодарность [Toru Kobayashi](https://twitter.com/koba04) и\n[Yixuan Xu](https://twitter.com/yixuanxu94) за их вклад в библиотеку, и\n[Paco Coursey](https://twitter.com/pacocoursey),\n[uttk](https://github.com/uttk), [Tomohiro SHIOYA](https://github.com/shioyang),\n[Markoz Peña](https://github.com/markozxuu),\n[SeulGi Choi](https://github.com/cs09g),\n[Fang Lu](https://github.com/huzhengen),\n[Валентину Политову](https://github.com/valentinpolitov) за их труд над\nпереводом документации. Этот релиз не состоялся бы без них.\n\nМы также хотим поблагодарить всё сообщество, наших\n[110 контрибютеров](https://github.com/vercel/swr/graphs/contributors) (+\n[45 контрибютеров документации](https://github.com/vercel/swr-site/graphs/contributors))\nи всех, кто помогал и оставлял нам отзывы!\n"
  },
  {
    "path": "examples/swr-site/content/ru/blog.mdx",
    "content": "import { Blog } from '@app/_components/blog'\n\n# Блог SWR\n\n<Blog lang={props.params.lang} />\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/_meta.ts",
    "content": "export default {\n  'getting-started': 'Начало работы',\n  options: 'Опции',\n  'global-configuration': 'Глобальная конфигурация',\n  'data-fetching': 'Выборка данных',\n  'error-handling': 'Обработка ошибок',\n  revalidation: 'Авто-ревалидация',\n  'conditional-fetching': 'Условная выборка данных',\n  arguments: 'Аргументы',\n  mutation: 'Мутация',\n  pagination: 'Пагинация',\n  prefetching: 'Пред-выборка',\n  'with-nextjs': 'Next.js SSG и SSR',\n  suspense: 'Задержка (Suspense)',\n  middleware: 'Промежуточное ПО (Middleware)',\n  advanced: 'Продвинутые',\n  'change-log': 'Журнал изменений',\n  'wrap-toc-items': 'Обернуть таблицу содержимого элементов'\n}\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/advanced/_meta.ts",
    "content": "export default {\n  cache: 'Кеш',\n  performance: 'Производительность',\n  'react-native': 'React Native',\n  'file-name.with.DOTS': 'Имя файла может содержать точки'\n}\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/advanced/cache.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Кеш\n\n<Callout>\n  Обновитесь до последней версии (≥ 1.0.0), чтобы использовать этот функционал.\n</Callout>\n\n<Callout type=\"warning\">\n  В большинстве случаев вы не должны напрямую _писать_ в кеш, поскольку это\n  может вызвать неопределенное поведение SWR. Если вам нужно вручную изменить\n  ключ, рассмотрите возможность использования API SWR.\n\nСм. также: [Мутация](/docs/mutation),\n[Сброс кеша между тестами](#сброс-кеша-между-тестами).\n\n</Callout>\n\nПо умолчанию SWR использует глобальный кеш для хранения и обмена данными между\nвсеми компонентами. Но вы также можете настроить это поведение с помощью опции\n`provider` в `SWRConfig`.\n\nCache providers are intended to enable SWR with more customized storages.\nПровайдеры кеша предназначены для включения SWR с более индивидуализированными\nхранилищами.\n\n## Провайдер кеша\n\nПоставщик кеша — это объект типа Map, который соответствует следующему\nопределению TypeScript (которое может быть импортировано из `swr`):\n\n```typescript\ninterface Cache<Data> {\n  get(key: string): Data | undefined\n  set(key: string, value: Data): void\n  delete(key: string): void\n}\n```\n\nНапример, экземпляр\n[JavaScript Map](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Map)\nможно напрямую использовать в качестве провайдера кеша для SWR.\n\n## Создание провайдера кеша\n\nОпция `provider` в `SWRConfig` получает функцию, которая возвращает\n[провайдер кеша](#провайдер-кеша). Затем провайдер будет использоваться всеми\nхукамми SWR в пределах `SWRConfig`. Например:\n\n```jsx\nimport useSWR, { SWRConfig } from 'swr'\n\nfunction App() {\n  return (\n    <SWRConfig value={{ provider: () => new Map() }}>\n      <Page />\n    </SWRConfig>\n  )\n}\n```\n\nВсе хуки SWR внутри `<Page>` будут читать и писать из этого экземпляра Map. Вы\nтакже можете использовать другие реализации поставщика кеша для вашего\nконкретного случая использования.\n\n<Callout>\n  В приведённом выше примере, когда компонент `<App>` повторно монтируется,\n  провайдер также будет повторно создан. Провайдеры кеша должны быть размещены\n  выше в дереве компонентов или вне рендеринга.\n</Callout>\n\nimport { CacheImage } from '@app/_icons'\n\n<CacheImage className=\"mt-6 dark:invert\" />\n\nПри вложенности, хуки SWR будут использовать провайдер кеша верхнего уровня.\nЕсли нет провайдера кеша верхнего уровня, он возвращается к провайдеру кэша по\nумолчанию, который является пустым `Map`.\n\n<Callout type=\"warning\">\n  Если используется провайдер кеша, глобальный `mutate` **не** будет работать для хуков SWR в пределе\n  этого `<SWRConfig>`. Пожалуйста, используйте [это](#доступ-к-текущему-провайдеру-кеша) взамен.\n</Callout>\n\n## Доступ к текущему провайдеру кеша\n\nНаходясь внутри компонента React, вам нужно использовать хук\n[`useSWRConfig`](/docs/global-configuration#доступ-к-глобальным-конфигурациям),\nчтобы получить доступ к текущему провайдеру кеша, а также к другим\nконфигурациям, включая `mutate`:\n\n```jsx\nimport { useSWRConfig } from 'swr'\n\nfunction Avatar() {\n  const { cache, mutate, ...extraConfig } = useSWRConfig()\n  // ...\n}\n```\n\nЕсли он не находится под каким-либо `<SWRConfig>`, он вернет конфигурации по\nумолчанию.\n\n## Экспериментально: Расширение провайдера кеша\n\n<Callout emoji=\"🧪\">\n  Это экспериментальный функционал, его поведение может измениться в будущих\n  обновлениях.\n</Callout>\n\nКогда несколько компонентов `<SWRConfig>` вложены, провайдер кеша может быть\nрасширен.\n\nПервым аргументом для функции `provider` является поставщик кеша верхнего уровня\n`<SWRConfig>` (или кеш по умолчанию, если нет родительского `<SWRConfig>`), вы\nможете использовать его для расширения провайдера кеша:\n\n```jsx\n<SWRConfig value={{ provider: cache => newCache }}>...</SWRConfig>\n```\n\n## Примеры\n\n### Мутация множества ключей из регулярных выражений (RegEx)\n\nБлагодаря гибкости API кеш-провайдера вы даже можете создать помощник «частичной\nмутации».\n\nВ приведенном ниже примере `matchMutate` может принимать регулярное выражение в\nкачестве ключа и использоваться для мутации тех, кто соответствует этому\nшаблону.\n\n```js\nfunction useMatchMutate() {\n  const { cache, mutate } = useSWRConfig()\n  return (matcher, ...args) => {\n    if (!(cache instanceof Map)) {\n      throw new Error(\n        'matchMutate требует, чтобы провайдер кеша был экземпляром Map'\n      )\n    }\n\n    const keys = []\n\n    for (const key of cache.keys()) {\n      if (matcher.test(key)) {\n        keys.push(key)\n      }\n    }\n\n    const mutations = keys.map(key => mutate(key, ...args))\n    return Promise.all(mutations)\n  }\n}\n```\n\nЗатем внутри вашего компонента:\n\n```jsx\nfunction Button() {\n  const matchMutate = useMatchMutate()\n  return (\n    <button onClick={() => matchMutate(/^\\/api\\//)}>\n      Ревалидировать все ключи, начинающиеся на \"/api/\"\n    </button>\n  )\n}\n```\n\n<Callout>\n  Обратите внимание, что данный пример требует, чтобы провайдер кеша был\n  экземпляром Map.\n</Callout>\n\n### Постоянный кеш на основе LocalStorage\n\nВозможно, вы захотите синхронизировать свой кеш с `localStorage`. Вот пример\nреализации:\n\n```jsx\nfunction localStorageProvider() {\n  // При инициализации мы восстанавливаем данные из `localStorage` в Map.\n  const map = new Map(JSON.parse(localStorage.getItem('app-cache') || '[]'))\n\n  // Перед выгрузкой приложения мы записываем все данные обратно в `localStorage`.\n  window.addEventListener('beforeunload', () => {\n    const appCache = JSON.stringify(Array.from(map.entries()))\n    localStorage.setItem('app-cache', appCache)\n  })\n\n  // Мы по-прежнему используем map для записи и чтения для производительности.\n  return map\n}\n```\n\nЗатем используйте его как провайдер:\n\n```jsx\n<SWRConfig value={{ provider: localStorageProvider }}>\n  <App />\n</SWRConfig>\n```\n\n<Callout>\n  В качестве улучшения вы также можете использовать кеш памяти в качестве буфера\n  и периодически записывать в `localStorage`. Вы также можете реализовать\n  аналогичный многоуровневый кеш с помощью IndexedDB или WebSQL.\n</Callout>\n\n### Сброс кеша между тестами\n\nПри тестировании приложения вы можете сбросить кеш SWR между тестами. Вы можете\nпросто обернуть ваше приложение пустым провайдером кеша. Вот пример с Jest:\n\n```jsx\ndescribe('тестирование', async () => {\n  it('тестовый пример', async () => {\n    render(\n      <SWRConfig value={{ provider: () => new Map() }}>\n        <App />\n      </SWRConfig>\n    )\n  })\n})\n```\n\n### Доступ к кешу\n\nПредупреждение: вы не должны писать в кеш напрямую, это может привести к\nнеопределенному поведению.\n\n```jsx\nconst { cache } = useSWRConfig()\n\ncache.get(key) // Получить текущие данные для ключа.\ncache.clear() // ⚠️ Очистить весь кеш. SWR проведёт ревалидацию при повторном рендеринге.\n```\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/advanced/file-name.with.DOTS.mdx",
    "content": "# Вы можете добавить точки в имя своих файлов\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/advanced/performance.mdx",
    "content": "# Производительность\n\nSWR обеспечивает критически важную функциональность во всех видах\nвеб-приложений, поэтому **производительность** является главным приоритетом.\n\nВстроенное **кеширование** и **[дедупликация](#дедупликация)** SWR пропускают\nненужные сетевые запросы, но производительность самого хука `useSWR` всё ещё\nимеет значение. В сложном приложении могут быть сотни вызовов `useSWR` при\nотрисовке одной страницы.\n\nSWR гарантирует, что в вашем приложении:\n\n- _нет лишних запросов_\n- _нет лишних повторных рендеров_\n- _не импортируется ненужный код_\n\nбез каких-либо изменений кода с вашей стороны.\n\n## Дедупликация\n\nХуки SWR зачастую используются в приложении повторно. Например, приложение,\nкоторое рендерит аватар текущего пользователя 5 раз:\n\n```jsx\nfunction useUser() {\n  return useSWR('/api/user', fetcher)\n}\n\nfunction Avatar() {\n  const { data, error } = useUser()\n\n  if (error) return <Error />\n  if (!data) return <Spinner />\n\n  return <img src={data.avatar_url} />\n}\n\nfunction App() {\n  return (\n    <>\n      <Avatar />\n      <Avatar />\n      <Avatar />\n      <Avatar />\n      <Avatar />\n    </>\n  )\n}\n```\n\nКаждый компонент `<Avatar>` имеет внутри хук `useSWR`. Поскольку они имеют\nодинаковый ключ SWR и рендерятся почти одновременно, **будет выполнен только 1\nсетевой запрос**.\n\nВы можете повторно использовать свои хуки данных (например, `useUser` в\nприведенном выше примере) повсюду, не беспокоясь о производительности или\nдублировании запросов.\n\nСуществует также [опция `dedupingInterval`](/docs/options) для переопределения\nинтервала дедупликации по умолчанию.\n\n## Глубокое сравнение\n\nSWR **глубоко сравнивает** изменения данных по умолчанию. Если значение `data`\nне изменилось, повторный рендеринг запускаться не будет.\n\nВы также можете настроить функцию сравнения с помощью\n[опции `compare`](/docs/options), если хотите изменить поведение. Например,\nнекоторые ответы API возвращают отметку времени сервера, которую вы, возможно,\nзахотите исключить из сравнения данных.\n\n## Коллекция зависимостей\n\n`useSWR` возвращает 3 значения **с сохранением состояния**: `data`, `error` и\n`isValidating`, каждое из которых может обновляться независимо. Например, если\nмы выведим эти значения внутри полного жизненного цикла выборки данных, это\nбудет примерно так:\n\n```jsx\nfunction App() {\n  const { data, error, isValidating } = useSWR('/api', fetcher)\n  console.log(data, error, isValidating)\n  return null\n}\n```\n\nВ худшем случае (первый запрос не удался, затем повторная попытка была успешной)\nвы увидите 4 строки журнала:\n\n```js\n// console.log(data, error, isValidating)\nundefined undefined true  // => начало выборки\nundefined Error false     // => конец выборки, получили ошибку\nundefined Error true      // => начало повторной попытки\nData undefined false      // => конец повторной попытки, получение данных\n```\n\nИзменения состояния имеют смысл. Но это также означает, что наш компонент\n**рендерился 4 раза**.\n\nЕсли мы изменим наш компонент на использование только `data`:\n\n```jsx\nfunction App() {\n  const { data } = useSWR('/api', fetcher)\n  console.log(data)\n  return null\n}\n```\n\nВолшебство происходит — теперь всего **2 рендера**:\n\n```js\n// console.log(data)\nundefined // => гидратация / начальный рендер\nData // => конец повторной попытки, получение данных\n```\n\nТочно такой же процесс произошёл внутри, возникла ошибка при первом запросе,\nзатем мы получили данные при повторной попытке. Однако **SWR обновляет только\nсостояния, которые используются компонентом**, которым сейчас является только\n`data`.\n\nЕсли вы не всегда используете все эти 3 состояния, вы уже извлекаете пользу из\nэтого функционала. В [Vercel](https://vercel.com) эта оптимизация приводит к\nсокращению повторного рендеринга примерно на 60%.\n\n## Встряхивание (Tree Shaking)\n\nПакет SWR легко [встряхивается](https://webpack.js.org/guides/tree-shaking) и не\nимеет побочных эффектов (side-effects). Это означает, что если вы импортируете\nтолько основной API `useSWR`, неиспользуемые API, такие как `useSWRInfinite`, не\nбудут включены в ваше приложение.\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/advanced/react-native.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# React Native\n\n<Callout>\n  Обновитесь до последней версии (≥ 1.0.0), чтобы испытать эту настройку.\n</Callout>\n\nВ отличие от React, работающего внутри браузеров, React Native имеет совсем\nдругой опыт использования. Например, нет «фокуса вкладки», вместо этого\nпереключение с фона на приложение рассматривается как «фокус». Чтобы настроить\nэто поведение, вы можете заменить стандартные прослушиватели событий `focus` и\n`online` в браузере на детекторы состояния приложения React Native и другие\nпортированные нативные API, а также настроить SWR для их использования.\n\n## Пример\n\n### Глобальная настройка\n\nВы можете обернуть своё приложение в `SWRConfig` и предварительно\nсконфигурировать все конфигурации там\n\n```jsx\n<SWRConfig\n  value={{\n    /* ... */\n  }}\n>\n  <App>\n</SWRConfig>\n```\n\n### Настроить события `focus` и `reconnect`\n\nВам нужно позаботиться о нескольких конфигурациях, таких как `isOnline`,\n`isVisible`, `initFocus` и `initReconnect`.\n\n`isOnline` и `isVisible` — это функции, которые возвращают логическое значение,\nчтобы определить, является ли приложение «активным». По умолчанию SWR придёт на\nпомощь сделав повторную валидацию, если эти условия не выполняются.\n\nПри использовании `initFocus` и `initReconnect` необходимо также настроить\n[кастомный провайдер кеша](/docs/advanced/cache). Вы можете использовать пустой\n`Map()` или любое другое хранилище, которое вам нравится.\n\n```jsx\n<SWRConfig\n  value={{\n    provider: () => new Map(),\n    isOnline() {\n      /* Настройте детектор состояния сети */\n      return true\n    },\n    isVisible() {\n      /* Настройте детектор состояния видимости */\n      return true\n    },\n    initFocus(callback) {\n      /* Зарегистрируйте слушатель в провайдере состояния */\n    },\n    initReconnect(callback) {\n      /* Зарегистрируйте слушатель в провайдере состояния */\n    }\n  }}\n>\n  <App />\n</SWRConfig>\n```\n\nРассмотрим пример `initFocus`:\n\n```jsx\nimport { AppState } from 'react-native'\n\n// ...\n\n<SWRConfig\n  value={{\n    provider: () => new Map(),\n    isVisible: () => { return true },\n    initFocus(callback) {\n      let appState = AppState.currentState\n\n      const onAppStateChange = (nextAppState) => {\n        /* Если оно переходит из фонового или неактивного режима в активный */\n        if (appState.match(/inactive|background/) && nextAppState === 'active') {\n          callback()\n        }\n        appState = nextAppState\n      }\n\n      // Подпишитесь на события изменения состояния приложения\n      const subscription = AppState.addEventListener('change', onAppStateChange)\n\n      return () => {\n        subscription.remove()\n      }\n    }\n  }}\n>\n  <App>\n</SWRConfig>\n```\n\nДля `initReconnect` требуется, чтобы некоторые сторонние библиотеки, такие как\n[NetInfo](https://github.com/react-native-netinfo/react-native-netinfo),\nподписывались на статус сети. Реализация будет аналогична приведенному выше\nпримеру: получение функции `callback` и её запуск, когда сеть выходит из\nавтономного режима, чтобы SWR смог начать ревалидацию, чтобы поддерживать ваши\nданные в актуальном состоянии.\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/arguments.mdx",
    "content": "# Аргументы\n\nПо умолчанию `key` будет передан в `fetcher` в качестве аргумента. Итак,\nследующие 3 выражения эквивалентны:\n\n```js\nuseSWR('/api/user', () => fetcher('/api/user'))\nuseSWR('/api/user', url => fetcher(url))\nuseSWR('/api/user', fetcher)\n```\n\n## Множественные аргументы\n\nВ некоторых сценариях полезно передать несколько аргументов (может быть любое\nзначение или объект) в `fetcher`. Например, запрос на выборку с авторизацией:\n\n```js\nuseSWR('/api/user', url => fetchWithToken(url, token))\n```\n\nЭто **неверно**. Поскольку идентификатор (также ключ кеша) данных - это\n`'/api/user'`, даже если `token` изменится, SWR все равно будет использовать тот\nже ключ и возвращать неверные данные.\n\nВместо этого вы можете использовать **массив** в качестве параметра `key`,\nкоторый содержит несколько аргументов `fetcher`:\n\n```js\nconst { data: user } = useSWR(['/api/user', token], fetchWithToken)\n```\n\nФункция `fetchWithToken` по-прежнему принимает те же 2 аргумента, но ключ кеша\nтеперь также будет связан с `token`.\n\n## Передача объектов\n\nimport { Callout } from 'nextra/components'\n\n<Callout>\n  Since SWR 1.1.0, object-like keys will be serialized under the hood\n  automatically.\n</Callout>\n\nSay you have another function that fetches data with a user scope:\n`fetchWithUser(api, user)`. You can do the following:\n\n```js\nconst { data: user } = useSWR(['/api/user', token], fetchWithToken)\n\n// ...and then pass it as an argument to another useSWR hook\nconst { data: orders } = useSWR(\n  user ? ['/api/orders', user] : null,\n  fetchWithUser\n)\n```\n\nYou can directly pass an object as the key, and `fetcher` will receive that\nobject too:\n\n```js\nconst { data: orders } = useSWR({ url: '/api/orders', args: user }, fetcher)\n```\n\n<Callout type=\"warning\">\n  In older versions (< 1.1.0), SWR **shallowly** compares the arguments on every render, and triggers revalidation if any of them has changed.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/change-log.mdx",
    "content": "import Markdown from 'markdown-to-jsx'\n\nexport async function ReleasesRenderer() {\n  const releases = await fetch(\n    `https://api.github.com/repos/vercel/swr/releases`\n  ).then(res => res.json())\n  return (\n    <Markdown>\n      {releases\n        // мы показываем здесь крайние 5 релизов\n        .slice(0, 5)\n        .map(release => {\n          const body = release.body\n            .replace(/&#39;/g, \"'\")\n            .replace(\n              /@([a-zA-Z0-9_-]+)(?=(,| ))/g,\n              '<a href=\"https://github.com/$1\" target=\"_blank\" rel=\"noopener\">@$1</a>'\n            )\n          return `## <a href=\"${\n            release.html_url\n          }\" target=\"_blank\" rel=\"noopener\">${release.tag_name}</a>\nОпубликовано ${new Date(release.published_at).toLocaleDateString(\n            'ru'\n          )}.\\n\\n${body}`\n        })\n        .join('\\n\\n')}\n    </Markdown>\n  )\n}\n\n# Журнал изменений\n\nПожалуйста, посетите\n[страницу релизов SWR](https://github.com/vercel/swr/releases), чтобы увидеть\nвсю историю релизов.\n\n<ReleasesRenderer />\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/conditional-fetching.md",
    "content": "# Условная выборка\n\n## Условная\n\nИспользуйте `null` или передайте функцию в качестве `key` для условной выборки\nданных. Если функция выводит ошибку или возвращает ложное значение, SWR не\nотправляет запрос.\n\n```js\n// условная выборка\nconst { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher)\n\n// ...или вернуть ложное значение\nconst { data } = useSWR(() => (shouldFetch ? '/api/data' : null), fetcher)\n\n// ...или вывести ошибку, если user.id не определен\nconst { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)\n```\n\n## Зависимая\n\nSWR также позволяет получать данные, которые зависят от других данных. Это\nобеспечивает максимально возможный параллелизм (избегая водопадов), а также\nпоследовательную выборку, когда для следующей выборки данных требуется фрагмент\nдинамических данных.\n\n```js\nfunction MyProjects() {\n  const { data: user } = useSWR('/api/user')\n  const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id)\n  // При передаче функции SWR будет использовать возвращаемое значение\n  // как `key`. Если функция выдает ошибку или возвращает ложь,\n  // SWR будет знать, что некоторые зависимости не готовы.\n  // В этом случае `user.id` выдает ошибку, когда `user` не загружен.\n\n  if (!projects) return 'загрузка...'\n  return 'У вас ' + projects.length + ' проектов'\n}\n```\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/data-fetching.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Выборка данных\n\n```js\nconst { data, error } = useSWR(key, fetcher)\n```\n\nЭто самый фундаментальный API SWR. `fetcher` здесь представляет собой\nасинхронную функцию, которая **принимает `key`** SWR и возвращает данные.\n\nВозвращаемое значение будет передано как `data`, и если оно будет выброшено, оно\nбудет перехвачено как `error`.\n\n<Callout>\n  Обратите внимание, что `fetcher` можно не указывать в параметрах, если он\n  [предоставляется глобально](/docs/global-configuration).\n</Callout>\n\n## Выборка (Fetch)\n\nВы можете использовать любую библиотеку для обработки выборки данных, например,\nполифил `fetch` — [developit/unfetch](https://github.com/developit/unfetch):\n\n```js\nimport fetch from 'unfetch'\n\nconst fetcher = url => fetch(url).then(r => r.json())\n\nfunction App() {\n  const { data, error } = useSWR('/api/data', fetcher)\n  // ...\n}\n```\n\n<Callout>\n  Если вы используете **Next.js**, вам не нужно импортировать этот\n  полифил:\n\n[Новые встроенные полифилы: fetch(), URL, и Object.assign](https://nextjs.org/blog/next-9-1-7#new-built-in-polyfills-fetch-url-and-objectassign)\n\n</Callout>\n\n## Axios\n\n```js\nimport axios from 'axios'\n\nconst fetcher = url => axios.get(url).then(res => res.data)\n\nfunction App() {\n  const { data, error } = useSWR('/api/data', fetcher)\n  // ...\n}\n```\n\n## GraphQL\n\nИли используйте GraphQL с такими библиотеками, как\n[graphql-request](https://github.com/prisma-labs/graphql-request):\n\n```js\nimport { request } from 'graphql-request'\n\nconst fetcher = query => request('/api/graphql', query)\n\nfunction App() {\n  const { data, error } = useSWR(\n    /* GraphQL */ `\n      {\n        Movie(title: \"Начало\") {\n          releaseDate\n          actors {\n            name\n          }\n        }\n      }\n    `,\n    fetcher\n  )\n  // ...\n}\n```\n\n_Если вы хотите передавать переменные в запрос GraphQL, ознакомьтесь с разделом\n[Множественные аргументы](/docs/arguments)._\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/error-handling.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Обработка ошибок\n\nЕсли ошибка возникает внутри [`fetcher`-а](/docs/data-fetching), она будет\nвозвращена хуком как `error`.\n\n```js\nconst fetcher = url => fetch(url).then(r => r.json())\n\n// ...\nconst { data, error } = useSWR('/api/user', fetcher)\n```\n\nОбъект `error` будет определен, если промис выборки будет отклонён.\n\n## Статус код и Объект ошибки\n\nИногда мы хотим, чтобы API возвращал объект ошибки вместе со статус кодом. Оба\nони полезны для клиента.\n\nМы можем настроить наш `fetcher`, чтобы он возвращал больше информации. Если\nстатус код не `2xx`, мы считаем это ошибкой, даже если он может быть\nпроанализирован как JSON:\n\n```js\nconst fetcher = async url => {\n  const res = await fetch(url)\n\n  // Если статус код не в диапазоне 200-299,\n  // мы все равно пытаемся его разобрать и выбросить.\n  if (!res.ok) {\n    const error = new Error('An error occurred while fetching the data.')\n    // Добавление дополнительной информации в объект ошибки.\n    error.info = await res.json()\n    error.status = res.status\n    throw error\n  }\n\n  return res.json()\n}\n\n// ...\nconst { data, error } = useSWR('/api/user', fetcher)\n// error.info === {\n//   message: \"У вас нет прав доступа к этому ресурсу.\",\n//   documentation_url: \"...\"\n// }\n// error.status === 403\n```\n\n<Callout>\n  Обратите внимание, что `data` и `error` могут существовать одновременно. Таким\n  образом, пользовательский интерфейс может отображать существующие данные,\n  зная, что предстоящий запрос потерпел неудачу.\n</Callout>\n\n[Здесь](/examples/error-handling) у нас есть пример.\n\n## Повтор при ошибке\n\nSWR использует\n[алгоритм экспоненциальной выдержки](https://ru.wikipedia.org/wiki/Экспоненциальная_выдержка)\nдля повторной попытки запроса в случае ошибки. Алгоритм позволяет приложению\nбыстро восстанавливаться после ошибок, но не тратить ресурсы на повторные\nпопытки слишком часто.\n\nВы также можете изменить это поведение с помощью опции\n[onErrorRetry](/docs/options#опции):\n\n```js\nuseSWR('/api/user', fetcher, {\n  onErrorRetry: (error, key, config, revalidate, { retryCount }) => {\n    // Никогда не повторяйте попытку при 404.\n    if (error.status === 404) return\n\n    // Никогда не повторяйте попытку при конкретном ключе.\n    if (key === '/api/user') return\n\n    // Повторить попытку до 10 раз.\n    if (retryCount >= 10) return\n\n    // Повторить попытку через 5 секунд.\n    setTimeout(() => revalidate({ retryCount }), 5000)\n  }\n})\n```\n\nЭтот колбэк дает вам возможность повторить попытку в зависимости от различных\nусловий. Вы также можете отключить его, установив `shouldRetryOnError: false`.\n\nТакже возможно предоставить его через контекст\n[Глобальной конфигурации](/docs/global-configuration).\n\n## Отчёт о глобальной ошибке\n\nВы всегда можете реактивно получить объект `error` внутри компонента. Но в\nслучае, если вы хотите обработать ошибку глобально, чтобы уведомить UI, чтобы\nпоказать [toast](https://vercel.com/design/toast) или\n[snackbar](https://material.io/components/snackbars), или сообщить об этом\nкуда-нибудь, например в [Sentry](https://sentry.io), есть событие\n[`onError`](/docs/options#опции):\n\n```jsx\n<SWRConfig\n  value={{\n    onError: (error, key) => {\n      if (error.status !== 403 && error.status !== 404) {\n        // Мы можем отправить ошибку в Sentry,\n        // или показать уведомление в UI.\n      }\n    }\n  }}\n>\n  <MyApp />\n</SWRConfig>\n```\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/getting-started.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Начало работы\n\n## Установка\n\nВнутри директории вашего React-проекта, выполните команду:\n\n```bash npm2yarn\nnpm i swr\n```\n\n## Быстрый старт\n\nДля обычных RESTful API с данными JSON сначала необходимо создать функцию\n`fetcher`, которая является просто оболочкой для нативного `fetch`:\n\n```jsx\nconst fetcher = (...args) => fetch(...args).then(res => res.json())\n```\n\n<Callout>\n  Если вы хотите использовать GraphQL API или библиотеки, такие как Axios, вы\n  можете создать свою собственную fetcher-функцию. Смотрите примеры\n  [здесь](/docs/data-fetching).\n</Callout>\n\nЗатем можете импортировать `useSWR` и использовать его внутри функциональных\nкомпонентов:\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user/123', fetcher)\n\n  if (error) return <div>ошибка загрузки</div>\n  if (!data) return <div>загрузка...</div>\n\n  // render data\n  return <div>привет, {data.name}!</div>\n}\n```\n\nОбычно существует 3 возможных состояния запроса: «загрузка», «готово» или\n«ошибка». Вы можете использовать значение `data` и `error`, чтобы определить\nтекущее состояние запроса и вернуть соответствующий UI.\n\n## Делайте многоразовами\n\nПри создании веб-приложения вам может потребоваться повторно использовать данные\nво многих местах пользовательского интерфейса. Создавать многоразовые хуки\nданных поверх SWR невероятно просто:\n\n```jsx\nfunction useUser(id) {\n  const { data, error } = useSWR(`/api/user/${id}`, fetcher)\n\n  return {\n    user: data,\n    isLoading: !error && !data,\n    isError: error\n  }\n}\n```\n\nИ используйте их в своих компонентах:\n\n```jsx\nfunction Avatar({ id }) {\n  const { user, isLoading, isError } = useUser(id)\n\n  if (isLoading) return <Spinner />\n  if (isError) return <Error />\n  return <img src={user.avatar} />\n}\n```\n\nИспользуя этот шаблон, вы можете забыть об императивном получении данных:\nотправить запрос, обновить состояние загрузки и вернуть окончательный результат.\nВместо этого ваш код более декларативен: вам просто нужно указать, какие данные\nиспользуются компонентом.\n\n## Пример\n\nВ реальном примере наш веб-сайт показывает панель навигации и контент, оба\nзависят от `user`:\n\nimport { WelcomeImage } from '@app/_icons'\n\n<WelcomeImage className=\"mt-6 dark:invert\" />\n\nТрадиционно мы получаем данные один раз, используя `useEffect` в компоненте\nверхнего уровня, и передаем их дочерним компонентам через пропсы (обратите\nвнимание, что мы пока не обрабатываем состояние ошибки):\n\n```jsx {7-11,17,18,27}\n// компонент страницы\n\nfunction Page() {\n  const [user, setUser] = useState(null)\n\n  // выборка данных\n  useEffect(() => {\n    fetch('/api/user')\n      .then(res => res.json())\n      .then(data => setUser(data))\n  }, [])\n\n  // глобальное состояние загрузки\n  if (!user) return <Spinner />\n\n  return (\n    <div>\n      <Navbar user={user} />\n      <Content user={user} />\n    </div>\n  )\n}\n\n// дочерний компонент\n\nfunction Navbar({ user }) {\n  return (\n    <div>\n      ...\n      <Avatar user={user} />\n    </div>\n  )\n}\n\nfunction Content({ user }) {\n  return <h1>С возвращением, {user.name}</h1>\n}\n\nfunction Avatar({ user }) {\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\nОбычно нам нужно сохранить выборку всех данных в компоненте верхнего уровня и\nпередавать пропсы к каждому компоненту в глубине дерева. Код станет труднее\nподдерживать, если мы добавим на страницу больше зависимостей данных.\n\nХотя мы можем избежать передачи пропсов с помощью\n[Контекста](https://ru.reactjs.org/docs/context.html), всё ещё существует\nпроблема с динамическим контентом: компоненты внутри контента страницы могут\nбыть динамическими, и компонент верхнего уровня может не знать, какие данные\nпотребуются его дочерним компонентам.\n\nSWR отлично решает проблему. С помощью только что созданного хука `useUser` код\nможно реорганизовать так:\n\n```jsx {20,26}\n// компонент страницы\n\nfunction Page() {\n  return (\n    <div>\n      <Navbar />\n      <Content />\n    </div>\n  )\n}\n\n// дочерний компонент\n\nfunction Navbar() {\n  return (\n    <div>\n      ...\n      <Avatar />\n    </div>\n  )\n}\n\nfunction Content() {\n  const { user, isLoading } = useUser()\n  if (isLoading) return <Spinner />\n  return <h1>С возвращением, {user.name}</h1>\n}\n\nfunction Avatar() {\n  const { user, isLoading } = useUser()\n  if (isLoading) return <Spinner />\n  return <img src={user.avatar} alt={user.name} />\n}\n```\n\nТеперь данные **привязаны** к компонентам, которым нужны данные, и все\nкомпоненты **независимы** друг от друга. Всем родительским компонентам не нужно\nничего знать о данных или об их передаче. Они просто рендерят. Код стал намного\nпроще и легче в обслуживании.\n\nСамым прекрасным является то, что в API будет отправлен всего **1 запрос**,\nпотому что они используют один и тот же ключ SWR, а запрос автоматически\n**выводится**, **кэшируется** и **распределяется**.\n\nКроме того, приложение теперь имеет возможность обновлять данные при\n[фокусе или переподключении к сети](/docs/revalidation)! Это означает, что когда\nноутбук пользователя выходит из спящего режима или он переключается между\nвкладками браузера, данные обновляются автоматически.\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/global-configuration.md",
    "content": "# Глобальная конфигурация\n\nКонтекст `SWRConfig` может предоставить глобальные конфигурации\n([опции](/docs/options)) для всех SWR хуков.\n\n```jsx\n<SWRConfig value={options}>\n  <Component />\n</SWRConfig>\n```\n\nВ этом примере все SWR хуки будут использовать один и тот же fetcher,\nпредоставленный для загрузки данных JSON, и по умолчанию обновляться каждые 3\nсекунды:\n\n```jsx\nimport useSWR, { SWRConfig } from 'swr'\n\nfunction Dashboard() {\n  const { data: events } = useSWR('/api/events')\n  const { data: projects } = useSWR('/api/projects')\n  const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // переопределение\n\n  // ...\n}\n\nfunction App() {\n  return (\n    <SWRConfig\n      value={{\n        refreshInterval: 3000,\n        fetcher: (resource, init) =>\n          fetch(resource, init).then(res => res.json())\n      }}\n    >\n      <Dashboard />\n    </SWRConfig>\n  )\n}\n```\n\n## Дополнительные API\n\n### Провайдер кеша\n\nПомимо всех перечисленных [опций](/docs/options), `SWRConfig` также принимает\nопциональную функцию `provider`. Пожалуйста, обратитесь к разделу\n[Кэш](/docs/cache) для более подробной информации.\n\n```jsx\n<SWRConfig value={{ provider: () => new Map() }}>\n  <Dashboard />\n</SWRConfig>\n```\n\n### Доступ к глобальным конфигурациям\n\nВы можете использовать ловушку `useSWRConfig` для получения глобальных\nконфигураций, а также [`mutate`](/docs/mutation) и\n[`cache`](/docs/advanced/cache):\n\n```jsx\nimport { useSWRConfig } from 'swr'\n\nfunction Component() {\n  const { refreshInterval, mutate, cache, ...restConfig } = useSWRConfig()\n\n  // ...\n}\n```\n\nВложенные конфигурации будут расширены. Если не используется `<SWRConfig>`,\nвернётся значение по умолчанию.\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/middleware.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Промежуточное программное обеспечение (ППО) (Middleware)\n\n<Callout>\n  Обновитесь до последней версии (≥ 1.0.0), чтобы использовать этот функционал.\n</Callout>\n\nФункционал ППО — это новое дополнение в SWR 1.0, которое позволяет вам выполнять\nлогику до и после SWR хуков.\n\n## Использование\n\nПромежуточное ПО получает SWR хук и может выполнять логику до и после его\nзапуска. Если ППО несколько, каждый ППО оборачивает последующий. Последний ППО в\nсписке получит исходный хук SWR — `useSWR`.\n\n### API\n\n```jsx\nfunction myMiddleware(useSWRNext) {\n  return (key, fetcher, config) => {\n    // До выполнения хука...\n\n    // Обработка следующего ППО, или хука `useSWR`, если это последнее.\n    const swr = useSWRNext(key, fetcher, config)\n\n    // После выполнения хука...\n    return swr\n  }\n}\n```\n\nВы можете передать массив из нескольких ППО как опцию `SWRConfig` или `useSWR`:\n\n```jsx\n<SWRConfig value={{ use: [myMiddleware] }}>\n\n// или...\n\nuseSWR(key, fetcher, { use: [myMiddleware] })\n```\n\n### Расширение\n\nПромежуточное ПО расширяется как обычные опции. Например:\n\n```jsx\nfunction Bar() {\n  useSWR(key, fetcher, { use: [c] })\n  // ...\n}\n\nfunction Foo() {\n  return (\n    <SWRConfig value={{ use: [a] }}>\n      <SWRConfig value={{ use: [b] }}>\n        <Bar />\n      </SWRConfig>\n    </SWRConfig>\n  )\n}\n```\n\nэквивалентно:\n\n```js\nuseSWR(key, fetcher, { use: [a, b, c] })\n```\n\n### Множество промежуточных ПО\n\nКаждое ППО обворачивает последующее, а последнее ППО обворачивает SWR хук.\nНапример:\n\n```jsx\nuseSWR(key, fetcher, { use: [a, b, c] })\n```\n\nПорядок выполнения ППО будет `a → b → c`, как показано ниже:\n\n```\nвход в  a\n  вход в  b\n    вход в  c\n      useSWR()\n    выход из  c\n  выход из  b\nвыход из  a\n```\n\n## Примеры\n\n### Регистратор запросов\n\nДавайте в качестве примера создадим простой ППО — регистратора запросов. Он\nвыводит все запросы fetcher-а, отправленные с этого хука SWR. Вы также можете\nиспользовать этот ППО для всех хуков SWR, добавив его в `SWRConfig`.\n\n```jsx\nfunction logger(useSWRNext) {\n  return (key, fetcher, config) => {\n    // Добавим регистратор в исходный fetcher.\n    const extendedFetcher = (...args) => {\n      console.log('SWR запрос:', key)\n      return fetcher(...args)\n    }\n\n    // Выполняем хук с новым fetcher-ом.\n    return useSWRNext(key, extendedFetcher, config)\n  }\n}\n\n// ... внутри вашего компонента\nuseSWR(key, fetcher, { use: [logger] })\n```\n\nКаждый раз, когда запрос запускается, он выводит ключ SWR в консоль:\n\n```\nSWR запрос: /api/user1\nSWR запрос: /api/user2\n```\n\n### Сохранение предыдущего результата\n\nИногда вы хотите, чтобы данные, возвращаемые `useSWR`, были «‎запаздывающими».\nДаже если ключ изменится, вы все равно хотите, чтобы он возвращал предыдущий\nрезультат, пока не загрузятся новые данные.\n\nЭто может быть построено как замедленное ППО используя `useRef`. В этом примере\nмы также собираемся расширить возвращаемый объект хука `useSWR`:\n\n```jsx\nimport { useCallback, useEffect, useRef } from 'react'\n\n// Это ППО SWR для хранения данных даже при изменении ключа.\nfunction laggy(useSWRNext) {\n  return (key, fetcher, config) => {\n    // Используйте ссылку для хранения ранее возвращённых данных.\n    const laggyDataRef = useRef()\n\n    // Фактический хук SWR.\n    const swr = useSWRNext(key, fetcher, config)\n\n    useEffect(() => {\n      // Обновите ссылку если данные определены.\n      if (swr.data !== undefined) {\n        laggyDataRef.current = swr.data\n      }\n    }, [swr.data])\n\n    // Предоставьте метод очистки запаздывающих данных, если таковые имеются.\n    const resetLaggy = useCallback(() => {\n      laggyDataRef.current = undefined\n    }, [])\n\n    // Возврат к предыдущим данным, если текущие данные не определены.\n    const dataOrLaggyData =\n      swr.data === undefined ? laggyDataRef.current : swr.data\n\n    // Показывает предыдущие данные?\n    const isLagging =\n      swr.data === undefined && laggyDataRef.current !== undefined\n\n    // Также добавьте поле `isLagging` в SWR.\n    return Object.assign({}, swr, {\n      data: dataOrLaggyData,\n      isLagging,\n      resetLaggy\n    })\n  }\n}\n```\n\nКогда вам нужно, чтобы хук SWR работал с задержкой, вы можете использовать это\nППО:\n\n```js\nconst { data, isLagging, resetLaggy } = useSWR(key, fetcher, { use: [laggy] })\n```\n\n### Сериализация ключей объекта\n\n<Callout>\n  Since SWR 1.1.0, object-like keys will be serialized under the hood\n  automatically.\n</Callout>\n\n<Callout type=\"warning\">\n  In older versions (< 1.1.0), SWR **shallowly** compares the arguments on every render, and triggers revalidation if any of them has changed.\n  If you are passing serializable objects as the key. You can serialize object keys to ensure its stability, a simple middleware can help:\n</Callout>\n\n```jsx\nfunction serialize(useSWRNext) {\n  return (key, fetcher, config) => {\n    // Сериализуйте ключ.\n    const serializedKey = Array.isArray(key) ? JSON.stringify(key) : key\n\n    // Передайте сериализованный ключ и десериализуйте его в fetcher-е.\n    return useSWRNext(serializedKey, (k) => fetcher(...JSON.parse(k)), config)\n  }\n}\n\n// ...\nuseSWR(['/api/user', { id: '73' }], fetcher, { use: [serialize] })\n\n// ... или включите его глобально с помощью\n<SWRConfig value={{ use: [serialize] }}>\n```\n\nВам не нужно беспокоиться о том, что объект может измениться между рендерами. Он\nвсегда сериализуется в одну и ту же строку, и fetcher по-прежнему получит эти\nаргументы объекта.\n\n<Callout>\n  Кроме того, вы можете использовать такие библиотеки, как\n  [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify)\n  вместо `JSON.stringify` — быстрее и стабильнее.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/mutation.md",
    "content": "# Мутация\n\n## Ревалидация\n\nВы можете получить функцию `mutate` из хука `useSWRConfig()`, и передать\nсообщение о ревалидации глобально другим SWR хукам<sup>\\*</sup>, использую тот\nже ключ, вызвав `mutate(key)`.\n\nВ этом примере показано, как автоматически обновлять информацию для входа\n(например, внутри `<Profile>`), когда пользователь нажимает кнопку «Выйти».\n\n```jsx\nimport useSWR, { useSWRConfig } from 'swr'\n\nfunction App() {\n  const { mutate } = useSWRConfig()\n\n  return (\n    <div>\n      <Profile />\n      <button\n        onClick={() => {\n          // установить cookie как просроченный\n          document.cookie =\n            'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'\n\n          // сообщить всем SWR с этим ключём, чтобы они ревалидировали\n          mutate('/api/user')\n        }}\n      >\n        Выйти\n      </button>\n    </div>\n  )\n}\n```\n\n\\*: _Транслируется всем SWR хукам с той же областью действия\n[кеш провайдера](/docs/cache). Если кеш-провайдера не существует, будет\nтранслироваться на все SWR хуки._\n\n## Мутация и POST запрос\n\nВо многих случаях применение локальных мутаций к данным — хороший способ\nускорить внесение изменений — не нужно ждать удаленного источника данных.\n\nС помощью `mutate` вы можете обновлять локальные данные программно, пока идёт\nревалидация и, в итоге, заменить их свежими данными.\n\n```jsx\nimport useSWR, { useSWRConfig } from 'swr'\n\nfunction Profile() {\n  const { mutate } = useSWRConfig()\n  const { data } = useSWR('/api/user', fetcher)\n\n  return (\n    <div>\n      <h1>Меня зовут {data.name}.</h1>\n      <button\n        onClick={async () => {\n          const newName = data.name.toUpperCase()\n\n          // немедленно обновить локальные данные, но отключить ревалидацию\n          mutate('/api/user', { ...data, name: newName }, false)\n\n          // отправить API запрос для обновления источника\n          await requestUpdateUsername(newName)\n\n          // вызвать ревалидацию (повторную выборку), чтобы убедиться, что наши локальные данные верны\n          mutate('/api/user')\n        }}\n      >\n        Перевести моё имя в верхнии регистр!\n      </button>\n    </div>\n  )\n}\n```\n\nНажатие кнопки в приведённом выше примере обновит локально данных клиента,\nотправит POST запрос для изменения удалённых данных и попытается получить свежие\n(ревалидировать).\n\nНо многие POST API возвращают обновленные данные напрямую, поэтому ревалидация\nне требуется. Вот пример, показывающий использование «локальная мутация -\nзапрос - обновление»:\n\n```jsx\nmutate('/api/user', newUser, false) // используйте `false` для мутации без ревалидации\nmutate('/api/user', updateUser(newUser), false) // `updateUser` является промисом запроса,\n// который возвращает обновленный документ\n```\n\n## Мутировать на основе текущих данных\n\nИногда вы хотите обновить часть ваших данных на основе текущих данных.\n\nС помощью `mutate` вы можете передать асинхронную функцию, которая получит\nтекущее закешированное значение, если оно есть, и вернет обновленный документ.\n\n```jsx\nmutate('/api/todos', async todos => {\n  // давайте обновим todo с ID равным `1`, и пометим его завершённым,\n  // этот API возвращает обновлённые данные\n  const updatedTodo = await fetch('/api/todos/1', {\n    method: 'PATCH',\n    body: JSON.stringify({ completed: true })\n  })\n\n  // отфильтруем список и вернём его с обновлённым элементом\n  const filteredTodos = todos.filter(todo => todo.id !== '1')\n  return [...filteredTodos, updatedTodo]\n})\n```\n\n## Возвращенные данные из мутации\n\nСкорее всего, вам понадобятся данные для обновления кеша. Данные разрешаются или\nвозвращаются из промиса или асинхронной функции, переданной в `mutate`.\n\nФункция, переданная в `mutate`, вернёт обновлённый документ, который\nиспользуется для обновления соответствующего значения кеша. Если при выполнении\nфункции выбрасывается ошибка, она будет выведена, чтобы её можно было обработать\nдолжным образом.\n\n```jsx\ntry {\n  const user = await mutate('/api/user', updateUser(newUser))\n} catch (error) {\n  // Обработайте ошибку здесь при обновлении пользователя\n}\n```\n\n## Связывание мутации\n\nОбъект SWR, возвращаемый `useSWR`, также содержит функцию `mutate()`, которая\nпредварительно привязана к ключу SWR.\n\nФункционально она эквивалентна глобальной функции `mutate`, но не требует\nпараметра `key`.\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, mutate } = useSWR('/api/user', fetcher)\n\n  return (\n    <div>\n      <h1>Меня зовут {data.name}.</h1>\n      <button\n        onClick={async () => {\n          const newName = data.name.toUpperCase()\n          // отправьте API запрос для обновления данных\n          await requestUpdateUsername(newName)\n          // немедленно обновите локальные данные и ревалидируйте их (повторная выборка)\n          // ПРИМЕЧАНИЕ: ключ не требуется при использовании мутации useSWR, поскольку он предварительно привязан\n          mutate({ ...data, name: newName })\n        }}\n      >\n        Перевести моё имя в верхнии регистр!\n      </button>\n    </div>\n  )\n}\n```\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/options.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Опции API\n\n```js\nconst { data, error, isValidating, mutate } = useSWR(key, fetcher, options)\n```\n\n## Параметры\n\n- `key`: уникальный строчный ключ для запроса (или функция / массив / null)\n  [(продвинутое использование)](/docs/conditional-fetching)\n- `fetcher`: (_опционально_) Promise возвращающий функцию для выборки данных\n  [(подробнее)](/docs/data-fetching)\n- `options`: (_опционально_) объект опций для этого SWR хука\n\n## Возвращаемые значения\n\n- `data`: данные для данного ключа, разрешенные `fetcher` (или undefined, если\n  не загружено)\n- `error`: ошибка, выброшенная `fetcher`-ом (или undefined)\n- `isValidating`: если запрос или ревалидация загружается\n- `mutate(data?, shouldRevalidate?)`: функция для мутации закешированных данных\n  [(подробнее)](/docs/mutation)\n\n## Опции\n\n- `suspense = false`: включить режим задержки React Suspense\n  [(подробнее)](/docs/suspense)\n- `fetcher(args)`: функция-fetcher\n- `revalidateIfStale = true`: автоматическая ревалидация при монтировании, даже\n  если есть устаревшие данные\n  [(подробнее)](/docs/revalidation#отключение-автоматических-ревалидаций)\n- `revalidateOnMount`: включить или отключить автоматическую ревалидацию при\n  монтировании компонента\n- `revalidateOnFocus = true`: автоматически ревалидировать, когда окно\n  фокусируется [(подробнее)](/docs/revalidation)\n- `revalidateOnReconnect = true`: автоматически ревалидировать, когда браузер\n  восстанавливает сетевое подключение (через `navigator.onLine`)\n  [(подробнее)](/docs/revalidation)\n- `refreshInterval` [(подробнее)](/docs/revalidation):\n  - по умолчанию отключен: `refreshInterval = 0`\n  - If set to a number, интервал поллинга в миллисекундах\n  - If set to a function, the function will receive the latest data and should\n    return the interval in milliseconds\n- `refreshWhenHidden = false`: поллинг, когда окно невидемо (если\n  `refreshInterval` включён)\n- `refreshWhenOffline = false`: поллинг, когда браузер оффлайн (определяется\n  `navigator.onLine`)\n- `shouldRetryOnError = true`: повторить попытку, если в fetcher-е возникла\n  ошибка\n- `dedupingInterval = 2000`: дедупликация запросов с тем же ключом за этот\n  промежуток времени в миллисекундах\n- `focusThrottleInterval = 5000`: проверять только один раз за период времени в\n  миллисекундах\n- `loadingTimeout = 3000`: тайм-аут для запуска события onLoadingSlow в\n  миллисекундах\n- `errorRetryInterval = 5000`: интервал повторной попытки ошибки в миллисекундах\n- `errorRetryCount`: максимальное количество повторных попыток при ошибке\n- `fallback`: объект типа \"ключ-значение\" из нескольких резервных данных\n  [(example)](/docs/with-nextjs)\n- `fallbackData`: исходные данные, которые должны быть возвращены (примечание:\n  это для каждого хука)\n- `onLoadingSlow(key, config)`: колбэк-функция, когда запрос загружается слишком\n  долго (см. `loadingTimeout`)\n- `onSuccess(data, key, config)`: колбэк-функция при успешном завершении запроса\n- `onError(err, key, config)`: колбэк-функция, когда запрос возвращает ошибку\n- `onErrorRetry(err, key, config, revalidate, revalidateOps)`: обработчик\n  повторной попытки при ошибке\n- `compare(a, b)`: функция сравнения, используемая для определения того, когда\n  возвращаемые данные были изменены, чтобы избежать ложных повторных отрисовок.\n  По умолчанию используется [dequal](https://github.com/lukeed/dequal).\n- `isPaused()`: функция, определяющая, приостанавливается ли ревалидация,\n  игнорирует полученные данные и ошибки, когда возвращает `true`. По умолчанию\n  возвращает `false`.\n- `use`: массив middleware-функций [(подробнее)](/docs/middleware)\n\n<Callout>\n  В медленной сети (2G, {'<='} 70 Кбит/с), `errorRetryInterval` будет 10 секунд,\n  а&nbsp;`loadingTimeout` будет по умолчанию 5 секунд.\n</Callout>\n\nВы также можете использовать\n[глобальную конфигурацию](/docs/global-configuration) для предоставления\nпараметров по умолчанию.\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/pagination.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Пагинация\n\n<Callout emoji=\"✅\">\n  Пожалуйста, обновитесь до последней версии (≥ 0.3.0), чтобы использовать этот\n  API. Предыдущий API `useSWRPages` является устаревшим.\n</Callout>\n\nSWR предоставляет специальный API `useSWRInfinite` для поддержки общепринятых UI\nшаблонов, таких как **пагинация** и **бесконечная загрузка**.\n\n## Когда использовать `useSWR`\n\n### Пагинация\n\nДля начала, нам может **НЕ** понадобится `useSWRInfinite`, а вместо него\nиспользовать просто `useSWR`, если мы создаем что-то вроде этого:\n\nimport { PaginationImage } from '@app/_icons'\n\n<PaginationImage className=\"mt-6 dark:invert\" />\n\n...что является типичной UI пагинацией. Посмотрим, как это легко реализовать с\nпомощью `useSWR`:\n\n```jsx {5}\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  // URL-адрес API включает индекс страницы, который является состоянием React.\n  const { data } = useSWR(`/api/data?page=${pageIndex}`, fetcher)\n\n  // ... обработка состояния загразки и ошибки\n\n  return (\n    <div>\n      {data.map(item => (\n        <div key={item.id}>{item.name}</div>\n      ))}\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Назад</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Вперёд</button>\n    </div>\n  )\n}\n```\n\nБолее того, мы можем создать абстракцию для этого «компонента страницы»:\n\n```jsx {13}\nfunction Page({ index }) {\n  const { data } = useSWR(`/api/data?page=${index}`, fetcher)\n\n  // ... обработка состояния загразки и ошибки\n\n  return data.map(item => <div key={item.id}>{item.name}</div>)\n}\n\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  return (\n    <div>\n      <Page index={pageIndex} />\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Назад</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Вперёд</button>\n    </div>\n  )\n}\n```\n\nБлагодаря кешу SWR мы получаем возможность предварительно загрузить следующую\nстраницу. Мы рендерим следующую страницу внутри скрытого div, поэтому SWR будет\nзапускать выборку данных следующей страницы. Когда пользователь переходит на\nследующую страницу, данные уже там:\n\n```jsx {6}\nfunction App() {\n  const [pageIndex, setPageIndex] = useState(0)\n\n  return (\n    <div>\n      <Page index={pageIndex} />\n      <div style={{ display: 'none' }}>\n        <Page index={pageIndex + 1} />\n      </div>\n      <button onClick={() => setPageIndex(pageIndex - 1)}>Назад</button>\n      <button onClick={() => setPageIndex(pageIndex + 1)}>Вперёд</button>\n    </div>\n  )\n}\n```\n\nВсего с одной строкой кода мы получаем улучшенный UX. Хук `useSWR` настолько\nмощный, что он покрывает большинство сценариев.\n\n### Бесконечная загрузка\n\nИногда мы хотим создать интерфейс **бесконечной загрузки** с кнопкой «Загрузить\nещё», которая добавляет данные в список (или делает это автоматически при\nпрокрутке):\n\nimport { InfiniteImage } from '@app/_icons'\n\n<InfiniteImage className=\"mt-6 dark:invert\" />\n\nЧтобы реализовать это, нам нужно сделать **динамическое количество запросов** на\nэтой странице. У хуков React есть\n[пара правил](https://ru.reactjs.org/docs/hooks-rules.html), поэтому мы **НЕ\nМОЖЕМ** делать что-то вроде этого:\n\n```jsx {5-9}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const list = []\n  for (let i = 0; i < cnt; i++) {\n    // 🚨 Это не правильно! Как правило, вы не можете использовать хуки внутри цикла.\n    const { data } = useSWR(`/api/data?page=${i}`)\n    list.push(data)\n  }\n\n  return (\n    <div>\n      {list.map((data, i) => (\n        <div key={i}>\n          {data.map(item => (\n            <div key={item.id}>{item.name}</div>\n          ))}\n        </div>\n      ))}\n      <button onClick={() => setCnt(cnt + 1)}>Загрузить ещё</button>\n    </div>\n  )\n}\n```\n\nВместо этого мы можем использовать абстракцию `<Page>`, которую мы создали для\nэтого:\n\n```jsx {5-7}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const pages = []\n  for (let i = 0; i < cnt; i++) {\n    pages.push(<Page index={i} key={i} />)\n  }\n\n  return (\n    <div>\n      {pages}\n      <button onClick={() => setCnt(cnt + 1)}>Загрузить ещё</button>\n    </div>\n  )\n}\n```\n\n### Продвинутые случаи\n\nОднако, в некоторых продвинутых случаях, приведенное выше решение не работает.\n\nНапример, мы всё ещё реализуем тот же UI «Загрузить ещё», но нам также\nнеобходимо отображать число, показывающее, сколько всего элементов имеется. Мы\nбольше не можем использовать решение `<Page>`, потому что UI верхнего уровня\n(`<App>`) нужны данные внутри каждой страницы:\n\n```jsx {10}\nfunction App() {\n  const [cnt, setCnt] = useState(1)\n\n  const pages = []\n  for (let i = 0; i < cnt; i++) {\n    pages.push(<Page index={i} key={i} />)\n  }\n\n  return (\n    <div>\n      <p>??? элементов</p>\n      {pages}\n      <button onClick={() => setCnt(cnt + 1)}>Загрузить ещё</button>\n    </div>\n  )\n}\n```\n\nКроме того, если используется API пагинации **на основе курсора**, это решение\nтоже не работает. Из-за того, что каждой странице нужны данные с предыдущей\nстраницы, они не изолированы.\n\nРешить эту задачу нам может помочь новый хук `useSWRInfinite`.\n\n## useSWRInfinite\n\n`useSWRInfinite` дает нам возможность запускать несколько запросов с помощью\nодного хука. Вот как это выглядит:\n\n```jsx\nimport useSWRInfinite from 'swr/infinite'\n\n// ...\nconst { data, error, isValidating, mutate, size, setSize } = useSWRInfinite(\n  getKey, fetcher?, options?\n)\n```\n\nПодобно `useSWR`, этот новый хук принимает функцию, которая возвращает ключ\nзапроса, функцию fetcher и опции. Он возвращает все значения, что и `useSWR`,\nвключая 2 дополнительных значения: размер страницы и установщик размера\nстраницы, как состояние React.\n\nПри бесконечной загрузке одна _страница_ — это один запрос, и наша цель —\nполучить несколько страниц и отобразить их.\n\n<Callout type=\"warning\">\n  Если вы используете версии SWR 0.x, `useSWRInfinite` необходимо импортировать\n  из `swr`:\n\n`import {useSWRInfinite} from 'swr'`\n\n</Callout>\n\n### API\n\n#### Параметры\n\n- `getKey`: функция, которая принимает индекс и данные предыдущей страницы,\n  возвращает ключ страницы\n- `fetcher`: то же, что и [fetcher-функция](/docs/data-fetching) `useSWR`\n- `options`: принимает все опции, которые поддерживает `useSWR`, с 3\n  дополнительными опциями:\n  - `initialSize = 1`: количество страниц, которые должны быть загружены\n    изначально\n  - `revalidateAll = false`: всегда пытаться ревалидировать все страницы\n  - `revalidateFirstPage = true`: always try to revalidate the first page\n  - `persistSize = false`: не сбрасывать размер страницы до 1 (или\n    `initialSize`, если установлен), когда ключ первой страницы изменяется\n\n<Callout>\n  Обратите внимание, что опцию `initialSize` нельзя изменять в жизненном цикле.\n</Callout>\n\n#### Возвращаемые значения\n\n- `data`: массив значений ответа выборки каждой страницы\n- `error`: то же , что и `error` в `useSWR`\n- `isValidating`: то же, что и `isValidating` в `useSWR`\n- `mutate`: то же, что и связанная функция мутации в `useSWR`, но манипулирует\n  массивом данных\n- `size`: количество страниц, которые _будут_ извлекаться и возвращаться\n- `setSize`: установить количество страниц, которые необходимо извлечь\n\n### Пример 1: API пагинации на основе индекса\n\nДля обычных API на основе индекса:\n\n```\nGET /users?page=0&limit=10\n[\n  { name: 'Алиса', ... },\n  { name: 'Вася', ... },\n  { name: 'Катя', ... },\n  ...\n]\n```\n\n```jsx {4-7,10}\n// Функция для получения ключа SWR каждой страницы,\n// её возвращаемое значение будет принято в `fetcher`.\n// Если возвращается `null`, запрос этой страницы не запускается.\nconst getKey = (pageIndex, previousPageData) => {\n  if (previousPageData && !previousPageData.length) return null // достигнут конец\n  return `/users?page=${pageIndex}&limit=10` // ключ SWR\n}\n\nfunction App() {\n  const { data, size, setSize } = useSWRInfinite(getKey, fetcher)\n  if (!data) return 'loading'\n\n  // Теперь мы можем подсчитать количество всех пользователей\n  let totalUsers = 0\n  for (let i = 0; i < data.length; i++) {\n    totalUsers += data[i].length\n  }\n\n  return (\n    <div>\n      <p>{totalUsers} users listed</p>\n      {data.map(users => {\n        // `data` — это массив ответов API каждой страницы.\n        return users.map(user => <div key={user.id}>{user.name}</div>)\n      })}\n      <button onClick={() => setSize(size + 1)}>Загрузить ещё</button>\n    </div>\n  )\n}\n```\n\nФункция `getKey` является основным отличием `useSWRInfinite` от `useSWR`. Она\nпринимает индекс текущей страницы, а также данные с предыдущей страницы. Таким\nобразом, оба API пагинации: на основе индекса, и на основе курсора хорошо\nподдерживаются.\n\nКроме того, `data` больше не является одним ответом API. Это массив из\nнескольких ответов API:\n\n```js\n// `data` будет выглядеть вот так:\n[\n  [\n    { name: 'Алиса', ... },\n    { name: 'Вася', ... },\n    { name: 'Катя', ... },\n    ...\n  ],\n  [\n    { name: 'Иван', ... },\n    { name: 'Павел', ... },\n    { name: 'Георгий', ... },\n    ...\n  ],\n  ...\n]\n```\n\n### Пример 2: API пагинации на основе курсора или смещения\n\nДопустим, API теперь требует курсор и возвращает следующий курсор вместе с\nданными:\n\n```plaintext\nGET /users?cursor=123&limit=10\n{\n  data: [\n    { name: 'Алиса' },\n    { name: 'Вася' },\n    { name: 'Катя' },\n    ...\n  ],\n  nextCursor: 456\n}\n```\n\nМы можем изменить нашу функцию `getKey` на:\n\n```jsx\nconst getKey = (pageIndex, previousPageData) => {\n  // достигнут конец\n  if (previousPageData && !previousPageData.data) return null\n\n  // первая страница, у нас нет `previousPageData`\n  if (pageIndex === 0) return `/users?limit=10`\n\n  // добавим курсор в endpoint API\n  return `/users?cursor=${previousPageData.nextCursor}&limit=10`\n}\n```\n\n### Расширенные возможности\n\n[Вот пример](/examples/infinite-loading), показывающий, как вы можете\nреализовать следующий функционал с помощью `useSWRInfinite`:\n\n- состояния загрузки\n- показ специального интерфейса, если он пуст\n- отключение кнопки «Загрузить ещё», если достигнут конец\n- изменяемый источник данных\n- обновление всего списка\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/prefetching.md",
    "content": "# Предварительная выборка данных\n\n## Данные страницы верхнего уровня\n\nЕсть много способов предварительно получить данные для SWR. Для запросов\nверхнего уровня настоятельно рекомендуется использовать\n[`rel=\"preload\"`](https://developer.mozilla.org/ru/docs/Web/HTML/Preloading_content):\n\n```html\n<link rel=\"preload\" href=\"/api/data\" as=\"fetch\" crossorigin=\"anonymous\" />\n```\n\nПросто поместите его в свой HTML `<head>`. Это просто, быстро и нативно.\n\nОн выполнит предварительную выборку данных при загрузке HTML, даже до того, как\nначнется загрузка JavaScript. Все ваши входящие запросы на выборку с одним и тем\nже URL-адресом будут повторно использовать этот результат (включая, конечно,\nSWR).\n\n## Программная предварительная выборка\n\nИногда вы хотите предварительно загрузить ресурс условно. Например,\nпредварительная загрузка данных, когда пользователь\n[наводит](https://github.com/GoogleChromeLabs/quicklink)\n[курсор](https://github.com/guess-js/guess) [на ссылку](https://instant.page).\nСамый интуитивно понятный способ — иметь функцию для повторной выборки и\nустановки кеша с помощью глобального [mutate](/docs/mutation):\n\n```js\nimport { mutate } from 'swr'\n\nfunction prefetch() {\n  mutate(\n    '/api/data',\n    fetch('/api/data').then(res => res.json())\n  )\n  // вторым параметром является промис\n  // SWR использует его результат, после того, как он разрешится\n}\n```\n\nВместе с такими техниками, как\n[предзагрузка страниц](https://nextjs.org/docs/api-reference/next/router#routerprefetch)\nв Next.js, вы сможете мгновенно загружать как следующую страницу, так и данные.\n\n## Предварительное заполнение данных\n\nЕсли вы хотите предварительно заполнить существующие данные в кэш SWR, вы можете\nиспользовать опцию `fallbackData`. Например:\n\n```jsx\nuseSWR('/api/data', fetcher, { fallbackData: prefetchedData })\n```\n\nЕсли SWR ещё не получил данные, этот хук вернёт `prefetchedData` в качестве\nзапасного варианта.\n\nВы также можете настроить это для всех SWR хуков и множественных ключей с\nпомощью `<SWRConfig>` и опцией `fallback`. Смотрите подробности в разделе\n[Next.js SSG и SSR](/docs/with-nextjs).\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/revalidation.mdx",
    "content": "import { Video } from '@app/_components/video'\nimport { Bleed, Callout } from 'nextra/components'\n\n# Автоматическая ревалидация\n\n<Callout>\n  Вы можете ревалидировать данные вручную, смотрите [мутацию](/docs/mutation).\n</Callout>\n\n## Ревалидация при фокусировке\n\nКогда вы перефокусируете страницу или переключаетесь между вкладками, SWR\nавтоматически ревалидирует данные.\n\nЭто может быть полезно для немедленной синхронизации с последним состоянием. Это\nполезно для обновления данных в таких сценариях, как устаревшие мобильные\nвкладки или ноутбуки, которые **перешли в спящий режим**.\n\n<Bleed>\n  <Video\n    src=\"https://raw.githubusercontent.com/vercel/swr-site/master/.github/videos/focus-revalidate.mp4\"\n    caption=\"Видео: использование ревалидации при фокусировке для автоматической синхронизации состояния входа в систему между страницами.\"\n    ratio={307 / 768}\n  />\n</Bleed>\n\nЭта функция включена по умолчанию. Вы можете её отключить через опцию\n[`revalidateOnFocus`](/docs/options).\n\n## Ревалидация с интервалом\n\nВо многих случаях данные меняются из-за нескольких устройств, нескольких\nпользователей, нескольких вкладок. Как мы можем со временем обновлять данные на\nэкране?\n\nSWR даст вам возможность автоматически обновлять данные. Он умный, что означает,\nчто повторная выборка будет происходить только в том случае, если компонент,\nсвязанный с хуком, находится **на экране**.\n\n<Bleed>\n  <Video\n    src=\"https://raw.githubusercontent.com/vercel/swr-site/master/.github/videos/refetch-interval.mp4\"\n    caption=\"Видео: когда пользователь вносит изменения, оба сеанса в конечном итоге будут отображать одни и те же данные.\"\n    ratio={307 / 768}\n  />\n</Bleed>\n\nВы можете включить её, установив значение для\n[`refreshInterval`](/docs/options):\n\n```js\nuseSWR('/api/todos', fetcher, { refreshInterval: 1000 })\n```\n\nЕсть также такие опции, как `refreshWhenHidden` и `refreshWhenOffline`. Обе они\nотключены по умолчанию, поэтому SWR не будет делать выборку, если веб-страница\nне отображается на экране или отсутствует сетевое соединение.\n\n## Ревалидация при повторном подключении\n\nТакже полезно провести ревалидацию, когда пользователь снова в сети. Этот\nсценарий часто случается, когда пользователь разблокирует свой компьютер, но в\nсоединение с Интернетом еще нет.\n\nЧтобы данные всегда были актуальными, SWR автоматически делает ревалидацию при\nвосстановлении сети.\n\nЭта функция включена по умолчанию. Вы можете её отключить через опцию\n[`revalidateOnReconnect`](/docs/options).\n\n## Отключение автоматических ревалидаций\n\nЕсли ресурс **неизменяемый**, и никогда не изменится при повторной ревалидации,\nмы можем отключить для него все виды автоматических ревалидаций.\n\nНачиная с версии 1.0, SWR предоставляет вспомогательный хук `useSWRImmutable`,\nчтобы пометить ресурс как неизменяемый:\n\n```js\nimport useSWRImmutable from 'swr/immutable'\n\n// ...\nuseSWRImmutable(key, fetcher, options)\n```\n\nОн имеет тот же API-интерфейс, что и обычный хук `useSWR`. Вы также можете\nсделать то же самое, отключив следующие опции ревалидации: It has the same API\ninterface as the normal `useSWR` hook. You can also do the same thing by disable\nthe following revalidation options:\n\n```js\nuseSWR(key, fetcher, {\n  revalidateIfStale: false,\n  revalidateOnFocus: false,\n  revalidateOnReconnect: false\n})\n\n// эквивалентно\nuseSWRImmutable(key, fetcher)\n```\n\n`revalidateIfStale`контролирует, должен ли SWR ревалидировать при монтировании и\nесть ли устаревшие данные.\n\nЭти 2 хука делают **то же самое**. После кэширования данных они больше никогда\nне будут запрашивать их.\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/suspense.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Задержка (Suspense)\n\n<Callout emoji=\"🚨\" type=\"error\">\n  Задержка (Suspense) в настоящее время является **экспериментальной** функцией React. Эти API могут значительно\n  измениться без предупреждения, прежде чем станут частью React.\n\n[Подробнее](https://reactjs.org/docs/concurrent-mode-suspense.html)\n\n</Callout>\n\n<Callout>\n  Обратите внимание, что React Suspense ещё не поддерживается в режиме SSR.\n</Callout>\n\nВы можете включить опцию `suspense`, чтобы использовать SWR с React Suspense:\n\n```jsx\nimport { Suspense } from 'react'\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data } = useSWR('/api/user', fetcher, { suspense: true })\n  return <div>привет, {data.name}</div>\n}\n\nfunction App() {\n  return (\n    <Suspense fallback={<div>загрузка...</div>}>\n      <Profile />\n    </Suspense>\n  )\n}\n```\n\n<Callout>\n  Обратите внимание, что опцию `suspense` нельзя изменять в жизненном цикле.\n</Callout>\n\nВ режиме задержки `data` всегда является ответом выборки (поэтому вам не нужно\nпроверять, является ли она `undefined`). Но если произошла ошибка, вам нужно\nиспользовать\n[предохранители](https://ru.reactjs.org/docs/concurrent-mode-suspense.html#handling-errors),\nчтобы её отловить:\n\n```jsx\n<ErrorBoundary fallback={<h2>Не удалось получить посты.</h2>}>\n  <Suspense fallback={<h1>Загрузка постов...</h1>}>\n    <Profile />\n  </Suspense>\n</ErrorBoundary>\n```\n\n---\n\n### Примечание: используя условную выборку\n\nОбычно, когда вы включаете `suspense`, гарантируется, что `data` всегда будет\nготова к рендерингу:\n\n```jsx\nfunction Profile() {\n  const { data } = useSWR('/api/user', fetcher, { suspense: true })\n\n  // `data` никогда не будет `undefined`\n  // ...\n}\n```\n\nОднако при её использовании вместе с условной выборкой или зависимой выборкой —\n`data` будет `undefined`, если запрос **приостановлен**:\n\n```jsx\nfunction Profile() {\n  const { data } = useSWR(isReady ? '/api/user' : null, fetcher, {\n    suspense: true\n  })\n\n  // `data` будет `undefined` если `isReady` имеет значение false\n  // ...\n}\n```\n\nЕсли вы хотите узнать больше технических подробностей об этом ограничении,\nсмотрите\n[обсуждения здесь](https://github.com/vercel/swr/pull/357#issuecomment-627089889).\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/understanding.mdx",
    "content": "import { Video } from '@app/_components/video'\nimport { Callout } from 'nextra/components'\n\n# Understanding SWR\n\n## State Machine\n\n`useSWR` returns `data`, `error`, `isLoading`, and `isValidating` depending on\nthe state of the `fetcher` function. This diagrams describe how SWR returns\nvalues in some scenarios.\n\n### Fetch and Revalidate\n\nThis pattern is to fetch data and revalidate it later.\n\n![A pattern for fetch and revalidate](/img/understanding/fetch-and-revalidate.svg)\n\n### Key Change\n\nThis pattern is to fetch data and change the key and revalidate it later.\n\n![A pattern for key change](/img/understanding/key-change.svg)\n\n### Key Change + Previous Data\n\nThis pattern is to fetch data and change the key and revalidate it later with\nthe `keepPreviousData` option.\n\n![A pattern for key change + previous data](/img/understanding/key-change-previous-data.svg)\n\n### Fallback\n\nThis pattern is to fetch data and revalidate it later with fallback data.\n\n![A pattern for fallback](/img/understanding/fallback.svg)\n\n### Key Change + Fallback\n\nThis pattern is to fetch data and change the key and revalidate it later with\nfallback data.\n\n![A pattern for key change + fallback](/img/understanding/key-change-fallback.svg)\n\n### Key Change + Previous Data + Fallback\n\nThis pattern is to fetch data and change the key and revalidate it later with\nthe `keepPreviousData` option and fallback data.\n\n![A pattern for key change + previous data + fallback](/img/understanding/key-change-previous-data-fallback.svg)\n\n## Combining with isLoading and isValidating for better UX\n\nComparing to the existing `isValidating` value, `isLoading` is a new property\nthat can help you for the more general loading cases for UX.\n\n- `isValidating` becomes `true` whenever there is an ongoing request **whatever\n  the the data is loaded or not**\n- `isLoading` becomes `true` when there is an ongoing request and **data is not\n  loaded yet**.\n\nSimply saying you can use `isValidating` for indicating everytime there is an\nongoing revalidation, and `isLoading` for indicating that SWR is revalidating\nbut there is no data yet to display.\n\n<Callout emoji=\"📝\">\n  Fallback data and previous data are not considered \"loaded data,\" so when you\n  use fallback data or enable the keepPreviousData option, you might have data\n  to display.\n</Callout>\n\n```jsx\nfunction Stock() {\n  const { data, isLoading, isValidating } = useSWR(STOCK_API, fetcher, {\n    refreshInterval: 3000\n  })\n\n  // If it's still loading the initial data, there is nothing to display.\n  // We return a skeleton here.\n  if (isLoading) return <div className=\"skeleton\" />\n\n  // Otherwise, display the data and a spinner that indicates a background\n  // revalidation.\n  return (\n    <>\n      <div>${data}</div>\n      {isValidating ? <div className=\"spinner\" /> : null}\n    </>\n  )\n}\n```\n\n![An example of using the isLoading state](/img/understanding/isloading.gif)\n\nYou can find the code example\n[here](https://codesandbox.io/s/swr-isloading-jtopow)\n\n## Return previous data for better UX\n\nWhen doing data fetching based on continuous user actions, e.g. real-time search\nwhen typing, keeping the previous fetched data can improve the UX a lot.\n`keepPreviousData` is an option to enable that behavior. Here's a simple search\nUI:\n\n```jsx\nfunction Search() {\n  const [search, setSearch] = React.useState('');\n\n  const { data, isLoading } = useSWR(`/search?q=${search}`, fetcher, {\n    keepPreviousData: true\n  });\n\n  return (\n    <div>\n      <input\n        type=\"text\"\n        value={search}\n        onChange={(e) => setSearch(e.target.value)}\n        placeholder=\"Search...\"\n      />\n\n      <div className={isLoading ? \"loading\" : \"\"}>\n        {data?.products.map(item => <Product key={item.id} name={item.name} />)\n      </div>\n    </div>\n  );\n}\n```\n\nWith `keepPreviousData` enabled, you will still get the previous data even if\nyou change the SWR key and the data for the new key starts loading again.\n\n<Video\n  src=\"https://user-images.githubusercontent.com/3676859/163695903-a3eb1259-180e-41e0-821e-21c320201194.mp4\"\n  caption=\"Keep previous search results when keepPreviousData has been enabled\"\n  ratio={640 / 730}\n/>\n\nYou can find the full code for this example here:\nhttps://codesandbox.io/s/swr-keeppreviousdata-fsjz3m.\n\n## Dependency Collection for performance\n\nSWR only triggers re-rendering when the states used in the component have been\nupdated. If you only use `data` in the component, SWR ignores the updates of\nother properties like `isValidating`, and `isLoading`. This reduces rendering\ncounts a lot. More information can be found\n[here](/docs/advanced/performance#dependency-collection).\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/with-nextjs.mdx",
    "content": "import { Callout } from 'nextra/components'\n\n# Использование с Next.js\n\n## Выборка данных на стороне клиента\n\nЕсли ваша страница содержит часто обновляемые данные, и вам не нужно\nпредварительно рендерить их, SWR идеально подходит и не требует специальной\nнастройки: просто импортируйте `useSWR` и используйте хук внутри любых\nкомпонентов, которые используют данные.\n\nВот как это работает:\n\n- Во-первых, сразу покажите страницу без данных. Вы можете отображать состояния\n  загрузки для отсутствующих данных.\n- Затем получите данные на стороне клиента и отобразите их по готовности.\n\nЭтот подход хорошо работает, например, для личных кабинетов. Поскольку личный\nкабинет является частной страницей, ориентированной на конкретного пользователя,\nпоисковая оптимизация не имеет значения, и страницу не нужно предварительно\nрендерить. Данные часто обновляются, что требует выборки данных во время\nзапроса.\n\n## Предварительный рендеринг с данными по умолчанию\n\nЕсли страницу необходимо предварительно отрендерить, Next.js поддерживает\n[2 формы пререндеринга](https://nextjs.org/docs/basic-features/data-fetching):  \n**Статическая генерация (SSG)** и **Серверный рендеринг (SSR)**.\n\nВместе с SWR вы можете предварительно обработать страницу для SEO, а также иметь\nтакие функции, как кэширование, ревалидация, отслеживание фокуса, интервальная\nповторная выборка на стороне клиента.\n\nВы можете использовать `fallback` опцию\n[`SWRConfig`](/docs/global-configuration), чтобы передать предварительно\nвыбранные данные в качестве начального значения всех SWR хуков. Например, с\n`getStaticProps`:\n\n```jsx\nexport async function getStaticProps() {\n  // `getStaticProps` выполняется на стороне сервера.\n  const article = await getArticleFromAPI()\n  return {\n    props: {\n      fallback: {\n        '/api/article': article\n      }\n    }\n  }\n}\n\nfunction Article() {\n  // `data` всегда будет дуступна, так как находится в `fallback`.\n  const { data } = useSWR('/api/article', fetcher)\n  return <h1>{data.title}</h1>\n}\n\nexport default function Page({ fallback }) {\n  // SWR хуки в пределах `SWRConfig` будет использовать эти значения.\n  return (\n    <SWRConfig value={{ fallback }}>\n      <Article />\n    </SWRConfig>\n  )\n}\n```\n\nСтраница всё ещё предварительно отрендерина. Она оптимизирована для SEO, быстро\nреагирует на запросы, а также полностью поддерживает SWR на стороне клиента.\nДанные могут быть динамическими и автоматически обновляться с течением времени.\n\n<Callout>\n  Компонент `Article` сначала отрендерит предварительно сгенерированные данные,\n  а после гидратации страницы он снова получит последние данные, чтобы они были\n  актуальными.\n</Callout>\n"
  },
  {
    "path": "examples/swr-site/content/ru/docs/wrap-toc-items.mdx",
    "content": "# Wrap Table of Content Items Properly\n\nTests whether long table of content items are wrapped properly for alignment.\n\n## First Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Second Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n#### Third Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n## Fourth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Fifth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n## No Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n\n### Sixth Long ToC Item That Definitely Needs to Wrap\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\nincididunt ut labore et dolore magna aliqua. Tempus egestas sed sed risus\npretium quam vulputate. Imperdiet proin fermentum leo vel orci porta non\npulvinar. Commodo elit at imperdiet dui. Elit ullamcorper dignissim cras\ntincidunt lobortis feugiat vivamus at. Purus gravida quis blandit turpis cursus\nin. Pharetra pharetra massa massa ultricies mi. Pretium lectus quam id leo.\nCursus turpis massa tincidunt dui ut. Nulla pharetra diam sit amet nisl suscipit\nadipiscing bibendum est. Et netus et malesuada fames. Nisl nisi scelerisque eu\nultrices vitae auctor eu augue ut. Molestie a iaculis at erat pellentesque\nadipiscing. Leo vel fringilla est ullamcorper. Faucibus interdum posuere lorem\nipsum. Sed arcu non odio euismod.\n"
  },
  {
    "path": "examples/swr-site/content/ru/examples/_meta.ts",
    "content": "export default {\n  basic: 'Основное использование',\n  auth: 'Аутентификация',\n  'infinite-loading': 'Бесконечная загрузка',\n  'error-handling': 'Обработка ошибок',\n  ssr: 'Next.js SSR'\n}\n"
  },
  {
    "path": "examples/swr-site/content/ru/examples/auth.mdx",
    "content": "---\ntitle: Аутентификация\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-auth-tuqtf?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Аутентификация\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/ru/examples/basic.mdx",
    "content": "---\ntitle: Основное использование\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-basic-p7dg6?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Основное использование\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/ru/examples/error-handling.mdx",
    "content": "---\ntitle: Обработка ошибок\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-states-4une7?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Обработка ошибок\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/ru/examples/infinite-loading.mdx",
    "content": "---\ntitle: Бесконечная загрузка\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-infinite-z6r0r?file=/src/App.js?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Бесконечная загрузка\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/ru/examples/ssr.mdx",
    "content": "---\ntitle: Next.js SSR\n---\n\n<iframe\n  src=\"https://codesandbox.io/embed/swr-ssr-j9b2y?file=/pages/index.js?codemirror=1&fontsize=14&theme=dark&autoresize=1&hidenavigation=1\"\n  style={{\n    width: '100%',\n    height: '100%',\n    border: 0,\n    overflow: 'hidden',\n    background: 'rgb(21, 21, 21)'\n  }}\n  title=\"SWR - Next.js SSR\"\n  allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n  sandbox=\"allow-autoplay allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n/>\n"
  },
  {
    "path": "examples/swr-site/content/ru/index.mdx",
    "content": "---\ntitle: React хуки для получения данных\nsearchable: false\n---\n\nimport { Features } from '@app/_components/features'\nimport { Callout } from 'nextra/components'\n\n# SWR\n\n<Features lang={props.params.lang} title={metadata.title} />\n\nНазвание \"SWR\" происходит от `stale-while-revalidate`, стратегия инвалидации\nHTTP-кеша, популяризированная\n[HTTP RFC 5861](https://tools.ietf.org/html/rfc5861). SWR — это стратегия,\nкоторая сначала возвращает данные из кеша (устаревшие), затем отправляет запрос\n(ревалидация), и в итоге возвращает актуальные данные.\n\n<Callout emoji=\"✅\">\n  С SWR, компоненты получат поток **постоянно** и **автоматически** обновляющихся данных.\n\nИ пользовательский интерфейс всегда будет **быстрым** и **реактивным**.\n\n</Callout>\n\n<div className=\"mt-16 mb-20 text-center\">\n  [Начать работу](/docs/getting-started) · [Примеры](/examples/basic) ·\n  [Блог](/blog) · [Репозиторий GitHub](https://github.com/vercel/swr)\n</div>\n\n## Обзор\n\n```jsx\nimport useSWR from 'swr'\n\nfunction Profile() {\n  const { data, error } = useSWR('/api/user', fetcher)\n\n  if (error) return <div>ошибка загрузки</div>\n  if (!data) return <div>загрузка...</div>\n  return <div>привет, {data.name}!</div>\n}\n```\n\nВ этом примере, хук `useSWR` принимает строку `key` и функцию `fetcher`. `key` —\nэто уникальный идентификатор данных (обычно URL-адрес API), который будет\nпередан в `fetcher`. `fetcher` может быть любая асинхронная функция, которая\nвозвращает данные, будь то нативный fetch или такие инструменты как Axios.\n\nХук возвращает 2 значения: `data` и `error`, основанные на статусе запроса.\n\n## Особенности\n\nВсего одной строкой кода вы можете упростить логику получения данных в своём\nпроекте, а также у вас будут эти удивительные возможности прямо из коробки:\n\n- **Быстрая**, **легковесная** и **многократно используемая** выборка данных\n- Встроенный **кеш** и дедупликация запросов\n- Опыт **реального времени**\n- Независимость от транспорта и протокола\n- Поддержка SSR / ISR / SSG\n- Готовность использования TypeScript\n- React Native\n\nSWR охватывает все аспекты скорости, правильности и стабильности, чтобы помочь\nвам улучшить опыт:\n\n- Быстрая навигация по страницам\n- Интервальный опрос\n- Зависимость от данных\n- Ревалидация при фокусировке\n- Ревалидация при восстановлении сети\n- Локальные мутации (Optimistic UI)\n- Умная повторная попытка при ошибке\n- Пагинация и восстановление позиции прокрутки\n- React Задержка (Suspense)\n\nИ многое [другое](/docs/getting-started).\n\n## Сообщество\n\n<p className=\"mt-6 flex h-6 gap-2\">\n  <img alt=\"звёзды\" src=\"https://badgen.net/github/stars/vercel/swr\" />\n  <img alt=\"загрузки\" src=\"https://badgen.net/npm/dt/swr\" />\n  <img alt=\"лицензия\" src=\"https://badgen.net/npm/license/swr\" />\n</p>\n\nSWR создана той же командой, что стоит за React фреймворком\n[Next.js](https://nextjs.org). Следите за [@vercel](https://twitter.com/vercel)\nв Твиттере, чтобы получать новости о проекте.\n\nПрисоединяйтесь к\n[обсуждениям на GitHub](https://github.com/vercel/swr/discussions)!\n"
  },
  {
    "path": "examples/swr-site/mdx-components.ts",
    "content": "import { useMDXComponents as getDocsMDXComponents } from 'nextra-theme-docs'\nimport { Pre, withIcons } from 'nextra/components'\nimport { GitHubIcon } from 'nextra/icons'\nimport type { UseMDXComponents } from 'nextra/mdx-components'\n\nconst docsComponents = getDocsMDXComponents({\n  pre: withIcons(Pre, { js: GitHubIcon })\n})\n\nexport const useMDXComponents: UseMDXComponents<typeof docsComponents> = <T>(\n  components?: T\n) => ({\n  ...docsComponents,\n  ...components\n})\n"
  },
  {
    "path": "examples/swr-site/next.config.ts",
    "content": "import bundleAnalyzer from '@next/bundle-analyzer'\nimport nextra from 'nextra'\n\nconst withNextra = nextra({\n  defaultShowCopyCode: true,\n  latex: true,\n  contentDirBasePath: '/'\n})\n\nconst withBundleAnalyzer = bundleAnalyzer({\n  enabled: process.env.ANALYZE === 'true'\n})\n\nconst nextConfig = withBundleAnalyzer(\n  withNextra({\n    reactStrictMode: true,\n    i18n: {\n      locales: ['en', 'es', 'ru'],\n      defaultLocale: 'en'\n    },\n    redirects: () => [\n      {\n        source: '/docs',\n        destination: '/docs/getting-started',\n        statusCode: 302\n      }\n    ],\n    webpack(config) {\n      // rule.exclude doesn't work starting from Next.js 15\n      const { test: _test, ...imageLoaderOptions } = config.module.rules.find(\n        // @ts-expect-error -- fixme\n        rule => rule.test?.test?.('.svg')\n      )\n      config.module.rules.push({\n        test: /\\.svg$/,\n        oneOf: [\n          {\n            resourceQuery: /svgr/,\n            use: ['@svgr/webpack']\n          },\n          imageLoaderOptions\n        ]\n      })\n      return config\n    },\n    turbopack: {\n      rules: {\n        './app/_icons/*.svg': {\n          loaders: ['@svgr/webpack'],\n          as: '*.js'\n        }\n      }\n    },\n    experimental: {\n      optimizePackageImports: [\n        // '@app/_icons'\n      ]\n    }\n  })\n)\n\nexport default nextConfig\n"
  },
  {
    "path": "examples/swr-site/nextra-remote-filepaths/fetch.js",
    "content": "import { fetchFilePathsFromGitHub } from 'nextra/fetch-filepaths-from-github'\n\nfetchFilePathsFromGitHub({\n  user: 'dotansimha',\n  repo: 'graphql-yoga',\n  // last commit with v2 source docs\n  branch: '291daaaf3921b2ab875d988b7a7880ee277f247e',\n  docsPath: 'website/src/pages/v2/',\n  outputPath: './nextra-remote-filepaths/graphql-yoga.json'\n})\n\nfetchFilePathsFromGitHub({\n  user: 'B2o5T',\n  repo: 'graphql-eslint',\n  branch: '34b722a2a520599ce06a4ddcccc9623b76434089',\n  docsPath: 'website/src/pages/docs/',\n  outputPath: './nextra-remote-filepaths/graphql-eslint.json'\n})\n"
  },
  {
    "path": "examples/swr-site/nextra-remote-filepaths/graphql-eslint.json",
    "content": "{\n  \"user\": \"B2o5T\",\n  \"repo\": \"graphql-eslint\",\n  \"branch\": \"34b722a2a520599ce06a4ddcccc9623b76434089\",\n  \"docsPath\": \"website/src/pages/docs/\",\n  \"filePaths\": [\n    \"configs.mdx\",\n    \"custom-rules.mdx\",\n    \"getting-started.mdx\",\n    \"getting-started/parser-options.mdx\",\n    \"getting-started/parser.mdx\",\n    \"index.mdx\"\n  ]\n}"
  },
  {
    "path": "examples/swr-site/nextra-remote-filepaths/graphql-yoga.json",
    "content": "{\n  \"user\": \"dotansimha\",\n  \"repo\": \"graphql-yoga\",\n  \"branch\": \"291daaaf3921b2ab875d988b7a7880ee277f247e\",\n  \"docsPath\": \"website/src/pages/v2/\",\n  \"filePaths\": [\n    \"features/apollo-federation.mdx\",\n    \"features/context.mdx\",\n    \"features/cors.mdx\",\n    \"features/envelop-plugins.mdx\",\n    \"features/error-masking.mdx\",\n    \"features/file-uploads.mdx\",\n    \"features/graphiql.mdx\",\n    \"features/subscriptions.mdx\",\n    \"features/testing.mdx\",\n    \"index.mdx\",\n    \"integrations/integration-with-aws-lambda.mdx\",\n    \"integrations/integration-with-cloudflare-workers.mdx\",\n    \"integrations/integration-with-deno.mdx\",\n    \"integrations/integration-with-express.mdx\",\n    \"integrations/integration-with-fastify.mdx\",\n    \"integrations/integration-with-koa.mdx\",\n    \"integrations/integration-with-nestjs.mdx\",\n    \"integrations/integration-with-nextjs.mdx\",\n    \"integrations/integration-with-sveltekit.mdx\",\n    \"integrations/z-other-environments.mdx\",\n    \"migration/migration-from-apollo-server.mdx\",\n    \"migration/migration-from-express-graphql.mdx\",\n    \"migration/migration-from-yoga-v1.mdx\"\n  ]\n}"
  },
  {
    "path": "examples/swr-site/package.json",
    "content": "{\n  \"name\": \"swr-site\",\n  \"type\": \"module\",\n  \"author\": \"Shu Ding\",\n  \"license\": \"Apache-2.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"analyze\": \"ANALYZE=true pnpm build\",\n    \"build\": \"next build\",\n    \"debug\": \"NODE_OPTIONS='--inspect' next dev\",\n    \"dev\": \"next\",\n    \"postbuild\": \"pagefind --site .next/server/app --output-path public/_pagefind\",\n    \"prebuild\": \"node nextra-remote-filepaths/fetch.js\",\n    \"predev\": \"pnpm prebuild\",\n    \"start\": \"next start\",\n    \"types:check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"markdown-to-jsx\": \"^7.4.0\",\n    \"next\": \"^16.0.7\",\n    \"nextra\": \"workspace:*\",\n    \"nextra-theme-docs\": \"workspace:*\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\",\n    \"react-intersection-observer\": \"^8.26.2\"\n  },\n  \"devDependencies\": {\n    \"@next/bundle-analyzer\": \"^14.2.13\",\n    \"@tailwindcss/postcss\": \"4.1.10\",\n    \"@types/react\": \"^19.1.8\",\n    \"pagefind\": \"^1.3.0\",\n    \"tailwindcss\": \"4.1.10\"\n  },\n  \"browserslist\": [\n    \">= .25%\",\n    \"not dead\"\n  ]\n}\n"
  },
  {
    "path": "examples/swr-site/postcss.config.js",
    "content": "/** @type {import('postcss').Postcss} */\nexport default {\n  plugins: {\n    '@tailwindcss/postcss': {}\n  }\n}\n"
  },
  {
    "path": "examples/swr-site/proxy.ts",
    "content": "export { proxy } from 'nextra/locales'\n\nexport const config = {\n  // Matcher ignoring `/_next/` and `/api/`\n  matcher: [\n    '/((?!api|_next/static|_next/image|favicon.ico|icon.svg|apple-icon.png|manifest|_pagefind).*)'\n  ]\n}\n"
  },
  {
    "path": "examples/swr-site/public/favicon/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo src=\"/mstile-150x150.png\"/>\n            <TileColor>#ffffff</TileColor>\n        </tile>\n    </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "examples/swr-site/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noEmit\": true,\n    \"incremental\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"react-jsx\",\n    \"moduleResolution\": \"bundler\",\n    \"baseUrl\": \"./\",\n    \"paths\": {\n      \"@app/*\": [\"./app/*\"]\n    },\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ],\n    \"strictNullChecks\": true,\n    \"noUncheckedIndexedAccess\": true\n  },\n  \"include\": [\n    \"next-env.d.ts\",\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \".next/types/**/*.ts\",\n    \".next/dev/types/**/*.ts\"\n  ],\n  \"exclude\": [\"node_modules\", \".next\"]\n}\n"
  },
  {
    "path": "examples/swr-site/vercel.json",
    "content": "{\n  \"public\": true\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"nextra-monorepo\",\n  \"private\": true,\n  \"packageManager\": \"pnpm@9.15.9\",\n  \"scripts\": {\n    \"build\": \"turbo run build --filter=./packages/\\\\*\",\n    \"build:all\": \"turbo run build\",\n    \"clean\": \"rm -rf .turbo && pnpm -r exec sh -c 'rm -rf dist .next .turbo'\",\n    \"dev\": \"turbo run dev --filter=./packages/\\\\*\",\n    \"dev:theme-blog\": \"turbo run dev --filter=example-blog... --filter=!docs\",\n    \"dev:theme-docs\": \"turbo run dev --filter=example-docs... --filter=!docs\",\n    \"dev:theme-i18n\": \"turbo run dev --filter=swr-site... --filter=!docs\",\n    \"dev:website\": \"turbo run dev --filter=docs...\",\n    \"format\": \"pnpm prettier --write\",\n    \"lint\": \"ESLINT_USE_FLAT_CONFIG=true eslint --config packages/eslint-config/src/index.ts --cache --max-warnings 0 .\",\n    \"lint:prettier\": \"pnpm prettier --check\",\n    \"postinstall\": \"pnpm build\",\n    \"prettier\": \"prettier --config-path packages/prettier-config/src/index.js --cache --ignore-path .gitignore --ignore-path .prettierignore --experimental-cli .\",\n    \"release\": \"changeset publish\",\n    \"test\": \"turbo run test\",\n    \"types:check\": \"turbo run types:check\",\n    \"version\": \"changeset version\"\n  },\n  \"devDependencies\": {\n    \"@changesets/cli\": \"2.29.4\",\n    \"@rollup/plugin-alias\": \"5.1.1\",\n    \"eslint\": \"9.39.1\",\n    \"prettier\": \"3.7.4\",\n    \"rimraf\": \"6.0.1\",\n    \"tsup\": \"8.4.0\",\n    \"turbo\": \"2.6.2\",\n    \"typescript\": \"5.9.3\"\n  },\n  \"pnpm\": {\n    \"overrides\": {\n      \"postcss\": \"8.5.6\",\n      \"lightningcss\": \"1.30.1\",\n      \"esbuild\": \"0.25.8\",\n      \"vite\": \"6.3.5\",\n      \"next\": \"16.0.10\"\n    },\n    \"patchedDependencies\": {\n      \"esbuild-plugin-svgr@3.1.1\": \"patches/esbuild-plugin-svgr.patch\",\n      \"@changesets/assemble-release-plan@6.0.8\": \"patches/@changesets__assemble-release-plan.patch\",\n      \"tsup\": \"patches/tsup.patch\",\n      \"next\": \"patches/next.patch\",\n      \"eslint-plugin-tailwindcss@3.17.3\": \"patches/eslint-plugin-tailwindcss.patch\"\n    }\n  }\n}\n"
  },
  {
    "path": "packages/esbuild-react-compiler-plugin/package.json",
    "content": "{\n  \"name\": \"esbuild-react-compiler-plugin\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"description\": \"\",\n  \"author\": \"Dimitri POSTOLOV\",\n  \"license\": \"ISC\",\n  \"private\": true,\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.js\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"scripts\": {\n    \"build\": \"tsup\",\n    \"dev\": \"tsup --watch\",\n    \"types:check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"babel-plugin-react-compiler\": \"^19.1.0-rc.2\",\n    \"react-compiler-webpack\": \"0.2.0\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.10.2\"\n  }\n}\n"
  },
  {
    "path": "packages/esbuild-react-compiler-plugin/src/env.d.ts",
    "content": "declare module 'react-compiler-webpack/dist/react-compiler-loader.js' {\n  export default function reactCompilerLoader(\n    source: string | Buffer\n  ): Promise<void>\n}\n"
  },
  {
    "path": "packages/esbuild-react-compiler-plugin/src/index.ts",
    "content": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport type { PluginOptions as ReactCompilerConfig } from 'babel-plugin-react-compiler'\nimport reactCompilerLoader from 'react-compiler-webpack/dist/react-compiler-loader.js'\nimport type { Options } from 'tsup'\n\nconst DEFAULT_REACT_COMPILER_CONFIG: Partial<ReactCompilerConfig> = {\n  sources(filename: string) {\n    return !filename.includes('node_modules')\n  },\n  // panicThreshold: 'all_errors',\n  target: '18',\n  logger: {\n    logEvent(filename, result) {\n      if (!filename) {\n        throw new Error('Missing filename')\n      }\n      const relativeFilePath = path.relative(process.cwd(), filename)\n      if (result.kind === 'CompileSuccess') {\n        console.info(\n          '🚀 File',\n          relativeFilePath,\n          'was optimized with react-compiler'\n        )\n        return\n      }\n      console.error(\n        '❌ File',\n        relativeFilePath,\n        'was not optimized with react-compiler'\n      )\n      console.error(result)\n      if (process.env.NODE_ENV === 'production') {\n        // eslint-disable-next-line unicorn/no-process-exit\n        process.exit(1)\n      }\n    }\n  }\n}\n\nexport const reactCompilerPlugin = ({\n  filter,\n  config\n}: {\n  filter: RegExp\n  config?: object\n}): NonNullable<Options['esbuildPlugins']>[number] => ({\n  name: 'react-compiler',\n  setup(build) {\n    config = {\n      ...DEFAULT_REACT_COMPILER_CONFIG,\n      ...config\n    }\n\n    build.onLoad({ filter }, async args => {\n      const {\n        contents = await fs.readFile(args.path),\n        loader = path.extname(args.path).slice(1) as 'ts' | 'tsx'\n      } = args.pluginData ?? {}\n      return new Promise<{\n        contents: string\n        loader: 'ts' | 'tsx'\n      }>((resolve, reject) => {\n        function callback(error: Error | null, result?: string) {\n          if (!result) {\n            reject(error)\n            return\n          }\n          resolve({ contents: result, loader })\n        }\n\n        reactCompilerLoader.call(\n          {\n            async: () => callback,\n            getOptions: () => config,\n            resourcePath: args.path\n          },\n          contents\n        )\n      })\n    })\n  }\n})\n"
  },
  {
    "path": "packages/esbuild-react-compiler-plugin/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2022\",\n    \"module\": \"ESNext\",\n    \"declaration\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": true,\n    \"lib\": [\"esnext\", \"dom\"],\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"noUncheckedIndexedAccess\": true\n  },\n  \"exclude\": [\"dist\"]\n}\n"
  },
  {
    "path": "packages/esbuild-react-compiler-plugin/tsup.config.ts",
    "content": "import { defineConfig } from 'tsup'\nimport packageJson from './package.json'\n\nexport default defineConfig({\n  name: packageJson.name,\n  entry: ['src/**/*.ts'],\n  format: 'esm',\n  dts: true,\n  splitting: process.env.NODE_ENV === 'production',\n  bundle: false\n})\n"
  },
  {
    "path": "packages/eslint-config/CHANGELOG.md",
    "content": "# @nextra/eslint-config\n\n## 0.0.1\n"
  },
  {
    "path": "packages/eslint-config/package.json",
    "content": "{\n  \"name\": \"@nextra/eslint-config\",\n  \"version\": \"0.0.1\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"scripts\": {\n    \"types:check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@eslint/compat\": \"2.0.0\",\n    \"@eslint/js\": \"9.39.1\",\n    \"@next/eslint-plugin-next\": \"16.0.7\",\n    \"eslint-config-prettier\": \"10.1.8\",\n    \"eslint-plugin-de-morgan\": \"2.0.0\",\n    \"eslint-plugin-import-x\": \"4.16.1\",\n    \"eslint-plugin-react\": \"7.37.5\",\n    \"eslint-plugin-react-hooks\": \"6.0.0-rc1\",\n    \"eslint-plugin-sonarjs\": \"3.0.5\",\n    \"eslint-plugin-tailwindcss\": \"3.17.3\",\n    \"eslint-plugin-typescript-sort-keys\": \"3.3.0\",\n    \"eslint-plugin-unicorn\": \"62.0.0\",\n    \"typescript-eslint\": \"8.48.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^22.10.5\"\n  }\n}\n"
  },
  {
    "path": "packages/eslint-config/src/index.ts",
    "content": "import path from 'node:path'\nimport { includeIgnoreFile } from '@eslint/compat'\nimport js from '@eslint/js'\nimport eslintPluginNext from '@next/eslint-plugin-next'\nimport type { Linter } from 'eslint'\n// import type { Linter } from 'eslint'\nimport eslintConfigPrettier from 'eslint-config-prettier'\nimport eslintPluginDeMorgan from 'eslint-plugin-de-morgan'\nimport eslintPluginImport from 'eslint-plugin-import-x'\nimport eslintPluginReact from 'eslint-plugin-react'\nimport eslintPluginReactHooks from 'eslint-plugin-react-hooks'\nimport eslintPluginSonarJs from 'eslint-plugin-sonarjs'\n// import eslintPluginTailwindCss from 'eslint-plugin-tailwindcss'\n// @ts-expect-error -- no types\nimport eslintPluginTsSortKeys from 'eslint-plugin-typescript-sort-keys'\nimport eslintPluginUnicorn from 'eslint-plugin-unicorn'\nimport { defineConfig } from 'eslint/config'\nimport tseslint from 'typescript-eslint'\n\n// TODO: Enable once `eslint-plugin-tailwindcss` will support Tailwind CSS v4\n// const TAILWIND_CONFIG = {\n//   extends: [eslintPluginTailwindCss.configs['flat/recommended']],\n//   rules: {\n//     'tailwindcss/classnames-order': 'off', // conflicts with prettier-plugin-tailwindcss\n//     'tailwindcss/enforces-negative-arbitrary-values': 'error',\n//     'tailwindcss/enforces-shorthand': 'error',\n//     'tailwindcss/migration-from-tailwind-2': 'error',\n//     'tailwindcss/no-custom-classname': 'error'\n//   } satisfies Linter.RulesRecord\n// }\n\nconst REACT_COMPILER_RESTRICT = {\n  name: 'react',\n  importNames: ['memo', 'useCallback', 'useMemo']\n}\n\nexport default defineConfig(\n  includeIgnoreFile(path.resolve('.gitignore')),\n  {\n    ignores: [\n      '**/generated-page-map.ts',\n      '**/next-env.d.ts',\n      '**/snapshots/**',\n      '**/types.generated.ts'\n    ]\n  },\n  // Rules for all files\n  {\n    files: ['**/*.{js,jsx,cjs,mjs,ts,tsx,cts,mts}'],\n    extends: [\n      js.configs.recommended,\n      tseslint.configs.recommended,\n      eslintPluginUnicorn.configs.recommended,\n      eslintPluginSonarJs.configs.recommended,\n      eslintPluginDeMorgan.configs.recommended,\n      eslintConfigPrettier\n    ],\n    plugins: {\n      // @ts-expect-error -- fixme\n      import: eslintPluginImport\n    },\n    rules: {\n      'no-extra-boolean-cast': ['error', { enforceForInnerExpressions: true }],\n      'prefer-object-has-own': 'error',\n      'logical-assignment-operators': [\n        'error',\n        'always',\n        { enforceForIfStatements: true }\n      ],\n      'no-else-return': ['error', { allowElseIf: false }],\n      'no-lonely-if': 'error',\n      'prefer-destructuring': [\n        'error',\n        { VariableDeclarator: { object: true } }\n      ],\n      'import/no-duplicates': 'error',\n      'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],\n      'object-shorthand': ['error', 'always'],\n      '@typescript-eslint/prefer-for-of': 'error',\n      quotes: ['error', 'single', { avoidEscape: true }], // Matches Prettier, but also replaces backticks\n      '@typescript-eslint/no-unused-vars': [\n        'error',\n        {\n          argsIgnorePattern: '^_',\n          varsIgnorePattern: '^_' // allow underscores in destructuring\n        }\n      ],\n      'prefer-object-spread': 'error',\n      'prefer-arrow-callback': ['error', { allowNamedFunctions: true }],\n      'prefer-const': ['error', { destructuring: 'all' }],\n      eqeqeq: ['error', 'always', { null: 'ignore' }],\n      'unicorn/switch-case-braces': ['error', 'avoid'],\n      'no-undef': 'off', // https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors\n\n      'unicorn/no-array-sort': 'off', // todo\n      'sonarjs/unused-named-groups': 'off', // todo\n      'sonarjs/cognitive-complexity': 'off', // todo\n      'sonarjs/prefer-nullish-coalescing': 'off', // todo\n      'sonarjs/no-nested-conditional': 'off', // todo\n      'sonarjs/slow-regex': 'off', // todo\n      'sonarjs/different-types-comparison': 'off', // todo\n      'sonarjs/default-param-last': 'off', // todo\n      'sonarjs/no-misleading-array-reverse': 'off', // todo\n      'sonarjs/sonar-prefer-regexp-exec': 'off', // todo\n      'sonarjs/no-nested-functions': 'off', // todo\n      'sonarjs/todo-tag': 'off', // todo\n      'sonarjs/no-unknown-property': 'off', // todo\n      'sonarjs/hook-use-state': 'off', // todo\n      'sonarjs/no-nested-template-literals': 'off', // todo\n      'sonarjs/label-has-associated-control': 'off', // todo\n      'sonarjs/no-nested-assignment': 'off', // todo\n      'sonarjs/function-return-type': 'off', // todo\n      'sonarjs/table-header': 'off', // todo\n      'sonarjs/anchor-is-valid': 'off', // todo\n      'sonarjs/sonar-no-unused-vars': 'off', // todo\n      'sonarjs/no-var': 'off', // todo\n      'sonarjs/argument-type': 'off', // todo\n      'sonarjs/no-array-index-key': 'off', // todo\n      'sonarjs/no-unstable-nested-components': 'off', // todo\n\n      'sonarjs/no-redundant-optional': 'off', // doesn't work well with tsconfig's `exactOptionalPropertyTypes: true`\n      'sonarjs/no-duplicate-in-composite': 'off', // covered by @typescript-eslint/no-duplicate-type-constituents\n      'sonarjs/deprecation': 'off', // covered by @typescript-eslint/no-deprecated\n      'sonarjs/no-unused-vars': 'off',\n      'sonarjs/prefer-regexp-exec': 'off',\n      'sonarjs/fixme-tag': 'off',\n      '@typescript-eslint/no-explicit-any': 'off', // Too many cases\n      'unicorn/prevent-abbreviations': 'off', // Too many cases\n      'unicorn/explicit-length-check': 'off', // I don't like\n      'unicorn/no-null': 'off', // I don't like\n      'unicorn/prefer-global-this': 'off', // Bundlers are smarter with `typeof window === 'undefined'` checks\n      'unicorn/prefer-optional-catch-binding': 'off' // catch by @typescript-eslint/no-unused-vars\n    }\n  },\n  // Rules for React files\n  {\n    files: ['{packages,examples,docs}/**'],\n    plugins: {\n      'react-hooks': eslintPluginReactHooks,\n      '@next/next': eslintPluginNext\n    },\n    extends: [\n      eslintPluginReact.configs.flat.recommended,\n      eslintPluginReact.configs.flat['jsx-runtime']\n    ],\n    rules: {\n      ...eslintPluginReactHooks.configs.recommended.rules,\n      ...(eslintPluginNext.configs.recommended.rules as Linter.RulesRecord),\n      ...(eslintPluginNext.configs['core-web-vitals']\n        .rules as Linter.RulesRecord),\n      'react/prop-types': 'off',\n      'react/no-unknown-property': ['error', { ignore: ['jsx'] }],\n      'react-hooks/exhaustive-deps': 'error',\n      'react/self-closing-comp': 'error',\n      'no-restricted-syntax': [\n        'error',\n        {\n          // ❌ z.object(…)\n          selector: 'MemberExpression[object.name=z] > .property[name=object]',\n          message: 'Use z.strictObject is more safe.'\n        }\n      ],\n      'react/jsx-filename-extension': [\n        'error',\n        { extensions: ['.tsx', '.jsx'], allow: 'as-needed' }\n      ],\n      'react/jsx-curly-brace-presence': 'error',\n      'react/jsx-boolean-value': 'error',\n      '@next/next/no-html-link-for-pages': 'off' // we use App Router\n    },\n    settings: {\n      react: { version: 'detect' }\n    }\n  },\n  // Rules for TypeScript files\n  {\n    files: ['**/*.{ts,tsx,cts,mts}'],\n    plugins: {\n      'typescript-sort-keys': eslintPluginTsSortKeys\n    },\n    // TODO: fix errors\n    // extends: [tseslint.configs.recommendedTypeChecked],\n    languageOptions: {\n      parserOptions: {\n        projectService: true\n      }\n    },\n    rules: {\n      '@typescript-eslint/no-duplicate-type-constituents': 'error',\n      '@typescript-eslint/no-redundant-type-constituents': 'error',\n      '@typescript-eslint/no-deprecated': 'error',\n      '@typescript-eslint/await-thenable': 'error',\n      '@typescript-eslint/no-unnecessary-type-assertion': 'error',\n      '@typescript-eslint/consistent-type-imports': 'error',\n      '@typescript-eslint/non-nullable-type-assertion-style': 'error',\n      '@typescript-eslint/prefer-optional-chain': 'error',\n      'prefer-destructuring': 'off',\n      '@typescript-eslint/prefer-destructuring': [\n        'error',\n        { VariableDeclarator: { object: true } }\n      ],\n      '@typescript-eslint/no-unnecessary-condition': 'error'\n    }\n  },\n  {\n    files: ['packages/**'],\n    rules: {\n      'no-restricted-imports': ['error', REACT_COMPILER_RESTRICT],\n      'react-hooks/react-compiler': 'error'\n    }\n  },\n  // ⚙️ nextra-theme-docs\n  {\n    // ...TAILWIND_CONFIG,\n    files: ['packages/nextra-theme-docs/**'],\n    settings: {\n      tailwindcss: {\n        callees: ['cn'],\n        whitelist: [\n          'nextra-navbar',\n          'nextra-navbar-blur',\n          'nextra-sidebar',\n          'nextra-breadcrumb',\n          'nextra-sidebar-footer',\n          'nextra-toc'\n        ]\n      }\n    },\n    rules: {\n      // ...TAILWIND_CONFIG.rules,\n      'no-restricted-imports': [\n        'error',\n        { name: 'next/link', message: 'Use `<Anchor>` instead' },\n        REACT_COMPILER_RESTRICT\n      ],\n      // False positive due Tailwind CSS v4\n      'tailwindcss/no-custom-classname': 'off'\n    }\n  },\n  // ⚙️ nextra-theme-blog\n  {\n    // ...TAILWIND_CONFIG,\n    files: ['packages/nextra-theme-blog/**'],\n    rules: {\n      // ...TAILWIND_CONFIG.rules,\n      'no-restricted-imports': [\n        'error',\n        {\n          name: 'next/link',\n          message: 'Use `<Link>` from `next-view-transitions` instead'\n        },\n        {\n          name: 'next/navigation',\n          importNames: ['useRouter'],\n          message:\n            'Use `useTransitionRouter` from `next-view-transitions` instead'\n        }\n      ],\n      // False positive due Tailwind CSS v4\n      'tailwindcss/no-custom-classname': 'off'\n    }\n  },\n  // ⚙️ nextra\n  {\n    // ...TAILWIND_CONFIG,\n    files: ['packages/nextra/**'],\n    settings: {\n      tailwindcss: {\n        callees: ['cn'],\n        whitelist: [\n          'nextra-code',\n          'nextra-filetree',\n          'nextra-bleed',\n          'nextra-skip-nav',\n          'nextra-search-results'\n        ]\n      }\n    },\n    rules: {\n      // ...TAILWIND_CONFIG.rules,\n      'import/extensions': ['error', 'ignorePackages'],\n      // False positive due Tailwind CSS v4\n      'tailwindcss/no-custom-classname': 'off'\n    }\n  },\n  // ⚙️ Docs\n  {\n    // ...TAILWIND_CONFIG,\n    files: ['docs/**'],\n    settings: {\n      tailwindcss: {\n        callees: ['cn'],\n        whitelist: [\n          'dash-ring',\n          'theme-1',\n          'theme-2',\n          'theme-3',\n          'theme-4',\n          'subtitle',\n          'headline',\n          'content-container',\n          'feat-darkmode',\n          'features-container',\n          // New in TailwindCSS v4\n          'z-1',\n          'z-2',\n          '.*nextra-focus' // I can't ignore colon `:`, use `*` instead\n        ],\n        cssFiles: [\n          'docs/app/globals.css',\n          'docs/app/_components/features/style.module.css',\n          'packages/nextra-theme-docs/dist/style.css'\n        ]\n      },\n      next: { rootDir: 'docs' }\n    }\n  },\n  // ⚙️ SWR-site example\n  {\n    // ...TAILWIND_CONFIG,\n    files: ['examples/swr-site/**'],\n    settings: {\n      tailwindcss: {\n        cssFiles: [\n          'examples/swr-site/app/[lang]/styles.css',\n          'examples/swr-site/app/_components/features.css',\n          'packages/nextra-theme-docs/dist/style.css'\n        ],\n        whitelist: [\n          '.*nextra-focus' // I can't ignore colon `:`, use `*` instead\n        ]\n      },\n      next: { rootDir: 'examples/swr-site' }\n    }\n  },\n  // ⚙️ blog example\n  {\n    files: ['examples/blog/**'],\n    settings: {\n      next: { rootDir: 'examples/blog' }\n    }\n  },\n  // ⚙️ docs example\n  {\n    files: ['examples/docs/**'],\n    settings: {\n      next: { rootDir: 'examples/docs' }\n    }\n  },\n  {\n    files: ['**/*.d.ts'],\n    rules: {\n      'no-var': 'off'\n    }\n  }\n)\n"
  },
  {
    "path": "packages/eslint-config/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2022\",\n    \"module\": \"ESNext\",\n    \"declaration\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": true,\n    \"lib\": [\"esnext\", \"dom\"],\n    \"moduleResolution\": \"node\",\n    \"noUncheckedIndexedAccess\": true\n  },\n  \"exclude\": [\"dist\"]\n}\n"
  },
  {
    "path": "packages/nextra/CHANGELOG.md",
    "content": "# nextra\n\n## 4.6.2\n\n### Patch Changes\n\n- 9e6f5af: Fix Pagefind search not working when using `basePath` in Next.js\n  config\n\n  When deploying Nextra to a subpath (e.g., `basePath: '/docs'`), the Pagefind\n  search would fail to load index files because `baseUrl` was hardcoded to `'/'`\n  instead of using `addBasePath('/')`.\n\n## 4.6.1\n\n### Patch Changes\n\n- 261fcdc: - update zod to v4 stable\n  - fix compatibility with Next.js 16\n\n## 4.6.0\n\n## 4.5.1\n\n### Patch Changes\n\n- 8a4d176: fix TSDoc `@inline` tag to properly expand nested type aliases\n\n## 4.5.0\n\n### Minor Changes\n\n- 356a782: fix copy page button does not return the correct page contents due to\n  cached MDX compiler\n\n  add a `copyPageButton` layout prop which show/hide copy page content button\n\n## 4.4.0\n\n### Minor Changes\n\n- 26b1281: feat: add Copy Documentation button/dropdown feature as LLM-Optimized\n  Prompt\n\n  ![](https://private-user-images.githubusercontent.com/7361780/473206831-aa851d94-3b83-46e8-8b00-5bf06c33314f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTQ0NjgwNzUsIm5iZiI6MTc1NDQ2Nzc3NSwicGF0aCI6Ii83MzYxNzgwLzQ3MzIwNjgzMS1hYTg1MWQ5NC0zYjgzLTQ2ZTgtOGIwMC01YmYwNmMzMzMxNGYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDgwNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA4MDZUMDgwOTM1WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MjgwZTI3YWMzODYwNjEwNTgwNGUyOTJkMDg5MzNjOGRjZWE0MWYzMWQwZmM3ZDJkMjQzMDc2ZDRjMzQ4ZTRlZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.C7LZXaay7uuPQsDBb3MKLrbiBWxTPM2q9nfSqUGp3_0)\n\n  > **Note**\n  >\n  > If you are using\n  > [`content` directory](https://nextra.site/docs/file-conventions/content-directory),\n  > you **must** pass the `sourceCode` prop to enable this feature.\n  >\n  > ```diff\n  > const {\n  >   default: MDXContent,\n  >   toc,\n  >   metadata,\n  > + sourceCode\n  > } = await importPage(params.mdxPath)\n  > return (\n  > - <Wrapper toc={toc} metadata={metadata}>\n  > + <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>\n  >     <MDXContent {...props} params={params} />\n  >   </Wrapper>\n  > )\n  > ```\n\n## 4.3.0\n\n### Minor Changes\n\n- eed8328: feat: adapt colors and icons from original GitHub alerts syntax\n\n  feat: new Callout type `important`\n\n  fix: inconsistent built-in Callout's icons size\n\n  feat: improve Callout's accessibility colors\n\n- 0831a1b: Add an `onSearch` callback to the `<Search />` component. This\n  callback, when specified, is called upon every search input change.\n- b0afee7: feat(tsdoc): add support for `@inline` tag on function parameters\n- c93fc48: update zod to v4\n\n  feat(TSDoc): rename `generateDocumentation` to `generateDefinition`\n\n  feat(Bleed): pass all props from `div` element to `Bleed`, `Callout`, `Banner`\n  container\n\n  fix(TSDoc): improve TSDoc comments for components\n  - `Banner`\n  - `Head`\n  - `Search`\n  - `Bleed`\n  - `Callout`\n  - `Cards`\n  - `FileTree`\n  - `Steps`\n  - `Table`\n  - `Tabs`\n  - `Playground`\n  - `TSDoc`\n  - `Layout`\n  - `Navbar`\n\n  fix(TSDoc): improve TSDoc comments for functions:\n  - `nextra`\n  - `generateDefinition`\n  - `useMDXComponents`\n\n- 01ac538: feat(tsdoc): support @inline tag and fix mobile overflow in <TSDoc />\n  table\n- 94b081c: feat: refactor `<Search>` component styles for improved transitions\n  and visibility\n- b5fab80: add `MDXRemote` component docs page\n  https://nextra.site/docs/built-ins/mdxremote\n- ef35ab9: accept all `ComboboxInputProps` in Nextra's `<Search />` component\n- d9dd061: update `tailwindcss` to `4.1.10` and `react-compiler-runtime` to\n  `19.1.0-rc.2`\n- c134abe: feat: improve overall accessibility, makes text/colors easier to read\n  and achieves WCAG Level AAA compliance in many places\n- 83f6c57: feat: introduce new `<TSDoc />` component\n\n  The `<TSDoc>` component from `nextra/tsdoc` generates a properties table that\n  displays:\n  - **Property name**\n  - **TypeScript type**\n  - **Property description** - is parsed from [TSDoc](https://tsdoc.org) inline\n    description or the `@description` tag. You can use any Markdown/MDX syntax\n    here.\n  - **Default value** - are extracted from the `@default` or `@defaultValue`\n    tag.\n  - **Permalink** - a `#` anchor link to the property row for easy reference.\n\n  More info can be found in https://nextra.site/docs/built-ins/tsdoc\n\n  > [!IMPORTANT]\n  >\n  > Huge thanks to\n  > [xyflow - Node Based UIs for React and Svelte](https://xyflow.com/?utm_source=github&utm_campaign=nextra-4.3&utm_content=changelog)\n  > for sponsoring this feature!\n\n- 07debf9: feat(TSDoc): support flattening return object fields\n\n### Patch Changes\n\n- 71f7b3f: Update https://nextra.site/docs/guide/search page\n\n  Fixes extra margin-top inside `Tabs.Tab`\n\n  Fix breaking `<Steps>` component numeration when there is `<Tabs>` component\n  inside\n\n- 47ba5f3: fix: use `em` for padding-y, padding-x and border-radius styles of\n  `<Code>` element\n\n  fix(TSDoc): for return signature without `name` return mobile card instead of\n  table\n\n  feat: use `em` instead `rem` for margins\n\n- 40267dc: split `TSDoc` component logic to `TSDoc` component and\n  `generateDocumentation` function\n\n  update https://nextra.site/docs/built-ins/tsdoc documentation\n\n- f717156: feat(TSDoc): enable `exactOptionalPropertyTypes` and\n  `strictNullChecks` in ts-morph `compilerOptions`\n- 9f449e5: fix(TSDoc): should show `null` type in properties table\n- 8ac2506: chore: bump `babel-plugin-react-compiler` and\n  `react-compiler-runtime`, remove custom pnpm patch for\n  `babel-plugin-react-compiler`\n- a6a1f97: fix(tsdoc): check `@inline` and `@remarks` tags on alias type too in\n  addition to field tags\n- fda0355: fix tsdoc File not found: /var/task/.../tsconfig.json\n- b2cba90: improve TSDoc comments for `getPageMap`, `generateStaticParamsFor`\n  and `importPage` functions. Add new https://nextra.site/docs/guide/api page.\n- f40e018: fix TSDoc error `Expected to find an alias symbol` when using\n  `@inline` comment\n- d29469e: support Next.js 15.3.0\n- 6a82e6f: - Fix: Received `false` for a non-boolean attribute `prefetch`.\n  - Allow override `next-mdx-import-source-file` in `turbopack.resolveAlias`\n    option\n- 7de40fb: Update Tailwind CSS guide to match v4 version\n  https://nextra.site/docs/advanced/tailwind-css\n- c7d25df: fix(tsdoc): should resolve `Partial` types as declared\n- 4547eb9: feat(TSDoc): add support for functions and functions with multiple\n  signatures\n- 407e0c4: feat(TSDoc): add `TSDoc.noParametersContent` prop\n- 00f4696: add https://nextra.site/api page generated with TSDoc component\n- 31ddba4: improve LaTeX docs, mention that you need apply styles for KaTeX\n  https://nextra.site/docs/advanced/latex#apply-styles\n- a506e0b: fix `TypeError: page.generateMetadata is not a function` when using\n  with `withSentryConfig` plugin\n- 9690841: Upgrade remark-reading-time to 2.0.2 in dependencies.\n\n## 4.3.0-alpha.31\n\n### Patch Changes\n\n- f40e018: fix TSDoc error `Expected to find an alias symbol` when using\n  `@inline` comment\n\n## 4.3.0-alpha.30\n\n### Minor Changes\n\n- b0afee7: feat(tsdoc): add support for `@inline` tag on function parameters\n\n## 4.3.0-alpha.29\n\n### Patch Changes\n\n- a6a1f97: fix(tsdoc): check `@inline` and `@remarks` tags on alias type too in\n  addition to field tags\n\n## 4.3.0-alpha.28\n\n### Minor Changes\n\n- ef35ab9: accept all `ComboboxInputProps` in Nextra's `<Search />` component\n\n## 4.3.0-alpha.27\n\n### Minor Changes\n\n- 01ac538: feat(tsdoc): support @inline tag and fix mobile overflow in <TSDoc />\n  table\n\n## 4.3.0-alpha.26\n\n### Patch Changes\n\n- c7d25df: fix(tsdoc): should resolve `Partial` types as declared\n\n## 4.3.0-alpha.25\n\n### Minor Changes\n\n- d9dd061: update `tailwindcss` to `4.1.10` and `react-compiler-runtime` to\n  `19.1.0-rc.2`\n\n## 4.3.0-alpha.24\n\n### Minor Changes\n\n- 0831a1b: Add an `onSearch` callback to the `<Search />` component. This\n  callback, when specified, is called upon every search input change.\n\n## 4.3.0-alpha.23\n\n### Patch Changes\n\n- 9690841: Upgrade remark-reading-time to 2.0.2 in dependencies.\n\n## 4.3.0-alpha.22\n\n### Minor Changes\n\n- c93fc48: update zod to v4\n\n  feat(TSDoc): rename `generateDocumentation` to `generateDefinition`\n\n  feat(Bleed): pass all props from `div` element to `Bleed`, `Callout`, `Banner`\n  container\n\n  fix(TSDoc): improve TSDoc comments for components\n  - `Banner`\n  - `Head`\n  - `Search`\n  - `Bleed`\n  - `Callout`\n  - `Cards`\n  - `FileTree`\n  - `Steps`\n  - `Table`\n  - `Tabs`\n  - `Playground`\n  - `TSDoc`\n  - `Layout`\n  - `Navbar`\n\n  fix(TSDoc): improve TSDoc comments for functions:\n  - `nextra`\n  - `generateDefinition`\n  - `useMDXComponents`\n\n- b5fab80: add `MDXRemote` component docs page\n  https://nextra.site/docs/built-ins/mdxremote\n\n## 4.3.0-alpha.21\n\n### Patch Changes\n\n- 6a82e6f: - Fix: Received `false` for a non-boolean attribute `prefetch`.\n  - Allow override `next-mdx-import-source-file` in `turbopack.resolveAlias`\n    option\n\n## 4.3.0-alpha.20\n\n## 4.3.0-alpha.19\n\n### Patch Changes\n\n- 407e0c4: feat(TSDoc): add `TSDoc.noParametersContent` prop\n\n## 4.3.0-alpha.18\n\n### Patch Changes\n\n- 7de40fb: Update Tailwind CSS guide to match v4 version\n  https://nextra.site/docs/advanced/tailwind-css\n- 00f4696: add https://nextra.site/api page generated with TSDoc component\n- 31ddba4: improve LaTeX docs, mention that you need apply styles for KaTeX\n  https://nextra.site/docs/advanced/latex#apply-styles\n\n## 4.3.0-alpha.17\n\n## 4.3.0-alpha.16\n\n## 4.3.0-alpha.15\n\n### Patch Changes\n\n- b2cba90: improve TSDoc comments for `getPageMap`, `generateStaticParamsFor`\n  and `importPage` functions. Add new https://nextra.site/docs/guide/api page.\n\n## 4.3.0-alpha.14\n\n### Patch Changes\n\n- a506e0b: fix `TypeError: page.generateMetadata is not a function` when using\n  with `withSentryConfig` plugin\n\n## 4.3.0-alpha.13\n\n### Patch Changes\n\n- 47ba5f3: fix: use `em` for padding-y, padding-x and border-radius styles of\n  `<Code>` element\n\n  fix(TSDoc): for return signature without `name` return mobile card instead of\n  table\n\n  feat: use `em` instead `rem` for margins\n\n- d29469e: support Next.js 15.3.0\n\n## 4.3.0-alpha.12\n\n### Patch Changes\n\n- 40267dc: split `TSDoc` component logic to `TSDoc` component and\n  `generateDocumentation` function\n\n  update https://nextra.site/docs/built-ins/tsdoc documentation\n\n## 4.3.0-alpha.11\n\n### Patch Changes\n\n- 71f7b3f: Update https://nextra.site/docs/guide/search page\n\n  Fixes extra margin-top inside `Tabs.Tab`\n\n  Fix breaking `<Steps>` component numeration when there is `<Tabs>` component\n  inside\n\n## 4.3.0-alpha.10\n\n## 4.3.0-alpha.9\n\n### Minor Changes\n\n- 94b081c: feat: refactor `<Search>` component styles for improved transitions\n  and visibility\n\n## 4.3.0-alpha.8\n\n### Minor Changes\n\n- c134abe: feat: improve overall accessibility, makes text/colors easier to read\n  and achieves WCAG Level AAA compliance in many places\n\n## 4.3.0-alpha.7\n\n### Minor Changes\n\n- 07debf9: feat(TSDoc): support flattening return object fields\n\n## 4.3.0-alpha.6\n\n## 4.3.0-alpha.5\n\n### Minor Changes\n\n- eed8328: feat: adapt colors and icons from original GitHub alerts syntax\n\n  feat: new Callout type `important`\n\n  fix: inconsistent built-in Callout's icons size\n\n  feat: improve Callout's accessibility colors\n\n## 4.3.0-alpha.4\n\n### Patch Changes\n\n- 4547eb9: feat(TSDoc): add support for functions and functions with multiple\n  signatures\n\n## 4.3.0-alpha.3\n\n### Patch Changes\n\n- f717156: feat(TSDoc): enable `exactOptionalPropertyTypes` and\n  `strictNullChecks` in ts-morph `compilerOptions`\n\n## 4.3.0-alpha.2\n\n### Patch Changes\n\n- 8ac2506: chore: bump `babel-plugin-react-compiler` and\n  `react-compiler-runtime`, remove custom pnpm patch for\n  `babel-plugin-react-compiler`\n\n## 4.3.0-alpha.1\n\n### Patch Changes\n\n- 9f449e5: fix(TSDoc): should show `null` type in properties table\n\n## 4.3.0-alpha.0\n\n### Minor Changes\n\n- 83f6c57: feat: introduce new `<TSDoc />` component\n\n  The `<TSDoc>` component from `nextra/tsdoc` generates a properties table that\n  displays:\n  - **Property name**\n  - **TypeScript type**\n  - **Property description** - is parsed from [TSDoc](https://tsdoc.org) inline\n    description or the `@description` tag. You can use any Markdown/MDX syntax\n    here.\n  - **Default value** - are extracted from the `@default` or `@defaultValue`\n    tag.\n  - **Permalink** - a `#` anchor link to the property row for easy reference.\n\n  More info can be found in https://nextra.site/docs/built-ins/tsdoc\n\n  > [!IMPORTANT]\n  >\n  > Huge thanks to\n  > [xyflow - Node Based UIs for React and Svelte](https://xyflow.com/?utm_source=github&utm_campaign=nextra-4.3&utm_content=changelog)\n  > for sponsoring this feature!\n\n## 4.2.18\n\n### Patch Changes\n\n- e1c2b1b: chore: update `shiki` and `@shikijs/twoslash` packages to version 3\n\n## 4.2.17\n\n### Patch Changes\n\n- a7db0e6: fix: use correct `ReactNode` zod validation for\n  `Layout.footer/banner/editLink/feedback.content/toc.backToTop/toc.extraContent/toc.title/search`\n  and `Navbar.children/projectIcon/chatIcon`\n- 18e7fb9: fix: allow override `NextraConfig.mdxOptions.format` option in\n  `next.config` file\n\n## 4.2.16\n\n### Patch Changes\n\n- 2cfaacc: fix: frozen spinner on loading state in search results by updating\n  Tailwind CSS to v4.0.10\n\n## 4.2.15\n\n### Patch Changes\n\n- 5617e04: fix: loading state in search results was only visible during the\n  first search\n\n## 4.2.14\n\n### Patch Changes\n\n- ccb5da2: removing custom nextra's scrollbar styles, allowing the browser's\n  default scrollbars to be used\n- 05a202d: fix: make search results appear above the navbar\n\n## 4.2.13\n\n### Patch Changes\n\n- fc4035c: add code block icon for `svelte` language\n- fc4035c: increase `z-index` for banner to `30` to fix hidden banner when\n  mobile nav is open\n\n## 4.2.12\n\n## 4.2.11\n\n## 4.2.10\n\n### Patch Changes\n\n- 5c22495: - add `Navbar.align` prop to align navigation links to the specified\n  side. (default `'right'`)\n  - fix hidden nav links when specified with `type: 'page', href: '...'` in\n    `_meta` files\n\n## 4.2.9\n\n## 4.2.8\n\n## 4.2.7\n\n## 4.2.6\n\n### Patch Changes\n\n- a7906d1: use `decodeURIComponent` instead `decodeURI` to properly decode `&`\n  character\n\n## 4.2.5\n\n### Patch Changes\n\n- e6c3050: add `display: 'normal' | 'hidden'` for `_meta` item `type: 'menu'`\n\n## 4.2.4\n\n### Patch Changes\n\n- b46d831: fix `Could not parse expression with acorn` for inline math code in\n  `development` mode without turbopack enabled\n- 7949e28: move setting `pageMap` items' `title` property from `normalizePages`\n  to `sortFolder`\n\n## 4.2.3\n\n### Patch Changes\n\n- ca67a19: remove requirement `page.{jsx,tsx}` pages to have exported `metadata`\n  object\n\n## 4.2.2\n\n### Patch Changes\n\n- dd32eca: fix route group within `app/` dir crash the `convertToPageMap`\n\n## 4.2.1\n\n## 4.2.0\n\n### Patch Changes\n\n- 427b080: calculate `--nextra-banner-height` after mounting banner, so banner\n  text can be wrapped on multiple lines\n- 6b8053f: fix a sudden height jump on opening for `<detail>` element when his\n  last children contain margins\n- b0e686e: hide default `<summary>` arrow on mobile\n\n## 4.1.1\n\n### Patch Changes\n\n- 29a44de: fix regression from Nextra 3 setting\n  [`theme.collapsed?: boolean` in `_meta` file](https://nextra.site/docs/file-conventions/meta-file#theme-option)\n  for folders has no effect in sidebar\n- 19578c3: improve github alert syntax name in DOM\n\n## 4.1.0\n\n### Minor Changes\n\n- 7caf059: - generate unique anchor id for `<summary>` elements based on its\n  content at build time\n  - add anchor link icon for `<summary>`\n\n## 4.0.9\n\n### Patch Changes\n\n- e78f796: fix console error from `<Search>` results error\n  `TypeError: Cannot destructure property 'results' of '(intermediate value)' as it is null.`\n\n  select right tab and scroll into view when html element with `location.hash`\n  id is inside `<Tabs.Tab>`\n\n- ff007b2: fix clicking on search result from same page doesn't scroll to the\n  heading\n\n## 4.0.8\n\n### Patch Changes\n\n- 267ef81: fix parsing empty front matter\n\n## 4.0.7\n\n### Patch Changes\n\n- 32e7d55: fix `::selection` styles, use `hsla` instead of `hsl` because it can\n  overlap text with `::selection` background when `background-clip: text` is set\n- 695e428: add new nextra config option `unstable_shouldAddLocaleToLinks` to\n  append locale to all links, for i18n websites which uses static exports and\n  can't use Nextra middleware\n- fc78033: fix crash of Nextra when `props` are used within headings, e.g.\n  `## Hello {props.something}`\n- b2f2458: do not log a bunch of\n  `Failed to get the last modified timestamp from Git for the file` messages if\n  init git repository failed\n\n## 4.0.6\n\n### Patch Changes\n\n- 44ea060: correctly handle non-English characters in filenames for `.md` and\n  `.mdx` pages\n\n## 4.0.5\n\n### Patch Changes\n\n- 14bf091: fix build crash after renaming mdx pages\n\n## 4.0.4\n\n### Patch Changes\n\n- 5132295: fix broken `showLineNumbers` setting on code blocks\n- 5132295: fix unable order \\_meta key with `index` name\n\n## 4.0.3\n\n## 4.0.2\n\n## 4.0.1\n\n### Patch Changes\n\n- 481e0d0: fix syntax highlighting for `mdx` lang and improve docs for\n  `/docs/docs-theme/start`\n- 426cd66: Remove margin-top from `.nextra-steps` `:before` pseudo selector\n\n## 4.0.0\n\n### Major Changes\n\n- 283320f: remove `\"typesVersions\"` field from `package.json`. You need to set\n  `\"moduleResolution\": \"bundler\"` in your `tsconfig.json` if you are using\n  TypeScript\n- 283320f: move `<Collapse>`, `<Details>`, `<Summary>`, `<SkipNavContent>`,\n  `SkipNavLink`, `<Select>` and `<Bleed>` from `nextra-theme-docs` to\n  `nextra/components`\n- 283320f: remove `<Th>`, `<Tr>` and `<Td>` exports (since they should be always\n  used with `<Table>` component)\n\n  ```diff\n  - import { Table, Th, Tr, Td } from 'nextra/components'\n  + import { Table } from 'nextra/components'\n\n  // ...\n\n  - <Th>\n  + <Table.Th>\n  - <Tr>\n  + <Table.Tr>\n  - <Td>\n  + <Table.Td>\n  ```\n\n- 283320f: make `compileMdx` from `nextra/compile` return a `string` instead of\n  an `object`\n- 283320f: remove `export const title` from generated mdx pages\n- 283320f: The initial version which supports App Router instead of Pages\n  Router, something may be broken, check\n  https://github.com/shuding/nextra/tree/v4-v2/examples for the migration guide\n- 283320f: fix focusing on first search result item\n- 283320f: rename `nextra/mdx` to `nextra/mdx-components`\n- 283320f: migrate search from Flexsearch to Pagefind\n- 283320f: remove `nextra/remote`, `nextra/schemas` and `nextra/remark-plugins`\n- 283320f: - add root `_meta.global.{js,jsx,ts,tsx}` file\n  > See\n  > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts)\n  > based on https://nextra.site website\n  - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2\n    `lang?: string, route?: string = '/'`\n  - remove `createCatchAllMeta` from `nextra/catch-all`\n  - remove `collectCatchAllRoutes`\n  - remove `normalizePageRoute`\n  - add `mergeMetaWithPageMap` to `nextra/page-map`\n  - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime`\n    in remark plugin\n  - refactor recma rewrite plugin and add tests\n    - remove `recmaRewriteJsx`\n    - remove `recmaRewriteFunctionBody`\n  - make `convertPageMapToJs` sync\n- 283320f: improve performance on projects without Turbopack enabled\n- 283320f: release Nextra rc.0\n- 283320f: - migrate to tailwind css v4.beta2\n  - refactor builtin CSS classes from `_` prefix to `x:` prefix\n  - remove `color-primary-750` theme color variant\n- 283320f: replace `export const useTOC = () = [/* your headings */]` by\n  `export const toc = [/* your headings */]`\n- 283320f: move `<Head>` component in `nextra/components`\n- 283320f: remove `renderComponent` and `renderString`\n- 283320f: require Next.js minimum v14\n- 283320f: - add `nextra/components` to `experimental.optimizePackageImports` to\n  optimize `nextra/components` by default\n  - remove `<RemoteContent>` from `nextra/components`\n  - rename `<RemoteContent>` to `MDXRemote` and move to `nextra/mdx-remote`\n\n### Minor Changes\n\n- 283320f: - use ReactIcon for code blocks with `jsx`, `tsx` language\n  - add JsonIcon for `json` language\n  - parse language from filename if exist when `diff` language is specified\n  - use JavaScript icon for `cjs` and `mjs`\n  - use TypeScript icon for `cts` and `mts`\n- 283320f: replace `useContentDir` with `contentDirBasePath` option which\n  configure `content` directory under a catch-all subdirectory\n- 283320f: move TOC logic from `recma-rewrite-jsx` plugin to\n  `rehype-extract-toc-content` plugin\n- 283320f: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and\n  also `content` folder files - all add to `pageMap`, but ignore dynamic pages\n  `[[`\n- e11dbe0: set `content` value for `<meta name=\"theme-color\">` based on\n  background value for light and dark themes\n- 283320f: compile `nextra/components`, `nextra/hooks`, `nextra-theme-docs` and\n  `nextra-theme-blog` source code with react-compiler\n\n### Patch Changes\n\n- 283320f: improve `generatePageMap` types\n- 283320f: search tweaks\n- fdd2c6a: fix steps background on dark mode fix headings anchor link color on\n  dark mode\n- 283320f: setup `@typescript-eslint/no-unnecessary-condition` rule and fix\n  warnings\n- aca79fa: Don't focus search input on `Ctrl + k` on non Mac devices. Don't\n  focus search input on `⌘ + Shift + k` or `Ctrl + Shift + k`.\n- 283320f: add helpful error message about not available search on development\n  mode\n- 283320f: add `getPageMap` helper function to `nextra/page-map`\n- 283320f: Fixes when Turbopack is enabled:\n  `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'`\n- 283320f: add `whiteListTagsStyling` nextra config option\n- 283320f: fix unable to select text and `::selection` style\n- 283320f: - allow override/add additional icons for code blocks\n  - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of\n    `mdx-components` file\n- 283320f: - Use Tailwind CSS CLI because CSS processing by `tsup` produce\n  different, weird and broken result\n  - Patch react-compiler with some fixes which isn't fixed\n- 283320f: use `Date.now()` for last edit time on development and git last\n  commit time on production\n- 283320f: move `pagefind` output to `public/_pagefind` directory\n  https://github.com/shuding/nextra/pull/3517\n- 283320f: initialize `transformerTwoslash` only 1 time outside of loader\n- 283320f: remove `NextraConfig.transformPageMap`\n- 283320f: - remove `nextra/context`\n  - remove `type NextraThemeLayoutProps`\n- 283320f: Export Meta type from schemas\n- 283320f: fix edit on github and last updated at for catch all routes\n- 283320f: simplify `generatePageMap`\n- 283320f: add icons for `javascript and `typescript langs\n- 283320f: - parse and transform `_meta` files with zod\n  - remove `_meta` `newWindow` field\n- 283320f: sync with nextra 3.1.0\n- 283320f: Cache the result of `repository.getFileLatestModifiedDateAsync`\n  because it can slow down Fast Refresh for uncommitted files.\n- 283320f: add `bottomContent` prop for `<Wrapper>` component, e.g. to put some\n  content after pagination in `nextra-theme-docs`\n- 283320f: select tab with active hash and scroll to right heading\n- 283320f: adjust RegEx for folder groups in app router\n- 283320f: - do not treat `content/page.{mdx,md}` as index page\n  - skip visiting directories which starts with underscore for `app` directory\n- 283320f: reduce bundle size of bundled website by compiling svg icons in\n  separated files\n- 283320f: enable page reload of catch-all routes `app/[[...slug]].jsx` on\n  content change\n- 283320f: move `createCatchAllMeta` from `nextra/catch-all` to\n  `nextra/page-map`\n- 283320f: remove false positive warnings on projects without `content/`\n  directory\n\n  ```\n  ⚠ Compiled with warnings\n\n  ../packages/nextra/dist/client/pages.js\n  Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client'\n  ```\n\n- 283320f: Fix `MetaRecord` type so it's no longer `unknown`\n- 283320f: fix error goes from `playground.js` file when your `mdx-components`\n  file contain server-only components\n\n  ```\n  ./app/layout.tsx\n  'client-only' cannot be imported from a Server Component module. It should only be used from a Client Component.\n\n  Import trace for requested module:\n  ../packages/components/dist/index.js\n  ./mdx-components.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/remote-content.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/playground.js\n  ```\n\n- 283320f: - sync with nextra 3.0.15\n  - bump to Next 15\n  - remove importing of `style.css` in themes, you need to import now manually\n    by\n\n  ```js\n  import 'nextra-theme-docs/style.css' // for docs theme\n  import 'nextra-theme-blog/style.css' // for blog theme\n  ```\n\n- 283320f: add `normalizePagesResult.activeMetadata` to get value of front\n  matter or exported metadata from page\n- 283320f: add support for turbopack `next dev --turbopack`\n- 283320f: fix `colorSchema` for HEX format with 4 chars, e.g. `#111`\n- 283320f: fix external svg icon was added for span in `<Anchor>`\n- 283320f: remove `NormalizedResult.flatDirectories`\n\n  remove `Item.withIndexPage`, use `'frontMatter' in Item`\n\n- 283320f: sync with nextra 3.0.10\n- 283320f: optimize compiled svg icons with react-compiler\n- 283320f: - simplify `generatePageMapFromFilepaths`\n  - sync with nextra 3.2.0\n- 283320f: defer pagefind results update for prioritizing the user input state\n- 283320f: make Nextra works with `src/app` and `src/content` directories\n- 283320f: - fix missing tailwind class for `json` icon in code blocks\n  - capitalize folders in sidebar even without index pages\n  - sync with nextra 3.2.4\n- 283320f: add ↗ char for external links\n- 283320f: remove check for filepaths outside cwd in `compileMdx`\n- 283320f: sync with nextra 3.0.3\n- 283320f: fix injecting mdx-components into headings and injecting into toc\n- 283320f: - add `disabled` prop for `<Folder>` component when `open` prop was\n  set (to disable click event and remove `cursor: pointer`)\n  - allow `<h5>` and `<h6>` tags be used with `<Steps>`\n  - fix Webpack module rebuild for pageMap when new files where added or removed\n    in `app` dir or `content` dir\n- 283320f: fix TypeError: Cannot read properties of undefined (reading 'id')\n  when importing partial MDX\n- 283320f: `firstChildRoute` should return \"index\" route as first\n- 283320f: Use `primaryColor` for `::selection` styles\n- 283320f: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean`\n- 283320f: support `GitHub Alert Syntax`\n- 283320f: fix search, didn't work with Next.js' `basePath` set\n- 283320f: make `<SkipNavContent>` as server component\n- 283320f: Allow `type: 'separator'` item as `items` for `type: 'menu'`\n\n## 4.0.0-rc.0\n\n### Major Changes\n\n- 28796b4: release Nextra rc.0\n\n## 4.0.0-app-router.43\n\n### Patch Changes\n\n- 50c2f76: add `bottomContent` prop for `<Wrapper>` component, e.g. to put some\n  content after pagination in `nextra-theme-docs`\n- 50c2f76: fix `colorSchema` for HEX format with 4 chars, e.g. `#111`\n\n## 4.0.0-app-router.42\n\n### Patch Changes\n\n- 242e0d0: search tweaks\n- 3fc12a0: - Use Tailwind CSS CLI because CSS processing by `tsup` produce\n  different, weird and broken result\n  - Patch react-compiler with some fixes which isn't fixed\n\n## 4.0.0-app-router.41\n\n## 4.0.0-app-router.40\n\n### Patch Changes\n\n- 88135ec: Fix `MetaRecord` type so it's no longer `unknown`\n\n## 4.0.0-app-router.39\n\n### Patch Changes\n\n- 711dbe7: add icons for `javascript and `typescript langs\n\n## 4.0.0-app-router.38\n\n### Patch Changes\n\n- 42eb445: remove check for filepaths outside cwd in `compileMdx`\n\n## 4.0.0-app-router.37\n\n### Patch Changes\n\n- ad80ee1: fix TypeError: Cannot read properties of undefined (reading 'id')\n  when importing partial MDX\n\n## 4.0.0-app-router.36\n\n### Patch Changes\n\n- 739e9eb: Export Meta type from schemas\n- d805f2a: adjust RegEx for folder groups in app router\n- 0ab4ff1: optimize compiled svg icons with react-compiler\n\n## 4.0.0-app-router.35\n\n### Patch Changes\n\n- 96fb083: select tab with active hash and scroll to right heading\n\n## 4.0.0-app-router.34\n\n## 4.0.0-app-router.33\n\n### Patch Changes\n\n- dd2e216: Allow `type: 'separator'` item as `items` for `type: 'menu'`\n\n## 4.0.0-app-router.32\n\n### Patch Changes\n\n- fbeef15: setup `@typescript-eslint/no-unnecessary-condition` rule and fix\n  warnings\n\n## 4.0.0-app-router.31\n\n### Minor Changes\n\n- 386b620: compile `nextra/components`, `nextra/hooks`, `nextra-theme-docs` and\n  `nextra-theme-blog` source code with react-compiler\n\n## 4.0.0-app-router.30\n\n### Patch Changes\n\n- f277a7a: fix search, didn't work with Next.js' `basePath` set\n\n## 4.0.0-app-router.29\n\n### Major Changes\n\n- 4bdf82d: - migrate to tailwind css v4.beta2\n  - refactor builtin CSS classes from `_` prefix to `x:` prefix\n  - remove `color-primary-750` theme color variant\n\n## 4.0.0-app-router.28\n\n### Patch Changes\n\n- 846552e: - fix missing tailwind class for `json` icon in code blocks\n  - capitalize folders in sidebar even without index pages\n  - sync with nextra 3.2.4\n\n## 4.0.0-app-router.27\n\n### Major Changes\n\n- 8a0ae0f: - add root `_meta.global.{js,jsx,ts,tsx}` file\n  > See\n  > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts)\n  > based on https://nextra.site website\n  - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2\n    `lang?: string, route?: string = '/'`\n  - remove `createCatchAllMeta` from `nextra/catch-all`\n  - remove `collectCatchAllRoutes`\n  - remove `normalizePageRoute`\n  - add `mergeMetaWithPageMap` to `nextra/page-map`\n  - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime`\n    in remark plugin\n  - refactor recma rewrite plugin and add tests\n    - remove `recmaRewriteJsx`\n    - remove `recmaRewriteFunctionBody`\n  - make `convertPageMapToJs` sync\n\n### Patch Changes\n\n- 5e06f57: fix injecting mdx-components into headings and injecting into toc\n\n## 4.0.0-app-router.26\n\n### Minor Changes\n\n- 0076bad: move TOC logic from `recma-rewrite-jsx` plugin to\n  `rehype-extract-toc-content` plugin\n\n### Patch Changes\n\n- be82724: Fixes when Turbopack is enabled:\n  `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'`\n\n## 4.0.0-app-router.25\n\n### Major Changes\n\n- c095f98: make `compileMdx` from `nextra/compile` return a `string` instead of\n  an `object`\n- 79bbab7: remove `export const title` from generated mdx pages\n- 33ee518: replace `export const useTOC = () = [/* your headings */]` by\n  `export const toc = [/* your headings */]`\n\n### Patch Changes\n\n- 3edc6d7: use `Date.now()` for last edit time on development and git last\n  commit time on production\n- fdbae45: initialize `transformerTwoslash` only 1 time outside of loader\n\n## 4.0.0-app-router.24\n\n### Patch Changes\n\n- e46dbdf: Cache the result of `repository.getFileLatestModifiedDateAsync`\n  because it can slow down Fast Refresh for uncommitted files.\n\n## 4.0.0-app-router.23\n\n### Patch Changes\n\n- b2e44d3: make Nextra works with `src/app` and `src/content` directories\n\n## 4.0.0-app-router.22\n\n### Patch Changes\n\n- 5f79b77: fix unable to select text and `::selection` style\n- 57fde3f: reduce bundle size of bundled website by compiling svg icons in\n  separated files\n\n## 4.0.0-app-router.21\n\n### Major Changes\n\n- 730899e: - add `nextra/components` to `experimental.optimizePackageImports` to\n  optimize `nextra/components` by default\n  - remove `<RemoteContent>` from `nextra/components`\n  - rename `<RemoteContent>` to `MDXRemote` and move to `nextra/mdx-remote`\n\n### Patch Changes\n\n- 4e02ef3: fix error goes from `playground.js` file when your `mdx-components`\n  file contain server-only components\n\n  ```\n  ./app/layout.tsx\n  'client-only' cannot be imported from a Server Component module. It should only be used from a Client Component.\n\n  Import trace for requested module:\n  ../packages/components/dist/index.js\n  ./mdx-components.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/remote-content.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/playground.js\n  ```\n\n- 0d74f68: fix external svg icon was added for span in `<Anchor>`\n\n## 4.0.0-app-router.20\n\n### Major Changes\n\n- 16816f2: remove `<Th>`, `<Tr>` and `<Td>` exports (since they should be always\n  used with `<Table>` component)\n\n  ```diff\n  - import { Table, Th, Tr, Td } from 'nextra/components'\n  + import { Table } from 'nextra/components'\n\n  // ...\n\n  - <Th>\n  + <Table.Th>\n  - <Tr>\n  + <Table.Tr>\n  - <Td>\n  + <Table.Td>\n  ```\n\n- aa94d91: rename `nextra/mdx` to `nextra/mdx-components`\n- 0a63ba3: improve performance on projects without Turbopack enabled\n\n### Patch Changes\n\n- 3d8705c: improve `generatePageMap` types\n- 27454c4: remove `NextraConfig.transformPageMap`\n- 7cc8ca1: simplify `generatePageMap`\n- 71a051b: - do not treat `content/page.{mdx,md}` as index page\n  - skip visiting directories which starts with underscore for `app` directory\n- 0a63ba3: move `createCatchAllMeta` from `nextra/catch-all` to\n  `nextra/page-map`\n- 16816f2: remove false positive warnings on projects without `content/`\n  directory\n\n  ```\n  ⚠ Compiled with warnings\n\n  ../packages/nextra/dist/client/pages.js\n  Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client'\n  ```\n\n- b873702: `firstChildRoute` should return \"index\" route as first\n\n## 4.0.0-app-router.19\n\n### Patch Changes\n\n- a3627e5: - simplify `generatePageMapFromFilepaths`\n  - sync with nextra 3.2.0\n\n## 4.0.0-app-router.18\n\n### Minor Changes\n\n- 439466a: replace `useContentDir` with `contentDirBasePath` option which\n  configure `content` directory under a catch-all subdirectory\n- b00a560: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and\n  also `content` folder files - all add to `pageMap`, but ignore dynamic pages\n  `[[`\n\n### Patch Changes\n\n- a074a99: add `whiteListTagsStyling` nextra config option\n\n## 4.0.0-app-router.17\n\n### Patch Changes\n\n- 33568c1: add `normalizePagesResult.activeMetadata` to get value of front\n  matter or exported metadata from page\n\n## 4.0.0-app-router.16\n\n### Minor Changes\n\n- ab21db7: - use ReactIcon for code blocks with `jsx`, `tsx` language\n  - add JsonIcon for `json` language\n  - parse language from filename if exist when `diff` language is specified\n  - use JavaScript icon for `cjs` and `mjs`\n  - use TypeScript icon for `cts` and `mts`\n\n### Patch Changes\n\n- 0540e6c: - add `disabled` prop for `<Folder>` component when `open` prop was\n  set (to disable click event and remove `cursor: pointer`)\n  - allow `<h5>` and `<h6>` tags be used with `<Steps>`\n  - fix Webpack module rebuild for pageMap when new files where added or removed\n    in `app` dir or `content` dir\n- 5b47509: make `<SkipNavContent>` as server component\n\n## 4.0.0-app-router.15\n\n## 4.0.0-app-router.14\n\n### Major Changes\n\n- be19dd4: remove `\"typesVersions\"` field from `package.json`. You need to set\n  `\"moduleResolution\": \"bundler\"` in your `tsconfig.json` if you are using\n  TypeScript\n\n## 4.0.0-app-router.13\n\n### Major Changes\n\n- 54657e2: require Next.js minimum v15\n\n### Patch Changes\n\n- 3ade013: - remove `nextra/context`\n  - remove `type NextraThemeLayoutProps`\n- ddc39cc: - parse and transform `_meta` files with zod\n  - remove `_meta` `newWindow` field\n- 07213e2: add support for turbopack `next dev --turbopack`\n\n## 4.0.0-app-router.12\n\n### Patch Changes\n\n- b8defc9: sync with nextra 3.1.0\n- b8defc9: remove `NormalizedResult.flatDirectories`\n\n  remove `Item.withIndexPage`, use `'frontMatter' in Item`\n\n## 4.0.0-app-router.11\n\n### Patch Changes\n\n- be15165: move `pagefind` output to `public/_pagefind` directory\n  https://github.com/shuding/nextra/pull/3517\n\n## 4.0.0-app-router.10\n\n### Patch Changes\n\n- 8b1a7c9: defer pagefind results update for prioritizing the user input state\n\n## 4.0.0-app-router.9\n\n### Patch Changes\n\n- 2c8a8ab: - sync with nextra 3.0.15\n  - bump to Next 15\n  - remove importing of `style.css` in themes, you need to import now manually\n    by\n\n  ```js\n  import 'nextra-theme-docs/style.css' // for docs theme\n  import 'nextra-theme-blog/style.css' // for blog theme\n  ```\n\n## 4.0.0-app-router.8\n\n### Patch Changes\n\n- 9832af9: add ↗ char for external links\n- ec39959: Use `primaryColor` for `::selection` styles\n- 875842b: support `GitHub Alert Syntax`\n\n## 4.0.0-app-router.7\n\n### Patch Changes\n\n- 5201e5f: add helpful error message about not available search on development\n  mode\n- 3ac2c32: add `getPageMap` helper function from `nextra/page-map`\n- b4ca36d: - allow override/add additional icons for code blocks\n  - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of\n    `mdx-components` file\n- 4768dee: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean`\n\n## 4.0.0-app-router.6\n\n### Patch Changes\n\n- 2092d5e: enable page reload of catch-all routes `app/[[...slug]].jsx` on\n  content change\n- a97e5cf: sync with nextra 3.0.10\n\n## 4.0.0-app-router.5\n\n### Patch Changes\n\n- 659b36e: remove `jsx-runtime.cjs`, import runtime from 'react/jsx-runtime'\n- a15a02d: sync with nextra 3.0.3\n\n## 4.0.0-app-router.4\n\n## 4.0.0-app-router.3\n\n### Major Changes\n\n- 1e77fab: move `<Collapse>`, `<Details>`, `<Summary>`, `<SkipNavContent>`,\n  `SkipNavLink`, `<Select>` and `<Bleed>` from `nextra-theme-docs` to\n  `nextra/components`\n- 1e77fab: remove `nextra/remote`, `nextra/schemas` and `nextra/remark-plugins`\n- 1e77fab: remove `renderComponent` and `renderString`\n\n### Patch Changes\n\n- 1e77fab: fix edit on github and last updated at for catch all routes\n\n## 4.0.0-app-router.2\n\n### Major Changes\n\n- 215aa08: fix focusing on first search result item\n- 8ef0f58: move `<Head>` component in `nextra/components`\n\n## 4.0.0-app-router.1\n\n### Major Changes\n\n- 26851b5: migrate search from Flexsearch to Pagefind\n\n## 4.0.0-app-router.0\n\n### Major Changes\n\n- 99f34d3: The initial version which supports App Router instead of Pages\n  Router, something may be broken, check\n  https://github.com/shuding/nextra/tree/v4-v2/examples for the migration guide\n\n## 3.3.1\n\n### Patch Changes\n\n- bfa61d9: add `text-overflow: ellipsis` for `<Cards.Card>` component\n\n## 3.3.0\n\n### Minor Changes\n\n- ee69234: add\n  [image zoom feature](http://nextra.site/docs/guide/image#image-zoom) for all\n  images written via [GFM syntax](https://github.github.com/gfm/#images) in\n  md/mdx files (except images inside links)\n\n## 3.2.5\n\n### Patch Changes\n\n- 2f5d954: fix unable override injected `img` component\n\n## 3.2.4\n\n### Patch Changes\n\n- a4b0bbb: fix(deps): update dependency title to v4\n\n  > This fix ReDoS vulnerability exposed via title → clipboardy → execa →\n  > cross-spawn dependency chain\n\n## 3.2.3\n\n### Patch Changes\n\n- 50f33f3: Add tabClassName to Tabs props\n\n## 3.2.2\n\n### Patch Changes\n\n- 45cccd4: allow passing `className` for `<Tabs>` and `<Tabs.Tab>`\n\n## 3.2.1\n\n## 3.2.0\n\n## 3.1.3\n\n### Patch Changes\n\n- 6e64b16: fix\n  `Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \"exports\" main defined in /path/to/project/node_modules/nextra/package.json`\n  when using `next.config.ts`\n- d44c4bc: requires to have a custom App component (`pages/_app.jsx`)\n- 24f9806: fix folder's index page was not merged with folder itself for some\n  edge case\n\n## 3.1.2\n\n### Patch Changes\n\n- 9c78588: fix(loader): Prevent overwriting of\n  `rehypePrettyCodeOptions.transformer`\n\n## 3.1.1\n\n### Patch Changes\n\n- 68633e5: fix: Improve Twoslash Popover Display\n\n## 3.1.0\n\n### Minor Changes\n\n- 8e9767e: `activeType` should be initialized from `meta['*']`\n- fec399a: fix `type: 'separator'`, `type: 'menu'` and `item` with `href` not\n  respecting order when not all pages specified in `_meta` file\n\n### Patch Changes\n\n- 035fe48: - fix empty dropdown menu when \\_meta item with `type: \"menu\"`\n  contains items with local pages\n- c002118: - add tests for should respect order for `type: \"separator\"`,\n  `type: \"menu\"` and item with `href`\n\n## 3.1.0-canary.1\n\n### Minor Changes\n\n- 8e9767e: `activeType` should be initialized from `meta['*']`\n\n### Patch Changes\n\n- 035fe48: - fix empty dropdown menu when \\_meta item with `type: \"menu\"`\n  contains items with local pages\n- c002118: - add tests for should respect order for `type: \"separator\"`,\n  `type: \"menu\"` and item with `href`\n\n## 3.1.0-canary.0\n\n### Minor Changes\n\n- fec399a: fix `type: 'separator'`, `type: 'menu'` and `item` with `href` not\n  respecting order when not all pages specified in `_meta` file\n\n## 3.0.15\n\n### Patch Changes\n\n- bd498c6: fix compatibility with Next.js `15.0.0-rc.1`\n\n## 3.0.14\n\n### Patch Changes\n\n- 6454938: update css selectors for `<code>`, use `code.nextra-code`\n- 9794e9e: update package version range for `@theguild/remark-mermaid` to be at\n  least `^0.1.3`\n  https://github.com/nextauthjs/next-auth/pull/12029#discussion_r1801785960\n- 9794e9e: Fix `frontMatter.sidebarTitle` didn't affect without\n  `frontMatter.title` set\n\n  now priority for sidebar title is:\n  1. `title` property from `_meta` file\n  1. `frontMatter.sidebarTitle`\n  1. `frontMatter.title`\n  1. formatted with [Title](https://title.sh) based on filename\n\n## 3.0.13\n\n## 3.0.12\n\n### Patch Changes\n\n- 7e0093f: Fix `nextra/locales` middleware, redirect to the docs URL relative to\n  the `/<basePath>`.\n\n## 3.0.11\n\n### Patch Changes\n\n- e0a9303: add `nextra/locales` middleware which can be exported from\n  `root-of-your-project/middleware.{js,ts}` file to detect and redirect to the\n  user-selected language for i18n websites\n\n## 3.0.10\n\n### Patch Changes\n\n- 31de764: another attempt to fix:\n\n  ```\n  Failed to compile.\n\n  ./node_modules/typescript/lib/typescript.js\n  Module not found: Can't resolve 'module'\n  ```\n\n- 161d350: fix `Could not find a declaration file for module 'nextra'`\n\n## 3.0.9\n\n### Patch Changes\n\n- f9cc160: - fix `Module not found: Can't resolve 'module'` in yarn@4.5.0\n  - disable `twoslash` in browser because he never worked in this environment\n\n## 3.0.8\n\n## 3.0.7\n\n### Patch Changes\n\n- 4bbc1fe: apply user's `recmaPlugins` first\n\n## 3.0.6\n\n## 3.0.5\n\n## 3.0.4\n\n### Patch Changes\n\n- 84a8a41: use 3 nextra's webpack loaders instead of 4\n- 659b36e: remove `jsx-runtime.cjs`, import runtime from 'react/jsx-runtime'\n- 84fc255: should get right `activeType`, `activeThemeContext` even when some\n  parent has `display: 'hidden'`\n\n## 3.0.3\n\n### Patch Changes\n\n- 82fc267: remove\n  `Critical dependency: the request of a dependency is an expression` warnings\n- edc6c29: remove `truthy()` helper function\n- 9d93caf: RTL support for the `<Steps>` component.\n- 5fbce2f: Added golang logo for code blocks.\n\n## 3.0.2\n\n### Patch Changes\n\n- b6341f7: remove warning\n  `Watchpack Error (initial scan): Error: ENOTDIR: not a directory, scandir 'path-to-your-node_modules/next/dist/pages/_app.js'`\n\n## 3.0.1\n\n## 3.0.0\n\n### Major Changes\n\n- e7e8e84: show react components, variable interpolation and latex in toc\n- 7188278: - insert `frontMatter` as export node via custom remark plugin\n  - remove `frontMatter.mdxOptions` support\n\n- 023d37b: add `\"type\": \"module\"` to `nextra` package\n- 50a52fd: - ❌ remove `_app.mdx`, use `_app.{js,jsx}` or `_app.{ts,tsx}` for\n  TypeScript projects instead\n  - ❌ remove Nextra middleware `nextra/locales`\n  - ❌ remove `parseFileName` from `nextra/utils`\n  - ❌ remove `nextra/filter-route-locale`\n  - ❌ remove `resolvePageMap` and `pageMapCache` from `nextra/page-map`\n  - ❌ remove `__nextraPageOptions.pageNextRoute`\n  - ❌ remove `pageOpts.route` and `pageOpts.newNextLinkBehavior`\n  - ❌ remove `LoaderOptions.defaultLocale`\n  - ❌ remove `__nextra_internal__.context[route].themeConfig`\n  - ✅ add `nextra/fetch-filepaths-from-github`\n  - save `pageMap` to `.next/static/chunks/nextra-page-map-{locale}.mjs`\n  - save `fileMap` to `.next/static/chunks/nextra-file-map.mjs`\n\n- c2ad837: update to MDX3\n- 148278c: rename tailwind prefix `nx-` to `_` to reduce bundle size\n- 919fe97: set `\"peerDependencies.next\": \">=13\"`\n- 47b125d: fix global style conflicts for\n  `<a>`/`<button>`/`<summary>`/`<input>`/`[tabindex]:not([tabindex='-1']`\n- ba30c6c: use render props for className with `selected`, `disabled` and\n  `hover` state for `<Tab>`\n- d7d8a3e: new styles for code blocks aka in next.js\n- 2872606: remove `image` prop from `<Card>` component, image will be showed\n  based on truthiness `children` prop now\n\n  set `icon` as optional prop\n\n- 63ca28b: Remove support of \"\\_meta.json\", use \"\\_meta.{js,jsx,ts,tsx}\"\n  instead.\n- ad4823d: add zod validation for nextraConfig\n- ab07609: remove `locale` and `defaultLocale` from `normalizePages`\n- 2f3be33: - set `\"engines.node\": \">=18\"`\n  - remove `Tab` export, use `Tabs.Tab` instead\n  - remove `Card` export, use `Cards.Card` instead\n  - disallow import md/mdx files that are outside the working directory, use\n    symlinks instead\n\n- 66cce1d: **BREAKING** bundle to ESM only\n\n  > ⚠️⚠️⚠️ use `next.config.mjs` or `next.config.js` with `\"type\": \"module\"`\n\n- b9f88e3: - remove `use-internals.ts`\n  - remove `layout.tsx`, move directly to `setup-page.tsx`\n  - remove `kind: 'Meta' | 'Folder' | 'MdxPage'` to keep page map smaller\n\n- 128e195: fix React warning, remove PageOpts.toc, use `toc` prop from\n  `components.wrapper`\n- 576cb6f: - rename `nextraConfig.flexsearch` to `nextraConfig.search`\n- 1f3e7cd: - remove `__nextraPageOptions.hot`\n  - remove `__nextraPageOptions.pageOptsChecksum`\n  - remove `__nextra_internal__.refreshListeners` (no longer needed since we\n    insert toc as esm node in remark plugin)\n  - remove `hashFnv32a`\n\n- 198dbcc: use toc with JSX elements for remote content\n- 191e6c4: - use `shikiji` instead of `shiki`\n  - rename `useSSG` to `useData`\n\n- c7f03e5: rename `pageOpts.headings` to `toc`\n\n### Minor Changes\n\n- 0fe55db: add `import { useRouter } from 'nextra/hooks'` for fetching `locale`\n  and `defaultLocale`\n- 6ec3241: Add Terraform/Move icon https://github.com/shuding/nextra/pull/2811\n  https://github.com/shuding/nextra/pull/2808\n- c7f03e5: should not add virtual `_meta` file if missing\n- 3644e1c: add `remark-smartypants`\n- 5a63701: add icons for following languages:\n  - GraphQL (`graphql`)\n  - C++ (`c++`, `cpp`)\n  - C# (`csharp`, `c#`, `cs`)\n  - Python (`python`, `py`)\n\n  allow disallow mobile word wrap button in code blocks with `word-wrap=false`\n  meta data setting\n\n- 60ec68c: improvements for remarkStaticImage:\n  - import same image only once\n  - support importing images by markdown image definitions\n\n- a52a869: add `frontmatter.sidebarTitle` support for setting page label in\n  sidebar via frontmatter\n- 6ec3241: Make the `<Tab>` component be crawlable and indexable by search\n  engines by default\n- f71e660: change to shiki again\n- 6070b02: rename `frontmatter.sidebar_label` to `frontmatter.sidebarTitle`\n- 4e55c06: add support for `_meta.{js,jsx,ts,tsx}` with JSX support\n- 8bce16d: replace `transformPageOpts` nextra option by `transformPageMap`\n- 3043826: add shikiji twoslash\n\n  Demo feature:\n  https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support\n\n- 6070b02: move `removeLinks` function from `nextra-theme-docs` to\n  `nextra/remove-links`\n- 440ff42: add MathJax support\n\n### Patch Changes\n\n- d1e3e9a: handle case when meta object was added in `transformPageMap`\n- 73239c4: To ensure consistent horizontal padding, set the default language as\n  plaintext for code blocks. This prevents any loss of formatting for code\n  blocks without a specified language.\n- 2b9b95b: migrate to `@headlessui/react` v2\n- 2a3e3e7: Fix first list item in `<FileTree>` not within permitted parent\n  elements\n- a3b67ae: `_meta` should return\n  `export const getStaticProps = () => ({ notFound: true })` for static exports,\n  instead of page without contain\n- 1a36469: add `frontMatter.sidebarTitle` only if `frontMatter.title` is empty\n- 799174f: fixed creating `pageMap` items for folders with dots\n\n  remove requirement of passing `filePaths` with `.md`/`.mdx` extensions for\n  `createCatchAllMeta` function\n\n- 98f439c: export `evaluate` function for remote content\n- cb24790: fix broken `export default` statement in mdx files\n- 982862f: Support for `h2` and `h4` Markdown headings with the Steps component.\n- a8c2196: use dynamic import for loading `mermaid`\n- 0b5cc9d: make nextra compatible with windows\n- fe5061b: fix for remote docs\n- 1a634cd: remove explicit `ZodError` assertion\n- ad108ff: use `overflow-x-auto` instead `overflow-x-scroll` for `<Table>`\n- 4f0f6b2: Omit `...{:type}` inline code annotations from search index #2922\n- 1f3e7cd: fix `pageProps` for NextraLayout\n- 90c129e: children in Card component is required only if the image prop is true\n- 150184b: attach heading anchor `id` attribute to heading (like Pagefind do)\n  and fix heading anchor styles when `theme.typesetting: 'article'` is set\n- c74ae90: Fix TypeError: \\_jsx is not a function for remote content on\n  development environment\n- 7615b62: fix `useRouter` in `nextra/hooks`, use `asPath` instead `route`\n  because locale can be dynamic `/[locale]`\n- 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to\n  improve type inference.\n- 8efbb45: remove `nextra/data` export, move `useData` to `nextra/hooks`,\n  `RemoteContent` to `nextra/components`\n- 6f4c83a: fix unclickable links in TOC\n\n  allow passing `recmaPlugins` in `mdxOptions`\n\n- d8a406b: add `\"sideEffects\": false` for better tree-shaking\n- 9f55bd1: update rehype-pretty-code/shikiji to latest\n- ccaf3d4: Add the `autoImportThemeStyle` option to the Nextra configuration.\n  This allows users to import the official Nextra theme CSS into a specific\n  cascade layer.\n- 2630461: fix\n  `TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))`\n  on dev environment when `frontMatter.searchable: false`\n- 217f708: update next-themes\n\n  fix wrong numbering for nested `<Steps>`\n\n- 57bc0e2: fix reload of nextra layout on route change, reported by sound.xyz\n- ca51306: Enhance focus ring style consistency.\n- f662237: avoid focus-visible style being cut off by overflow-hidden\n- 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts`\n- 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `<Ident>` and svg\n  icons in `<Folder>` and `<File>`\n- fef635e: ignore loading pageMap for dynamic locale `/[locale]`\n- 237c345: Make React 18 as minimal requirement\n- 7faa096: fix visible hidden pages on mobile which set up with\n  `display: 'hidden'`\n- 9099c35: remove `nextra/mdx-plugins`, add `nextra/remark-plugins`\n- 98f439c: add rust icon\n- a95e745: Fix the line highlighting background-color does not extend to the\n  full width of the code block when a scrollbar appears with line numbers.\n- 80e11e0: move `resolvePageMap` to `nextra/page-map-dynamic`\n\n## 3.0.0-alpha.42\n\n### Patch Changes\n\n- ca51306: Enhance focus ring style consistency.\n\n## 3.0.0-alpha.41\n\n### Patch Changes\n\n- 237c345: Make React 18 as minimal requirement\n\n## 3.0.0-alpha.40\n\n### Patch Changes\n\n- 982862f: Support for `h2` and `h4` Markdown headings with the Steps component.\n\n## 3.0.0-alpha.39\n\n### Major Changes\n\n- 47b125d: fix global style conflicts for\n  `<a>`/`<button>`/`<summary>`/`<input>`/`[tabindex]:not([tabindex='-1']`\n- ba30c6c: use render props for className with `selected`, `disabled` and\n  `hover` state for `<Tab>`\n- 2872606: remove `image` prop from `<Card>` component, image will be showed\n  based on truthiness `children` prop now\n\n  set `icon` as optional prop\n\n## 3.0.0-alpha.38\n\n### Patch Changes\n\n- ccaf3d4: Add the `autoImportThemeStyle` option to the Nextra configuration.\n  This allows users to import the official Nextra theme CSS into a specific\n  cascade layer.\n\n## 3.0.0-alpha.37\n\n### Patch Changes\n\n- 2a3e3e7: Fix first list item in `<FileTree>` not within permitted parent\n  elements\n\n## 3.0.0-alpha.36\n\n### Patch Changes\n\n- 2b9b95b: migrate to `@headlessui/react` v2\n\n## 3.0.0-alpha.35\n\n### Patch Changes\n\n- f662237: avoid focus-visible style being cut off by overflow-hidden\n\n## 3.0.0-alpha.34\n\n### Patch Changes\n\n- 1a634cd: remove explicit `ZodError` assertion\n\n## 3.0.0-alpha.33\n\n### Patch Changes\n\n- 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to\n  improve type inference.\n\n## 3.0.0-alpha.32\n\n### Patch Changes\n\n- 73239c4: To ensure consistent horizontal padding, set the default language as\n  plaintext for code blocks. This prevents any loss of formatting for code\n  blocks without a specified language.\n- 799174f: fixed creating `pageMap` items for folders with dots\n\n  remove requirement of passing `filePaths` with `.md`/`.mdx` extensions for\n  `createCatchAllMeta` function\n\n- 150184b: attach heading anchor `id` attribute to heading (like Pagefind do)\n  and fix heading anchor styles when `theme.typesetting: 'article'` is set\n- 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts`\n\n## 3.0.0-alpha.31\n\n### Patch Changes\n\n- d1e3e9a: handle case when meta object was added in `transformPageMap`\n\n## 3.0.0-alpha.30\n\n### Patch Changes\n\n- 7615b62: fix `useRouter` in `nextra/hooks`, use `asPath` instead `route`\n  because locale can be dynamic `/[locale]`\n\n## 3.0.0-alpha.29\n\n### Patch Changes\n\n- fef635e: ignore loading pageMap for dynamic locale `/[locale]`\n\n## 3.0.0-alpha.28\n\n### Patch Changes\n\n- a8c2196: use dynamic import for loading `mermaid`\n- 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `<Ident />` and svg\n  icons in `<Folder />` and `<File />`\n\n## 3.0.0-alpha.27\n\n### Patch Changes\n\n- 4f0f6b27: Omit `...{:type}` inline code annotations from search index #2922\n- a95e7454: Fix the line highlighting background-color does not extend to the\n  full width of the code block when a scrollbar appears with line numbers.\n\n## 3.0.0-alpha.26\n\n## 3.0.0-alpha.25\n\n## 3.0.0-alpha.24\n\n### Patch Changes\n\n- 6f4c83a8: fix unclickable links in TOC\n\n  allow passing `recmaPlugins` in `mdxOptions`\n\n## 3.0.0-alpha.23\n\n### Minor Changes\n\n- 6ec3241c: Add Terraform/Move icon https://github.com/shuding/nextra/pull/2811\n  https://github.com/shuding/nextra/pull/2808\n- 6ec3241c: Make the `<Tab />` component be crawlable and indexable by search\n  engines by default\n\n### Patch Changes\n\n- ad108ff7: use `overflow-x-auto` instead `overflow-x-scroll` for `<Table />`\n- 217f7082: update next-themes\n\n  fix wrong numbering for nested `<Steps />`\n\n## 3.0.0-alpha.22\n\n### Patch Changes\n\n- 2630461c: fix\n  `TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))`\n  on dev environment when `frontMatter.searchable: false`\n\n## 3.0.0-alpha.21\n\n## 3.0.0-alpha.20\n\n## 3.0.0-alpha.19\n\n## 3.0.0-alpha.18\n\n### Minor Changes\n\n- f71e660e: change to shiki again\n\n### Patch Changes\n\n- 98f439ca: export `evaluate` function for remote content\n- 98f439ca: add rust icon\n\n## 3.0.0-alpha.17\n\n### Minor Changes\n\n- 30438264: add shikiji twoslash\n\n  Demo feature:\n  https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support\n\n### Patch Changes\n\n- 9f55bd1f: update rehype-pretty-code/shikiji to latest\n\n## 3.0.0-alpha.16\n\n### Minor Changes\n\n- 5a637010: add icons for following languages:\n  - GraphQL (`graphql`)\n  - C++ (`c++`, `cpp`)\n  - C# (`csharp`, `c#`, `cs`)\n  - Python (`python`, `py`)\n\n  allow disallow mobile word wrap button in code blocks with `word-wrap=false`\n  meta data setting\n\n### Patch Changes\n\n- 90c129e6: children in Card component is required only if the image prop is\n  true\n\n## 3.0.0-alpha.15\n\n### Patch Changes\n\n- 1a364694: add `frontMatter.sidebarTitle` only if `frontMatter.title` is empty\n\n## 3.0.0-alpha.14\n\n## 3.0.0-alpha.13\n\n### Minor Changes\n\n- 60ec68c4: improvements for remarkStaticImage:\n  - import same image only once\n  - support importing images by markdown image definitions\n\n- 6070b025: rename `frontmatter.sidebar_label` to `frontmatter.sidebarTitle`\n- 8bce16d3: replace `transformPageOpts` nextra option by `transformPageMap`\n- 6070b025: move `removeLinks` function from `nextra-theme-docs` to\n  `nextra/remove-links`\n\n### Patch Changes\n\n- c74ae90a: Fix TypeError: \\_jsx is not a function for remote content on\n  development environment\n\n## 3.0.0-alpha.12\n\n### Minor Changes\n\n- 3644e1c2: add `remark-smartypants`\n\n### Patch Changes\n\n- 57bc0e2a: fix reload of nextra layout on route change, reported by sound.xyz\n\n## 3.0.0-alpha.11\n\n### Major Changes\n\n- c2ad837d: update to MDX3\n\n## 3.0.0-alpha.10\n\n### Patch Changes\n\n- 9099c354: remove `nextra/mdx-plugins`, add `nextra/remark-plugins`\n\n## 3.0.0-alpha.9\n\n### Patch Changes\n\n- 8efbb45c: remove `nextra/data` export, move `useData` to `nextra/hooks`,\n  `RemoteContent` to `nextra/components`\n- 80e11e04: move `resolvePageMap` to `nextra/page-map-dynamic`\n\n## 3.0.0-alpha.8\n\n### Minor Changes\n\n- 440ff42d: add MathJax support\n\n## 3.0.0-alpha.7\n\n### Patch Changes\n\n- 0b5cc9d5: make nextra compatible with windows\n\n## 3.0.0-alpha.6\n\n### Patch Changes\n\n- 03da778a: fix `*` theme settings for dynamic routes when route is not exist in\n  page map\n\n## 3.0.0-alpha.5\n\n### Patch Changes\n\n- a3b67aea: `_meta` should return\n  `export const getStaticProps = () => ({ notFound: true })` for static exports,\n  instead of page without contain\n\n## 3.0.0-alpha.4\n\n### Patch Changes\n\n- 7faa0968: fix visible hidden pages on mobile which set up with\n  `display: 'hidden'`\n\n## 3.0.0-alpha.3\n\n### Patch Changes\n\n- fe5061b7: fix for remote docs\n\n## 3.0.0-alpha.2\n\n### Patch Changes\n\n- cb247901: fix broken `export default` statement in mdx files\n\n## 3.0.0-alpha.1\n\n### Major Changes\n\n- e7e8e849: show react components, variable interpolation and latex in toc\n- 71882780: - insert `frontMatter` as export node via custom remark plugin\n  - remove `frontMatter.mdxOptions` support\n\n- 023d37b1: add `\"type\": \"module\"` to `nextra` package\n- 148278ce: rename tailwind prefix `nx-` to `_` to reduce bundle size\n- d7d8a3eb: new styles for code blocks aka in next.js\n- 63ca28be: Remove support of \"\\_meta.json\", use \"\\_meta.{js,jsx,ts,tsx}\"\n  instead.\n- b9f88e34: - remove `use-internals.ts`\n  - remove `layout.tsx`, move directly to `setup-page.tsx`\n  - remove `kind: 'Meta' | 'Folder' | 'MdxPage'` to keep page map smaller\n\n- 128e195f: fix React warning, remove PageOpts.toc, use `toc` prop from\n  `components.wrapper`\n- 1f3e7cd4: - remove `__nextraPageOptions.hot`\n  - remove `__nextraPageOptions.pageOptsChecksum`\n  - remove `__nextra_internal__.refreshListeners` (no longer needed since we\n    insert toc as esm node in remark plugin)\n  - remove `hashFnv32a`\n\n- 198dbcca: use toc with JSX elements for remote content\n- 191e6c41: - use `shikiji` instead of `shiki`\n  - rename `useSSG` to `useData`\n\n- c7f03e54: rename `pageOpts.headings` to `toc`\n\n### Minor Changes\n\n- c7f03e54: should not add virtual `_meta` file if missing\n- a52a869e: add `frontmatter.sidebar_label` support for setting page label in\n  sidebar via frontmatter\n- 4e55c064: add support for `_meta.{js,jsx,ts,tsx}` with JSX support\n\n### Patch Changes\n\n- 1f3e7cd4: fix `pageProps` for NextraLayout\n\n## 3.0.0-alpha.0\n\n### Major Changes\n\n- 50a52fd1: - ❌ remove `_app.mdx`, use `_app.{js,jsx}` or `_app.{ts,tsx}` for\n  TypeScript projects instead\n  - ❌ remove Nextra middleware `nextra/locales`\n  - ❌ remove `parseFileName` from `nextra/utils`\n  - ❌ remove `nextra/filter-route-locale`\n  - ❌ remove `resolvePageMap` and `pageMapCache` from `nextra/page-map`\n  - ❌ remove `__nextraPageOptions.pageNextRoute`\n  - ❌ remove `pageOpts.route` and `pageOpts.newNextLinkBehavior`\n  - ❌ remove `LoaderOptions.defaultLocale`\n  - ❌ remove `__nextra_internal__.context[route].themeConfig`\n  - ✅ add `nextra/fetch-filepaths-from-github`\n  - save `pageMap` to `.next/static/chunks/nextra-page-map-{locale}.mjs`\n  - save `fileMap` to `.next/static/chunks/nextra-file-map.mjs`\n\n- 919fe977: set `\"peerDependencies.next\": \">=13\"`\n- ad4823d9: add zod validation for nextraConfig\n- ab07609c: remove `locale` and `defaultLocale` from `normalizePages`\n- 2f3be336: - set `\"engines.node\": \">=18\"`\n  - remove `Tab` export, use `Tabs.Tab` instead\n  - remove `Card` export, use `Cards.Card` instead\n  - disallow import md/mdx files that are outside the working directory, use\n    symlinks instead\n\n- 66cce1d1: **BREAKING** bundle to ESM only\n\n  > ⚠️⚠️⚠️ use `next.config.mjs` or `next.config.js` with `\"type\": \"module\"`\n\n- 576cb6f1: - rename `nextraConfig.flexsearch` to `nextraConfig.search`\n\n### Minor Changes\n\n- 0fe55db2: add `import { useRouter } from 'nextra/hooks'` for fetching `locale`\n  and `defaultLocale`\n\n### Patch Changes\n\n- d8a406b4: add `\"sideEffects\": false` for better tree-shaking\n\n## 2.13.4\n\n## 2.13.3\n\n### Patch Changes\n\n- 93b57052: fix `type: 'separator'` zod validation, mark `title` field as\n  optional\n\n## 2.13.2\n\n### Patch Changes\n\n- ad7b31b0: downgrade remark-math from `6` to `5.1.1` to fix\n  `TypeError: Cannot read properties of undefined (reading 'mathFlowInside')`\n  error\n\n  fix support of ```math lang that was overridden by `rehype-pretty-code`\n\n## 2.13.1\n\n### Patch Changes\n\n- ee02a483: fix `Property 'existsSync' does not exist on type`\n\n## 2.13.0\n\n## 2.12.3\n\n### Patch Changes\n\n- ffb6d808: - Fix\n  `TypeError: Cannot read properties of null (reading 'classList')` while\n  navigating to route that doesn't have toc with `router.push` for example\n  - Add alias `Tabs.Tab` to `Tab` component\n  - Add alias `Cards.Card` to `Card` component\n  - should not attach custom heading id as id attribute if parent is `Tabs.Tab`\n    or `Tab`\n  - should not save to toc list headings of level 1\n\n## 2.12.2\n\n### Patch Changes\n\n- 7c8c4989: fix `Out of Memory` in search while indexing large words\n\n## 2.12.1\n\n### Patch Changes\n\n- 52ae8fc5: - always cache md/mdx compiler for non-remote content and never\n  cache for remote content\n  - refactor function arguments for `compileMdx`\n  - fix source code from loader was stripped starting from last match\n    `export default MDXContent;` and until the end, so `transform` function was\n    not applied\n  - fix `headings` were `undefined` in remote content\n\n## 2.12.0\n\n### Minor Changes\n\n- d9820746: - show headings for partial md/mdx in toc\n  - hide headings in toc when parent `<Tab />` or `<Tabs.Tab />`\n\n- 8962597e: - allow override static image component that was hardcoded to\n  `import Image from 'next/image'` now it's plain `<img />`\n  - support `<details />`/`<summary />` for `.md` files\n\n### Patch Changes\n\n- fbf003cd: cache md/mdx processor\n\n## 2.11.1\n\n### Patch Changes\n\n- ddddce95: skip search indexing for 404/500 pages\n- 6154e312: ensure first h1 is set as page title if frontmatter.title is missing\n- 46743ba4: fix TS error\n  `Cannot find module 'nextra/filter-route-locale' or its corresponding type declarations.`\n  while importing\n\n  ```js\n  import filterRouteLocale from 'nextra/filter-route-locale'\n  ```\n\n- 4dd720ad: remove `font-weight: 500;` from styles of code blocks since it gives\n  no effect\n\n## 2.11.0\n\n### Patch Changes\n\n- 3bb480a4: use github-slugger for custom heading ids to prevent duplicated\n  headings\n- 3bb480a4: fix custom heading id in search result\n- 3bb480a4: fix\n  `Warning: Prop href did not match. Server: \"/blog.en-US#\" Client: \"/blog#\"` in\n  by `normalizePages` from nextra/normalize-pages`\n- 3bb480a4: strip `.html` extension from URL route for static export\n\n## 2.10.0\n\n### Minor Changes\n\n- e54b008: - add `@theguild/remark-npm2yarn` package that replaces the code\n  block that has `npm2yarn` metadata with `<Tabs />` and `<Tab />` components\n  from `nextra/components`.\n  - `<Tabs />` now has `selectedKey` prop, the chosen tab is saved in the local\n    storage, which will be chosen in future page renders.\n\n  More info https://nextra.site/docs/guide/advanced/npm2yarn\n\n## 2.9.0\n\n### Minor Changes\n\n- 16bbb88: Move below packages to nextra package\n  - `<Cards />` and `<Card />`\n  - `<Tabs />` and `<Tab />`\n  - `<Steps />`\n  - `<FileTree />`\n\n  to import them you can use the following in your official `nextra-theme-blog`\n  and `nextra-theme-docs`\n\n  ```js\n  import { Card, Cards } from 'nextra/components'\n  ```\n\n  ```js\n  import { Tab, Tabs } from 'nextra/components'\n  ```\n\n  ```js\n  import { Steps } from 'nextra/components'\n  ```\n\n  ```js\n  import { FileTree } from 'nextra/components'\n  ```\n\n### Patch Changes\n\n- 23a25b1: replace last match of `export default MDXContent;`\n\n## 2.8.0\n\n### Patch Changes\n\n- 6c12bf4: fix broken code format while selecting and copying code with\n  `showLineNumbers` option enabled\n\n## 2.7.1\n\n### Patch Changes\n\n- 0e53ca51: remarkMermaid should be before removing imports for remote markdown\n\n## 2.7.0\n\n### Minor Changes\n\n- 44626e8f: support mermaid diagrams\n\n## 2.6.2\n\n### Patch Changes\n\n- 9c9625ee: Fix search not working in certain Next.js versions\n\n## 2.6.1\n\n### Patch Changes\n\n- 1e9ebabc: remove `remarkLinkRewriteOptions` from `buildDynamicMDX`\n\n## 2.6.0\n\n### Minor Changes\n\n- 1c6256b: Move Callout component to nextra package\n\n### Patch Changes\n\n- 15c4092: fix inconsistent `font-weight: bold` style for `type: 'menu'`\n\n## 2.5.2\n\n### Patch Changes\n\n- a3601e5: fix Module not found: Can't resolve\n  '.../node_modules/nextra/dist/mdx.mjs'\n\n## 2.5.1\n\n### Patch Changes\n\n- d408ab0: fix `Error: ENOENT: no such file or directory` in Nx-managed\n  monorepos\n\n## 2.5.0\n\n### Minor Changes\n\n- 08d393e: support ANSI highlighting\n\n## 2.4.2\n\n### Patch Changes\n\n- 16e562d: fix Next.js 13.3.1 compatibility for SyntaxError: Named export\n  'existsSync' not found.\n\n## 2.4.1\n\n### Patch Changes\n\n- a992ce1: do not add dynamic routes to pageMap\n\n## 2.4.0\n\n### Minor Changes\n\n- 0a50cad: support symlinked pages\n\n### Patch Changes\n\n- 545bd7c: Remove `.mdx?` of local links only\n- 259bfbc: do not throw error when `output: 'export'` is specified in\n  `next.config.js`\n\n## 2.3.0\n\n### Minor Changes\n\n- 6ea1caf: fix crash of dev server when `_meta.js` contains errors\n\n  disallow caching of `_meta.js` on dev env\n\n  set minimal `node` as `16`\n\n- 76e8b0f: support custom heading id via\n  `# my very long heading... [#my-custom-heading]` syntax\n  https://github.com/shuding/nextra/pull/1645\n\n### Patch Changes\n\n- 0dd028a: Prints the warning inline instead of the current behavior which\n  includes a stack trace.\n\n## 2.2.20\n\n### Patch Changes\n\n- 2e48307: export `normalizePages` from `nextra/normalize-pages`, `useFSRoute`\n  from `nextra/hooks` (can be useful for custom theme)\n- e4c8b6d: fix crash of dev server when \\_meta.json is malformed\n\n## 2.2.19\n\n### Patch Changes\n\n- e41cbbc: fix `transformPageOpts` with \\_app.mdx, `pageMap` was still included\n  even it was removed in `transformPageOpts`\n- a1e59b2: Support Markdown links with query or anchor.\n\n## 2.2.18\n\n### Patch Changes\n\n- 9bd2d59: remove the .md and .mdx extension from links\n- c2287e1: fix buildDynamicMDX options passed to compileMdx\n- 90cb6b8: do not auto create `_app.mdx` if missing\n\n## 2.2.17\n\n### Patch Changes\n\n- 4a66366: fix TypeError: Cannot read properties of undefined (reading '/') with\n  \\_app.mdx while editing theme.config, \\_meta.json or adding/removing md/mdx\n  files\n\n## 2.2.16\n\n### Patch Changes\n\n- d495e5f: introduce `_app.mdx` for better performance and smallest\n  `.next/static/chunks` size\n\n## 2.2.15\n\n### Patch Changes\n\n- d5aa17c: do not redirect `.txt` files in nextra's `locales` middleware\n- 016828e: do not redirect .mp4 in locales middleware\n- b3219c3: do not override `className` for `<Td />`, `<Th />` and `<Tr />`\n  components\n\n## 2.2.14\n\n### Patch Changes\n\n- bcaba9c: fix capitalizing sidebar links + tests\n- a683c84: fix `*` key for `collectCatchAll`\n- a404ef7: fix rewrites\n\n## 2.2.13\n\n### Patch Changes\n\n- d1d873f: typed frontmatter -> `useConfig<YOUR_FRONTMATTER_TYPE>`\n- 6626356: prefer `import type`\n- 2234a13: fix raw `__esModule` string ☠️\n\n## 2.2.12\n\n### Patch Changes\n\n- 619ae3a: fix pageMap for remote content\n\n## 2.2.11\n\n### Patch Changes\n\n- 7d96698: compile mdx with `format: 'detect'` in loader\n- e10bf74: add support for remote `[...catchAll]` routes\n\n  support meta keys with `/`\n\n  sanitize remote mdx by removing `import` statements\n\n- e04e2ce: better types for dynamic meta\n- 5fd2183: ignore `.xml` files in locales middleware\n- e38e61f: use decodeURI in static-image.ts\n\n## 2.2.10\n\n### Patch Changes\n\n- c97143f: fix search index output location\n- 256282a: fix codeHighlight being false by default for remote contet\n- 4d3c20a: fix special modules being bundled in client\n- 4b2052f: fix `Module not found: Can't resolve 'nextra-theme-docs/style.css'`\n  for imported markdown files that located outside of CWD\n- 624d6b4: fix when sidebar show non-md folders\n- 0c957db: fix capitalizing of undefined \\_meta.json file/folders\n- d0b9249: fix subpath import failed\n\n## 2.2.9\n\n### Patch Changes\n\n- c50474e: support dynamic markdown import\n\n## 2.2.8\n\n### Patch Changes\n\n- d2ed10f: remove development: false\n- b943146: add transformPageOpts option for advanced use cases\n\n## 2.2.7\n\n### Patch Changes\n\n- 36fd8c7: add format detection\n- 64cec8f: disable code splitting and fix dev errors\n\n## 2.2.6\n\n### Patch Changes\n\n- be24334: improve search index generation\n- 4fc13df: fix warning of dynamic imports\n\n## 2.2.5\n\n### Patch Changes\n\n- 163065c: loader refactor, type-safe `__nextra_resolvePageMap`, avoid code\n  interpolation in loader.ts\n\n## 2.2.4\n\n### Patch Changes\n\n- 091b77b: fix missing filename\n\n  add filename / copy code with \"codeHighlight: false\"\n\n  add unit tests for filename and copy code\n\n- 917de49: remove `github-slugger` from docs\n\n## 2.2.3\n\n### Patch Changes\n\n- 11b2870: fix copy code button position\n\n## 2.2.2\n\n### Patch Changes\n\n- 3145f53: extend `plugin:react/recommended`, `plugin:react-hooks/recommended`\n  and `plugin:@next/next/recommended` configs\n- 1834730: fix hydration error produced by cached compiler, fix broken\n  code-blocks styles while setting `nextraConfig.codeHighlight: false`\n- f53b935: Allow disabling code highlighting & memory improvements\n\n## 2.2.1\n\n### Patch Changes\n\n- 9bcfc1d: fix error was swallowed silently\n\n## 2.2.0\n\n### Minor Changes\n\n- e4b20ca: support `transform` in nextra config\n\n### Patch Changes\n\n- 52a1bf3: feat: allow to use plain md syntax\n- af76dbe: fix highlight substring from filename for code blocks\n\n## 2.1.0\n\n### Minor Changes\n\n- e5262d0: improve hmr and internal api for layout (toc and meta files)\n\n### Patch Changes\n\n- a923bd5: fix `collectFiles` concurrency\n- 5bdc62c: fix static images on windows\n- c86508c: lint fixes for `eslint:recommended` and\n  `plugin:@typescript-eslint/recommended` configs\n- d6c871a: simplify the custom theme layout api\n- 1ff43c1: use OKLCH colors where possible\n- a31678a: improve copy\n\n## 2.0.3\n\n### Patch Changes\n\n- adb2d25: fix remote mdx\n- 8060ed3: style improvements\n\n## 2.0.2\n\n### Patch Changes\n\n- 1e2afcf: Add LaTeX support\n- 99ec64e: fix indentation for copy code button\n- 3a08fe2: Add Callout border in dark mode\n- f488e2e: remove @react/skip-nev #1051\n\n  fix: staticImage should only set blur placeholder for jpeg,png,webp,avif\n\n- cf9b886: better performance of `collectFiles`\n- f35e724: update shiki to v0.12.1\n- b2fc168: support `nextConfig.distDir`\n- cc1cb5f: support `nextConfig.basePath` with i18n\n\n## 2.0.1\n\n### Patch Changes\n\n- a9748aa: fix: A11y improvements to the docs theme\n- ac82b1f: make code-blocks buttons focusable if they are visible on page\n\n## 2.0.0\n\n### Major Changes\n\n- 793eedb: chore: Fix CI\n\n### Patch Changes\n\n- e4cfb83: `addPage` no longer need accept `frontMatter`\n- 94ef0b3: improve 2.0 docs\n- 8101efe: fix(nextra): use `rehype-mdx-title` to determine page title\n- 6644bd5: pass unstable_flexsearch\n- cef5546: allow headings contain links\n- 2217f9c: fix `Warning: Prop `href` did not match. Server: \"#\" Client: ...`\n- e6771ca: fix edit on github button for cases when filename named as `index`\n- 2217f9c: fix `next export` command\n- fdb2f57: update docs to use next.js 13\n- 803553c: use `findPagesDir` from `next/dist/lib/find-pages-dir`\n- 568282e: fix broken build `SyntaxError: Unexpected token '}'`\n- a0398e0: fix: avoid mutating nextConfig\n- e6771ca: fix `ReferenceError` when trying to access `__nextra_pageOpts__`\n  inside MDX file\n- 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible\n  with next 13\n- 488f737: fix client console error - Text content does not match\n  server-rendered HTML\n- fc8cca0: add `<InformationCircleIcon />` icon, improve `<Callout />` default\n  emojis\n- fe2b714: upgrade to react 18\n- 02bc6fc: use `next/future/image` if next>=12.3.0\n- e4cfb83: define page title in sidebar from `frontMatter.title` if page is not\n  specified in `_meta.json`\n- 1ee3c92: reuse table styles from docs in blog\n- f569d90: missing `nx-` class prefixes in blog fix callout padding in docs\n- b1d7361: improve docs for 2.0\n- 8dab966: fix invisible copy button in code blocks\n- 6f987e9: fix: print shallow warning only once\n- 4825365: add `@types/github-slugger` instead of manually declaring type\n- f7856a1: change default options for `compileMdx`, set `jsx: false` and\n  `outputFormat: 'function-body'` by default\n- cc1379c: fix `Hydration failed because the initial UI...` while modifying\n  `meta.json` on dev env and react 18\n- 66712f0: polish docs\n- e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add\n  `NextraConfig.unstable_defaultShowCopyCode` option to show button by default,\n  add `copy` and `copy=false` options for code-blocks\n- 96ed5c2: [nextra/nextra-theme-docs]: support both\n  `experimental.newNextLinkBehavior` - `true` and `false`\n- b365bb0: fix TypeError: Cannot read properties of undefined (reading 'data')\n- 580c433: add nx- to all tailwind classes for style isolation\n- c3e6227: add `overflow-x-scroll` for tables\n- 1c3fedb: add missing `nx-` prefixes to table/th/tr elements\n- d7e7f5b: do not add `placeholder=\"blur\"` on `.svg` static images\n- 78f1519: chore: Add strict-peer-dependencies=false\n- 97e6141: fix(nextra/docs): fallback search to `en-US` instead `default`\n- a0e5847: Rename some docs theme configurations\n- 74a3398: update docs for 2.0\n- 93d028b: use `title` package in nextra to determine sidebar title based on\n  pagename\n- bd2cefa: Fix css classes with `eslint-plugin-tailwindcss`\n- ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile)\n- 009bf6a: Fix release workflow.\n- e6771ca: rename `meta.json` to `_meta.json`\n- ff8967c: fix missing `Copy Code` button in code-blocks without language\n- 4a7cc10: feat(nextra): allow define custom languages for shiki with\n  `mdxOptions.rehypePrettyCodeOptions` option\n- a2bc427: compile `context.ts`, `ssg.ts` and `locales.ts` to esm\n- 64ae4b5: add `nextraConfig.unstable_readingTime` option for blog theme\n- a9523c9: fix nextra on webcontainers\n- 383b869: Add Changesets and setup pre-release and release CI.\n- 6dc4dee: fix `Unhandled Runtime Error: No content found for <route>`\n- d7f2bbc: adjust docs theme; rename options\n- 256154a: use \"next/future/image\" if\n  `\"experimental.images.allowFutureImage\": true` is set in next config\n- a9414be: always use `next/image`, since in next 12.3.2 `next/future/image` was\n  renamed to `next/image`\n- 512953f: chore: remove redundant check for\n  `MARKDOWN_EXTENSION_REGEX.test(filename)` in loader\n- c8605d6: feat: New layout implementation\n- e6771ca: better loader types, add `MetaJsonFile`, `MdxFile`, `Folder` types\n- 4157b71: set lower build target and share code highlight theme through nextra\n- a1c1e4e: Update docs\n- 1942a2e: chore: Fix build script\n- 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well\n- 044721d: chore: Update turbo filters\n- 256154a: replace images with `<NextImage />` even when url not relative but\n  that starts from `/` (public directory)\n- c751458: fix(nextra): ignore in loader files from `pages/api` folder\n- e573175: Fix release CI\n- 21009c7: better focus ui, use ring color as theme hue color\n- 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader\n- 71528f1: show copy code button only on hover of container\n- 03e90d8: refresh build system with tsup and fix nextra type\n- e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter`\n- 37b4445: fix react-dom peer dependency version\n- 094fdec: sort `defaultMeta` by `frontMatter.date`, if missing by\n  `frontMatter.title` and after by capitalized page name\n- e6771ca: move `withLayout` logic directly in nextra loader\n- efd95ec: fix(nextra): allow to contain dots in page filenames\n- 094fdec: capitalize sidebar's folders names if item is missing in `_meta.json`\n- e35bbf7: chore: rename `module` to `mod` to avoid confusing with global\n  `module` object\n\n## 2.0.0-beta.45\n\n### Patch Changes\n\n- 66712f0: polish docs\n\n## 2.0.0-beta.44\n\n### Patch Changes\n\n- 94ef0b3: improve 2.0 docs\n- fdb2f57: update docs to use next.js 13\n- b1d7361: improve docs for 2.0\n- 74a3398: update docs for 2.0\n- d7f2bbc: adjust docs theme; rename options\n- a1c1e4e: Update docs\n\n## 2.0.0-beta.43\n\n### Patch Changes\n\n- 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible\n  with next 13\n\n## 2.0.0-beta.42\n\n## 2.0.0-beta.41\n\n### Patch Changes\n\n- bd2cefa: Fix css classes with `eslint-plugin-tailwindcss`\n\n## 2.0.0-beta.40\n\n### Patch Changes\n\n- f569d90: missing `nx-` class prefixes in blog fix callout padding in docs\n\n## 2.0.0-beta.39\n\n### Patch Changes\n\n- a9414be: always use `next/image`, since in next 12.3.2 `next/future/image` was\n  renamed to `next/image`\n\n## 2.0.0-beta.38\n\n## 2.0.0-beta.37\n\n## 2.0.0-beta.36\n\n### Patch Changes\n\n- 1c3fedb: add missing `nx-` prefixes to table/th/tr elements\n\n## 2.0.0-beta.35\n\n## 2.0.0-beta.34\n\n## 2.0.0-beta.33\n\n### Patch Changes\n\n- 580c433: add nx- to all tailwind classes for style isolation\n- 094fdec: sort `defaultMeta` by `frontMatter.date`, if missing by\n  `frontMatter.title` and after by capitalized page name\n- 094fdec: capitalize sidebar's folders names if item is missing in `_meta.json`\n\n## 2.0.0-beta.32\n\n### Patch Changes\n\n- fc8cca0: add `<InformationCircleIcon />` icon, improve `<Callout />` default\n  emojis\n\n## 2.0.0-beta.31\n\n### Patch Changes\n\n- cef5546: allow headings contain links\n\n## 2.0.0-beta.30\n\n### Patch Changes\n\n- 02bc6fc: use `next/future/image` if next>=12.3.0\n- f7856a1: change default options for `compileMdx`, set `jsx: false` and\n  `outputFormat: 'function-body'` by default\n\n## 2.0.0-beta.29\n\n## 2.0.0-beta.28\n\n## 2.0.0-beta.27\n\n### Patch Changes\n\n- d7e7f5b: do not add `placeholder=\"blur\"` on `.svg` static images\n- a9523c9: fix nextra on webcontainers\n- 21009c7: better focus ui, use ring color as theme hue color\n\n## 2.0.0-beta.26\n\n### Patch Changes\n\n- b365bb0: fix TypeError: Cannot read properties of undefined (reading 'data')\n- a0e5847: Rename some docs theme configurations\n\n## 2.0.0-beta.25\n\n### Patch Changes\n\n- e4cfb83: `addPage` no longer need accept `frontMatter`\n- e4cfb83: define page title in sidebar from `frontMatter.title` if page is not\n  specified in `_meta.json`\n- c3e6227: add `overflow-x-scroll` for tables\n- 93d028b: use `title` package in nextra to determine sidebar title based on\n  pagename\n- ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile)\n- ff8967c: fix missing `Copy Code` button in code-blocks without language\n- 256154a: use \"next/future/image\" if\n  `\"experimental.images.allowFutureImage\": true` is set in next config\n- 256154a: replace images with `<NextImage />` even when url not relative but\n  that starts from `/` (public directory)\n\n## 2.0.0-beta.24\n\n### Patch Changes\n\n- a2bc427: compile `context.ts`, `ssg.ts` and `locales.ts` to esm\n\n## 2.0.0-beta.23\n\n## 2.0.0-beta.22\n\n### Patch Changes\n\n- 8dab966: fix invisible copy button in code blocks\n\n## 2.0.0-beta.21\n\n### Patch Changes\n\n- 568282e: fix broken build `SyntaxError: Unexpected token '}'`\n\n## 2.0.0-beta.20\n\n### Patch Changes\n\n- e6771ca: fix edit on github button for cases when filename named as `index`\n- e6771ca: fix `ReferenceError` when trying to access `__nextra_pageOpts__`\n  inside MDX file\n- 1ee3c92: reuse table styles from docs in blog\n- e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add\n  `NextraConfig.unstable_defaultShowCopyCode` option to show button by default,\n  add `copy` and `copy=false` options for code-blocks\n- e6771ca: rename `meta.json` to `_meta.json`\n- 64ae4b5: add `nextraConfig.unstable_readingTime` option for blog theme\n- e6771ca: better loader types, add `MetaJsonFile`, `MdxFile`, `Folder` types\n- 71528f1: show copy code button only on hover of container\n- e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter`\n- e6771ca: move `withLayout` logic directly in nextra loader\n\n## 2.0.0-beta.19\n\n### Patch Changes\n\n- 37b4445: fix react-dom peer dependency version\n\n## 2.0.0-beta.18\n\n### Patch Changes\n\n- 803553c: use `findPagesDir` from `next/dist/lib/find-pages-dir`\n\n## 2.0.0-beta.17\n\n### Patch Changes\n\n- 2217f9c: fix `Warning: Prop`href`did not match. Server: \"#\" Client: ...`\n- 2217f9c: fix `next export` command\n- 6dc4dee: fix `Unhandled Runtime Error: No content found for <route>`\n\n## 2.0.0-beta.16\n\n### Patch Changes\n\n- 4825365: add `@types/github-slugger` instead of manually declaring type\n\n## 2.0.0-beta.15\n\n## 2.0.0-beta.14\n\n### Patch Changes\n\n- 96ed5c2: [nextra/nextra-theme-docs]: support both\n  `experimental.newNextLinkBehavior` - `true` and `false`\n- c8605d6: feat: New layout implementation\n\n## 2.0.0-beta.13\n\n### Patch Changes\n\n- 4157b71: set lower build target and share code highlight theme through nextra\n\n## 2.0.0-beta.12\n\n### Patch Changes\n\n- cc1379c: fix `Hydration failed because the initial UI...` while modifying\n  `meta.json` on dev env and react 18\n- 512953f: chore: remove redundant check for\n  `MARKDOWN_EXTENSION_REGEX.test(filename)` in loader\n- 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader\n\n## 2.0.0-beta.11\n\n### Patch Changes\n\n- a0398e0: fix: avoid mutating nextConfig\n- fe2b714: upgrade to react 18\n- 78f1519: chore: Add strict-peer-dependencies=false\n- 1942a2e: chore: Fix build script\n- 044721d: chore: Update turbo filters\n\n## 2.0.0-beta.10\n\n### Patch Changes\n\n- 8101efe: fix(nextra): use `rehype-mdx-title` to determine page title\n- 6f987e9: fix: print shallow warning only once\n- 97e6141: fix(nextra/docs): fallback search to `en-US` instead `default`\n- 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well\n- 03e90d8: refresh build system with tsup and fix nextra type\n\n## 2.0.0-beta.9\n\n### Major Changes\n\n- 793eedb: chore: Fix CI\n\n### Patch Changes\n\n- 6644bd5: pass unstable_flexsearch\n- 488f737: fix client console error - Text content does not match\n  server-rendered HTML\n- 4a7cc10: feat(nextra): allow define custom languages for shiki with\n  `mdxOptions.rehypePrettyCodeOptions` option\n- c751458: fix(nextra): ignore in loader files from `pages/api` folder\n- e573175: Fix release CI\n- efd95ec: fix(nextra): allow to contain dots in page filenames\n- e35bbf7: chore: rename `module` to `mod` to avoid confusing with global\n  `module` object\n\n## 2.0.0-beta.8\n\n### Patch Changes\n\n- 009bf6a: Fix release workflow.\n\n## 2.0.0-beta.7\n\n### Patch Changes\n\n- 383b869: Add Changesets and setup pre-release and release CI.\n"
  },
  {
    "path": "packages/nextra/default-entry.ts",
    "content": "export const defaultEntry = [\n  'src/**/*.{ts,tsx}',\n  '!**/*.d.ts',\n  '!**/__tests__',\n  '!**/*.{test,spec}.{ts,tsx}'\n]\n"
  },
  {
    "path": "packages/nextra/loader.cjs",
    "content": "/* eslint-env node */\n// https://github.com/mdx-js/mdx/blob/061cdbf440bd8193867fcef3f5a131c08e4fe469/packages/loader/index.cjs\n\n/**\n * Webpack loader\n *\n * @todo once webpack supports ESM loaders, remove this wrapper.\n *\n * @this {import('webpack').LoaderContext}\n * @param {string} code\n * @return {Promise<void>}\n */\nmodule.exports = async function loader(code) {\n  const callback = this.async()\n\n  try {\n    // Note that `import()` caches, so this should be fast enough.\n    const { loader } = await import('./dist/server/loader.js')\n    const result = await loader.call(this, code)\n    callback(null, result)\n  } catch (error) {\n    callback(error)\n  }\n}\n"
  },
  {
    "path": "packages/nextra/package.json",
    "content": "{\n  \"name\": \"nextra\",\n  \"version\": \"4.6.2\",\n  \"type\": \"module\",\n  \"description\": \"Next.js and MDX based site generator.\",\n  \"repository\": \"https://github.com/shuding/nextra\",\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=18\"\n  },\n  \"types\": \"./dist/server/index.d.ts\",\n  \"exports\": {\n    \"./package.json\": \"./package.json\",\n    \".\": {\n      \"types\": \"./dist/server/index.d.ts\",\n      \"import\": \"./dist/server/index.js\",\n      \"require\": \"./dist/server/index.js\"\n    },\n    \"./components\": {\n      \"types\": \"./dist/client/components/index.d.ts\",\n      \"import\": \"./dist/client/components/index.js\"\n    },\n    \"./hooks\": {\n      \"types\": \"./dist/client/hooks/index.d.ts\",\n      \"import\": \"./dist/client/hooks/index.js\"\n    },\n    \"./icons\": {\n      \"types\": \"./dist/client/icons/index.d.ts\",\n      \"import\": \"./dist/client/icons/index.js\"\n    },\n    \"./compile\": {\n      \"types\": \"./dist/server/compile.d.ts\",\n      \"import\": \"./dist/server/compile.js\"\n    },\n    \"./locales\": {\n      \"types\": \"./dist/server/locales.d.ts\",\n      \"import\": \"./dist/server/locales.js\"\n    },\n    \"./fetch-filepaths-from-github\": {\n      \"types\": \"./dist/server/fetch-filepaths-from-github.d.ts\",\n      \"import\": \"./dist/server/fetch-filepaths-from-github.js\"\n    },\n    \"./page-map\": {\n      \"types\": \"./dist/server/page-map/index.d.ts\",\n      \"import\": \"./dist/server/page-map/index.js\"\n    },\n    \"./schemas\": {\n      \"types\": \"./dist/server/schemas.d.ts\",\n      \"import\": \"./dist/server/schemas.js\"\n    },\n    \"./tsdoc\": {\n      \"types\": \"./dist/server/tsdoc/index.d.ts\",\n      \"import\": \"./dist/server/tsdoc/index.js\"\n    },\n    \"./merge-meta-with-page-map\": {\n      \"types\": \"./dist/server/page-map/merge-meta-with-page-map.d.ts\",\n      \"import\": \"./dist/server/page-map/merge-meta-with-page-map.js\"\n    },\n    \"./*\": {\n      \"types\": \"./dist/client/*.d.ts\",\n      \"import\": \"./dist/client/*.js\"\n    }\n  },\n  \"files\": [\n    \"dist\",\n    \"loader.cjs\",\n    \"styles\"\n  ],\n  \"scripts\": {\n    \"build\": \"NODE_ENV=production tsup\",\n    \"dev\": \"NODE_OPTIONS=--max_old_space_size=8192 tsup --watch\",\n    \"prepublishOnly\": \"pnpm build\",\n    \"test\": \"vitest --typecheck\",\n    \"types:check\": \"tsc --noEmit\"\n  },\n  \"peerDependencies\": {\n    \"next\": \">=14\",\n    \"react\": \">=18\",\n    \"react-dom\": \">=18\"\n  },\n  \"dependencies\": {\n    \"@formatjs/intl-localematcher\": \"^0.6.0\",\n    \"@headlessui/react\": \"^2.1.2\",\n    \"@mdx-js/mdx\": \"^3.0.0\",\n    \"@napi-rs/simple-git\": \"^0.1.9\",\n    \"@shikijs/twoslash\": \"^3.2.1\",\n    \"@theguild/remark-mermaid\": \"^0.3.0\",\n    \"@theguild/remark-npm2yarn\": \"^0.3.2\",\n    \"better-react-mathjax\": \"^2.3.0\",\n    \"clsx\": \"^2.1.0\",\n    \"estree-util-to-js\": \"^2.0.0\",\n    \"estree-util-value-to-estree\": \"^3.3.3\",\n    \"fast-glob\": \"^3.3.2\",\n    \"github-slugger\": \"^2.0.0\",\n    \"hast-util-to-estree\": \"^3.1.0\",\n    \"katex\": \"^0.16.21\",\n    \"mdast-util-from-markdown\": \"^2.0.1\",\n    \"mdast-util-gfm\": \"^3.0.0\",\n    \"mdast-util-to-hast\": \"^13.2.0\",\n    \"negotiator\": \"^1.0.0\",\n    \"react-compiler-runtime\": \"^19.1.0-rc.2\",\n    \"react-medium-image-zoom\": \"^5.2.12\",\n    \"rehype-katex\": \"^7.0.0\",\n    \"rehype-pretty-code\": \"0.14.1\",\n    \"rehype-raw\": \"^7.0.0\",\n    \"remark-frontmatter\": \"^5.0.0\",\n    \"remark-gfm\": \"^4.0.0\",\n    \"remark-math\": \"^6.0.0\",\n    \"remark-reading-time\": \"^2.0.2\",\n    \"remark-smartypants\": \"^3.0.0\",\n    \"server-only\": \"^0.0.1\",\n    \"shiki\": \"^3.2.1\",\n    \"slash\": \"^5.1.0\",\n    \"title\": \"^4.0.1\",\n    \"ts-morph\": \"^27.0.0\",\n    \"unist-util-remove\": \"^4.0.0\",\n    \"unist-util-visit\": \"^5.0.0\",\n    \"unist-util-visit-children\": \"^3.0.0\",\n    \"yaml\": \"^2.3.2\",\n    \"zod\": \"^4.1.12\"\n  },\n  \"devDependencies\": {\n    \"@svgr/plugin-svgo\": \"^8.1.0\",\n    \"@testing-library/react\": \"^16.0.0\",\n    \"@types/estree\": \"^1.0.5\",\n    \"@types/hast\": \"^3.0.4\",\n    \"@types/mdast\": \"^4.0.4\",\n    \"@types/negotiator\": \"^0.6.3\",\n    \"@types/react\": \"^19.1.8\",\n    \"@types/webpack\": \"^5.28.5\",\n    \"@vitejs/plugin-react\": \"^4.3.4\",\n    \"esbuild-plugin-svgr\": \"^3.1.1\",\n    \"esbuild-react-compiler-plugin\": \"workspace:*\",\n    \"mdast-util-mdx-jsx\": \"^3.1.3\",\n    \"mdast-util-mdxjs-esm\": \"^2.0.1\",\n    \"next\": \"^16.0.7\",\n    \"react\": \"19.1.0\",\n    \"react-dom\": \"19.1.0\",\n    \"unified\": \"^11.0.5\",\n    \"vitest\": \"^3.0.0\"\n  },\n  \"sideEffects\": false\n}\n"
  },
  {
    "path": "packages/nextra/setup-files.ts",
    "content": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { HeadPropsSchema } from './src/client/components/head.js'\nimport { NextraConfigSchema } from './src/server/schemas.js'\nimport { generateTsFromZod } from './src/server/tsdoc/zod-to-ts.js'\n\nconst rawTs = `export interface NextraConfig ${generateTsFromZod(NextraConfigSchema)}\n\nexport interface HeadProps ${generateTsFromZod(HeadPropsSchema)}`\n\nawait fs.writeFile(path.resolve('src', 'types.generated.ts'), rawTs)\n"
  },
  {
    "path": "packages/nextra/src/client/__tests__/mdx-components.test-d.ts",
    "content": "import { useMDXComponents } from '../mdx-components.js'\n\ndescribe('useMDXComponents', () => {\n  test('when `MDXComponent`s are provided', () => {\n    const components = useMDXComponents({ h2: () => null })\n    expectTypeOf(components['img']).toBeFunction()\n    expectTypeOf(components['a']).toBeFunction()\n    expectTypeOf(components['h2']).toBeFunction()\n\n    // @ts-expect-error -- assert does not exist on type\n    expectTypeOf(components['h1']).not.toBeFunction()\n  })\n  test('when `MDXComponent`s are not provided', () => {\n    const components = useMDXComponents()\n    expectTypeOf(components['img']).toBeFunction()\n    expectTypeOf(components['a']).toBeFunction()\n\n    // @ts-expect-error -- assert does not exist on type\n    expectTypeOf(components['h1']).not.toBeFunction()\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/client/__tests__/remove-links.test.tsx",
    "content": "import { removeLinks } from '../remove-links.js'\n\ndescribe('removeLinks()', () => {\n  it('should return string', () => {\n    expect(removeLinks('foo')).toBe('foo')\n  })\n  it('should remove link inside fragment', () => {\n    const node = (\n      <>\n        foo\n        <code>\n          <a href=\"#\">bar</a>\n        </code>\n      </>\n    )\n    expect(removeLinks(node)).toMatchInlineSnapshot(`\n      [\n        <React.Fragment>\n          foo\n          <code>\n            bar\n          </code>\n        </React.Fragment>,\n      ]\n    `)\n  })\n  it('should remove wrapper link', () => {\n    const node = (\n      <a href=\"#\">\n        foo<code>bar</code>\n      </a>\n    )\n    expect(removeLinks(node)).toMatchInlineSnapshot(`\n      [\n        \"foo\",\n        <code>\n          bar\n        </code>,\n      ]\n    `)\n  })\n  it('should remove `undefined`', () => {\n    const node = <>foo{undefined}bar</>\n    expect(removeLinks(node)).toMatchInlineSnapshot(`\n      [\n        <React.Fragment>\n          foo\n          bar\n        </React.Fragment>,\n      ]\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/client/__tests__/use-fs-route.test.ts",
    "content": "import { renderHook } from '@testing-library/react'\nimport { usePathname } from 'next/navigation'\nimport type { Mock } from 'vitest'\nimport { useFSRoute } from '../hooks/use-fs-route.js'\n\nvi.mock('next/navigation', () => ({\n  usePathname: vi.fn()\n}))\n\nfunction mockAndRenderHook(pathname: string) {\n  ;(usePathname as Mock).mockReturnValue(pathname)\n  const { result } = renderHook(useFSRoute)\n  return result.current\n}\n\ndescribe('getFSRoute', () => {\n  it('replace index', () => {\n    const withIndex = mockAndRenderHook('/bar/index')\n    expect(withIndex).toEqual('/bar')\n  })\n\n  it('remove trailing slash', () => {\n    const value = mockAndRenderHook('/foo/')\n    expect(value).toEqual('/foo')\n  })\n\n  it('should strip .html file extension', () => {\n    const value = mockAndRenderHook('/foo.html')\n    expect(value).toEqual('/foo')\n  })\n\n  it('should strip .html file extension and replace index', () => {\n    const value = mockAndRenderHook('/foo/index.html')\n    expect(value).toEqual('/foo')\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/client/components/banner/close-banner-button.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport type { FC, ReactNode } from 'react'\nimport { Button } from '../button.js'\n\nexport const CloseBannerButton: FC<{\n  storageKey: string\n  children: ReactNode\n}> = ({ storageKey, children }) => {\n  return (\n    <Button\n      aria-label=\"Dismiss banner\"\n      className={({ hover }) =>\n        cn('x:p-2', hover ? 'x:opacity-100' : 'x:opacity-80')\n      }\n      onClick={event => {\n        event.currentTarget.parentElement!.classList.add('x:hidden')\n        try {\n          localStorage.setItem(storageKey, '1')\n        } catch {\n          /* ignore */\n        }\n      }}\n    >\n      {children}\n    </Button>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/banner/index.client.tsx",
    "content": "'use client'\n\nimport type { ComponentPropsWithoutRef, FC } from 'react'\nimport { useEffect, useRef } from 'react'\n\nexport const ClientBanner: FC<ComponentPropsWithoutRef<'div'>> = props => {\n  const banner = useRef<HTMLDivElement>(null!)\n\n  useEffect(() => {\n    const resizeObserver = new ResizeObserver(entries => {\n      for (const entry of entries) {\n        const { height } = entry.contentRect\n        // Set height because banner text can be wrapped on next line and his height can be different\n        document.documentElement.style.setProperty(\n          '--nextra-banner-height',\n          `${height}px`\n        )\n      }\n    })\n    resizeObserver.observe(banner.current)\n    return () => {\n      resizeObserver.disconnect()\n    }\n  }, [])\n\n  return <div ref={banner} {...props} />\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/banner/index.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes } from 'react'\nimport { XIcon } from '../../icons/index.js'\nimport { CloseBannerButton } from './close-banner-button.js'\nimport { ClientBanner } from './index.client'\n\nconst BANNER_CLASS_NAME = 'nextra-banner'\n\ntype BannerProps = HTMLAttributes<HTMLDivElement> & {\n  /**\n   * Closable banner or not.\n   * @default true\n   */\n  dismissible?: boolean\n  /**\n   * Storage key to keep the banner state.\n   * @default 'nextra-banner'\n   */\n  storageKey?: string\n}\n\n/**\n * A built-in component to show a banner on the top of the website. It can be used to show a warning\n * or a notice.\n *\n * @example\n * ### Banner key\n *\n * A banner can be dismissed. By default, it's used by\n * [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)\n * to keep the banner state on the client.\n *\n * If you have updated your banner text, you should change the key to make sure the banner is shown\n * again. The best practice is to always use a descriptive key for the current text, for example:\n *\n * ![Banner](https://nextra.site/assets/docs/banner.png)\n *\n * ```jsx filename=\"app/layout.jsx\" {7-11}\n * import { Layout } from 'my-nextra-theme'\n * import { Banner } from 'nextra/components'\n *\n * export default function MyLayout({ children, ...props }) {\n *   return (\n *     <Layout>\n *       <Banner storageKey=\"2.0-release\">\n *         <a href=\"https://nextra.site\" target=\"_blank\">\n *           🎉 Nextra 2.0 is released. Read more →\n *         </a>\n *       </Banner>\n *       {children}\n *     </Layout>\n *   )\n * }\n * ```\n */\nexport const Banner: FC<BannerProps> = ({\n  dismissible = true,\n  storageKey = BANNER_CLASS_NAME,\n  className,\n  ...props\n}) => {\n  if (!props.children) {\n    return null\n  }\n  const hideBannerScript = `try{document.querySelector('.${BANNER_CLASS_NAME}').classList.toggle('x:hidden',localStorage.getItem(${JSON.stringify(storageKey)}))}catch(e){}`\n\n  return (\n    <ClientBanner\n      className={cn(\n        BANNER_CLASS_NAME,\n        'x:max-md:sticky x:top-0 x:z-30 x:flex x:items-center x:px-2',\n        'x:text-slate-50 x:dark:text-white x:bg-neutral-900 x:dark:bg-[linear-gradient(1deg,#383838,#212121)]',\n        'x:print:[display:none]' // to not match `x:[.nextra-banner:not([class$=hidden])~&]` class\n      )}\n      // Because we update class in `<script>`\n      suppressHydrationWarning\n    >\n      <div\n        className={cn(\n          'x:w-full x:text-center x:font-medium x:text-sm x:py-2.5',\n          className\n        )}\n        {...props}\n      />\n      {dismissible && (\n        <CloseBannerButton storageKey={storageKey}>\n          <script dangerouslySetInnerHTML={{ __html: hideBannerScript }} />\n          <XIcon height=\"1em\" />\n        </CloseBannerButton>\n      )}\n    </ClientBanner>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/bleed.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes } from 'react'\n\n/**\n * A built-in component to slightly expand content beyond the container's width, `<Bleed>` allows it\n * to overflow on both sides.\n *\n * It's ideal for enhancing the presentation of graphical elements, offering a more immersive and\n * visually appealing reading experience.\n *\n * @example\n *\n * You can put text, image, video or any component inside.\n *\n * ### Text\n *\n * <Bleed className=\"bg-white dark:bg-neutral-800 px-16 py-10 text-center border\">\n *   _There is nothing to writing. All you do is sit down at a typewriter and **bleed**._\n *\n *   — Ernest Hemingway\n * </Bleed>\n *\n * ### Video\n *\n * <Bleed>\n *   <iframe\n *     className=\"aspect-video w-full\"\n *     src=\"https://youtube.com/embed/3hccXiXI0u8\"\n *     allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\"\n *     allowFullScreen\n *   />\n * </Bleed>\n *\n * ### Full-bleed\n *\n * You can even make it full-bleed by using `<Bleed full>`:\n *\n * <Bleed full>![Nextra](/opengraph-image.jpeg)</Bleed>\n *\n * @usage\n *\n * ```mdx filename=\"MDX\"\n * import { Bleed } from 'nextra/components'\n *\n * <Bleed>Hey, I can use **Markdown** syntax here.</Bleed>\n *\n * <Bleed full>![Nextra](https://nextra.site/og.jpeg)</Bleed>\n *\n * <Bleed full>\n *   <iframe\n *     src=\"https://codesandbox.io/embed/swr-states-4une7\"\n *     width=\"100%\"\n *     height=\"500px\"\n *     title=\"SWR-States\"\n *   />\n * </Bleed>\n * ```\n */\nexport const Bleed: FC<\n  {\n    /** Extend content to the very edges of its container. */\n    full: boolean\n  } & HTMLAttributes<HTMLDivElement>\n> = ({ full, className, ...props }) => {\n  return (\n    <div\n      className={cn(\n        'nextra-bleed x:relative x:-mx-4 x:mt-[1.25em] x:md:-mx-8 x:2xl:-mx-24',\n        'x:z-1', // for firefox https://github.com/shuding/nextra/issues/2824\n        full && [\n          // 'md:mx:[calc(-50vw+50%+8rem)',\n          'x:xl:me-[calc(50%-50vw)] x:xl:ms-[calc(50%-50vw+16rem)]'\n        ],\n        className\n      )}\n      {...props}\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/button.tsx",
    "content": "'use client'\n\nimport { Button as HeadlessButton } from '@headlessui/react'\nimport type { ButtonProps as HeadlessButtonProps } from '@headlessui/react'\nimport cn from 'clsx'\nimport type { FC } from 'react'\nimport { classes } from '../mdx-components/pre/index.js'\n\nexport type ButtonProps = HeadlessButtonProps & {\n  variant?: 'outline' | 'default'\n}\n\nexport const Button: FC<ButtonProps> = ({\n  children,\n  className,\n  variant = 'default',\n  ...props\n}) => {\n  return (\n    <HeadlessButton\n      className={args =>\n        cn(\n          'x:transition x:cursor-pointer',\n          args.focus && 'x:nextra-focus',\n          variant === 'outline' && [classes.border, 'x:rounded-md x:p-1.5'],\n          typeof className === 'function' ? className(args) : className\n        )\n      }\n      {...props}\n    >\n      {children}\n    </HeadlessButton>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/callout.tsx",
    "content": "import cn from 'clsx'\nimport type { CSSProperties, FC, HTMLAttributes, ReactNode } from 'react'\nimport {\n  GitHubCautionIcon,\n  GitHubImportantIcon,\n  GitHubNoteIcon,\n  GitHubTipIcon,\n  GitHubWarningIcon\n} from '../icons/index.js'\n\nconst TypeToEmoji = {\n  default: <GitHubTipIcon height=\".8em\" className=\"x:mt-[.3em]\" />,\n  error: <GitHubCautionIcon height=\".8em\" className=\"x:mt-[.3em]\" />,\n  info: <GitHubNoteIcon height=\".8em\" className=\"x:mt-[.3em]\" />,\n  warning: <GitHubWarningIcon height=\".8em\" className=\"x:mt-[.3em]\" />,\n  important: <GitHubImportantIcon height=\".8em\" className=\"x:mt-[.3em]\" />\n}\n\ntype CalloutType = keyof typeof TypeToEmoji\n\nconst classes: Record<CalloutType, string> = {\n  default: cn(\n    'x:bg-green-100 x:dark:bg-green-900/30',\n    'x:text-green-700 x:dark:text-green-500',\n    'x:border-green-700 x:dark:border-green-800'\n  ),\n  error: cn(\n    'x:bg-red-100 x:dark:bg-red-900/30',\n    'x:text-red-700 x:dark:text-red-500',\n    'x:border-red-700 x:dark:border-red-600'\n  ),\n  info: cn(\n    'x:bg-blue-100 x:dark:bg-blue-900/30',\n    'x:text-blue-700 x:dark:text-blue-400',\n    'x:border-blue-700 x:dark:border-blue-600'\n  ),\n  warning: cn(\n    'x:bg-yellow-50 x:dark:bg-yellow-700/30',\n    'x:text-yellow-700 x:dark:text-yellow-500',\n    'x:border-yellow-700'\n  ),\n  important: cn(\n    'x:bg-purple-100 x:dark:bg-purple-900/30',\n    'x:text-purple-600 x:dark:text-purple-400',\n    'x:border-purple-600'\n  )\n}\n\ntype CalloutProps = HTMLAttributes<HTMLDivElement> & {\n  /**\n   * Defines the style of the callout and determines the default icon if `emoji` is not provided.\n   *\n   * If set to `null`, no border, background, or text styling will be applied.\n   * @default 'default'\n   */\n  type?: CalloutType | null\n  /**\n   * Icon displayed in the callout. Can be a string emoji or a custom React element.\n   *\n   * Default values based on `type`:\n   * - `<GitHubTipIcon />` for `type: 'default'`\n   * - `<GitHubCautionIcon />` for `type: 'error'`\n   * - `<GitHubNoteIcon />` for `type: 'info'`\n   * - `<GitHubWarningIcon />` for `type: 'warning'`\n   * - `<GitHubImportantIcon />` for `type: 'important'`\n   * @default Determined by `type`\n   */\n  emoji?: ReactNode\n}\n\n/**\n * A built-in component to show important information to the reader.\n *\n * @example\n * <Callout>\n *   A **callout** is a short piece of text intended to attract attention.\n * </Callout>\n *\n * <Callout type=\"info\">\n *   A **callout** is a short piece of text intended to attract attention.\n * </Callout>\n *\n * <Callout type=\"warning\">\n *   A **callout** is a short piece of text intended to attract attention.\n * </Callout>\n *\n * <Callout type=\"error\">\n *   A **callout** is a short piece of text intended to attract attention.\n * </Callout>\n *\n * <Callout type=\"important\">\n *   A **callout** is a short piece of text intended to attract attention.\n * </Callout>\n *\n * @usage\n * ### Default\n *\n * <Callout>Helpful advice for doing things better or more easily.</Callout>\n *\n * ```mdx\n * import { Callout } from 'nextra/components'\n *\n * <Callout>Helpful advice for doing things better or more easily.</Callout>\n * ```\n *\n * ### Info\n *\n * <Callout type=\"info\">\n *   Useful information that users should know, even when skimming content.\n * </Callout>\n *\n * ```mdx\n * import { Callout } from 'nextra/components'\n *\n * <Callout type=\"info\">\n *   Useful information that users should know, even when skimming content.\n * </Callout>\n * ```\n *\n * ### Warning\n *\n * <Callout type=\"warning\">\n *   Urgent info that needs immediate user attention to avoid problems.\n * </Callout>\n *\n * ```mdx\n * import { Callout } from 'nextra/components'\n *\n * <Callout type=\"warning\">\n *   Urgent info that needs immediate user attention to avoid problems.\n * </Callout>\n * ```\n *\n * ### Error\n *\n * <Callout type=\"error\">\n *   Advises about risks or negative outcomes of certain actions.\n * </Callout>\n *\n * ```mdx\n * import { Callout } from 'nextra/components'\n *\n * <Callout type=\"error\">\n *   Advises about risks or negative outcomes of certain actions.\n * </Callout>\n * ```\n *\n * ### Important\n *\n * <Callout type=\"important\">\n *   Key information users need to know to achieve their goal.\n * </Callout>\n *\n * ```mdx\n * import { Callout } from 'nextra/components'\n *\n * <Callout type=\"important\">\n *   Key information users need to know to achieve their goal.\n * </Callout>\n * ```\n *\n * ### Custom icon\n *\n * <Callout type=\"info\" emoji=\"⭐\">Nextra has 13k stars on GitHub!</Callout>\n *\n * ```mdx\n * import { Callout } from 'nextra/components'\n *\n * <Callout type=\"info\" emoji=\"⭐\">Nextra has 13k stars on GitHub!</Callout>\n * ```\n */\nexport const Callout: FC<CalloutProps> = ({\n  className,\n  type = 'default',\n  emoji = type && TypeToEmoji[type],\n  ...props\n}) => {\n  return (\n    <div\n      className={cn(\n        'nextra-callout x:overflow-x-auto x:not-first:mt-[1.25em] x:flex x:rounded-lg x:border x:py-[.5em] x:pe-[1em]',\n        'x:contrast-more:border-current!',\n        type && classes[type]\n      )}\n    >\n      <div\n        className=\"x:select-none x:text-[1.25em] x:ps-[.6em] x:pe-[.4em]\"\n        style={style}\n        data-pagefind-ignore=\"all\"\n      >\n        {emoji}\n      </div>\n      <div className={cn('x:w-full x:min-w-0', className)} {...props} />\n    </div>\n  )\n}\n\nconst style: CSSProperties = {\n  fontFamily: '\"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\"'\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/cards.tsx",
    "content": "import cn from 'clsx'\nimport NextLink from 'next/link'\nimport type { FC, HTMLAttributes, ReactElement, ReactNode } from 'react'\n\nconst Card: FC<{\n  title: string\n  icon?: ReactElement\n  arrow?: boolean\n  href: string\n  children?: ReactNode\n  /** CSS class name. */\n  className?: string\n}> = ({ children, title, icon, arrow, href, className, ...props }) => {\n  return (\n    <NextLink\n      href={href}\n      className={cn(\n        'x:group',\n        'x:focus-visible:nextra-focus nextra-card x:flex x:flex-col x:justify-start x:overflow-hidden x:rounded-lg x:border x:border-gray-200',\n        'x:text-current x:no-underline x:dark:shadow-none',\n        'x:hover:shadow-gray-100 x:dark:hover:shadow-none x:shadow-gray-100',\n        'x:active:shadow-sm x:active:shadow-gray-200',\n        'x:transition-all x:duration-200 x:hover:border-gray-300',\n        children\n          ? 'x:bg-gray-100 x:shadow x:dark:border-neutral-700 x:dark:bg-neutral-800 x:dark:text-gray-50 x:hover:shadow-lg x:dark:hover:border-neutral-500 x:dark:hover:bg-neutral-700'\n          : 'x:bg-transparent x:shadow-sm x:dark:border-neutral-800 x:hover:bg-slate-50 x:hover:shadow-md x:dark:hover:border-neutral-700 x:dark:hover:bg-neutral-900',\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <span\n        className={cn(\n          'x:flex x:font-semibold x:items-center x:gap-2 x:p-4 x:text-gray-700 x:hover:text-gray-900',\n          arrow && [\n            'x:after:content-[\"→\"] x:after:transition-transform x:after:duration-75',\n            'x:group-hover:after:translate-x-0.5',\n            'x:group-focus:after:translate-x-0.5'\n          ],\n          children\n            ? 'x:dark:text-gray-300 x:dark:hover:text-gray-100'\n            : 'x:dark:text-neutral-200 x:dark:hover:text-neutral-50'\n        )}\n        title={typeof title === 'string' ? title : undefined}\n      >\n        {icon}\n        <span className=\"_truncate\">{title}</span>\n      </span>\n    </NextLink>\n  )\n}\n\nconst _Cards: FC<\n  {\n    /**\n     * Number of columns.\n     * @default 3\n     */\n    num?: number\n  } & HTMLAttributes<HTMLDivElement>\n> = ({ children, num = 3, className, style, ...props }) => {\n  return (\n    <div\n      className={cn(\n        'nextra-cards x:mt-4 x:gap-4 x:grid',\n        'not-prose', // for nextra-theme-blog\n        className\n      )}\n      {...props}\n      style={{\n        ...style,\n        ['--rows' as string]: num\n      }}\n    >\n      {children}\n    </div>\n  )\n}\n\n/**\n * A built-in component that allows you to display content in a visually appealing card format. It\n * includes options for adding an icon, title, link and an image to related content.\n *\n * @example\n * ### Grouped cards\n *\n * <Cards>\n *   <Cards.Card\n *     icon={<WarningIcon />}\n *     title=\"Callout\"\n *     href=\"/docs/built-ins/callout\"\n *   />\n *   <Cards.Card\n *     icon={<CardsIcon />}\n *     title=\"Tabs\"\n *     href=\"/docs/built-ins/tabs\"\n *   />\n *   <Cards.Card\n *     icon={<OneIcon />}\n *     title=\"Steps\"\n *     href=\"/docs/built-ins/steps\"\n *   />\n * </Cards>\n *\n * ### Single card\n *\n * <br />\n * <Cards.Card\n *   icon={<BoxIcon />}\n *   title=\"About Nextra\"\n *   href=\"/about\"\n *   arrow\n * />\n *\n * @usage\n * ### Grouped cards\n *\n * Import the `<Cards>` component to your page, which includes the `<Card>` component.\n *\n * Then, optionally import the icons that you want to use. To create a set of cards, follow the\n * example below where the `<Cards.Card>` component is used to create a card and the `<Cards>`\n * component is used to group multiple cards together.\n *\n * ```mdx filename=\"MDX\"\n * import { Cards } from 'nextra/components'\n * import { CardsIcon, OneIcon, WarningIcon } from '../path/with/your/icons'\n *\n * <Cards>\n *   <Cards.Card\n *     icon={<WarningIcon />}\n *     title=\"Callout\"\n *     href=\"/docs/built-ins/callout\"\n *   />\n *   <Cards.Card\n *     icon={<CardsIcon />}\n *     title=\"Tabs\"\n *     href=\"/docs/built-ins/tabs\"\n *   />\n *   <Cards.Card\n *     icon={<OneIcon />}\n *     title=\"Steps\"\n *     href=\"/docs/built-ins/steps\"\n *   />\n * </Cards>\n * ```\n *\n * ### Single card\n *\n * A `<Card>` not wrapped in a `<Cards>` component will not be grouped with other cards. This can\n * be useful if you want to display a single card in a different format than the other cards on the\n * page.\n *\n * ```mdx filename=\"MDX\"\n * <Cards.Card\n *   icon={<BoxIcon />}\n *   title=\"About Nextra\"\n *   href=\"/about\"\n *   arrow\n * />\n * ```\n */\nexport const Cards = Object.assign(_Cards, { displayName: 'Cards', Card })\n"
  },
  {
    "path": "packages/nextra/src/client/components/collapse.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport type { FC, ReactNode } from 'react'\nimport { Children, useEffect, useRef, useState } from 'react'\n\nexport const Collapse: FC<{\n  className?: string\n  children: ReactNode\n  isOpen: boolean\n  horizontal?: boolean\n  openDuration?: number\n  closeDuration?: number\n}> = ({\n  className,\n  children,\n  isOpen,\n  horizontal = false,\n  openDuration = 500,\n  closeDuration = 300\n}) => {\n  const containerRef = useRef<HTMLDivElement>(null!)\n  const [initialOpen] = useState(isOpen)\n  const animationRef = useRef(0)\n  const initialRender = useRef(true)\n  useEffect(() => {\n    const animation = animationRef.current\n    const container = containerRef.current\n    if (animation) {\n      clearTimeout(animation)\n      animationRef.current = 0\n    }\n\n    if (initialRender.current) {\n      return\n    }\n    const child = container.children[0] as HTMLDivElement\n\n    if (horizontal) {\n      // save initial width to avoid word wrapping when container width will be changed\n      child.style.width = `${child.clientWidth}px`\n      container.style.width = `${child.clientWidth}px`\n    } else {\n      container.style.height = `${child.clientHeight}px`\n    }\n    if (isOpen) {\n      animationRef.current = window.setTimeout(() => {\n        // should be style property in kebab-case, not CSS class name\n        container.style.removeProperty('height')\n      }, openDuration)\n    } else {\n      requestAnimationFrame(() => {\n        // Hide content on next tick\n        if (horizontal) {\n          container.style.width = '0'\n        } else {\n          container.style.height = '0'\n        }\n      })\n    }\n  }, [horizontal, isOpen, openDuration])\n\n  useEffect(() => {\n    if (\n      // for horizontal only for first open state\n      isOpen ||\n      !horizontal\n    ) {\n      initialRender.current = false\n    }\n  }, [horizontal, isOpen])\n\n  // Add inner <div> only if children.length != 1\n  const newChildren =\n    Children.count(children) === 1 &&\n    children &&\n    typeof children === 'object' &&\n    'type' in children ? (\n      children\n    ) : (\n      <div>{children}</div>\n    )\n\n  return (\n    <div\n      ref={containerRef}\n      className={cn(\n        'x:transform-gpu x:transition-all x:ease-in-out x:motion-reduce:transition-none',\n        isOpen ? 'x:opacity-100' : 'x:opacity-0 x:overflow-hidden',\n        className\n      )}\n      style={{\n        ...(initialOpen || horizontal ? undefined : { height: 0 }),\n        transitionDuration: (isOpen ? openDuration : closeDuration) + 'ms'\n      }}\n    >\n      {newChildren}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/file-tree/file.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, ReactNode } from 'react'\nimport { FileIcon } from '../../icons/index.js'\n\nexport type FileProps = {\n  name: ReactNode\n  active?: boolean\n}\n\nexport const File: FC<FileProps> = ({ name, active }) => {\n  return (\n    <li\n      className={cn(\n        'x:flex x:items-center x:gap-1 x:break-all',\n        active && 'x:text-primary-600'\n      )}\n    >\n      {/* Text can shrink icon */}\n      <FileIcon height=\"14\" className=\"x:shrink-0\" />\n      {name}\n    </li>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/file-tree/folder.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport { useState } from 'react'\nimport type { FC, ReactNode } from 'react'\nimport { FolderIcon, FolderOpenIcon } from '../../icons/index.js'\nimport { Button } from '../button.js'\nimport type { FileProps } from './file.js'\n\ntype FolderProps = FileProps & {\n  open?: boolean\n  /** @default false */\n  defaultOpen?: boolean\n  children: ReactNode\n}\n\nexport const Folder: FC<FolderProps> = ({\n  name,\n  open,\n  children,\n  defaultOpen = false,\n  active\n}) => {\n  const [isOpen, setIsOpen] = useState(defaultOpen)\n\n  const toggle = () => {\n    setIsOpen(v => !v)\n  }\n\n  const isFolderOpen = open === undefined ? isOpen : open\n\n  const ComponentToUse = isFolderOpen ? FolderOpenIcon : FolderIcon\n\n  return (\n    <li className=\"x:flex x:flex-col x:gap-1\">\n      <Button\n        onClick={toggle}\n        disabled={open}\n        className={({ hover }) =>\n          cn(\n            'x:flex x:items-center x:gap-1 x:break-all',\n            'x:text-start', // override browser default\n            hover && 'x:opacity-60',\n            active && 'x:text-primary-600'\n          )\n        }\n      >\n        {/* Text can shrink icon */}\n        <ComponentToUse height=\"14\" className=\"x:shrink-0\" />\n        {name}\n      </Button>\n      {isFolderOpen && (\n        <ul className=\"x:flex x:flex-col x:gap-2 x:ps-4\">{children}</ul>\n      )}\n    </li>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/file-tree/index.tsx",
    "content": "'use no memo'\n\nimport type { ComponentProps } from 'react'\nimport { File } from './file.js'\nimport { Folder } from './folder.js'\nimport { Tree } from './tree.js'\n\n// Workaround to fix\n// Error: Cannot access File.propTypes on the server. You cannot dot into a client\n// module from a server component. You can only pass the imported name through.\n/**\n * A built-in component to visually represent a file tree.\n *\n * @example\n * Click the folder to test the dynamic functionality of the file tree.\n *\n * <FileTree>\n *   <FileTree.Folder name=\"content\" defaultOpen>\n *     <FileTree.File name=\"_meta.js\" />\n *     <FileTree.File name=\"contact.md\" />\n *     <FileTree.File name=\"index.mdx\" />\n *     <FileTree.Folder name=\"about\">\n *       <FileTree.File name=\"_meta.js\" />\n *       <FileTree.File name=\"legal.md\" />\n *       <FileTree.File name=\"index.mdx\" />\n *     </FileTree.Folder>\n *   </FileTree.Folder>\n * </FileTree>\n *\n * @usage\n * Create the file tree structure by nesting `<FileTree.Folder>` and\n * `<FileTree.File>` components within a `<FileTree>`. Name each file or folder\n * with the `name` attribute. Use `defaultOpen` to set the folder to open on load.\n *\n * ```mdx filename=\"MDX\"\n * import { FileTree } from 'nextra/components'\n *\n * <FileTree>\n *   <FileTree.Folder name=\"content\" defaultOpen>\n *     <FileTree.File name=\"_meta.js\" />\n *     <FileTree.File name=\"contact.md\" />\n *     <FileTree.File name=\"index.mdx\" />\n *     <FileTree.Folder name=\"about\">\n *       <FileTree.File name=\"_meta.js\" />\n *       <FileTree.File name=\"legal.md\" />\n *       <FileTree.File name=\"index.mdx\" />\n *     </FileTree.Folder>\n *   </FileTree.Folder>\n * </FileTree>\n * ```\n */\nexport const FileTree = Object.assign(\n  (props: ComponentProps<typeof Tree>) => <Tree {...props} />,\n  { Folder, File }\n)\n"
  },
  {
    "path": "packages/nextra/src/client/components/file-tree/tree.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes } from 'react'\n\nexport const Tree: FC<HTMLAttributes<HTMLUListElement>> = ({\n  className,\n  ...props\n}) => {\n  return (\n    <ul\n      className={cn(\n        'nextra-filetree x:mt-[1.25em] x:select-none x:text-sm x:text-gray-800 x:dark:text-gray-300',\n        'not-prose', // for nextra-theme-blog\n        'x:rounded-lg x:border x:px-4 x:py-3 x:inline-flex x:flex-col x:gap-2',\n        'nextra-border',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/head.tsx",
    "content": "import type { FC } from 'react'\nimport { z } from 'zod'\nimport { reactNode } from '../../server/schemas.js'\nimport type { HeadProps } from '../../types.generated.js'\n\nconst darkLightSchema = z.union([\n  z.number(),\n  z.strictObject({\n    dark: z.number(),\n    light: z.number()\n  })\n])\n\nfunction convertColor(v: z.infer<typeof darkLightSchema>) {\n  return typeof v === 'number' ? { dark: v, light: v } : v\n}\n\nfunction hexToRgb(hex: string): string {\n  hex = hex.slice(1)\n  if (hex.length === 3) {\n    hex = hex\n      // eslint-disable-next-line unicorn/prefer-spread -- https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2521#issuecomment-2564033898\n      .split('')\n      .map(char => char + char)\n      .join('')\n  }\n  const bigint = Number.parseInt(hex, 16)\n  const r = (bigint >> 16) & 255\n  const g = (bigint >> 8) & 255\n  const b = bigint & 255\n  return `${r},${g},${b}`\n}\n\nconst RGB_RE = /^rgb\\((?<rgb>.*?)\\)$/\nconst HEX_RE = /^#(?<hex>[0-9a-f]{3,6})$/i\n\nfunction normalizeColor(value: string): string {\n  if (value.startsWith('#')) {\n    return hexToRgb(value)\n  }\n  const rgb = value.match(RGB_RE)?.groups!.rgb\n  if (rgb) {\n    return rgb.replaceAll(' ', '')\n  }\n  return value\n}\n\nconst stringColorSchema = z.string().refine(str => {\n  if (HEX_RE.test(str) || RGB_RE.test(str)) {\n    return true\n  }\n  throw new Error(\n    'Color format should be in HEX or RGB format. E.g. #000, #112233 or rgb(255,255,255)'\n  )\n})\n\nconst colorSchema = z.strictObject({\n  hue: darkLightSchema\n    .default({ dark: 204, light: 212 })\n    .overwrite(convertColor)\n    .meta({\n      description: 'The hue of the primary theme color.<br/>Range: `0 - 360`'\n    }),\n  saturation: darkLightSchema.default(100).overwrite(convertColor).meta({\n    description:\n      'The saturation of the primary theme color.<br/>Range: `0 - 100`'\n  }),\n  lightness: darkLightSchema\n    .default({ dark: 55, light: 45 })\n    .overwrite(convertColor)\n    .meta({\n      description:\n        'The lightness of the primary theme color.<br/>Range: `0 - 100`'\n    })\n})\n\nconst bgColorSchema = z.strictObject({\n  dark: stringColorSchema\n    .default('rgb(17,17,17)')\n    .transform(normalizeColor)\n    .meta({\n      description:\n        'Background color for dark theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`'\n    }),\n  light: stringColorSchema\n    .default('rgb(250,250,250)')\n    .transform(normalizeColor)\n    .meta({\n      description:\n        'Background color for light theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`'\n    })\n})\n\nexport const HeadPropsSchema = z.strictObject({\n  color: colorSchema.default(colorSchema.parse({})),\n  faviconGlyph: z.string().optional().meta({\n    description: 'The glyph to use as the favicon.'\n  }),\n  backgroundColor: bgColorSchema.default(bgColorSchema.parse({})),\n  children: reactNode.optional().meta({\n    description: 'Content of `<head>`.'\n  })\n})\n\n/**\n * Configure the `<head>` tags, primary color, background color and favicon glyph\n * of the website.\n *\n * @usage\n * ### Static head tags\n *\n * If you have static head tags, they should be put as `children` in `Head`. For\n * example:\n *\n * ```jsx filename=\"app/layout.jsx\" {8}\n * import { Layout } from 'my-nextra-theme'\n * import { Head } from 'nextra/components'\n *\n * export default function MyLayout({ children, ...props }) {\n *   return (\n *     <html lang=\"en\">\n *       <Head>\n *         <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n *       </Head>\n *       <body>\n *         <Layout>{children}</Layout>\n *       </body>\n *     </html>\n *   )\n * }\n * ```\n *\n * ### Dynamic tags based on page\n *\n * You can dynamically generate the head tags based on the current page's front\n * matter. For example:\n *\n * #### via Markdown front matter\n *\n * ```mdx filename=\"my-page/page.mdx\"\n * ---\n * title: My title\n * description: My description\n * ---\n * ```\n *\n * #### via exporting `metadata` object\n *\n * ```mdx filename=\"my-page/page.mdx\"\n * export const metadata = {\n *   title: 'My title',\n *   description: 'My description'\n * }\n * ```\n *\n * #### in [dynamic routes with catch-all segment](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#catch-all-segments)\n *\n * ```jsx filename=\"app/[[...mdxPath]]/page.jsx\"\n * import { importPage } from 'nextra/pages'\n *\n * export async function generateMetadata(props) {\n *   const { mdxPath } = await props.params\n *   const { metadata } = await importPage(mdxPath)\n *   return {\n *     title: metadata.title || 'Nextra',\n *     description: metadata.description || 'The next site builder'\n *   }\n * }\n * ```\n *\n * ### Theme color\n *\n * You can adjust the theme color of the website by setting primary Hue, Saturation\n * and Lightness (HSL) values for light and dark themes. Try it out for this\n * website:\n *\n * | Hue (H)                                            | Saturation (S)                                            | Lightness (L)                                             | Background Color   |\n * | -------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- | ------------------ |\n * | <Slider max={360} cssVar=\"--nextra-primary-hue\" /> | <Slider max={100} cssVar=\"--nextra-primary-saturation\" /> | <Slider max={100} cssVar=\"--nextra-primary-lightness\"  /> | <BackgroundColor/> |\n *\n * > [!TIP]\n * >\n * > You can adjust the lightness independently for dark or light mode to increase\n * > legibility. E.g. to have a neutral primary color you can set the primary color\n * > to be white `HSL(0, 0%, 100%)` on dark theme and gray `HSL(0, 0%, 50%)` for\n * > light theme.\n * >\n * > ```jsx filename=\"app/layout.jsx\"\n * > <Head\n * >   color={{\n * >     hue: 0,\n * >     saturation: 0,\n * >     lightness: {\n * >       light: 50,\n * >       dark: 100\n * >     }\n * >   }}\n * > />\n * > ```\n *\n * ### Favicon glyph\n *\n * This isn't supported by all browsers, but it's a nice way to customize the\n * favicon of the website simply by using an emoji or character.\n *\n * ```jsx filename=\"app/layout.jsx\"\n * <Head faviconGlyph=\"✦\" />\n * ```\n */\nexport const Head: FC<HeadProps> = ({ children, ...props }) => {\n  const { data, error } = HeadPropsSchema.safeParse(props)\n  if (error) {\n    throw z.prettifyError(error)\n  }\n  // TODO: fix it\n  const { color, backgroundColor, faviconGlyph } = data as any\n\n  const style = `\n:root {\n  --nextra-primary-hue: ${color.hue.light}deg;\n  --nextra-primary-saturation: ${color.saturation.light}%;\n  --nextra-primary-lightness: ${color.lightness.light}%;\n  --nextra-bg: ${backgroundColor.light};\n  --nextra-content-width: 90rem;\n}\n.dark {\n  --nextra-primary-hue: ${color.hue.dark}deg;\n  --nextra-primary-saturation: ${color.saturation.dark}%;\n  --nextra-primary-lightness: ${color.lightness.dark}%;\n  --nextra-bg: ${backgroundColor.dark};\n}\n::selection {\n  background: hsla(var(--nextra-primary-hue),var(--nextra-primary-saturation),var(--nextra-primary-lightness),.3);\n}\nhtml {\n  background: rgb(var(--nextra-bg));\n}\n`.trim()\n\n  return (\n    // eslint-disable-next-line @next/next/no-head-element -- false positive, we use it in App router\n    <head>\n      {children}\n      <style>{style}</style>\n      <meta\n        name=\"theme-color\"\n        media=\"(prefers-color-scheme: light)\"\n        content={`rgb(${backgroundColor.light})`}\n      />\n      <meta\n        name=\"theme-color\"\n        media=\"(prefers-color-scheme: dark)\"\n        content={`rgb(${backgroundColor.dark})`}\n      />\n      {faviconGlyph && (\n        <link\n          rel=\"icon\"\n          href={`data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text x='50' y='.9em' font-size='90' text-anchor='middle'>${faviconGlyph}</text><style>svg{font-family:system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\"}@media(prefers-color-scheme:dark){svg{fill:#fff}}</style></svg>`}\n        />\n      )}\n    </head>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/image-zoom.tsx",
    "content": "'use client'\n\nimport { type ImageProps } from 'next/image'\nimport { useEffect, useRef, useState, type FC } from 'react'\nimport Zoom from 'react-medium-image-zoom'\nimport { Image } from '../mdx-components/image.js'\n\nfunction getImageSrc(src: ImageProps['src']): string {\n  if (typeof src === 'string') {\n    return src\n  }\n  if ('default' in src) {\n    return src.default.src\n  }\n  return src.src\n}\n\nexport const ImageZoom: FC<ImageProps> = props => {\n  const imgRef = useRef<HTMLImageElement>(null!)\n  const [isInsideAnchor, setIsInsideAnchor] = useState(false)\n\n  useEffect(() => {\n    setIsInsideAnchor(imgRef.current.closest('a') !== null)\n  }, [])\n\n  const img = <Image {...props} ref={imgRef} />\n\n  if (isInsideAnchor) {\n    // There is no need to add zoom for images inside anchor tags\n    return img\n  }\n\n  return (\n    <Zoom\n      zoomMargin={40}\n      zoomImg={{\n        src: getImageSrc(props.src),\n        alt: props.alt\n      }}\n      // fix Expected server HTML to contain a matching <div> in <p>.\n      wrapElement=\"span\"\n    >\n      {img}\n    </Zoom>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/index.ts",
    "content": "// @ts-expect-error -- types available only with \"moduleResolution\": \"bundler\" in tsconfig\nexport { Mermaid } from '@theguild/remark-mermaid/mermaid'\nexport { MathJax, MathJaxContext } from 'better-react-mathjax'\n\nexport { Banner } from './banner/index.js'\nexport { FileTree } from './file-tree/index.js'\nexport { SkipNavContent, SkipNavLink } from './skip-nav/index.js'\nexport { Popup } from './popup/index.js'\nexport { Tabs } from './tabs/index.js'\nexport { Bleed } from './bleed.js'\nexport { Button } from './button.js'\nexport { Callout } from './callout.js'\nexport { Cards } from './cards.js'\nexport { Collapse } from './collapse.js'\nexport { Head } from './head.js'\nexport { ImageZoom } from './image-zoom.js'\nexport { Playground } from './playground.js'\nexport { Search } from './search.js'\nexport { Select } from './select.js'\nexport { Steps } from './steps.js'\nexport * from '../hocs/index.js'\nexport * from '../mdx-components/index.js'\n"
  },
  {
    "path": "packages/nextra/src/client/components/playground.tsx",
    "content": "'use client'\n\nimport { useEffect, useState } from 'react'\nimport type { FC, ReactElement } from 'react'\nimport { evaluate } from '../evaluate.js'\nimport type { MDXRemoteProps } from '../mdx-remote.js'\nimport { Callout } from './callout.js'\n\ntype PlaygroundProps = {\n  /**\n   * String with source MDX.\n   * @example '# hello world <br /> nice to see you'\n   */\n  source: string\n  /**\n   * Fallback component for loading.\n   * @default null\n   */\n  fallback?: ReactElement | null\n} & Pick<MDXRemoteProps, 'components' | 'scope'>\n\n/**\n * A built-in component lets you write Nextra-compatible MDX that renders only on the client.\n * @example\n * <PlaygroundDemo />\n *\n * @usage\n * ```mdx filename=\"Basic Usage\"\n * import { Playground } from 'nextra/components'\n *\n * # Playground\n *\n * Below is a playground component. It mixes into the rest of your MDX perfectly.\n *\n * <Playground\n *   source=\"## Hello world\"\n *   components={{ h2: props => <h2 {...props} className=\"myClass\" /> }}\n * />\n * ```\n *\n * You may also specify a fallback component like so:\n *\n * ```mdx filename=\"Usage with Fallback\"\n * import { Playground } from 'nextra/components'\n *\n * <Playground\n *   source=\"## Hello world\"\n *   components={{ h2: props => <h2 {...props} className=\"myClass\" /> }}\n *   fallback={<div>Loading playground...</div>}\n * />\n * ```\n *\n * ### Avoiding unstyled outputs\n *\n * To prevent unstyled elements, import `useMDXComponents` from your\n * `mdx-components` file. Call this function and pass the returned components to\n * the `components` prop. You can also include your custom components as the first\n * argument:\n *\n * ```mdx {1,6-8}\n * import { Playground } from 'nextra/components'\n * import { useMDXComponents } from '../path/to/my/mdx-components'\n *\n * <Playground\n *   source=\"## Hello world\"\n *   components={useMDXComponents({\n *     h2: props => <h2 {...props} className=\"myClass\" />\n *   })}\n *   fallback={<div>Loading playground...</div>}\n * />\n * ```\n */\nexport const Playground: FC<PlaygroundProps> = ({\n  source,\n  fallback = null,\n  components,\n  scope\n}) => {\n  const [compiledSource, setCompiledSource] = useState('')\n  const [error, setError] = useState<unknown>()\n\n  useEffect(() => {\n    async function doCompile() {\n      // Importing in useEffect to not increase global bundle size\n      const { compileMdx } = await importCompile()\n      try {\n        const rawJs = await compileMdx(source)\n        setCompiledSource(rawJs)\n        setError(null)\n      } catch (error) {\n        setError(error)\n      }\n    }\n\n    doCompile()\n  }, [source])\n\n  if (error) {\n    return (\n      <Callout type=\"error\">\n        <b>Could not compile code</b>\n        <br />\n        {error instanceof Error\n          ? `${error.name}: ${error.message}`\n          : String(error)}\n      </Callout>\n    )\n  }\n\n  if (compiledSource) {\n    // `<MDXRemote>` cannot be used here because `useMDXComponents` may include components that\n    // are only available on the server.\n    const MDXContent = evaluate(compiledSource, components, scope).default\n    return <MDXContent />\n  }\n\n  return fallback\n}\n\n// Otherwise react-compiler fails\nfunction importCompile() {\n  return import('../../server/compile.js')\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/popup/index.client.tsx",
    "content": "'use client'\n\nimport { Popover, PopoverPanel } from '@headlessui/react'\nimport type { PopoverPanelProps, PopoverProps } from '@headlessui/react'\nimport cn from 'clsx'\nimport { createContext, useContext, useState } from 'react'\nimport type { FC, MouseEventHandler } from 'react'\n\nconst PopupContext = createContext<boolean | null>(null)\n\nfunction usePopup(): boolean {\n  const ctx = useContext(PopupContext)\n  if (typeof ctx !== 'boolean') {\n    // eslint-disable-next-line unicorn/prefer-type-error -- Doesn't fit in this case\n    throw new Error('`usePopup` must be used within a `<Popup>` component')\n  }\n  return ctx\n}\n\nexport const Popup: FC<PopoverProps> = props => {\n  const [isOpen, setIsOpen] = useState(false)\n\n  const handleMouse: MouseEventHandler = event => {\n    setIsOpen(event.type === 'mouseenter')\n  }\n\n  return (\n    <PopupContext.Provider value={isOpen}>\n      <Popover\n        as=\"span\"\n        onMouseEnter={handleMouse}\n        onMouseLeave={handleMouse}\n        {...props}\n      />\n    </PopupContext.Provider>\n  )\n}\n\nexport const PopupPanel: FC<PopoverPanelProps> = props => {\n  const isOpen = usePopup()\n  return (\n    <PopoverPanel\n      static={isOpen}\n      anchor={{ to: 'bottom start', gap: -24 }}\n      {...props}\n      className={cn(\n        'x:max-w-2xl!', // Override headlessui's computed max-width\n        props.className\n      )}\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/popup/index.tsx",
    "content": "'use no memo'\n\nimport { PopoverButton } from '@headlessui/react'\nimport type { ComponentProps } from 'react'\nimport { Popup as _Popup, PopupPanel } from './index.client.js'\n\n// Workaround to fix\n// Error: Cannot access Popup.Button on the server. You cannot dot into a client\n// module from a server component. You can only pass the imported name through.\nexport const Popup = Object.assign(\n  (props: ComponentProps<typeof _Popup>) => <_Popup {...props} />,\n  {\n    Button: PopoverButton,\n    Panel: PopupPanel\n  }\n)\n"
  },
  {
    "path": "packages/nextra/src/client/components/search.tsx",
    "content": "'use client'\n\nimport {\n  Combobox,\n  ComboboxInput,\n  ComboboxOption,\n  ComboboxOptions,\n  type ComboboxInputProps\n} from '@headlessui/react'\nimport cn from 'clsx'\nimport { addBasePath } from 'next/dist/client/add-base-path'\nimport NextLink from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type {\n  FC,\n  FocusEventHandler,\n  ReactElement,\n  ReactNode,\n  SyntheticEvent\n} from 'react'\nimport { useDeferredValue, useEffect, useRef, useState } from 'react'\nimport type { PagefindSearchOptions } from '../../types.js'\nimport { useMounted } from '../hooks/use-mounted.js'\nimport { InformationCircleIcon, SpinnerIcon } from '../icons/index.js'\n\n// Fix React Compiler (BuildHIR::lowerExpression) Handle Import expressions\nexport async function importPagefind() {\n  window.pagefind = await import(\n    /* webpackIgnore: true */ addBasePath('/_pagefind/pagefind.js')\n  )\n  await window.pagefind!.options({\n    baseUrl: addBasePath('/')\n    // ... more search options\n  })\n}\n\ntype PagefindResult = {\n  excerpt: string\n  meta: {\n    title: string\n  }\n  raw_url: string\n  sub_results: {\n    excerpt: string\n    title: string\n    url: string\n  }[]\n  url: string\n}\n\ntype InputProps = Omit<\n  ComboboxInputProps,\n  'className' | 'onChange' | 'onFocus' | 'onBlur' | 'value' | 'placeholder'\n>\n\ninterface SearchProps extends InputProps {\n  /**\n   * Not found text.\n   * @default 'No results found.'\n   */\n  emptyResult?: ReactNode\n  /**\n   * Error text.\n   * @default 'Failed to load search index.'\n   * */\n  errorText?: ReactNode\n  /**\n   * Loading text.\n   * @default 'Loading…'\n   */\n  loading?: ReactNode\n  /**\n   * Placeholder text.\n   * @default 'Search documentation…'\n   */\n  placeholder?: string\n  /** Input container CSS class name. */\n  className?: string\n  searchOptions?: PagefindSearchOptions\n  /**\n   * Callback function that triggers whenever the search input changes.\n   *\n   * This prop is **not serializable** and cannot be used directly in a server-side layout.\n   *\n   * To use this prop, wrap the component in a **client-side** wrapper. Example:\n   *\n   * ```tsx filename=\"search-with-callback.jsx\"\n   * 'use client'\n   *\n   * import { Search } from 'nextra/components'\n   *\n   * export function SearchWithCallback() {\n   *   return (\n   *     <Search\n   *       onSearch={query => {\n   *         console.log('Search query:', query)\n   *       }}\n   *     />\n   *   )\n   * }\n   * ```\n   *\n   * Then pass the wrapper to the layout:\n   *\n   * ```tsx filename=\"app/layout.jsx\"\n   * import { SearchWithCallback } from '../path/to/your/search-with-callback'\n   * // ...\n   * <Layout search={<SearchWithCallback />} {...rest} />\n   * ```\n   *\n   * @param query - The current search input string.\n   */\n  onSearch?: (query: string) => void\n}\n\nconst INPUTS = new Set(['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA'])\n\nconst DEV_SEARCH_NOTICE = (\n  <>\n    <p>\n      Search isn&apos;t available in development because Nextra&nbsp;4 uses\n      Pagefind package, which indexes built `.html` files instead of\n      `.md`/`.mdx`.\n    </p>\n    <p className=\"x:mt-2\">\n      To test search during development, run `next build` and then restart your\n      app with `next dev`.\n    </p>\n  </>\n)\n\n/**\n * A built-in search component provides a seamless and fast search\n * experience out of the box. Under the hood, it leverages the\n * [Pagefind package](https://pagefind.app) — a fully client-side search engine optimized for static\n * sites. Pagefind indexes your content at build time and enables highly performant,\n * zero-JavaScript-dependency searches at runtime.\n *\n * @see [Nextra search setup guide](https://nextra.site/docs/guide/search)\n */\nexport const Search: FC<SearchProps> = ({\n  className,\n  emptyResult = 'No results found.',\n  errorText = 'Failed to load search index.',\n  loading = 'Loading…',\n  placeholder = 'Search documentation…',\n  searchOptions,\n  onSearch,\n  ...props\n}) => {\n  const [isLoading, setIsLoading] = useState(true)\n  const [error, setError] = useState<ReactElement | string>('')\n  const [results, setResults] = useState<PagefindResult[]>([])\n  const [search, setSearch] = useState('')\n  // https://github.com/shuding/nextra/pull/3514\n  // defer pagefind results update for prioritizing user input state\n  const deferredSearch = useDeferredValue(search)\n\n  useEffect(() => {\n    const handleSearch = async (value: string) => {\n      if (!value) {\n        setResults([])\n        setError('')\n        return\n      }\n      setIsLoading(true)\n      if (!window.pagefind) {\n        try {\n          await importPagefind()\n        } catch (error) {\n          const message =\n            error instanceof Error\n              ? process.env.NODE_ENV !== 'production' &&\n                error.message.includes('Failed to fetch')\n                ? DEV_SEARCH_NOTICE // This error will be tree-shaked in production\n                : `${error.constructor.name}: ${error.message}`\n              : String(error)\n          setError(message)\n          setIsLoading(false)\n          return\n        }\n      }\n      const response = await window.pagefind!.debouncedSearch<PagefindResult>(\n        value,\n        searchOptions\n      )\n      if (!response) return\n\n      const data = await Promise.all(response.results.map(o => o.data()))\n      setIsLoading(false)\n      setError('')\n      setResults(\n        data.map(newData => ({\n          ...newData,\n          sub_results: newData.sub_results.map(r => {\n            const url = r.url.replace(/\\.html$/, '').replace(/\\.html#/, '#')\n\n            return { ...r, url }\n          })\n        }))\n      )\n    }\n    handleSearch(deferredSearch)\n  }, [deferredSearch]) // eslint-disable-line react-hooks/exhaustive-deps -- ignore searchOptions\n\n  const router = useRouter()\n  const [focused, setFocused] = useState(false)\n  const mounted = useMounted()\n  const inputRef = useRef<HTMLInputElement>(null!)\n\n  useEffect(() => {\n    function handleKeyDown(event: KeyboardEvent) {\n      const el = document.activeElement\n      if (\n        !el ||\n        INPUTS.has(el.tagName) ||\n        (el as HTMLElement).isContentEditable\n      ) {\n        return\n      }\n      if (\n        event.key === '/' ||\n        (event.key === 'k' &&\n          !event.shiftKey &&\n          (navigator.userAgent.includes('Mac') ? event.metaKey : event.ctrlKey))\n      ) {\n        event.preventDefault()\n        // prevent to scroll to top\n        inputRef.current.focus({ preventScroll: true })\n      }\n    }\n\n    window.addEventListener('keydown', handleKeyDown)\n    return () => {\n      window.removeEventListener('keydown', handleKeyDown)\n    }\n  }, [])\n\n  const shortcut = (\n    <kbd\n      className={cn(\n        'x:absolute x:my-1.5 x:select-none x:pointer-events-none x:end-1.5 x:transition-all',\n        'x:h-5 x:rounded x:bg-nextra-bg x:px-1.5 x:font-mono x:text-[11px] x:font-medium x:text-gray-600 x:dark:text-gray-400',\n        'x:border nextra-border',\n        'x:contrast-more:text-current',\n        'x:items-center x:gap-1 x:flex',\n        'x:max-sm:hidden not-prose',\n        (!mounted || focused) && 'x:invisible x:opacity-0'\n      )}\n    >\n      {mounted && navigator.userAgent.includes('Mac') ? (\n        <>\n          <span className=\"x:text-xs\">⌘</span>K\n        </>\n      ) : (\n        'CTRL K'\n      )}\n    </kbd>\n  )\n\n  const handleFocus: FocusEventHandler = event => {\n    const isFocus = event.type === 'focus'\n    setFocused(isFocus)\n  }\n\n  const handleChange = (event: SyntheticEvent<HTMLInputElement>) => {\n    const { value } = event.currentTarget\n    setSearch(value)\n    onSearch?.(value)\n  }\n\n  const handleSelect = (searchResult: PagefindResult | null) => {\n    if (!searchResult) return\n    // Calling before navigation so selector `html:not(:has(*:focus))` in styles.css will work,\n    // and we'll have padding top since input is not focused\n    inputRef.current.blur()\n    const [url, hash] = searchResult.url.split('#')\n    const isSamePathname = location.pathname === url\n    // `useHash` hook doesn't work with NextLink, and clicking on search\n    // result from same page doesn't scroll to the heading\n    if (isSamePathname) {\n      location.href = `#${hash}`\n    } else {\n      router.push(searchResult.url)\n    }\n    setSearch('')\n  }\n\n  return (\n    <Combobox onChange={handleSelect}>\n      <div\n        className={cn(\n          'nextra-search',\n          'x:relative x:flex x:items-center',\n          'x:text-gray-900 x:dark:text-gray-300',\n          'x:contrast-more:text-gray-800 x:contrast-more:dark:text-gray-300',\n          className\n        )}\n      >\n        <ComboboxInput\n          spellCheck={false}\n          autoComplete=\"off\"\n          type=\"search\"\n          {...props}\n          ref={inputRef}\n          className={({ focus }) =>\n            cn(\n              'x:rounded-lg x:px-3 x:py-2 x:transition-all',\n              'x:w-full x:md:w-64',\n              'x:text-base x:leading-tight x:md:text-sm',\n              focus\n                ? 'x:bg-transparent x:nextra-focus'\n                : 'x:bg-black/[.05] x:dark:bg-gray-50/10',\n              'x:placeholder:text-gray-600 x:dark:placeholder:text-gray-400',\n              'x:contrast-more:border x:contrast-more:border-current',\n              'x:[&::-webkit-search-cancel-button]:appearance-none'\n            )\n          }\n          onChange={handleChange}\n          onFocus={handleFocus}\n          onBlur={handleFocus}\n          value={search}\n          placeholder={placeholder}\n        />\n        {shortcut}\n      </div>\n      <ComboboxOptions\n        transition\n        anchor={{ to: 'top end', gap: 10, padding: 16 }}\n        className={cn(\n          'nextra-search-results', // for user styling\n          'nextra-scrollbar x:max-md:h-full',\n          'x:border x:border-gray-200 x:text-gray-100 x:dark:border-neutral-800',\n          'x:z-30 x:rounded-xl x:py-2.5 x:shadow-xl',\n          'x:contrast-more:border x:contrast-more:border-gray-900 x:contrast-more:dark:border-gray-50',\n          'x:backdrop-blur-md x:bg-nextra-bg/70',\n          'x:motion-reduce:transition-none',\n          // From https://headlessui.com/react/combobox#adding-transitions\n          'x:origin-top x:transition x:duration-200 x:ease-out x:data-closed:scale-95 x:data-closed:opacity-0 x:empty:invisible',\n          error || isLoading || !results.length\n            ? [\n                'x:md:min-h-28 x:grow x:flex x:justify-center x:text-sm x:gap-2 x:px-8',\n                error\n                  ? 'x:text-red-500 x:items-start'\n                  : 'x:text-gray-400 x:items-center'\n              ]\n            : // headlessui adds max-height as style, use !important to override\n              'x:md:max-h-[min(calc(100vh-5rem),400px)]!',\n          'x:w-full x:md:w-[576px]'\n        )}\n      >\n        {error ? (\n          <>\n            <InformationCircleIcon height=\"1.25em\" className=\"x:shrink-0\" />\n            <div className=\"x:grid\">\n              <b className=\"x:mb-2\">{errorText}</b>\n              {error}\n            </div>\n          </>\n        ) : isLoading ? (\n          <>\n            <SpinnerIcon height=\"20\" className=\"x:shrink-0 x:animate-spin\" />\n            {loading}\n          </>\n        ) : results.length ? (\n          results.map(searchResult => (\n            <Result key={searchResult.url} data={searchResult} />\n          ))\n        ) : (\n          deferredSearch && emptyResult\n        )}\n      </ComboboxOptions>\n    </Combobox>\n  )\n}\n\nconst Result: FC<{ data: PagefindResult }> = ({ data }) => {\n  return (\n    <>\n      <div\n        className={cn(\n          'x:mx-2.5 x:mb-2 x:not-first:mt-6 x:select-none x:border-b x:border-black/10 x:px-2.5 x:pb-1.5 x:text-xs x:font-semibold x:uppercase x:text-gray-600 x:dark:border-white/20 x:dark:text-gray-300',\n          'x:contrast-more:border-gray-600 x:contrast-more:text-gray-900 x:contrast-more:dark:border-gray-50 x:contrast-more:dark:text-gray-50'\n        )}\n      >\n        {data.meta.title}\n      </div>\n      {data.sub_results.map(subResult => (\n        <ComboboxOption\n          key={subResult.url}\n          as={NextLink}\n          value={subResult}\n          href={subResult.url}\n          className={({ focus }) =>\n            cn(\n              'x:mx-2.5 x:break-words x:rounded-md',\n              'x:contrast-more:border',\n              focus\n                ? 'x:text-primary-600 x:contrast-more:border-current x:bg-primary-500/10'\n                : 'x:text-gray-800 x:dark:text-gray-300 x:contrast-more:border-transparent',\n              'x:block x:scroll-m-12 x:px-2.5 x:py-2'\n            )\n          }\n        >\n          <div className=\"x:text-base x:font-semibold x:leading-5\">\n            {subResult.title}\n          </div>\n          <div\n            className={cn(\n              'x:mt-1 x:text-sm x:leading-[1.35rem] x:text-gray-600 x:dark:text-gray-400 x:contrast-more:dark:text-gray-50',\n              'x:[&_mark]:bg-primary-600/80 x:[&_mark]:text-white'\n            )}\n            dangerouslySetInnerHTML={{ __html: subResult.excerpt }}\n          />\n        </ComboboxOption>\n      ))}\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/select.tsx",
    "content": "'use client'\n\nimport {\n  Listbox,\n  ListboxButton,\n  ListboxOption,\n  ListboxOptions\n} from '@headlessui/react'\nimport type { AnchorPropsWithSelection } from '@headlessui/react/dist/internal/floating'\nimport cn from 'clsx'\nimport type { Dispatch, FC, ReactNode } from 'react'\nimport { Fragment } from 'react'\nimport { CheckIcon } from '../icons/index.js'\n\ninterface MenuOption {\n  id: string\n  name: ReactNode\n}\n\ninterface MenuProps {\n  selectedOption: ReactNode\n  value: string\n  onChange: Dispatch<string>\n  options: MenuOption[]\n  title?: string\n  className?: string\n  anchor?: AnchorPropsWithSelection\n}\n\nexport const Select: FC<MenuProps> = ({\n  options,\n  onChange,\n  selectedOption,\n  value,\n  title,\n  className,\n  anchor = { to: 'top start', gap: 10 }\n}) => {\n  return (\n    <Listbox value={value} onChange={onChange}>\n      <ListboxButton\n        title={title}\n        className={({ hover, open, focus }) =>\n          cn(\n            'x:cursor-pointer',\n            'x:h-7 x:rounded-md x:px-2 x:text-xs x:font-medium x:transition-colors',\n            open\n              ? 'x:bg-gray-200 x:text-gray-900 x:dark:bg-primary-100/10 x:dark:text-gray-50'\n              : hover\n                ? 'x:bg-gray-200 x:text-gray-900 x:dark:bg-primary-100/5 x:dark:text-gray-50'\n                : 'x:text-gray-600 x:dark:text-gray-400',\n            focus && 'x:nextra-focus',\n            className\n          )\n        }\n      >\n        {selectedOption}\n      </ListboxButton>\n      <ListboxOptions\n        as=\"ul\"\n        transition\n        anchor={anchor}\n        className={({ open }) =>\n          cn(\n            'x:focus-visible:nextra-focus',\n            open ? 'x:opacity-100' : 'x:opacity-0',\n            'x:motion-reduce:transition-none x:transition-opacity x:min-w-(--button-width) x:z-30 x:max-h-64 x:rounded-md x:border x:border-black/5 x:backdrop-blur-md x:bg-nextra-bg/70 x:py-1 x:text-sm x:shadow-lg x:dark:border-white/20'\n          )\n        }\n      >\n        {options.map(option => (\n          <ListboxOption key={option.id} value={option.id} as={Fragment}>\n            {({ selected, focus }) => (\n              <li\n                className={cn(\n                  focus\n                    ? 'x:bg-primary-100 x:text-primary-800 x:dark:text-primary-500 x:dark:bg-primary-500/10'\n                    : 'x:text-gray-800 x:dark:text-gray-100',\n                  'x:cursor-pointer x:whitespace-nowrap x:py-1.5 x:px-3',\n                  'x:transition-colors',\n                  selected && 'x:flex x:items-center x:justify-between x:gap-3'\n                )}\n              >\n                {option.name}\n                {selected && <CheckIcon height=\"1em\" />}\n              </li>\n            )}\n          </ListboxOption>\n        ))}\n      </ListboxOptions>\n    </Listbox>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/skip-nav/index.client.tsx",
    "content": "'use client'\n\n/**\n * The code included in this file is inspired by https://github.com/reach/reach-ui/blob/43f450db7bcb25a743121fe31355f2294065a049/packages/skip-nav/src/reach-skip-nav.tsx which is part of the @reach/skip-nav library.\n *\n * @reach/skip-nav is licensed as follows:\n * The MIT License (MIT)\n *\n * Copyright (c) 2018-2023, React Training LLC\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of\n * this software and associated documentation files (the \"Software\"), to deal in\n * the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\n * the Software, and to permit persons to whom the Software is furnished to do so,\n * subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\n * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * Source: https://github.com/reach/reach-ui/blob/43f450db7bcb25a743121fe31355f2294065a049/LICENSE\n */\nimport { Button } from '@headlessui/react'\nimport type { ButtonProps } from '@headlessui/react'\nimport cn from 'clsx'\nimport type { FC } from 'react'\n\nconst DEFAULT_ID = 'nextra-skip-nav'\nconst DEFAULT_LABEL = 'Skip to Content'\n\nexport const SkipNavLink: FC = ({\n  // Give the option to the user to pass a falsy other than undefined to remove the default styles\n  className,\n  id = DEFAULT_ID,\n  children = DEFAULT_LABEL\n}: Pick<ButtonProps, 'className' | 'id' | 'children'>) => {\n  return (\n    <Button\n      as=\"a\"\n      href={`#${id}`}\n      className={({ focus }) =>\n        cn(\n          'nextra-skip-nav',\n          focus\n            ? 'x:nextra-focus x:fixed x:z-50 x:my-3 x:mx-4 x:rounded-lg x:px-3 x:py-2 x:text-sm x:font-bold x:bg-nextra-bg x:border x:border-current'\n            : 'x:sr-only',\n          className\n        )\n      }\n    >\n      {children}\n    </Button>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/skip-nav/index.tsx",
    "content": "import type { FC, HTMLAttributes } from 'react'\n\nconst DEFAULT_ID = 'nextra-skip-nav'\n\nexport { SkipNavLink } from './index.client.js'\n\nexport const SkipNavContent: FC<Pick<HTMLAttributes<HTMLDivElement>, 'id'>> = ({\n  id = DEFAULT_ID\n}) => {\n  return <div id={id} />\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/steps.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes } from 'react'\nimport { useId } from 'react'\n\n/**\n * A built-in component to turn a numbered list into a visual representation of\n * steps.\n *\n * @example\n * <Steps>\n *\n * ### This is the first step\n *\n * This is the first step description.\n *\n * ### This is the second step\n *\n * This is the second step description.\n *\n * ### This is the third step\n *\n * This is the third step description.\n *\n * </Steps>\n *\n * @usage\n * Wrap a set of Markdown headings (from `<h2>` to `<h6>`) with the `<Steps>`\n * component to display them as visual steps. You can choose the appropriate\n * heading level based on the content hierarchy on the page.\n *\n * ```mdx filename=\"MDX\" {7-15}\n * import { Steps } from 'nextra/components'\n *\n * ## Getting Started\n *\n * Here is some description.\n *\n * <Steps>\n * ### Step 1\n *\n * Contents for step 1.\n *\n * ### Step 2\n *\n * Contents for step 2.\n * </Steps>\n * ```\n *\n * ### Excluding Headings from Table of Contents\n *\n * To exclude the headings from the `<Steps>` component (or any other headings)\n * to appear in the Table of Contents, replace the Markdown headings `### ...`\n * with `<h3>` HTML element wrapped in curly braces.\n *\n * ```diff filename=\"MDX\"\n * <Steps>\n * - ### Step 1\n * + {<h3>Step 1</h3>}\n *\n * Contents for step 1.\n * </Steps>\n * ```\n */\nexport const Steps: FC<HTMLAttributes<HTMLDivElement>> = ({\n  children,\n  className,\n  style,\n  ...props\n}) => {\n  const id = useId().replaceAll(':', '')\n  return (\n    <div\n      className={cn(\n        'nextra-steps x:ms-4 x:mb-12 x:border-s x:border-gray-200 x:ps-6',\n        'x:dark:border-neutral-800',\n        className\n      )}\n      style={{\n        ...style,\n        // @ts-expect-error -- fixme\n        '--counter-id': id\n      }}\n      {...props}\n    >\n      {children}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/tabs/index.client.tsx",
    "content": "'use client'\n\nimport {\n  Tab as HeadlessTab,\n  TabGroup,\n  TabList,\n  TabPanel,\n  TabPanels\n} from '@headlessui/react'\nimport type {\n  TabProps as HeadlessTabProps,\n  TabGroupProps,\n  TabListProps,\n  TabPanelProps\n} from '@headlessui/react'\nimport cn from 'clsx'\nimport type { FC, ReactElement, ReactNode } from 'react'\nimport { Fragment, useEffect, useRef, useState } from 'react'\nimport { useHash } from '../../hooks/use-hash.js'\n\ntype TabItem = string | ReactElement\n\ntype TabObjectItem = {\n  label: TabItem\n  disabled: boolean\n}\n\nfunction isTabObjectItem(item: unknown): item is TabObjectItem {\n  return !!item && typeof item === 'object' && 'label' in item\n}\n\nexport const Tabs: FC<\n  {\n    items: (TabItem | TabObjectItem)[]\n    children: ReactNode\n    /** LocalStorage key for persisting the selected tab. */\n    storageKey?: string\n    /** Tabs CSS class name. */\n    className?: TabListProps['className']\n    /** Tab CSS class name. */\n    tabClassName?: HeadlessTabProps['className']\n  } & Pick<TabGroupProps, 'defaultIndex' | 'selectedIndex' | 'onChange'>\n> = ({\n  items,\n  children,\n  storageKey,\n  defaultIndex = 0,\n  selectedIndex: _selectedIndex,\n  onChange,\n  className,\n  tabClassName\n}) => {\n  const [selectedIndex, setSelectedIndex] = useState(defaultIndex)\n  const hash = useHash()\n  const tabPanelsRef = useRef<HTMLDivElement>(null!)\n\n  useEffect(() => {\n    if (_selectedIndex !== undefined) {\n      setSelectedIndex(_selectedIndex)\n    }\n  }, [_selectedIndex])\n\n  useEffect(() => {\n    if (!hash) return\n    const tabPanel = tabPanelsRef.current.querySelector(\n      `[role=tabpanel]:has([id=\"${hash}\"])`\n    )\n    if (!tabPanel) return\n\n    for (const [index, el] of Object.entries(tabPanelsRef.current.children)) {\n      if (el === tabPanel) {\n        setSelectedIndex(Number(index))\n        // Clear hash first, otherwise page isn't scrolled\n        location.hash = ''\n        // Execute on next tick after `selectedIndex` update\n        requestAnimationFrame(() => {\n          location.hash = `#${hash}`\n        })\n      }\n    }\n  }, [hash])\n\n  useEffect(() => {\n    if (!storageKey) {\n      // Do not listen storage events if there is no storage key\n      return\n    }\n\n    function fn(event: StorageEvent) {\n      if (event.key === storageKey) {\n        setSelectedIndex(Number(event.newValue))\n      }\n    }\n\n    const index = Number(localStorage.getItem(storageKey))\n    setSelectedIndex(Number.isNaN(index) ? 0 : index)\n\n    window.addEventListener('storage', fn)\n    return () => {\n      window.removeEventListener('storage', fn)\n    }\n  }, []) // eslint-disable-line react-hooks/exhaustive-deps -- only on mount\n\n  const handleChange = (index: number) => {\n    if (storageKey) {\n      const newValue = String(index)\n      localStorage.setItem(storageKey, newValue)\n\n      // the storage event only get picked up (by the listener) if the localStorage was changed in\n      // another browser's tab/window (of the same app), but not within the context of the current tab.\n      window.dispatchEvent(\n        new StorageEvent('storage', { key: storageKey, newValue })\n      )\n      return\n    }\n    setSelectedIndex(index)\n    onChange?.(index)\n  }\n\n  return (\n    <TabGroup\n      selectedIndex={selectedIndex}\n      defaultIndex={defaultIndex}\n      onChange={handleChange}\n      as={Fragment}\n    >\n      <TabList\n        className={args =>\n          cn(\n            'nextra-scrollbar x:overflow-x-auto x:overscroll-x-contain x:overflow-y-hidden',\n            'x:mt-4 x:flex x:w-full x:gap-2 x:border-b x:border-gray-200 x:pb-px x:dark:border-neutral-800',\n            'x:focus-visible:nextra-focus',\n            typeof className === 'function' ? className(args) : className\n          )\n        }\n      >\n        {items.map((item, index) => (\n          <HeadlessTab\n            key={index}\n            disabled={isTabObjectItem(item) && item.disabled}\n            className={args => {\n              const { selected, disabled, hover, focus } = args\n              return cn(\n                focus && 'x:nextra-focus x:ring-inset',\n                'x:whitespace-nowrap x:cursor-pointer',\n                'x:rounded-t x:p-2 x:font-medium x:leading-5 x:transition-colors',\n                'x:-mb-0.5 x:select-none x:border-b-2',\n                selected\n                  ? 'x:border-current x:outline-none'\n                  : hover\n                    ? 'x:border-gray-200 x:dark:border-neutral-800'\n                    : 'x:border-transparent',\n                selected\n                  ? 'x:text-primary-600'\n                  : disabled\n                    ? 'x:text-gray-400 x:dark:text-neutral-600 x:pointer-events-none'\n                    : hover\n                      ? 'x:text-black x:dark:text-white'\n                      : 'x:text-gray-600 x:dark:text-gray-200',\n                typeof tabClassName === 'function'\n                  ? tabClassName(args)\n                  : tabClassName\n              )\n            }}\n          >\n            {isTabObjectItem(item) ? item.label : item}\n          </HeadlessTab>\n        ))}\n      </TabList>\n      <TabPanels ref={tabPanelsRef}>{children}</TabPanels>\n    </TabGroup>\n  )\n}\n\nexport const Tab: FC<TabPanelProps> = ({\n  children,\n  // For SEO display all the Panel in the DOM and set `display: none;` for those that are not selected\n  unmount = false,\n  className,\n  ...props\n}) => {\n  return (\n    <TabPanel\n      {...props}\n      unmount={unmount}\n      className={args =>\n        cn(\n          'x:rounded x:mt-[1.25em]',\n          args.focus && 'x:nextra-focus',\n          typeof className === 'function' ? className(args) : className\n        )\n      }\n    >\n      {children}\n    </TabPanel>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/components/tabs/index.tsx",
    "content": "'use no memo'\n\nimport type { ComponentProps } from 'react'\nimport { Tabs as _Tabs, Tab } from './index.client.js'\n\n// Workaround to fix\n// Error: Cannot access Tab.propTypes on the server. You cannot dot into a client module from a\n// server component. You can only pass the imported name through.\n/**\n * A built-in component for creating tabbed content, helping organize related information in a\n * compact, interactive layout.\n *\n * @example\n * <Tabs items={['pnpm', 'npm', 'yarn']}>\n *   <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n *   <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n *   <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n * </Tabs>\n *\n * @usage\n * ```mdx\n * import { Tabs } from 'nextra/components'\n *\n * <Tabs items={['pnpm', 'npm', 'yarn']}>\n *   <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n *   <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n *   <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n * </Tabs>\n * ```\n *\n * ### Default Selected Index\n *\n * You can use the `defaultIndex` prop to set the default tab index:\n *\n * ```mdx /defaultIndex=\"1\"/\n * import { Tabs } from 'nextra/components'\n *\n * <Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\"1\">\n *   ...\n * </Tabs>\n * ```\n *\n * And you will have `npm` as the default tab:\n *\n * <Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\"1\">\n *   <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n *   <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n *   <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n * </Tabs>\n */\nexport const Tabs = Object.assign(\n  (props: ComponentProps<typeof _Tabs>) => <_Tabs {...props} />,\n  { Tab }\n)\n"
  },
  {
    "path": "packages/nextra/src/client/evaluate.ts",
    "content": "'use no memo'\n\nimport jsxDevRuntime from 'react/jsx-dev-runtime'\nimport jsxRuntime from 'react/jsx-runtime'\nimport type { EvaluateResult } from '../types.js'\nimport type { MDXComponents } from './mdx-components.js'\n\nconst runtime =\n  process.env.NODE_ENV === 'production' ? jsxRuntime : jsxDevRuntime\n\nexport type Scope = Record<string, unknown>\n\nexport function evaluate(\n  rawJs: string,\n  /** @default {} */\n  components: MDXComponents = {},\n  /** @default {} */\n  scope: Scope = {}\n): EvaluateResult {\n  // If we're ready to render, we can assemble the component tree and let React do its thing\n  // first we set up the scope which has to include the mdx custom\n  // create element function as well as any components we're using\n  const keys = Object.keys(scope)\n  const values = Object.values(scope)\n  // Now we eval the source code using a function constructor\n  // in order for this to work, we need to have React, the mdx `createElement`,\n  // and all our components in scope for the function, which is the case here\n  // we pass the names (via keys) in as the function's args, and execute the\n  // function with the actual values.\n  const hydrateFn = Reflect.construct(Function, ['$', ...keys, rawJs])\n\n  return hydrateFn(\n    {\n      ...runtime,\n      // Inject components in `<MDXContent>` and TOC\n      useMDXComponents: () => components\n    },\n    ...values\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/hocs/index.ts",
    "content": "export { withIcons } from './with-icons.js'\nexport { withGitHubAlert } from './with-github-alert.js'\n"
  },
  {
    "path": "packages/nextra/src/client/hocs/with-github-alert.tsx",
    "content": "// should be used on server\n'use no memo'\n\nimport type { ComponentProps, FC, ReactNode } from 'react'\n\ntype BlockquoteType = FC<ComponentProps<'blockquote'>>\ntype T = (typeof GITHUB_ALERTS)[number]\n\nconst GITHUB_ALERT_RE = /^\\s*\\[!(?<name>.*?)]\\s*$/\n\nconst GITHUB_ALERTS = [\n  'note',\n  'tip',\n  'important',\n  'warning',\n  'caution'\n] as const\n\nconst GITHUB_ALERT_TYPES = new Set<string>(GITHUB_ALERTS)\n\nexport function withGitHubAlert(\n  fn: FC<{ type: T; children: ReactNode }>,\n  Component: BlockquoteType | 'blockquote' = 'blockquote'\n): BlockquoteType {\n  return function Blockquote(props) {\n    if (Array.isArray(props.children)) {\n      const str = props.children[1].props.children\n      if (typeof str === 'string') {\n        const alertName = str\n          .match(GITHUB_ALERT_RE)\n          ?.groups?.name!.toLowerCase()\n\n        if (alertName) {\n          if (!GITHUB_ALERT_TYPES.has(alertName)) {\n            throw new Error(\n              `Invalid GitHub alert type: \"${alertName}\". Should be one of: ${GITHUB_ALERTS.join(', ')}.`\n            )\n          }\n          const capitalizedName =\n            alertName[0]!.toUpperCase() + alertName.slice(1)\n          return fn({\n            ...props,\n            type: alertName as T,\n            children: [\n              <b key={0}>{capitalizedName}</b>,\n              ...props.children.slice(2)\n            ]\n          })\n        }\n      }\n    }\n\n    return <Component {...props} />\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/client/hocs/with-icons.tsx",
    "content": "// should be used on server\n'use no memo'\n\nimport path from 'node:path'\nimport type { FC, SVGProps } from 'react'\nimport {\n  CPPIcon,\n  CsharpIcon,\n  CssIcon,\n  GoIcon,\n  GraphQLIcon,\n  JavaScriptIcon,\n  JSONIcon,\n  MarkdownIcon,\n  MdxIcon,\n  MoveIcon,\n  PythonIcon,\n  ReactIcon,\n  RustIcon,\n  SvelteIcon,\n  TerminalIcon,\n  TerraformIcon,\n  TypeScriptIcon\n} from '../icons/index.js'\nimport type { PreProps } from '../mdx-components/pre/index.js'\n\nfunction getIcon(language: string) {\n  switch (language) {\n    case 'javascript':\n    case 'js':\n    case 'mjs':\n    case 'cjs':\n      return JavaScriptIcon\n    case 'typescript':\n    case 'ts':\n    case 'mts':\n    case 'cts':\n      return TypeScriptIcon\n    case 'jsx':\n    case 'tsx':\n      return ReactIcon\n    case 'md':\n      return MarkdownIcon\n    case 'mdx':\n      return MdxIcon\n    case 'sh':\n    case 'bash':\n      return TerminalIcon\n    case 'css':\n      return CssIcon\n    case 'c++':\n    case 'cpp':\n      return CPPIcon\n    case 'csharp':\n    case 'cs':\n    case 'c#':\n      return CsharpIcon\n    case 'graphql':\n    case 'gql':\n      return GraphQLIcon\n    case 'python':\n    case 'py':\n      return PythonIcon\n    case 'rust':\n    case 'rs':\n      return RustIcon\n    case 'terraform':\n    case 'tf':\n      return TerraformIcon\n    case 'move':\n      return MoveIcon\n    case 'go':\n    case 'golang':\n      return GoIcon\n    case 'json':\n    case 'jsonc':\n      return JSONIcon\n    case 'svelte':\n      return SvelteIcon\n  }\n}\n\nexport function withIcons(\n  Component: FC,\n  obj?: Record<string, FC<SVGProps<SVGElement>>>\n): FC<PreProps> {\n  return function Pre(props) {\n    let language = props['data-language']\n    const filename = props['data-filename']\n    if (language === 'diff' && filename) {\n      const ext = path.parse(filename).ext.slice(1)\n      if (ext) {\n        language = ext\n      }\n    }\n    const Icon = language && (obj?.[language] || getIcon(language))\n\n    return (\n      <Component\n        icon={Icon && <Icon height=\"1em\" className=\"x:max-w-6 x:shrink-0\" />}\n        {...props}\n      />\n    )\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/client/hooks/index.ts",
    "content": "export { useMounted } from './use-mounted.js'\nexport { useCopy } from './use-copy.js'\nexport { useFSRoute } from './use-fs-route.js'\nexport { useHash } from './use-hash.js'\n"
  },
  {
    "path": "packages/nextra/src/client/hooks/use-copy.ts",
    "content": "'use client'\n\nimport { useEffect, useState } from 'react'\n\nexport function useCopy({\n  timeout = 2000\n}: {\n  /** @default 2000 */\n  timeout?: number\n} = {}) {\n  const [isCopied, setCopied] = useState(false)\n\n  useEffect(() => {\n    if (!isCopied) return\n    const timerId = setTimeout(() => {\n      setCopied(false)\n    }, timeout)\n\n    return () => {\n      clearTimeout(timerId)\n    }\n  }, [isCopied]) // eslint-disable-line react-hooks/exhaustive-deps -- ignore timeout\n\n  async function copy(content: string) {\n    setCopied(true)\n    try {\n      await navigator.clipboard.writeText(content)\n    } catch {\n      console.error('Failed to copy!')\n    }\n  }\n\n  return {\n    copy,\n    isCopied\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/client/hooks/use-fs-route.ts",
    "content": "'use client'\n\nimport { usePathname } from 'next/navigation'\n\nconst defaultLocale = process.env.NEXTRA_DEFAULT_LOCALE\n\nexport function useFSRoute() {\n  const pathname = usePathname()\n  return (\n    (process.env.NEXTRA_SHOULD_ADD_LOCALE_TO_LINKS !== 'true' && defaultLocale\n      ? '/' + pathname.split('/').slice(2).join('/')\n      : pathname\n    )\n      .replace(/\\.html$/, '')\n      .replace(/\\/index(\\/|$)/, '$1')\n      .replace(/\\/$/, '') || '/'\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/hooks/use-hash.ts",
    "content": "'use client'\n\n// don't need to memoize string `hash` value\n'use no memo'\n\nimport { useEffect, useState } from 'react'\n\nexport function useHash() {\n  const [hash, setHash] = useState('')\n\n  useEffect(() => {\n    function handleHashChange() {\n      setHash(location.hash.replace('#', ''))\n    }\n    handleHashChange()\n\n    window.addEventListener('hashchange', handleHashChange)\n    return () => {\n      window.removeEventListener('hashchange', handleHashChange)\n    }\n  }, [])\n\n  return hash\n}\n"
  },
  {
    "path": "packages/nextra/src/client/hooks/use-mounted.ts",
    "content": "'use client'\n\n// don't need to memoize boolean `mounted` value\n'use no memo'\n\nimport { useEffect, useState } from 'react'\n\nexport function useMounted(): boolean {\n  const [mounted, setMounted] = useState(false)\n\n  useEffect(() => {\n    setMounted(true)\n  }, [])\n\n  return mounted\n}\n"
  },
  {
    "path": "packages/nextra/src/client/icons/index.ts",
    "content": "export { ReactComponent as ArrowRightIcon } from './arrow-right.svg'\nexport { ReactComponent as ChatGPTIcon } from './chatgpt.svg'\nexport { ReactComponent as CheckIcon } from './check.svg'\nexport { ReactComponent as ClaudeIcon } from './claude.svg'\nexport { ReactComponent as CopyIcon } from './copy.svg'\nexport { ReactComponent as DiscordIcon } from './discord.svg'\nexport { ReactComponent as ExpandIcon } from './expand.svg'\nexport { ReactComponent as GitHubIcon } from './github.svg'\nexport { ReactComponent as GlobeIcon } from './globe.svg'\nexport { ReactComponent as GoIcon } from './go.svg'\nexport { ReactComponent as MenuIcon } from './menu.svg'\nexport { ReactComponent as MoonIcon } from './moon.svg'\nexport { ReactComponent as SpinnerIcon } from './spinner.svg'\nexport { ReactComponent as SunIcon } from './sun.svg'\nexport { ReactComponent as SvelteIcon } from './svelte.svg'\nexport { ReactComponent as WordWrapIcon } from './word-wrap.svg'\nexport { ReactComponent as XIcon } from './x.svg'\nexport { ReactComponent as JavaScriptIcon } from './javascript.svg'\nexport { ReactComponent as LinkArrowIcon } from './link-arrow.svg'\nexport { ReactComponent as TypeScriptIcon } from './typescript.svg'\nexport { ReactComponent as MarkdownIcon } from './markdown.svg'\nexport { ReactComponent as MdxIcon } from './mdx.svg'\nexport { ReactComponent as TerminalIcon } from './terminal.svg'\nexport { ReactComponent as CssIcon } from './css.svg'\nexport { ReactComponent as CPPIcon } from './cpp.svg'\nexport { ReactComponent as CsharpIcon } from './csharp.svg'\nexport { ReactComponent as GraphQLIcon } from './graphql.svg'\nexport { ReactComponent as PythonIcon } from './python.svg'\nexport { ReactComponent as ReactIcon } from './react.svg'\nexport { ReactComponent as JSONIcon } from './json.svg'\nexport { ReactComponent as RustIcon } from './rust.svg'\nexport { ReactComponent as TerraformIcon } from './terraform.svg'\nexport { ReactComponent as MoveIcon } from './move.svg'\nexport { ReactComponent as CrossCircledIcon } from './cross-circled.svg'\nexport { ReactComponent as FileIcon } from './file.svg'\nexport { ReactComponent as FolderIcon } from './folder.svg'\nexport { ReactComponent as FolderOpenIcon } from './folder-open.svg'\nexport { ReactComponent as LinkIcon } from './link.svg'\nexport {\n  ReactComponent as GitHubNoteIcon,\n  // Backward compatibility\n  ReactComponent as InformationCircleIcon\n} from './github-note.svg'\nexport { ReactComponent as GitHubTipIcon } from './github-tip.svg'\nexport { ReactComponent as GitHubImportantIcon } from './github-important.svg'\nexport { ReactComponent as GitHubWarningIcon } from './github-warning.svg'\nexport { ReactComponent as GitHubCautionIcon } from './github-caution.svg'\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/anchor.tsx",
    "content": "import cn from 'clsx'\nimport Link from 'next/link'\nimport type { ComponentPropsWithoutRef, FC } from 'react'\nimport { EXTERNAL_URL_RE } from '../../server/constants.js'\nimport { LinkArrowIcon } from '../icons/index.js'\n\ntype NextLinkProps = ComponentPropsWithoutRef<typeof Link>\n\ntype Props = Omit<NextLinkProps, 'href'> & {\n  href?: NextLinkProps['href'] | undefined\n}\n\nexport const Anchor: FC<Props> = ({ href = '', prefetch, ...props }) => {\n  props = {\n    ...props,\n    className: cn('x:focus-visible:nextra-focus', props.className)\n  }\n  if (typeof href === 'string') {\n    if (href.startsWith('#')) {\n      return <a href={href} {...props} />\n    }\n    if (EXTERNAL_URL_RE.test(href)) {\n      const { children } = props\n      return (\n        <a href={href} target=\"_blank\" rel=\"noreferrer\" {...props}>\n          {children}\n          {typeof children === 'string' && (\n            <>\n              &nbsp;\n              <LinkArrowIcon\n                // based on font-size\n                height=\"1em\"\n                className=\"x:inline x:align-baseline x:shrink-0\"\n              />\n            </>\n          )}\n        </a>\n      )\n    }\n  }\n  return <Link href={href} prefetch={prefetch} {...props} />\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/code.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes } from 'react'\n\nexport const Code: FC<\n  HTMLAttributes<HTMLElement> & {\n    'data-language'?: string\n  }\n> = ({ children, className, 'data-language': _language, ...props }) => {\n  return (\n    <code\n      className={cn(\n        'nextra-code',\n        'data-line-numbers' in props && '[counter-reset:line]',\n        className\n      )}\n      // always show code blocks in ltr\n      dir=\"ltr\"\n      {...props}\n    >\n      {children}\n    </code>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/details.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport type {\n  ComponentProps,\n  Dispatch,\n  FC,\n  MouseEvent,\n  ReactNode,\n  SetStateAction\n} from 'react'\nimport { Children, cloneElement, useEffect, useRef, useState } from 'react'\nimport { Collapse } from '../components/collapse.js'\nimport { useHash } from '../hooks/index.js'\n\nexport const Details: FC<ComponentProps<'details'>> = ({\n  children,\n  open,\n  className,\n  ...props\n}) => {\n  const [isOpen, setIsOpen] = useState(!!open)\n  // To animate the close animation we have to delay the DOM node state here.\n  const [delayedOpenState, setDelayedOpenState] = useState(isOpen)\n  const animationRef = useRef(0)\n\n  useEffect(() => {\n    const animation = animationRef.current\n    if (animation) {\n      clearTimeout(animation)\n      animationRef.current = 0\n    }\n    if (!isOpen) {\n      animationRef.current = window.setTimeout(\n        () => setDelayedOpenState(isOpen),\n        300\n      )\n      return () => {\n        clearTimeout(animationRef.current)\n      }\n    }\n    setDelayedOpenState(true)\n  }, [isOpen])\n\n  const [summaryElement, restChildren] = findSummary(children, setIsOpen)\n\n  const hash = useHash()\n  const detailsRef = useRef<HTMLDetailsElement>(null!)\n  useEffect(() => {\n    if (!hash) return\n    const elementWithHashId = detailsRef.current.querySelector(`[id=\"${hash}\"]`)\n    if (!elementWithHashId) return\n    setIsOpen(true)\n  }, [hash])\n\n  return (\n    <details\n      className={cn(\n        'x:not-first:mt-4 x:rounded x:border x:border-gray-200 x:bg-white x:p-2 x:shadow-sm x:dark:border-neutral-800 x:dark:bg-neutral-900',\n        'x:overflow-hidden',\n        className\n      )}\n      ref={detailsRef}\n      {...props}\n      // `isOpen ||` fix issue on mobile devices while clicking on details, open attribute is still\n      // false, and we can't calculate child.clientHeight\n      open={isOpen || delayedOpenState}\n      data-expanded={isOpen ? '' : undefined}\n    >\n      {summaryElement}\n      <Collapse\n        isOpen={isOpen}\n        className={cn(\n          'x:*:pt-2',\n          'x:grid' // fix sudden height jump on open state https://github.com/shuding/nextra/issues/4074\n        )}\n      >\n        {restChildren}\n      </Collapse>\n    </details>\n  )\n}\n\n// Fix Unsupported declaration type for hoisting. variable \"findSummary\" declared with FunctionExpression\nfunction findSummary(\n  list: ReactNode,\n  setIsOpen: Dispatch<SetStateAction<boolean>>\n): [summary: ReactNode, ReactNode] {\n  let summary: ReactNode\n\n  const rest = Children.map(list, child => {\n    if (\n      !summary && // Add onClick only for first summary\n      child &&\n      typeof child === 'object' &&\n      'type' in child\n    ) {\n      if (child.type === 'summary') {\n        summary = cloneElement(child, {\n          // @ts-expect-error -- fixme\n          onClick(event: MouseEvent) {\n            // @ts-expect-error -- fixme\n            if (event.target.tagName !== 'A') {\n              event.preventDefault()\n              setIsOpen(v => !v)\n            }\n          }\n        })\n        return\n      }\n      // @ts-expect-error -- fixme\n      if (child.type !== Details && child.props.children) {\n        // @ts-expect-error -- fixme\n        ;[summary, child] = findSummary(child.props.children, setIsOpen)\n      }\n    }\n    return child\n  })\n\n  return [summary, rest]\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/image.tsx",
    "content": "import type { ImageProps } from 'next/image'\nimport NextImage from 'next/image'\nimport { forwardRef } from 'react'\n\nexport const Image = forwardRef<HTMLImageElement, ImageProps>((props, ref) => {\n  if (\n    process.env.NODE_ENV !== 'production' &&\n    typeof props.src === 'object' &&\n    !('blurDataURL' in props.src)\n  ) {\n    console.warn(\n      `[nextra] Failed to load blur image \"${(props.src as any).src}\" due missing \"src.blurDataURL\" value.\nThis is Turbopack bug, which will not occurs on production (since Webpack is used for \"next build\" command).`\n    )\n    props = {\n      ...props,\n      placeholder: 'empty'\n    }\n  }\n  const ComponentToUse = typeof props.src === 'object' ? NextImage : 'img'\n  return (\n    // @ts-expect-error -- fixme\n    <ComponentToUse\n      {...props}\n      ref={ref}\n      data-pagefind-index-attrs=\"title,alt\"\n    />\n  )\n})\n\nImage.displayName = 'Image'\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/index.ts",
    "content": "export { Pre } from './pre/index.js'\nexport { Anchor } from './anchor.js'\nexport { Code } from './code.js'\nexport { Details } from './details.js'\nexport { Image } from './image.js'\nexport { Summary } from './summary.js'\nexport { Table } from './table.js'\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/pre/copy-to-clipboard.tsx",
    "content": "'use client'\n\nimport type { FC, HTMLAttributes, MouseEvent } from 'react'\nimport { Button } from '../../components/button.js'\nimport { useCopy } from '../../hooks/use-copy.js'\nimport { CheckIcon, CopyIcon } from '../../icons/index.js'\n\nexport const CopyToClipboard: FC<HTMLAttributes<HTMLButtonElement>> = props => {\n  const { copy, isCopied } = useCopy()\n\n  const handleClick = async (event: MouseEvent) => {\n    const container = event.currentTarget.parentNode!.parentNode!\n    const content = container.querySelector('pre code')?.textContent || ''\n    copy(content)\n  }\n\n  const IconToUse = isCopied ? CheckIcon : CopyIcon\n\n  return (\n    <Button\n      onClick={handleClick}\n      title=\"Copy code\"\n      variant=\"outline\"\n      {...props}\n    >\n      <IconToUse height=\"1em\" className=\"nextra-copy-icon\" />\n    </Button>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/pre/index.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes, ReactNode } from 'react'\nimport { WordWrapIcon } from '../../icons/index.js'\nimport { CopyToClipboard } from './copy-to-clipboard.js'\nimport { ToggleWordWrapButton } from './toggle-word-wrap-button.js'\n\nexport const classes = {\n  border: cn(\n    'x:border x:border-gray-300 x:dark:border-neutral-700',\n    'x:contrast-more:border-gray-900 x:contrast-more:dark:border-gray-50'\n  )\n}\n\nexport type PreProps = HTMLAttributes<HTMLPreElement> & {\n  'data-filename'?: string\n  'data-copy'?: ''\n  'data-language'?: string\n  'data-word-wrap'?: ''\n  'data-pagefind-ignore'?: string\n  icon?: ReactNode\n}\n\nexport const Pre: FC<PreProps> = ({\n  children,\n  className,\n  'data-filename': filename,\n  'data-copy': copy,\n  'data-language': _language,\n  'data-word-wrap': hasWordWrap,\n  'data-pagefind-ignore': pagefindIgnore,\n  icon,\n  ...props\n}) => {\n  const copyButton = copy === '' && (\n    <CopyToClipboard className={filename ? 'x:ms-auto x:text-sm' : ''} />\n  )\n\n  return (\n    <div\n      data-pagefind-ignore={pagefindIgnore}\n      className=\"nextra-code x:relative x:not-first:mt-[1.25em]\"\n    >\n      {filename && (\n        <div\n          className={cn(\n            'x:px-4 x:text-xs x:text-gray-700 x:dark:text-gray-200',\n            'x:bg-gray-100 x:dark:bg-neutral-900',\n            'x:flex x:items-center x:h-12 x:gap-2 x:rounded-t-md',\n            classes.border,\n            'x:border-b-0'\n          )}\n        >\n          {icon}\n          <span className=\"x:truncate\">{filename}</span>\n          {copyButton}\n        </div>\n      )}\n      <pre\n        className={cn(\n          'x:group',\n          'x:focus-visible:nextra-focus',\n          'x:overflow-x-auto x:subpixel-antialiased x:text-[.9em]',\n          'x:bg-white x:dark:bg-black x:py-4',\n          'x:ring-1 x:ring-inset x:ring-gray-300 x:dark:ring-neutral-700',\n          'x:contrast-more:ring-gray-900 x:contrast-more:dark:ring-gray-50',\n          'x:contrast-more:contrast-150',\n          filename ? 'x:rounded-b-md' : 'x:rounded-md',\n          'not-prose', // for nextra-theme-blog\n          className\n        )}\n        {...props}\n      >\n        <div\n          className={cn(\n            'x:group-hover:opacity-100',\n            'x:group-focus:opacity-100',\n            'x:opacity-0 x:transition x:focus-within:opacity-100',\n            'x:flex x:gap-1 x:absolute x:right-4',\n            filename ? 'x:top-14' : 'x:top-2'\n          )}\n        >\n          {hasWordWrap === '' && (\n            <ToggleWordWrapButton>\n              <WordWrapIcon height=\"1em\" />\n            </ToggleWordWrapButton>\n          )}\n          {!filename && copyButton}\n        </div>\n        {children}\n      </pre>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/pre/toggle-word-wrap-button.tsx",
    "content": "'use client'\n\nimport type { FC, ReactNode } from 'react'\nimport { Button } from '../../components/button.js'\n\nfunction toggleWordWrap() {\n  const htmlDataset = document.documentElement.dataset\n  const hasWordWrap = 'nextraWordWrap' in htmlDataset\n  if (hasWordWrap) {\n    delete htmlDataset.nextraWordWrap\n  } else {\n    htmlDataset.nextraWordWrap = ''\n  }\n}\n\nexport const ToggleWordWrapButton: FC<{\n  children: ReactNode\n}> = ({ children }) => {\n  return (\n    <Button\n      onClick={toggleWordWrap}\n      className=\"x:md:hidden\"\n      title=\"Toggle word wrap\"\n      variant=\"outline\"\n    >\n      {children}\n    </Button>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/summary.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes } from 'react'\nimport { ArrowRightIcon, LinkIcon } from '../icons/index.js'\n\nexport const Summary: FC<HTMLAttributes<HTMLElement>> = ({\n  children,\n  className,\n  id,\n  ...props\n}) => {\n  return (\n    <summary\n      className={cn(\n        'x:focus-visible:nextra-focus',\n        'x:cursor-pointer x:transition-colors',\n        'x:hover:bg-gray-100 x:dark:hover:bg-neutral-800',\n        'x:select-none x:rounded',\n        'x:[&::-webkit-details-marker]:hidden', // Safari\n        'x:flex x:items-center',\n        className\n      )}\n      {...props}\n    >\n      <ArrowRightIcon\n        height=\"1em\"\n        className={cn(\n          'x:motion-reduce:transition-none x:ms-2 x:me-1 x:shrink-0',\n          'x:rtl:rotate-180 x:[[data-expanded]>summary:first-child>&]:rotate-90 x:transition'\n        )}\n        strokeWidth=\"3\"\n      />\n      <h3\n        // ID attached to `<summary>` jumps to incorrect position in viewport.\n        // Also, it's better to put `<summary>` content inside heading, so Pagefind will have\n        // sub result title of this `<summary>` content\n        id={id}\n        className=\"x:grow x:hyphens-auto x:p-1\"\n      >\n        {children}\n      </h3>\n      {id && (\n        <a\n          href={`#${id}`}\n          aria-label=\"Permalink for this section\"\n          className={cn(\n            'x:self-stretch',\n            'x:flex x:items-center',\n            'x:focus-visible:nextra-focus x:rounded x:px-2',\n            'x:hover:bg-gray-100 x:dark:hover:bg-neutral-800',\n            'x:hover:[summary:has(&)]:bg-transparent'\n          )}\n        >\n          <LinkIcon\n            height=\"1em\"\n            // avoid triggering by event.target in onClick handler from `<details>`\n            className=\"x:pointer-events-none\"\n          />\n        </a>\n      )}\n    </summary>\n  )\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components/table.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, HTMLAttributes } from 'react'\n\nconst Table_: FC<HTMLAttributes<HTMLTableElement>> = props => (\n  <table\n    {...props}\n    className={cn('x:block x:overflow-x-auto', props.className)}\n  />\n)\nconst Th: FC<HTMLAttributes<HTMLTableCellElement>> = props => {\n  return (\n    <th\n      {...props}\n      className={cn(\n        'x:m-0 x:border x:border-gray-300 x:px-4 x:py-2 x:font-semibold x:dark:border-gray-600',\n        props.className\n      )}\n    />\n  )\n}\nconst Tr: FC<HTMLAttributes<HTMLTableRowElement>> = props => {\n  return (\n    <tr\n      {...props}\n      className={cn(\n        'x:m-0 x:border-t x:border-gray-300 x:p-0 x:dark:border-gray-600',\n        'x:even:bg-gray-100 x:even:dark:bg-gray-600/20',\n        props.className\n      )}\n    />\n  )\n}\nconst Td: FC<HTMLAttributes<HTMLTableCellElement>> = props => {\n  return (\n    <td\n      {...props}\n      className={cn(\n        'x:m-0 x:border x:border-gray-300 x:px-4 x:py-2 x:dark:border-gray-600',\n        props.className\n      )}\n    />\n  )\n}\n\n/**\n * A collection of built-in components designed to create styled, non-markdown\n * (i.e., literal) HTML tables.\n *\n * @example\n * <Table className=\"mt-6\">\n *   <thead>\n *     <Table.Tr>\n *       <Table.Th>Country</Table.Th>\n *       <Table.Th>Flag</Table.Th>\n *     </Table.Tr>\n *   </thead>\n *   <tbody>\n *     <Table.Tr>\n *       <Table.Td>France</Table.Td>\n *       <Table.Td>🇫🇷</Table.Td>\n *     </Table.Tr>\n *     <Table.Tr>\n *       <Table.Td>Ukraine</Table.Td>\n *       <Table.Td>🇺🇦</Table.Td>\n *     </Table.Tr>\n *   </tbody>\n * </Table>\n *\n * @usage\n * ```mdx\n * import { Table } from 'nextra/components'\n *\n * <Table>\n *   <thead>\n *     <Table.Tr>\n *       <Table.Th>Country</Table.Th>\n *       <Table.Th>Flag</Table.Th>\n *     </Table.Tr>\n *   </thead>\n *   <tbody>\n *     <Table.Tr>\n *       <Table.Td>France</Table.Td>\n *       <Table.Td>🇫🇷</Table.Td>\n *     </Table.Tr>\n *     <Table.Tr>\n *       <Table.Td>Ukraine</Table.Td>\n *       <Table.Td>🇺🇦</Table.Td>\n *     </Table.Tr>\n *   </tbody>\n * </Table>\n * ```\n */\nexport const Table = Object.assign(Table_, {\n  Th,\n  Tr,\n  Td\n})\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-components.ts",
    "content": "import type { ComponentPropsWithoutRef, FC, JSX } from 'react'\nimport type { MDXWrapper } from '../types.js'\nimport { ImageZoom } from './components/image-zoom.js'\nimport { Anchor } from './mdx-components/anchor.js'\n\n/**\n * A valid JSX string component.\n */\ntype StringComponent = Exclude<keyof JSX.IntrinsicElements, 'img' | 'a'>\n\n/**\n * Any allowed JSX component.\n */\ntype Component<Props> = FC<Props> | StringComponent\n\nexport interface NestedMDXComponents {\n  [key: string]: NestedMDXComponents | Component<any>\n}\n\n/**\n * MDX components may be passed as the `components`.\n *\n * The key is the name of the element to override. The value is the component to render instead.\n */\nexport type MDXComponents = NestedMDXComponents & {\n  [Key in StringComponent]?: FC<ComponentPropsWithoutRef<Key>>\n} & {\n  /**\n   * If a wrapper component is defined, the MDX content will be wrapped inside it.\n   */\n  wrapper?: MDXWrapper\n} & DefaultMdxComponents\n\ntype DefaultMdxComponents = {\n  /**\n   * Nextra's `<ImageZoom />` component with zoom functionality.\n   * Uses `<NextImage>` for static images and falls back to a standard `<img>` element for others.\n   */\n  img?: typeof ImageZoom\n  /**\n   * Nextra's `<Anchor />` component for rendering links.\n   * Uses `<NextLink>` for internal navigation and falls back to a regular `<a>` element for\n   * external links.\n   */\n  a?: typeof Anchor\n}\n\nconst DEFAULT_COMPONENTS = {\n  img: ImageZoom,\n  a: Anchor\n} satisfies DefaultMdxComponents\n\n/**\n * Get current MDX components.\n * @returns The current set of MDX components.\n */\nexport type UseMDXComponents<\n  /**\n   * Default MDX components\n   */\n  DefaultMDXComponents extends MDXComponents\n> = {\n  <components extends MDXComponents>(\n    /**\n     * An object where:\n     * - The key is the name of the HTML element to override.\n     * - The value is the component to render instead.\n     * @remarks `MDXComponents`\n     */\n    components: components\n  ): DefaultMDXComponents & components\n  (): DefaultMDXComponents\n}\n\nexport const useMDXComponents: UseMDXComponents<typeof DEFAULT_COMPONENTS> = <\n  T\n>(\n  components?: T\n) => {\n  return {\n    ...DEFAULT_COMPONENTS,\n    ...components\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/client/mdx-remote.tsx",
    "content": "import { useMDXComponents } from 'next-mdx-import-source-file'\nimport type { FC } from 'react'\nimport { evaluate } from './evaluate.js'\nimport type { Scope } from './evaluate.js'\nimport type { MDXComponents } from './mdx-components.js'\n\nexport type MDXRemoteProps = Readonly<{\n  /**\n   * An object mapping names to React components.\n   * The key used will be the name accessible to MDX.\n   *\n   * @example\n   * `{ ComponentName: Component }` will be accessible in the MDX as `<ComponentName>`.\n   */\n  components?: MDXComponents\n  /**\n   * Pass-through variables for use in the MDX content.\n   * These variables will be available in the MDX scope.\n   */\n  scope?: Scope\n  /**\n   * Raw JavaScript compiled MDX source code, a result of Nextra's\n   * [`compileMdx` function](https://nextra.site/api/compilemdx).\n   */\n  compiledSource: string\n}>\n\n/**\n * A React component that renders compiled MDX content.\n *\n * @returns A rendered React element that renders the MDX content.\n * @example\n * ```mdx filename=\"example.mdx\"\n * import { compileMdx } from 'nextra/compile'\n * import { MDXRemote } from 'nextra/mdx-remote'\n *\n * <MDXRemote\n *   compiledSource={await compileMdx('# Hello {myVariable} <MyComponent />')}\n *   components={{ MyComponent: () => <div>My Component</div> }}\n *   scope={{ myVariable: 'World' }}\n * />\n * ```\n */\nexport const MDXRemote: FC<MDXRemoteProps> = ({\n  scope,\n  components,\n  compiledSource\n}) => {\n  const MDXContent = evaluate(\n    compiledSource,\n    useMDXComponents(components),\n    scope\n  ).default\n\n  return <MDXContent />\n}\n"
  },
  {
    "path": "packages/nextra/src/client/normalize-pages.ts",
    "content": "'use no memo'\n\nimport type { ReactNode } from 'react'\nimport type { z } from 'zod'\nimport type { itemSchema, menuSchema } from '../server/schemas.js'\nimport type { Folder, FrontMatter, MdxFile, PageMapItem } from '../types.js'\n\nconst DEFAULT_PAGE_THEME: PageTheme = {\n  breadcrumb: true,\n  collapsed: undefined,\n  copyPage: true,\n  footer: true,\n  layout: 'default',\n  navbar: true,\n  pagination: true,\n  sidebar: true,\n  timestamp: true,\n  toc: true,\n  typesetting: 'default'\n}\n\ntype PageTheme = NonNullable<z.infer<typeof itemSchema>['theme']>\ntype Display = z.infer<typeof itemSchema>['display']\ntype IMenuItem = z.infer<typeof menuSchema>\ntype MetaType = Record<string, any>\n\nfunction extendMeta(\n  _meta: MetaType = {},\n  fallback: MetaType,\n  metadata: MetaType = {}\n): MetaType {\n  const theme: PageTheme = {\n    ...fallback.theme,\n    ..._meta.theme,\n    ...metadata.theme\n  }\n  return {\n    ...fallback,\n    ..._meta,\n    display: metadata.display || _meta.display || fallback.display,\n    theme\n  }\n}\n\ntype FolderWithoutChildren = Omit<Folder, 'children'>\n\nexport type Item = (MdxFile | FolderWithoutChildren) & {\n  title: ReactNode\n  type: string\n  children: Item[]\n  display?: Display\n  theme?: PageTheme\n  frontMatter: FrontMatter\n  isUnderCurrentDocsTree?: boolean\n}\n\nexport type PageItem = (MdxFile | FolderWithoutChildren) & {\n  title: ReactNode\n  type: string\n  href?: string\n  children?: PageItem[]\n  firstChildRoute?: string\n  display?: Display\n  isUnderCurrentDocsTree?: boolean\n}\n\nexport type MenuItem = (MdxFile | FolderWithoutChildren) &\n  IMenuItem & {\n    children?: PageItem[]\n  }\n\ntype DocsItem = (MdxFile | FolderWithoutChildren) & {\n  title: ReactNode\n  type: string\n  children: DocsItem[]\n  firstChildRoute?: string\n  isUnderCurrentDocsTree?: boolean\n}\n\nfunction findFirstRoute(items: DocsItem[]): string | undefined {\n  for (const item of items) {\n    if (item.route) return item.route\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- fixme\n    if (item.children) {\n      const route = findFirstRoute(item.children)\n      if (route) return route\n    }\n  }\n}\n\ntype NormalizedResult = {\n  /** Active type for current page, used to determine layout in theme. */\n  activeType?: 'doc' | 'page' | 'menu'\n  /**\n   * Active index for current page, used for pagination in combination with `flatDocsDirectories`\n   * items.\n   */\n  activeIndex: number\n  activeThemeContext: PageTheme\n  /**\n   * Parsed [front matter](https://jekyllrb.com/docs/front-matter) or exported\n   * [Metadata](https://nextjs.org/docs/app/building-your-application/optimizing/metadata) from page.\n   */\n  activeMetadata?: FrontMatter\n  /** Active path for current page, used for breadcrumb navigation. */\n  activePath: Item[]\n  /** All directories in the tree structure. */\n  directories: Item[]\n  /** Directories with `type: 'doc'` in `_meta` file. */\n  docsDirectories: DocsItem[]\n  /** Flattened directories with `type: 'doc'` in `_meta` file. */\n  flatDocsDirectories: DocsItem[]\n  /** Navbar items, items which have `type: 'page'` in `_meta` file. */\n  topLevelNavbarItems: (PageItem | MenuItem)[]\n}\n\nexport function normalizePages({\n  list,\n  route,\n  /** @default '' */\n  docsRoot = '',\n  /** @default DEFAULT_PAGE_THEME */\n  pageThemeContext = DEFAULT_PAGE_THEME\n}: {\n  list: PageMapItem[]\n  route: string\n  docsRoot?: string\n  underCurrentDocsRoot?: boolean\n  pageThemeContext?: PageTheme\n}): NormalizedResult {\n  // If the doc is under the active page root.\n  const underCurrentDocsRoot = route.startsWith(docsRoot)\n  const directories: Item[] = []\n  const docsDirectories: DocsItem[] = []\n  const flatDocsDirectories: DocsItem[] = []\n  const topLevelNavbarItems: (PageItem | MenuItem)[] = []\n  const firstItem = list[0]! // always exists\n  const meta = 'data' in firstItem ? (firstItem.data as MetaType) : {}\n  // Normalize items based on files and _meta.json.\n  const items = ('data' in firstItem ? list.slice(1) : list) as (\n    | (Folder & { frontMatter?: FrontMatter })\n    | MdxFile\n  )[]\n\n  const fallbackMeta = meta['*'] || {}\n\n  let activeType: NormalizedResult['activeType'] = fallbackMeta.type\n  let activeIndex = 0\n  let activeThemeContext = {\n    ...pageThemeContext,\n    ...fallbackMeta.theme\n  }\n  let activePath: Item[] = []\n\n  for (const currentItem of items) {\n    // Get the item's meta information.\n    const extendedMeta = extendMeta(\n      meta[currentItem.name],\n      fallbackMeta,\n      currentItem.frontMatter\n    )\n    const { display, type = 'doc' } = extendedMeta\n    const extendedPageThemeContext = {\n      ...pageThemeContext,\n      ...extendedMeta.theme\n    }\n\n    const normalizedChildren: false | NormalizedResult =\n      'children' in currentItem &&\n      normalizePages({\n        list: currentItem.children,\n        route,\n        docsRoot:\n          type === 'page' || type === 'menu' ? currentItem.route : docsRoot,\n        underCurrentDocsRoot,\n        pageThemeContext: extendedPageThemeContext\n      })\n\n    const getItem = (): Item => ({\n      ...currentItem,\n      type,\n      ...('title' in currentItem && { title: currentItem.title }),\n      ...(display && { display }),\n      ...(normalizedChildren && { children: [] })\n    })\n    const item: Item = getItem()\n    const docsItem: DocsItem = getItem()\n    if ('children' in docsItem) {\n      const { collapsed } = extendedMeta.theme\n      if (typeof collapsed === 'boolean') {\n        // @ts-expect-error -- fixme\n        docsItem.theme = { collapsed }\n      }\n    }\n    const pageItem: PageItem = getItem()\n\n    docsItem.isUnderCurrentDocsTree = underCurrentDocsRoot\n    if (type === 'separator') {\n      item.isUnderCurrentDocsTree = underCurrentDocsRoot\n    }\n\n    // This item is currently active, we collect the active path etc.\n    if (currentItem.route === route) {\n      activePath = [item]\n      activeType = type\n      // There can be multiple matches.\n      activeThemeContext = {\n        ...activeThemeContext,\n        ...extendedPageThemeContext\n      }\n      switch (type) {\n        case 'page':\n        case 'menu':\n          // Active on the navbar\n          activeIndex = topLevelNavbarItems.length\n          break\n        case 'doc':\n          // Active in the docs tree\n          activeIndex = flatDocsDirectories.length\n      }\n    }\n    const isHidden = display === 'hidden'\n\n    // If this item has children\n    if (normalizedChildren) {\n      // If the active item is in its children\n      if (\n        // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- fixme\n        normalizedChildren.activeIndex !== undefined &&\n        normalizedChildren.activeType !== undefined\n      ) {\n        activeThemeContext = normalizedChildren.activeThemeContext\n        activeType = normalizedChildren.activeType\n        if (isHidden) {\n          continue\n        }\n        activePath = [\n          item,\n          // Do not include folder which shows only his children\n          ...normalizedChildren.activePath.filter(\n            item => item.display !== 'children'\n          )\n        ]\n\n        switch (activeType) {\n          case 'page':\n          case 'menu':\n            activeIndex =\n              topLevelNavbarItems.length + normalizedChildren.activeIndex\n            break\n          case 'doc':\n            activeIndex =\n              flatDocsDirectories.length + normalizedChildren.activeIndex\n            break\n        }\n        if ('frontMatter' in currentItem && type === 'doc') {\n          activeIndex++\n        }\n      }\n\n      switch (type) {\n        case 'page':\n        case 'menu':\n          // @ts-expect-error normalizedChildren === true\n          pageItem.children.push(...normalizedChildren.directories)\n          docsDirectories.push(...normalizedChildren.docsDirectories)\n\n          // If it's a page with children inside, we inject itself as a page too.\n          if (normalizedChildren.flatDocsDirectories.length) {\n            const route = findFirstRoute(normalizedChildren.flatDocsDirectories)\n            if (route) pageItem.firstChildRoute = route\n            topLevelNavbarItems.push(pageItem)\n          } else if ('frontMatter' in pageItem) {\n            topLevelNavbarItems.push(pageItem)\n          }\n\n          break\n        case 'doc':\n          docsItem.children.push(...normalizedChildren.docsDirectories)\n          // Itself is a doc page.\n          if ('frontMatter' in item && display !== 'children') {\n            flatDocsDirectories.push(docsItem)\n          }\n      }\n\n      flatDocsDirectories.push(...normalizedChildren.flatDocsDirectories)\n      item.children.push(...normalizedChildren.directories)\n    } else {\n      if (isHidden) {\n        continue\n      }\n      switch (type) {\n        case 'page':\n        case 'menu':\n          topLevelNavbarItems.push(pageItem)\n          break\n        case 'doc': {\n          const withHrefProp = 'href' in item\n          // Do not include links with href in pagination\n          if (!withHrefProp) {\n            flatDocsDirectories.push(docsItem)\n          }\n        }\n      }\n    }\n\n    if (isHidden) {\n      continue\n    }\n\n    if (type === 'doc' && display === 'children') {\n      // Hide the directory itself and treat all its children as pages\n      // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- fixme\n      if (docsItem.children) {\n        // @ts-expect-error -- fixme\n        directories.push(...docsItem.children)\n        docsDirectories.push(...docsItem.children)\n      }\n    } else {\n      directories.push(item)\n    }\n\n    switch (type) {\n      case 'page':\n      case 'menu':\n        // @ts-expect-error -- fixme\n        docsDirectories.push(pageItem)\n        break\n      case 'doc':\n        if (display !== 'children') {\n          docsDirectories.push(docsItem)\n        }\n        break\n      case 'separator':\n        docsDirectories.push(item)\n    }\n  }\n  const activeMetadata = activePath.at(-1)?.frontMatter\n\n  const result = {\n    activeType,\n    activeIndex,\n    activeThemeContext,\n    activeMetadata,\n    activePath,\n    directories,\n    docsDirectories: docsDirectories.filter(\n      item => item.isUnderCurrentDocsTree\n    ),\n    flatDocsDirectories,\n    topLevelNavbarItems\n  }\n\n  return result\n}\n"
  },
  {
    "path": "packages/nextra/src/client/pages.ts",
    "content": "'use no memo'\n\nimport { notFound } from 'next/navigation'\nimport { getRouteToFilepath } from '../server/page-map/get.js'\nimport { logger } from '../server/utils.js'\nimport type { EvaluateResult } from '../types.js'\n\n/**\n * Function to import an MDX/Markdown page from the `content` directory.\n *\n * This function is essential for Nextra's dynamic page loading from a catch-all route.\n *\n * @returns\n * A Promise that resolves to an object containing:\n *  - `default`: The MDX component to render\n *  - `toc`: Table of contents list\n *  - `metadata`: Page's front matter or `metadata` object including `title`, `description`, etc.\n *\n * @example\n * ### Basic usage in a dynamic Next.js route\n *\n * ```ts\n * const { default: MDXContent, toc, metadata } = await importPage(['docs', 'getting-started'])\n * ```\n *\n * ### Usage with i18n\n *\n * ```ts\n * const { default: MDXContent } = await importPage(['docs', 'getting-started'], 'en')\n * ```\n *\n * ### Import page's front matter in `generateMetadata` function\n *\n * ```ts\n * // app/[[...mdxPath]]/page.tsx\n * import { importPage } from 'nextra/pages'\n *\n * export async function generateMetadata(props) {\n *   const params = await props.params\n *   const { metadata } = await importPage(params.mdxPath)\n *   return metadata\n * }\n * ```\n *\n * ### Import page in a catch-all route\n *\n * ```tsx\n * // app/[[...mdxPath]]/page.tsx\n * import { generateStaticParamsFor, importPage } from 'nextra/pages'\n * import { useMDXComponents as getMDXComponents } from 'path/to/your/mdx-components'\n *\n * export const generateStaticParams = generateStaticParamsFor('mdxPath')\n *\n * const Wrapper = getMDXComponents().wrapper\n *\n * export default async function Page(props) {\n *   const params = await props.params\n *   const result = await importPage(params.mdxPath)\n *   const { default: MDXContent, toc, metadata } = result\n *   return (\n *     <Wrapper toc={toc} metadata={metadata}>\n *       <MDXContent {...props} params={params} />\n *     </Wrapper>\n *   )\n * }\n * ```\n *\n * @see\n * - [Content Directory Documentation](https://nextra.site/docs/file-conventions/content-directory)\n * - [Next.js Dynamic Routes](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes)\n * - [Next.js Metadata API](https://nextjs.org/docs/app/building-your-application/optimizing/metadata)\n */\nexport async function importPage(\n  /**\n   * Array of path segments representing the route to the page.\n   *\n   * E.g., for the route `/docs/getting-started/installation`, pass `['docs', 'getting-started', 'installation']`.\n   * @default []\n   */\n  pathSegments: string[] = [],\n  /**\n   * The language segment when using i18n.\n   * @default ''\n   */\n  lang = ''\n): Promise<EvaluateResult> {\n  const RouteToFilepath = await getRouteToFilepath(lang)\n\n  const pathname = pathSegments.join('/')\n  // handle non-\"\\w\" characters,`decodeURIComponent` decodes `%26` (`&`) character\n  const decodedPath = decodeURIComponent(pathname)\n\n  const pagePath = RouteToFilepath[decodedPath]\n  try {\n    // eslint-disable-next-line @typescript-eslint/no-require-imports -- Require statement enables Fast Refresh\n    return require(`private-next-content-dir/${lang && `${lang}/`}${pagePath}`)\n  } catch (error) {\n    logger.error('Error while loading', { pathSegments }, error)\n    notFound()\n  }\n}\n\n/**\n * Generates static parameters based on your `content` directory structure.\n *\n * This helper function is designed to work with Next.js' `generateStaticParams` function to create\n * static paths for all your MDX/Markdown pages.\n *\n * @returns A function that generates an array of parameters for static page generation.\n *\n * @example\n * ### Basic usage with a catch-all route\n *\n * ```ts\n * // app/[[...slug]]/page.tsx\n * export const generateStaticParams = generateStaticParamsFor('slug')\n * ```\n *\n * ### Usage with i18n support\n *\n * ```ts\n * // app/[locale]/[[...mdxPath]]/page.tsx\n * export const generateStaticParams = generateStaticParamsFor('mdxPath', 'locale')\n * ```\n *\n * @see\n * - [Next.js `generateStaticParams` function](https://nextjs.org/docs/app/api-reference/functions/generate-static-params)\n * - [Content Directory Structure](https://nextra.site/docs/file-conventions/content-directory)\n */\nexport function generateStaticParamsFor(\n  /** The name of your catch-all route segment (e.g., `'slug'`, `'mdxPath'`). */\n  segmentKey: string,\n  /**\n   * The name of the locale segment when you have i18n.\n   * @default \"lang\"\n   */\n  localeSegmentKey = 'lang'\n) {\n  return async () => {\n    const locales = JSON.parse(process.env.NEXTRA_LOCALES!) as string[]\n    const result = []\n\n    for (const locale of locales) {\n      const RouteToFilepath = await getRouteToFilepath(locale)\n      const routes = Object.keys(RouteToFilepath)\n\n      result.push(\n        ...routes.map(route => ({\n          ...(locale && { [localeSegmentKey]: locale }),\n          [segmentKey]: route.split('/')\n        }))\n      )\n    }\n    return result\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/client/remove-links.ts",
    "content": "// should be used on server\n'use no memo'\n\nimport type { ReactElement, ReactNode } from 'react'\nimport { Children, cloneElement } from 'react'\n\ntype TOCElement = ReactElement | string\n\nfunction hasProps(node: ReactNode) {\n  return !!node && typeof node === 'object'\n}\n\nexport function removeLinks(node: ReactNode): TOCElement[] | string {\n  if (typeof node === 'string') {\n    return node\n  }\n  // @ts-expect-error fixme\n  return Children.map(node, child => {\n    if (\n      hasProps(child) &&\n      // @ts-expect-error -- fixme\n      child.props.href\n    ) {\n      // Skip footnotes links\n      // @ts-expect-error -- fixme\n      if (child.props['data-footnote-ref']) {\n        return\n      }\n      // @ts-expect-error -- fixme\n      child = child.props.children\n    }\n\n    if (typeof child === 'string') {\n      return child\n    }\n\n    if (Array.isArray(child)) {\n      return removeLinks(child)\n    }\n    if (!hasProps(child)) {\n      return child\n    }\n    // @ts-expect-error -- fixme\n    const children = removeLinks(child.props.children)\n    // @ts-expect-error -- fixme\n    return cloneElement(child, { children })\n  })\n}\n"
  },
  {
    "path": "packages/nextra/src/client/setup-page.tsx",
    "content": "// should be used on server\n'use no memo'\n\n/*\n * ⚠️ Attention!\n * This file should be never used directly, only in loader.ts\n */\nimport { useMDXComponents as getMDXComponents } from 'next-mdx-import-source-file'\nimport type { ComponentProps, FC } from 'react'\nimport { createElement } from 'react'\nimport type { MDXWrapper } from '../types.js'\n\nconst Wrapper = getMDXComponents().wrapper\n\ntype WrapperProps = ComponentProps<MDXWrapper>\n\nexport function HOC_MDXWrapper(\n  MDXContent: MDXWrapper,\n  hocProps: Omit<WrapperProps, 'children'>\n): FC<WrapperProps> {\n  return function MDXWrapper(props) {\n    const children = createElement(MDXContent, props)\n\n    return Wrapper ? <Wrapper {...hocProps}>{children}</Wrapper> : children\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/env.d.ts",
    "content": "declare namespace globalThis {\n  import type { PagefindSearchOptions } from './types.js'\n  var pagefind:\n    | {\n        // https://github.com/CloudCannon/pagefind/blob/2a0aa90cfb78bb8551645ac9127a1cd49cf54add/pagefind_web_js/lib/coupled_search.ts#L600\n        debouncedSearch: <T>(\n          term: string,\n          options?: PagefindSearchOptions,\n          debounceTimeoutMs?: number\n        ) => Promise<{\n          results: {\n            data: () => Promise<T>\n            id: string\n          }[]\n        } | null>\n        options: (opts: Record<string, unknown>) => Promise<void>\n      }\n    | undefined\n}\n\ndeclare module '*.svg' {\n  export { ReactComponent } from './icon.js'\n}\n\ndeclare module 'next-mdx-import-source-file' {\n  // eslint-disable-next-line import/extensions -- false positive, should be without extension\n  export { useMDXComponents } from 'nextra/mdx-components'\n}\n"
  },
  {
    "path": "packages/nextra/src/icon.ts",
    "content": "/*\n * This file is used in tsup patch to generate types for SVG files.\n **/\nimport type { FC, SVGProps } from 'react'\n\ndeclare const ReactComponent: FC<SVGProps<SVGElement>>\n\nexport { ReactComponent }\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/__snapshots__/compile.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`Process heading > code-h1 1`] = `\n\"/*@jsxRuntime automatic*/\n/*@jsxImportSource react*/\nimport { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\nexport const metadata = {\n  title: 'codegen.yml'\n}\nexport const sourceCode = '# \\`codegen.yml\\`'\nfunction useTOC(props) {\n  return []\n}\nexport const toc = useTOC({})\nfunction _createMdxContent(props) {\n  const _components = {\n    code: 'code',\n    h1: 'h1',\n    ..._provideComponents(),\n    ...props.components\n  }\n  return (\n    <_components.h1>\n      <_components.code>{'codegen.yml'}</_components.code>\n    </_components.h1>\n  )\n}\nexport default _createMdxContent\"\n`;\n\nexports[`Process heading > code-with-text-h1 1`] = `\n\"/*@jsxRuntime automatic*/\n/*@jsxImportSource react*/\nimport { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\nexport const metadata = {\n  title: 'codegen.yml file'\n}\nexport const sourceCode = '# \\`codegen.yml\\` file'\nfunction useTOC(props) {\n  return []\n}\nexport const toc = useTOC({})\nfunction _createMdxContent(props) {\n  const _components = {\n    code: 'code',\n    h1: 'h1',\n    ..._provideComponents(),\n    ...props.components\n  }\n  return (\n    <_components.h1>\n      <_components.code>{'codegen.yml'}</_components.code>\n      {' file'}\n    </_components.h1>\n  )\n}\nexport default _createMdxContent\"\n`;\n\nexports[`Process heading > dynamic-h1 1`] = `\n\"/*@jsxRuntime automatic*/\n/*@jsxImportSource react*/\nimport { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\nexport const metadata = {\n  title: 'Posts Tagged with \"\"'\n}\nimport { useRouter } from 'next/router'\nexport const TagName = () => {\n  const { tag } = useRouter().query\n  return tag || null\n}\nexport const sourceCode =\n  'import { useRouter } from \\\\'next/router\\\\'\\\\n\\\\nexport const TagName = () => {\\\\n  const { tag } = useRouter().query\\\\n  return tag || null\\\\n}\\\\n\\\\n# Posts Tagged with \"<TagName/>\"'\nfunction useTOC(props) {\n  return []\n}\nexport const toc = useTOC({})\nfunction _createMdxContent(props) {\n  const _components = {\n    h1: 'h1',\n    ..._provideComponents(),\n    ...props.components\n  }\n  return (\n    <_components.h1>\n      {'Posts Tagged with \"'}\n      <TagName />\n      {'\"'}\n    </_components.h1>\n  )\n}\nexport default _createMdxContent\"\n`;\n\nexports[`Process heading > no-h1 1`] = `\n\"/*@jsxRuntime automatic*/\n/*@jsxImportSource react*/\nimport { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\nexport const metadata = {}\nexport const sourceCode = '## H2'\nfunction useTOC(props) {\n  return [\n    {\n      value: 'H2',\n      id: 'h2',\n      depth: 2\n    }\n  ]\n}\nexport const toc = useTOC({})\nfunction _createMdxContent(props) {\n  const _components = {\n    h2: 'h2',\n    ..._provideComponents(),\n    ...props.components\n  }\n  return <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n}\nexport default _createMdxContent\"\n`;\n\nexports[`Process heading > static-h1 1`] = `\n\"/*@jsxRuntime automatic*/\n/*@jsxImportSource react*/\nimport { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\nexport const metadata = {\n  title: 'Hello World'\n}\nexport const sourceCode = '# Hello World'\nfunction useTOC(props) {\n  return []\n}\nexport const toc = useTOC({})\nfunction _createMdxContent(props) {\n  const _components = {\n    h1: 'h1',\n    ..._provideComponents(),\n    ...props.components\n  }\n  return <_components.h1>{'Hello World'}</_components.h1>\n}\nexport default _createMdxContent\"\n`;\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/__snapshots__/normalize.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`normalize-page > en-US getting-started 1`] = `\n{\n  \"activeIndex\": 1,\n  \"activeMetadata\": undefined,\n  \"activePath\": [\n    {\n      \"children\": [\n        {\n          \"name\": \"getting-started\",\n          \"route\": \"/docs/getting-started\",\n          \"title\": \"Getting Started\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"options\",\n          \"route\": \"/docs/options\",\n          \"title\": \"Options\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"global-configuration\",\n          \"route\": \"/docs/global-configuration\",\n          \"title\": \"Global Configuration\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"data-fetching\",\n          \"route\": \"/docs/data-fetching\",\n          \"title\": \"Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"error-handling\",\n          \"route\": \"/docs/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"revalidation\",\n          \"route\": \"/docs/revalidation\",\n          \"title\": \"Auto Revalidation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"conditional-fetching\",\n          \"route\": \"/docs/conditional-fetching\",\n          \"title\": \"Conditional Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"arguments\",\n          \"route\": \"/docs/arguments\",\n          \"title\": \"Arguments\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"mutation\",\n          \"route\": \"/docs/mutation\",\n          \"title\": \"Mutation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"pagination\",\n          \"route\": \"/docs/pagination\",\n          \"title\": \"Pagination\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"prefetching\",\n          \"route\": \"/docs/prefetching\",\n          \"title\": \"Prefetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"with-nextjs\",\n          \"route\": \"/docs/with-nextjs\",\n          \"title\": \"Next.js SSG and SSR\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"typescript\",\n          \"route\": \"/docs/typescript\",\n          \"title\": \"Typescript\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"suspense\",\n          \"route\": \"/docs/suspense\",\n          \"title\": \"Suspense\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"middleware\",\n          \"route\": \"/docs/middleware\",\n          \"title\": \"Middleware\",\n          \"type\": \"doc\",\n        },\n        {\n          \"children\": [\n            {\n              \"name\": \"cache\",\n              \"route\": \"/docs/advanced/cache\",\n              \"title\": \"Cache\",\n              \"type\": \"doc\",\n            },\n            {\n              \"name\": \"performance\",\n              \"route\": \"/docs/advanced/performance\",\n              \"title\": \"Performance\",\n              \"type\": \"doc\",\n            },\n            {\n              \"name\": \"react-native\",\n              \"route\": \"/docs/advanced/react-native\",\n              \"title\": \"React Native\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"name\": \"advanced\",\n          \"route\": \"/docs/advanced\",\n          \"title\": \"Advanced\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"change-log\",\n          \"route\": \"/docs/change-log\",\n          \"title\": \"Change Log\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"name\": \"docs\",\n      \"route\": \"/docs\",\n      \"title\": \"Docs\",\n      \"type\": \"doc\",\n    },\n    {\n      \"name\": \"getting-started\",\n      \"route\": \"/docs/getting-started\",\n      \"title\": \"Getting Started\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"activeThemeContext\": {\n    \"breadcrumb\": true,\n    \"collapsed\": undefined,\n    \"copyPage\": true,\n    \"footer\": true,\n    \"layout\": \"default\",\n    \"navbar\": true,\n    \"pagination\": true,\n    \"sidebar\": true,\n    \"timestamp\": true,\n    \"toc\": true,\n    \"typesetting\": \"default\",\n  },\n  \"activeType\": \"doc\",\n  \"directories\": [\n    {\n      \"frontMatter\": {\n        \"title\": \"React Hooks for Data Fetching\",\n      },\n      \"name\": \"index\",\n      \"route\": \"/\",\n      \"title\": \"Introduction\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"name\": \"getting-started\",\n          \"route\": \"/docs/getting-started\",\n          \"title\": \"Getting Started\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"options\",\n          \"route\": \"/docs/options\",\n          \"title\": \"Options\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"global-configuration\",\n          \"route\": \"/docs/global-configuration\",\n          \"title\": \"Global Configuration\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"data-fetching\",\n          \"route\": \"/docs/data-fetching\",\n          \"title\": \"Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"error-handling\",\n          \"route\": \"/docs/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"revalidation\",\n          \"route\": \"/docs/revalidation\",\n          \"title\": \"Auto Revalidation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"conditional-fetching\",\n          \"route\": \"/docs/conditional-fetching\",\n          \"title\": \"Conditional Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"arguments\",\n          \"route\": \"/docs/arguments\",\n          \"title\": \"Arguments\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"mutation\",\n          \"route\": \"/docs/mutation\",\n          \"title\": \"Mutation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"pagination\",\n          \"route\": \"/docs/pagination\",\n          \"title\": \"Pagination\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"prefetching\",\n          \"route\": \"/docs/prefetching\",\n          \"title\": \"Prefetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"with-nextjs\",\n          \"route\": \"/docs/with-nextjs\",\n          \"title\": \"Next.js SSG and SSR\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"typescript\",\n          \"route\": \"/docs/typescript\",\n          \"title\": \"Typescript\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"suspense\",\n          \"route\": \"/docs/suspense\",\n          \"title\": \"Suspense\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"middleware\",\n          \"route\": \"/docs/middleware\",\n          \"title\": \"Middleware\",\n          \"type\": \"doc\",\n        },\n        {\n          \"children\": [\n            {\n              \"name\": \"cache\",\n              \"route\": \"/docs/advanced/cache\",\n              \"title\": \"Cache\",\n              \"type\": \"doc\",\n            },\n            {\n              \"name\": \"performance\",\n              \"route\": \"/docs/advanced/performance\",\n              \"title\": \"Performance\",\n              \"type\": \"doc\",\n            },\n            {\n              \"name\": \"react-native\",\n              \"route\": \"/docs/advanced/react-native\",\n              \"title\": \"React Native\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"name\": \"advanced\",\n          \"route\": \"/docs/advanced\",\n          \"title\": \"Advanced\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"change-log\",\n          \"route\": \"/docs/change-log\",\n          \"title\": \"Change Log\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"name\": \"docs\",\n      \"route\": \"/docs\",\n      \"title\": \"Docs\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"title\": \"Basic Usage\",\n          },\n          \"name\": \"basic\",\n          \"route\": \"/examples/basic\",\n          \"title\": \"Basic Usage\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Authentication\",\n          },\n          \"name\": \"auth\",\n          \"route\": \"/examples/auth\",\n          \"title\": \"Authentication\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Infinite Loading\",\n          },\n          \"name\": \"infinite-loading\",\n          \"route\": \"/examples/infinite-loading\",\n          \"title\": \"Infinite Loading\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Error Handling\",\n          },\n          \"name\": \"error-handling\",\n          \"route\": \"/examples/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Next.js SSR\",\n          },\n          \"name\": \"ssr\",\n          \"route\": \"/examples/ssr\",\n          \"title\": \"Next.js SSR\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"name\": \"examples\",\n      \"route\": \"/examples\",\n      \"title\": \"Examples\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"description\": \"Almost 2 years ago we open sourced SWR, the tiny data-fetching React library that people love. Today we are reaching another milestone: the 1.0 version of SWR.\",\n            \"image\": \"https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\",\n          },\n          \"name\": \"swr-v1\",\n          \"route\": \"/blog/swr-v1\",\n          \"title\": \"Announcing SWR 1.0\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"name\": \"blog\",\n      \"route\": \"/blog\",\n      \"title\": \"Blog\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"docsDirectories\": [\n    {\n      \"frontMatter\": {\n        \"title\": \"React Hooks for Data Fetching\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"index\",\n      \"route\": \"/\",\n      \"title\": \"Introduction\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"getting-started\",\n          \"route\": \"/docs/getting-started\",\n          \"title\": \"Getting Started\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"options\",\n          \"route\": \"/docs/options\",\n          \"title\": \"Options\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"global-configuration\",\n          \"route\": \"/docs/global-configuration\",\n          \"title\": \"Global Configuration\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"data-fetching\",\n          \"route\": \"/docs/data-fetching\",\n          \"title\": \"Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"error-handling\",\n          \"route\": \"/docs/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"revalidation\",\n          \"route\": \"/docs/revalidation\",\n          \"title\": \"Auto Revalidation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"conditional-fetching\",\n          \"route\": \"/docs/conditional-fetching\",\n          \"title\": \"Conditional Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"arguments\",\n          \"route\": \"/docs/arguments\",\n          \"title\": \"Arguments\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"mutation\",\n          \"route\": \"/docs/mutation\",\n          \"title\": \"Mutation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"pagination\",\n          \"route\": \"/docs/pagination\",\n          \"title\": \"Pagination\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"prefetching\",\n          \"route\": \"/docs/prefetching\",\n          \"title\": \"Prefetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"with-nextjs\",\n          \"route\": \"/docs/with-nextjs\",\n          \"title\": \"Next.js SSG and SSR\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"typescript\",\n          \"route\": \"/docs/typescript\",\n          \"title\": \"Typescript\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"suspense\",\n          \"route\": \"/docs/suspense\",\n          \"title\": \"Suspense\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"middleware\",\n          \"route\": \"/docs/middleware\",\n          \"title\": \"Middleware\",\n          \"type\": \"doc\",\n        },\n        {\n          \"children\": [\n            {\n              \"isUnderCurrentDocsTree\": true,\n              \"name\": \"cache\",\n              \"route\": \"/docs/advanced/cache\",\n              \"title\": \"Cache\",\n              \"type\": \"doc\",\n            },\n            {\n              \"isUnderCurrentDocsTree\": true,\n              \"name\": \"performance\",\n              \"route\": \"/docs/advanced/performance\",\n              \"title\": \"Performance\",\n              \"type\": \"doc\",\n            },\n            {\n              \"isUnderCurrentDocsTree\": true,\n              \"name\": \"react-native\",\n              \"route\": \"/docs/advanced/react-native\",\n              \"title\": \"React Native\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"advanced\",\n          \"route\": \"/docs/advanced\",\n          \"title\": \"Advanced\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"change-log\",\n          \"route\": \"/docs/change-log\",\n          \"title\": \"Change Log\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"docs\",\n      \"route\": \"/docs\",\n      \"title\": \"Docs\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"title\": \"Basic Usage\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"basic\",\n          \"route\": \"/examples/basic\",\n          \"title\": \"Basic Usage\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Authentication\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"auth\",\n          \"route\": \"/examples/auth\",\n          \"title\": \"Authentication\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Infinite Loading\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"infinite-loading\",\n          \"route\": \"/examples/infinite-loading\",\n          \"title\": \"Infinite Loading\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Error Handling\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"error-handling\",\n          \"route\": \"/examples/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Next.js SSR\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"ssr\",\n          \"route\": \"/examples/ssr\",\n          \"title\": \"Next.js SSR\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"examples\",\n      \"route\": \"/examples\",\n      \"title\": \"Examples\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"description\": \"Almost 2 years ago we open sourced SWR, the tiny data-fetching React library that people love. Today we are reaching another milestone: the 1.0 version of SWR.\",\n            \"image\": \"https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"swr-v1\",\n          \"route\": \"/blog/swr-v1\",\n          \"title\": \"Announcing SWR 1.0\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"blog\",\n      \"route\": \"/blog\",\n      \"title\": \"Blog\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"flatDocsDirectories\": [\n    {\n      \"frontMatter\": {\n        \"title\": \"React Hooks for Data Fetching\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"index\",\n      \"route\": \"/\",\n      \"title\": \"Introduction\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"getting-started\",\n      \"route\": \"/docs/getting-started\",\n      \"title\": \"Getting Started\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"options\",\n      \"route\": \"/docs/options\",\n      \"title\": \"Options\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"global-configuration\",\n      \"route\": \"/docs/global-configuration\",\n      \"title\": \"Global Configuration\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"data-fetching\",\n      \"route\": \"/docs/data-fetching\",\n      \"title\": \"Data Fetching\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"error-handling\",\n      \"route\": \"/docs/error-handling\",\n      \"title\": \"Error Handling\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"revalidation\",\n      \"route\": \"/docs/revalidation\",\n      \"title\": \"Auto Revalidation\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"conditional-fetching\",\n      \"route\": \"/docs/conditional-fetching\",\n      \"title\": \"Conditional Data Fetching\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"arguments\",\n      \"route\": \"/docs/arguments\",\n      \"title\": \"Arguments\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"mutation\",\n      \"route\": \"/docs/mutation\",\n      \"title\": \"Mutation\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"pagination\",\n      \"route\": \"/docs/pagination\",\n      \"title\": \"Pagination\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"prefetching\",\n      \"route\": \"/docs/prefetching\",\n      \"title\": \"Prefetching\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"with-nextjs\",\n      \"route\": \"/docs/with-nextjs\",\n      \"title\": \"Next.js SSG and SSR\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"typescript\",\n      \"route\": \"/docs/typescript\",\n      \"title\": \"Typescript\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"suspense\",\n      \"route\": \"/docs/suspense\",\n      \"title\": \"Suspense\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"middleware\",\n      \"route\": \"/docs/middleware\",\n      \"title\": \"Middleware\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"cache\",\n      \"route\": \"/docs/advanced/cache\",\n      \"title\": \"Cache\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"performance\",\n      \"route\": \"/docs/advanced/performance\",\n      \"title\": \"Performance\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"react-native\",\n      \"route\": \"/docs/advanced/react-native\",\n      \"title\": \"React Native\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"change-log\",\n      \"route\": \"/docs/change-log\",\n      \"title\": \"Change Log\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Basic Usage\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"basic\",\n      \"route\": \"/examples/basic\",\n      \"title\": \"Basic Usage\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Authentication\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"auth\",\n      \"route\": \"/examples/auth\",\n      \"title\": \"Authentication\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Infinite Loading\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"infinite-loading\",\n      \"route\": \"/examples/infinite-loading\",\n      \"title\": \"Infinite Loading\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Error Handling\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"error-handling\",\n      \"route\": \"/examples/error-handling\",\n      \"title\": \"Error Handling\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Next.js SSR\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"ssr\",\n      \"route\": \"/examples/ssr\",\n      \"title\": \"Next.js SSR\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"description\": \"Almost 2 years ago we open sourced SWR, the tiny data-fetching React library that people love. Today we are reaching another milestone: the 1.0 version of SWR.\",\n        \"image\": \"https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"swr-v1\",\n      \"route\": \"/blog/swr-v1\",\n      \"title\": \"Announcing SWR 1.0\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"topLevelNavbarItems\": [],\n}\n`;\n\nexports[`normalize-page > en-US home 1`] = `\n{\n  \"activeIndex\": 0,\n  \"activeMetadata\": {\n    \"title\": \"React Hooks for Data Fetching\",\n  },\n  \"activePath\": [\n    {\n      \"frontMatter\": {\n        \"title\": \"React Hooks for Data Fetching\",\n      },\n      \"name\": \"index\",\n      \"route\": \"/\",\n      \"title\": \"Introduction\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"activeThemeContext\": {\n    \"breadcrumb\": true,\n    \"collapsed\": undefined,\n    \"copyPage\": true,\n    \"footer\": true,\n    \"layout\": \"default\",\n    \"navbar\": true,\n    \"pagination\": true,\n    \"sidebar\": true,\n    \"timestamp\": true,\n    \"toc\": true,\n    \"typesetting\": \"default\",\n  },\n  \"activeType\": \"doc\",\n  \"directories\": [\n    {\n      \"frontMatter\": {\n        \"title\": \"React Hooks for Data Fetching\",\n      },\n      \"name\": \"index\",\n      \"route\": \"/\",\n      \"title\": \"Introduction\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"name\": \"getting-started\",\n          \"route\": \"/docs/getting-started\",\n          \"title\": \"Getting Started\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"options\",\n          \"route\": \"/docs/options\",\n          \"title\": \"Options\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"global-configuration\",\n          \"route\": \"/docs/global-configuration\",\n          \"title\": \"Global Configuration\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"data-fetching\",\n          \"route\": \"/docs/data-fetching\",\n          \"title\": \"Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"error-handling\",\n          \"route\": \"/docs/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"revalidation\",\n          \"route\": \"/docs/revalidation\",\n          \"title\": \"Auto Revalidation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"conditional-fetching\",\n          \"route\": \"/docs/conditional-fetching\",\n          \"title\": \"Conditional Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"arguments\",\n          \"route\": \"/docs/arguments\",\n          \"title\": \"Arguments\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"mutation\",\n          \"route\": \"/docs/mutation\",\n          \"title\": \"Mutation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"pagination\",\n          \"route\": \"/docs/pagination\",\n          \"title\": \"Pagination\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"prefetching\",\n          \"route\": \"/docs/prefetching\",\n          \"title\": \"Prefetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"with-nextjs\",\n          \"route\": \"/docs/with-nextjs\",\n          \"title\": \"Next.js SSG and SSR\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"typescript\",\n          \"route\": \"/docs/typescript\",\n          \"title\": \"Typescript\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"suspense\",\n          \"route\": \"/docs/suspense\",\n          \"title\": \"Suspense\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"middleware\",\n          \"route\": \"/docs/middleware\",\n          \"title\": \"Middleware\",\n          \"type\": \"doc\",\n        },\n        {\n          \"children\": [\n            {\n              \"name\": \"cache\",\n              \"route\": \"/docs/advanced/cache\",\n              \"title\": \"Cache\",\n              \"type\": \"doc\",\n            },\n            {\n              \"name\": \"performance\",\n              \"route\": \"/docs/advanced/performance\",\n              \"title\": \"Performance\",\n              \"type\": \"doc\",\n            },\n            {\n              \"name\": \"react-native\",\n              \"route\": \"/docs/advanced/react-native\",\n              \"title\": \"React Native\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"name\": \"advanced\",\n          \"route\": \"/docs/advanced\",\n          \"title\": \"Advanced\",\n          \"type\": \"doc\",\n        },\n        {\n          \"name\": \"change-log\",\n          \"route\": \"/docs/change-log\",\n          \"title\": \"Change Log\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"name\": \"docs\",\n      \"route\": \"/docs\",\n      \"title\": \"Docs\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"title\": \"Basic Usage\",\n          },\n          \"name\": \"basic\",\n          \"route\": \"/examples/basic\",\n          \"title\": \"Basic Usage\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Authentication\",\n          },\n          \"name\": \"auth\",\n          \"route\": \"/examples/auth\",\n          \"title\": \"Authentication\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Infinite Loading\",\n          },\n          \"name\": \"infinite-loading\",\n          \"route\": \"/examples/infinite-loading\",\n          \"title\": \"Infinite Loading\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Error Handling\",\n          },\n          \"name\": \"error-handling\",\n          \"route\": \"/examples/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Next.js SSR\",\n          },\n          \"name\": \"ssr\",\n          \"route\": \"/examples/ssr\",\n          \"title\": \"Next.js SSR\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"name\": \"examples\",\n      \"route\": \"/examples\",\n      \"title\": \"Examples\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"description\": \"Almost 2 years ago we open sourced SWR, the tiny data-fetching React library that people love. Today we are reaching another milestone: the 1.0 version of SWR.\",\n            \"image\": \"https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\",\n          },\n          \"name\": \"swr-v1\",\n          \"route\": \"/blog/swr-v1\",\n          \"title\": \"Announcing SWR 1.0\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"name\": \"blog\",\n      \"route\": \"/blog\",\n      \"title\": \"Blog\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"docsDirectories\": [\n    {\n      \"frontMatter\": {\n        \"title\": \"React Hooks for Data Fetching\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"index\",\n      \"route\": \"/\",\n      \"title\": \"Introduction\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"getting-started\",\n          \"route\": \"/docs/getting-started\",\n          \"title\": \"Getting Started\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"options\",\n          \"route\": \"/docs/options\",\n          \"title\": \"Options\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"global-configuration\",\n          \"route\": \"/docs/global-configuration\",\n          \"title\": \"Global Configuration\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"data-fetching\",\n          \"route\": \"/docs/data-fetching\",\n          \"title\": \"Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"error-handling\",\n          \"route\": \"/docs/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"revalidation\",\n          \"route\": \"/docs/revalidation\",\n          \"title\": \"Auto Revalidation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"conditional-fetching\",\n          \"route\": \"/docs/conditional-fetching\",\n          \"title\": \"Conditional Data Fetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"arguments\",\n          \"route\": \"/docs/arguments\",\n          \"title\": \"Arguments\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"mutation\",\n          \"route\": \"/docs/mutation\",\n          \"title\": \"Mutation\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"pagination\",\n          \"route\": \"/docs/pagination\",\n          \"title\": \"Pagination\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"prefetching\",\n          \"route\": \"/docs/prefetching\",\n          \"title\": \"Prefetching\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"with-nextjs\",\n          \"route\": \"/docs/with-nextjs\",\n          \"title\": \"Next.js SSG and SSR\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"typescript\",\n          \"route\": \"/docs/typescript\",\n          \"title\": \"Typescript\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"suspense\",\n          \"route\": \"/docs/suspense\",\n          \"title\": \"Suspense\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"middleware\",\n          \"route\": \"/docs/middleware\",\n          \"title\": \"Middleware\",\n          \"type\": \"doc\",\n        },\n        {\n          \"children\": [\n            {\n              \"isUnderCurrentDocsTree\": true,\n              \"name\": \"cache\",\n              \"route\": \"/docs/advanced/cache\",\n              \"title\": \"Cache\",\n              \"type\": \"doc\",\n            },\n            {\n              \"isUnderCurrentDocsTree\": true,\n              \"name\": \"performance\",\n              \"route\": \"/docs/advanced/performance\",\n              \"title\": \"Performance\",\n              \"type\": \"doc\",\n            },\n            {\n              \"isUnderCurrentDocsTree\": true,\n              \"name\": \"react-native\",\n              \"route\": \"/docs/advanced/react-native\",\n              \"title\": \"React Native\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"advanced\",\n          \"route\": \"/docs/advanced\",\n          \"title\": \"Advanced\",\n          \"type\": \"doc\",\n        },\n        {\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"change-log\",\n          \"route\": \"/docs/change-log\",\n          \"title\": \"Change Log\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"docs\",\n      \"route\": \"/docs\",\n      \"title\": \"Docs\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"title\": \"Basic Usage\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"basic\",\n          \"route\": \"/examples/basic\",\n          \"title\": \"Basic Usage\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Authentication\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"auth\",\n          \"route\": \"/examples/auth\",\n          \"title\": \"Authentication\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Infinite Loading\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"infinite-loading\",\n          \"route\": \"/examples/infinite-loading\",\n          \"title\": \"Infinite Loading\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Error Handling\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"error-handling\",\n          \"route\": \"/examples/error-handling\",\n          \"title\": \"Error Handling\",\n          \"type\": \"doc\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"Next.js SSR\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"ssr\",\n          \"route\": \"/examples/ssr\",\n          \"title\": \"Next.js SSR\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"examples\",\n      \"route\": \"/examples\",\n      \"title\": \"Examples\",\n      \"type\": \"doc\",\n    },\n    {\n      \"children\": [\n        {\n          \"frontMatter\": {\n            \"description\": \"Almost 2 years ago we open sourced SWR, the tiny data-fetching React library that people love. Today we are reaching another milestone: the 1.0 version of SWR.\",\n            \"image\": \"https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\",\n          },\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"swr-v1\",\n          \"route\": \"/blog/swr-v1\",\n          \"title\": \"Announcing SWR 1.0\",\n          \"type\": \"doc\",\n        },\n      ],\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"blog\",\n      \"route\": \"/blog\",\n      \"title\": \"Blog\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"flatDocsDirectories\": [\n    {\n      \"frontMatter\": {\n        \"title\": \"React Hooks for Data Fetching\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"index\",\n      \"route\": \"/\",\n      \"title\": \"Introduction\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"getting-started\",\n      \"route\": \"/docs/getting-started\",\n      \"title\": \"Getting Started\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"options\",\n      \"route\": \"/docs/options\",\n      \"title\": \"Options\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"global-configuration\",\n      \"route\": \"/docs/global-configuration\",\n      \"title\": \"Global Configuration\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"data-fetching\",\n      \"route\": \"/docs/data-fetching\",\n      \"title\": \"Data Fetching\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"error-handling\",\n      \"route\": \"/docs/error-handling\",\n      \"title\": \"Error Handling\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"revalidation\",\n      \"route\": \"/docs/revalidation\",\n      \"title\": \"Auto Revalidation\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"conditional-fetching\",\n      \"route\": \"/docs/conditional-fetching\",\n      \"title\": \"Conditional Data Fetching\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"arguments\",\n      \"route\": \"/docs/arguments\",\n      \"title\": \"Arguments\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"mutation\",\n      \"route\": \"/docs/mutation\",\n      \"title\": \"Mutation\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"pagination\",\n      \"route\": \"/docs/pagination\",\n      \"title\": \"Pagination\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"prefetching\",\n      \"route\": \"/docs/prefetching\",\n      \"title\": \"Prefetching\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"with-nextjs\",\n      \"route\": \"/docs/with-nextjs\",\n      \"title\": \"Next.js SSG and SSR\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"typescript\",\n      \"route\": \"/docs/typescript\",\n      \"title\": \"Typescript\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"suspense\",\n      \"route\": \"/docs/suspense\",\n      \"title\": \"Suspense\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"middleware\",\n      \"route\": \"/docs/middleware\",\n      \"title\": \"Middleware\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"cache\",\n      \"route\": \"/docs/advanced/cache\",\n      \"title\": \"Cache\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"performance\",\n      \"route\": \"/docs/advanced/performance\",\n      \"title\": \"Performance\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"react-native\",\n      \"route\": \"/docs/advanced/react-native\",\n      \"title\": \"React Native\",\n      \"type\": \"doc\",\n    },\n    {\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"change-log\",\n      \"route\": \"/docs/change-log\",\n      \"title\": \"Change Log\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Basic Usage\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"basic\",\n      \"route\": \"/examples/basic\",\n      \"title\": \"Basic Usage\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Authentication\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"auth\",\n      \"route\": \"/examples/auth\",\n      \"title\": \"Authentication\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Infinite Loading\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"infinite-loading\",\n      \"route\": \"/examples/infinite-loading\",\n      \"title\": \"Infinite Loading\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Error Handling\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"error-handling\",\n      \"route\": \"/examples/error-handling\",\n      \"title\": \"Error Handling\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"title\": \"Next.js SSR\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"ssr\",\n      \"route\": \"/examples/ssr\",\n      \"title\": \"Next.js SSR\",\n      \"type\": \"doc\",\n    },\n    {\n      \"frontMatter\": {\n        \"description\": \"Almost 2 years ago we open sourced SWR, the tiny data-fetching React library that people love. Today we are reaching another milestone: the 1.0 version of SWR.\",\n        \"image\": \"https://assets.vercel.com/image/upload/v1630059453/swr/v1.png\",\n      },\n      \"isUnderCurrentDocsTree\": true,\n      \"name\": \"swr-v1\",\n      \"route\": \"/blog/swr-v1\",\n      \"title\": \"Announcing SWR 1.0\",\n      \"type\": \"doc\",\n    },\n  ],\n  \"topLevelNavbarItems\": [],\n}\n`;\n\nexports[`normalize-page > should keep \\`activeThemeContext\\`, \\`activeType\\` for hidden route 1`] = `\n{\n  \"activeIndex\": 0,\n  \"activeMetadata\": undefined,\n  \"activePath\": [],\n  \"activeThemeContext\": {\n    \"breadcrumb\": true,\n    \"collapsed\": undefined,\n    \"copyPage\": true,\n    \"footer\": true,\n    \"layout\": \"full\",\n    \"navbar\": true,\n    \"pagination\": true,\n    \"sidebar\": false,\n    \"timestamp\": true,\n    \"toc\": false,\n    \"typesetting\": \"article\",\n  },\n  \"activeType\": \"page\",\n  \"directories\": [],\n  \"docsDirectories\": [],\n  \"flatDocsDirectories\": [],\n  \"topLevelNavbarItems\": [],\n}\n`;\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/compile-metadata.test.ts",
    "content": "import { compileMetadata } from '../compile-metadata.js'\n\ndescribe('compileMetadata()', () => {\n  it('should remove everything', () => {\n    const mdx = `---\ntitle: Foo\ndescription: Bar\n---\n\n# A\n\n## B\n\n### C\n\n#### D\n\n##### E\n\n###### F\n\n- a\n- b\n- c\n\n> q\n\nexport const MyComponent = () => null\n\n<MyComponent />\n`\n    const result = compileMetadata(mdx, { filePath: 'foo.mdx' })\n    return expect(result).resolves.toMatchInlineSnapshot(`\n      \"import {Fragment as _Fragment, jsx as _jsx} from \"react/jsx-runtime\";\n      export const metadata = {\n        \"title\": \"Foo\",\n        \"description\": \"Bar\",\n        \"filePath\": \"foo.mdx\"\n      };\n      \"\n    `)\n  })\n  it('should remove everything with export default', () => {\n    const result = compileMetadata('export { default } from \"./foo.mdx\"', {\n      filePath: 'bar.mdx'\n    })\n    return expect(result).resolves.toMatchInlineSnapshot(`\n      \"import {Fragment as _Fragment, jsx as _jsx} from \"react/jsx-runtime\";\n      export const metadata = {\n        \"title\": \"Bar\",\n        \"filePath\": \"bar.mdx\"\n      };\n      \"\n    `)\n  })\n\n  it('should remove everything for `format: \"md\"` which is by default', () => {\n    const result = compileMetadata(\n      `\n<!-- export title: \"Foo\" -->\n\n# world`,\n      { filePath: 'foo.md' }\n    )\n    return expect(result).resolves.toMatchInlineSnapshot(`\n      \"import {Fragment as _Fragment, jsx as _jsx} from \"react/jsx-runtime\";\n      export const metadata = {\n        \"title\": \"world\",\n        \"filePath\": \"foo.md\"\n      };\n      \"\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/compile.test.ts",
    "content": "import { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\nconst mdxOptions = {\n  jsx: true,\n  outputFormat: 'program' as const\n}\n\ndescribe('Compile', () => {\n  it('should work with export default', async () => {\n    const rawJs = await compileMdx(\n      `import foo from './foo'\n      \n## heading\n\nexport default foo`,\n      { mdxOptions }\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { HOC_MDXWrapper } from 'nextra/setup-page'\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {}\n      import foo from './foo'\n      const MDXLayout = foo\n      export const sourceCode = \"import foo from './foo'\\n      \\n## heading\\n\\nexport default foo\"\n      function useTOC(props) {\n        return [\n          {\n            value: 'heading',\n            id: 'heading',\n            depth: 2\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          h2: 'h2',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n      }\n      function MDXContent(props = {}) {\n        return (\n          <MDXLayout {...props}>\n            <_createMdxContent {...props} />\n          </MDXLayout>\n        )\n      }\n      export default HOC_MDXWrapper(MDXContent, {\n        metadata,\n        toc,\n        sourceCode\n      })\"\n    `)\n  })\n  it('should work with export as default', async () => {\n    const rawJs = await compileMdx(\n      `## heading\n      \nexport { foo as default } from './foo'`,\n      { mdxOptions }\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {}\n      import { foo as MDXLayout } from './foo'\n      export const sourceCode = \"## heading\\n      \\nexport { foo as default } from './foo'\"\n      function useTOC(props) {\n        return [\n          {\n            value: 'heading',\n            id: 'heading',\n            depth: 2\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          h2: 'h2',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n      }\n      export default _createMdxContent\"\n    `)\n  })\n})\n\ndescribe('Process heading', () => {\n  it('code-h1', async () => {\n    const rawJs = await compileMdx('# `codegen.yml`', { mdxOptions })\n    return expect(clean(rawJs)).resolves.toMatchSnapshot()\n  })\n  it('code-with-text-h1', async () => {\n    const rawJs = await compileMdx('# `codegen.yml` file', { mdxOptions })\n    return expect(clean(rawJs)).resolves.toMatchSnapshot()\n  })\n  it('static-h1', async () => {\n    const rawJs = await compileMdx('# Hello World', { mdxOptions })\n    return expect(clean(rawJs)).resolves.toMatchSnapshot()\n  })\n  it('dynamic-h1', async () => {\n    const rawJs = await compileMdx(\n      `\nimport { useRouter } from 'next/router'\n\nexport const TagName = () => {\n  const { tag } = useRouter().query\n  return tag || null\n}\n\n# Posts Tagged with \"<TagName/>\"\n    `,\n      { mdxOptions }\n    )\n    return expect(clean(rawJs)).resolves.toMatchSnapshot()\n  })\n  it('no-h1', async () => {\n    const rawJs = await compileMdx('## H2', { mdxOptions })\n    return expect(clean(rawJs)).resolves.toMatchSnapshot()\n  })\n  it('use custom heading id', async () => {\n    const rawJs = await compileMdx(\n      `\n# My Header [#test-id]\n## Some extra space [#extra-space]&nbsp;\n### Some extra space in heading    [#extra-space-in-heading]\n### nospace[#without-space]\n#### foo [#другой язык]\n##### bar Baz []\n###### bar Qux [#]`,\n      { mdxOptions }\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {\n        title: 'My Header'\n      }\n      export const sourceCode =\n        '# My Header [#test-id]\\n## Some extra space [#extra-space]&nbsp;\\n### Some extra space in heading    [#extra-space-in-heading]\\n### nospace[#without-space]\\n#### foo [#другой язык]\\n##### bar Baz []\\n###### bar Qux [#]'\n      function useTOC(props) {\n        return [\n          {\n            value: 'Some extra space',\n            id: 'extra-space',\n            depth: 2\n          },\n          {\n            value: 'Some extra space in heading',\n            id: 'extra-space-in-heading',\n            depth: 3\n          },\n          {\n            value: 'nospace',\n            id: 'without-space',\n            depth: 3\n          },\n          {\n            value: 'foo',\n            id: 'другой-язык',\n            depth: 4\n          },\n          {\n            value: 'bar Baz []',\n            id: 'bar-baz-',\n            depth: 5\n          },\n          {\n            value: 'bar Qux [#]',\n            id: 'bar-qux-',\n            depth: 6\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          h1: 'h1',\n          h2: 'h2',\n          h3: 'h3',\n          h4: 'h4',\n          h5: 'h5',\n          h6: 'h6',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return (\n          <>\n            <_components.h1 id=\"test-id\">{'My Header'}</_components.h1>\n            {'\\n'}\n            <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n            {'\\n'}\n            <_components.h3 id={toc[1].id}>{toc[1].value}</_components.h3>\n            {'\\n'}\n            <_components.h3 id={toc[2].id}>{toc[2].value}</_components.h3>\n            {'\\n'}\n            <_components.h4 id={toc[3].id}>{toc[3].value}</_components.h4>\n            {'\\n'}\n            <_components.h5 id={toc[4].id}>{toc[4].value}</_components.h5>\n            {'\\n'}\n            <_components.h6 id={toc[5].id}>{toc[5].value}</_components.h6>\n          </>\n        )\n      }\n      export default _createMdxContent\"\n    `)\n  })\n  it('use github-slugger', async () => {\n    const rawJs = await compileMdx('### My Header', { mdxOptions })\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {}\n      export const sourceCode = '### My Header'\n      function useTOC(props) {\n        return [\n          {\n            value: 'My Header',\n            id: 'my-header',\n            depth: 3\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          h3: 'h3',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return <_components.h3 id={toc[0].id}>{toc[0].value}</_components.h3>\n      }\n      export default _createMdxContent\"\n    `)\n  })\n\n  it('should merge headings from partial components', async () => {\n    const rawJs = await compileMdx(\n      `\nimport FromMdx from './one.mdx'\nimport FromMarkdown from './two.md'\nimport IgnoreMe from './foo'\n\n## ❤️\n\n<FromMdx />\n\n## ✅\n\n<FromMarkdown />\n\nimport Last from './three.mdx'\n\n<Last />\n\n<IgnoreMe />\n\n## 👋\n\n## kek <Kek />\n\n## \\`try\\` me\n\n## latex $l$\n\n## {'interpolate'} {1} {true} {null} {variable}\n\n`,\n      { mdxOptions, latex: true }\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {}\n      import FromMdx, { toc as toc0 } from './one.mdx'\n      import FromMarkdown, { toc as toc1 } from './two.md'\n      import IgnoreMe from './foo'\n      import Last, { toc as toc2 } from './three.mdx'\n      export const sourceCode =\n        \"import FromMdx from './one.mdx'\\\\nimport FromMarkdown from './two.md'\\\\nimport IgnoreMe from './foo'\\\\n\\\\n## ❤️\\\\n\\\\n<FromMdx />\\\\n\\\\n## ✅\\\\n\\\\n<FromMarkdown />\\\\n\\\\nimport Last from './three.mdx'\\\\n\\\\n<Last />\\\\n\\\\n<IgnoreMe />\\\\n\\\\n## 👋\\\\n\\\\n## kek <Kek />\\\\n\\\\n## \\`try\\` me\\\\n\\\\n## latex $l$\\\\n\\\\n## {'interpolate'} {1} {true} {null} {variable}\"\n      function useTOC(props) {\n        const _components = {\n            annotation: 'annotation',\n            code: 'code',\n            math: 'math',\n            mi: 'mi',\n            mrow: 'mrow',\n            semantics: 'semantics',\n            span: 'span',\n            ..._provideComponents()\n          },\n          { Kek } = _components\n        if (!Kek) _missingMdxReference('Kek', true)\n        return [\n          {\n            value: '❤️',\n            id: '️',\n            depth: 2\n          },\n          ...toc0,\n          {\n            value: '✅',\n            id: '',\n            depth: 2\n          },\n          ...toc1,\n          ...toc2,\n          {\n            value: '👋',\n            id: '-1',\n            depth: 2\n          },\n          {\n            value: (\n              <>\n                {'kek '}\n                <Kek />\n              </>\n            ),\n            id: 'kek-',\n            depth: 2\n          },\n          {\n            value: (\n              <>\n                <_components.code>{'try'}</_components.code>\n                {' me'}\n              </>\n            ),\n            id: 'try-me',\n            depth: 2\n          },\n          {\n            value: (\n              <>\n                {'latex '}\n                <_components.span className=\"katex\">\n                  <_components.span className=\"katex-mathml\">\n                    <_components.math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n                      <_components.semantics>\n                        <_components.mrow>\n                          <_components.mi>{'l'}</_components.mi>\n                        </_components.mrow>\n                        <_components.annotation encoding=\"application/x-tex\">{'l'}</_components.annotation>\n                      </_components.semantics>\n                    </_components.math>\n                  </_components.span>\n                  <_components.span className=\"katex-html\" aria-hidden=\"true\">\n                    <_components.span className=\"base\">\n                      <_components.span\n                        className=\"strut\"\n                        style={{\n                          height: '0.6944em'\n                        }}\n                      />\n                      <_components.span\n                        className=\"mord mathnormal\"\n                        style={{\n                          marginRight: '0.01968em'\n                        }}\n                      >\n                        {'l'}\n                      </_components.span>\n                    </_components.span>\n                  </_components.span>\n                </_components.span>\n              </>\n            ),\n            id: 'latex-l',\n            depth: 2\n          },\n          {\n            value: (\n              <>\n                {'interpolate'} {1} {true} {null} {variable}\n              </>\n            ),\n            id: 'interpolate-1-true-null-variable',\n            depth: 2\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n            annotation: 'annotation',\n            code: 'code',\n            h2: 'h2',\n            math: 'math',\n            mi: 'mi',\n            mrow: 'mrow',\n            semantics: 'semantics',\n            span: 'span',\n            ..._provideComponents(),\n            ...props.components\n          },\n          { Kek } = _components\n        if (!Kek) _missingMdxReference('Kek', true)\n        return (\n          <>\n            <_components.h2 id=\"️\">{'❤️'}</_components.h2>\n            {'\\\\n'}\n            <FromMdx />\n            {'\\\\n'}\n            <_components.h2 id=\"\">{'✅'}</_components.h2>\n            {'\\\\n'}\n            <FromMarkdown />\n            {'\\\\n'}\n            {'\\\\n'}\n            <Last />\n            {'\\\\n'}\n            <IgnoreMe />\n            {'\\\\n'}\n            <_components.h2 id=\"-1\">{'👋'}</_components.h2>\n            {'\\\\n'}\n            <_components.h2 id=\"kek-\">\n              {'kek '}\n              <Kek />\n            </_components.h2>\n            {'\\\\n'}\n            <_components.h2 id=\"try-me\">\n              <_components.code>{'try'}</_components.code>\n              {' me'}\n            </_components.h2>\n            {'\\\\n'}\n            <_components.h2 id=\"latex-l\">\n              {'latex '}\n              <_components.span className=\"katex\">\n                <_components.span className=\"katex-mathml\">\n                  <_components.math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n                    <_components.semantics>\n                      <_components.mrow>\n                        <_components.mi>{'l'}</_components.mi>\n                      </_components.mrow>\n                      <_components.annotation encoding=\"application/x-tex\">{'l'}</_components.annotation>\n                    </_components.semantics>\n                  </_components.math>\n                </_components.span>\n                <_components.span className=\"katex-html\" aria-hidden=\"true\">\n                  <_components.span className=\"base\">\n                    <_components.span\n                      className=\"strut\"\n                      style={{\n                        height: '0.6944em'\n                      }}\n                    />\n                    <_components.span\n                      className=\"mord mathnormal\"\n                      style={{\n                        marginRight: '0.01968em'\n                      }}\n                    >\n                      {'l'}\n                    </_components.span>\n                  </_components.span>\n                </_components.span>\n              </_components.span>\n            </_components.h2>\n            {'\\\\n'}\n            <_components.h2 id=\"interpolate-1-true-null-variable\">\n              {'interpolate'} {1} {true} {null} {variable}\n            </_components.h2>\n          </>\n        )\n      }\n      export default _createMdxContent\n      function _missingMdxReference(id, component) {\n        throw new Error(\n          'Expected ' +\n            (component ? 'component' : 'object') +\n            ' \\`' +\n            id +\n            '\\` to be defined: you likely forgot to import, pass, or provide it.'\n        )\n      }\"\n    `)\n  })\n})\n\ndescribe('Link', () => {\n  it('supports .md links', async () => {\n    const rawJs = await compileMdx('[link](../file.md)', { mdxOptions })\n    expect(rawJs).toMatch('<_components.a href=\"../file\">')\n  })\n\n  it('supports .mdx links', async () => {\n    const rawJs = await compileMdx('[link](../file.mdx)', { mdxOptions })\n    expect(rawJs).toMatch('<_components.a href=\"../file\">')\n  })\n\n  it('supports URL links', async () => {\n    const rawJs = await compileMdx('[link](../file)', { mdxOptions })\n    expect(rawJs).toMatch('<_components.a href=\"../file\">')\n  })\n\n  it('supports query', async () => {\n    const rawJs = await compileMdx('[link](../file.md?query=a)', {\n      mdxOptions\n    })\n    expect(rawJs).toMatch('<_components.a href=\"../file?query=a\">')\n  })\n\n  it('supports anchor', async () => {\n    const rawJs = await compileMdx('[link](../file.md#anchor)', {\n      mdxOptions\n    })\n    expect(rawJs).toMatch('<_components.a href=\"../file#anchor\">')\n  })\n\n  it('supports external .md links', async () => {\n    const rawJs = await compileMdx('[link](https://example.com/file.md)', {\n      mdxOptions\n    })\n    expect(rawJs).toMatch('<_components.a href=\"https://example.com/file.md\">')\n  })\n\n  it('supports external .mdx links', async () => {\n    const rawJs = await compileMdx('[link](https://example.com/file.mdx)', {\n      mdxOptions\n    })\n    expect(rawJs).toMatch('<_components.a href=\"https://example.com/file.mdx\">')\n  })\n})\n\ndescribe('Code block', () => {\n  describe('Filename', () => {\n    it('attach with \"codeHighlight: true\" by default', async () => {\n      const rawJs = await compileMdx('```text filename=\"test.js\"\\n```', {\n        mdxOptions,\n        search: true\n      })\n      expect(rawJs).toMatch(\n        '<_components.pre tabIndex=\"0\" data-language=\"text\" data-word-wrap=\"\" data-filename=\"test.js\">'\n      )\n    })\n\n    it('attach with \"codeHighlight: false\"', async () => {\n      const rawJs = await compileMdx('```js filename=\"test.js\"\\n```', {\n        mdxOptions,\n        codeHighlight: false\n      })\n      expect(rawJs).toMatch(\n        '<_components.pre data-filename=\"test.js\" data-word-wrap=\"\">'\n      )\n    })\n\n    it('not highlight filename as substring', async () => {\n      const rawJs = await compileMdx('```js filename=\"/foo/\"\\nfoo\\n```', {\n        mdxOptions,\n        codeHighlight: true // processed only by rehype-pretty-code\n      })\n      expect(rawJs).not.toMatch(\n        'className=\"highlighted\">{\"foo\"}</_components.span>'\n      )\n      expect(rawJs).toMatch('}}>{\"foo\"}</_components.span>')\n    })\n  })\n\n  describe('Highlight', () => {\n    it('should support line highlights', async () => {\n      const rawJs = await compileMdx('```js filename=\"test.js\" {1}\\n123\\n```', {\n        mdxOptions\n      })\n      expect(rawJs).toMatch('<_components.span data-highlighted-line=\"\">')\n    })\n  })\n\n  describe('Copy code button', () => {\n    for (const codeHighlight of [true, false]) {\n      describe(`codeHighlight: ${codeHighlight}`, () => {\n        it('attach with \"copy\"', async () => {\n          const rawJs = await compileMdx('```js copy\\n```', {\n            mdxOptions,\n            codeHighlight,\n            search: true\n          })\n          expect(rawJs).toMatch('data-word-wrap=\"\" data-copy=\"\">')\n        })\n\n        it('attach with \"defaultShowCopyCode: true\"', async () => {\n          const rawJs = await compileMdx('```js\\n```', {\n            mdxOptions,\n            defaultShowCopyCode: true,\n            codeHighlight,\n            search: true\n          })\n          expect(rawJs).toMatch('data-word-wrap=\"\" data-copy=\"\">')\n        })\n\n        it('not attach with \"defaultShowCopyCode: true\" and \"copy=false\"', async () => {\n          const rawJs = await compileMdx('```js copy=false\\n```', {\n            mdxOptions,\n            defaultShowCopyCode: true,\n            codeHighlight\n          })\n          expect(rawJs).not.toMatch('data-copy=\"\"')\n        })\n      })\n    }\n  })\n\n  describe('toc', () => {\n    it('should attach heading', async () => {\n      const rawMdx = `<Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\"1\">\n  <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n  <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n  <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n</Tabs>\n`\n      const rawJs = await compileMdx(rawMdx + rawMdx, {\n        mdxOptions\n      })\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {}\n        export const sourceCode =\n          \"<Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\\\\\"1\\\\\">\\\\n  <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\\\\n  <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\\\\n  <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\\\\n</Tabs>\\\\n<Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\\\\\"1\\\\\">\\\\n  <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\\\\n  <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\\\\n  <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\\\\n</Tabs>\"\n        function useTOC(props) {\n          return []\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n              strong: 'strong',\n              ..._provideComponents(),\n              ...props.components\n            },\n            { Tabs } = _components\n          if (!Tabs) _missingMdxReference('Tabs', true)\n          if (!Tabs.Tab) _missingMdxReference('Tabs.Tab', true)\n          return (\n            <>\n              <Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\"1\">\n                <Tabs.Tab>\n                  <h3\n                    id=\"pnpm\"\n                    style={{\n                      visibility: 'hidden',\n                      width: 0,\n                      height: 0\n                    }}\n                  >\n                    {'pnpm'}\n                  </h3>\n                  <_components.strong>{'pnpm'}</_components.strong>\n                  {': Fast, disk space efficient package manager.'}\n                </Tabs.Tab>\n                <Tabs.Tab>\n                  <h3\n                    id=\"npm\"\n                    style={{\n                      visibility: 'hidden',\n                      width: 0,\n                      height: 0\n                    }}\n                  >\n                    {'npm'}\n                  </h3>\n                  <_components.strong>{'npm'}</_components.strong>\n                  {' is a package manager for the JavaScript programming language.'}\n                </Tabs.Tab>\n                <Tabs.Tab>\n                  <h3\n                    id=\"yarn\"\n                    style={{\n                      visibility: 'hidden',\n                      width: 0,\n                      height: 0\n                    }}\n                  >\n                    {'yarn'}\n                  </h3>\n                  <_components.strong>{'Yarn'}</_components.strong>\n                  {' is a software packaging system.'}\n                </Tabs.Tab>\n              </Tabs>\n              {'\\\\n'}\n              <Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\"1\">\n                <Tabs.Tab>\n                  <h3\n                    id=\"pnpm-1\"\n                    style={{\n                      visibility: 'hidden',\n                      width: 0,\n                      height: 0\n                    }}\n                  >\n                    {'pnpm'}\n                  </h3>\n                  <_components.strong>{'pnpm'}</_components.strong>\n                  {': Fast, disk space efficient package manager.'}\n                </Tabs.Tab>\n                <Tabs.Tab>\n                  <h3\n                    id=\"npm-1\"\n                    style={{\n                      visibility: 'hidden',\n                      width: 0,\n                      height: 0\n                    }}\n                  >\n                    {'npm'}\n                  </h3>\n                  <_components.strong>{'npm'}</_components.strong>\n                  {' is a package manager for the JavaScript programming language.'}\n                </Tabs.Tab>\n                <Tabs.Tab>\n                  <h3\n                    id=\"yarn-1\"\n                    style={{\n                      visibility: 'hidden',\n                      width: 0,\n                      height: 0\n                    }}\n                  >\n                    {'yarn'}\n                  </h3>\n                  <_components.strong>{'Yarn'}</_components.strong>\n                  {' is a software packaging system.'}\n                </Tabs.Tab>\n              </Tabs>\n            </>\n          )\n        }\n        export default _createMdxContent\n        function _missingMdxReference(id, component) {\n          throw new Error(\n            'Expected ' +\n              (component ? 'component' : 'object') +\n              ' \\`' +\n              id +\n              '\\` to be defined: you likely forgot to import, pass, or provide it.'\n          )\n        }\"\n      `)\n    })\n  })\n\n  it('should attach id to summary', async () => {\n    const rawMdx = `\n<details>\n  <summary>foo</summary>\n  bar\n</details>\n<details>\n  <summary>foo</summary>\n  bar\n</details>\n`\n    const rawJs = await compileMdx(rawMdx, { mdxOptions })\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {}\n      export const sourceCode =\n        '<details>\\n  <summary>foo</summary>\\n  bar\\n</details>\\n<details>\\n  <summary>foo</summary>\\n  bar\\n</details>'\n      function useTOC(props) {\n        return []\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          details: 'details',\n          p: 'p',\n          summary: 'summary',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return (\n          <>\n            <_components.details>\n              <_components.p>\n                <_components.summary id=\"foo\">{'foo'}</_components.summary>\n                {'\\nbar'}\n              </_components.p>\n            </_components.details>\n            {'\\n'}\n            <_components.details>\n              <_components.p>\n                <_components.summary id=\"foo-1\">{'foo'}</_components.summary>\n                {'\\nbar'}\n              </_components.p>\n            </_components.details>\n          </>\n        )\n      }\n      export default _createMdxContent\"\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/active-type-should-be-initialized-from-star/1-level/_meta.ts",
    "content": "export default {\n  '*': {\n    type: 'page',\n    theme: {\n      layout: 'default',\n      toc: false\n    }\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/active-type-should-be-initialized-from-star/1-level/foo.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/active-type-should-be-initialized-from-star/_meta.ts",
    "content": "export default {\n  '1-level': {\n    display: 'hidden',\n    theme: {\n      layout: 'full'\n    }\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/active-type-should-be-initialized-from-star/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.ts\";\nimport _1_level_meta from \"./1-level/_meta.ts\";\nimport {metadata as _1_level_foo} from \"./1-level/foo.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"1-level\",\n  route: \"/1-level\",\n  children: [{\n    data: _1_level_meta\n  }, {\n    name: \"foo\",\n    route: \"/1-level/foo\",\n    frontMatter: _1_level_foo\n  }]\n}])\n\nexport const RouteToFilepath = {\n  \"1-level/foo\": \"1-level/foo.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/first-child-route-should-return-index-as-first/_meta.ts",
    "content": "export default {\n  blog: {\n    type: 'page'\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/first-child-route-should-return-index-as-first/blog/_.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/first-child-route-should-return-index-as-first/blog/a.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/first-child-route-should-return-index-as-first/blog/index.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/first-child-route-should-return-index-as-first/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.ts\";\nimport {metadata as blog_} from \"./blog/_.md?metadata\";\nimport {metadata as blog_a} from \"./blog/a.md?metadata\";\nimport {metadata as blog_index} from \"./blog/index.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"blog\",\n  route: \"/blog\",\n  children: [{\n    name: \"_\",\n    route: \"/blog/_\",\n    frontMatter: blog_\n  }, {\n    name: \"a\",\n    route: \"/blog/a\",\n    frontMatter: blog_a\n  }, {\n    name: \"index\",\n    route: \"/blog\",\n    frontMatter: blog_index\n  }]\n}])\n\nexport const RouteToFilepath = {\n  \"blog/_\": \"blog/_.md\",\n  \"blog/a\": \"blog/a.md\",\n  \"blog\": \"blog/index.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-index-page-and-folder-should-be-merged/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport {metadata as themes_test} from \"./themes-test.md?metadata\";\nimport {metadata as themes_test_foo} from \"./themes-test/foo.md?metadata\";\nimport {metadata as themes} from \"./themes.md?metadata\";\nimport {metadata as themes_bar} from \"./themes/bar.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  name: \"themes-test\",\n  route: \"/themes-test\",\n  children: [{\n    name: \"index\",\n    route: \"/themes-test\",\n    frontMatter: themes_test\n  }, {\n    name: \"foo\",\n    route: \"/themes-test/foo\",\n    frontMatter: themes_test_foo\n  }]\n}, {\n  name: \"themes\",\n  route: \"/themes\",\n  children: [{\n    name: \"index\",\n    route: \"/themes\",\n    frontMatter: themes\n  }, {\n    name: \"bar\",\n    route: \"/themes/bar\",\n    frontMatter: themes_bar\n  }]\n}])\n\nexport const RouteToFilepath = {\n  \"themes-test\": \"themes-test.md\",\n  \"themes-test/foo\": \"themes-test/foo.md\",\n  \"themes\": \"themes.md\",\n  \"themes/bar\": \"themes/bar.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-index-page-and-folder-should-be-merged/themes/bar.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-index-page-and-folder-should-be-merged/themes-test/foo.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-index-page-and-folder-should-be-merged/themes-test.md",
    "content": "export const metadata = { asIndexPage: true }\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-index-page-and-folder-should-be-merged/themes.md",
    "content": "export const metadata = { asIndexPage: true }\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-with-symlinks/docs/test2.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-with-symlinks/pages/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport {metadata as docs_test2} from \"./docs/test2.md?metadata\";\nimport {metadata as test1} from \"./test1.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  name: \"docs\",\n  route: \"/docs\",\n  children: [{\n    name: \"test2\",\n    route: \"/docs/test2\",\n    frontMatter: docs_test2\n  }]\n}, {\n  name: \"test1\",\n  route: \"/test1\",\n  frontMatter: test1\n}])\n\nexport const RouteToFilepath = {\n  \"docs/test2\": \"docs/test2.md\",\n  \"test1\": \"test1.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-with-symlinks/test1.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-without-markdown-files/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\n\nexport const pageMap = normalizePageMap([])\n\nexport const RouteToFilepath = {}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-without-markdown-files/test.ts",
    "content": "// eslint-disable-next-line unicorn/no-empty-file -- For test case\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-without-meta-json/callout.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-without-meta-json/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport {metadata as callout} from \"./callout.md?metadata\";\nimport {metadata as tabs} from \"./tabs.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  name: \"callout\",\n  route: \"/callout\",\n  frontMatter: callout\n}, {\n  name: \"tabs\",\n  route: \"/tabs\",\n  frontMatter: tabs\n}])\n\nexport const RouteToFilepath = {\n  \"callout\": \"callout.md\",\n  \"tabs\": \"tabs.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/folder-without-meta-json/tabs.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/hidden-route-should-have-theme-context/1-level/2-level/_meta.ts",
    "content": "export default {\n  foo: {\n    type: 'page',\n    theme: {\n      sidebar: false,\n      toc: false,\n      layout: 'full'\n    }\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/hidden-route-should-have-theme-context/1-level/2-level/foo.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/hidden-route-should-have-theme-context/1-level/qux.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/hidden-route-should-have-theme-context/_meta.ts",
    "content": "export default {\n  '*': {\n    display: 'hidden',\n    theme: {\n      typesetting: 'article'\n    }\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/hidden-route-should-have-theme-context/bar.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/hidden-route-should-have-theme-context/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.ts\";\nimport _1_level_2_level_meta from \"./1-level/2-level/_meta.ts\";\nimport {metadata as _1_level_2_level_foo} from \"./1-level/2-level/foo.md?metadata\";\nimport {metadata as _1_level_qux} from \"./1-level/qux.md?metadata\";\nimport {metadata as bar} from \"./bar.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"1-level\",\n  route: \"/1-level\",\n  children: [{\n    name: \"2-level\",\n    route: \"/1-level/2-level\",\n    children: [{\n      data: _1_level_2_level_meta\n    }, {\n      name: \"foo\",\n      route: \"/1-level/2-level/foo\",\n      frontMatter: _1_level_2_level_foo\n    }]\n  }, {\n    name: \"qux\",\n    route: \"/1-level/qux\",\n    frontMatter: _1_level_qux\n  }]\n}, {\n  name: \"bar\",\n  route: \"/bar\",\n  frontMatter: bar\n}])\n\nexport const RouteToFilepath = {\n  \"1-level/2-level/foo\": \"1-level/2-level/foo.md\",\n  \"1-level/qux\": \"1-level/qux.md\",\n  \"bar\": \"bar.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/non-english-characters-in-filename/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport {metadata as D1_82_D0_B5_D1_81_D1_82} from \"./тест.mdx?metadata\";\nimport {metadata as E6_B5_8B_E8_AF_95} from \"./测试.mdx?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  name: \"тест\",\n  route: \"/тест\",\n  frontMatter: D1_82_D0_B5_D1_81_D1_82\n}, {\n  name: \"测试\",\n  route: \"/测试\",\n  frontMatter: E6_B5_8B_E8_AF_95\n}])\n\nexport const RouteToFilepath = {\n  \"тест\": \"тест.mdx\",\n  \"测试\": \"测试.mdx\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/non-english-characters-in-filename/тест.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/non-english-characters-in-filename/测试.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/page-map.ts",
    "content": "import type { PageMapItem } from '../../../../types.js'\n\nexport const usPageMap: PageMapItem[] = [\n  {\n    data: {\n      index: 'Introduction',\n      docs: 'Docs',\n      examples: 'Examples',\n      blog: 'Blog'\n    }\n  },\n  {\n    name: 'blog',\n    children: [\n      {\n        data: {\n          'swr-v1': 'Announcing SWR 1.0'\n        }\n      },\n      {\n        name: 'swr-v1',\n        route: '/blog/swr-v1',\n        frontMatter: {\n          image:\n            'https://assets.vercel.com/image/upload/v1630059453/swr/v1.png',\n          description:\n            'Almost 2 years ago we open sourced SWR, the tiny data-fetching React library that people love. Today we are reaching another milestone: the 1.0 version of SWR.'\n        }\n      }\n    ],\n    route: '/blog'\n  },\n  {\n    name: 'docs',\n    children: [\n      {\n        data: {\n          'getting-started': 'Getting Started',\n          options: 'Options',\n          'global-configuration': 'Global Configuration',\n          'data-fetching': 'Data Fetching',\n          'error-handling': 'Error Handling',\n          revalidation: 'Auto Revalidation',\n          'conditional-fetching': 'Conditional Data Fetching',\n          arguments: 'Arguments',\n          mutation: 'Mutation',\n          pagination: 'Pagination',\n          prefetching: 'Prefetching',\n          'with-nextjs': 'Next.js SSG and SSR',\n          typescript: 'Typescript',\n          suspense: 'Suspense',\n          middleware: 'Middleware',\n          advanced: 'Advanced',\n          'change-log': 'Change Log'\n        }\n      },\n      {\n        name: 'advanced',\n        children: [\n          {\n            data: {\n              cache: 'Cache',\n              performance: 'Performance',\n              'react-native': 'React Native'\n            }\n          },\n          {\n            name: 'cache',\n            route: '/docs/advanced/cache'\n          },\n          {\n            name: 'performance',\n            route: '/docs/advanced/performance'\n          },\n          {\n            name: 'react-native',\n            route: '/docs/advanced/react-native'\n          }\n        ],\n        route: '/docs/advanced'\n      },\n      {\n        name: 'arguments',\n        route: '/docs/arguments'\n      },\n      {\n        name: 'change-log',\n        route: '/docs/change-log'\n      },\n      {\n        name: 'conditional-fetching',\n        route: '/docs/conditional-fetching'\n      },\n      {\n        name: 'data-fetching',\n        route: '/docs/data-fetching'\n      },\n      {\n        name: 'error-handling',\n        route: '/docs/error-handling'\n      },\n      {\n        name: 'getting-started',\n        route: '/docs/getting-started'\n      },\n      {\n        name: 'global-configuration',\n        route: '/docs/global-configuration'\n      },\n      {\n        name: 'middleware',\n        route: '/docs/middleware'\n      },\n      {\n        name: 'mutation',\n        route: '/docs/mutation'\n      },\n      {\n        name: 'options',\n        route: '/docs/options'\n      },\n      {\n        name: 'pagination',\n        route: '/docs/pagination'\n      },\n      {\n        name: 'prefetching',\n        route: '/docs/prefetching'\n      },\n      {\n        name: 'revalidation',\n        route: '/docs/revalidation'\n      },\n      {\n        name: 'suspense',\n        route: '/docs/suspense'\n      },\n      {\n        name: 'typescript',\n        route: '/docs/typescript'\n      },\n      {\n        name: 'with-nextjs',\n        route: '/docs/with-nextjs'\n      }\n    ],\n    route: '/docs'\n  },\n  {\n    name: 'examples',\n    children: [\n      {\n        data: {\n          basic: 'Basic Usage',\n          auth: 'Authentication',\n          'infinite-loading': 'Infinite Loading',\n          'error-handling': 'Error Handling',\n          ssr: 'Next.js SSR'\n        }\n      },\n      {\n        name: 'auth',\n        route: '/examples/auth',\n        frontMatter: {\n          title: 'Authentication'\n        }\n      },\n      {\n        name: 'basic',\n        route: '/examples/basic',\n        frontMatter: {\n          title: 'Basic Usage'\n        }\n      },\n      {\n        name: 'error-handling',\n        route: '/examples/error-handling',\n        frontMatter: {\n          title: 'Error Handling'\n        }\n      },\n      {\n        name: 'infinite-loading',\n        route: '/examples/infinite-loading',\n        frontMatter: {\n          title: 'Infinite Loading'\n        }\n      },\n      {\n        name: 'ssr',\n        route: '/examples/ssr',\n        frontMatter: {\n          title: 'Next.js SSR'\n        }\n      }\n    ],\n    route: '/examples'\n  },\n  {\n    name: 'index',\n    route: '/',\n    frontMatter: {\n      title: 'React Hooks for Data Fetching'\n    }\n  }\n]\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/pages-order-without-type-page/_meta.ts",
    "content": "export default {\n  docs: {\n    type: 'page'\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/pages-order-without-type-page/docs/_meta.ts",
    "content": "export default {\n  _: {\n    type: 'separator'\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/pages-order-without-type-page/docs/bar.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/pages-order-without-type-page/foo.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/pages-order-without-type-page/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.ts\";\nimport docs_meta from \"./docs/_meta.ts\";\nimport {metadata as docs_bar} from \"./docs/bar.md?metadata\";\nimport {metadata as foo} from \"./foo.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"docs\",\n  route: \"/docs\",\n  children: [{\n    data: docs_meta\n  }, {\n    name: \"bar\",\n    route: \"/docs/bar\",\n    frontMatter: docs_bar\n  }]\n}, {\n  name: \"foo\",\n  route: \"/foo\",\n  frontMatter: foo\n}])\n\nexport const RouteToFilepath = {\n  \"docs/bar\": \"docs/bar.md\",\n  \"foo\": \"foo.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/respect-order-for-type-separator-menu-and-item-with-href/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport {metadata as one_two_2024} from \"./one/two/2024.md?metadata\";\nimport one_two_meta from \"./one/two/_meta.ts\";\nimport {metadata as one_two_1_one} from \"./one/two/1-one.md?metadata\";\nimport {metadata as one_two_foo} from \"./one/two/foo.md?metadata\";\nimport {metadata as one_two_one} from \"./one/two/one.md?metadata\";\nimport {metadata as one_two_qux} from \"./one/two/qux.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  name: \"one\",\n  route: \"/one\",\n  children: [{\n    name: \"two\",\n    route: \"/one/two\",\n    children: [{\n      name: \"2024\",\n      route: \"/one/two/2024\",\n      frontMatter: one_two_2024\n    }, {\n      data: one_two_meta\n    }, {\n      name: \"1-one\",\n      route: \"/one/two/1-one\",\n      frontMatter: one_two_1_one\n    }, {\n      name: \"foo\",\n      route: \"/one/two/foo\",\n      frontMatter: one_two_foo\n    }, {\n      name: \"one\",\n      route: \"/one/two/one\",\n      frontMatter: one_two_one\n    }, {\n      name: \"qux\",\n      route: \"/one/two/qux\",\n      frontMatter: one_two_qux\n    }]\n  }]\n}])\n\nexport const RouteToFilepath = {\n  \"one/two/1-one\": \"one/two/1-one.md\",\n  \"one/two/2024\": \"one/two/2024.md\",\n  \"one/two/foo\": \"one/two/foo.md\",\n  \"one/two/one\": \"one/two/one.md\",\n  \"one/two/qux\": \"one/two/qux.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/respect-order-for-type-separator-menu-and-item-with-href/one/two/1-one.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/respect-order-for-type-separator-menu-and-item-with-href/one/two/2024.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/respect-order-for-type-separator-menu-and-item-with-href/one/two/_meta.ts",
    "content": "export default {\n  menu: {\n    type: 'menu',\n    items: {\n      nextra: {\n        title: 'Nextra',\n        href: 'https://nextra.site'\n      }\n    }\n  },\n  '---': {\n    type: 'separator'\n  },\n  qux: '',\n  nextra: {\n    title: 'Nextra',\n    href: 'https://nextra.site'\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/respect-order-for-type-separator-menu-and-item-with-href/one/two/foo.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/respect-order-for-type-separator-menu-and-item-with-href/one/two/one.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/respect-order-for-type-separator-menu-and-item-with-href/one/two/qux.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/should-move-file-with-index-name/_meta.ts",
    "content": "export default {\n  foo: '',\n  index: ''\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/should-move-file-with-index-name/foo.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/should-move-file-with-index-name/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.ts\";\nimport {metadata as foo} from \"./foo.mdx?metadata\";\nimport {metadata as index} from \"./index.mdx?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"foo\",\n  route: \"/foo\",\n  frontMatter: foo\n}, {\n  name: \"index\",\n  route: \"/\",\n  frontMatter: index\n}])\n\nexport const RouteToFilepath = {\n  \"foo\": \"foo.mdx\",\n  \"\": \"index.mdx\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/should-move-file-with-index-name/index.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/should-rename-folder/_meta.js",
    "content": "export default {\n  test: 'HELLO'\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/should-rename-folder/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.js\";\nimport {metadata as test_foo} from \"./test/foo.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"test\",\n  route: \"/test\",\n  children: [{\n    name: \"foo\",\n    route: \"/test/foo\",\n    frontMatter: test_foo\n  }]\n}])\n\nexport const RouteToFilepath = {\n  \"test/foo\": \"test/foo.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/should-rename-folder/test/foo.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/1-meta.mdx",
    "content": "export const metadata = {\n  sidebarTitle: 'from sidebarTitle',\n  title: 'from title'\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/2-sidebar-title.mdx",
    "content": "export const metadata = {\n  sidebarTitle: 'from sidebarTitle',\n  title: 'from title'\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/3-title.mdx",
    "content": "export const metadata = {\n  title: 'from title'\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/4-from-filename.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/_meta.ts",
    "content": "export default {\n  _: {\n    type: 'separator'\n  },\n  folder: 'from meta',\n  'folder-with-index': '',\n  '1-meta': 'from meta',\n  '2-sidebar-title': '',\n  '3-title': '',\n  '4-from-filename': '',\n  _2: {\n    type: 'separator',\n    title: 'separator with title'\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/folder/bar.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/folder/index.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/folder-with-index/foo.mdx",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/folder-with-index/index.mdx",
    "content": "export const metadata = {\n  asIndexPage: true,\n  sidebarTitle: 'from sidebarTitle',\n  title: 'from title'\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/title/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.ts\";\nimport {metadata as _1_meta} from \"./1-meta.mdx?metadata\";\nimport {metadata as _2_sidebar_title} from \"./2-sidebar-title.mdx?metadata\";\nimport {metadata as _3_title} from \"./3-title.mdx?metadata\";\nimport {metadata as _4_from_filename} from \"./4-from-filename.mdx?metadata\";\nimport {metadata as folder_with_index_foo} from \"./folder-with-index/foo.mdx?metadata\";\nimport {metadata as folder_with_index_index} from \"./folder-with-index/index.mdx?metadata\";\nimport {metadata as folder_bar} from \"./folder/bar.mdx?metadata\";\nimport {metadata as folder_index} from \"./folder/index.mdx?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"1-meta\",\n  route: \"/1-meta\",\n  frontMatter: _1_meta\n}, {\n  name: \"2-sidebar-title\",\n  route: \"/2-sidebar-title\",\n  frontMatter: _2_sidebar_title\n}, {\n  name: \"3-title\",\n  route: \"/3-title\",\n  frontMatter: _3_title\n}, {\n  name: \"4-from-filename\",\n  route: \"/4-from-filename\",\n  frontMatter: _4_from_filename\n}, {\n  name: \"folder-with-index\",\n  route: \"/folder-with-index\",\n  children: [{\n    name: \"foo\",\n    route: \"/folder-with-index/foo\",\n    frontMatter: folder_with_index_foo\n  }, {\n    name: \"index\",\n    route: \"/folder-with-index\",\n    frontMatter: folder_with_index_index\n  }]\n}, {\n  name: \"folder\",\n  route: \"/folder\",\n  children: [{\n    name: \"bar\",\n    route: \"/folder/bar\",\n    frontMatter: folder_bar\n  }, {\n    name: \"index\",\n    route: \"/folder\",\n    frontMatter: folder_index\n  }]\n}])\n\nexport const RouteToFilepath = {\n  \"1-meta\": \"1-meta.mdx\",\n  \"2-sidebar-title\": \"2-sidebar-title.mdx\",\n  \"3-title\": \"3-title.mdx\",\n  \"4-from-filename\": \"4-from-filename.mdx\",\n  \"folder-with-index/foo\": \"folder-with-index/foo.mdx\",\n  \"folder-with-index\": \"folder-with-index/index.mdx\",\n  \"folder/bar\": \"folder/bar.mdx\",\n  \"folder\": \"folder/index.mdx\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-items/_meta.ts",
    "content": "export default {\n  mix: {\n    type: 'menu',\n    title: 'Mix',\n    items: {\n      nextra: {\n        title: 'Nextra',\n        href: 'https://nextra.site'\n      },\n      qux: ''\n    }\n  },\n  hrefOnly: {\n    type: 'menu',\n    title: 'Href Only',\n    items: {\n      nextra: {\n        title: 'Nextra',\n        href: 'https://nextra.site'\n      }\n    }\n  },\n  pagesOnly: {\n    type: 'menu',\n    title: 'Pages Only',\n    items: {\n      one: '',\n      two: ''\n    }\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-items/generated-page-map.ts",
    "content": "// @ts-nocheck\nimport { normalizePageMap } from 'nextra/page-map'\n\nimport meta from \"./_meta.ts\";\nimport {metadata as mix_not_specified} from \"./mix/not-specified.md?metadata\";\nimport {metadata as mix_qux} from \"./mix/qux.md?metadata\";\nimport {metadata as pagesOnly_one} from \"./pagesOnly/one.md?metadata\";\nimport {metadata as pagesOnly_two} from \"./pagesOnly/two.md?metadata\";\n\nexport const pageMap = normalizePageMap([{\n  data: meta\n}, {\n  name: \"mix\",\n  route: \"/mix\",\n  children: [{\n    name: \"not-specified\",\n    route: \"/mix/not-specified\",\n    frontMatter: mix_not_specified\n  }, {\n    name: \"qux\",\n    route: \"/mix/qux\",\n    frontMatter: mix_qux\n  }]\n}, {\n  name: \"pagesOnly\",\n  route: \"/pagesOnly\",\n  children: [{\n    name: \"one\",\n    route: \"/pagesOnly/one\",\n    frontMatter: pagesOnly_one\n  }, {\n    name: \"two\",\n    route: \"/pagesOnly/two\",\n    frontMatter: pagesOnly_two\n  }]\n}])\n\nexport const RouteToFilepath = {\n  \"mix/not-specified\": \"mix/not-specified.md\",\n  \"mix/qux\": \"mix/qux.md\",\n  \"pagesOnly/one\": \"pagesOnly/one.md\",\n  \"pagesOnly/two\": \"pagesOnly/two.md\"\n}"
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-items/mix/not-specified.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-items/mix/qux.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-items/pagesOnly/one.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-items/pagesOnly/two.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-local-pages/mix/not-specified.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-local-pages/mix/qux.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/fixture/page-maps/type-menu-should-contain-local-pages/one/bar.md",
    "content": ""
  },
  {
    "path": "packages/nextra/src/server/__tests__/latex.test.ts",
    "content": "import { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\nconst options = {\n  mdxOptions: { jsx: true },\n  latex: true\n}\n\ndescribe('LaTeX', () => {\n  describe('KaTeX', () => {\n    it('should convert ```math code block language', async () => {\n      const rawJs = await compileMdx('```math\\nx^2\\n```', options)\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        'use strict'\n        const { useMDXComponents: _provideComponents } = arguments[0]\n        const metadata = {}\n        const sourceCode = '\\`\\`\\`math\\\\nx^2\\\\n\\`\\`\\`'\n        function useTOC(props) {\n          return []\n        }\n        const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            annotation: 'annotation',\n            math: 'math',\n            mi: 'mi',\n            mn: 'mn',\n            mrow: 'mrow',\n            msup: 'msup',\n            semantics: 'semantics',\n            span: 'span',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return (\n            <_components.span className=\"katex-display\">\n              <_components.span className=\"katex\">\n                <_components.span className=\"katex-mathml\">\n                  <_components.math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\">\n                    <_components.semantics>\n                      <_components.mrow>\n                        <_components.msup>\n                          <_components.mi>{'x'}</_components.mi>\n                          <_components.mn>{'2'}</_components.mn>\n                        </_components.msup>\n                      </_components.mrow>\n                      <_components.annotation encoding=\"application/x-tex\">{'x^2\\\\n'}</_components.annotation>\n                    </_components.semantics>\n                  </_components.math>\n                </_components.span>\n                <_components.span className=\"katex-html\" aria-hidden=\"true\">\n                  <_components.span className=\"base\">\n                    <_components.span\n                      className=\"strut\"\n                      style={{\n                        height: '0.8641em'\n                      }}\n                    />\n                    <_components.span className=\"mord\">\n                      <_components.span className=\"mord mathnormal\">{'x'}</_components.span>\n                      <_components.span className=\"msupsub\">\n                        <_components.span className=\"vlist-t\">\n                          <_components.span className=\"vlist-r\">\n                            <_components.span\n                              className=\"vlist\"\n                              style={{\n                                height: '0.8641em'\n                              }}\n                            >\n                              <_components.span\n                                style={{\n                                  top: '-3.113em',\n                                  marginRight: '0.05em'\n                                }}\n                              >\n                                <_components.span\n                                  className=\"pstrut\"\n                                  style={{\n                                    height: '2.7em'\n                                  }}\n                                />\n                                <_components.span className=\"sizing reset-size6 size3 mtight\">\n                                  <_components.span className=\"mord mtight\">{'2'}</_components.span>\n                                </_components.span>\n                              </_components.span>\n                            </_components.span>\n                          </_components.span>\n                        </_components.span>\n                      </_components.span>\n                    </_components.span>\n                  </_components.span>\n                </_components.span>\n              </_components.span>\n            </_components.span>\n          )\n        }\n        return {\n          metadata,\n          sourceCode,\n          toc,\n          default: _createMdxContent\n        }\"\n      `)\n    })\n  })\n\n  describe('MathJax', () => {\n    const options = {\n      mdxOptions: { jsx: true, outputFormat: 'program' },\n      latex: { renderer: 'mathjax' }\n    } as const\n\n    const INLINE_MATH = String.raw`$a=\\sqrt{b^2 + c^2}$`\n    const MATH_LANG = '```math\\nx^2\\n```'\n\n    it('should convert math inline', async () => {\n      const rawJs = await compileMdx(INLINE_MATH, options)\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {}\n        export const sourceCode = '$a=\\\\sqrt{b^2 + c^2}$'\n        import { MathJax, MathJaxContext } from 'nextra/components'\n        function useTOC(props) {\n          return []\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            p: 'p',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return (\n            <MathJaxContext>\n              {'\\n'}\n              <_components.p>\n                <MathJax inline>{'\\\\(a=\\\\sqrt{b^2 + c^2}\\\\)'}</MathJax>\n              </_components.p>\n              {'\\n'}\n            </MathJaxContext>\n          )\n        }\n        export default _createMdxContent\"\n      `)\n    })\n\n    it('should convert ```math code block language', async () => {\n      const rawJs = await compileMdx(MATH_LANG, options)\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {}\n        export const sourceCode = '\\`\\`\\`math\\\\nx^2\\\\n\\`\\`\\`'\n        import { MathJax, MathJaxContext } from 'nextra/components'\n        function useTOC(props) {\n          return []\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          return (\n            <MathJaxContext>\n              {'\\\\n'}\n              <MathJax>{'\\\\\\\\[x^2\\\\n\\\\\\\\]'}</MathJax>\n              {'\\\\n'}\n            </MathJaxContext>\n          )\n        }\n        export default _createMdxContent\"\n      `)\n    })\n\n    it('should add imports only once, and move imports/exports at top', async () => {\n      const rawMdx = `${INLINE_MATH}\n\nimport foo from 'foo'\n\nexport let bar\n\n${MATH_LANG}`\n      const rawJs = await compileMdx(rawMdx, options)\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {}\n        import foo from 'foo'\n        export let bar\n        export const sourceCode = \"$a=\\\\\\\\sqrt{b^2 + c^2}$\\\\n\\\\nimport foo from 'foo'\\\\n\\\\nexport let bar\\\\n\\\\n\\`\\`\\`math\\\\nx^2\\\\n\\`\\`\\`\"\n        import { MathJax, MathJaxContext } from 'nextra/components'\n        function useTOC(props) {\n          return []\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            p: 'p',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return (\n            <MathJaxContext>\n              {'\\\\n'}\n              <_components.p>\n                <MathJax inline>{'\\\\\\\\(a=\\\\\\\\sqrt{b^2 + c^2}\\\\\\\\)'}</MathJax>\n              </_components.p>\n              {'\\\\n'}\n              {'\\\\n'}\n              {'\\\\n'}\n              <MathJax>{'\\\\\\\\[x^2\\\\n\\\\\\\\]'}</MathJax>\n              {'\\\\n'}\n            </MathJaxContext>\n          )\n        }\n        export default _createMdxContent\"\n      `)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/merge-meta-with-page-map.test.ts",
    "content": "import type { Folder } from '../../types.js'\nimport { convertToPageMap } from '../page-map/index.js'\nimport { mergeMetaWithPageMap } from '../page-map/merge-meta-with-page-map.js'\n\ndescribe('mergeMetaWithPageMap', () => {\n  it('should collect', async () => {\n    const filePaths = [\n      'configs.mdx',\n      'custom-rules.mdx',\n      'getting-started.mdx',\n      'getting-started/parser-options.mdx',\n      'getting-started/parser.mdx',\n      'index.mdx'\n    ]\n\n    const { pageMap } = convertToPageMap({\n      filePaths,\n      basePath: 'remote/graphql-eslint'\n    })\n    const [eslintPage] = (pageMap[0] as Folder).children\n\n    // @ts-expect-error -- fixme\n    const result = mergeMetaWithPageMap(eslintPage, {\n      index: 'Introduction',\n      'getting-started': {\n        items: {\n          'parser-options': 'Parser Options',\n          parser: 'Parser'\n        }\n      },\n      configs: 'Configs',\n      'custom-rules': 'Custom Rules'\n    })\n\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"children\": [\n          {\n            \"data\": {\n              \"configs\": \"Configs\",\n              \"custom-rules\": \"Custom Rules\",\n              \"getting-started\": {},\n              \"index\": \"Introduction\",\n            },\n          },\n          {\n            \"name\": \"configs\",\n            \"route\": \"/remote/graphql-eslint/configs\",\n          },\n          {\n            \"name\": \"custom-rules\",\n            \"route\": \"/remote/graphql-eslint/custom-rules\",\n          },\n          {\n            \"children\": [\n              {\n                \"data\": {\n                  \"parser\": \"Parser\",\n                  \"parser-options\": \"Parser Options\",\n                },\n              },\n              {\n                \"name\": \"index\",\n                \"route\": \"/remote/graphql-eslint/getting-started\",\n              },\n              {\n                \"name\": \"parser-options\",\n                \"route\": \"/remote/graphql-eslint/getting-started/parser-options\",\n              },\n              {\n                \"name\": \"parser\",\n                \"route\": \"/remote/graphql-eslint/getting-started/parser\",\n              },\n            ],\n            \"name\": \"getting-started\",\n            \"route\": \"/remote/graphql-eslint/getting-started\",\n          },\n          {\n            \"name\": \"index\",\n            \"route\": \"/remote/graphql-eslint\",\n          },\n        ],\n        \"name\": \"graphql-eslint\",\n        \"route\": \"/remote/graphql-eslint\",\n      }\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/nextra-config.test-d.ts",
    "content": "import type { z } from 'zod'\nimport type { HeadPropsSchema } from '../../client/components/head.js'\nimport type { HeadProps, NextraConfig } from '../../types.generated.js'\nimport type { NextraConfigSchema } from '../schemas.js'\nimport type { IsEqual } from './test-utils.js'\n\ndescribe('Assert types', () => {\n  it('foo should be a `string`', () => {\n    type Expected = { foo: string }\n    type Actual = { foo: number }\n    assertType<IsEqual<Expected, Actual>>(false)\n    return expectTypeOf<Actual>().not.toEqualTypeOf<Expected>\n  })\n  it('foo.bar should be a `string`', () => {\n    type Expected = { foo: { bar: string } }\n    type Actual = { foo: { bar: number } }\n    assertType<IsEqual<Expected, Actual>>(false)\n    return expectTypeOf<Actual>().not.toEqualTypeOf<Expected>\n  })\n  it('foo should be optional', () => {\n    type Expected = { foo?: string }\n    type Actual = { foo: string }\n    assertType<IsEqual<Expected, Actual>>(false)\n    return expectTypeOf<Actual>().not.toEqualTypeOf<Expected>\n  })\n  it('foo should be optional, not `undefined`', () => {\n    type Expected = { foo?: string }\n    type Actual = { foo: string | undefined }\n    assertType<IsEqual<Expected, Actual>>(false)\n    return expectTypeOf<Actual>().not.toEqualTypeOf<Expected>\n  })\n  it('NextraConfig should be identical', () => {\n    type Expected = z.input<typeof NextraConfigSchema>\n    type Actual = NextraConfig\n    return expectTypeOf<Actual>().toEqualTypeOf<Expected>\n  })\n  it.skip('HeadProps should be identical', () => {\n    type _Expected = z.input<typeof HeadPropsSchema>\n    type _Actual = HeadProps\n    // TODO: fix `backgroundColor`\n    // return expectTypeOf<Actual>().toEqualTypeOf<Expected>\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/normalize.test.ts",
    "content": "import { normalizePages } from '../../client/normalize-pages.js'\nimport { normalizePageMap } from '../page-map/normalize.js'\nimport { usPageMap } from './fixture/page-maps/page-map.js'\nimport { getPageMapForFixture } from './test-utils.js'\n\ndescribe('normalize-page', () => {\n  it('en-US home', () => {\n    const result = normalizePages({\n      list: normalizePageMap(usPageMap),\n      route: '/'\n    })\n    expect(result).toMatchSnapshot()\n  })\n\n  it('en-US getting-started', () => {\n    const result = normalizePages({\n      list: normalizePageMap(usPageMap),\n      route: '/docs/getting-started'\n    })\n    expect(result).toMatchSnapshot()\n  })\n\n  // https://github.com/shuding/nextra/issues/3331\n  it('should keep `activeThemeContext`, `activeType` for hidden route', async () => {\n    const pageMap = await getPageMapForFixture(\n      'hidden-route-should-have-theme-context'\n    )\n    expect(pageMap).toEqual([\n      {\n        data: {\n          '*': {\n            display: 'hidden',\n            theme: {\n              typesetting: 'article'\n            }\n          }\n        }\n      },\n      {\n        name: '1-level',\n        route: '/1-level',\n        title: '1 Level',\n        children: [\n          {\n            name: '2-level',\n            route: '/1-level/2-level',\n            title: '2 Level',\n            children: [\n              {\n                data: {\n                  foo: {\n                    type: 'page',\n                    theme: {\n                      layout: 'full',\n                      sidebar: false,\n                      toc: false\n                    }\n                  }\n                }\n              },\n              {\n                name: 'foo',\n                route: '/1-level/2-level/foo',\n                frontMatter: undefined,\n                title: 'Foo'\n              }\n            ]\n          },\n          {\n            name: 'qux',\n            route: '/1-level/qux',\n            frontMatter: undefined,\n            title: 'Qux'\n          }\n        ]\n      },\n      {\n        name: 'bar',\n        route: '/bar',\n        frontMatter: undefined,\n        title: 'Bar'\n      }\n    ])\n\n    const result2 = normalizePages({\n      list: normalizePageMap(pageMap),\n      route: '/1-level/2-level/foo'\n    })\n    expect(result2).toMatchSnapshot()\n  })\n\n  it('should initialize `activeType` from `*`', async () => {\n    const pageMap = await getPageMapForFixture(\n      'active-type-should-be-initialized-from-star'\n    )\n    expect(pageMap).toEqual([\n      {\n        data: {\n          '1-level': {\n            display: 'hidden',\n            theme: {\n              layout: 'full'\n            }\n          }\n        }\n      },\n      {\n        name: '1-level',\n        route: '/1-level',\n        title: '1 Level',\n        children: [\n          {\n            data: {\n              '*': {\n                type: 'page',\n                theme: {\n                  layout: 'default',\n                  toc: false\n                }\n              }\n            }\n          },\n          {\n            name: 'foo',\n            route: '/1-level/foo',\n            frontMatter: undefined,\n            title: 'Foo'\n          }\n        ]\n      }\n    ])\n\n    const { activeType, activeIndex, activeThemeContext } = normalizePages({\n      list: normalizePageMap(pageMap),\n      route: '/1-level/not-exist'\n    })\n    expect({ activeType, activeIndex, activeThemeContext }).toEqual({\n      activeType: 'page',\n      activeIndex: 0,\n      activeThemeContext: {\n        breadcrumb: true,\n        collapsed: undefined,\n        copyPage: true,\n        footer: true,\n        layout: 'default',\n        navbar: true,\n        pagination: true,\n        sidebar: true,\n        timestamp: true,\n        toc: false,\n        typesetting: 'default'\n      }\n    })\n  })\n\n  it('should respect order for `type: \"separator\"`, `type: \"menu\"` and item with `href`', async () => {\n    const pageMap = await getPageMapForFixture(\n      'respect-order-for-type-separator-menu-and-item-with-href'\n    )\n\n    const normalizedResult = normalizePages({\n      list: normalizePageMap(pageMap),\n      route: '/one/two/qux'\n    })\n    expect(normalizedResult.docsDirectories).toMatchInlineSnapshot(`\n      [\n        {\n          \"children\": [\n            {\n              \"children\": [\n                {\n                  \"isUnderCurrentDocsTree\": true,\n                  \"name\": \"---\",\n                  \"type\": \"separator\",\n                },\n                {\n                  \"frontMatter\": undefined,\n                  \"isUnderCurrentDocsTree\": true,\n                  \"name\": \"qux\",\n                  \"route\": \"/one/two/qux\",\n                  \"title\": \"Qux\",\n                  \"type\": \"doc\",\n                },\n                {\n                  \"href\": \"https://nextra.site\",\n                  \"isUnderCurrentDocsTree\": true,\n                  \"name\": \"nextra\",\n                  \"title\": \"Nextra\",\n                  \"type\": \"doc\",\n                },\n                {\n                  \"frontMatter\": undefined,\n                  \"isUnderCurrentDocsTree\": true,\n                  \"name\": \"1-one\",\n                  \"route\": \"/one/two/1-one\",\n                  \"title\": \"1 One\",\n                  \"type\": \"doc\",\n                },\n                {\n                  \"frontMatter\": undefined,\n                  \"isUnderCurrentDocsTree\": true,\n                  \"name\": \"2024\",\n                  \"route\": \"/one/two/2024\",\n                  \"title\": \"2024\",\n                  \"type\": \"doc\",\n                },\n                {\n                  \"frontMatter\": undefined,\n                  \"isUnderCurrentDocsTree\": true,\n                  \"name\": \"foo\",\n                  \"route\": \"/one/two/foo\",\n                  \"title\": \"Foo\",\n                  \"type\": \"doc\",\n                },\n                {\n                  \"frontMatter\": undefined,\n                  \"isUnderCurrentDocsTree\": true,\n                  \"name\": \"one\",\n                  \"route\": \"/one/two/one\",\n                  \"title\": \"One\",\n                  \"type\": \"doc\",\n                },\n              ],\n              \"isUnderCurrentDocsTree\": true,\n              \"name\": \"two\",\n              \"route\": \"/one/two\",\n              \"title\": \"Two\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"isUnderCurrentDocsTree\": true,\n          \"name\": \"one\",\n          \"route\": \"/one\",\n          \"title\": \"One\",\n          \"type\": \"doc\",\n        },\n      ]\n    `)\n  })\n\n  it('`type: \"menu\"` should contain `items`', async () => {\n    const pageMap = await getPageMapForFixture('type-menu-should-contain-items')\n\n    const normalizedResult = normalizePages({\n      list: normalizePageMap(pageMap),\n      route: '/pagesOnly/one'\n    })\n    expect(\n      normalizedResult.topLevelNavbarItems.find(i => i.name === 'mix')\n    ).toHaveProperty('items')\n    expect(\n      normalizedResult.topLevelNavbarItems.find(i => i.name === 'pagesOnly')\n    ).toHaveProperty('items')\n    expect(normalizedResult.topLevelNavbarItems).toMatchInlineSnapshot(`\n      [\n        {\n          \"children\": [\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"not-specified\",\n              \"route\": \"/mix/not-specified\",\n              \"title\": \"Not Specified\",\n              \"type\": \"doc\",\n            },\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"qux\",\n              \"route\": \"/mix/qux\",\n              \"title\": \"Qux\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"firstChildRoute\": \"/mix/not-specified\",\n          \"items\": {\n            \"nextra\": {\n              \"href\": \"https://nextra.site\",\n              \"title\": \"Nextra\",\n            },\n            \"qux\": {\n              \"title\": \"Qux\",\n            },\n          },\n          \"name\": \"mix\",\n          \"route\": \"/mix\",\n          \"title\": \"Mix\",\n          \"type\": \"menu\",\n        },\n        {\n          \"items\": {\n            \"nextra\": {\n              \"href\": \"https://nextra.site\",\n              \"title\": \"Nextra\",\n            },\n          },\n          \"name\": \"hrefOnly\",\n          \"title\": \"Href Only\",\n          \"type\": \"menu\",\n        },\n        {\n          \"children\": [\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"one\",\n              \"route\": \"/pagesOnly/one\",\n              \"title\": \"One\",\n              \"type\": \"doc\",\n            },\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"two\",\n              \"route\": \"/pagesOnly/two\",\n              \"title\": \"Two\",\n              \"type\": \"doc\",\n            },\n          ],\n          \"firstChildRoute\": \"/pagesOnly/one\",\n          \"items\": {\n            \"one\": {\n              \"title\": \"One\",\n            },\n            \"two\": {\n              \"title\": \"Two\",\n            },\n          },\n          \"name\": \"pagesOnly\",\n          \"route\": \"/pagesOnly\",\n          \"title\": \"Pages Only\",\n          \"type\": \"menu\",\n        },\n      ]\n    `)\n  })\n\n  it('pages order without `type: \"page\"`', async () => {\n    const pageMap = await getPageMapForFixture('pages-order-without-type-page')\n\n    const normalizedResult = normalizePages({\n      list: normalizePageMap(pageMap),\n      route: '/docs/bar'\n    })\n    const { docsDirectories } = normalizedResult\n    expect(docsDirectories[0]!.name).toBe('_')\n    expect(docsDirectories[1]!.route).toBe('/docs/bar')\n    expect(docsDirectories[2]!.route).toBe('/foo')\n  })\n\n  // https://github.com/shuding/nextra/issues/3581\n  it(\"folder's index page and folder itself should be merged\", async () => {\n    const pageMap = await getPageMapForFixture(\n      'folder-index-page-and-folder-should-be-merged'\n    )\n    const normalizedResult = normalizePages({\n      list: pageMap,\n      route: '/themes'\n    })\n    expect(normalizedResult.docsDirectories).toEqual([\n      {\n        name: 'themes',\n        route: '/themes',\n        children: [\n          {\n            name: 'bar',\n            route: '/themes/bar',\n            frontMatter: undefined,\n            type: 'doc',\n            title: 'Bar',\n            isUnderCurrentDocsTree: true\n          }\n        ],\n        frontMatter: {\n          asIndexPage: true\n        },\n        type: 'doc',\n        title: 'Themes',\n        isUnderCurrentDocsTree: true\n      },\n      {\n        name: 'themes-test',\n        route: '/themes-test',\n        children: [\n          {\n            name: 'foo',\n            route: '/themes-test/foo',\n            frontMatter: undefined,\n            type: 'doc',\n            title: 'Foo',\n            isUnderCurrentDocsTree: true\n          }\n        ],\n        frontMatter: {\n          asIndexPage: true\n        },\n        type: 'doc',\n        title: 'Themes Test',\n        isUnderCurrentDocsTree: true\n      }\n    ])\n  })\n\n  it('firstChildRoute should return \"index\" route as first', async () => {\n    const pageMap = await getPageMapForFixture(\n      'first-child-route-should-return-index-as-first'\n    )\n    const normalizedResult = normalizePages({\n      list: pageMap,\n      route: '/'\n    })\n    // @ts-expect-error -- fixme\n    expect(normalizedResult.topLevelNavbarItems[0].firstChildRoute).toBe(\n      '/blog'\n    )\n  })\n\n  it('should rename folder', async () => {\n    const pageMap = await getPageMapForFixture('should-rename-folder')\n    const normalizedResult = normalizePages({\n      list: pageMap,\n      route: '/test/foo'\n    })\n    expect(\n      normalizedResult.docsDirectories.find(o => o.name === 'test')!.title\n    ).toBe('HELLO')\n  })\n\n  it('should move file with `index` name', async () => {\n    const pageMap = await getPageMapForFixture(\n      'should-move-file-with-index-name'\n    )\n    const normalizedResult = normalizePages({\n      list: pageMap,\n      route: '/'\n    })\n    expect(normalizedResult.docsDirectories[0]!.name).toBe('foo')\n    expect(normalizedResult.docsDirectories[1]!.name).toBe('index')\n  })\n\n  it('non-english characters in filename', async () => {\n    const pageMap = await getPageMapForFixture(\n      'non-english-characters-in-filename'\n    )\n    expect(pageMap).toBeInstanceOf(Array)\n  })\n\n  it('title priority', async () => {\n    const pageMap = await getPageMapForFixture('title')\n    expect(pageMap).toMatchInlineSnapshot(`\n      [\n        {\n          \"data\": {\n            \"1-meta\": {\n              \"title\": \"from meta\",\n            },\n            \"2-sidebar-title\": {\n              \"title\": \"\",\n            },\n            \"3-title\": {\n              \"title\": \"\",\n            },\n            \"4-from-filename\": {\n              \"title\": \"\",\n            },\n            \"_\": {\n              \"type\": \"separator\",\n            },\n            \"_2\": {\n              \"title\": \"separator with title\",\n              \"type\": \"separator\",\n            },\n            \"folder\": {\n              \"title\": \"from meta\",\n            },\n            \"folder-with-index\": {\n              \"title\": \"\",\n            },\n          },\n        },\n        {\n          \"name\": \"_\",\n          \"type\": \"separator\",\n        },\n        {\n          \"children\": [\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"index\",\n              \"route\": \"/folder\",\n              \"title\": \"Index\",\n            },\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"bar\",\n              \"route\": \"/folder/bar\",\n              \"title\": \"Bar\",\n            },\n          ],\n          \"name\": \"folder\",\n          \"route\": \"/folder\",\n          \"title\": \"from meta\",\n        },\n        {\n          \"children\": [\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"foo\",\n              \"route\": \"/folder-with-index/foo\",\n              \"title\": \"Foo\",\n            },\n          ],\n          \"frontMatter\": {\n            \"asIndexPage\": true,\n            \"sidebarTitle\": \"from sidebarTitle\",\n            \"title\": \"from title\",\n          },\n          \"name\": \"folder-with-index\",\n          \"route\": \"/folder-with-index\",\n          \"title\": \"from sidebarTitle\",\n        },\n        {\n          \"frontMatter\": {\n            \"sidebarTitle\": \"from sidebarTitle\",\n            \"title\": \"from title\",\n          },\n          \"name\": \"1-meta\",\n          \"route\": \"/1-meta\",\n          \"title\": \"from meta\",\n        },\n        {\n          \"frontMatter\": {\n            \"sidebarTitle\": \"from sidebarTitle\",\n            \"title\": \"from title\",\n          },\n          \"name\": \"2-sidebar-title\",\n          \"route\": \"/2-sidebar-title\",\n          \"title\": \"from sidebarTitle\",\n        },\n        {\n          \"frontMatter\": {\n            \"title\": \"from title\",\n          },\n          \"name\": \"3-title\",\n          \"route\": \"/3-title\",\n          \"title\": \"from title\",\n        },\n        {\n          \"frontMatter\": undefined,\n          \"name\": \"4-from-filename\",\n          \"route\": \"/4-from-filename\",\n          \"title\": \"4 from Filename\",\n        },\n        {\n          \"name\": \"_2\",\n          \"title\": \"separator with title\",\n          \"type\": \"separator\",\n        },\n      ]\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/page-map.test.ts",
    "content": "import { getPageMapForFixture } from './test-utils.js'\n\ndescribe('Page Process', () => {\n  it(\"should not add `_meta.json` file if folder doesn't contain markdown files\", async () => {\n    const pageMap = await getPageMapForFixture('folder-without-markdown-files')\n    expect(pageMap).toEqual([])\n  })\n\n  it(\"should not add `_meta.json` file if it's missing\", async () => {\n    const pageMap = await getPageMapForFixture('folder-without-meta-json')\n    expect(pageMap).toMatchInlineSnapshot(`\n      [\n        {\n          \"frontMatter\": undefined,\n          \"name\": \"callout\",\n          \"route\": \"/callout\",\n          \"title\": \"Callout\",\n        },\n        {\n          \"frontMatter\": undefined,\n          \"name\": \"tabs\",\n          \"route\": \"/tabs\",\n          \"title\": \"Tabs\",\n        },\n      ]\n    `)\n  })\n\n  it('should resolve symlinked files and directories', async () => {\n    const pageMap = await getPageMapForFixture('folder-with-symlinks/pages')\n    expect(pageMap).toMatchInlineSnapshot(`\n      [\n        {\n          \"children\": [\n            {\n              \"frontMatter\": undefined,\n              \"name\": \"test2\",\n              \"route\": \"/docs/test2\",\n              \"title\": \"Test2\",\n            },\n          ],\n          \"name\": \"docs\",\n          \"route\": \"/docs\",\n          \"title\": \"Docs\",\n        },\n        {\n          \"frontMatter\": undefined,\n          \"name\": \"test1\",\n          \"route\": \"/test1\",\n          \"title\": \"Test1\",\n        },\n      ]\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/recma-rewrite.test.ts",
    "content": "import { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\ndescribe('recma-rewrite', () => {\n  const testMdx = `\n# h1\n## h2 content\n### h3 content\n\n- list 1\n- list 2\n  `\n\n  const testMdxWithDefaultExport = `${testMdx}\nexport default function Foo(props) {\n  return <div>Default Export {props.children}</div>\n}\n`\n\n  describe(\"outputFormat: 'function-body'\", () => {\n    it('should work', async () => {\n      const rawMdx = await compileMdx(testMdx)\n      return expect(clean(rawMdx)).resolves.toMatchInlineSnapshot(String.raw`\n        \"'use strict'\n        const { Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs } = arguments[0]\n        const { useMDXComponents: _provideComponents } = arguments[0]\n        const metadata = {\n          title: 'h1'\n        }\n        const sourceCode = '# h1\\n## h2 content\\n### h3 content\\n\\n- list 1\\n- list 2'\n        function useTOC(props) {\n          return [\n            {\n              value: 'h2 content',\n              id: 'h2-content',\n              depth: 2\n            },\n            {\n              value: 'h3 content',\n              id: 'h3-content',\n              depth: 3\n            }\n          ]\n        }\n        const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            h1: 'h1',\n            h2: 'h2',\n            h3: 'h3',\n            li: 'li',\n            ul: 'ul',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return _jsxs(_Fragment, {\n            children: [\n              _jsx(_components.h1, {\n                children: 'h1'\n              }),\n              '\\n',\n              _jsx(_components.h2, {\n                id: toc[0].id,\n                children: toc[0].value\n              }),\n              '\\n',\n              _jsx(_components.h3, {\n                id: toc[1].id,\n                children: toc[1].value\n              }),\n              '\\n',\n              _jsxs(_components.ul, {\n                children: [\n                  '\\n',\n                  _jsx(_components.li, {\n                    children: 'list 1'\n                  }),\n                  '\\n',\n                  _jsx(_components.li, {\n                    children: 'list 2'\n                  }),\n                  '\\n'\n                ]\n              })\n            ]\n          })\n        }\n        return {\n          metadata,\n          sourceCode,\n          toc,\n          default: _createMdxContent\n        }\"\n      `)\n    })\n    it('should work with `export default`', async () => {\n      const rawMdx = await compileMdx(testMdxWithDefaultExport)\n      return expect(clean(rawMdx)).resolves.toMatchInlineSnapshot(String.raw`\n        \"'use strict'\n        const { Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs } = arguments[0]\n        const { useMDXComponents: _provideComponents } = arguments[0]\n        const metadata = {\n          title: 'h1'\n        }\n        const MDXLayout = function Foo(props) {\n          return _jsxs('div', {\n            children: ['Default Export ', props.children]\n          })\n        }\n        const sourceCode =\n          '# h1\\n## h2 content\\n### h3 content\\n\\n- list 1\\n- list 2\\n  \\nexport default function Foo(props) {\\n  return <div>Default Export {props.children}</div>\\n}'\n        function useTOC(props) {\n          return [\n            {\n              value: 'h2 content',\n              id: 'h2-content',\n              depth: 2\n            },\n            {\n              value: 'h3 content',\n              id: 'h3-content',\n              depth: 3\n            }\n          ]\n        }\n        const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            h1: 'h1',\n            h2: 'h2',\n            h3: 'h3',\n            li: 'li',\n            ul: 'ul',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return _jsxs(_Fragment, {\n            children: [\n              _jsx(_components.h1, {\n                children: 'h1'\n              }),\n              '\\n',\n              _jsx(_components.h2, {\n                id: toc[0].id,\n                children: toc[0].value\n              }),\n              '\\n',\n              _jsx(_components.h3, {\n                id: toc[1].id,\n                children: toc[1].value\n              }),\n              '\\n',\n              _jsxs(_components.ul, {\n                children: [\n                  '\\n',\n                  _jsx(_components.li, {\n                    children: 'list 1'\n                  }),\n                  '\\n',\n                  _jsx(_components.li, {\n                    children: 'list 2'\n                  }),\n                  '\\n'\n                ]\n              })\n            ]\n          })\n        }\n        function MDXContent(props = {}) {\n          return _jsx(MDXLayout, {\n            ...props,\n            children: _jsx(_createMdxContent, {\n              ...props\n            })\n          })\n        }\n        return {\n          metadata,\n          sourceCode,\n          toc,\n          default: MDXContent\n        }\"\n      `)\n    })\n\n    it('should replace return statement when there is `_missingMdxReference`', async () => {\n      const rawMdx = await compileMdx(`\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n<MDXRemote />`)\n      return expect(clean(rawMdx)).resolves.toMatchInlineSnapshot(`\n        \"'use strict'\n        const { jsx: _jsx } = arguments[0]\n        const { useMDXComponents: _provideComponents } = arguments[0]\n        const metadata = {}\n        const sourceCode = \"import { MDXRemote } from 'nextra/mdx-remote'\\\\n\\\\n<MDXRemote />\"\n        function useTOC(props) {\n          return []\n        }\n        const toc = useTOC({})\n        function _createMdxContent(props) {\n          const { MDXRemote } = {\n            ..._provideComponents(),\n            ...props.components\n          }\n          if (!MDXRemote) _missingMdxReference('MDXRemote', true)\n          return _jsx(MDXRemote, {})\n        }\n        return {\n          metadata,\n          sourceCode,\n          toc,\n          default: _createMdxContent\n        }\n        function _missingMdxReference(id, component) {\n          throw new Error(\n            'Expected ' +\n              (component ? 'component' : 'object') +\n              ' \\`' +\n              id +\n              '\\` to be defined: you likely forgot to import, pass, or provide it.'\n          )\n        }\"\n      `)\n    })\n  })\n\n  describe(\"outputFormat: 'program'\", () => {\n    const options = {\n      mdxOptions: {\n        outputFormat: 'program' as const,\n        jsx: true\n      }\n    }\n    it('should work', async () => {\n      const rawMdx = await compileMdx(testMdx, options)\n      return expect(clean(rawMdx)).resolves.toMatchInlineSnapshot(String.raw`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {\n          title: 'h1'\n        }\n        export const sourceCode = '# h1\\n## h2 content\\n### h3 content\\n\\n- list 1\\n- list 2'\n        function useTOC(props) {\n          return [\n            {\n              value: 'h2 content',\n              id: 'h2-content',\n              depth: 2\n            },\n            {\n              value: 'h3 content',\n              id: 'h3-content',\n              depth: 3\n            }\n          ]\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            h1: 'h1',\n            h2: 'h2',\n            h3: 'h3',\n            li: 'li',\n            ul: 'ul',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return (\n            <>\n              <_components.h1>{'h1'}</_components.h1>\n              {'\\n'}\n              <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n              {'\\n'}\n              <_components.h3 id={toc[1].id}>{toc[1].value}</_components.h3>\n              {'\\n'}\n              <_components.ul>\n                {'\\n'}\n                <_components.li>{'list 1'}</_components.li>\n                {'\\n'}\n                <_components.li>{'list 2'}</_components.li>\n                {'\\n'}\n              </_components.ul>\n            </>\n          )\n        }\n        export default _createMdxContent\"\n      `)\n    })\n    it('should work with `isPageImport`', async () => {\n      const rawMdx = await compileMdx(testMdx, {\n        ...options,\n        isPageImport: true\n      })\n      return expect(clean(rawMdx)).resolves.toMatchInlineSnapshot(String.raw`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { HOC_MDXWrapper } from 'nextra/setup-page'\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {\n          title: 'h1'\n        }\n        export const sourceCode = '# h1\\n## h2 content\\n### h3 content\\n\\n- list 1\\n- list 2'\n        function useTOC(props) {\n          return [\n            {\n              value: 'h2 content',\n              id: 'h2-content',\n              depth: 2\n            },\n            {\n              value: 'h3 content',\n              id: 'h3-content',\n              depth: 3\n            }\n          ]\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            h1: 'h1',\n            h2: 'h2',\n            h3: 'h3',\n            li: 'li',\n            ul: 'ul',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return (\n            <>\n              <_components.h1>{'h1'}</_components.h1>\n              {'\\n'}\n              <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n              {'\\n'}\n              <_components.h3 id={toc[1].id}>{toc[1].value}</_components.h3>\n              {'\\n'}\n              <_components.ul>\n                {'\\n'}\n                <_components.li>{'list 1'}</_components.li>\n                {'\\n'}\n                <_components.li>{'list 2'}</_components.li>\n                {'\\n'}\n              </_components.ul>\n            </>\n          )\n        }\n        export default HOC_MDXWrapper(_createMdxContent, {\n          metadata,\n          toc,\n          sourceCode\n        })\"\n      `)\n    })\n\n    it('should work with `export default`', async () => {\n      const rawMdx = await compileMdx(testMdxWithDefaultExport, options)\n      return expect(clean(rawMdx)).resolves.toMatchInlineSnapshot(String.raw`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { HOC_MDXWrapper } from 'nextra/setup-page'\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {\n          title: 'h1'\n        }\n        const MDXLayout = function Foo(props) {\n          return <div>Default Export {props.children}</div>\n        }\n        export const sourceCode =\n          '# h1\\n## h2 content\\n### h3 content\\n\\n- list 1\\n- list 2\\n  \\nexport default function Foo(props) {\\n  return <div>Default Export {props.children}</div>\\n}'\n        function useTOC(props) {\n          return [\n            {\n              value: 'h2 content',\n              id: 'h2-content',\n              depth: 2\n            },\n            {\n              value: 'h3 content',\n              id: 'h3-content',\n              depth: 3\n            }\n          ]\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            h1: 'h1',\n            h2: 'h2',\n            h3: 'h3',\n            li: 'li',\n            ul: 'ul',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return (\n            <>\n              <_components.h1>{'h1'}</_components.h1>\n              {'\\n'}\n              <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n              {'\\n'}\n              <_components.h3 id={toc[1].id}>{toc[1].value}</_components.h3>\n              {'\\n'}\n              <_components.ul>\n                {'\\n'}\n                <_components.li>{'list 1'}</_components.li>\n                {'\\n'}\n                <_components.li>{'list 2'}</_components.li>\n                {'\\n'}\n              </_components.ul>\n            </>\n          )\n        }\n        function MDXContent(props = {}) {\n          return (\n            <MDXLayout {...props}>\n              <_createMdxContent {...props} />\n            </MDXLayout>\n          )\n        }\n        export default HOC_MDXWrapper(MDXContent, {\n          metadata,\n          toc,\n          sourceCode\n        })\"\n      `)\n    })\n\n    it('should have styled inline code and anchor', async () => {\n      const rawMdx = await compileMdx(\n        '## A `Theme` [google](https://google.com) $e = mc^2$',\n        {\n          mdxOptions: {\n            ...options.mdxOptions,\n            providerImportSource: '👍'\n          },\n          latex: true\n        }\n      )\n      return expect(clean(rawMdx)).resolves.toMatchInlineSnapshot(`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { useMDXComponents as _provideComponents } from '👍'\n        export const metadata = {}\n        export const sourceCode = '## A \\`Theme\\` [google](https://google.com) $e = mc^2$'\n        function useTOC(props) {\n          const _components = {\n            a: 'a',\n            annotation: 'annotation',\n            code: 'code',\n            math: 'math',\n            mi: 'mi',\n            mn: 'mn',\n            mo: 'mo',\n            mrow: 'mrow',\n            msup: 'msup',\n            semantics: 'semantics',\n            span: 'span',\n            ..._provideComponents()\n          }\n          return [\n            {\n              value: (\n                <>\n                  {'A '}\n                  <_components.code>{'Theme'}</_components.code>{' '}\n                  <_components.a href=\"https://google.com\">{'google'}</_components.a>{' '}\n                  <_components.span className=\"katex\">\n                    <_components.span className=\"katex-mathml\">\n                      <_components.math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n                        <_components.semantics>\n                          <_components.mrow>\n                            <_components.mi>{'e'}</_components.mi>\n                            <_components.mo>{'='}</_components.mo>\n                            <_components.mi>{'m'}</_components.mi>\n                            <_components.msup>\n                              <_components.mi>{'c'}</_components.mi>\n                              <_components.mn>{'2'}</_components.mn>\n                            </_components.msup>\n                          </_components.mrow>\n                          <_components.annotation encoding=\"application/x-tex\">{'e = mc^2'}</_components.annotation>\n                        </_components.semantics>\n                      </_components.math>\n                    </_components.span>\n                    <_components.span className=\"katex-html\" aria-hidden=\"true\">\n                      <_components.span className=\"base\">\n                        <_components.span\n                          className=\"strut\"\n                          style={{\n                            height: '0.4306em'\n                          }}\n                        />\n                        <_components.span className=\"mord mathnormal\">{'e'}</_components.span>\n                        <_components.span\n                          className=\"mspace\"\n                          style={{\n                            marginRight: '0.2778em'\n                          }}\n                        />\n                        <_components.span className=\"mrel\">{'='}</_components.span>\n                        <_components.span\n                          className=\"mspace\"\n                          style={{\n                            marginRight: '0.2778em'\n                          }}\n                        />\n                      </_components.span>\n                      <_components.span className=\"base\">\n                        <_components.span\n                          className=\"strut\"\n                          style={{\n                            height: '0.8141em'\n                          }}\n                        />\n                        <_components.span className=\"mord mathnormal\">{'m'}</_components.span>\n                        <_components.span className=\"mord\">\n                          <_components.span className=\"mord mathnormal\">{'c'}</_components.span>\n                          <_components.span className=\"msupsub\">\n                            <_components.span className=\"vlist-t\">\n                              <_components.span className=\"vlist-r\">\n                                <_components.span\n                                  className=\"vlist\"\n                                  style={{\n                                    height: '0.8141em'\n                                  }}\n                                >\n                                  <_components.span\n                                    style={{\n                                      top: '-3.063em',\n                                      marginRight: '0.05em'\n                                    }}\n                                  >\n                                    <_components.span\n                                      className=\"pstrut\"\n                                      style={{\n                                        height: '2.7em'\n                                      }}\n                                    />\n                                    <_components.span className=\"sizing reset-size6 size3 mtight\">\n                                      <_components.span className=\"mord mtight\">{'2'}</_components.span>\n                                    </_components.span>\n                                  </_components.span>\n                                </_components.span>\n                              </_components.span>\n                            </_components.span>\n                          </_components.span>\n                        </_components.span>\n                      </_components.span>\n                    </_components.span>\n                  </_components.span>\n                </>\n              ),\n              id: 'a-theme-google-e--mc2',\n              depth: 2\n            }\n          ]\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            h2: 'h2',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n        }\n        export default _createMdxContent\"\n      `)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/rehype-extract-toc-content.test.ts",
    "content": "import { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\nconst opts = {\n  mdxOptions: {\n    jsx: true,\n    outputFormat: 'program'\n  },\n  latex: true\n} as const\n\ndescribe('rehypeExtractTocContent', () => {\n  it('should work with footnotes or user ids', async () => {\n    const rawJs = await compileMdx(\n      `\n## foo\nbar[^1]\n\n[^1]: bar description\n`,\n      opts\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {}\n      export const sourceCode = '## foo\\nbar[^1]\\n\\n[^1]: bar description'\n      function useTOC(props) {\n        return [\n          {\n            value: 'foo',\n            id: 'foo',\n            depth: 2\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          a: 'a',\n          h2: 'h2',\n          li: 'li',\n          ol: 'ol',\n          p: 'p',\n          section: 'section',\n          sup: 'sup',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return (\n          <>\n            <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n            {'\\n'}\n            <_components.p>\n              {'bar'}\n              <_components.sup>\n                <_components.a\n                  href=\"#user-content-fn-1\"\n                  id=\"user-content-fnref-1\"\n                  data-footnote-ref\n                  aria-describedby=\"footnote-label\"\n                >\n                  {'1'}\n                </_components.a>\n              </_components.sup>\n            </_components.p>\n            {'\\n'}\n            {'\\n'}\n            <_components.section data-footnotes className=\"footnotes\">\n              <_components.h2 className=\"sr-only\" id=\"footnote-label\">\n                {'Footnotes'}\n              </_components.h2>\n              {'\\n'}\n              <_components.ol>\n                {'\\n'}\n                <_components.li id=\"user-content-fn-1\">\n                  {'\\n'}\n                  <_components.p>\n                    {'bar description '}\n                    <_components.a\n                      href=\"#user-content-fnref-1\"\n                      data-footnote-backref=\"\"\n                      aria-label=\"Back to reference 1\"\n                      className=\"data-footnote-backref\"\n                    >\n                      {'↩'}\n                    </_components.a>\n                  </_components.p>\n                  {'\\n'}\n                </_components.li>\n                {'\\n'}\n              </_components.ol>\n              {'\\n'}\n            </_components.section>\n          </>\n        )\n      }\n      export default _createMdxContent\"\n    `)\n  })\n\n  it('should fill heading deeply', async () => {\n    const rawJs = await compileMdx(\n      `\nimport { Steps } from 'nextra/components'\n\n## baz qux\n\n<Steps>\n  <div>\n  ### foo bar\n  </div>\n</Steps>\n`,\n      opts\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const metadata = {}\n      import { Steps } from 'nextra/components'\n      export const sourceCode =\n        \"import { Steps } from 'nextra/components'\\n\\n## baz qux\\n\\n<Steps>\\n  <div>\\n  ### foo bar\\n  </div>\\n</Steps>\"\n      function useTOC(props) {\n        return [\n          {\n            value: 'baz qux',\n            id: 'baz-qux',\n            depth: 2\n          },\n          {\n            value: 'foo bar',\n            id: 'foo-bar',\n            depth: 3\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          h2: 'h2',\n          h3: 'h3',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return (\n          <>\n            <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n            {'\\n'}\n            <Steps>\n              <div>\n                <_components.h3 id={toc[1].id}>{toc[1].value}</_components.h3>\n              </div>\n            </Steps>\n          </>\n        )\n      }\n      export default _createMdxContent\"\n    `)\n  })\n\n  it('should extract', async () => {\n    const rawJs = await compileMdx(\n      `\n# Heading 1\n\nexport const myVar = 'interpolated'\n\n## Heading {myVar}\n\n### Heading $latex$\n\n### Heading \\`<Code />:{jsx}\\`\n\nexport const Test = () => <span>Hello</span>\n\n#### <Test /> World\n\n##### String\n\n###### 123\n\n###### Dada 123 true\n\nexport const metadata = {\n  test: 'extract toc content'\n}\n    `,\n      opts\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      export const myVar = 'interpolated'\n      export const Test = () => <span>Hello</span>\n      export const metadata = {\n        test: 'extract toc content',\n        title: 'Heading 1'\n      }\n      export const sourceCode =\n        \"# Heading 1\\\\n\\\\nexport const myVar = 'interpolated'\\\\n\\\\n## Heading {myVar}\\\\n\\\\n### Heading $latex$\\\\n\\\\n### Heading \\`<Code />:{jsx}\\`\\\\n\\\\nexport const Test = () => <span>Hello</span>\\\\n\\\\n#### <Test /> World\\\\n\\\\n##### String\\\\n\\\\n###### 123\\\\n\\\\n###### Dada 123 true\\\\n\\\\nexport const metadata = {\\\\n  test: 'extract toc content'\\\\n}\"\n      function useTOC(props) {\n        const _components = {\n          annotation: 'annotation',\n          code: 'code',\n          math: 'math',\n          mi: 'mi',\n          mrow: 'mrow',\n          semantics: 'semantics',\n          span: 'span',\n          ..._provideComponents()\n        }\n        return [\n          {\n            value: (\n              <>\n                {'Heading '}\n                {myVar}\n              </>\n            ),\n            id: 'heading-myvar',\n            depth: 2\n          },\n          {\n            value: (\n              <>\n                {'Heading '}\n                <_components.span className=\"katex\">\n                  <_components.span className=\"katex-mathml\">\n                    <_components.math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n                      <_components.semantics>\n                        <_components.mrow>\n                          <_components.mi>{'l'}</_components.mi>\n                          <_components.mi>{'a'}</_components.mi>\n                          <_components.mi>{'t'}</_components.mi>\n                          <_components.mi>{'e'}</_components.mi>\n                          <_components.mi>{'x'}</_components.mi>\n                        </_components.mrow>\n                        <_components.annotation encoding=\"application/x-tex\">{'latex'}</_components.annotation>\n                      </_components.semantics>\n                    </_components.math>\n                  </_components.span>\n                  <_components.span className=\"katex-html\" aria-hidden=\"true\">\n                    <_components.span className=\"base\">\n                      <_components.span\n                        className=\"strut\"\n                        style={{\n                          height: '0.6944em'\n                        }}\n                      />\n                      <_components.span\n                        className=\"mord mathnormal\"\n                        style={{\n                          marginRight: '0.01968em'\n                        }}\n                      >\n                        {'l'}\n                      </_components.span>\n                      <_components.span className=\"mord mathnormal\">{'a'}</_components.span>\n                      <_components.span className=\"mord mathnormal\">{'t'}</_components.span>\n                      <_components.span className=\"mord mathnormal\">{'e'}</_components.span>\n                      <_components.span className=\"mord mathnormal\">{'x'}</_components.span>\n                    </_components.span>\n                  </_components.span>\n                </_components.span>\n              </>\n            ),\n            id: 'heading-latex',\n            depth: 3\n          },\n          {\n            value: (\n              <>\n                {'Heading '}\n                <_components.code>{'<Code />:{jsx}'}</_components.code>\n              </>\n            ),\n            id: 'heading-code-jsx',\n            depth: 3\n          },\n          {\n            value: (\n              <>\n                <Test />\n                {' World'}\n              </>\n            ),\n            id: '-world',\n            depth: 4\n          },\n          {\n            value: 'String',\n            id: 'string',\n            depth: 5\n          },\n          {\n            value: '123',\n            id: '123',\n            depth: 6\n          },\n          {\n            value: 'Dada 123 true',\n            id: 'dada-123-true',\n            depth: 6\n          }\n        ]\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          h1: 'h1',\n          h2: 'h2',\n          h3: 'h3',\n          h4: 'h4',\n          h5: 'h5',\n          h6: 'h6',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return (\n          <>\n            <_components.h1>{'Heading 1'}</_components.h1>\n            {'\\\\n'}\n            {'\\\\n'}\n            <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n            {'\\\\n'}\n            <_components.h3 id={toc[1].id}>{toc[1].value}</_components.h3>\n            {'\\\\n'}\n            <_components.h3 id={toc[2].id}>{toc[2].value}</_components.h3>\n            {'\\\\n'}\n            {'\\\\n'}\n            <_components.h4 id={toc[3].id}>{toc[3].value}</_components.h4>\n            {'\\\\n'}\n            <_components.h5 id={toc[4].id}>{toc[4].value}</_components.h5>\n            {'\\\\n'}\n            <_components.h6 id={toc[5].id}>{toc[5].value}</_components.h6>\n            {'\\\\n'}\n            <_components.h6 id={toc[6].id}>{toc[6].value}</_components.h6>\n          </>\n        )\n      }\n      export default _createMdxContent\"\n    `)\n  })\n\n  describe('Remote MDX', () => {\n    it(\"with outputFormat: 'program'\", async () => {\n      const rawMdx = `\nimport { MDXRemote } from 'nextra/mdx-remote'\n\n## hello\n\n<MDXRemote components={{ Callout, $Tabs: Tabs }} />`\n\n      const rawJs = await compileMdx(rawMdx, {\n        ...opts,\n        filePath: '[[...slug]].mdx'\n      })\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n        \"/*@jsxRuntime automatic*/\n        /*@jsxImportSource react*/\n        import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n        export const metadata = {\n          title: '[[...slug]]',\n          filePath: '[[...slug]].mdx'\n        }\n        import { MDXRemote } from 'nextra/mdx-remote'\n        export const sourceCode =\n          \"import { MDXRemote } from 'nextra/mdx-remote'\\n\\n## hello\\n\\n<MDXRemote components={{ Callout, $Tabs: Tabs }} />\"\n        function useTOC(props) {\n          return [\n            {\n              value: 'hello',\n              id: 'hello',\n              depth: 2\n            }\n          ]\n        }\n        export const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n            h2: 'h2',\n            ..._provideComponents(),\n            ...props.components\n          }\n          return (\n            <>\n              <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n              {'\\n'}\n              <MDXRemote\n                components={{\n                  Callout,\n                  $Tabs: Tabs\n                }}\n              />\n            </>\n          )\n        }\n        export default _createMdxContent\"\n      `)\n    })\n\n    it(\"with outputFormat: 'function-body'\", async () => {\n      const rawMdx = `\nimport { Foo } from 'foo'\n\n## bar\n\n<Foo />\n\nexport const myVar = 123\n\n### 123 {myVar}`\n\n      const rawJs = await compileMdx(rawMdx)\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n        \"'use strict'\n        const { Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs } = arguments[0]\n        const { useMDXComponents: _provideComponents } = arguments[0]\n        const metadata = {}\n        const myVar = 123\n        const sourceCode = \"import { Foo } from 'foo'\\\\n\\\\n## bar\\\\n\\\\n<Foo />\\\\n\\\\nexport const myVar = 123\\\\n\\\\n### 123 {myVar}\"\n        function useTOC(props) {\n          return [\n            {\n              value: 'bar',\n              id: 'bar',\n              depth: 2\n            },\n            {\n              value: _jsxs(_Fragment, {\n                children: ['123 ', myVar]\n              }),\n              id: '123-myvar',\n              depth: 3\n            }\n          ]\n        }\n        const toc = useTOC({})\n        function _createMdxContent(props) {\n          const _components = {\n              h2: 'h2',\n              h3: 'h3',\n              ..._provideComponents(),\n              ...props.components\n            },\n            { Foo } = _components\n          if (!Foo) _missingMdxReference('Foo', true)\n          return _jsxs(_Fragment, {\n            children: [\n              _jsx(_components.h2, {\n                id: toc[0].id,\n                children: toc[0].value\n              }),\n              '\\\\n',\n              _jsx(Foo, {}),\n              '\\\\n',\n              '\\\\n',\n              _jsx(_components.h3, {\n                id: toc[1].id,\n                children: toc[1].value\n              })\n            ]\n          })\n        }\n        return {\n          metadata,\n          myVar,\n          sourceCode,\n          toc,\n          default: _createMdxContent\n        }\n        function _missingMdxReference(id, component) {\n          throw new Error(\n            'Expected ' +\n              (component ? 'component' : 'object') +\n              ' \\`' +\n              id +\n              '\\` to be defined: you likely forgot to import, pass, or provide it.'\n          )\n        }\"\n      `)\n      expect(rawJs).toMatch('default: _createMdxContent')\n      expect(rawJs).toMatch('const metadata = {')\n      expect(rawJs).toMatch('const toc = useTOC({})')\n      expect(rawJs).not.toMatch('MDXContent')\n    })\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/remark-mdx-frontmatter.test.ts",
    "content": "import { evaluate } from '../../client/evaluate.js'\nimport { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\nconst YAML_FRONTMATTER = '---\\nfoo: bar\\n---'\nconst ESM_FRONTMATTER = \"export const metadata = { foo: 'bar' }\"\n\ndescribe('remarkMdxFrontMatter', () => {\n  it('should throw error if both yaml/esm frontmatter are used', () => {\n    const processor = compileMdx(`${YAML_FRONTMATTER}\\n${ESM_FRONTMATTER}`)\n    return expect(processor).rejects.toThrowError(\n      \"Both YAML front matter and `metadata` aren't supported. Keep only 1.\"\n    )\n  })\n\n  describe('yaml frontmatter', async () => {\n    const rawJs = await compileMdx(YAML_FRONTMATTER)\n\n    it('should export yaml frontmatter', () => {\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n        \"'use strict'\n        const { Fragment: _Fragment, jsx: _jsx } = arguments[0]\n        const { useMDXComponents: _provideComponents } = arguments[0]\n        const metadata = {\n          foo: 'bar'\n        }\n        const sourceCode = '---\\nfoo: bar\\n---'\n        function useTOC(props) {\n          return []\n        }\n        const toc = useTOC({})\n        function _createMdxContent(props) {\n          return _jsx(_Fragment, {})\n        }\n        return {\n          metadata,\n          sourceCode,\n          toc,\n          default: _createMdxContent\n        }\"\n      `)\n    })\n\n    it('should add file.data', () => {\n      const { metadata } = evaluate(rawJs)\n      expect(metadata).toEqual({ foo: 'bar' })\n    })\n    it('should parse empty front matter', async () => {\n      const rawJs = await compileMdx('---\\n---')\n      const { metadata } = evaluate(rawJs)\n      expect(metadata).toEqual({})\n    })\n  })\n\n  describe('esm frontmatter', async () => {\n    const rawJs = await compileMdx(ESM_FRONTMATTER)\n    it('should export esm frontmatter', () => {\n      return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(`\n        \"'use strict'\n        const { Fragment: _Fragment, jsx: _jsx } = arguments[0]\n        const { useMDXComponents: _provideComponents } = arguments[0]\n        const metadata = {\n          foo: 'bar'\n        }\n        const sourceCode = \"export const metadata = { foo: 'bar' }\"\n        function useTOC(props) {\n          return []\n        }\n        const toc = useTOC({})\n        function _createMdxContent(props) {\n          return _jsx(_Fragment, {})\n        }\n        return {\n          metadata,\n          sourceCode,\n          toc,\n          default: _createMdxContent\n        }\"\n      `)\n    })\n    it('should add file.data', () => {\n      const { metadata } = evaluate(rawJs)\n      expect(metadata).toEqual({ foo: 'bar' })\n    })\n  })\n\n  describe('should parse frontMatter', () => {\n    const result = {\n      string: 'Hello',\n      number: 222,\n      boolean: true,\n      object: {\n        prop: 'Foo',\n        nested: {\n          deep: {\n            val: null\n          }\n        }\n      },\n      array: ['foo', 1, null, { hello: 'world' }, ['undefined', true, 'Bool']]\n    }\n\n    it('yaml', async () => {\n      const rawJs = await compileMdx(`---\nstring: Hello\nnumber: 222\nboolean: true\nobject:\n  prop: Foo\n  nested:\n    deep:\n      val: null\narray:\n  - foo\n  - 1\n  - null\n  - \n    hello: world\n  - [undefined, true, Bool]\n---\n`)\n      const { metadata } = evaluate(rawJs)\n      expect(metadata).toEqual(result)\n    })\n    it('esm', async () => {\n      const rawJs = await compileMdx(\n        `export const metadata = ${JSON.stringify(result)}`\n      )\n      const { metadata } = evaluate(rawJs)\n      expect(metadata).toEqual(result)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/remark-mdx-title.test.ts",
    "content": "import { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\nconst opts = {\n  filePath: 'foo/my-test-file.mdx'\n}\n\ndescribe('remarkMdxTitle', () => {\n  describe('should prioritize frontmatter', () => {\n    it('yaml', async () => {\n      const title = 'From yaml frontMatter'\n      const rawJs = await compileMdx(\n        `---\ntitle: ${title}\n---\n\n# Hello`,\n        opts\n      )\n      return expect(clean(rawJs)).resolves.toMatch(`title: '${title}',`)\n    })\n\n    it('esm', async () => {\n      const title = 'From esm frontMatter'\n      const rawJs = await compileMdx(\n        `export const metadata = { title: '${title}' }\n\n# Hello`,\n        opts\n      )\n      return expect(clean(rawJs)).resolves.toMatch(`title: '${title}',`)\n    })\n  })\n\n  it('should fallback to first h1', async () => {\n    const rawJs = await compileMdx(\n      `## h2\n# h1 1\n# h1 2\n`,\n      opts\n    )\n    return expect(clean(rawJs)).resolves.toMatch(\"title: 'h1 1',\")\n  })\n\n  it('should fallback to capitalized filename', async () => {\n    const rawJs = await compileMdx('', opts)\n    return expect(clean(rawJs)).resolves.toMatch(\"title: 'My Test File',\")\n  })\n\n  it('should not set `metadata.title` if there is no h1 or filename provided', async () => {\n    const rawJs = await compileMdx('')\n    return expect(clean(rawJs)).resolves.toMatch('const metadata = {}')\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/remark-remove-imports.test.ts",
    "content": "import { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\nconst opts = {\n  mdxOptions: { jsx: true }\n} as const\n\ndescribe('remarkRemoveImports', () => {\n  it('should fill heading deeply', async () => {\n    const rawJs = await compileMdx(\n      `\nimport { Steps } from 'nextra/components'\n\nexport const myVar = 123\n\nexport const Test = ({value}) => value\n\n## <Test value=\"Hello\" /> {myVar}\n`,\n      opts\n    )\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      'use strict'\n      const { useMDXComponents: _provideComponents } = arguments[0]\n      const metadata = {}\n      const myVar = 123\n      const Test = ({ value }) => value\n      const sourceCode =\n        'import { Steps } from \\'nextra/components\\'\\n\\nexport const myVar = 123\\n\\nexport const Test = ({value}) => value\\n\\n## <Test value=\"Hello\" /> {myVar}'\n      function useTOC(props) {\n        return [\n          {\n            value: (\n              <>\n                <Test value=\"Hello\" /> {myVar}\n              </>\n            ),\n            id: '-myvar',\n            depth: 2\n          }\n        ]\n      }\n      const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          h2: 'h2',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return <_components.h2 id={toc[0].id}>{toc[0].value}</_components.h2>\n      }\n      return {\n        metadata,\n        myVar,\n        Test,\n        sourceCode,\n        toc,\n        default: _createMdxContent\n      }\"\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/remark-static-images.test.ts",
    "content": "import { compileMdx } from '../compile.js'\nimport { clean } from './test-utils.js'\n\ndescribe('remarkStaticImages', () => {\n  it('should insert same import only once', async () => {\n    const rawJs = await compileMdx(\n      `\n![](../foo.png)\n\n![](../bar.jpeg)\n\n![](../foo.png)`,\n      {\n        mdxOptions: {\n          jsx: true,\n          outputFormat: 'program'\n        },\n        staticImage: true\n      }\n    )\n\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      import __img0 from '../foo.png'\n      import __img1 from '../bar.jpeg'\n      export const metadata = {}\n      export const sourceCode = '![](../foo.png)\\n\\n![](../bar.jpeg)\\n\\n![](../foo.png)'\n      function useTOC(props) {\n        return []\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          img: 'img',\n          p: 'p',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return (\n          <>\n            <_components.p>\n              <_components.img placeholder=\"blur\" src={__img0} />\n            </_components.p>\n            {'\\n'}\n            <_components.p>\n              <_components.img placeholder=\"blur\" src={__img1} />\n            </_components.p>\n            {'\\n'}\n            <_components.p>\n              <_components.img placeholder=\"blur\" src={__img0} />\n            </_components.p>\n          </>\n        )\n      }\n      export default _createMdxContent\"\n    `)\n  })\n\n  it('should work with link definitions', async () => {\n    const rawJs = await compileMdx(\n      `\n![One][link-def]\n\n![](../foo.png)\n\n![](./bar.svg)\n\n![Two][link-def]\n\n![External][external-link-def]\n\n[link-def]: ../foo.png\n[external-link-def]: https://foo.png`,\n      {\n        mdxOptions: {\n          jsx: true,\n          outputFormat: 'program'\n        },\n        staticImage: true\n      }\n    )\n\n    return expect(clean(rawJs)).resolves.toMatchInlineSnapshot(String.raw`\n      \"/*@jsxRuntime automatic*/\n      /*@jsxImportSource react*/\n      import { useMDXComponents as _provideComponents } from 'next-mdx-import-source-file'\n      import __img0 from '../foo.png'\n      import __img1 from './bar.svg'\n      export const metadata = {}\n      export const sourceCode =\n        '![One][link-def]\\n\\n![](../foo.png)\\n\\n![](./bar.svg)\\n\\n![Two][link-def]\\n\\n![External][external-link-def]\\n\\n[link-def]: ../foo.png\\n[external-link-def]: https://foo.png'\n      function useTOC(props) {\n        return []\n      }\n      export const toc = useTOC({})\n      function _createMdxContent(props) {\n        const _components = {\n          img: 'img',\n          p: 'p',\n          ..._provideComponents(),\n          ...props.components\n        }\n        return (\n          <>\n            <_components.p>\n              <_components.img alt=\"One\" placeholder=\"blur\" src={__img0} />\n            </_components.p>\n            {'\\n'}\n            <_components.p>\n              <_components.img placeholder=\"blur\" src={__img0} />\n            </_components.p>\n            {'\\n'}\n            <_components.p>\n              <_components.img src={__img1} />\n            </_components.p>\n            {'\\n'}\n            <_components.p>\n              <_components.img alt=\"Two\" placeholder=\"blur\" src={__img0} />\n            </_components.p>\n            {'\\n'}\n            <_components.p>\n              <_components.img src=\"https://foo.png\" alt=\"External\" />\n            </_components.p>\n          </>\n        )\n      }\n      export default _createMdxContent\"\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/test-utils.ts",
    "content": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport prettier from 'prettier'\nimport { findMetaAndPageFilePaths } from '../page-map/find-meta-and-page-file-paths.js'\nimport { convertPageMapToJs } from '../page-map/to-js.js'\nimport { convertToPageMap } from '../page-map/to-page-map.js'\n\nexport type IsEqual<A, B> =\n  (<G>() => G extends (A & G) | G ? 1 : 2) extends <G>() => G extends\n    | (B & G)\n    | G\n    ? 1\n    : 2\n    ? true\n    : false\n\nexport async function clean(content: string): Promise<string> {\n  const result = await prettier.format(content, {\n    parser: 'typescript',\n    semi: false,\n    trailingComma: 'none',\n    singleQuote: true,\n    printWidth: 120,\n    arrowParens: 'avoid'\n  })\n  return result.trimEnd()\n}\n\nexport async function getPageMapForFixture(dirName: string) {\n  const dir = path.join(import.meta.dirname, 'fixture', 'page-maps', dirName)\n  const filePaths = await findMetaAndPageFilePaths({ dir, cwd: dir })\n  const { pageMap, mdxPages } = convertToPageMap({ filePaths })\n  const rawJs = convertPageMapToJs({ pageMap, mdxPages })\n\n  await fs.writeFile(\n    path.join(dir, 'generated-page-map.ts'),\n    '// @ts-nocheck\\n' + rawJs.replaceAll('private-next-root-dir', '.')\n  )\n\n  const result = await import(`${dir}/generated-page-map.js`)\n  return result.pageMap\n}\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/to-js.test.ts",
    "content": "import path from 'node:path'\nimport { CWD } from '../constants.js'\nimport { findMetaAndPageFilePaths } from '../page-map/find-meta-and-page-file-paths.js'\nimport { convertPageMapToJs } from '../page-map/to-js.js'\nimport { convertToPageMap } from '../page-map/to-page-map.js'\n\ndescribe('convertPageMapToJs()', () => {\n  it('should work for docs example', async () => {\n    const cwd = path.join(CWD, '..', '..', 'examples', 'docs')\n    const filePaths = await findMetaAndPageFilePaths({\n      dir: path.join(cwd, 'src/app'),\n      cwd,\n      contentDir: 'src/content'\n    })\n    const { pageMap, mdxPages } = convertToPageMap({ filePaths })\n\n    const result = convertPageMapToJs({ pageMap, mdxPages })\n    expect(result).toMatchInlineSnapshot(`\n      \"import { normalizePageMap, getMetadata } from 'nextra/page-map'\n\n      import meta from \"private-next-root-dir/src/content/_meta.js\";\n      import features_meta from \"private-next-root-dir/src/content/features/_meta.js\";\n      import {metadata as features_i18n} from \"private-next-root-dir/src/content/features/i18n.mdx?metadata\";\n      import {metadata as features_image} from \"private-next-root-dir/src/content/features/image.mdx?metadata\";\n      import {metadata as features_latex} from \"private-next-root-dir/src/content/features/latex.mdx?metadata\";\n      import {metadata as features_mdx} from \"private-next-root-dir/src/content/features/mdx.mdx?metadata\";\n      import {metadata as features_ssg} from \"private-next-root-dir/src/content/features/ssg.mdx?metadata\";\n      import {metadata as features_themes} from \"private-next-root-dir/src/content/features/themes.mdx?metadata\";\n      import themes_meta from \"private-next-root-dir/src/content/themes/_meta.js\";\n      import themes_blog_meta from \"private-next-root-dir/src/content/themes/blog/_meta.js\";\n      import {metadata as themes_blog_index} from \"private-next-root-dir/src/content/themes/blog/index.mdx?metadata\";\n      import themes_docs_meta from \"private-next-root-dir/src/content/themes/docs/_meta.js\";\n      import {metadata as themes_docs_bleed} from \"private-next-root-dir/src/content/themes/docs/bleed.mdx?metadata\";\n      import {metadata as themes_docs_callout} from \"private-next-root-dir/src/content/themes/docs/callout.mdx?metadata\";\n      import {metadata as themes_docs_configuration} from \"private-next-root-dir/src/content/themes/docs/configuration.mdx?metadata\";\n      import {metadata as themes_docs_index} from \"private-next-root-dir/src/content/themes/docs/index.mdx?metadata\";\n      import {metadata as themes_docs_tabs} from \"private-next-root-dir/src/content/themes/docs/tabs.mdx?metadata\";\n      import * as src_app_blog_page from \"private-next-root-dir/src/app/blog/page.jsx\";\n      import {metadata as index} from \"private-next-root-dir/src/content/index.mdx?metadata\";\n      import * as src_app_showcase_overview_page from \"private-next-root-dir/src/app/showcase/(overview)/page.jsx\";\n      import {metadata as advanced_code_highlighting} from \"private-next-root-dir/src/content/advanced/code-highlighting.mdx?metadata\";\n      import {metadata as get_started} from \"private-next-root-dir/src/content/get-started.mdx?metadata\";\n      import {metadata as mermaid} from \"private-next-root-dir/src/content/mermaid.mdx?metadata\";\n      import {metadata as page} from \"private-next-root-dir/src/content/page.mdx?metadata\";\n\n      export const pageMap = normalizePageMap([{\n        data: meta\n      }, {\n        name: \"features\",\n        route: \"/features\",\n        children: [{\n          data: features_meta\n        }, {\n          name: \"i18n\",\n          route: \"/features/i18n\",\n          frontMatter: features_i18n\n        }, {\n          name: \"image\",\n          route: \"/features/image\",\n          frontMatter: features_image\n        }, {\n          name: \"latex\",\n          route: \"/features/latex\",\n          frontMatter: features_latex\n        }, {\n          name: \"mdx\",\n          route: \"/features/mdx\",\n          frontMatter: features_mdx\n        }, {\n          name: \"ssg\",\n          route: \"/features/ssg\",\n          frontMatter: features_ssg\n        }, {\n          name: \"themes\",\n          route: \"/features/themes\",\n          frontMatter: features_themes\n        }]\n      }, {\n        name: \"themes\",\n        route: \"/themes\",\n        children: [{\n          data: themes_meta\n        }, {\n          name: \"blog\",\n          route: \"/themes/blog\",\n          children: [{\n            data: themes_blog_meta\n          }, {\n            name: \"index\",\n            route: \"/themes/blog\",\n            frontMatter: themes_blog_index\n          }]\n        }, {\n          name: \"docs\",\n          route: \"/themes/docs\",\n          children: [{\n            data: themes_docs_meta\n          }, {\n            name: \"bleed\",\n            route: \"/themes/docs/bleed\",\n            frontMatter: themes_docs_bleed\n          }, {\n            name: \"callout\",\n            route: \"/themes/docs/callout\",\n            frontMatter: themes_docs_callout\n          }, {\n            name: \"configuration\",\n            route: \"/themes/docs/configuration\",\n            frontMatter: themes_docs_configuration\n          }, {\n            name: \"index\",\n            route: \"/themes/docs\",\n            frontMatter: themes_docs_index\n          }, {\n            name: \"tabs\",\n            route: \"/themes/docs/tabs\",\n            frontMatter: themes_docs_tabs\n          }]\n        }]\n      }, {\n        name: \"blog\",\n        route: \"/blog\",\n        frontMatter: getMetadata(src_app_blog_page)\n      }, {\n        name: \"index\",\n        route: \"/\",\n        frontMatter: index\n      }, {\n        name: \"showcase\",\n        route: \"/showcase\",\n        frontMatter: getMetadata(src_app_showcase_overview_page)\n      }, {\n        name: \"advanced\",\n        route: \"/advanced\",\n        children: [{\n          name: \"code-highlighting\",\n          route: \"/advanced/code-highlighting\",\n          frontMatter: advanced_code_highlighting\n        }]\n      }, {\n        name: \"get-started\",\n        route: \"/get-started\",\n        frontMatter: get_started\n      }, {\n        name: \"mermaid\",\n        route: \"/mermaid\",\n        frontMatter: mermaid\n      }, {\n        name: \"page\",\n        route: \"/page\",\n        frontMatter: page\n      }])\n\n      export const RouteToFilepath = {\n        \"\": \"index.mdx\",\n        \"advanced/code-highlighting\": \"advanced/code-highlighting.mdx\",\n        \"features/i18n\": \"features/i18n.mdx\",\n        \"features/image\": \"features/image.mdx\",\n        \"features/latex\": \"features/latex.mdx\",\n        \"features/mdx\": \"features/mdx.mdx\",\n        \"features/ssg\": \"features/ssg.mdx\",\n        \"features/themes\": \"features/themes.mdx\",\n        \"get-started\": \"get-started.mdx\",\n        \"mermaid\": \"mermaid.mdx\",\n        \"page\": \"page.mdx\",\n        \"themes/blog\": \"themes/blog/index.mdx\",\n        \"themes/docs/bleed\": \"themes/docs/bleed.mdx\",\n        \"themes/docs/callout\": \"themes/docs/callout.mdx\",\n        \"themes/docs/configuration\": \"themes/docs/configuration.mdx\",\n        \"themes/docs\": \"themes/docs/index.mdx\",\n        \"themes/docs/tabs\": \"themes/docs/tabs.mdx\"\n      }\"\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/__tests__/to-page-map.test.ts",
    "content": "import path from 'node:path'\nimport { CWD } from '../constants.js'\nimport { findMetaAndPageFilePaths } from '../page-map/find-meta-and-page-file-paths.js'\nimport { convertPageMapToJs } from '../page-map/to-js.js'\nimport { convertToPageMap } from '../page-map/to-page-map.js'\n\ndescribe('generatePageMap()', () => {\n  it('should work for blog example', async () => {\n    const cwd = path.join(CWD, '..', '..', 'examples', 'blog')\n    const filePaths = await findMetaAndPageFilePaths({\n      dir: path.join(cwd, 'app'),\n      cwd\n    })\n    const { pageMap } = convertToPageMap({ filePaths })\n    expect(filePaths).toMatchInlineSnapshot(`\n      [\n        \"app/_meta.global.js\",\n        \"app/page.mdx\",\n        \"app/posts/(with-comments)/aaron-swartz-a-programmable-web/page.mdx\",\n        \"app/posts/(with-comments)/code-blocks/page.mdx\",\n        \"app/posts/(with-comments)/draft/page.mdx\",\n        \"app/posts/(with-comments)/lists/page.mdx\",\n        \"app/posts/(with-comments)/nextra-components/page.mdx\",\n        \"app/posts/(with-comments)/table/page.mdx\",\n        \"app/posts/page.jsx\",\n      ]\n    `)\n    expect(pageMap).toMatchInlineSnapshot(`\n      [\n        {\n          \"__pagePath\": \"app/page.mdx\",\n          \"name\": \"index\",\n          \"route\": \"/\",\n        },\n        {\n          \"children\": [\n            {\n              \"__pagePath\": \"app/posts/(with-comments)/aaron-swartz-a-programmable-web/page.mdx\",\n              \"name\": \"aaron-swartz-a-programmable-web\",\n              \"route\": \"/posts/aaron-swartz-a-programmable-web\",\n            },\n            {\n              \"__pagePath\": \"app/posts/(with-comments)/code-blocks/page.mdx\",\n              \"name\": \"code-blocks\",\n              \"route\": \"/posts/code-blocks\",\n            },\n            {\n              \"__pagePath\": \"app/posts/(with-comments)/draft/page.mdx\",\n              \"name\": \"draft\",\n              \"route\": \"/posts/draft\",\n            },\n            {\n              \"__pagePath\": \"app/posts/(with-comments)/lists/page.mdx\",\n              \"name\": \"lists\",\n              \"route\": \"/posts/lists\",\n            },\n            {\n              \"__pagePath\": \"app/posts/(with-comments)/nextra-components/page.mdx\",\n              \"name\": \"nextra-components\",\n              \"route\": \"/posts/nextra-components\",\n            },\n            {\n              \"__pagePath\": \"app/posts/(with-comments)/table/page.mdx\",\n              \"name\": \"table\",\n              \"route\": \"/posts/table\",\n            },\n            {\n              \"__pagePath\": \"app/posts/page.jsx\",\n              \"name\": \"index\",\n              \"route\": \"/posts\",\n            },\n          ],\n          \"name\": \"posts\",\n          \"route\": \"/posts\",\n        },\n      ]\n    `)\n  })\n\n  it('should work for nextra.site', async () => {\n    const cwd = path.join(CWD, '..', '..', 'docs')\n    const filePaths = await findMetaAndPageFilePaths({\n      dir: path.join(cwd, 'app'),\n      cwd\n    })\n    const { pageMap, mdxPages } = convertToPageMap({ filePaths })\n    expect(filePaths).toMatchInlineSnapshot(`\n      [\n        \"app/_meta.global.tsx\",\n        \"app/about/page.mdx\",\n        \"app/api/page.mdx\",\n        \"app/blog/page.mdx\",\n        \"app/docs/advanced/customize-the-cascade-layers/page.mdx\",\n        \"app/docs/advanced/latex/page.mdx\",\n        \"app/docs/advanced/mermaid/page.mdx\",\n        \"app/docs/advanced/npm2yarn/page.mdx\",\n        \"app/docs/advanced/page.mdx\",\n        \"app/docs/advanced/remote/page.mdx\",\n        \"app/docs/advanced/table/page.mdx\",\n        \"app/docs/advanced/tailwind-css/page.mdx\",\n        \"app/docs/advanced/twoslash/page.mdx\",\n        \"app/docs/advanced/typescript/page.mdx\",\n        \"app/docs/blog-theme/get-posts-and-tags/page.mdx\",\n        \"app/docs/blog-theme/page.mdx\",\n        \"app/docs/blog-theme/posts/page.mdx\",\n        \"app/docs/blog-theme/rss/page.mdx\",\n        \"app/docs/blog-theme/start/page.mdx\",\n        \"app/docs/blog-theme/tags/page.mdx\",\n        \"app/docs/built-ins/page.mdx\",\n        \"app/docs/custom-theme/page.mdx\",\n        \"app/docs/docs-theme/api/page.mdx\",\n        \"app/docs/docs-theme/built-ins/footer/page.mdx\",\n        \"app/docs/docs-theme/built-ins/layout/page.mdx\",\n        \"app/docs/docs-theme/built-ins/navbar/page.mdx\",\n        \"app/docs/docs-theme/built-ins/not-found/page.mdx\",\n        \"app/docs/docs-theme/built-ins/page.mdx\",\n        \"app/docs/docs-theme/page.mdx\",\n        \"app/docs/docs-theme/start/page.mdx\",\n        \"app/docs/file-conventions/content-directory/page.mdx\",\n        \"app/docs/file-conventions/mdx-components-file/page.mdx\",\n        \"app/docs/file-conventions/meta-file/page.mdx\",\n        \"app/docs/file-conventions/page-file/page.mdx\",\n        \"app/docs/file-conventions/page.mdx\",\n        \"app/docs/file-conventions/src-directory/page.mdx\",\n        \"app/docs/guide/custom-css/page.mdx\",\n        \"app/docs/guide/github-alert-syntax/page.mdx\",\n        \"app/docs/guide/i18n/page.mdx\",\n        \"app/docs/guide/image/page.mdx\",\n        \"app/docs/guide/link/page.mdx\",\n        \"app/docs/guide/markdown/page.mdx\",\n        \"app/docs/guide/page.mdx\",\n        \"app/docs/guide/search/ai/page.mdx\",\n        \"app/docs/guide/search/page.mdx\",\n        \"app/docs/guide/ssg/page.mdx\",\n        \"app/docs/guide/static-exports/page.mdx\",\n        \"app/docs/guide/syntax-highlighting/page.mdx\",\n        \"app/docs/guide/turbopack/page.mdx\",\n        \"app/docs/page.mdx\",\n        \"app/page.tsx\",\n        \"app/showcase/page.mdx\",\n        \"app/sponsors/page.mdx\",\n      ]\n    `)\n    expect(pageMap).toMatchInlineSnapshot(`\n      [\n        {\n          \"__pagePath\": \"app/about/page.mdx\",\n          \"name\": \"about\",\n          \"route\": \"/about\",\n        },\n        {\n          \"__pagePath\": \"app/api/page.mdx\",\n          \"name\": \"api\",\n          \"route\": \"/api\",\n        },\n        {\n          \"__pagePath\": \"app/blog/page.mdx\",\n          \"name\": \"blog\",\n          \"route\": \"/blog\",\n        },\n        {\n          \"children\": [\n            {\n              \"children\": [\n                {\n                  \"__pagePath\": \"app/docs/advanced/customize-the-cascade-layers/page.mdx\",\n                  \"name\": \"customize-the-cascade-layers\",\n                  \"route\": \"/docs/advanced/customize-the-cascade-layers\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/latex/page.mdx\",\n                  \"name\": \"latex\",\n                  \"route\": \"/docs/advanced/latex\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/mermaid/page.mdx\",\n                  \"name\": \"mermaid\",\n                  \"route\": \"/docs/advanced/mermaid\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/npm2yarn/page.mdx\",\n                  \"name\": \"npm2yarn\",\n                  \"route\": \"/docs/advanced/npm2yarn\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/page.mdx\",\n                  \"name\": \"index\",\n                  \"route\": \"/docs/advanced\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/remote/page.mdx\",\n                  \"name\": \"remote\",\n                  \"route\": \"/docs/advanced/remote\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/table/page.mdx\",\n                  \"name\": \"table\",\n                  \"route\": \"/docs/advanced/table\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/tailwind-css/page.mdx\",\n                  \"name\": \"tailwind-css\",\n                  \"route\": \"/docs/advanced/tailwind-css\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/twoslash/page.mdx\",\n                  \"name\": \"twoslash\",\n                  \"route\": \"/docs/advanced/twoslash\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/advanced/typescript/page.mdx\",\n                  \"name\": \"typescript\",\n                  \"route\": \"/docs/advanced/typescript\",\n                },\n              ],\n              \"name\": \"advanced\",\n              \"route\": \"/docs/advanced\",\n            },\n            {\n              \"children\": [\n                {\n                  \"__pagePath\": \"app/docs/blog-theme/get-posts-and-tags/page.mdx\",\n                  \"name\": \"get-posts-and-tags\",\n                  \"route\": \"/docs/blog-theme/get-posts-and-tags\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/blog-theme/page.mdx\",\n                  \"name\": \"index\",\n                  \"route\": \"/docs/blog-theme\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/blog-theme/posts/page.mdx\",\n                  \"name\": \"posts\",\n                  \"route\": \"/docs/blog-theme/posts\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/blog-theme/rss/page.mdx\",\n                  \"name\": \"rss\",\n                  \"route\": \"/docs/blog-theme/rss\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/blog-theme/start/page.mdx\",\n                  \"name\": \"start\",\n                  \"route\": \"/docs/blog-theme/start\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/blog-theme/tags/page.mdx\",\n                  \"name\": \"tags\",\n                  \"route\": \"/docs/blog-theme/tags\",\n                },\n              ],\n              \"name\": \"blog-theme\",\n              \"route\": \"/docs/blog-theme\",\n            },\n            {\n              \"__pagePath\": \"app/docs/built-ins/page.mdx\",\n              \"name\": \"built-ins\",\n              \"route\": \"/docs/built-ins\",\n            },\n            {\n              \"__pagePath\": \"app/docs/custom-theme/page.mdx\",\n              \"name\": \"custom-theme\",\n              \"route\": \"/docs/custom-theme\",\n            },\n            {\n              \"children\": [\n                {\n                  \"__pagePath\": \"app/docs/docs-theme/api/page.mdx\",\n                  \"name\": \"api\",\n                  \"route\": \"/docs/docs-theme/api\",\n                },\n                {\n                  \"children\": [\n                    {\n                      \"__pagePath\": \"app/docs/docs-theme/built-ins/footer/page.mdx\",\n                      \"name\": \"footer\",\n                      \"route\": \"/docs/docs-theme/built-ins/footer\",\n                    },\n                    {\n                      \"__pagePath\": \"app/docs/docs-theme/built-ins/layout/page.mdx\",\n                      \"name\": \"layout\",\n                      \"route\": \"/docs/docs-theme/built-ins/layout\",\n                    },\n                    {\n                      \"__pagePath\": \"app/docs/docs-theme/built-ins/navbar/page.mdx\",\n                      \"name\": \"navbar\",\n                      \"route\": \"/docs/docs-theme/built-ins/navbar\",\n                    },\n                    {\n                      \"__pagePath\": \"app/docs/docs-theme/built-ins/not-found/page.mdx\",\n                      \"name\": \"not-found\",\n                      \"route\": \"/docs/docs-theme/built-ins/not-found\",\n                    },\n                    {\n                      \"__pagePath\": \"app/docs/docs-theme/built-ins/page.mdx\",\n                      \"name\": \"index\",\n                      \"route\": \"/docs/docs-theme/built-ins\",\n                    },\n                  ],\n                  \"name\": \"built-ins\",\n                  \"route\": \"/docs/docs-theme/built-ins\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/docs-theme/page.mdx\",\n                  \"name\": \"index\",\n                  \"route\": \"/docs/docs-theme\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/docs-theme/start/page.mdx\",\n                  \"name\": \"start\",\n                  \"route\": \"/docs/docs-theme/start\",\n                },\n              ],\n              \"name\": \"docs-theme\",\n              \"route\": \"/docs/docs-theme\",\n            },\n            {\n              \"children\": [\n                {\n                  \"__pagePath\": \"app/docs/file-conventions/content-directory/page.mdx\",\n                  \"name\": \"content-directory\",\n                  \"route\": \"/docs/file-conventions/content-directory\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/file-conventions/mdx-components-file/page.mdx\",\n                  \"name\": \"mdx-components-file\",\n                  \"route\": \"/docs/file-conventions/mdx-components-file\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/file-conventions/meta-file/page.mdx\",\n                  \"name\": \"meta-file\",\n                  \"route\": \"/docs/file-conventions/meta-file\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/file-conventions/page-file/page.mdx\",\n                  \"name\": \"page-file\",\n                  \"route\": \"/docs/file-conventions/page-file\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/file-conventions/page.mdx\",\n                  \"name\": \"index\",\n                  \"route\": \"/docs/file-conventions\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/file-conventions/src-directory/page.mdx\",\n                  \"name\": \"src-directory\",\n                  \"route\": \"/docs/file-conventions/src-directory\",\n                },\n              ],\n              \"name\": \"file-conventions\",\n              \"route\": \"/docs/file-conventions\",\n            },\n            {\n              \"children\": [\n                {\n                  \"__pagePath\": \"app/docs/guide/custom-css/page.mdx\",\n                  \"name\": \"custom-css\",\n                  \"route\": \"/docs/guide/custom-css\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/github-alert-syntax/page.mdx\",\n                  \"name\": \"github-alert-syntax\",\n                  \"route\": \"/docs/guide/github-alert-syntax\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/i18n/page.mdx\",\n                  \"name\": \"i18n\",\n                  \"route\": \"/docs/guide/i18n\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/image/page.mdx\",\n                  \"name\": \"image\",\n                  \"route\": \"/docs/guide/image\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/link/page.mdx\",\n                  \"name\": \"link\",\n                  \"route\": \"/docs/guide/link\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/markdown/page.mdx\",\n                  \"name\": \"markdown\",\n                  \"route\": \"/docs/guide/markdown\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/page.mdx\",\n                  \"name\": \"index\",\n                  \"route\": \"/docs/guide\",\n                },\n                {\n                  \"children\": [\n                    {\n                      \"__pagePath\": \"app/docs/guide/search/ai/page.mdx\",\n                      \"name\": \"ai\",\n                      \"route\": \"/docs/guide/search/ai\",\n                    },\n                    {\n                      \"__pagePath\": \"app/docs/guide/search/page.mdx\",\n                      \"name\": \"index\",\n                      \"route\": \"/docs/guide/search\",\n                    },\n                  ],\n                  \"name\": \"search\",\n                  \"route\": \"/docs/guide/search\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/ssg/page.mdx\",\n                  \"name\": \"ssg\",\n                  \"route\": \"/docs/guide/ssg\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/static-exports/page.mdx\",\n                  \"name\": \"static-exports\",\n                  \"route\": \"/docs/guide/static-exports\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/syntax-highlighting/page.mdx\",\n                  \"name\": \"syntax-highlighting\",\n                  \"route\": \"/docs/guide/syntax-highlighting\",\n                },\n                {\n                  \"__pagePath\": \"app/docs/guide/turbopack/page.mdx\",\n                  \"name\": \"turbopack\",\n                  \"route\": \"/docs/guide/turbopack\",\n                },\n              ],\n              \"name\": \"guide\",\n              \"route\": \"/docs/guide\",\n            },\n            {\n              \"__pagePath\": \"app/docs/page.mdx\",\n              \"name\": \"index\",\n              \"route\": \"/docs\",\n            },\n          ],\n          \"name\": \"docs\",\n          \"route\": \"/docs\",\n        },\n        {\n          \"__pagePath\": \"app/page.tsx\",\n          \"name\": \"index\",\n          \"route\": \"/\",\n        },\n        {\n          \"__pagePath\": \"app/showcase/page.mdx\",\n          \"name\": \"showcase\",\n          \"route\": \"/showcase\",\n        },\n        {\n          \"__pagePath\": \"app/sponsors/page.mdx\",\n          \"name\": \"sponsors\",\n          \"route\": \"/sponsors\",\n        },\n      ]\n    `)\n\n    const globalMetaPath = filePaths.find(filePath =>\n      filePath.includes('/_meta.global.')\n    )\n\n    expect(convertPageMapToJs({ pageMap, mdxPages, globalMetaPath }))\n      .toMatchInlineSnapshot(`\n        \"import { normalizePageMap, mergeMetaWithPageMap, getMetadata } from 'nextra/page-map'\n        import globalMeta from 'private-next-root-dir/app/_meta.global.tsx'\n        import {metadata as app_about_page} from \"private-next-root-dir/app/about/page.mdx?metadata\";\n        import {metadata as app_api_page} from \"private-next-root-dir/app/api/page.mdx?metadata\";\n        import {metadata as app_blog_page} from \"private-next-root-dir/app/blog/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_customize_the_cascade_layers_page} from \"private-next-root-dir/app/docs/advanced/customize-the-cascade-layers/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_latex_page} from \"private-next-root-dir/app/docs/advanced/latex/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_mermaid_page} from \"private-next-root-dir/app/docs/advanced/mermaid/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_npm2yarn_page} from \"private-next-root-dir/app/docs/advanced/npm2yarn/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_page} from \"private-next-root-dir/app/docs/advanced/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_remote_page} from \"private-next-root-dir/app/docs/advanced/remote/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_table_page} from \"private-next-root-dir/app/docs/advanced/table/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_tailwind_css_page} from \"private-next-root-dir/app/docs/advanced/tailwind-css/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_twoslash_page} from \"private-next-root-dir/app/docs/advanced/twoslash/page.mdx?metadata\";\n        import {metadata as app_docs_advanced_typescript_page} from \"private-next-root-dir/app/docs/advanced/typescript/page.mdx?metadata\";\n        import {metadata as app_docs_blog_theme_get_posts_and_tags_page} from \"private-next-root-dir/app/docs/blog-theme/get-posts-and-tags/page.mdx?metadata\";\n        import {metadata as app_docs_blog_theme_page} from \"private-next-root-dir/app/docs/blog-theme/page.mdx?metadata\";\n        import {metadata as app_docs_blog_theme_posts_page} from \"private-next-root-dir/app/docs/blog-theme/posts/page.mdx?metadata\";\n        import {metadata as app_docs_blog_theme_rss_page} from \"private-next-root-dir/app/docs/blog-theme/rss/page.mdx?metadata\";\n        import {metadata as app_docs_blog_theme_start_page} from \"private-next-root-dir/app/docs/blog-theme/start/page.mdx?metadata\";\n        import {metadata as app_docs_blog_theme_tags_page} from \"private-next-root-dir/app/docs/blog-theme/tags/page.mdx?metadata\";\n        import {metadata as app_docs_built_ins_page} from \"private-next-root-dir/app/docs/built-ins/page.mdx?metadata\";\n        import {metadata as app_docs_custom_theme_page} from \"private-next-root-dir/app/docs/custom-theme/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_api_page} from \"private-next-root-dir/app/docs/docs-theme/api/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_built_ins_footer_page} from \"private-next-root-dir/app/docs/docs-theme/built-ins/footer/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_built_ins_layout_page} from \"private-next-root-dir/app/docs/docs-theme/built-ins/layout/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_built_ins_navbar_page} from \"private-next-root-dir/app/docs/docs-theme/built-ins/navbar/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_built_ins_not_found_page} from \"private-next-root-dir/app/docs/docs-theme/built-ins/not-found/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_built_ins_page} from \"private-next-root-dir/app/docs/docs-theme/built-ins/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_page} from \"private-next-root-dir/app/docs/docs-theme/page.mdx?metadata\";\n        import {metadata as app_docs_docs_theme_start_page} from \"private-next-root-dir/app/docs/docs-theme/start/page.mdx?metadata\";\n        import {metadata as app_docs_file_conventions_content_directory_page} from \"private-next-root-dir/app/docs/file-conventions/content-directory/page.mdx?metadata\";\n        import {metadata as app_docs_file_conventions_mdx_components_file_page} from \"private-next-root-dir/app/docs/file-conventions/mdx-components-file/page.mdx?metadata\";\n        import {metadata as app_docs_file_conventions_meta_file_page} from \"private-next-root-dir/app/docs/file-conventions/meta-file/page.mdx?metadata\";\n        import {metadata as app_docs_file_conventions_page_file_page} from \"private-next-root-dir/app/docs/file-conventions/page-file/page.mdx?metadata\";\n        import {metadata as app_docs_file_conventions_page} from \"private-next-root-dir/app/docs/file-conventions/page.mdx?metadata\";\n        import {metadata as app_docs_file_conventions_src_directory_page} from \"private-next-root-dir/app/docs/file-conventions/src-directory/page.mdx?metadata\";\n        import {metadata as app_docs_guide_custom_css_page} from \"private-next-root-dir/app/docs/guide/custom-css/page.mdx?metadata\";\n        import {metadata as app_docs_guide_github_alert_syntax_page} from \"private-next-root-dir/app/docs/guide/github-alert-syntax/page.mdx?metadata\";\n        import {metadata as app_docs_guide_i18n_page} from \"private-next-root-dir/app/docs/guide/i18n/page.mdx?metadata\";\n        import {metadata as app_docs_guide_image_page} from \"private-next-root-dir/app/docs/guide/image/page.mdx?metadata\";\n        import {metadata as app_docs_guide_link_page} from \"private-next-root-dir/app/docs/guide/link/page.mdx?metadata\";\n        import {metadata as app_docs_guide_markdown_page} from \"private-next-root-dir/app/docs/guide/markdown/page.mdx?metadata\";\n        import {metadata as app_docs_guide_page} from \"private-next-root-dir/app/docs/guide/page.mdx?metadata\";\n        import {metadata as app_docs_guide_search_ai_page} from \"private-next-root-dir/app/docs/guide/search/ai/page.mdx?metadata\";\n        import {metadata as app_docs_guide_search_page} from \"private-next-root-dir/app/docs/guide/search/page.mdx?metadata\";\n        import {metadata as app_docs_guide_ssg_page} from \"private-next-root-dir/app/docs/guide/ssg/page.mdx?metadata\";\n        import {metadata as app_docs_guide_static_exports_page} from \"private-next-root-dir/app/docs/guide/static-exports/page.mdx?metadata\";\n        import {metadata as app_docs_guide_syntax_highlighting_page} from \"private-next-root-dir/app/docs/guide/syntax-highlighting/page.mdx?metadata\";\n        import {metadata as app_docs_guide_turbopack_page} from \"private-next-root-dir/app/docs/guide/turbopack/page.mdx?metadata\";\n        import {metadata as app_docs_page} from \"private-next-root-dir/app/docs/page.mdx?metadata\";\n        import * as app_page from \"private-next-root-dir/app/page.tsx\";\n        import {metadata as app_showcase_page} from \"private-next-root-dir/app/showcase/page.mdx?metadata\";\n        import {metadata as app_sponsors_page} from \"private-next-root-dir/app/sponsors/page.mdx?metadata\";\n\n        export const pageMap = normalizePageMap(mergeMetaWithPageMap([{\n          name: \"about\",\n          route: \"/about\",\n          frontMatter: app_about_page\n        }, {\n          name: \"api\",\n          route: \"/api\",\n          frontMatter: app_api_page\n        }, {\n          name: \"blog\",\n          route: \"/blog\",\n          frontMatter: app_blog_page\n        }, {\n          name: \"docs\",\n          route: \"/docs\",\n          children: [{\n            name: \"advanced\",\n            route: \"/docs/advanced\",\n            children: [{\n              name: \"customize-the-cascade-layers\",\n              route: \"/docs/advanced/customize-the-cascade-layers\",\n              frontMatter: app_docs_advanced_customize_the_cascade_layers_page\n            }, {\n              name: \"latex\",\n              route: \"/docs/advanced/latex\",\n              frontMatter: app_docs_advanced_latex_page\n            }, {\n              name: \"mermaid\",\n              route: \"/docs/advanced/mermaid\",\n              frontMatter: app_docs_advanced_mermaid_page\n            }, {\n              name: \"npm2yarn\",\n              route: \"/docs/advanced/npm2yarn\",\n              frontMatter: app_docs_advanced_npm2yarn_page\n            }, {\n              name: \"index\",\n              route: \"/docs/advanced\",\n              frontMatter: app_docs_advanced_page\n            }, {\n              name: \"remote\",\n              route: \"/docs/advanced/remote\",\n              frontMatter: app_docs_advanced_remote_page\n            }, {\n              name: \"table\",\n              route: \"/docs/advanced/table\",\n              frontMatter: app_docs_advanced_table_page\n            }, {\n              name: \"tailwind-css\",\n              route: \"/docs/advanced/tailwind-css\",\n              frontMatter: app_docs_advanced_tailwind_css_page\n            }, {\n              name: \"twoslash\",\n              route: \"/docs/advanced/twoslash\",\n              frontMatter: app_docs_advanced_twoslash_page\n            }, {\n              name: \"typescript\",\n              route: \"/docs/advanced/typescript\",\n              frontMatter: app_docs_advanced_typescript_page\n            }]\n          }, {\n            name: \"blog-theme\",\n            route: \"/docs/blog-theme\",\n            children: [{\n              name: \"get-posts-and-tags\",\n              route: \"/docs/blog-theme/get-posts-and-tags\",\n              frontMatter: app_docs_blog_theme_get_posts_and_tags_page\n            }, {\n              name: \"index\",\n              route: \"/docs/blog-theme\",\n              frontMatter: app_docs_blog_theme_page\n            }, {\n              name: \"posts\",\n              route: \"/docs/blog-theme/posts\",\n              frontMatter: app_docs_blog_theme_posts_page\n            }, {\n              name: \"rss\",\n              route: \"/docs/blog-theme/rss\",\n              frontMatter: app_docs_blog_theme_rss_page\n            }, {\n              name: \"start\",\n              route: \"/docs/blog-theme/start\",\n              frontMatter: app_docs_blog_theme_start_page\n            }, {\n              name: \"tags\",\n              route: \"/docs/blog-theme/tags\",\n              frontMatter: app_docs_blog_theme_tags_page\n            }]\n          }, {\n            name: \"built-ins\",\n            route: \"/docs/built-ins\",\n            frontMatter: app_docs_built_ins_page\n          }, {\n            name: \"custom-theme\",\n            route: \"/docs/custom-theme\",\n            frontMatter: app_docs_custom_theme_page\n          }, {\n            name: \"docs-theme\",\n            route: \"/docs/docs-theme\",\n            children: [{\n              name: \"api\",\n              route: \"/docs/docs-theme/api\",\n              frontMatter: app_docs_docs_theme_api_page\n            }, {\n              name: \"built-ins\",\n              route: \"/docs/docs-theme/built-ins\",\n              children: [{\n                name: \"footer\",\n                route: \"/docs/docs-theme/built-ins/footer\",\n                frontMatter: app_docs_docs_theme_built_ins_footer_page\n              }, {\n                name: \"layout\",\n                route: \"/docs/docs-theme/built-ins/layout\",\n                frontMatter: app_docs_docs_theme_built_ins_layout_page\n              }, {\n                name: \"navbar\",\n                route: \"/docs/docs-theme/built-ins/navbar\",\n                frontMatter: app_docs_docs_theme_built_ins_navbar_page\n              }, {\n                name: \"not-found\",\n                route: \"/docs/docs-theme/built-ins/not-found\",\n                frontMatter: app_docs_docs_theme_built_ins_not_found_page\n              }, {\n                name: \"index\",\n                route: \"/docs/docs-theme/built-ins\",\n                frontMatter: app_docs_docs_theme_built_ins_page\n              }]\n            }, {\n              name: \"index\",\n              route: \"/docs/docs-theme\",\n              frontMatter: app_docs_docs_theme_page\n            }, {\n              name: \"start\",\n              route: \"/docs/docs-theme/start\",\n              frontMatter: app_docs_docs_theme_start_page\n            }]\n          }, {\n            name: \"file-conventions\",\n            route: \"/docs/file-conventions\",\n            children: [{\n              name: \"content-directory\",\n              route: \"/docs/file-conventions/content-directory\",\n              frontMatter: app_docs_file_conventions_content_directory_page\n            }, {\n              name: \"mdx-components-file\",\n              route: \"/docs/file-conventions/mdx-components-file\",\n              frontMatter: app_docs_file_conventions_mdx_components_file_page\n            }, {\n              name: \"meta-file\",\n              route: \"/docs/file-conventions/meta-file\",\n              frontMatter: app_docs_file_conventions_meta_file_page\n            }, {\n              name: \"page-file\",\n              route: \"/docs/file-conventions/page-file\",\n              frontMatter: app_docs_file_conventions_page_file_page\n            }, {\n              name: \"index\",\n              route: \"/docs/file-conventions\",\n              frontMatter: app_docs_file_conventions_page\n            }, {\n              name: \"src-directory\",\n              route: \"/docs/file-conventions/src-directory\",\n              frontMatter: app_docs_file_conventions_src_directory_page\n            }]\n          }, {\n            name: \"guide\",\n            route: \"/docs/guide\",\n            children: [{\n              name: \"custom-css\",\n              route: \"/docs/guide/custom-css\",\n              frontMatter: app_docs_guide_custom_css_page\n            }, {\n              name: \"github-alert-syntax\",\n              route: \"/docs/guide/github-alert-syntax\",\n              frontMatter: app_docs_guide_github_alert_syntax_page\n            }, {\n              name: \"i18n\",\n              route: \"/docs/guide/i18n\",\n              frontMatter: app_docs_guide_i18n_page\n            }, {\n              name: \"image\",\n              route: \"/docs/guide/image\",\n              frontMatter: app_docs_guide_image_page\n            }, {\n              name: \"link\",\n              route: \"/docs/guide/link\",\n              frontMatter: app_docs_guide_link_page\n            }, {\n              name: \"markdown\",\n              route: \"/docs/guide/markdown\",\n              frontMatter: app_docs_guide_markdown_page\n            }, {\n              name: \"index\",\n              route: \"/docs/guide\",\n              frontMatter: app_docs_guide_page\n            }, {\n              name: \"search\",\n              route: \"/docs/guide/search\",\n              children: [{\n                name: \"ai\",\n                route: \"/docs/guide/search/ai\",\n                frontMatter: app_docs_guide_search_ai_page\n              }, {\n                name: \"index\",\n                route: \"/docs/guide/search\",\n                frontMatter: app_docs_guide_search_page\n              }]\n            }, {\n              name: \"ssg\",\n              route: \"/docs/guide/ssg\",\n              frontMatter: app_docs_guide_ssg_page\n            }, {\n              name: \"static-exports\",\n              route: \"/docs/guide/static-exports\",\n              frontMatter: app_docs_guide_static_exports_page\n            }, {\n              name: \"syntax-highlighting\",\n              route: \"/docs/guide/syntax-highlighting\",\n              frontMatter: app_docs_guide_syntax_highlighting_page\n            }, {\n              name: \"turbopack\",\n              route: \"/docs/guide/turbopack\",\n              frontMatter: app_docs_guide_turbopack_page\n            }]\n          }, {\n            name: \"index\",\n            route: \"/docs\",\n            frontMatter: app_docs_page\n          }]\n        }, {\n          name: \"index\",\n          route: \"/\",\n          frontMatter: getMetadata(app_page)\n        }, {\n          name: \"showcase\",\n          route: \"/showcase\",\n          frontMatter: app_showcase_page\n        }, {\n          name: \"sponsors\",\n          route: \"/sponsors\",\n          frontMatter: app_sponsors_page\n        }], globalMeta, true))\n\n        export const RouteToFilepath = {}\"\n      `)\n  })\n\n  describe('should work for docs example', async () => {\n    const cwd = path.join(CWD, '..', '..', 'examples', 'docs')\n    const filePaths = await findMetaAndPageFilePaths({\n      dir: path.join(cwd, 'src/app'),\n      cwd,\n      contentDir: 'src/content'\n    })\n    it('should match filepaths', () => {\n      expect(filePaths).toMatchInlineSnapshot(`\n        [\n          \"src/app/_meta.js\",\n          \"src/app/blog/page.jsx\",\n          \"src/app/page.jsx\",\n          \"src/app/showcase/(overview)/page.jsx\",\n          \"src/content/_meta.js\",\n          \"src/content/advanced/code-highlighting.mdx\",\n          \"src/content/features/_meta.js\",\n          \"src/content/features/i18n.mdx\",\n          \"src/content/features/image.mdx\",\n          \"src/content/features/latex.mdx\",\n          \"src/content/features/mdx.mdx\",\n          \"src/content/features/ssg.mdx\",\n          \"src/content/features/themes.mdx\",\n          \"src/content/get-started.mdx\",\n          \"src/content/index.mdx\",\n          \"src/content/mermaid.mdx\",\n          \"src/content/page.mdx\",\n          \"src/content/themes/_meta.js\",\n          \"src/content/themes/blog/_meta.js\",\n          \"src/content/themes/blog/index.mdx\",\n          \"src/content/themes/docs/_meta.js\",\n          \"src/content/themes/docs/bleed.mdx\",\n          \"src/content/themes/docs/callout.mdx\",\n          \"src/content/themes/docs/configuration.mdx\",\n          \"src/content/themes/docs/index.mdx\",\n          \"src/content/themes/docs/tabs.mdx\",\n        ]\n      `)\n    })\n    it('should match page map', () => {\n      const { pageMap } = convertToPageMap({ filePaths })\n      expect(pageMap).toMatchInlineSnapshot(`\n        [\n          {\n            \"__metaPath\": \"src/content/_meta.js\",\n          },\n          {\n            \"children\": [\n              {\n                \"__metaPath\": \"src/content/features/_meta.js\",\n              },\n              {\n                \"__pagePath\": \"src/content/features/i18n.mdx\",\n                \"name\": \"i18n\",\n                \"route\": \"/features/i18n\",\n              },\n              {\n                \"__pagePath\": \"src/content/features/image.mdx\",\n                \"name\": \"image\",\n                \"route\": \"/features/image\",\n              },\n              {\n                \"__pagePath\": \"src/content/features/latex.mdx\",\n                \"name\": \"latex\",\n                \"route\": \"/features/latex\",\n              },\n              {\n                \"__pagePath\": \"src/content/features/mdx.mdx\",\n                \"name\": \"mdx\",\n                \"route\": \"/features/mdx\",\n              },\n              {\n                \"__pagePath\": \"src/content/features/ssg.mdx\",\n                \"name\": \"ssg\",\n                \"route\": \"/features/ssg\",\n              },\n              {\n                \"__pagePath\": \"src/content/features/themes.mdx\",\n                \"name\": \"themes\",\n                \"route\": \"/features/themes\",\n              },\n            ],\n            \"name\": \"features\",\n            \"route\": \"/features\",\n          },\n          {\n            \"children\": [\n              {\n                \"__metaPath\": \"src/content/themes/_meta.js\",\n              },\n              {\n                \"children\": [\n                  {\n                    \"__metaPath\": \"src/content/themes/blog/_meta.js\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/themes/blog/index.mdx\",\n                    \"name\": \"index\",\n                    \"route\": \"/themes/blog\",\n                  },\n                ],\n                \"name\": \"blog\",\n                \"route\": \"/themes/blog\",\n              },\n              {\n                \"children\": [\n                  {\n                    \"__metaPath\": \"src/content/themes/docs/_meta.js\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/themes/docs/bleed.mdx\",\n                    \"name\": \"bleed\",\n                    \"route\": \"/themes/docs/bleed\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/themes/docs/callout.mdx\",\n                    \"name\": \"callout\",\n                    \"route\": \"/themes/docs/callout\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/themes/docs/configuration.mdx\",\n                    \"name\": \"configuration\",\n                    \"route\": \"/themes/docs/configuration\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/themes/docs/index.mdx\",\n                    \"name\": \"index\",\n                    \"route\": \"/themes/docs\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/themes/docs/tabs.mdx\",\n                    \"name\": \"tabs\",\n                    \"route\": \"/themes/docs/tabs\",\n                  },\n                ],\n                \"name\": \"docs\",\n                \"route\": \"/themes/docs\",\n              },\n            ],\n            \"name\": \"themes\",\n            \"route\": \"/themes\",\n          },\n          {\n            \"__pagePath\": \"src/app/blog/page.jsx\",\n            \"name\": \"blog\",\n            \"route\": \"/blog\",\n          },\n          {\n            \"__pagePath\": \"src/content/index.mdx\",\n            \"name\": \"index\",\n            \"route\": \"/\",\n          },\n          {\n            \"__pagePath\": \"src/app/showcase/(overview)/page.jsx\",\n            \"name\": \"showcase\",\n            \"route\": \"/showcase\",\n          },\n          {\n            \"children\": [\n              {\n                \"__pagePath\": \"src/content/advanced/code-highlighting.mdx\",\n                \"name\": \"code-highlighting\",\n                \"route\": \"/advanced/code-highlighting\",\n              },\n            ],\n            \"name\": \"advanced\",\n            \"route\": \"/advanced\",\n          },\n          {\n            \"__pagePath\": \"src/content/get-started.mdx\",\n            \"name\": \"get-started\",\n            \"route\": \"/get-started\",\n          },\n          {\n            \"__pagePath\": \"src/content/mermaid.mdx\",\n            \"name\": \"mermaid\",\n            \"route\": \"/mermaid\",\n          },\n          {\n            \"__pagePath\": \"src/content/page.mdx\",\n            \"name\": \"page\",\n            \"route\": \"/page\",\n          },\n        ]\n      `)\n    })\n\n    it('should match page map with base path', () => {\n      const { pageMap, mdxPages } = convertToPageMap({\n        filePaths,\n        basePath: 'docs'\n      })\n      // Assert leading slash is removed when `basePath` is set\n      // Assert we don't add pages from `app/` dir to `mdxPages`\n      expect(mdxPages).toMatchInlineSnapshot(`\n        {\n          \"\": \"index.mdx\",\n          \"advanced/code-highlighting\": \"advanced/code-highlighting.mdx\",\n          \"features/i18n\": \"features/i18n.mdx\",\n          \"features/image\": \"features/image.mdx\",\n          \"features/latex\": \"features/latex.mdx\",\n          \"features/mdx\": \"features/mdx.mdx\",\n          \"features/ssg\": \"features/ssg.mdx\",\n          \"features/themes\": \"features/themes.mdx\",\n          \"get-started\": \"get-started.mdx\",\n          \"mermaid\": \"mermaid.mdx\",\n          \"page\": \"page.mdx\",\n          \"themes/blog\": \"themes/blog/index.mdx\",\n          \"themes/docs\": \"themes/docs/index.mdx\",\n          \"themes/docs/bleed\": \"themes/docs/bleed.mdx\",\n          \"themes/docs/callout\": \"themes/docs/callout.mdx\",\n          \"themes/docs/configuration\": \"themes/docs/configuration.mdx\",\n          \"themes/docs/tabs\": \"themes/docs/tabs.mdx\",\n        }\n      `)\n      expect(pageMap).toMatchInlineSnapshot(`\n        [\n          {\n            \"__metaPath\": \"src/app/_meta.js\",\n          },\n          {\n            \"children\": [\n              {\n                \"__metaPath\": \"src/content/_meta.js\",\n              },\n              {\n                \"children\": [\n                  {\n                    \"__metaPath\": \"src/content/features/_meta.js\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/features/i18n.mdx\",\n                    \"name\": \"i18n\",\n                    \"route\": \"/docs/features/i18n\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/features/image.mdx\",\n                    \"name\": \"image\",\n                    \"route\": \"/docs/features/image\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/features/latex.mdx\",\n                    \"name\": \"latex\",\n                    \"route\": \"/docs/features/latex\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/features/mdx.mdx\",\n                    \"name\": \"mdx\",\n                    \"route\": \"/docs/features/mdx\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/features/ssg.mdx\",\n                    \"name\": \"ssg\",\n                    \"route\": \"/docs/features/ssg\",\n                  },\n                  {\n                    \"__pagePath\": \"src/content/features/themes.mdx\",\n                    \"name\": \"themes\",\n                    \"route\": \"/docs/features/themes\",\n                  },\n                ],\n                \"name\": \"features\",\n                \"route\": \"/docs/features\",\n              },\n              {\n                \"children\": [\n                  {\n                    \"__metaPath\": \"src/content/themes/_meta.js\",\n                  },\n                  {\n                    \"children\": [\n                      {\n                        \"__metaPath\": \"src/content/themes/blog/_meta.js\",\n                      },\n                      {\n                        \"__pagePath\": \"src/content/themes/blog/index.mdx\",\n                        \"name\": \"index\",\n                        \"route\": \"/docs/themes/blog\",\n                      },\n                    ],\n                    \"name\": \"blog\",\n                    \"route\": \"/docs/themes/blog\",\n                  },\n                  {\n                    \"children\": [\n                      {\n                        \"__metaPath\": \"src/content/themes/docs/_meta.js\",\n                      },\n                      {\n                        \"__pagePath\": \"src/content/themes/docs/bleed.mdx\",\n                        \"name\": \"bleed\",\n                        \"route\": \"/docs/themes/docs/bleed\",\n                      },\n                      {\n                        \"__pagePath\": \"src/content/themes/docs/callout.mdx\",\n                        \"name\": \"callout\",\n                        \"route\": \"/docs/themes/docs/callout\",\n                      },\n                      {\n                        \"__pagePath\": \"src/content/themes/docs/configuration.mdx\",\n                        \"name\": \"configuration\",\n                        \"route\": \"/docs/themes/docs/configuration\",\n                      },\n                      {\n                        \"__pagePath\": \"src/content/themes/docs/index.mdx\",\n                        \"name\": \"index\",\n                        \"route\": \"/docs/themes/docs\",\n                      },\n                      {\n                        \"__pagePath\": \"src/content/themes/docs/tabs.mdx\",\n                        \"name\": \"tabs\",\n                        \"route\": \"/docs/themes/docs/tabs\",\n                      },\n                    ],\n                    \"name\": \"docs\",\n                    \"route\": \"/docs/themes/docs\",\n                  },\n                ],\n                \"name\": \"themes\",\n                \"route\": \"/docs/themes\",\n              },\n              {\n                \"children\": [\n                  {\n                    \"__pagePath\": \"src/content/advanced/code-highlighting.mdx\",\n                    \"name\": \"code-highlighting\",\n                    \"route\": \"/docs/advanced/code-highlighting\",\n                  },\n                ],\n                \"name\": \"advanced\",\n                \"route\": \"/docs/advanced\",\n              },\n              {\n                \"__pagePath\": \"src/content/get-started.mdx\",\n                \"name\": \"get-started\",\n                \"route\": \"/docs/get-started\",\n              },\n              {\n                \"__pagePath\": \"src/content/index.mdx\",\n                \"name\": \"index\",\n                \"route\": \"/docs\",\n              },\n              {\n                \"__pagePath\": \"src/content/mermaid.mdx\",\n                \"name\": \"mermaid\",\n                \"route\": \"/docs/mermaid\",\n              },\n              {\n                \"__pagePath\": \"src/content/page.mdx\",\n                \"name\": \"page\",\n                \"route\": \"/docs/page\",\n              },\n            ],\n            \"name\": \"docs\",\n            \"route\": \"/docs\",\n          },\n          {\n            \"__pagePath\": \"src/app/blog/page.jsx\",\n            \"name\": \"blog\",\n            \"route\": \"/blog\",\n          },\n          {\n            \"__pagePath\": \"src/app/page.jsx\",\n            \"name\": \"index\",\n            \"route\": \"/\",\n          },\n          {\n            \"__pagePath\": \"src/app/showcase/(overview)/page.jsx\",\n            \"name\": \"showcase\",\n            \"route\": \"/showcase\",\n          },\n        ]\n      `)\n    })\n  })\n\n  describe('should work for i18n example', async () => {\n    const cwd = path.join(CWD, '..', '..', 'examples', 'swr-site')\n    const filePaths = await findMetaAndPageFilePaths({\n      dir: path.join(cwd, 'app'),\n      cwd,\n      locale: 'en'\n    })\n    it('should match filepaths', () => {\n      expect(filePaths).toMatchInlineSnapshot(`\n        [\n          \"content/en/_meta.ts\",\n          \"content/en/about/_meta.ts\",\n          \"content/en/about/a-page.mdx\",\n          \"content/en/about/acknowledgement.mdx\",\n          \"content/en/about/changelog.md\",\n          \"content/en/about/team.mdx\",\n          \"content/en/blog.mdx\",\n          \"content/en/blog/swr-v1.mdx\",\n          \"content/en/docs/_meta.tsx\",\n          \"content/en/docs/advanced.mdx\",\n          \"content/en/docs/advanced/_meta.tsx\",\n          \"content/en/docs/advanced/cache.mdx\",\n          \"content/en/docs/advanced/code-highlighting.mdx\",\n          \"content/en/docs/advanced/dynamic-markdown-import.mdx\",\n          \"content/en/docs/advanced/file-name.with.DOTS.mdx\",\n          \"content/en/docs/advanced/images.mdx\",\n          \"content/en/docs/advanced/markdown-import.mdx\",\n          \"content/en/docs/advanced/more/loooooooooooooooooooong-title.mdx\",\n          \"content/en/docs/advanced/more/tree/one.mdx\",\n          \"content/en/docs/advanced/more/tree/three.mdx\",\n          \"content/en/docs/advanced/more/tree/two.mdx\",\n          \"content/en/docs/advanced/performance.mdx\",\n          \"content/en/docs/advanced/react-native.mdx\",\n          \"content/en/docs/advanced/scrollbar-x.mdx\",\n          \"content/en/docs/arguments.mdx\",\n          \"content/en/docs/callout.mdx\",\n          \"content/en/docs/change-log.mdx\",\n          \"content/en/docs/code-block-without-language.mdx\",\n          \"content/en/docs/conditional-fetching.md\",\n          \"content/en/docs/custom-header-ids.mdx\",\n          \"content/en/docs/data-fetching.mdx\",\n          \"content/en/docs/error-handling.mdx\",\n          \"content/en/docs/getting-started.mdx\",\n          \"content/en/docs/global-configuration.md\",\n          \"content/en/docs/middleware.mdx\",\n          \"content/en/docs/mutation.md\",\n          \"content/en/docs/options.mdx\",\n          \"content/en/docs/pagination.mdx\",\n          \"content/en/docs/prefetching.md\",\n          \"content/en/docs/revalidation.mdx\",\n          \"content/en/docs/suspense.mdx\",\n          \"content/en/docs/typescript.mdx\",\n          \"content/en/docs/understanding.mdx\",\n          \"content/en/docs/with-nextjs.mdx\",\n          \"content/en/docs/wrap-toc-items.mdx\",\n          \"content/en/examples/_meta.ts\",\n          \"content/en/examples/auth.mdx\",\n          \"content/en/examples/basic.mdx\",\n          \"content/en/examples/error-handling.mdx\",\n          \"content/en/examples/full.mdx\",\n          \"content/en/examples/infinite-loading.mdx\",\n          \"content/en/examples/ssr.mdx\",\n          \"content/en/foo.md\",\n          \"content/en/index.mdx\",\n          \"content/en/test.md\",\n        ]\n      `)\n    })\n\n    it('should match page map', () => {\n      const { pageMap, mdxPages } = convertToPageMap({\n        filePaths,\n        locale: 'en'\n      })\n      expect(mdxPages).toMatchInlineSnapshot(`\n        {\n          \"\": \"index.mdx\",\n          \"about/a-page\": \"about/a-page.mdx\",\n          \"about/acknowledgement\": \"about/acknowledgement.mdx\",\n          \"about/changelog\": \"about/changelog.md\",\n          \"about/team\": \"about/team.mdx\",\n          \"blog\": \"blog.mdx\",\n          \"blog/swr-v1\": \"blog/swr-v1.mdx\",\n          \"docs/advanced\": \"docs/advanced.mdx\",\n          \"docs/advanced/cache\": \"docs/advanced/cache.mdx\",\n          \"docs/advanced/code-highlighting\": \"docs/advanced/code-highlighting.mdx\",\n          \"docs/advanced/dynamic-markdown-import\": \"docs/advanced/dynamic-markdown-import.mdx\",\n          \"docs/advanced/file-name.with.DOTS\": \"docs/advanced/file-name.with.DOTS.mdx\",\n          \"docs/advanced/images\": \"docs/advanced/images.mdx\",\n          \"docs/advanced/markdown-import\": \"docs/advanced/markdown-import.mdx\",\n          \"docs/advanced/more/loooooooooooooooooooong-title\": \"docs/advanced/more/loooooooooooooooooooong-title.mdx\",\n          \"docs/advanced/more/tree/one\": \"docs/advanced/more/tree/one.mdx\",\n          \"docs/advanced/more/tree/three\": \"docs/advanced/more/tree/three.mdx\",\n          \"docs/advanced/more/tree/two\": \"docs/advanced/more/tree/two.mdx\",\n          \"docs/advanced/performance\": \"docs/advanced/performance.mdx\",\n          \"docs/advanced/react-native\": \"docs/advanced/react-native.mdx\",\n          \"docs/advanced/scrollbar-x\": \"docs/advanced/scrollbar-x.mdx\",\n          \"docs/arguments\": \"docs/arguments.mdx\",\n          \"docs/callout\": \"docs/callout.mdx\",\n          \"docs/change-log\": \"docs/change-log.mdx\",\n          \"docs/code-block-without-language\": \"docs/code-block-without-language.mdx\",\n          \"docs/conditional-fetching\": \"docs/conditional-fetching.md\",\n          \"docs/custom-header-ids\": \"docs/custom-header-ids.mdx\",\n          \"docs/data-fetching\": \"docs/data-fetching.mdx\",\n          \"docs/error-handling\": \"docs/error-handling.mdx\",\n          \"docs/getting-started\": \"docs/getting-started.mdx\",\n          \"docs/global-configuration\": \"docs/global-configuration.md\",\n          \"docs/middleware\": \"docs/middleware.mdx\",\n          \"docs/mutation\": \"docs/mutation.md\",\n          \"docs/options\": \"docs/options.mdx\",\n          \"docs/pagination\": \"docs/pagination.mdx\",\n          \"docs/prefetching\": \"docs/prefetching.md\",\n          \"docs/revalidation\": \"docs/revalidation.mdx\",\n          \"docs/suspense\": \"docs/suspense.mdx\",\n          \"docs/typescript\": \"docs/typescript.mdx\",\n          \"docs/understanding\": \"docs/understanding.mdx\",\n          \"docs/with-nextjs\": \"docs/with-nextjs.mdx\",\n          \"docs/wrap-toc-items\": \"docs/wrap-toc-items.mdx\",\n          \"examples/auth\": \"examples/auth.mdx\",\n          \"examples/basic\": \"examples/basic.mdx\",\n          \"examples/error-handling\": \"examples/error-handling.mdx\",\n          \"examples/full\": \"examples/full.mdx\",\n          \"examples/infinite-loading\": \"examples/infinite-loading.mdx\",\n          \"examples/ssr\": \"examples/ssr.mdx\",\n          \"foo\": \"foo.md\",\n          \"test\": \"test.md\",\n        }\n      `)\n      expect(pageMap).toMatchInlineSnapshot(`\n        [\n          {\n            \"__metaPath\": \"content/en/_meta.ts\",\n          },\n          {\n            \"children\": [\n              {\n                \"__metaPath\": \"content/en/about/_meta.ts\",\n              },\n              {\n                \"__pagePath\": \"content/en/about/a-page.mdx\",\n                \"name\": \"a-page\",\n                \"route\": \"/about/a-page\",\n              },\n              {\n                \"__pagePath\": \"content/en/about/acknowledgement.mdx\",\n                \"name\": \"acknowledgement\",\n                \"route\": \"/about/acknowledgement\",\n              },\n              {\n                \"__pagePath\": \"content/en/about/changelog.md\",\n                \"name\": \"changelog\",\n                \"route\": \"/about/changelog\",\n              },\n              {\n                \"__pagePath\": \"content/en/about/team.mdx\",\n                \"name\": \"team\",\n                \"route\": \"/about/team\",\n              },\n            ],\n            \"name\": \"about\",\n            \"route\": \"/about\",\n          },\n          {\n            \"children\": [\n              {\n                \"__metaPath\": \"content/en/docs/_meta.tsx\",\n              },\n              {\n                \"children\": [\n                  {\n                    \"__metaPath\": \"content/en/docs/advanced/_meta.tsx\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced.mdx\",\n                    \"name\": \"index\",\n                    \"route\": \"/docs/advanced\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/cache.mdx\",\n                    \"name\": \"cache\",\n                    \"route\": \"/docs/advanced/cache\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/code-highlighting.mdx\",\n                    \"name\": \"code-highlighting\",\n                    \"route\": \"/docs/advanced/code-highlighting\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/dynamic-markdown-import.mdx\",\n                    \"name\": \"dynamic-markdown-import\",\n                    \"route\": \"/docs/advanced/dynamic-markdown-import\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/file-name.with.DOTS.mdx\",\n                    \"name\": \"file-name.with.DOTS\",\n                    \"route\": \"/docs/advanced/file-name.with.DOTS\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/images.mdx\",\n                    \"name\": \"images\",\n                    \"route\": \"/docs/advanced/images\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/markdown-import.mdx\",\n                    \"name\": \"markdown-import\",\n                    \"route\": \"/docs/advanced/markdown-import\",\n                  },\n                  {\n                    \"children\": [\n                      {\n                        \"__pagePath\": \"content/en/docs/advanced/more/loooooooooooooooooooong-title.mdx\",\n                        \"name\": \"loooooooooooooooooooong-title\",\n                        \"route\": \"/docs/advanced/more/loooooooooooooooooooong-title\",\n                      },\n                      {\n                        \"children\": [\n                          {\n                            \"__pagePath\": \"content/en/docs/advanced/more/tree/one.mdx\",\n                            \"name\": \"one\",\n                            \"route\": \"/docs/advanced/more/tree/one\",\n                          },\n                          {\n                            \"__pagePath\": \"content/en/docs/advanced/more/tree/three.mdx\",\n                            \"name\": \"three\",\n                            \"route\": \"/docs/advanced/more/tree/three\",\n                          },\n                          {\n                            \"__pagePath\": \"content/en/docs/advanced/more/tree/two.mdx\",\n                            \"name\": \"two\",\n                            \"route\": \"/docs/advanced/more/tree/two\",\n                          },\n                        ],\n                        \"name\": \"tree\",\n                        \"route\": \"/docs/advanced/more/tree\",\n                      },\n                    ],\n                    \"name\": \"more\",\n                    \"route\": \"/docs/advanced/more\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/performance.mdx\",\n                    \"name\": \"performance\",\n                    \"route\": \"/docs/advanced/performance\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/react-native.mdx\",\n                    \"name\": \"react-native\",\n                    \"route\": \"/docs/advanced/react-native\",\n                  },\n                  {\n                    \"__pagePath\": \"content/en/docs/advanced/scrollbar-x.mdx\",\n                    \"name\": \"scrollbar-x\",\n                    \"route\": \"/docs/advanced/scrollbar-x\",\n                  },\n                ],\n                \"name\": \"advanced\",\n                \"route\": \"/docs/advanced\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/arguments.mdx\",\n                \"name\": \"arguments\",\n                \"route\": \"/docs/arguments\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/callout.mdx\",\n                \"name\": \"callout\",\n                \"route\": \"/docs/callout\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/change-log.mdx\",\n                \"name\": \"change-log\",\n                \"route\": \"/docs/change-log\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/code-block-without-language.mdx\",\n                \"name\": \"code-block-without-language\",\n                \"route\": \"/docs/code-block-without-language\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/conditional-fetching.md\",\n                \"name\": \"conditional-fetching\",\n                \"route\": \"/docs/conditional-fetching\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/custom-header-ids.mdx\",\n                \"name\": \"custom-header-ids\",\n                \"route\": \"/docs/custom-header-ids\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/data-fetching.mdx\",\n                \"name\": \"data-fetching\",\n                \"route\": \"/docs/data-fetching\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/error-handling.mdx\",\n                \"name\": \"error-handling\",\n                \"route\": \"/docs/error-handling\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/getting-started.mdx\",\n                \"name\": \"getting-started\",\n                \"route\": \"/docs/getting-started\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/global-configuration.md\",\n                \"name\": \"global-configuration\",\n                \"route\": \"/docs/global-configuration\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/middleware.mdx\",\n                \"name\": \"middleware\",\n                \"route\": \"/docs/middleware\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/mutation.md\",\n                \"name\": \"mutation\",\n                \"route\": \"/docs/mutation\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/options.mdx\",\n                \"name\": \"options\",\n                \"route\": \"/docs/options\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/pagination.mdx\",\n                \"name\": \"pagination\",\n                \"route\": \"/docs/pagination\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/prefetching.md\",\n                \"name\": \"prefetching\",\n                \"route\": \"/docs/prefetching\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/revalidation.mdx\",\n                \"name\": \"revalidation\",\n                \"route\": \"/docs/revalidation\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/suspense.mdx\",\n                \"name\": \"suspense\",\n                \"route\": \"/docs/suspense\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/typescript.mdx\",\n                \"name\": \"typescript\",\n                \"route\": \"/docs/typescript\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/understanding.mdx\",\n                \"name\": \"understanding\",\n                \"route\": \"/docs/understanding\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/with-nextjs.mdx\",\n                \"name\": \"with-nextjs\",\n                \"route\": \"/docs/with-nextjs\",\n              },\n              {\n                \"__pagePath\": \"content/en/docs/wrap-toc-items.mdx\",\n                \"name\": \"wrap-toc-items\",\n                \"route\": \"/docs/wrap-toc-items\",\n              },\n            ],\n            \"name\": \"docs\",\n            \"route\": \"/docs\",\n          },\n          {\n            \"children\": [\n              {\n                \"__metaPath\": \"content/en/examples/_meta.ts\",\n              },\n              {\n                \"__pagePath\": \"content/en/examples/auth.mdx\",\n                \"name\": \"auth\",\n                \"route\": \"/examples/auth\",\n              },\n              {\n                \"__pagePath\": \"content/en/examples/basic.mdx\",\n                \"name\": \"basic\",\n                \"route\": \"/examples/basic\",\n              },\n              {\n                \"__pagePath\": \"content/en/examples/error-handling.mdx\",\n                \"name\": \"error-handling\",\n                \"route\": \"/examples/error-handling\",\n              },\n              {\n                \"__pagePath\": \"content/en/examples/full.mdx\",\n                \"name\": \"full\",\n                \"route\": \"/examples/full\",\n              },\n              {\n                \"__pagePath\": \"content/en/examples/infinite-loading.mdx\",\n                \"name\": \"infinite-loading\",\n                \"route\": \"/examples/infinite-loading\",\n              },\n              {\n                \"__pagePath\": \"content/en/examples/ssr.mdx\",\n                \"name\": \"ssr\",\n                \"route\": \"/examples/ssr\",\n              },\n            ],\n            \"name\": \"examples\",\n            \"route\": \"/examples\",\n          },\n          {\n            \"children\": [\n              {\n                \"__pagePath\": \"content/en/blog.mdx\",\n                \"name\": \"index\",\n                \"route\": \"/blog\",\n              },\n              {\n                \"__pagePath\": \"content/en/blog/swr-v1.mdx\",\n                \"name\": \"swr-v1\",\n                \"route\": \"/blog/swr-v1\",\n              },\n            ],\n            \"name\": \"blog\",\n            \"route\": \"/blog\",\n          },\n          {\n            \"__pagePath\": \"content/en/foo.md\",\n            \"name\": \"foo\",\n            \"route\": \"/foo\",\n          },\n          {\n            \"__pagePath\": \"content/en/index.mdx\",\n            \"name\": \"index\",\n            \"route\": \"/\",\n          },\n          {\n            \"__pagePath\": \"content/en/test.md\",\n            \"name\": \"test\",\n            \"route\": \"/test\",\n          },\n        ]\n      `)\n    })\n  })\n\n  it('should add `basePath` for graphql-eslint where there is no `content` dir', () => {\n    const { mdxPages, pageMap } = convertToPageMap({\n      filePaths: [\n        'configs.mdx',\n        'custom-rules.mdx',\n        'getting-started.mdx',\n        'getting-started/parser-options.mdx',\n        'getting-started/parser.mdx',\n        'index.mdx'\n      ],\n      basePath: 'remote/graphql-eslint'\n    })\n    expect(mdxPages).toMatchInlineSnapshot(`\n      {\n        \"\": \"index.mdx\",\n        \"configs\": \"configs.mdx\",\n        \"custom-rules\": \"custom-rules.mdx\",\n        \"getting-started\": \"getting-started.mdx\",\n        \"getting-started/parser\": \"getting-started/parser.mdx\",\n        \"getting-started/parser-options\": \"getting-started/parser-options.mdx\",\n      }\n    `)\n    expect(pageMap).toMatchInlineSnapshot(`\n      [\n        {\n          \"children\": [\n            {\n              \"children\": [\n                {\n                  \"__pagePath\": \"configs.mdx\",\n                  \"name\": \"configs\",\n                  \"route\": \"/remote/graphql-eslint/configs\",\n                },\n                {\n                  \"__pagePath\": \"custom-rules.mdx\",\n                  \"name\": \"custom-rules\",\n                  \"route\": \"/remote/graphql-eslint/custom-rules\",\n                },\n                {\n                  \"children\": [\n                    {\n                      \"__pagePath\": \"getting-started.mdx\",\n                      \"name\": \"index\",\n                      \"route\": \"/remote/graphql-eslint/getting-started\",\n                    },\n                    {\n                      \"__pagePath\": \"getting-started/parser-options.mdx\",\n                      \"name\": \"parser-options\",\n                      \"route\": \"/remote/graphql-eslint/getting-started/parser-options\",\n                    },\n                    {\n                      \"__pagePath\": \"getting-started/parser.mdx\",\n                      \"name\": \"parser\",\n                      \"route\": \"/remote/graphql-eslint/getting-started/parser\",\n                    },\n                  ],\n                  \"name\": \"getting-started\",\n                  \"route\": \"/remote/graphql-eslint/getting-started\",\n                },\n                {\n                  \"__pagePath\": \"index.mdx\",\n                  \"name\": \"index\",\n                  \"route\": \"/remote/graphql-eslint\",\n                },\n              ],\n              \"name\": \"graphql-eslint\",\n              \"route\": \"/remote/graphql-eslint\",\n            },\n          ],\n          \"name\": \"remote\",\n          \"route\": \"/remote\",\n        },\n      ]\n    `)\n  })\n})\n"
  },
  {
    "path": "packages/nextra/src/server/compile-metadata.ts",
    "content": "import { createProcessor } from '@mdx-js/mdx'\nimport type { Program } from 'estree'\nimport remarkFrontmatter from 'remark-frontmatter'\nimport remarkMath from 'remark-math'\nimport type { Plugin, Transformer } from 'unified'\nimport {\n  remarkAssignFrontMatter,\n  remarkExportOnlyMetadata,\n  remarkMdxFrontMatter,\n  remarkMdxTitle\n} from './remark-plugins/index.js'\n\n/**\n * `nextra/dist/server/page-map/placeholder.js` imports all `metadata`s from `.md`/`.mdx` files to\n * build `pageMap`.\n * If a request includes the resource query `?metadata`, compiling MDX to JSX is unnecessary.\n * This step can be skipped to improve performance in the development environment.\n */\nexport async function compileMetadata(\n  source: string,\n  { filePath, lastCommitTime }: { filePath: string; lastCommitTime?: number }\n): Promise<string> {\n  const format = filePath.endsWith('.mdx') ? 'mdx' : 'md'\n\n  const compiler = createProcessor({\n    format,\n    remarkPlugins: [\n      remarkFrontmatter, // parse and attach yaml node\n      remarkMdxFrontMatter,\n      remarkMdxTitle,\n      [remarkAssignFrontMatter, { lastCommitTime }],\n      remarkExportOnlyMetadata,\n      remarkMath // https://github.com/shuding/nextra/issues/4164\n    ],\n    recmaPlugins: [recmaExportOnlyMetadata]\n  })\n  const vFile = await compiler.process({ value: source, path: filePath })\n\n  return vFile.value as string\n}\n\nconst transformer: Transformer<Program> = ast => {\n  const importReact = ast.body[0]! // always exist\n\n  ast.body = ast.body.filter(\n    node =>\n      node.type === 'ExportNamedDeclaration' &&\n      (node.declaration as any).declarations[0].id.name === 'metadata'\n  )\n  ast.body.unshift(importReact)\n}\n\nconst recmaExportOnlyMetadata: Plugin<[], Program> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/compile.ts",
    "content": "import type { ProcessorOptions } from '@mdx-js/mdx'\nimport { createProcessor } from '@mdx-js/mdx'\nimport { remarkMermaid } from '@theguild/remark-mermaid'\nimport { remarkNpm2Yarn } from '@theguild/remark-npm2yarn'\nimport rehypeKatex from 'rehype-katex'\nimport rehypePrettyCode from 'rehype-pretty-code'\nimport rehypeRaw from 'rehype-raw'\nimport remarkFrontmatter from 'remark-frontmatter'\nimport remarkGfm from 'remark-gfm'\nimport remarkMath from 'remark-math'\nimport remarkReadingTime from 'remark-reading-time'\nimport remarkSmartypants from 'remark-smartypants'\nimport type { Pluggable } from 'unified'\nimport type { LoaderOptions, NextraConfig } from '../types.js'\nimport { MARKDOWN_URL_EXTENSION_RE } from './constants.js'\nimport { recmaRewrite } from './recma-plugins/index.js'\nimport {\n  DEFAULT_REHYPE_PRETTY_CODE_OPTIONS,\n  rehypeAttachCodeMeta,\n  rehypeBetterReactMathjax,\n  rehypeExtractTocContent,\n  rehypeParseCodeMeta,\n  rehypeTwoslashPopup\n} from './rehype-plugins/index.js'\nimport {\n  remarkAssignFrontMatter,\n  remarkCustomHeadingId,\n  remarkExportSourceCode,\n  remarkHeadings,\n  remarkLinkRewrite,\n  remarkMdxDisableExplicitJsx,\n  remarkMdxFrontMatter,\n  remarkMdxTitle,\n  remarkRemoveImports,\n  remarkStaticImage\n} from './remark-plugins/index.js'\n\ntype Processor = ReturnType<typeof createProcessor>\n\nconst cachedCompilerForFormat: Record<\n  `${NonNullable<ProcessorOptions['format']>}:${boolean}`,\n  Processor | void\n> = Object.create(null)\n\ntype MdxOptions = NextraConfig['mdxOptions'] &\n  Pick<ProcessorOptions, 'jsx' | 'outputFormat' | 'providerImportSource'>\n\ntype CompileMdxOptions = Pick<\n  LoaderOptions,\n  | 'staticImage'\n  | 'search'\n  | 'defaultShowCopyCode'\n  | 'readingTime'\n  | 'latex'\n  | 'codeHighlight'\n  | 'whiteListTagsStyling'\n> & {\n  /** @default {} */\n  mdxOptions: MdxOptions\n  /** @default '' */\n  filePath: string\n  useCachedCompiler: boolean\n  /** @default false */\n  isPageImport: boolean\n  lastCommitTime: number\n}\n\n/**\n * @example\n * ```ts\n * // Usage with MDXRemote\n * import { compileMdx } from 'nextra/compile'\n * import { MDXRemote } from 'nextra/mdx-remote'\n *\n * const rawJs = await compileMdx(rawMdx)\n * const content = <MDXRemote compiledSource={rawJs} components={...} scope={...} />\n * ```\n */\nexport async function compileMdx(\n  rawMdx: string,\n  {\n    staticImage,\n    search,\n    readingTime,\n    latex,\n    codeHighlight,\n    defaultShowCopyCode,\n    mdxOptions = {},\n    filePath = '',\n    useCachedCompiler,\n    isPageImport = false,\n    whiteListTagsStyling = [],\n    lastCommitTime\n  }: Partial<CompileMdxOptions> = {}\n): Promise<string> {\n  const {\n    jsx = false,\n    format: _format = 'mdx',\n    outputFormat = 'function-body',\n    remarkPlugins,\n    rehypePlugins,\n    recmaPlugins,\n    rehypePrettyCodeOptions,\n    providerImportSource = 'next-mdx-import-source-file'\n  } = mdxOptions\n\n  const format =\n    _format === 'detect' ? (filePath.endsWith('.mdx') ? 'mdx' : 'md') : _format\n\n  const fileCompatible = filePath ? { value: rawMdx, path: filePath } : rawMdx\n\n  const isRemoteContent = outputFormat === 'function-body'\n\n  const compiler =\n    !useCachedCompiler || isRemoteContent\n      ? createCompiler()\n      : (cachedCompilerForFormat[`${format}:${isPageImport}`] ||=\n          createCompiler())\n  const processor = compiler()\n\n  try {\n    const vFile = await processor.process(fileCompatible)\n    const rawJs = (vFile.value as string)\n      // https://github.com/shuding/nextra/issues/1032\n      .replaceAll('__esModule', String.raw`_\\_esModule`)\n    return rawJs\n  } catch (error) {\n    console.error(`[nextra] Error compiling ${filePath}.`)\n    throw error\n  }\n\n  function createCompiler(): Processor {\n    return createProcessor({\n      jsx,\n      format,\n      outputFormat,\n      providerImportSource,\n      // Fix TypeError: _jsx is not a function for remote content\n      development: process.env.NODE_ENV === 'development',\n      remarkPlugins: [\n        ...(remarkPlugins || []),\n        remarkMermaid, // should be before remarkRemoveImports because contains `import { Mermaid } from ...`\n        [\n          remarkNpm2Yarn, // should be before remarkRemoveImports because contains `import { Tabs as $Tabs, Tab as $Tab } from ...`\n          {\n            packageName: 'nextra/components',\n            tabNamesProp: 'items',\n            storageKey: 'selectedPackageManager'\n          }\n        ] satisfies Pluggable,\n        isRemoteContent && remarkRemoveImports,\n        remarkFrontmatter, // parse and attach yaml node\n        remarkMdxFrontMatter,\n        readingTime && remarkReadingTime,\n        // before mdx title\n        remarkCustomHeadingId,\n        remarkMdxTitle,\n        [remarkAssignFrontMatter, { lastCommitTime }] satisfies Pluggable,\n        remarkGfm,\n        format !== 'md' &&\n          ([\n            remarkMdxDisableExplicitJsx,\n            // Replace the <summary> and <details> with customized components\n            { whiteList: ['details', 'summary', ...whiteListTagsStyling] }\n          ] satisfies Pluggable),\n        [remarkHeadings, { isRemoteContent }] satisfies Pluggable,\n        staticImage && remarkStaticImage,\n        latex && remarkMath,\n        // Remove the markdown file extension from links\n        [\n          remarkLinkRewrite,\n          {\n            pattern: MARKDOWN_URL_EXTENSION_RE,\n            replace: '',\n            excludeExternalLinks: true\n          }\n        ] satisfies Pluggable,\n        remarkSmartypants,\n        remarkExportSourceCode\n      ].filter(v => !!v),\n      rehypePlugins: [\n        ...(rehypePlugins || []),\n        format === 'md' && [\n          // To render `<details>` and `<summary>` correctly\n          rehypeRaw,\n          // fix Error: Cannot compile `mdxjsEsm` node for npm2yarn and mermaid\n          {\n            passThrough: ['mdxjsEsm', 'mdxJsxFlowElement', 'mdxTextExpression']\n          }\n        ],\n        [rehypeParseCodeMeta, { defaultShowCopyCode }],\n        // Should be before `rehypePrettyCode`\n        latex &&\n          (typeof latex === 'object'\n            ? latex.renderer === 'mathjax'\n              ? [rehypeBetterReactMathjax, latex.options, isRemoteContent]\n              : [rehypeKatex, latex.options]\n            : rehypeKatex),\n        ...(codeHighlight === false\n          ? []\n          : [\n              [\n                rehypePrettyCode,\n                {\n                  ...DEFAULT_REHYPE_PRETTY_CODE_OPTIONS,\n                  ...rehypePrettyCodeOptions\n                }\n              ] as any,\n              rehypeTwoslashPopup,\n              [rehypeAttachCodeMeta, { search }]\n            ]),\n        rehypeExtractTocContent\n      ].filter(v => !!v),\n      recmaPlugins: [\n        ...(recmaPlugins || []),\n        [recmaRewrite, { isPageImport, isRemoteContent }] satisfies Pluggable\n      ]\n    })\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/constants.ts",
    "content": "/*\n * Benefit of server/constants - do not include unneeded `path` polyfill in client bundle,\n * while importing constants in client file\n */\nimport type { Property } from 'estree'\n\nexport const MARKDOWN_EXTENSION_RE = /\\.mdx?$/\n\nexport const CWD = process.cwd()\n\nexport const MARKDOWN_URL_EXTENSION_RE = /\\.mdx?(?:(?=[#?])|$)/\n\nexport const IS_PRODUCTION = process.env.NODE_ENV === 'production'\n\nexport const EXTERNAL_URL_RE = /^https?:\\/\\//\n\nexport const DEFAULT_PROPERTY_PROPS = {\n  type: 'Property',\n  kind: 'init',\n  method: false,\n  shorthand: false,\n  computed: false\n} satisfies Omit<Property, 'key' | 'value'>\n\nexport const METADATA_ONLY_RQ = '?metadata'\n"
  },
  {
    "path": "packages/nextra/src/server/fetch-filepaths-from-github.ts",
    "content": "import fs from 'node:fs/promises'\nimport { MARKDOWN_EXTENSION_RE } from './constants.js'\n\ntype Params = {\n  user: string\n  repo: string\n  branch: string\n  docsPath: string\n  outputPath: string\n}\n\nexport async function fetchFilePathsFromGitHub({\n  user,\n  repo,\n  branch,\n  docsPath,\n  outputPath\n}: Params): Promise<void> {\n  const url = `https://api.github.com/repos/${user}/${repo}/git/trees/${branch}?recursive=1`\n  const response = await fetch(url)\n\n  const data = await response.json()\n  if (data.message) {\n    console.error(\n      '❌ GitHub API rate limit exceeded, skipping…',\n      JSON.stringify(data, null, 2)\n    )\n    // eslint-disable-next-line unicorn/no-process-exit -- This file is a CLI\n    process.exit(0)\n  }\n  const filePaths = (data.tree as { path: string }[])\n    .filter(item => item.path.startsWith(docsPath))\n    .map(item => item.path.replace(docsPath, ''))\n\n  const result = {\n    user,\n    repo,\n    branch,\n    docsPath,\n    filePaths: filePaths.filter(filePath =>\n      MARKDOWN_EXTENSION_RE.test(filePath)\n    )\n  }\n  const json = JSON.stringify(result, null, 2)\n\n  await fs.writeFile(outputPath, json)\n\n  console.log(`✅ Remote files from \"${url}\" saved!`)\n}\n"
  },
  {
    "path": "packages/nextra/src/server/index.ts",
    "content": "/* eslint-env node */\nimport { createRequire } from 'node:module'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport fg from 'fast-glob'\nimport type { NextConfig } from 'next'\nimport type { RuleSetRule } from 'webpack'\nimport { z } from 'zod'\nimport type { NextraConfig } from '../types.js'\nimport { CWD, MARKDOWN_EXTENSION_RE } from './constants.js'\nimport { NextraConfigSchema } from './schemas.js'\nimport { logger } from './utils.js'\n\nconst require = createRequire(import.meta.url)\n\nconst MARKDOWN_EXTENSIONS = ['md', 'mdx'] as const\n\nconst DEFAULT_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx'] as const\n\nconst FILENAME = fileURLToPath(import.meta.url)\n\nconst LOADER_PATH = path.join(FILENAME, '..', '..', '..', 'loader.cjs')\n\nconst SEP = path.sep === '/' ? '/' : '\\\\\\\\'\n\nconst GET_PAGE_MAP_PATH = '/nextra/dist/server/page-map/get.js'\n\nconst PAGE_MAP_PLACEHOLDER_PATH = '/nextra/dist/server/page-map/placeholder.js'\n\nconst GET_PAGE_MAP_RE = new RegExp(\n  GET_PAGE_MAP_PATH.replaceAll('/', SEP).replaceAll('.', String.raw`\\.`)\n)\nconst PAGE_MAP_PLACEHOLDER_RE = new RegExp(\n  PAGE_MAP_PLACEHOLDER_PATH.replaceAll('/', SEP).replaceAll('.', String.raw`\\.`)\n)\nconst CONTENT_DIR = getContentDirectory()\n\nfunction getContentDirectory() {\n  // Next.js gives priority to `app` over `src/app`, we do the same for `content` directory\n  const [contentDir = 'content'] = fg.sync(['{src/,}content'], {\n    onlyDirectories: true\n  })\n  return contentDir\n}\n\nconst [nextMajorVersion, nextMinorVersion] = require('next/package.json')\n  .version.split('.', 2)\n  .map(Number)\n\nconst shouldUseConfigTurbopack =\n  nextMajorVersion > 15 || (nextMajorVersion === 15 && nextMinorVersion > 2)\n\n/**\n * Nextra is a Next.js plugin that allows you to create Markdown-based content with ease.\n *\n * @example\n * ```js filename=\"next.config.mjs\"\n * import nextra from 'nextra'\n *\n * // Set up Nextra with its configuration\n * const withNextra = nextra({\n *   // ... Add Nextra-specific options here\n * })\n *\n * // Export the final Next.js config with Nextra included\n * export default withNextra({\n *   // ... Add regular Next.js options here\n * })\n * ```\n * @see\n * - [`NextraConfig` options](https://nextra.site/api/nextra)\n * - [Nextra documentation](https://nextra.site)\n * - [`NextConfig` options](https://nextjs.org/docs/pages/api-reference/config/next-config-js)\n */\nconst nextra = (nextraConfig: NextraConfig) => {\n  const { error, data: loaderOptions } =\n    NextraConfigSchema.safeParse(nextraConfig)\n  if (error) {\n    logger.error('Error validating nextraConfig')\n    throw z.prettifyError(error)\n  }\n\n  const loader = {\n    loader: LOADER_PATH,\n    options: loaderOptions\n  }\n  const pageImportLoader = {\n    loader: LOADER_PATH,\n    options: { ...loaderOptions, isPageImport: true }\n  }\n  const pageMapPlaceholderLoader = {\n    loader: LOADER_PATH,\n    options: {\n      // Remove forward slash\n      contentDirBasePath: loaderOptions.contentDirBasePath.slice(1),\n      contentDir: CONTENT_DIR,\n      shouldAddLocaleToLinks: loaderOptions.unstable_shouldAddLocaleToLinks\n    }\n  }\n\n  return function withNextra(nextConfig: NextConfig = {}): NextConfig {\n    const { locales, defaultLocale } = nextConfig.i18n || {}\n    if (locales) {\n      logger.info(\n        'You have Next.js i18n enabled, read here https://nextjs.org/docs/app/building-your-application/routing/internationalization for the docs.'\n      )\n    }\n    const pageMapLoader = {\n      loader: LOADER_PATH,\n      options: {\n        // ts complains about readonly array\n        locales: locales ? [...locales] : ['']\n      }\n    }\n    const turbopackConfig =\n      (shouldUseConfigTurbopack\n        ? nextConfig.turbopack\n        : // @ts-expect-error -- Backwards compatibility\n          nextConfig.experimental?.turbo) ?? {}\n\n    const turbopack = {\n      ...turbopackConfig,\n      rules: {\n        ...turbopackConfig.rules,\n        [`./{src/,}app/**/page.{${MARKDOWN_EXTENSIONS}}`]: {\n          as: '*.tsx',\n          loaders: [pageImportLoader as any]\n        },\n        // Order matter here, pages match first -> after partial files\n        [`*.{${MARKDOWN_EXTENSIONS}}`]: {\n          as: '*.tsx',\n          loaders: [loader as any]\n        },\n        [`**${PAGE_MAP_PLACEHOLDER_PATH}`]: {\n          loaders: [pageMapPlaceholderLoader]\n        },\n        [`**${GET_PAGE_MAP_PATH}`]: {\n          loaders: [pageMapLoader]\n        }\n      },\n      resolveAlias: {\n        'next-mdx-import-source-file':\n          '@vercel/turbopack-next/mdx-import-source',\n        // Fixes when Turbopack is enabled: Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'\n        '@theguild/remark-mermaid/mermaid': path.relative(\n          CWD,\n          path.join(\n            require.resolve('@theguild/remark-mermaid/package.json'),\n            '..',\n            'dist',\n            'mermaid.js'\n          )\n        ),\n        ...turbopackConfig.resolveAlias,\n        'private-next-root-dir/*': './*',\n        'private-next-content-dir/*': `./${CONTENT_DIR}/*`\n      }\n    } satisfies NextConfig['turbopack']\n\n    return {\n      ...nextConfig,\n      ...(shouldUseConfigTurbopack && { turbopack }),\n      transpilePackages: [\n        // To import ESM-only packages with `next dev --turbopack`. Source: https://github.com/vercel/next.js/issues/63318#issuecomment-2079677098\n        ...// Next.js 15\n        (process.env.TURBOPACK === '1' ||\n        // Next.js 16\n        process.env.TURBOPACK === 'auto'\n          ? ['shiki', 'ts-morph']\n          : []),\n        ...(nextConfig.transpilePackages || [])\n      ],\n      pageExtensions: [\n        ...(nextConfig.pageExtensions || DEFAULT_EXTENSIONS),\n        ...MARKDOWN_EXTENSIONS\n      ],\n      // We always unset `nextConfig.i18n` property\n      i18n: undefined,\n      env: {\n        ...nextConfig.env,\n        NEXTRA_LOCALES: JSON.stringify(pageMapLoader.options.locales),\n        NEXTRA_DEFAULT_LOCALE: defaultLocale,\n        NEXTRA_SHOULD_ADD_LOCALE_TO_LINKS: String(\n          loaderOptions.unstable_shouldAddLocaleToLinks\n        )\n      },\n      experimental: {\n        ...nextConfig.experimental,\n        optimizePackageImports: [\n          'nextra/components',\n          'nextra-theme-docs',\n          'nextra-theme-blog',\n          ...(nextConfig.experimental?.optimizePackageImports || [])\n        ],\n        ...(!shouldUseConfigTurbopack && { turbo: turbopack })\n      },\n      webpack(config, options) {\n        // Fixes https://github.com/vercel/next.js/issues/55872\n        if (config.watchOptions.ignored instanceof RegExp) {\n          const ignored = config.watchOptions.ignored.source\n\n          config.watchOptions = {\n            ...config.watchOptions,\n            ignored: new RegExp(\n              ignored.replace(\n                String.raw`(\\.(git|next)|node_modules)`,\n                String.raw`\\.(git|next)`\n              )\n            )\n          }\n        }\n        config.resolve.alias['private-next-content-dir'] = [\n          'private-next-root-dir/content',\n          'private-next-root-dir/src/content'\n        ]\n        config.resolve.alias['next-mdx-import-source-file'] = [\n          'private-next-root-dir/mdx-components',\n          'private-next-root-dir/src/mdx-components'\n        ]\n        const rules = config.module.rules as RuleSetRule[]\n\n        rules.push(\n          {\n            test: PAGE_MAP_PLACEHOLDER_RE,\n            use: [options.defaultLoaders.babel, pageMapPlaceholderLoader]\n          },\n          {\n            test: GET_PAGE_MAP_RE,\n            use: [options.defaultLoaders.babel, pageMapLoader]\n          },\n          {\n            test: MARKDOWN_EXTENSION_RE,\n            oneOf: [\n              {\n                // Match pages (imports without an issuer request).\n                issuer: request => request === '',\n                use: [options.defaultLoaders.babel, pageImportLoader]\n              },\n              {\n                // Match Markdown imports from non-pages. These imports have an\n                // issuer, which can be anything as long as it's not empty string.\n                // When the issuer is `null`, it means that it can be imported via a\n                // runtime import call such as `import('...')`.\n                // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- types are wrong, value can be null\n                issuer: request => request === null || !!request,\n                use: [options.defaultLoaders.babel, loader]\n              }\n            ]\n          }\n        )\n\n        return nextConfig.webpack?.(config, options) || config\n      }\n    }\n  }\n}\n\nexport default nextra\n\nexport type * from '../types.js'\n"
  },
  {
    "path": "packages/nextra/src/server/loader.ts",
    "content": "import path from 'node:path'\nimport { transformerTwoslash } from '@shikijs/twoslash'\nimport { findPagesDir } from 'next/dist/lib/find-pages-dir.js'\nimport type { LoaderContext } from 'webpack'\nimport type { LoaderOptions } from '../types.js'\nimport { compileMetadata } from './compile-metadata.js'\nimport { compileMdx } from './compile.js'\nimport { CWD, IS_PRODUCTION, METADATA_ONLY_RQ } from './constants.js'\nimport { findMetaAndPageFilePaths } from './page-map/find-meta-and-page-file-paths.js'\nimport { convertPageMapToJs } from './page-map/to-js.js'\nimport { convertToPageMap } from './page-map/to-page-map.js'\nimport { twoslashRenderer } from './twoslash.js'\nimport { logger } from './utils.js'\n\nconst NOW = Date.now()\nconst APP_DIR = findPagesDir(CWD).appDir!\n\nif (!APP_DIR) {\n  throw new Error('Unable to find `app` directory')\n}\n\nconst repository = await (async () => {\n  if (process.versions.webcontainer) return\n  const { Repository } = await import('@napi-rs/simple-git')\n  try {\n    const repository = Repository.discover(CWD)\n    if (repository.isShallow()) {\n      if (process.env.VERCEL) {\n        logger.warn(\n          'The repository is shallow cloned, so the latest modified time will not be presented. Set the VERCEL_DEEP_CLONE=true environment variable to enable deep cloning.'\n        )\n      } else if (process.env.GITHUB_ACTION) {\n        logger.warn(\n          'The repository is shallow cloned, so the latest modified time will not be presented. See https://github.com/actions/checkout#fetch-all-history-for-all-tags-and-branches to fetch all the history.'\n        )\n      } else {\n        logger.warn(\n          'The repository is shallow cloned, so the latest modified time will not be presented.'\n        )\n      }\n    }\n    return repository\n  } catch (error) {\n    logger.warn(`Init git repository failed ${(error as Error).message}`)\n  }\n})()\n\n// repository.path() returns the `/path/to/repo/.git`, we need the parent directory of it\nconst GIT_ROOT = repository ? path.join(repository.path(), '..') : ''\n\nconst DEFAULT_TRANSFORMERS = transformerTwoslash({\n  renderer: twoslashRenderer(),\n  explicitTrigger: true\n})\n\nexport async function loader(\n  this: LoaderContext<LoaderOptions>,\n  source: string\n): Promise<string> {\n  const {\n    isPageImport,\n    defaultShowCopyCode,\n    search,\n    staticImage,\n    readingTime: _readingTime,\n    latex,\n    codeHighlight,\n    mdxOptions,\n    contentDirBasePath,\n    contentDir,\n    locales,\n    whiteListTagsStyling,\n    shouldAddLocaleToLinks\n  } = this.getOptions()\n  const { resourcePath, resourceQuery } = this\n\n  // We pass `contentDir` only for `page-map/placeholder.ts`\n  if (contentDir) {\n    const locale = resourceQuery.replace('?lang=', '')\n    // Add `app` and `content` folders as the dependencies, so Webpack will\n    // rebuild the module if anything in that context changes\n    //\n    // Note: should be added for dev and prod environment since build can be crashed after renaming\n    // mdx pages https://github.com/shuding/nextra/issues/3988#issuecomment-2605389046\n    this.addContextDependency(APP_DIR)\n    this.addContextDependency(path.join(CWD, contentDir, locale))\n\n    const filePaths = await findMetaAndPageFilePaths({\n      dir: APP_DIR,\n      cwd: CWD,\n      locale,\n      contentDir\n    })\n    let { pageMap, mdxPages } = convertToPageMap({\n      filePaths,\n      basePath: shouldAddLocaleToLinks\n        ? [locale, contentDirBasePath].filter(Boolean).join('/')\n        : contentDirBasePath,\n      locale\n    })\n    if (shouldAddLocaleToLinks && 'children' in pageMap[0]!) {\n      pageMap = pageMap[0].children\n    }\n    const globalMetaPath = filePaths.find(filePath =>\n      filePath.includes('/_meta.global.')\n    )\n    return convertPageMapToJs({ pageMap, mdxPages, globalMetaPath })\n  }\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- We pass `locales` only for `page-map/get.ts`\n  if (locales) {\n    return replaceDynamicResourceQuery(\n      source,\n      'import(`./placeholder.js?lang=${lang}`)',\n      locales\n    )\n  }\n\n  // Run only on production because it can slow down Fast Refresh for uncommitted files\n  // https://github.com/shuding/nextra/issues/3675#issuecomment-2466416366\n  const lastCommitTime = IS_PRODUCTION\n    ? await getLastCommitTime(resourcePath)\n    : NOW\n\n  if (!IS_PRODUCTION && resourceQuery === METADATA_ONLY_RQ) {\n    return compileMetadata(source, {\n      filePath: resourcePath,\n      lastCommitTime\n    })\n  }\n  return compileMdx(source, {\n    mdxOptions: {\n      ...mdxOptions,\n      jsx: true,\n      outputFormat: 'program',\n      rehypePrettyCodeOptions: {\n        ...mdxOptions.rehypePrettyCodeOptions,\n        transformers: [\n          DEFAULT_TRANSFORMERS,\n          ...(mdxOptions.rehypePrettyCodeOptions.transformers || [])\n        ]\n      }\n    },\n    readingTime: _readingTime,\n    defaultShowCopyCode,\n    staticImage,\n    search,\n    latex,\n    codeHighlight,\n    filePath: resourcePath,\n    useCachedCompiler: true,\n    isPageImport,\n    whiteListTagsStyling,\n    lastCommitTime\n  })\n}\n\n/*\n * https://github.com/vercel/next.js/issues/71453#issuecomment-2431810574\n *\n * Replace `await import(`./placeholder.js?lang=${lang}`)`\n *\n * with:\n *\n * await {\n * \"en\": () => import(\"./placeholder.js?lang=en\"),\n * \"es\": () => import(\"./placeholder.js?lang=es\"),\n * \"ru\": () => import(\"./placeholder.js?lang=ru\")\n * }[locale]()\n *\n * So static analyzer will know which `resourceQuery` to pass to the loader\n **/\nfunction replaceDynamicResourceQuery(\n  rawJs: string,\n  rawImport: string,\n  locales: string[]\n): string {\n  const { importPath } =\n    rawJs.match(/import\\(`(?<importPath>.+?)\\?lang=\\${lang}`\\)/)?.groups || {}\n  if (!importPath) {\n    throw new Error(\n      `Can't find \\`${rawImport}\\` statement. This is a Nextra bug`\n    )\n  }\n\n  const replaced = `{\n${locales\n  .map(lang => `\"${lang}\": () => import(\"${importPath}?lang=${lang}\")`)\n  .join(',\\n')}\n}[lang]()`\n\n  return rawJs.replace(rawImport, replaced)\n}\n\nasync function getLastCommitTime(\n  filePath: string\n): Promise<number | undefined> {\n  if (!repository) {\n    // Skip since we already logged logger.warn('Init git repository failed')\n    return\n  }\n  const relativePath = path.relative(GIT_ROOT, filePath)\n  try {\n    return await repository.getFileLatestModifiedDateAsync(relativePath)\n  } catch {\n    logger.warn(\n      'Failed to get the last modified timestamp from Git for the file',\n      relativePath\n    )\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/locales.ts",
    "content": "import { match as matchLocale } from '@formatjs/intl-localematcher'\nimport Negotiator from 'negotiator'\nimport { addBasePath } from 'next/dist/client/add-base-path'\nimport { NextResponse } from 'next/server'\nimport type { NextRequest } from 'next/server'\n\nconst locales = JSON.parse(process.env.NEXTRA_LOCALES!) as string[]\n\nconst defaultLocale = process.env.NEXTRA_DEFAULT_LOCALE!\n\nconst HAS_LOCALE_RE = new RegExp(String.raw`^\\/(${locales.join('|')})(\\/|$)`)\n\nconst COOKIE_NAME = 'NEXT_LOCALE'\n\nfunction getHeadersLocale(request: NextRequest): string {\n  const headers = Object.fromEntries(\n    // @ts-expect-error -- this works\n    request.headers.entries()\n  )\n\n  // Use negotiator and intl-localematcher to get best locale\n  const languages = new Negotiator({ headers }).languages(locales)\n  const locale = matchLocale(languages, locales, defaultLocale)\n\n  return locale\n}\n\n/**\n *\n * @example\n * ```ts\n * // Basic usage\n * export { proxy } from 'nextra/locales'\n *\n * export const config = {\n *   // Matcher ignoring `/_next/` and `/api/`\n *   matcher: [\n *     '/((?!api|_next/static|_next/image|favicon.ico|icon.svg|apple-icon.png|manifest|_pagefind).*)'\n *   ]\n * }\n * ```\n */\nexport function proxy(request: NextRequest) {\n  const { pathname } = request.nextUrl\n\n  // Check if there is any supported locale in the pathname\n  const pathnameHasLocale = HAS_LOCALE_RE.test(pathname)\n  const cookieLocale = request.cookies.get(COOKIE_NAME)?.value\n\n  // Redirect if there is no locale\n  if (!pathnameHasLocale) {\n    const locale = cookieLocale || getHeadersLocale(request)\n\n    const url = addBasePath(`/${locale}${pathname}`)\n    // e.g. incoming request is /products\n    // The new URL is now /en-US/products\n    return NextResponse.redirect(new URL(url, request.url))\n  }\n\n  const [, requestLocale] = pathname.split('/', 2)\n\n  if (requestLocale !== cookieLocale) {\n    const response = NextResponse.next()\n    response.cookies.set(COOKIE_NAME, requestLocale!)\n    return response\n  }\n}\n\n/** @deprecated Use `export { proxy } from 'nextra/locales'` instead. */\nexport const middleware = proxy\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/find-meta-and-page-file-paths.ts",
    "content": "import path from 'node:path'\nimport fg from 'fast-glob'\nimport slash from 'slash'\n\nexport async function findMetaAndPageFilePaths({\n  dir,\n  cwd,\n  locale = '',\n  // Can be `src/content` also\n  contentDir = 'content'\n}: {\n  dir: string\n  cwd: string\n  locale?: string\n  contentDir?: string\n}): Promise<string[]> {\n  const appDir = slash(path.relative(cwd, dir))\n  if (locale) contentDir += `/${locale}`\n  // appDir is empty string on tests\n  const pattern = appDir\n    ? [\n        `${contentDir}/**/_meta.{js,jsx,ts,tsx}`, // Include `_meta` files from `content` directory\n        `${contentDir}/**/*.{md,mdx}`, // Include all Markdown/MDX files from `content` directory\n        `${appDir}/**/page.{js,jsx,jsx,tsx,md,mdx}`,\n        `${appDir}/**/_meta.{js,jsx,ts,tsx}`, // Include `_meta` files from `app` directory\n        `${appDir}/_meta.global.{js,jsx,ts,tsx}`, // Include global `_meta` file from `app` directory\n        `!${appDir}/**/{_,[}*/*` // Ignore subdirectories starting with `_` and dynamic routes\n      ]\n    : ['**/_meta.{js,jsx,ts,tsx}', '**/*.{md,mdx}']\n  const result = await fg(pattern, { cwd })\n  // Sort file paths alphabetically because there is different order on each\n  // fast-glob invocation\n  const relativePaths = result.sort((a, b) => a.localeCompare(b))\n  return relativePaths\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/get.ts",
    "content": "import type { Folder, PageMapItem } from '../../types.js'\n\nfunction importPageMap(lang = ''): Promise<{\n  pageMap: PageMapItem[]\n  RouteToFilepath: Record<string, string>\n}> {\n  return import(`./placeholder.js?lang=${lang}`)\n}\n\nconst defaultLocale = process.env.NEXTRA_DEFAULT_LOCALE\n\n/**\n * Retrieves the page map structure for a given route handling nested routes.\n *\n * The page map structure represents the hierarchical organization of your documentation or content,\n * where each item can be either a page or a folder containing more pages.\n *\n * @returns A Promise that resolves to an array of `PageMapItem` objects representing the page structure\n * such as `MdxFile`, `Folder` and `MetaJsonFile`.\n *\n * @example\n * ```ts\n * import { getPageMap } from 'nextra/page-map'\n *\n * // Get the root page map\n * const rootPageMap = await getPageMap()\n *\n * // Get the page map for a specific route\n * const blogPageMap = await getPageMap('/blog')\n *\n * // Get the page map for a specific language when using i18n\n * const enPageMap = await getPageMap('/en')\n * ```\n *\n * @throws {Error} when the specified route segment cannot be found in the page map.\n *\n * @see [Page Map Structure Documentation](https://nextra.site/docs/file-conventions/meta-file#pagemap-structure).\n */\nexport async function getPageMap(\n  /**\n   * The route path to retrieve the page map for.\n   * @default \"/\"\n   */\n  route = '/'\n) {\n  const segments = route.split('/')\n  // Remove 1 or 2 items from the beginning of the array\n  const lang = segments.splice(0, defaultLocale ? 2 : 1).at(-1)!\n  let { pageMap } = await importPageMap(lang)\n\n  let segment: string | undefined\n  while ((segment = segments.shift())) {\n    const folder = pageMap.find(\n      (item): item is Folder => 'name' in item && item.name === segment\n    )\n    if (!folder) {\n      throw new Error(`Can't find pageMap for \"${segment}\" in route \"${route}\"`)\n    }\n    pageMap = folder.children\n  }\n\n  return pageMap\n}\n\nexport async function getRouteToFilepath(\n  lang?: string\n): Promise<Record<string, string>> {\n  const { RouteToFilepath } = await importPageMap(lang)\n  return RouteToFilepath\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/index-page.ts",
    "content": "import type { MdxFile, PageMapItem, SeparatorItem } from '../../types.js'\nimport { compileMdx } from '../compile.js'\n\nfunction renderCard(item: MdxFile): string {\n  const icon = item.frontMatter?.icon\n  const Icon = icon ? `<${icon}/>` : 'null'\n  // @ts-expect-error -- fixme\n  return `<Cards.Card title=\"${item.title}\" href=\"${item.route}\" icon={${Icon}} />`\n}\n\nexport async function createIndexPage(pageMap: PageMapItem[]): Promise<string> {\n  const result = []\n  let hasCards = false\n  for (const item of pageMap) {\n    if ('data' in item) {\n      continue\n    }\n    // @ts-expect-error fixme\n    if (item.type === 'separator') {\n      if (hasCards) {\n        result.push('</Cards>')\n        hasCards = false\n      }\n      // @ts-expect-error fixme\n      result.push(`## ${item.title}`)\n      continue\n    }\n    if (!hasCards) {\n      hasCards = true\n      result.push('<Cards>')\n    }\n    result.push(renderCard(item))\n  }\n  if (hasCards) {\n    result.push('</Cards>')\n  }\n  const rawMdx = result.join('\\n')\n\n  const rawJs = await compileMdx(rawMdx)\n\n  return rawJs\n}\n\nexport function getIndexPageMap(pageMap: PageMapItem[]) {\n  const result: (SeparatorItem | MdxFile[])[] = []\n  for (const item of pageMap) {\n    if ('data' in item) {\n      continue\n    }\n    // @ts-expect-error fixme\n    if (item.type === 'separator') {\n      // @ts-expect-error fixme\n      result.push(item)\n    } else {\n      const lastResult = result.at(-1)\n      if (Array.isArray(lastResult)) {\n        lastResult.push(item)\n      } else {\n        result.push([item])\n      }\n    }\n  }\n  return result\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/index.ts",
    "content": "import type { Metadata } from 'next'\n\nexport { normalizePageMap } from './normalize.js'\nexport { convertToPageMap } from './to-page-map.js'\nexport { mergeMetaWithPageMap } from './merge-meta-with-page-map.js'\nexport { getPageMap } from './get.js'\nexport { createIndexPage, getIndexPageMap } from './index-page.js'\n\nexport function getMetadata(\n  page:\n    | { metadata: Metadata }\n    | { generateMetadata?: (props: object) => Promise<Metadata> }\n): Promise<Metadata> | Metadata {\n  if (\n    'generateMetadata' in page &&\n    // `@sentry/nextjs` makes `generateMetadata` getter function which can be `undefined`\n    page.generateMetadata\n  ) {\n    return page.generateMetadata({})\n  }\n  if ('metadata' in page) {\n    return page.metadata\n  }\n  return {}\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/merge-meta-with-page-map.ts",
    "content": "import path from 'node:path'\nimport type {\n  $NextraMetadata,\n  DynamicFolder,\n  DynamicMeta,\n  DynamicMetaItem,\n  Folder,\n  MetaJsonFile,\n  PageMapItem,\n  TItem\n} from '../../types.js'\nimport { pageTitleFromFilename } from '../utils.js'\n\nfunction isFolder(value: DynamicMetaItem): value is DynamicFolder {\n  return (\n    !!value &&\n    typeof value === 'object' &&\n    'items' in value &&\n    // @ts-expect-error -- fixme\n    value.type !== 'menu'\n  )\n}\n\nfunction normalizeMetaRecord(\n  obj: DynamicMeta,\n  map: Record<string, $NextraMetadata>\n): DynamicMeta {\n  return Object.fromEntries(\n    Object.entries(obj).map(([key, value]) => {\n      let val\n\n      if (isFolder(value)) {\n        // Remove `items` object to make zod happy\n        const { items: _items, ...rest } = value\n        val = rest\n      } else {\n        val = value\n      }\n      return [key, map[key] ? val : val || pageTitleFromFilename(key)]\n    })\n  )\n}\n\nexport function mergeMetaWithPageMap<T extends Folder | PageMapItem[] | TItem>(\n  pageMap: T,\n  meta: DynamicMeta,\n  shouldCheckIndividualMetaFilesUsage = false\n): T {\n  if ('children' in pageMap) {\n    return {\n      ...pageMap,\n      children: mergeMetaWithPageMap(\n        // @ts-expect-error -- fixme\n        pageMap.children,\n        meta,\n        shouldCheckIndividualMetaFilesUsage\n      )\n    }\n  }\n  // @ts-expect-error -- pagePath exist\n  const result = pageMap.map(({ __pagePath, ...restParent }) => {\n    if ('children' in restParent) {\n      restParent.children = mergeMetaWithPageMap(\n        restParent.children,\n        // @ts-expect-error -- fixme\n        meta[restParent.name]?.items || {}\n      )\n      return restParent\n    }\n    return restParent\n  })\n  const normalizedMetaRecord = normalizeMetaRecord(\n    meta,\n    // @ts-expect-error -- fixme\n    Object.fromEntries(result.map(key => [key.name, key.frontMatter]))\n  )\n  const metaRecord = result[0] && 'data' in result[0] && result[0].data\n  if (metaRecord) {\n    if (shouldCheckIndividualMetaFilesUsage) {\n      const childRoute = result[1].route\n      const { dir } = path.parse(childRoute)\n      const metaPath = `${dir.replace(/^\\/$/, '')}/_meta`\n      throw new Error(\n        [\n          'Merging an `_meta.global` file with a folder-specific `_meta` is unsupported.',\n          `Move content of \\`${metaPath}\\` file into the \\`_meta.global\\` file`\n        ].join('\\n')\n      )\n    }\n    ;(result[0] as MetaJsonFile).data = {\n      ...metaRecord,\n      ...normalizedMetaRecord\n    }\n  } else {\n    result.unshift({ data: normalizedMetaRecord })\n  }\n  return result\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/normalize.ts",
    "content": "import { z } from 'zod'\nimport type {\n  Folder,\n  FrontMatter,\n  MdxFile,\n  PageMapItem,\n  TItem\n} from '../../types.js'\nimport { metaSchema } from '../schemas.js'\nimport { pageTitleFromFilename } from '../utils.js'\n\nexport function normalizePageMap(pageMap: PageMapItem[] | Folder | TItem): any {\n  if (Array.isArray(pageMap)) {\n    return sortFolder(\n      pageMap.map(item => ('children' in item ? normalizePageMap(item) : item))\n    )\n  }\n  return sortFolder(pageMap)\n}\n\ntype ParsedFolder = Folder & {\n  frontMatter?: FrontMatter\n}\n\nfunction titlize(item: Folder | MdxFile, meta: MetaRecord): string {\n  const titleFromMeta = meta[item.name]?.title\n  if (titleFromMeta) return titleFromMeta\n  if ('frontMatter' in item && item.frontMatter) {\n    const titleFromFrontMatter =\n      item.frontMatter.sidebarTitle || item.frontMatter.title\n\n    if (titleFromFrontMatter) return titleFromFrontMatter\n  }\n  // We use `title` package for capitalize folders without index page\n  return pageTitleFromFilename(item.name)\n}\n\ntype MetaRecord = Record<string, Record<string, any>>\n\nfunction sortFolder(pageMap: PageMapItem[] | Folder | TItem) {\n  const newChildren: (Folder | MdxFile)[] = []\n\n  const isFolder = !Array.isArray(pageMap)\n\n  const folder = (\n    isFolder ? { ...pageMap } : { children: pageMap }\n  ) as ParsedFolder\n\n  const meta: Record<string, Record<string, any>> = {}\n  for (const item of folder.children) {\n    if (\n      isFolder &&\n      'frontMatter' in item &&\n      item.frontMatter?.asIndexPage &&\n      item.route === folder.route\n    ) {\n      folder.frontMatter = item.frontMatter\n    } else if ('children' in item) {\n      newChildren.push(normalizePageMap(item))\n    } else if ('data' in item) {\n      for (const [key, titleOrObject] of Object.entries(item.data)) {\n        const { data, error } = metaSchema.safeParse(titleOrObject)\n        if (error) {\n          throw z.prettifyError(error)\n        }\n        if (key === '*') {\n          // @ts-expect-error -- fixme\n          delete data.title\n          // @ts-expect-error -- fixme\n          delete data.href\n        }\n        // @ts-expect-error -- fixme\n        meta[key] = data\n      }\n    } else {\n      newChildren.push(item)\n    }\n  }\n\n  const metaKeys = Object.keys(meta)\n  const hasIndexKey = metaKeys.includes('index')\n\n  // Normalize items based on files and _meta.json.\n  const items = newChildren.sort((a, b) => {\n    const indexA = metaKeys.indexOf(a.name)\n    const indexB = metaKeys.indexOf(b.name)\n    if (!hasIndexKey) {\n      if (b.name === 'index') return 1\n      if (a.name === 'index') return -1\n    }\n\n    if (indexA === -1 && indexB === -1) return a.name < b.name ? -1 : 1\n    if (indexA === -1) return 1\n    if (indexB === -1) return -1\n    return indexA - indexB\n  })\n\n  for (const [index, metaKey] of metaKeys\n    .filter(key => key !== '*')\n    .entries()) {\n    const metaItem = meta[metaKey]!\n    const item = items.find(item => item.name === metaKey)\n    if (metaItem.type === 'menu' && item) {\n      // @ts-expect-error fixme\n      item.items = metaItem.items\n\n      // Validate menu items, local page should exist\n      const { children } = items.find(\n        (i): i is Folder<MdxFile> => i.name === metaKey\n      )!\n      for (const [key, value] of Object.entries(\n        // @ts-expect-error fixme\n        item.items as Record<string, { title: string; href?: string }>\n      )) {\n        if (!value.href && children.every(i => i.name !== key)) {\n          throw new Error(\n            `Validation of \"_meta\" file has failed.\nThe field key \"${metaKey}.items.${key}\" in \\`_meta\\` file refers to a page that cannot be found, remove this key from \"_meta\" file.`\n          )\n        }\n      }\n    }\n    if (item) continue\n\n    const isValid =\n      metaItem.type === 'separator' || metaItem.type === 'menu' || metaItem.href\n\n    if (!isValid) {\n      throw new Error(\n        `Validation of \"_meta\" file has failed.\nThe field key \"${metaKey}\" in \\`_meta\\` file refers to a page that cannot be found, remove this key from \"_meta\" file.`\n      )\n    }\n\n    const currentItem = items[index]\n    if (currentItem?.name === metaKey) continue\n    items.splice(\n      index, // index at which to start changing the array\n      0, // remove zero items\n      // @ts-expect-error fixme\n      { name: metaKey, ...meta[metaKey] }\n    )\n  }\n\n  if (metaKeys.length) {\n    // @ts-expect-error -- fixme\n    items.unshift({ data: meta })\n  }\n\n  const itemsWithTitle = items.map(item => {\n    const isSeparator = 'type' in item && item.type === 'separator'\n    if ('name' in item && !isSeparator) {\n      return {\n        ...item,\n        title: titlize(item, meta)\n      }\n    }\n    return item\n  })\n\n  const result = isFolder\n    ? {\n        ...folder,\n        title: titlize(folder, {}),\n        children: itemsWithTitle\n      }\n    : itemsWithTitle\n  return result\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/placeholder.ts",
    "content": "// eslint-disable-next-line unicorn/no-empty-file -- Should exist; will be overridden by Webpack\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/to-ast.ts",
    "content": "import path from 'node:path'\nimport type { ArrayExpression } from 'estree'\nimport type { Import, TItem } from '../../types.js'\nimport { MARKDOWN_EXTENSION_RE } from '../constants.js'\nimport { createAstObject } from '../utils.js'\n\nfunction cleanFilePath(filePath: string): string {\n  // Remove extension\n  const { dir, name } = path.parse(filePath)\n  // Remove `content` prefix\n  const fileName = `${dir.replace(/^(src\\/)?content\\/?/, '')}_${name}`\n  return (\n    // handle non-\"\\w\" characters\n    encodeURI(fileName)\n      .replaceAll(/[\\W_]+/g, '_')\n      // Remove leading `_`\n      .replace(/^_/, '')\n      // Variable can't start with a number\n      .replace(/^\\d/, match => `_${match}`)\n  )\n}\n\nexport function convertPageMapToAst(\n  pageMap: TItem[],\n  imports: Import[]\n): ArrayExpression {\n  const elements = pageMap.map(item => {\n    if ('children' in item) {\n      return createAstObject({\n        name: item.name,\n        route: item.route,\n        children: convertPageMapToAst(item.children, imports)\n      })\n    }\n    if ('route' in item) {\n      const filePath = item.__pagePath\n      const importName = cleanFilePath(filePath)\n      imports.push({ importName, filePath })\n      return createAstObject({\n        name: item.name,\n        route: item.route,\n        frontMatter: MARKDOWN_EXTENSION_RE.test(filePath)\n          ? { type: 'Identifier', name: importName }\n          : {\n              type: 'CallExpression',\n              callee: { type: 'Identifier', name: 'getMetadata' },\n              arguments: [{ type: 'Identifier', name: importName }],\n              optional: false\n            }\n      })\n    }\n    const filePath = item.__metaPath\n    const importName = cleanFilePath(filePath)\n    imports.push({ importName, filePath })\n    return createAstObject({\n      data: { type: 'Identifier', name: importName }\n    })\n  })\n\n  return { type: 'ArrayExpression', elements }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/to-js.ts",
    "content": "import type { ImportDeclaration } from 'estree'\nimport { toJs } from 'estree-util-to-js'\nimport type { Import, TItem } from '../../types.js'\nimport { MARKDOWN_EXTENSION_RE, METADATA_ONLY_RQ } from '../constants.js'\nimport { convertPageMapToAst } from './to-ast.js'\n\nconst META_RE = /_meta\\.[jt]sx?$/\n\nexport function convertPageMapToJs({\n  pageMap,\n  mdxPages,\n  globalMetaPath\n}: {\n  pageMap: TItem[]\n  mdxPages: Record<string, string>\n  globalMetaPath?: string\n}): string {\n  const imports: Import[] = []\n  const pageMapAst = convertPageMapToAst(pageMap, imports)\n  const importsAst: ImportDeclaration[] = imports.map(\n    ({ filePath, importName }) => {\n      const isMdx = MARKDOWN_EXTENSION_RE.test(filePath)\n      const isMeta = META_RE.test(filePath)\n      return {\n        type: 'ImportDeclaration',\n        source: {\n          type: 'Literal',\n          // Add resource query only for `.md`, `.mdx` files\n          value: `private-next-root-dir/${filePath}${isMdx ? METADATA_ONLY_RQ : ''}`\n        },\n        specifiers: [\n          isMeta || isMdx\n            ? {\n                local: { type: 'Identifier', name: importName },\n                ...(isMeta\n                  ? { type: 'ImportDefaultSpecifier' }\n                  : {\n                      type: 'ImportSpecifier',\n                      imported: { type: 'Identifier', name: 'metadata' }\n                    })\n              }\n            : {\n                type: 'ImportNamespaceSpecifier',\n                local: { type: 'Identifier', name: importName }\n              }\n        ]\n      }\n    }\n  )\n\n  const importsResult = toJs({\n    type: 'Program',\n    sourceType: 'module',\n    body: importsAst\n  })\n\n  const pageMapResult = toJs({\n    type: 'Program',\n    sourceType: 'module',\n    body: [{ type: 'ExpressionStatement', expression: pageMapAst }]\n  })\n\n  let pageMapRawJs = pageMapResult.value.slice(0, -2 /* replace semicolon */)\n  if (globalMetaPath) {\n    pageMapRawJs = `mergeMetaWithPageMap(${pageMapRawJs}, globalMeta, true)`\n  }\n\n  const rawJs = `import { ${[\n    'normalizePageMap',\n    globalMetaPath && 'mergeMetaWithPageMap',\n    imports.some(\n      o => !MARKDOWN_EXTENSION_RE.test(o.filePath) && !META_RE.test(o.filePath)\n    ) && 'getMetadata'\n  ]\n    .filter(Boolean)\n    .join(', ')} } from 'nextra/page-map'\n${globalMetaPath ? `import globalMeta from 'private-next-root-dir/${globalMetaPath}'` : ''}\n${importsResult.value}\nexport const pageMap = normalizePageMap(${pageMapRawJs})\n\nexport const RouteToFilepath = ${JSON.stringify(mdxPages, null, 2)}`\n  return rawJs\n}\n"
  },
  {
    "path": "packages/nextra/src/server/page-map/to-page-map.ts",
    "content": "import path from 'node:path'\nimport { normalizeAppPath } from 'next/dist/shared/lib/router/utils/app-paths.js'\nimport type { TItem } from '../../types.js'\n\ninterface NestedMap {\n  [key: string]: NestedMap\n}\n\ntype StringMap = Record<string, string>\n\nfunction createNested(map: NestedMap, path: string): void {\n  let current = map\n  for (const part of path.split('/')) {\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- false positive?\n    current[part] ||= {} // Create the nested object if it doesn't exist\n    current = current[part] // Move to the next level of the structure\n  }\n}\n\nconst APP_DIR_SUFFIX_RE = /^(src\\/)?app\\//\n\nexport function convertToPageMap({\n  filePaths,\n  basePath,\n  locale\n}: {\n  filePaths: string[]\n  basePath?: string\n  locale?: string\n}) {\n  const pages: StringMap = {}\n  const metaFiles: StringMap = {}\n  const nestedMap: NestedMap = {}\n\n  for (const filePath of filePaths) {\n    let { name, dir } = path.parse(filePath)\n    const inAppDir = APP_DIR_SUFFIX_RE.test(filePath)\n    if (inAppDir) {\n      dir = dir.replace(/^(src\\/)?app(\\/|$)/, '')\n    } else {\n      let filePath = dir.replace(/^(src\\/)?content(\\/|$)/, '')\n      if (locale) filePath = filePath.replace(new RegExp(`^${locale}/?`), '')\n      dir = [basePath, filePath].filter(Boolean).join('/')\n    }\n    if (name === '_meta') {\n      const key = dir ? `${dir}/${name}` : name\n      metaFiles[key] = filePath\n    } else if (name !== '_meta.global') {\n      const key = inAppDir\n        ? // In Next.js we can organize routes without affecting the URL\n          // https://nextjs.org/docs/app/building-your-application/routing/route-groups#organize-routes-without-affecting-the-url-path\n          //\n          // E.g. we have the following filepath:\n          // app/posts/(with-comments)/aaron-swartz-a-programmable-web/()/page.mdx\n          //\n          // will be normalized to:\n          // app/posts/aaron-swartz-a-programmable-web/page.mdx\n          //\n          // The `normalizeAppPath` function ensures a leading slash is present, so we slice it off.\n          normalizeAppPath(dir).slice(1)\n        : [dir, name !== 'index' && name].filter(Boolean).join('/')\n      pages[key] = filePath\n    }\n  }\n\n  for (const path of Object.keys(metaFiles)) {\n    createNested(nestedMap, path)\n  }\n  for (const path of Object.keys(pages)) {\n    createNested(nestedMap, path && `${path}/`)\n  }\n\n  function fillPageMap(obj: NestedMap, prefix?: string): TItem[] {\n    return Object.entries(obj).map(([key, value]) => {\n      const path = prefix && key ? `${prefix}/${key}` : prefix || key\n      if (key === '_meta') {\n        const __metaPath = metaFiles[path]\n        if (!__metaPath) {\n          const o = JSON.stringify({ path, metaFiles }, null, 2)\n          throw new Error(`Can't find \"_meta\" file for:\\n${o}`)\n        }\n        return { __metaPath }\n      }\n      const item = {\n        name: key || 'index',\n        route: `/${path}`\n      }\n      const keys = Object.keys(value)\n      const isFolder = keys.length > 1 || (keys.length === 1 && keys[0] !== '')\n      if (isFolder) {\n        return { ...item, children: fillPageMap(value, path) }\n      }\n      const __pagePath = pages[path]\n      if (!__pagePath) {\n        const o = JSON.stringify({ path, mdxPages: pages }, null, 2)\n        throw new Error(`Can't find \"page\" file for:\\n${o}`)\n      }\n      return { ...item, __pagePath }\n    })\n  }\n\n  const pageMap = fillPageMap(nestedMap)\n\n  const mdxPages = Object.fromEntries(\n    Object.entries(pages).flatMap(([key, value]) => {\n      if (basePath) key = key.replace(new RegExp(`^${basePath}/?`), '')\n      value = value.replace(/^(src\\/)?content\\//, '')\n      if (locale) value = value.replace(new RegExp(`^${locale}/`), '')\n\n      // Do not add pages from `app/` dir to `mdxPages`\n      if (APP_DIR_SUFFIX_RE.test(value)) {\n        return []\n      }\n\n      return [[key, value]]\n    })\n  )\n  return { pageMap, mdxPages }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/recma-plugins/index.ts",
    "content": "export { recmaRewrite } from './recma-rewrite.js'\n"
  },
  {
    "path": "packages/nextra/src/server/recma-plugins/recma-rewrite.ts",
    "content": "import type {\n  CallExpression,\n  ImportDeclaration,\n  ObjectExpression,\n  Program\n} from 'estree'\nimport type { Plugin } from 'unified'\nimport { DEFAULT_PROPERTY_PROPS } from '../constants.js'\n\nenum Mdx {\n  Wrapper = 'MDXContent',\n  Content = '_createMdxContent'\n}\n\nexport const recmaRewrite: Plugin<\n  [{ isPageImport?: boolean; isRemoteContent?: boolean }],\n  Program\n> =\n  ({ isPageImport, isRemoteContent }) =>\n  (ast: Program) => {\n    const hasMdxLayout = ast.body.some(\n      node =>\n        node.type === 'VariableDeclaration' &&\n        node.kind === 'const' &&\n        node.declarations[0]!.id.type === 'Identifier' &&\n        node.declarations[0]!.id.name === 'MDXLayout'\n    )\n    // Remote MDX\n    if (isRemoteContent) {\n      if (hasMdxLayout) {\n        return\n      }\n      // Remove `function MDXContent` with wrapper logic\n      ast.body = ast.body.filter(\n        node =>\n          node.type !== 'FunctionDeclaration' || node.id.name !== Mdx.Wrapper\n      )\n      const returnStatement = ast.body.find(\n        node => node.type === 'ReturnStatement'\n      )!\n      const { properties } = returnStatement.argument as ObjectExpression\n      for (const node of properties) {\n        if (\n          node.type === 'Property' &&\n          node.key.type === 'Identifier' &&\n          node.key.name === 'default' &&\n          node.value.type === 'Identifier' &&\n          node.value.name === Mdx.Wrapper\n        ) {\n          node.value.name = Mdx.Content\n          break\n        }\n      }\n      return\n    }\n    const defaultExport = ast.body.find(\n      node => node.type === 'ExportDefaultDeclaration'\n    )!\n\n    if (hasMdxLayout) {\n      // `export default function MDXContent` > `function MDXContent`\n      Object.assign(defaultExport, defaultExport.declaration)\n      ast.body.unshift(HOC_IMPORT_AST)\n      ast.body.push({\n        type: 'ExportDefaultDeclaration',\n        declaration: createHocCallAst(Mdx.Wrapper)\n      })\n      return\n    }\n\n    // Page MDX\n    if (isPageImport) {\n      ast.body.unshift(HOC_IMPORT_AST)\n      defaultExport.declaration = createHocCallAst(Mdx.Content)\n      return\n    }\n    // Partial MDX\n    defaultExport.declaration = {\n      type: 'Identifier',\n      name: Mdx.Content\n    }\n  }\n\nconst HOC_IMPORT_AST: ImportDeclaration = {\n  type: 'ImportDeclaration',\n  source: { type: 'Literal', value: 'nextra/setup-page' },\n  specifiers: [\n    {\n      type: 'ImportSpecifier',\n      imported: { type: 'Identifier', name: 'HOC_MDXWrapper' },\n      local: { type: 'Identifier', name: 'HOC_MDXWrapper' }\n    }\n  ]\n}\n\nfunction createHocCallAst(componentName: string): CallExpression {\n  return {\n    type: 'CallExpression',\n    callee: { type: 'Identifier', name: 'HOC_MDXWrapper' },\n    optional: false,\n    arguments: [\n      { type: 'Identifier', name: componentName },\n      {\n        type: 'ObjectExpression',\n        properties: [\n          {\n            ...DEFAULT_PROPERTY_PROPS,\n            shorthand: true,\n            key: { type: 'Identifier', name: 'metadata' },\n            value: { type: 'Identifier', name: 'metadata' }\n          },\n          {\n            ...DEFAULT_PROPERTY_PROPS,\n            shorthand: true,\n            key: { type: 'Identifier', name: 'toc' },\n            value: { type: 'Identifier', name: 'toc' }\n          },\n          {\n            ...DEFAULT_PROPERTY_PROPS,\n            shorthand: true,\n            key: { type: 'Identifier', name: 'sourceCode' },\n            value: { type: 'Identifier', name: 'sourceCode' }\n          }\n        ]\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/rehype-plugins/index.ts",
    "content": "export {\n  rehypeParseCodeMeta,\n  rehypeAttachCodeMeta,\n  DEFAULT_REHYPE_PRETTY_CODE_OPTIONS\n} from './rehype.js'\nexport { rehypeBetterReactMathjax } from './rehype-better-react-mathjax.js'\nexport { rehypeExtractTocContent } from './rehype-extract-toc-content.js'\nexport { rehypeTwoslashPopup } from './rehype-twoslash-popup.js'\n"
  },
  {
    "path": "packages/nextra/src/server/rehype-plugins/rehype-better-react-mathjax.ts",
    "content": "import type { ImportDeclaration } from 'estree'\nimport { valueToEstree } from 'estree-util-value-to-estree'\nimport type { Element, ElementContent, Root } from 'hast'\nimport type { MdxJsxAttribute, MdxJsxFlowElementHast } from 'mdast-util-mdx-jsx'\nimport type { MdxjsEsmHast } from 'mdast-util-mdxjs-esm'\nimport type { Plugin } from 'unified'\nimport { visit } from 'unist-util-visit'\nimport type { MathJaxOptions } from '../../types.js'\n\nconst MATHJAX_IMPORTS = {\n  type: 'mdxjsEsm',\n  data: {\n    estree: {\n      body: [\n        {\n          type: 'ImportDeclaration',\n          source: { type: 'Literal', value: 'nextra/components' },\n          specifiers: ['MathJax', 'MathJaxContext'].map(name => ({\n            type: 'ImportSpecifier',\n            imported: { type: 'Identifier', name },\n            local: { type: 'Identifier', name }\n          }))\n        } satisfies ImportDeclaration\n      ]\n    }\n  }\n} as MdxjsEsmHast\n\nfunction wrapInMathJaxContext(\n  children: ElementContent[],\n  { config, src }: NonNullable<MathJaxOptions>\n): MdxJsxFlowElementHast {\n  const attributes: MdxJsxAttribute[] = []\n  if (src) {\n    attributes.push({ type: 'mdxJsxAttribute', name: 'src', value: src })\n  }\n  if (config && Object.keys(config).length) {\n    attributes.push({\n      type: 'mdxJsxAttribute',\n      name: 'config',\n      value: {\n        type: 'mdxJsxAttributeValueExpression',\n        value: '',\n        data: {\n          estree: {\n            type: 'Program',\n            sourceType: 'module',\n            body: [\n              { type: 'ExpressionStatement', expression: valueToEstree(config) }\n            ]\n          }\n        }\n      }\n    })\n  }\n\n  return {\n    type: 'mdxJsxFlowElement',\n    name: 'MathJaxContext',\n    attributes,\n    children\n  }\n}\n\n/**\n * Wrap the math in the appropriate braces. Defaults to `\\(...\\)` for inline and `\\[...\\]` for display,\n * but will use the braces provided by `options` if they are present.\n */\nfunction wrapInBraces(\n  source: string,\n  mathInline: boolean,\n  options: NonNullable<MathJaxOptions>\n): string {\n  const { inlineMath, displayMath } = options.config?.tex || {}\n\n  const inlineBraces = inlineMath?.[0] || [String.raw`\\(`, String.raw`\\)`]\n  const displayBraces = displayMath?.[0] || [String.raw`\\[`, String.raw`\\]`]\n  const [before, after] = mathInline ? inlineBraces : displayBraces\n  return `${before}${source}${after}`\n}\n\n/**\n * Wraps math in a `<MathJax>` component so that it can be rendered by `better-react-mathjax`.\n */\nexport const rehypeBetterReactMathjax: Plugin<\n  [Opts: MathJaxOptions, isRemoteContent: boolean],\n  Root\n> =\n  (options = {}, isRemoteContent) =>\n  ast => {\n    let hasMathJax = false\n\n    visit(ast, { tagName: 'code' }, (node, _index, parent) => {\n      const classes = Array.isArray(node.properties.className)\n        ? node.properties.className\n        : []\n      // This class can be generated from markdown with ` ```math `\n      const hasMathLanguage = classes.includes('language-math')\n      if (!hasMathLanguage) return\n\n      // This class is used by `remark-math` for text math (inline, `$math$`)\n      const isInlineMath = classes.includes('math-inline')\n\n      const [{ value }] = node.children as any\n      const bracketedValue = wrapInBraces(value, isInlineMath, options)\n\n      const mathJaxNode: Element = {\n        type: 'element',\n        tagName: 'MathJax',\n        children: [{ type: 'text', value: bracketedValue }],\n        properties: isInlineMath ? { inline: true } : {}\n      }\n\n      Object.assign((isInlineMath ? node : parent) as any, mathJaxNode)\n      hasMathJax = true\n    })\n\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- fixme\n    if (!hasMathJax) return\n\n    const mdxjsEsmNodes = []\n    const rest: ElementContent[] = []\n    for (const child of ast.children) {\n      if (child.type === 'mdxjsEsm') {\n        mdxjsEsmNodes.push(child)\n      } else {\n        rest.push(child as any)\n      }\n    }\n    ast.children = [\n      ...mdxjsEsmNodes,\n      ...(isRemoteContent ? [] : [MATHJAX_IMPORTS]),\n      // Wrap everything in a `<MathJaxContext>` component.\n      wrapInMathJaxContext(rest, options)\n    ]\n  }\n"
  },
  {
    "path": "packages/nextra/src/server/rehype-plugins/rehype-extract-toc-content.ts",
    "content": "import type { SpreadElement } from 'estree'\nimport type { Element, Root, Text } from 'hast'\nimport { toEstree } from 'hast-util-to-estree'\nimport type { MdxjsEsmHast } from 'mdast-util-mdxjs-esm'\nimport type { Plugin, Transformer } from 'unified'\nimport { SKIP, visit } from 'unist-util-visit'\nimport type { Heading } from '../../types.js'\nimport { createAstExportConst, createAstObject } from '../utils.js'\n\nconst TOC_HEADING_RE = /^h[2-6]$/\n\nconst transformer: Transformer<Root> = (ast, file) => {\n  const TocMap: Record<string, Element> = {}\n  visit(ast, 'element', (node, _index, parent) => {\n    if (!TOC_HEADING_RE.test(node.tagName)) return\n    if (parent && 'properties' in parent && parent.properties.dataFootnotes) {\n      return SKIP\n    }\n    const { id } = node.properties\n    TocMap[id as string] = node\n  })\n\n  const hasPartialMDX = (file.data.toc as Heading[]).some(\n    name => typeof name === 'string'\n  )\n\n  const elements = (file.data.toc as Heading[]).map((name, index) => {\n    if (typeof name === 'string') {\n      return {\n        type: 'SpreadElement',\n        argument: { type: 'Identifier', name }\n      } satisfies SpreadElement\n    }\n\n    const node = TocMap[name.id]!\n\n    const isTextOnly = node.children.every(child => child.type === 'text')\n\n    const result = isTextOnly\n      ? node.children.map(n => (n as Text).value).join('')\n      : // @ts-expect-error -- fixme\n        Object.assign(toEstree(node).body[0].expression, {\n          type: 'JSXFragment',\n          openingFragment: { type: 'JSXOpeningFragment' },\n          closingFragment: { type: 'JSXClosingFragment' }\n        })\n\n    // Example:\n    //\n    // ```mdx\n    // import Foo from './foo.mdx'\n    // # One\n    // <Foo />\n    // # Two <- will fails if Foo contains 0 toc items\n    // ```\n    //\n    // TODO: We can't know right toc index, because we don't know how many toc items exist in partial toc\n    // maybe we could refactor to have offset in the future\n    // this fix TypeError: Cannot read properties of undefined (reading 'id')\n    if (!hasPartialMDX) {\n      Object.assign(node, {\n        type: 'mdxJsxFlowElement',\n        name: node.tagName,\n        attributes: [\n          {\n            type: 'mdxJsxAttribute',\n            name: 'id',\n            value: createComputedKey(\n              'mdxJsxAttributeValueExpression',\n              index,\n              'id'\n            )\n          }\n        ],\n        children: [createComputedKey('mdxFlowExpression', index, 'value')]\n      })\n    }\n\n    return createAstObject({\n      value: result,\n      id: node.properties.id as string,\n      depth: Number(node.tagName[1])\n    })\n  })\n\n  ast.children.push({\n    type: 'mdxjsEsm',\n    data: {\n      estree: {\n        body: [\n          {\n            // TOC links must be inside a function, in our case inside useTOC, so\n            // mdx components will be injected for `<a>` or `<code>` tags inside headings\n            type: 'FunctionDeclaration',\n            id: { type: 'Identifier', name: 'useTOC' },\n            params: [{ type: 'Identifier', name: 'props' }],\n            body: {\n              type: 'BlockStatement',\n              body: [\n                {\n                  type: 'ReturnStatement',\n                  argument: { type: 'ArrayExpression', elements }\n                }\n              ]\n            }\n          },\n          createAstExportConst('toc', {\n            type: 'CallExpression',\n            callee: { type: 'Identifier', name: 'useTOC' },\n            // https://github.com/shuding/nextra/issues/3979\n            arguments: [{ type: 'ObjectExpression', properties: [] }],\n            optional: false\n          })\n        ]\n      }\n    }\n  } as MdxjsEsmHast)\n}\n\nfunction createComputedKey(\n  type: 'mdxFlowExpression' | 'mdxJsxAttributeValueExpression',\n  index: number,\n  key: string\n) {\n  return {\n    type,\n    data: {\n      estree: {\n        body: [\n          {\n            type: 'ExpressionStatement',\n            expression: {\n              type: 'MemberExpression',\n              property: { type: 'Identifier', name: key },\n              object: {\n                type: 'MemberExpression',\n                object: { type: 'Identifier', name: 'toc' },\n                property: { type: 'Literal', value: index },\n                computed: true\n              }\n            }\n          }\n        ]\n      }\n    }\n  }\n}\n\nexport const rehypeExtractTocContent: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/rehype-plugins/rehype-twoslash-popup.ts",
    "content": "import type { ImportDeclaration } from 'estree'\nimport type { Root } from 'hast'\nimport type { MdxjsEsmHast } from 'mdast-util-mdxjs-esm'\nimport type { Plugin, Transformer } from 'unified'\nimport { EXIT, visit } from 'unist-util-visit'\n\nconst TWOSLASH_POPUP_IMPORT_AST = {\n  type: 'mdxjsEsm',\n  data: {\n    estree: {\n      body: [\n        {\n          type: 'ImportDeclaration',\n          source: { type: 'Literal', value: 'nextra/components' },\n          specifiers: [\n            {\n              type: 'ImportSpecifier',\n              imported: { type: 'Identifier', name: 'Popup' },\n              local: { type: 'Identifier', name: 'Popup' }\n            }\n          ]\n        } satisfies ImportDeclaration\n      ]\n    }\n  }\n} as MdxjsEsmHast\n\nconst transformer: Transformer<Root> = ast => {\n  // The tagName is being converted to lowercase when calling the shiki.codeToHtml\n  // method inside rehypePrettyCode. Convert it back to Uppercase.\n  visit(\n    ast,\n    [\n      { tagName: 'popup' },\n      { tagName: 'popupbutton' },\n      { tagName: 'popuppanel' }\n    ],\n    node => {\n      const n = node as { tagName: string }\n      const tagName = {\n        popup: 'Popup',\n        popupbutton: 'Popup.Button',\n        popuppanel: 'Popup.Panel'\n      }[n.tagName]!\n      n.tagName = tagName\n    }\n  )\n\n  visit(ast, { tagName: 'code' }, node => {\n    if (node.data?.meta === 'twoslash') {\n      ast.children.unshift(TWOSLASH_POPUP_IMPORT_AST)\n      return EXIT\n    }\n  })\n}\n\nexport const rehypeTwoslashPopup: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/rehype-plugins/rehype.ts",
    "content": "import type { Element, Root } from 'hast'\nimport type { Options as RehypePrettyCodeOptions } from 'rehype-pretty-code'\nimport { bundledLanguages, createHighlighter } from 'shiki'\nimport type { Plugin } from 'unified'\nimport { SKIP, visit } from 'unist-util-visit'\nimport type { NextraConfig } from '../../types.js'\n\ntype PreElement = Element & {\n  __filename?: string\n  __hasCopyCode?: boolean\n  __hasWordWrap?: boolean\n}\n\nconst CODE_BLOCK_FILENAME_RE = /filename=\"([^\"]+)\"/\n\nexport const DEFAULT_REHYPE_PRETTY_CODE_OPTIONS: RehypePrettyCodeOptions = {\n  keepBackground: false,\n  grid: false,\n  onVisitLine(node) {\n    // Prevent lines from collapsing in `display: grid` mode, and\n    // allow empty lines to be copy/pasted\n    if (node.children.length === 0) {\n      node.children.push({ type: 'text', value: ' ' })\n    }\n    delete node.properties['data-line']\n  },\n  theme: {\n    light: 'github-light',\n    dark: 'github-dark'\n  },\n  defaultLang: {\n    block: 'plaintext'\n  },\n  filterMetaString: meta => meta.replace(CODE_BLOCK_FILENAME_RE, ''),\n  getHighlighter(opts) {\n    const langs = Object.keys(bundledLanguages).filter(l => l !== 'mermaid')\n    return createHighlighter({\n      ...opts,\n      // Without `getHighlighter` option ```mdx lang isn't highlighted\n      langs\n    })\n  }\n}\n\nexport const rehypeParseCodeMeta: Plugin<\n  [{ defaultShowCopyCode?: boolean }],\n  Root\n> =\n  ({ defaultShowCopyCode }) =>\n  ast => {\n    visit(ast, { tagName: 'pre' }, (node: PreElement) => {\n      const [codeEl] = node.children as Element[]\n      const { meta = '' } = codeEl!.data || {}\n\n      node.__filename = meta!.match(CODE_BLOCK_FILENAME_RE)?.[1]\n      node.properties['data-filename'] = node.__filename\n\n      node.__hasWordWrap = !meta!.includes('word-wrap=false')\n      if (node.__hasWordWrap) {\n        node.properties['data-word-wrap'] = ''\n      }\n\n      node.__hasCopyCode = meta\n        ? (defaultShowCopyCode && !/( |^)copy=false($| )/.test(meta)) ||\n          /( |^)copy($| )/.test(meta)\n        : defaultShowCopyCode\n      if (node.__hasCopyCode) {\n        node.properties['data-copy'] = ''\n      }\n    })\n  }\n\nexport const rehypeAttachCodeMeta: Plugin<\n  [{ search: NextraConfig['search'] }],\n  Root\n> = ({ search }) => {\n  const parseCodeblocks =\n    typeof search === 'object' ? search.codeblocks : search\n\n  return ast => {\n    visit(\n      ast as any,\n      [{ tagName: 'figure' }, { tagName: 'span' }],\n      (node: Element) => {\n        const isRehypePrettyCode =\n          'data-rehype-pretty-code-figure' in node.properties\n\n        if (!isRehypePrettyCode) return\n\n        // remove <figure data-rehype-pretty-code-figure> element that wraps <pre> element\n        // because we'll wrap with our own <div>\n        const preEl: PreElement = Object.assign(node, node.children[0])\n        delete preEl.properties['data-theme']\n\n        if (preEl.tagName === 'pre') {\n          const codeEl = preEl.children[0] as Element\n          delete codeEl.properties['data-theme']\n          delete codeEl.properties['data-language']\n\n          if (preEl.__hasWordWrap) {\n            preEl.properties['data-word-wrap'] = ''\n          }\n\n          if (preEl.__filename) {\n            preEl.properties['data-filename'] = preEl.__filename\n          }\n          if (preEl.__hasCopyCode) {\n            preEl.properties['data-copy'] = ''\n          }\n          if (!parseCodeblocks) {\n            preEl.properties['data-pagefind-ignore'] = 'all'\n          }\n          return SKIP\n        }\n\n        // remove class=\"line\"\n        // @ts-expect-error fixme\n        delete node.children[0].properties.className\n      }\n    )\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/index.ts",
    "content": "export { remarkCustomHeadingId } from './remark-custom-heading-id.js'\nexport { remarkExportOnlyMetadata } from './remark-export-only-metadata.js'\nexport { remarkExportSourceCode } from './remark-export-source-code.js'\nexport { remarkMdxFrontMatter } from './remark-mdx-frontmatter.js'\nexport { remarkMdxTitle } from './remark-mdx-title.js'\nexport { remarkHeadings } from './remark-headings.js'\nexport { remarkRemoveImports } from './remark-remove-imports.js'\nexport {\n  remarkLinkRewrite,\n  type RemarkLinkRewriteOptions\n} from './remark-link-rewrite.js'\nexport { remarkMdxDisableExplicitJsx } from './remark-mdx-disable-explicit-jsx.js'\nexport { remarkStaticImage } from './remark-static-image.js'\nexport { remarkAssignFrontMatter } from './remark-assign-frontmatter.js'\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-assign-frontmatter.ts",
    "content": "import path from 'node:path'\nimport type { Property } from 'estree'\nimport { valueToEstree } from 'estree-util-value-to-estree'\nimport type { Root } from 'mdast'\nimport slash from 'slash'\nimport type { Plugin } from 'unified'\nimport type { ReadingTime } from '../../types.js'\nimport { CWD } from '../constants.js'\nimport { getFrontMatterASTObject, isExportNode } from './remark-mdx-title.js'\n\nexport const remarkAssignFrontMatter: Plugin<\n  [{ lastCommitTime?: number }],\n  Root\n> =\n  ({ lastCommitTime }) =>\n  (ast: Root, file) => {\n    const frontMatterNode = ast.children.find(node =>\n      isExportNode(node, 'metadata')\n    )!\n    const frontMatter = getFrontMatterASTObject(frontMatterNode)\n\n    const [filePath] = file.history\n    const { readingTime, title } = file.data as {\n      readingTime?: ReadingTime\n      title?: string\n    }\n\n    const { properties } = valueToEstree({\n      ...(title && { title }),\n      // File path can be undefined (e.g. dynamic mdx without filePath provided to processor)\n      ...(filePath && { filePath: slash(path.relative(CWD, filePath)) }),\n      ...(readingTime && { readingTime }),\n      ...(lastCommitTime && { timestamp: lastCommitTime })\n    }) as { properties: Property[] }\n    frontMatter.push(...properties)\n  }\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-custom-heading-id.ts",
    "content": "import type { Root } from 'mdast'\nimport type { Plugin, Transformer } from 'unified'\nimport { visit } from 'unist-util-visit'\n\nexport type HProperties = {\n  id?: string\n}\n\nconst transformer: Transformer<Root> = ast => {\n  visit(ast, 'heading', node => {\n    const lastChild = node.children.at(-1)\n    if (lastChild?.type !== 'text') return\n\n    const heading = lastChild.value\n    const matched = heading.match(/\\s*\\[#([^]+?)]\\s*$/)\n\n    if (!matched) return\n    node.data ||= {}\n    const headingProps: HProperties = (node.data.hProperties ||= {})\n    headingProps.id = matched[1]\n\n    lastChild.value = heading.slice(0, matched.index)\n  })\n}\n\nexport const remarkCustomHeadingId: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-export-only-metadata.ts",
    "content": "import type { Root } from 'mdast'\nimport type { Plugin, Transformer } from 'unified'\nimport { remove } from 'unist-util-remove'\n\nconst transformer: Transformer<Root> = ast => {\n  remove(ast, node => {\n    const isMdxJs = node.type === 'mdxjsEsm'\n\n    if (!isMdxJs) return true\n\n    // @ts-expect-error -- fixme\n    const [body] = node.data.estree.body\n    const isExportNamed = body.type === 'ExportNamedDeclaration'\n\n    if (!isExportNamed) return true\n\n    const isVariableDeclaration =\n      body.declaration?.type === 'VariableDeclaration'\n    if (!isVariableDeclaration) return true\n\n    const isMetadata = body.declaration.declarations[0].id.name === 'metadata'\n    return !isMetadata\n  })\n}\nexport const remarkExportOnlyMetadata: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-export-source-code.ts",
    "content": "import type { Root } from 'mdast'\nimport type { Plugin } from 'unified'\n\n// eslint-disable-next-line unicorn/consistent-function-scoping\nexport const remarkExportSourceCode: Plugin<[], Root> = () => (ast, file) => {\n  ast.children.push({\n    type: 'mdxjsEsm',\n    value: '',\n    data: {\n      estree: {\n        type: 'Program',\n        sourceType: 'module',\n        body: [\n          {\n            type: 'ExportNamedDeclaration',\n            specifiers: [],\n            declaration: {\n              type: 'VariableDeclaration',\n              kind: 'const',\n              declarations: [\n                {\n                  type: 'VariableDeclarator',\n                  id: { type: 'Identifier', name: 'sourceCode' },\n                  init: {\n                    type: 'Literal',\n                    value: String(file.value).trim()\n                  }\n                }\n              ]\n            }\n          }\n        ]\n      }\n    }\n  })\n}\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-headings.ts",
    "content": "import Slugger from 'github-slugger'\nimport type { Literal } from 'hast'\nimport type { Parent, Root } from 'mdast'\nimport type {\n  MdxJsxAttribute,\n  MdxJsxExpressionAttribute\n} from 'mdast-util-mdx-jsx'\nimport type { Plugin } from 'unified'\nimport { visit } from 'unist-util-visit'\nimport { visitChildren } from 'unist-util-visit-children'\nimport type { Heading } from '../../types.js'\nimport { MARKDOWN_EXTENSION_RE } from '../constants.js'\nimport { createAstObject } from '../utils.js'\nimport type { HProperties } from './remark-custom-heading-id.js'\n\nexport const getFlattenedValue = (node: Parent): string =>\n  node.children\n    .map(child =>\n      'children' in child\n        ? getFlattenedValue(child)\n        : 'value' in child\n          ? child.value\n          : ''\n    )\n    .join('')\n\nexport const remarkHeadings: Plugin<\n  [{ exportName?: string; isRemoteContent?: boolean }],\n  Root\n> = ({ exportName = 'toc', isRemoteContent }) => {\n  const headings: (Heading | string)[] = []\n\n  const slugger = new Slugger()\n  return (ast, file) => {\n    const PartialComponentToHeadingsName: Record<string, string> =\n      Object.create(null)\n\n    visit(\n      ast,\n      [\n        'heading',\n        // push partial component's `toc` export name to headings list\n        'mdxJsxFlowElement',\n        // verify .md/.mdx exports and attach named `toc` export\n        'mdxjsEsm'\n      ],\n      (node, index, parent) => {\n        if (node.type === 'heading') {\n          if (node.depth === 1) {\n            return\n          }\n\n          node.data ||= {}\n          const headingProps: HProperties = (node.data.hProperties ||= {})\n          const value = getFlattenedValue(node)\n          const id = slugger.slug(headingProps.id || value)\n          // Attach flattened/custom #id to heading node\n          headingProps.id = id\n          headings.push({ depth: node.depth, value, id })\n          return\n        }\n\n        const isTab =\n          node.type === 'mdxJsxFlowElement' && node.name === 'Tabs.Tab'\n        if (isTab) {\n          const itemsAttr: any =\n            parent?.type === 'mdxJsxFlowElement' &&\n            parent.name === 'Tabs' &&\n            parent.attributes.find(\n              (\n                attr: MdxJsxExpressionAttribute | MdxJsxAttribute\n              ): attr is MdxJsxAttribute =>\n                attr.type === 'mdxJsxAttribute' && attr.name === 'items'\n            )\n          if (!itemsAttr) return\n          const tabName =\n            itemsAttr.value.data.estree.body[0].expression.elements.map(\n              (el: Literal) => el.value\n            )[index!]\n          const id = slugger.slug(tabName)\n          node.children.unshift({\n            type: 'mdxJsxFlowElement',\n            name: 'h3',\n            data: { _mdxExplicitJsx: true },\n            children: [{ type: 'text', value: tabName }],\n            attributes: [\n              { type: 'mdxJsxAttribute', name: 'id', value: id },\n              {\n                type: 'mdxJsxAttribute',\n                name: 'style',\n                value: {\n                  type: 'mdxJsxAttributeValueExpression',\n                  value: '',\n                  data: {\n                    estree: {\n                      type: 'Program',\n                      sourceType: 'module',\n                      comments: [],\n                      body: [\n                        {\n                          type: 'ExpressionStatement',\n                          expression: createAstObject({\n                            visibility: 'hidden',\n                            width: 0,\n                            height: 0\n                          })\n                        }\n                      ]\n                    }\n                  }\n                }\n              }\n            ] satisfies MdxJsxAttribute[]\n          } as any)\n        }\n\n        const isDetails =\n          node.type === 'mdxJsxFlowElement' && node.name === 'details'\n        if (isDetails) {\n          const visitor = visitChildren((node: any) => {\n            const isSummary =\n              node.type === 'mdxJsxTextElement' && node.name === 'summary'\n            if (isSummary) {\n              const value = getFlattenedValue(node)\n              const id = slugger.slug(value)\n              node.attributes.push({\n                type: 'mdxJsxAttribute',\n                name: 'id',\n                value: id\n              })\n            } else if ('children' in node) {\n              visitor(node)\n            }\n          })\n          visitor(node)\n        }\n\n        if (isRemoteContent) {\n          // skip\n        } else if ((node as any).type === 'mdxjsEsm') {\n          for (const child of (node as any).data.estree.body) {\n            if (child.type !== 'ImportDeclaration') continue\n            const importPath = child.source.value\n            const isMdxImport = MARKDOWN_EXTENSION_RE.test(importPath)\n            if (!isMdxImport) continue\n\n            const componentName = child.specifiers.find(\n              (o: any) => o.type === 'ImportDefaultSpecifier'\n            )?.local.name\n\n            if (!componentName) continue\n            const { length } = Object.keys(PartialComponentToHeadingsName)\n            const exportAsName = `${exportName}${length}`\n            PartialComponentToHeadingsName[componentName] = exportAsName\n\n            child.specifiers.push({\n              type: 'ImportSpecifier',\n              imported: { type: 'Identifier', name: exportName },\n              local: { type: 'Identifier', name: exportAsName }\n            })\n          }\n        } else {\n          // If component name equals default export name from .md/.mdx import\n          const headingsName =\n            PartialComponentToHeadingsName[(node as any).name]\n          if (headingsName) {\n            headings.push(headingsName)\n          }\n        }\n      }\n    )\n\n    file.data.toc = headings\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-link-rewrite.ts",
    "content": "import type { Root } from 'mdast'\nimport type { Plugin } from 'unified'\nimport { visit } from 'unist-util-visit'\nimport { EXTERNAL_URL_RE } from '../constants.js'\n\nexport type RemarkLinkRewriteOptions = {\n  pattern: RegExp\n  replace: string\n  excludeExternalLinks?: boolean\n}\n\nexport const remarkLinkRewrite: Plugin<[RemarkLinkRewriteOptions], Root> =\n  ({ pattern, replace, excludeExternalLinks }) =>\n  ast => {\n    visit(ast, 'link', node => {\n      if (!excludeExternalLinks || !EXTERNAL_URL_RE.test(node.url)) {\n        node.url = node.url.replace(pattern, replace)\n      }\n    })\n  }\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-mdx-disable-explicit-jsx.ts",
    "content": "import type { Root } from 'mdast'\nimport type { Plugin } from 'unified'\nimport { visit } from 'unist-util-visit'\n\nexport const remarkMdxDisableExplicitJsx: Plugin<\n  [{ whiteList: string[] }],\n  Root\n> =\n  ({ whiteList }) =>\n  ast => {\n    const test = whiteList.map(name => ({ name }))\n    visit(ast, test, node => {\n      delete (node.data as any)._mdxExplicitJsx\n    })\n  }\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-mdx-frontmatter.ts",
    "content": "import { valueToEstree } from 'estree-util-value-to-estree'\nimport type { Root } from 'mdast'\nimport type { MdxjsEsmHast } from 'mdast-util-mdxjs-esm'\nimport type { Plugin, Transformer } from 'unified'\nimport { parse as parseYaml } from 'yaml'\nimport { createAstExportConst } from '../utils.js'\nimport { isExportNode } from './remark-mdx-title.js'\n\nfunction createNode(data: Record<string, unknown>) {\n  return {\n    type: 'mdxjsEsm',\n    data: {\n      estree: {\n        body: [createAstExportConst('metadata', valueToEstree(data))]\n      }\n    }\n  } as MdxjsEsmHast\n}\n\nconst transformer: Transformer<Root> = ast => {\n  const yamlNodeIndex = ast.children.findIndex(node => node.type === 'yaml')\n  const esmNodeIndex = ast.children.findIndex(node =>\n    isExportNode(node, 'metadata')\n  )\n  const hasYaml = yamlNodeIndex !== -1\n  const hasEsm = esmNodeIndex !== -1\n\n  if (hasYaml) {\n    if (hasEsm) {\n      throw new Error(\n        \"Both YAML front matter and `metadata` aren't supported. Keep only 1.\"\n      )\n    }\n    const node = ast.children[yamlNodeIndex] as { value: string }\n    ast.children[yamlNodeIndex] = createNode(parseYaml(node.value) ?? {})\n  } else if (!hasEsm) {\n    // Attach empty node\n    ast.children.unshift(createNode({}))\n  }\n}\n\nexport const remarkMdxFrontMatter: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-mdx-title.ts",
    "content": "import path from 'node:path'\nimport type { Property } from 'estree'\nimport type { Root, RootContent } from 'mdast'\nimport type { MdxjsEsmHast } from 'mdast-util-mdxjs-esm'\nimport type { Plugin, Transformer } from 'unified'\nimport { EXIT, visit } from 'unist-util-visit'\nimport { pageTitleFromFilename } from '../utils.js'\nimport { getFlattenedValue } from './remark-headings.js'\n\nexport function getFrontMatterASTObject(node: MdxjsEsmHast): Property[] {\n  const [n] = node.data!.estree!.body\n  return (n as any).declaration.declarations[0].init.properties\n}\n\nexport function isExportNode(\n  node: MdxjsEsmHast | RootContent,\n  varName: string\n): node is MdxjsEsmHast {\n  if (node.type !== 'mdxjsEsm') return false\n  const n = node.data!.estree!.body[0]!\n\n  if (n.type !== 'ExportNamedDeclaration') return false\n\n  const name = (n as any).declaration?.declarations?.[0].id.name\n  if (!name) return false\n\n  return name === varName\n}\n\nconst transformer: Transformer<Root> = (ast, file) => {\n  let title = ''\n\n  const frontMatterNode = ast.children.find(node =>\n    isExportNode(node, 'metadata')\n  )!\n\n  for (const { key, value } of getFrontMatterASTObject(frontMatterNode)) {\n    if (key.type === 'Literal' && key.value === 'title') {\n      // @ts-expect-error -- fixme\n      title = value.value\n      break\n    }\n    if (key.type === 'Identifier' && key.name === 'title') {\n      // @ts-expect-error -- fixme\n      title = value.value\n      break\n    }\n  }\n  // No title in metadata\n  if (!title) {\n    // Get from first h1\n    visit(ast, { type: 'heading', depth: 1 }, node => {\n      title = getFlattenedValue(node)\n      return EXIT\n    })\n    // Get from filename\n    if (!title) {\n      const [filePath] = file.history\n      if (filePath) {\n        title = pageTitleFromFilename(path.parse(filePath).name)\n      }\n    }\n    // Set from h1 or from filename\n    if (title) {\n      file.data.title = title\n    }\n  }\n}\n\nexport const remarkMdxTitle: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-remove-imports.ts",
    "content": "import type { Root } from 'mdast'\nimport type { Plugin, Transformer } from 'unified'\nimport { remove } from 'unist-util-remove'\n\nconst transformer: Transformer<Root> = ast => {\n  remove(\n    ast,\n    node =>\n      node.type === 'mdxjsEsm' &&\n      // @ts-expect-error -- fixme\n      node.data.estree.body[0].type === 'ImportDeclaration'\n  )\n}\n\nexport const remarkRemoveImports: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/remark-plugins/remark-static-image.ts",
    "content": "import path from 'node:path'\nimport type { ImportDeclaration } from 'estree'\nimport type { Definition, Image, ImageReference, Root } from 'mdast'\nimport type { MdxjsEsmHast } from 'mdast-util-mdxjs-esm'\nimport type { Plugin, Transformer } from 'unified'\nimport { visit } from 'unist-util-visit'\nimport { EXTERNAL_URL_RE } from '../constants.js'\n\n/**\n * @link https://github.com/vercel/next.js/blob/6cfebfb02c2a52a1f99fca59a2eac2d704d053db/packages/next/build/webpack/loaders/next-image-loader.js#L6\n * @link https://github.com/vercel/next.js/blob/6cfebfb02c2a52a1f99fca59a2eac2d704d053db/packages/next/client/image.tsx#LL702\n */\nconst VALID_BLUR_EXT = ['.jpeg', '.png', '.webp', '.avif', '.jpg']\n\nconst VARIABLE_PREFIX = '__img'\n\n// Based on the remark-embed-images project\n// https://github.com/remarkjs/remark-embed-images\nconst transformer: Transformer<Root> = ast => {\n  const definitionNodes: Definition[] = []\n\n  const imageImports = new Set<string>()\n  const imageNodes: (Image | ImageReference)[] = []\n\n  visit(ast, 'definition', node => {\n    definitionNodes.push(node)\n  })\n\n  visit(ast, ['image', 'imageReference'], _node => {\n    const node = _node as Image | ImageReference\n    // https://github.com/shuding/nextra/issues/1344\n    let url = decodeURI(\n      node.type === 'image'\n        ? node.url\n        : (definitionNodes.find(\n            definition => definition.identifier === node.identifier\n          )?.url ?? '')\n    )\n\n    if (!url) {\n      return\n    }\n\n    if (EXTERNAL_URL_RE.test(url)) {\n      // do nothing with images with external url\n      return\n    }\n\n    if (url.startsWith('/')) {\n      url = path.posix.join('private-next-root-dir', 'public', url)\n    }\n    imageImports.add(url)\n    // @ts-expect-error -- we assign explicitly\n    node.url = url\n    imageNodes.push(node)\n  })\n\n  const imageUrls = [...imageImports]\n\n  for (const node of imageNodes) {\n    // @ts-expect-error -- we assigned explicitly\n    const { url } = node\n    const imageIndex = imageUrls.indexOf(url)\n    const variableName = `${VARIABLE_PREFIX}${imageIndex}`\n    const hasBlur = VALID_BLUR_EXT.some(ext => url.endsWith(ext))\n    // Replace the image node with an MDX component node (Next.js Image)\n    Object.assign(node, {\n      type: 'mdxJsxFlowElement',\n      name: 'img',\n      attributes: [\n        // do not render empty alt in html markup\n        node.alt && {\n          type: 'mdxJsxAttribute',\n          name: 'alt',\n          value: node.alt\n        },\n        hasBlur && {\n          type: 'mdxJsxAttribute',\n          name: 'placeholder',\n          value: 'blur'\n        },\n        {\n          type: 'mdxJsxAttribute',\n          name: 'src',\n          value: {\n            type: 'mdxJsxAttributeValueExpression',\n            value: variableName,\n            data: {\n              estree: {\n                body: [\n                  {\n                    type: 'ExpressionStatement',\n                    expression: { type: 'Identifier', name: variableName }\n                  }\n                ]\n              }\n            }\n          }\n        }\n      ].filter(v => !!v)\n    })\n  }\n\n  if (imageUrls.length) {\n    ast.children.unshift(\n      ...imageUrls.map(\n        (imageUrl, index) =>\n          ({\n            type: 'mdxjsEsm',\n            data: {\n              estree: {\n                body: [\n                  {\n                    type: 'ImportDeclaration',\n                    source: { type: 'Literal', value: imageUrl },\n                    specifiers: [\n                      {\n                        type: 'ImportDefaultSpecifier',\n                        local: {\n                          type: 'Identifier',\n                          name: `${VARIABLE_PREFIX}${index}`\n                        }\n                      }\n                    ]\n                  } satisfies ImportDeclaration\n                ]\n              }\n            }\n          }) as MdxjsEsmHast\n      )\n    )\n  }\n}\n\nexport const remarkStaticImage: Plugin<[], Root> = () => transformer\n"
  },
  {
    "path": "packages/nextra/src/server/schemas.ts",
    "content": "import type { ProcessorOptions } from '@mdx-js/mdx'\nimport type { MathJax3Config } from 'better-react-mathjax'\nimport type { ReactElement, ReactNode } from 'react'\nimport { isValidElement } from 'react'\nimport type { Options as RehypeKatexOptions } from 'rehype-katex'\nimport type { Options as RehypePrettyCodeOptions } from 'rehype-pretty-code'\nimport { z } from 'zod'\nimport { pageTitleFromFilename } from './utils.js'\n\nexport const MathJaxOptionsSchema = z.strictObject({\n  src: z.string().optional().meta({\n    description: 'URL for MathJax.',\n    default: '\"https://cdnjs.cloudflare.com\"'\n  }),\n  config: z.custom<MathJax3Config>().optional().meta({\n    description:\n      'MathJax config. See [configuring MathJax](https://docs.mathjax.org/en/latest/options/index.html).',\n    type: 'import(\"better-react-mathjax\").MathJax3Config'\n  })\n})\n\nconst MdxOptionsSchema = z.strictObject({\n  rehypePlugins: z.custom<ProcessorOptions['rehypePlugins']>().optional().meta({\n    description: 'List of rehype plugins.',\n    type: 'import(\"@mdx-js/mdx\").ProcessorOptions[\"rehypePlugins\"]'\n  }),\n  remarkPlugins: z.custom<ProcessorOptions['remarkPlugins']>().optional().meta({\n    description: 'List of remark plugins.',\n    type: 'import(\"@mdx-js/mdx\").ProcessorOptions[\"remarkPlugins\"]'\n  }),\n  recmaPlugins: z.custom<ProcessorOptions['recmaPlugins']>().optional().meta({\n    description:\n      'List of recma plugins. This is a new ecosystem, currently in beta, to transform esast trees (JavaScript).',\n    type: 'import(\"@mdx-js/mdx\").ProcessorOptions[\"recmaPlugins\"]'\n  }),\n  format: z\n    .enum(['detect', 'mdx', 'md'])\n    .default('detect')\n    .meta({\n      description: `Format of the file.\n- \\`'md'\\` means treat as markdown\n- \\`'mdx'\\` means treat as MDX\n- \\`'detect'\\` means try to detect the format based on file path.`\n    }),\n  rehypePrettyCodeOptions: z\n    .custom<RehypePrettyCodeOptions>()\n    .default({})\n    .meta({\n      description: `Configuration options for [Rehype Pretty Code](https://github.com/rehype-pretty/rehype-pretty-code).\n@remarks \\`RehypePrettyCodeOptions\\``,\n      type: 'import(\"rehype-pretty-code\").Options'\n    })\n})\n\nexport const NextraConfigSchema = z.strictObject({\n  defaultShowCopyCode: z\n    .boolean()\n    .optional()\n    .meta({\n      description: `Enable the copy button for all code blocks by default, without needing to set \\`copy=true\\` attribute in the code block metadata.\n> [!TIP]\n>\n> You could still disable the button for specific blocks using \\`copy=false\\` attribute.`\n    }),\n  search: z\n    .union([\n      z.boolean(),\n      z.strictObject({\n        codeblocks: z.boolean().meta({\n          description: 'Whether to index code blocks.'\n        })\n      })\n    ])\n    .default({ codeblocks: false })\n    .meta({\n      description: `Option to enable search functionality. When enabled, it sets the \\`data-pagefind-body\\` attribute on the \\`<main>\\` element.\n> [!TIP]\n>\n> When set to \\`codeblocks: false\\`, it adds the \\`data-pagefind-ignore=\"all\"\\` attribute to all code blocks (\\`<pre>\\` elements).`\n    }),\n  staticImage: z\n    .boolean()\n    .default(true)\n    .meta({\n      description: `Option to automatically optimizing your static image imports with the Markdown syntax.\n> [!TIP]\n>\n> Example: \\`![Hello](/demo.png)\\`.`\n    }),\n  readingTime: z\n    .boolean()\n    .optional()\n    .meta({\n      description: `Adds estimated reading time of \\`.md\\` and \\`.mdx\\` files using [readingTime](https://npmjs.com/package/reading-time) package.\n> [!TIP]\n>\n> The reading time is added to the front matter under the \\`readingTime\\` key.`\n    }),\n  latex: z\n    .union([\n      z.boolean(),\n      z.strictObject({\n        renderer: z.literal('mathjax'),\n        options: MathJaxOptionsSchema.optional()\n      }),\n      z.strictObject({\n        renderer: z.literal('katex'),\n        options: z.custom<RehypeKatexOptions>().meta({\n          description:\n            'KaTeX options. See https://katex.org/docs/options.html.',\n          type: 'import(\"rehype-katex\").Options'\n        })\n      })\n    ])\n    .optional()\n    .meta({\n      description:\n        'Enable LaTeX either with [KaTeX](https://katex.org) to pre-render LaTeX expressions directly in MDX or [MathJax](https://mathjax.org) to dynamically render math in the browser.'\n    }),\n  codeHighlight: z.boolean().default(true).meta({\n    description: 'Enable or disable syntax highlighting.'\n  }),\n  mdxOptions: MdxOptionsSchema.default(MdxOptionsSchema.parse({})).meta({\n    description: `Options specific to MDX compiling.\n@remarks \\`MdxOptions\\``\n  }),\n  whiteListTagsStyling: z\n    .array(z.string())\n    .optional()\n    .meta({\n      description: `Allows you to whitelist HTML elements to be replaced with components defined in the \\`mdx-components.js\\` file.\n> [!TIP]\n>\n> By default, Nextra only replaces \\`<details>\\` and \\`<summary>\\` elements.`\n    }),\n  contentDirBasePath: z\n    .string()\n    .startsWith('/')\n    .refine(value => value.length === 1 || !value.endsWith('/'), {\n      error: 'Must not end with \"/\"'\n    })\n    .default('/')\n    .meta({\n      description:\n        'Option to serve your `.md` and `.mdx` files from the `content` directory at a custom path instead of the root (`/`).'\n    }),\n  unstable_shouldAddLocaleToLinks: z.boolean().default(false).meta({\n    description:\n      \"Prefixes locale to all links in the page map information. Useful for i18n when you don't want to use Nextra's `middleware` function.\"\n  })\n})\n\nexport const element = z.custom<ReactElement>(\n  function checkReactElement(data) {\n    return isValidElement(data)\n  },\n  { error: 'Must be a valid React element' }\n)\n/**\n * https://react.dev/reference/react/isValidElement#react-elements-vs-react-nodes\n */\nexport const reactNode = z.custom<ReactNode>(\n  function checkReactNode(data): data is ReactNode {\n    if (\n      // Check if it's a valid React element\n      isValidElement(data) ||\n      // Check if it's null or undefined\n      data == null ||\n      typeof data === 'string' ||\n      typeof data === 'number' ||\n      typeof data === 'boolean'\n    ) {\n      return true\n    }\n    // Check if it's an array of React nodes\n    if (Array.isArray(data)) {\n      return data.every(item => checkReactNode(item))\n    }\n    const isServerComponent =\n      typeof data === 'object' &&\n      '$$typeof' in data &&\n      data.$$typeof === Symbol.for('react.lazy')\n    // If it's none of the above, it's not a valid React node\n    return isServerComponent\n  },\n  { error: 'Must be a valid React node' }\n)\n\nconst stringOrElement = z.union([z.string(), element])\n\nexport const pageThemeSchema = z.strictObject({\n  breadcrumb: z.boolean().optional().meta({\n    description: 'Show or hide breadcrumb navigation.',\n    default: true\n  }),\n  collapsed: z.boolean().optional().meta({\n    description:\n      'Indicates whether the item in sidebar is collapsed by default.',\n    default: false\n  }),\n  copyPage: z.boolean().optional().meta({\n    description: 'Specifies whether to display the copy page button.',\n    default: true\n  }),\n  footer: z.boolean().optional().meta({\n    description: 'Specifies whether to display the footer.',\n    default: true\n  }),\n  layout: z.literal(['default', 'full']).optional().meta({\n    description: 'Defines the layout style.',\n    default: \"'default'\"\n  }),\n  navbar: z.boolean().optional().meta({\n    description: 'Specifies whether to display the navbar.',\n    default: true\n  }),\n  pagination: z.boolean().optional().meta({\n    description: 'Determines if pagination controls are shown.',\n    default: true\n  }),\n  sidebar: z.boolean().optional().meta({\n    description: 'Specifies whether to display the sidebar.',\n    default: true\n  }),\n  timestamp: z.boolean().optional().meta({\n    description: 'Indicates if \"last updated\" timestamps are displayed.',\n    default: true\n  }),\n  toc: z.boolean().optional().meta({\n    description: 'Determines whether a table of contents is displayed.',\n    default: true\n  }),\n  typesetting: z.literal(['default', 'article']).optional().meta({\n    description: 'Configures the text typesetting style.',\n    default: \"'default'\"\n  })\n})\n\nconst title = stringOrElement.optional()\n\nconst linkSchema = z.strictObject({\n  title,\n  href: z.string()\n})\n\nexport const separatorItemSchema = z.strictObject({\n  type: z.literal('separator'),\n  title\n})\n\nconst menuItemSchema = z\n  .union([\n    stringOrElement,\n    linkSchema,\n    z.strictObject({ title: stringOrElement }),\n    separatorItemSchema\n  ])\n  .transform(transformTitle)\n\nexport const menuSchema = z.strictObject({\n  type: z.literal('menu'),\n  title,\n  items: z.record(z.string(), menuItemSchema).transform(obj => {\n    for (const key in obj) {\n      // @ts-expect-error -- fixme\n      obj[key].title ||= pageTitleFromFilename(key)\n    }\n    return obj\n  }),\n  display: z.enum(['normal', 'hidden']).optional()\n})\n\nexport const itemSchema = z.strictObject({\n  type: z.enum(['page', 'doc']).optional(),\n  title,\n  /**\n   * An option to control how an item should be displayed in the sidebar:\n   * - `normal`: the default behavior, item will be displayed\n   * - `hidden`: the item will not be displayed in the sidebar entirely\n   * - `children`: if the item is a folder, itself will be hidden but all its children will still be processed\n   */\n  display: z.enum(['normal', 'hidden', 'children']).optional(),\n  theme: pageThemeSchema.optional()\n})\n\nexport const metaSchema = z.union([\n  stringOrElement.transform(transformTitle),\n  itemSchema,\n  linkSchema.extend({\n    type: z.enum(['page', 'doc']).optional(),\n    display: z.enum(['normal', 'hidden']).optional()\n  }),\n  separatorItemSchema,\n  menuSchema\n])\n\nfunction transformTitle<T>(title: T) {\n  return typeof title === 'string' || isValidElement(title) ? { title } : title\n}\n"
  },
  {
    "path": "packages/nextra/src/server/tsdoc/base.ts",
    "content": "import path from 'node:path'\nimport slash from 'slash'\nimport type {\n  ExportedDeclarations,\n  Node as TsNode,\n  Symbol as TsSymbol,\n  Type\n} from 'ts-morph'\nimport { Project, SyntaxKind, ts } from 'ts-morph'\nimport { CWD } from '../constants.js'\nimport { logger } from '../utils.js'\nimport type {\n  BaseArgs,\n  GeneratedDefinition,\n  GeneratedFunction,\n  GeneratedType,\n  Tags,\n  TypeField\n} from './types.js'\n\nconst project = new Project({\n  tsConfigFilePath: './tsconfig.json',\n  skipAddingFilesFromTsConfig: true,\n  compilerOptions: {\n    // Do not show `undefined` value in type for optional value\n    exactOptionalPropertyTypes: true,\n    // Show `null` value in type if exist\n    strictNullChecks: true\n  }\n})\n\nconst DEFAULT_FILENAME = '$.ts'\n\nlet compilerObject: ts.TypeChecker\n\n/**\n * Generate documentation for properties of `type` and `interface` and parameters and returns\n * signature of `function`.\n * @returns Parsed TSDoc definition from TypeScript `type`, `interface` or `function`.\n * @example\n * To generate documentation for a `type`, `interface`, or `function`, export it via the `code`\n * argument.\n *\n * ### As a `default` export\n *\n * ```mdx\n * import { generateDefinition, TSDoc } from 'nextra/tsdoc'\n *\n * <TSDoc\n *   definition={generateDefinition({\n *     code: \"export { yourTypeOrFunction as default } from 'your-package'\",\n *   })}\n * />\n * ```\n *\n * ### As a named export\n *\n * ```mdx\n * import { generateDefinition, TSDoc } from 'nextra/tsdoc'\n *\n * <TSDoc\n *   definition={generateDefinition({\n *     code: \"export { yourTypeOrFunction } from 'your-package'\",\n *     exportName: 'yourTypeOrFunction'\n *   })}\n * />\n * ```\n */\nexport function generateDefinition({\n  code,\n  exportName = 'default',\n  flattened = false\n}: BaseArgs): GeneratedDefinition & (GeneratedType | GeneratedFunction) {\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Can't access at top level, fix File not found: /var/task/.../tsconfig.json\n  compilerObject ??= project.getTypeChecker().compilerObject\n  const sourceFile = project.createSourceFile(DEFAULT_FILENAME, code, {\n    overwrite: true\n  })\n  const output: ExportedDeclarations[] = []\n  for (const [key, declaration] of sourceFile.getExportedDeclarations()) {\n    if (key === exportName) output.push(...declaration)\n  }\n  const declaration = output[0]\n  if (!declaration) {\n    throw new Error(`Can't find \"${exportName}\" declaration`)\n  }\n  const declarationFilePath = declaration.getSourceFile().getFilePath()\n  const filePath = slash(path.relative(CWD, declarationFilePath))\n  const symbol = declaration.getSymbolOrThrow()\n  const { comment, tags } = getCommentAndTags(declaration)\n  const description = ts.displayPartsToString(comment)\n  tags.returns &&= replaceJsDocLinks(tags.returns)\n\n  const definition: GeneratedDefinition = {\n    // Skip adding `filePath` to snapshots on test env, since we have tests on Mac and on Windows, they fail\n    ...// process.env.NODE_ENV !== 'test' &&\n    (filePath !== DEFAULT_FILENAME && { filePath }),\n    name: symbol.getName(),\n    ...(description && { description }),\n    ...(Object.keys(tags).length && { tags })\n  }\n\n  const declarationType = declaration.getType()\n  const callSignatures = declarationType.getCallSignatures()\n  const isFunction = callSignatures.length > 0\n\n  if (!isFunction) {\n    const entries = declarationType\n      .getProperties()\n      .flatMap(prop =>\n        getDocEntry({\n          symbol: prop,\n          declaration,\n          flattened\n        })\n      )\n      .filter(entry => !entry.tags || !('internal' in entry.tags))\n    if (!entries.length) {\n      const typeName = declarationType.getText()\n      if (typeName === 'any') {\n        throw new Error(\n          'Your type is resolved as \"any\", it seems like you have an issue in \"generateDefinition.code\" argument.'\n        )\n      }\n      throw new Error(\n        `No properties found, check if your type \"${typeName}\" exist.`\n      )\n    }\n\n    return {\n      ...definition,\n      entries\n    }\n  }\n  return {\n    ...definition,\n    signatures: callSignatures.map(signature => {\n      const params = signature.getParameters()\n      const typeParams = params.flatMap(param =>\n        getDocEntry({\n          symbol: param,\n          declaration,\n          flattened\n        })\n      )\n      // signature.getReturnType() evaluates and expands the type fully, we use signature.getDeclaration().getSignature().getReturnType()\n      const returnType = signature\n        .getDeclaration()\n        .getSignature()\n        .getReturnType()\n      let flattenedReturnType: GeneratedFunction['signatures'][number]['returns'] =\n        flattened && shouldFlattenType(returnType)\n          ? returnType.getProperties().flatMap(childProp =>\n              getDocEntry({\n                symbol: childProp,\n                declaration,\n                flattened\n              })\n            )\n          : []\n\n      if (!flattenedReturnType.length) {\n        flattenedReturnType = {\n          type: getFormattedText(returnType)\n        }\n      }\n\n      return {\n        params: typeParams,\n        returns: flattenedReturnType\n      }\n    })\n  }\n}\n\n/**\n * If no comments are found on the symbol, use the alias symbol's comments.\n */\nfunction getCommentAndTags(declaration: ExportedDeclarations): {\n  comment: ts.SymbolDisplayPart[]\n  tags: Tags\n} {\n  const symbol = declaration.getSymbolOrThrow()\n  const comment = symbol.compilerSymbol.getDocumentationComment(compilerObject)\n  if (!comment.length) {\n    const aliasSymbol = declaration.getType().getAliasSymbol()\n    if (aliasSymbol) {\n      return {\n        comment:\n          aliasSymbol.compilerSymbol.getDocumentationComment(compilerObject),\n        tags: getTags(aliasSymbol)\n      }\n    }\n  }\n  return {\n    comment,\n    tags: getTags(symbol)\n  }\n}\n\nfunction getDocEntry({\n  symbol,\n  declaration,\n  flattened,\n  prefix = ''\n}: {\n  symbol: TsSymbol\n  declaration: ExportedDeclarations\n  flattened: boolean\n  prefix?: string\n}): TypeField | TypeField[] {\n  const originalSubType = project\n    .getTypeChecker()\n    .getTypeOfSymbolAtLocation(symbol, declaration)\n  const valueDeclaration = symbol.getValueDeclaration()\n  const isFunctionParameter =\n    valueDeclaration && valueDeclaration.getKind() === SyntaxKind.Parameter\n\n  const subType = isFunctionParameter\n    ? originalSubType.getNonNullableType()\n    : originalSubType\n  if (flattened && shouldFlattenType(subType)) {\n    return subType.getProperties().flatMap(childProp => {\n      const childPrefix = isFunctionParameter\n        ? symbol.getName().replace(/^_+/, '')\n        : symbol.getName()\n      const newPrefix =\n        typeof +childPrefix === 'number' && !Number.isNaN(+childPrefix)\n          ? `[${childPrefix}]` + (originalSubType.isNullable() ? '?' : '')\n          : childPrefix\n      return getDocEntry({\n        symbol: childProp,\n        declaration,\n        flattened,\n        prefix: prexify(prefix, newPrefix)\n      })\n    })\n  }\n  const tags = getTags(symbol)\n\n  const name = symbol.getName()\n  const typeDescription = replaceJsDocLinks(\n    ts.displayPartsToString(\n      symbol.compilerSymbol.getDocumentationComment(compilerObject)\n    )\n  ).replace(/^- /, '')\n  const isOptional = isFunctionParameter\n    ? // @ts-expect-error -- fixme\n      valueDeclaration.isOptional()\n    : symbol.isOptional()\n\n  const typeName = getTypeName({\n    tags,\n    symbol,\n    subType,\n    valueDeclaration\n  })\n  return {\n    name: prexify(prefix, name),\n    type: typeName,\n    ...(typeDescription && { description: typeDescription }),\n    ...(Object.keys(tags).length && { tags }),\n    ...(isOptional && { optional: isOptional })\n  }\n}\n\nfunction printType(paramType: Type): string {\n  const inlineParamAlias = paramType.getNonNullableType().getAliasSymbol()\n  const paramTags = inlineParamAlias && getTags(inlineParamAlias)\n  const hasLine = paramTags && 'inline' in paramTags\n  if (!hasLine) {\n    return getFormattedText(paramType)\n  }\n  const typeText = inlineParamAlias.getDeclaredType().getText(\n    undefined,\n    ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.InTypeAlias\n    // | ts.TypeFormatFlags.WriteArrayAsGenericType\n    // | ts.TypeFormatFlags.UseFullyQualifiedType\n  )\n  return typeText\n}\n\nfunction getTypeName({\n  tags,\n  symbol,\n  subType,\n  valueDeclaration\n}: {\n  tags: Tags\n  symbol: TsSymbol\n  subType: Type\n  valueDeclaration: TsNode | undefined\n}) {\n  const aliasSymbol = subType.getAliasSymbol()\n  const subTypeTags = aliasSymbol ? getTags(aliasSymbol) : {}\n  const typeName = (tags.remarks || subTypeTags.remarks)?.match(\n    /^`(?<name>.+)`/\n  )?.groups!.name\n\n  if (typeName) {\n    return typeName\n  }\n\n  const declarationNode = symbol\n    .getDeclarations()\n    .find(\n      d =>\n        ts.isPropertySignature(d.compilerNode) || ts.isParameter(d.compilerNode)\n    )\n  const typeNode =\n    declarationNode?.asKind(SyntaxKind.PropertySignature) ??\n    declarationNode?.asKind(SyntaxKind.Parameter)\n  const t = typeNode?.getTypeNode()?.getText()\n\n  const useTypeNode =\n    t &&\n    (t.startsWith('Partial<') ||\n      ['React.ReactNode', 'React.ReactElement'].includes(t))\n\n  if (useTypeNode) {\n    return t\n  }\n  const isInline = 'inline' in tags || 'inline' in subTypeTags\n  if (!isInline) {\n    const typeOf = valueDeclaration?.getType() ?? symbol.getDeclaredType()\n    return typeOf.isUnknown() ? 'unknown' : getFormattedText(subType)\n  }\n  const [signature] = subType.getCallSignatures()\n  const isFunction = !!signature\n  if (isFunction) {\n    const params = signature.getParameters().map(param => {\n      const paramDecl = param.getDeclarations()[0]!\n      const paramType = project\n        .getTypeChecker()\n        .getTypeOfSymbolAtLocation(param, paramDecl)\n      const paramTypeStr = printType(paramType)\n      const optional = paramDecl\n        .asKindOrThrow(SyntaxKind.Parameter)\n        .isOptional()\n\n      return `${param.getName()}${optional ? '?' : ''}: ${paramTypeStr}`\n    })\n\n    return `(${params.join(', ')}) => ${getFormattedText(signature.getReturnType())}`\n  }\n  const [aliasDecl] = aliasSymbol!.getDeclarations()\n  if (!aliasDecl) {\n    throw new Error(\"Can't find alias declaration for type.\")\n  }\n  const inlineNode = aliasDecl\n    .asKindOrThrow(SyntaxKind.TypeAliasDeclaration)\n    .getTypeNodeOrThrow()\n  return inlineNode.getText()\n}\n\nfunction prexify(prefix: string, name: string): string {\n  return prefix ? [prefix, name].join('.') : name\n}\n\nfunction shouldFlattenType(t: Type): boolean {\n  if (\n    !t.isObject() ||\n    t.isArray() ||\n    t.isTuple() ||\n    // Is not function\n    t.getCallSignatures().length > 0 ||\n    // Is not `unknown`\n    t.getText() === '{}' ||\n    // Is not an empty object\n    !t.getProperties().length\n  ) {\n    return false\n  }\n  try {\n    const baseName = t.getSymbolOrThrow().getName()\n    if (IGNORED_TYPES.has(baseName)) return false\n    return t.isInterface() || baseName === '__type' || baseName === '__object'\n  } catch {\n    logger.error(`Symbol \"${t.getText()}\" isn't found.`)\n    return false\n  }\n}\n\nconst IGNORED_TYPES = new Set([\n  'Date',\n  'RegExp',\n  'ReactElement',\n  'Element',\n  'CSSProperties'\n])\n\nfunction getTags(prop: TsSymbol): Tags {\n  const tags: Record<string, string> = Object.create(null)\n  for (const tag of prop.getJsDocTags()) {\n    const tagName = tag.getName()\n    const tagValue = ts.displayPartsToString(tag.getText())\n    if (tagName in tags) {\n      tags[tagName] += `\\n${tagValue}`\n    } else {\n      tags[tagName] = tagValue\n    }\n  }\n  return tags\n}\n\nfunction getFormattedText(t: Type): string {\n  return t.getText(\n    undefined,\n    ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope\n  )\n}\n\nfunction replaceJsDocLinks(md: string): string {\n  return md.replaceAll(/{@link (?<link>[^}]*)}/g, '$1')\n}\n"
  },
  {
    "path": "packages/nextra/src/server/tsdoc/index.ts",
    "content": "import 'server-only'\n\nexport { TSDoc } from './tsdoc.js'\nexport { generateDefinition } from './base.js'\nexport { generateTsFromZod } from './zod-to-ts.js'\nexport * from './types.js'\n"
  },
  {
    "path": "packages/nextra/src/server/tsdoc/tsdoc.tsx",
    "content": "import cn from 'clsx'\nimport Slugger from 'github-slugger'\nimport type { FC, ReactElement, ReactNode } from 'react'\nimport { Callout } from '../../client/components/callout.js'\nimport { Tabs } from '../../client/components/tabs/index.js'\nimport { Anchor } from '../../client/mdx-components/anchor.js'\nimport { Code } from '../../client/mdx-components/code.js'\nimport { MDXRemote } from '../../client/mdx-remote.js'\nimport { compileMdx } from '../compile.js'\nimport type { generateDefinition } from './base.js'\nimport type { GeneratedFunction, TypeField } from './types.js'\n\ntype TSDocProps = {\n  /**\n   * Parsed `type`, `interface` or `function` definition from\n   * [`generateDefinition` function](https://nextra.site/api/generatedefinition).\n   */\n  definition: ReturnType<typeof generateDefinition>\n  /**\n   * Override the function to render markdown into JSX nodes.\n   * @default\n   * async function renderMarkdownDefault(description?: string): Promise<ReactNode> {\n   *   if (!description) return\n   *   const rawJs = await compileMdx(description)\n   *   return <MDXRemote compiledSource={rawJs} />\n   * }\n   */\n  renderMarkdown?: typeof renderMarkdownDefault\n  /**\n   * Type links map.\n   * @default {}\n   */\n  typeLinkMap?: Record<string, string>\n  /**\n   * Custom content to display when a function has no parameters.\n   * @default <Callout type=\"info\">This function does not accept any parameters.</Callout>\n   */\n  noParametersContent?: ReactNode\n}\n\n// copied from nextra-theme-docs\nconst Link: typeof Anchor = ({ className, ...props }) => {\n  return (\n    <Anchor\n      className={cn(\n        'x:text-primary-600 x:underline x:hover:no-underline x:decoration-from-font x:[text-underline-position:from-font]',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nasync function renderMarkdownDefault(description?: string): Promise<ReactNode> {\n  if (!description) return\n  const rawJs = await compileMdx(description)\n  return <MDXRemote compiledSource={rawJs} />\n}\n\nconst classes = {\n  card: cn(\n    'x:rounded-xl nextra-border x:hover:bg-primary-50 x:dark:hover:bg-primary-500/10'\n  ),\n  anchor: cn(\n    'x:absolute x:top-0 x:right-0 x:text-lg x:font-black',\n    'x:before:content-[\"#\"] x:hover:text-black x:dark:hover:text-white',\n    'x:px-3 x:py-[min(1%,12px)]' // Increase click box\n  )\n}\n\n/**\n * A built-in component lets you generate documentation from `type`, `interface`, and `function`\n * definitions  using [TSDoc](https://tsdoc.org) annotations.\n *\n * ## What it generates\n *\n * ### For `type` and `interface`\n *\n * Generates a **properties table** with:\n *\n * - Name\n * - Type and description\n * - Default Value\n * - Permalink\n *\n * ### For `function`\n *\n * 1. **Parameters table**, including:\n *\n *    - Name\n *    - Type and description\n *    - Default value\n *    - Permalink\n *\n * 2. **Return signature table**, including:\n *    - Description\n *    - Return values table\n *\n * > [!TIP]\n * >\n * > - Permalink is a `#` anchor link for easy reference to individual rows.\n * > - Descriptions are parsed from inline TSDoc comments or the `@description`\n * >   tag.\n * > - Supports full Markdown/MDX syntax in descriptions.\n * > - Default values are extracted from the `@default` or `@defaultValue` tags.\n * > - Return descriptions come from the `@returns` tag.\n *\n * > [!WARNING]\n * >\n * > **Server Component Only** – TSDoc component cannot be used in a client\n * > component.<br />\n * > **Available from:** Nextra 4.3 (alpha).<br />\n * > **Dependency:** Uses TypeScript Compiler API from\n * > [`ts-morph`](https://github.com/dsherret/ts-morph).\n *\n * @example\n * To generate the props table for the `TSDoc` component shown on this page:\n *\n * ```mdx\n * import { generateDefinition, TSDoc } from 'nextra/tsdoc'\n *\n * <TSDoc\n *   definition={generateDefinition({\n *     code: `\n * import type { TSDoc } from 'nextra/tsdoc'\n * type MyProps = React.ComponentProps<typeof TSDoc>\n * export default MyProps`\n *   })}\n * />\n * ```\n *\n * ### Overriding a type\n *\n * You can override the inferred type using the `@remarks` tag using backticks (`).\n *\n * <ExampleTSDoc />\n */\nexport const TSDoc: FC<TSDocProps> = ({\n  definition,\n  renderMarkdown = renderMarkdownDefault,\n  typeLinkMap = {},\n  noParametersContent = (\n    <Callout type=\"info\">This function does not accept any parameters.</Callout>\n  )\n}) => {\n  if ('entries' in definition) {\n    return (\n      <FieldsTable\n        fields={definition.entries}\n        typeLinkMap={typeLinkMap}\n        renderMarkdown={renderMarkdown}\n      />\n    )\n  }\n  const { signatures, tags } = definition\n  const withSignatures = signatures.length > 1\n\n  if (!withSignatures) {\n    return <FunctionSignature signature={signatures[0]!} />\n  }\n\n  return (\n    <Tabs\n      items={signatures.map((_, index) => `Function Signature ${index + 1}`)}\n    >\n      {signatures.map((signature, index) => (\n        <Tabs.Tab key={index}>\n          <FunctionSignature signature={signature} index={index + 1} />\n        </Tabs.Tab>\n      ))}\n    </Tabs>\n  )\n\n  async function FunctionSignature({\n    signature,\n    index = ''\n  }: Readonly<{\n    signature: GeneratedFunction['signatures'][number]\n    /** Signature index, will be appended to returns anchor. */\n    index?: string | number\n  }>) {\n    const slugger = new Slugger()\n    const description = await renderMarkdown(tags?.returns)\n    const unnamedReturnId = `returns${index}`\n    return (\n      <>\n        <b className=\"x:mt-[1.25em] x:block\">Parameters:</b>\n        {signature.params.length ? (\n          <FieldsTable\n            fields={signature.params}\n            typeLinkMap={typeLinkMap}\n            renderMarkdown={renderMarkdown}\n          />\n        ) : (\n          noParametersContent\n        )}\n        <b className=\"x:mt-[1.25em] x:block\">Returns:</b>\n        {Array.isArray(signature.returns) ? (\n          <>\n            {description}\n            <table className=\"x:my-6 x:w-full x:text-sm\">\n              <thead className=\"nextra-border x:border-b x:text-left x:max-lg:hidden\">\n                <tr>\n                  <th className=\"x:py-1.5\">Name</th>\n                  <th className=\"x:p-1.5 x:px-3\">Type</th>\n                </tr>\n              </thead>\n              <tbody>\n                {signature.returns.map(async prop => {\n                  const id = slugger.slug(prop.name)\n                  const description = await renderMarkdown(\n                    prop.description || prop.tags?.description\n                  )\n                  return (\n                    <Row key={id} id={id}>\n                      <NameCell\n                        id={id}\n                        optional={prop.optional}\n                        name={prop.name}\n                      />\n                      <TypeAndDescriptionCell\n                        type={prop.type}\n                        description={description}\n                        typeLinkMap={typeLinkMap}\n                      />\n                    </Row>\n                  )\n                })}\n              </tbody>\n            </table>\n          </>\n        ) : (\n          <div\n            id={unnamedReturnId}\n            className={cn(\n              classes.card,\n              'x:text-sm x:relative x:p-3 x:border x:before:content-[\"Type:_\"] x:mt-5'\n            )}\n          >\n            <a href={`#${unnamedReturnId}`} className={cn(classes.anchor)} />\n            <Code>{linkify(signature.returns.type, typeLinkMap)}</Code>\n            {description && <div className=\"x:mt-2\">{description}</div>}\n          </div>\n        )}\n      </>\n    )\n  }\n}\n\nconst Row: FC<{\n  children: ReactNode\n  id: string\n}> = ({ children, id }) => {\n  return (\n    <tr\n      id={id}\n      className={cn(\n        classes.card,\n        'x:group x:mb-5 x:max-lg:block x:max-lg:border x:lg:border-b',\n        'x:lg:not-target:[&>td>a]:opacity-0'\n      )}\n    >\n      {children}\n    </tr>\n  )\n}\n\nconst NameCell: FC<{\n  name: string\n  id: string\n  optional?: boolean\n}> = ({ name, id, optional }) => {\n  return (\n    <td\n      className={cn(\n        'x:relative x:max-lg:block',\n        name && 'x:py-3 x:max-lg:px-3'\n      )}\n    >\n      <a\n        href={`#${id}`}\n        className={cn(\n          classes.anchor,\n          'x:group-hover:opacity-100! x:lg:top-1/2 x:lg:right-full x:lg:-translate-y-1/2'\n        )}\n      />\n      {name && (\n        <Code\n          className={cn(\n            'x:max-md:break-all',\n            // add `?` via CSS `content` property so value will be not selectable\n            optional && 'x:after:content-[\"?\"]'\n          )}\n        >\n          {name}\n        </Code>\n      )}\n    </td>\n  )\n}\n\nconst TypeAndDescriptionCell: FC<{\n  type: string\n  description: ReactNode\n  typeLinkMap: TSDocProps['typeLinkMap']\n}> = ({ type, description, typeLinkMap }) => {\n  return (\n    <td\n      // add `Type: ` via CSS `content` property so value will be not selectable\n      className='x:p-3 x:max-lg:block x:max-lg:before:content-[\"Type:_\"]'\n    >\n      <Code>{linkify(type, typeLinkMap)}</Code>\n      {description && <div className=\"x:mt-2\">{description}</div>}\n    </td>\n  )\n}\n\nconst FieldsTable: FC<\n  {\n    fields: TypeField[]\n  } & Required<Pick<TSDocProps, 'renderMarkdown' | 'typeLinkMap'>>\n> = ({ fields, typeLinkMap, renderMarkdown }) => {\n  const slugger = new Slugger()\n  return (\n    <table className=\"x:my-8 x:w-full x:text-sm\">\n      <thead className=\"nextra-border x:border-b x:text-left x:max-lg:hidden\">\n        <tr>\n          <th className=\"x:py-1.5\">Name</th>\n          <th className=\"x:p-1.5 x:px-3\">Type</th>\n          <th className=\"x:py-1.5\">Default</th>\n        </tr>\n      </thead>\n      <tbody>\n        {fields.map(async field => {\n          const id = slugger.slug(field.name)\n          const tags = field.tags ?? {}\n          const defaultValue = tags.default || tags.defaultValue\n          const description = await renderMarkdown(\n            [\n              field.description || tags.description,\n              tags.deprecated && `**Deprecated**: ${tags.deprecated}`\n            ]\n              .filter(Boolean)\n              .join('\\n')\n          )\n          return (\n            <Row key={id} id={id}>\n              <NameCell id={id} optional={field.optional} name={field.name} />\n              <TypeAndDescriptionCell\n                type={field.type}\n                description={description}\n                typeLinkMap={typeLinkMap}\n              />\n              <td\n                className={cn(\n                  'x:max-lg:block',\n                  // For the mobile view, we want to hide the default column entirely if there is no\n                  // content for it. We want this because otherwise, the default padding applied to\n                  // table cells will add some extra blank space we don't want.\n                  defaultValue\n                    ? // add `Default: ` via CSS `content` property so value will be not selectable\n                      'x:py-3 x:max-lg:pt-0 x:max-lg:px-3 x:max-lg:before:content-[\"Default:_\"]'\n                    : 'x:lg:after:content-[\"–\"]'\n                )}\n              >\n                {defaultValue && (\n                  <Code className=\"x:whitespace-pre-wrap x:inline-block\">\n                    {linkify(defaultValue, typeLinkMap)}\n                  </Code>\n                )}\n              </td>\n            </Row>\n          )\n        })}\n      </tbody>\n    </table>\n  )\n}\n\n// This function takes a string representing some type and attempts to turn any\n// types referenced inside into links, either internal or external.\nfunction linkify(\n  type: string,\n  typeLinkMap: TSDocProps['typeLinkMap'] = {}\n): ReactNode {\n  const result: (string | ReactElement)[] = []\n  for (const chunk of type.match(/(\\w+|\\W+)/g)!) {\n    const href = typeLinkMap[chunk]\n    if (href) {\n      result.push(\n        <Link key={result.length} href={href}>\n          {/* use React fragment to avoid rendering external link icon */}\n          <>{chunk}</>\n        </Link>\n      )\n      continue\n    }\n    if (typeof result.at(-1) === 'string') {\n      // Concatenate strings to avoid multiple text nodes in DOM\n      result[result.length - 1] += chunk\n      continue\n    }\n    result.push(chunk)\n  }\n  return result\n}\n"
  },
  {
    "path": "packages/nextra/src/server/tsdoc/types.ts",
    "content": "export type GeneratedType = {\n  /** Type fields. */\n  entries: TypeField[]\n}\n\nexport type Tags = Record<string, string>\n\nexport type ReturnField = {\n  /** Function return type. */\n  type: string\n}\n\nexport type GeneratedDefinition = {\n  /**\n   * Where type definition is located on disk.\n   */\n  filePath?: string\n  /**\n   * Definition name.\n   */\n  name: string\n  /**\n   * Definition description.\n   */\n  description?: string\n  /**\n   * [TSDoc tags](https://tsdoc.org/pages/spec/tag_kinds).\n   */\n  tags?: Tags\n}\n\nexport type GeneratedFunction = {\n  signatures: {\n    /** Function parameters. */\n    params: TypeField[]\n    /** Function return. */\n    returns: TypeField[] | ReturnField\n  }[]\n}\n\nexport type TypeField = {\n  /** Field name. */\n  name: string\n  /** Field type. */\n  type: string\n  /** Field description. */\n  description?: string\n  /** Is field optional. */\n  optional?: boolean\n  /** Field tags. */\n  tags?: Tags\n}\n\nexport type BaseArgs = {\n  /** TypeScript source code to be processed. */\n  code: string\n  /**\n   * The name of the exported declaration.\n   * @default \"default\"\n   */\n  exportName?: string\n  /**\n   * Whether to flatten nested objects.\n   * E.g. `{ foo: { bar: string } }` will be represented as: `{ foo.bar: string }`\n   * @default false\n   */\n  flattened?: boolean\n}\n"
  },
  {
    "path": "packages/nextra/src/server/tsdoc/zod-to-ts.ts",
    "content": "import { z } from 'zod'\n\nexport function generateTsFromZod(schema: z.ZodType, indent = 2): string {\n  const isZodObject = schema instanceof z.ZodObject\n  if (!isZodObject) {\n    return generateTsFromZodType(schema, indent)\n  }\n  const objectFields = Object.entries(schema.shape)\n    .map(([key, _value]) => {\n      const value = _value as z.ZodType\n      const tsType = generateTsFromZodType(value, indent + 2)\n      const docComment = getDocComment(value, indent)\n      // Check if field explicitly set as optional with .optional(),\n      // otherwise it's optional if it has a default value\n      const isOptional =\n        value instanceof z.ZodOptional || getDefaultValue(value) !== undefined\n      return [\n        docComment,\n        ' '.repeat(indent),\n        key,\n        isOptional ? '?' : '',\n        `: ${tsType}\\n`\n      ].join('')\n    })\n    .join('\\n')\n\n  return ['{\\n', objectFields, ' '.repeat(indent - 2), '}'].join('')\n}\n\nfunction generateTsFromZodType(schema: z.ZodType, indent: number): string {\n  const { name } = schema.constructor\n  const typeName = schema.meta()?.type as string | undefined\n  if (typeName) return typeName\n\n  if (schema instanceof z.ZodCustom) {\n    const fnName = schema.def.fn.name\n    return fnName.startsWith('check')\n      ? 'React.' + fnName.slice(5)\n      : '\"@TODO TO IMPLEMENT\"'\n  }\n\n  switch (name) {\n    case 'ZodString':\n      return 'string'\n    case 'ZodNumber':\n      return 'number'\n    case 'ZodBoolean':\n      return 'boolean'\n  }\n  if (schema instanceof z.ZodPipe) {\n    // @ts-expect-error -- fixme\n    return generateTsFromZodType(schema.in, indent)\n  }\n  if (schema instanceof z.ZodLiteral) {\n    return `\"${[...schema.values]}\"`\n  }\n  if (schema instanceof z.ZodOptional || schema instanceof z.ZodDefault) {\n    // @ts-expect-error -- fixme\n    return generateTsFromZodType(schema.def.innerType, indent)\n  }\n  if (schema instanceof z.ZodNullable) {\n    // @ts-expect-error -- fixme\n    return `${generateTsFromZodType(schema.def.innerType, indent)} | null`\n  }\n  if (schema instanceof z.ZodArray) {\n    // @ts-expect-error -- fixme\n    return `${generateTsFromZodType(schema.def.element, indent)}[]`\n  }\n  if (schema instanceof z.ZodUnion) {\n    return schema.def.options\n      .map(opt => {\n        const r = generateTsFromZodType(opt as z.ZodType, indent)\n        return opt instanceof z.ZodArray ? `(${r.replace('[', ')[')}` : r\n      })\n      .join(' | ')\n  }\n  if (schema instanceof z.ZodObject) {\n    return generateTsFromZod(schema, indent)\n  }\n  if (schema instanceof z.ZodEnum) {\n    // @ts-expect-error -- fixme\n    return schema.options.map((v: string) => `\"${v}\"`).join(' | ')\n  }\n  throw new Error(`Unknown schema type '${name}'`)\n}\n\nfunction getDefaultValue(schema: z.ZodType): unknown {\n  if (schema instanceof z.ZodDefault) {\n    return schema.def.defaultValue\n  }\n  if (schema instanceof z.ZodPipe) {\n    // @ts-expect-error fixme\n    return schema.in.def.defaultValue\n  }\n  // eslint-disable-next-line sonarjs/no-redundant-jump -- this fix types-check error in `@nextra-tsdoc` – ../nextra/src/server/tsdoc/zod-to-ts.ts:87:46 - error TS7030: Not all code paths return a value.\n  return\n}\n\nfunction getDocComment(schema: z.ZodType, indent: number): string {\n  const meta = (schema.meta() ?? {}) as Record<string, string>\n  const description: string =\n    // @ts-expect-error -- fixme\n    meta.description || schema.def.innerType?.description\n  const defaultValue = getDefaultValue(schema)\n  const def =\n    meta.default ??\n    (defaultValue === undefined\n      ? undefined\n      : JSON.stringify(defaultValue, null, 2))\n  const comments: string[] = []\n  if (description) {\n    comments.push(description)\n  }\n  if (def !== undefined) {\n    comments.push(`@default ${def}`)\n  }\n  if (!comments.length) {\n    return ''\n  }\n  const comment = [\n    //\n    '/**',\n    ...comments.flatMap(comment =>\n      comment.split('\\n').map(line => ` * ${line}`)\n    ),\n    ' */'\n  ]\n    .map(line => `${' '.repeat(indent)}${line}`)\n    .join('\\n')\n\n  return comment + '\\n'\n}\n"
  },
  {
    "path": "packages/nextra/src/server/twoslash.ts",
    "content": "/**\n * We explicitly didn't put this file in `rehype-twoslash-popup.ts` to avoid\n * having warnings which comes from `@typescript/vfs` https://github.com/shuding/nextra/pull/3349\n */\n\nimport { rendererRich } from '@shikijs/twoslash'\nimport type { RendererRichOptions } from '@shikijs/twoslash'\nimport type { Element, ElementContent } from 'hast'\nimport type { Code } from 'mdast'\nimport { fromMarkdown } from 'mdast-util-from-markdown'\nimport { gfmFromMarkdown } from 'mdast-util-gfm'\nimport { defaultHandlers, toHast } from 'mdast-util-to-hast'\nimport type { ShikiTransformerContextCommon } from 'shiki'\n\nfunction renderMarkdown(\n  this: ShikiTransformerContextCommon,\n  md: string\n): ElementContent[] {\n  const mdast = fromMarkdown(\n    md.replaceAll(/{@link (?<link>[^}]*)}/g, '$1'), // replace jsdoc links\n    { mdastExtensions: [gfmFromMarkdown()] }\n  )\n\n  return (\n    toHast(mdast, {\n      handlers: {\n        code: (state, node: Code) => {\n          if (node.lang) {\n            return this.codeToHast(node.value, {\n              ...this.options,\n              transformers: [],\n              meta: {\n                __raw: node.meta ?? undefined\n              },\n              lang: node.lang\n            }).children[0] as Element\n          }\n\n          return defaultHandlers.code(state, node)\n        }\n      }\n    }) as Element\n  ).children\n}\n\nfunction renderMarkdownInline(\n  this: ShikiTransformerContextCommon,\n  md: string,\n  context?: string\n): ElementContent[] {\n  const text =\n    context === 'tag:param' ? md.replace(/^(?<link>[\\w$-]+)/, '`$1` ') : md\n\n  const children = renderMarkdown.call(this, text)\n  const [firstChild] = children\n  if (\n    children.length === 1 &&\n    firstChild?.type === 'element' &&\n    firstChild.tagName === 'p'\n  )\n    return firstChild.children\n  return children\n}\n\nexport function twoslashRenderer(options?: RendererRichOptions) {\n  return rendererRich({\n    ...options,\n    renderMarkdown,\n    renderMarkdownInline,\n    hast: {\n      hoverToken: { tagName: 'Popup' },\n      hoverPopup: { tagName: 'PopupPanel' },\n      hoverCompose: ({ popup, token }) => [\n        popup,\n        {\n          type: 'element',\n          tagName: 'PopupButton',\n          properties: {},\n          children: [token]\n        }\n      ],\n      ...options?.hast\n    }\n  })\n}\n"
  },
  {
    "path": "packages/nextra/src/server/utils.ts",
    "content": "import type {\n  ArrayExpression,\n  ExportNamedDeclaration,\n  Expression,\n  ObjectExpression\n} from 'estree'\nimport title from 'title'\nimport { DEFAULT_PROPERTY_PROPS } from './constants.js'\n\nexport const logger = {\n  info: console.log.bind(null, '-', '\\u001B[36minfo\\u001B[0m', '[nextra]'),\n  warn: console.log.bind(null, '-', '\\u001B[33mwarn\\u001B[0m', '[nextra]'),\n  error: console.log.bind(null, '-', '\\u001B[31merror\\u001B[0m', '[nextra]')\n}\n\nexport function pageTitleFromFilename(fileName: string) {\n  return title(fileName.replaceAll(/[-_]/g, ' '), {\n    special: ['SSR', 'CORS', 'ESLint']\n  })\n}\n\nexport function createAstExportConst(\n  name: string,\n  value: ArrayExpression | ObjectExpression | Expression\n): ExportNamedDeclaration {\n  return {\n    type: 'ExportNamedDeclaration',\n    specifiers: [],\n    declaration: {\n      type: 'VariableDeclaration',\n      kind: 'const',\n      declarations: [\n        {\n          type: 'VariableDeclarator',\n          id: { type: 'Identifier', name },\n          init: value\n        }\n      ]\n    }\n  }\n}\n\nexport function createAstObject(\n  obj: Record<string, string | number | boolean | null | Expression>\n): ObjectExpression {\n  return {\n    type: 'ObjectExpression',\n    properties: Object.entries(obj).map(([key, value]) => ({\n      ...DEFAULT_PROPERTY_PROPS,\n      key: { type: 'Identifier', name: key },\n      value:\n        value && typeof value === 'object' ? value : { type: 'Literal', value }\n    }))\n  }\n}\n"
  },
  {
    "path": "packages/nextra/src/types.generated.ts",
    "content": "export interface NextraConfig {\n  /**\n   * Enable the copy button for all code blocks by default, without needing to set `copy=true` attribute in the code block metadata.\n   * > [!TIP]\n   * >\n   * > You could still disable the button for specific blocks using `copy=false` attribute.\n   */\n  defaultShowCopyCode?: boolean\n\n  /**\n   * Option to enable search functionality. When enabled, it sets the `data-pagefind-body` attribute on the `<main>` element.\n   * > [!TIP]\n   * >\n   * > When set to `codeblocks: false`, it adds the `data-pagefind-ignore=\"all\"` attribute to all code blocks (`<pre>` elements).\n   * @default {\n   *   \"codeblocks\": false\n   * }\n   */\n  search?: boolean | {\n    /**\n     * Whether to index code blocks.\n     */\n    codeblocks: boolean\n  }\n\n  /**\n   * Option to automatically optimizing your static image imports with the Markdown syntax.\n   * > [!TIP]\n   * >\n   * > Example: `![Hello](/demo.png)`.\n   * @default true\n   */\n  staticImage?: boolean\n\n  /**\n   * Adds estimated reading time of `.md` and `.mdx` files using [readingTime](https://npmjs.com/package/reading-time) package.\n   * > [!TIP]\n   * >\n   * > The reading time is added to the front matter under the `readingTime` key.\n   */\n  readingTime?: boolean\n\n  /**\n   * Enable LaTeX either with [KaTeX](https://katex.org) to pre-render LaTeX expressions directly in MDX or [MathJax](https://mathjax.org) to dynamically render math in the browser.\n   */\n  latex?: boolean | {\n    renderer: \"mathjax\"\n\n    options?: {\n      /**\n       * URL for MathJax.\n       * @default \"https://cdnjs.cloudflare.com\"\n       */\n      src?: string\n\n      /**\n       * MathJax config. See [configuring MathJax](https://docs.mathjax.org/en/latest/options/index.html).\n       */\n      config?: import(\"better-react-mathjax\").MathJax3Config\n    }\n  } | {\n    renderer: \"katex\"\n\n    /**\n     * KaTeX options. See https://katex.org/docs/options.html.\n     */\n    options: import(\"rehype-katex\").Options\n  }\n\n  /**\n   * Enable or disable syntax highlighting.\n   * @default true\n   */\n  codeHighlight?: boolean\n\n  /**\n   * Options specific to MDX compiling.\n   * @remarks `MdxOptions`\n   * @default {\n   *   \"format\": \"detect\",\n   *   \"rehypePrettyCodeOptions\": {}\n   * }\n   */\n  mdxOptions?: {\n    /**\n     * List of rehype plugins.\n     */\n    rehypePlugins?: import(\"@mdx-js/mdx\").ProcessorOptions[\"rehypePlugins\"]\n\n    /**\n     * List of remark plugins.\n     */\n    remarkPlugins?: import(\"@mdx-js/mdx\").ProcessorOptions[\"remarkPlugins\"]\n\n    /**\n     * List of recma plugins. This is a new ecosystem, currently in beta, to transform esast trees (JavaScript).\n     */\n    recmaPlugins?: import(\"@mdx-js/mdx\").ProcessorOptions[\"recmaPlugins\"]\n\n    /**\n     * Format of the file.\n     * - `'md'` means treat as markdown\n     * - `'mdx'` means treat as MDX\n     * - `'detect'` means try to detect the format based on file path.\n     * @default \"detect\"\n     */\n    format?: \"detect\" | \"mdx\" | \"md\"\n\n    /**\n     * Configuration options for [Rehype Pretty Code](https://github.com/rehype-pretty/rehype-pretty-code).\n     * @remarks `RehypePrettyCodeOptions`\n     * @default {}\n     */\n    rehypePrettyCodeOptions?: import(\"rehype-pretty-code\").Options\n  }\n\n  /**\n   * Allows you to whitelist HTML elements to be replaced with components defined in the `mdx-components.js` file.\n   * > [!TIP]\n   * >\n   * > By default, Nextra only replaces `<details>` and `<summary>` elements.\n   */\n  whiteListTagsStyling?: string[]\n\n  /**\n   * Option to serve your `.md` and `.mdx` files from the `content` directory at a custom path instead of the root (`/`).\n   * @default \"/\"\n   */\n  contentDirBasePath?: string\n\n  /**\n   * Prefixes locale to all links in the page map information. Useful for i18n when you don't want to use Nextra's `middleware` function.\n   * @default false\n   */\n  unstable_shouldAddLocaleToLinks?: boolean\n}\n\nexport interface HeadProps {\n  /**\n   * @default {\n   *   \"hue\": {\n   *     \"dark\": 204,\n   *     \"light\": 212\n   *   },\n   *   \"saturation\": {\n   *     \"dark\": 100,\n   *     \"light\": 100\n   *   },\n   *   \"lightness\": {\n   *     \"dark\": 55,\n   *     \"light\": 45\n   *   }\n   * }\n   */\n  color?: {\n    /**\n     * The hue of the primary theme color.<br/>Range: `0 - 360`\n     * @default {\n     *   \"dark\": 204,\n     *   \"light\": 212\n     * }\n     */\n    hue?: number | {\n      dark: number\n\n      light: number\n    }\n\n    /**\n     * The saturation of the primary theme color.<br/>Range: `0 - 100`\n     * @default 100\n     */\n    saturation?: number | {\n      dark: number\n\n      light: number\n    }\n\n    /**\n     * The lightness of the primary theme color.<br/>Range: `0 - 100`\n     * @default {\n     *   \"dark\": 55,\n     *   \"light\": 45\n     * }\n     */\n    lightness?: number | {\n      dark: number\n\n      light: number\n    }\n  }\n\n  /**\n   * The glyph to use as the favicon.\n   */\n  faviconGlyph?: string\n\n  /**\n   * @default {\n   *   \"dark\": \"17,17,17\",\n   *   \"light\": \"250,250,250\"\n   * }\n   */\n  backgroundColor?: {\n    /**\n     * Background color for dark theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`\n     * @default \"rgb(17,17,17)\"\n     */\n    dark?: string\n\n    /**\n     * Background color for light theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`\n     * @default \"rgb(250,250,250)\"\n     */\n    light?: string\n  }\n\n  /**\n   * Content of `<head>`.\n   */\n  children?: React.ReactNode\n}"
  },
  {
    "path": "packages/nextra/src/types.ts",
    "content": "import type { Heading as MDASTHeading } from 'mdast'\nimport type { Metadata } from 'next'\nimport type { FC, ReactElement, ReactNode } from 'react'\nimport type { z } from 'zod'\nimport type {\n  MathJaxOptionsSchema,\n  menuSchema,\n  metaSchema,\n  NextraConfigSchema,\n  separatorItemSchema\n} from './server/schemas.js'\n\nexport type { NextraConfig } from './types.generated.js'\n\ntype NextraConfigFromZod = z.infer<typeof NextraConfigSchema>\n\nexport interface LoaderOptions extends NextraConfigFromZod {\n  isPageImport?: boolean\n  locales: string[]\n  contentDir?: string\n  shouldAddLocaleToLinks?: boolean\n}\n\ntype TPageItem = { name: string; route: string; __pagePath: string }\ntype TMetaItem = { __metaPath: string }\n\ninterface TFolder<T = TItem> {\n  name: string\n  route: string\n  children: T[]\n}\n\nexport type TItem = TPageItem | TMetaItem | TFolder\n\nexport interface Folder<FileType = PageMapItem> {\n  name: string\n  route: string\n  children: FileType[]\n}\n\nexport type Import = {\n  importName: string\n  filePath: string\n}\n\nexport type MetaJsonFile = {\n  data: {\n    [fileName: string]: Meta\n  }\n}\n\nexport type DynamicFolder = {\n  items: DynamicMeta\n  title?: string\n}\n\nexport type DynamicMetaItem = Meta | DynamicFolder\n\nexport type DynamicMeta = Record<string, DynamicMetaItem>\n\nexport type FrontMatter = Record<string, any>\nexport type Meta = string | Record<string, any>\n\nexport type MdxFile<FrontMatterType = FrontMatter> = {\n  name: string\n  route: string\n  frontMatter?: FrontMatterType\n}\n\nexport type PageMapItem = Folder | MdxFile | MetaJsonFile\n\n// PageMapItem without MetaJsonFile and with its meta from _meta.json\nexport type Page = (MdxFile | Folder<Page>) & {\n  meta?: Exclude<Meta, string>\n}\n\nexport type Heading = {\n  depth: Exclude<MDASTHeading['depth'], 1>\n  value: string | ReactElement\n  id: string\n}\n\nexport type $NextraMetadata = Omit<Metadata, 'title'> & {\n  title: string\n  filePath: string\n  timestamp?: number\n  readingTime?: ReadingTime\n}\n\nexport type ReadingTime = {\n  text: string\n  minutes: number\n  time: number\n  words: number\n}\n\nexport type MathJaxOptions = z.infer<typeof MathJaxOptionsSchema>\n\nexport type MDXWrapper = FC<\n  {\n    children: ReactNode\n    bottomContent?: ReactNode\n  } & Omit<EvaluateResult, 'default'>\n>\n\nexport type MetaRecord = Record<string, z.infer<typeof metaSchema>>\n\nexport type SeparatorItem = z.infer<typeof separatorItemSchema>\nexport type MenuItem = z.infer<typeof menuSchema>\n\n/**\n * Options that can be passed to `pagefind.search()`.\n * @remarks Copied from https://github.com/CloudCannon/pagefind/blob/2a0aa90cfb78bb8551645ac9127a1cd49cf54add/pagefind_web_js/types/index.d.ts#L72-L82\n */\nexport type PagefindSearchOptions = {\n  /**\n   * If set, this call will load all assets but return before searching. Prefer using `pagefind.preload()` instead.\n   */\n  preload?: boolean\n  /**\n   * Add more verbose console logging for this search query.\n   */\n  verbose?: boolean\n  /**\n   * The set of filters to execute with this search. Input type is extremely flexible, see the filtering docs for details.\n   */\n  filters?: object\n  /**\n   * The set of sorts to use for this search, instead of relevancy.\n   */\n  sort?: object\n}\n\nexport type NextraMetadata = Metadata & {\n  asIndexPage?: boolean\n  sidebarTitle?: string\n}\n\nexport type EvaluateResult = {\n  /** The MDX component to render. */\n  default: FC<any>\n  /** Table of contents list. */\n  toc: Heading[]\n  /** Page's front matter or `metadata` object including `title`, `description`, etc. */\n  metadata: $NextraMetadata\n  /** Raw MDX source code */\n  sourceCode: string\n}\n"
  },
  {
    "path": "packages/nextra/styles/cards.css",
    "content": ".nextra-cards {\n  grid-template-columns: repeat(\n    auto-fill,\n    minmax(max(250px, calc((100% - 1rem * 2) / var(--rows))), 1fr)\n  );\n}\n\n.nextra-card {\n  img {\n    @apply x:select-none;\n  }\n\n  & > span > svg {\n    @apply x:w-6 x:h-auto x:transition x:text-black/50 x:dark:text-white/50 x:shrink-0;\n  }\n\n  &:hover > span > svg {\n    @apply x:text-current!;\n  }\n\n  p {\n    @apply x:mt-2;\n  }\n}\n"
  },
  {
    "path": "packages/nextra/styles/code-block.css",
    "content": ".nextra-code span {\n  @apply x:bg-(--shiki-light-bg) x:text-(--shiki-light);\n  @apply x:dark:bg-(--shiki-dark-bg) x:dark:text-(--shiki-dark);\n}\n\ncode.nextra-code {\n  box-decoration-break: slice;\n  font-feature-settings:\n    'rlig' 1,\n    'calt' 1,\n    'ss01' 1;\n  @apply x:text-sm;\n\n  :not(pre) > &:not([class*='twoslash-']) {\n    @apply x:p-[.12em_.25em];\n    @apply x:rounded-[.375em];\n    @apply x:border-black/[0.04] x:bg-black/[0.03] x:break-words x:border x:text-[.9em];\n    @apply x:dark:border-white/10 x:dark:bg-white/10;\n  }\n}\n\npre code.nextra-code:not([class*='twoslash-']) {\n  @apply x:grid;\n  counter-reset: line;\n\n  &[data-line-numbers] > span {\n    @apply x:pl-2;\n    @apply x:before:text-gray-600 x:dark:before:text-gray-400;\n    &::before {\n      counter-increment: line;\n      content: counter(line);\n      @apply x:inline-block x:pr-4 x:text-right x:min-w-[2.6rem];\n    }\n  }\n\n  & > span {\n    @apply x:px-4;\n\n    &[data-highlighted-line] {\n      @apply x:bg-primary-600/10 x:dark:bg-primary-600/20 x:text-primary-600/80! x:shadow-[2px_0_currentColor_inset];\n    }\n\n    [data-highlighted-chars] {\n      @apply x:rounded-sm x:ring-2 x:ring-primary-600/20 x:dark:ring-primary-600/40;\n      @apply x:bg-primary-600/20 x:dark:bg-primary-600/40;\n    }\n  }\n\n  html[data-nextra-word-wrap] & {\n    @apply x:max-md:whitespace-pre-wrap;\n  }\n}\n\n.nextra-copy-icon {\n  animation: fade-in 0.3s ease forwards;\n}\n\n@keyframes fade-in {\n  0% {\n    opacity: 0;\n  }\n  100% {\n    opacity: 1;\n  }\n}\n\n/* ===== Basic ===== */\n:root {\n  --twoslash-border-color: #8888;\n  --twoslash-underline-color: currentColor;\n  --twoslash-highlighted-border: 195, 125, 13;\n  --twoslash-popup-bg: #f8f8f8;\n  --twoslash-popup-color: inherit;\n  --twoslash-popup-shadow: rgba(0, 0, 0.08) 0px 1px 4px;\n  --twoslash-docs-color: #888;\n  --twoslash-docs-font: sans-serif;\n  --twoslash-matched-color: inherit;\n  --twoslash-unmatched-color: #888;\n  --twoslash-cursor-color: #8888;\n  --twoslash-error-color: 212, 86, 86;\n  --twoslash-error-bg: rgba(var(--twoslash-error-color), 0.13);\n  --twoslash-tag-color: 55, 114, 207;\n  --twoslash-tag-warn-color: 195, 125, 13;\n  --twoslash-tag-annotate-color: 27, 166, 115;\n}\n\n.dark {\n  --twoslash-popup-bg: #000;\n  --twoslash-border-color: #404040;\n}\n\n/* Respect people's wishes to not have animations */\n@media (prefers-reduced-motion: reduce) {\n  .twoslash * {\n    transition: none !important;\n  }\n}\n\n/* ===== Hover Info ===== */\n.twoslash:hover .twoslash-hover {\n  border-color: var(--twoslash-underline-color);\n}\n\n.twoslash-hover {\n  border-bottom: 1px dotted transparent;\n  transition-timing-function: ease;\n  transition: border-color 0.3s;\n  position: relative;\n}\n\n.twoslash-popup-container {\n  @apply x:inline-flex x:flex-col x:absolute x:transition-opacity x:duration-300 x:z-10 x:mt-1.5 x:rounded;\n  transform: translateY(1.1em);\n  background: var(--twoslash-popup-bg) !important;\n  color: var(--twoslash-popup-color);\n  border: 1px solid var(--twoslash-border-color);\n  text-align: left;\n  /*box-shadow: var(--twoslash-popup-shadow);*/\n}\n\n.twoslash-query-presisted .twoslash-popup-container {\n  z-index: 9;\n  transform: translateY(1.5em);\n}\n\n.twoslash-popup-arrow {\n  @apply x:absolute x:-top-1 x:border-t x:border-r x:size-1.5 x:-rotate-45;\n  @apply x:border-(--twoslash-border-color) x:bg-(--twoslash-popup-bg);\n  left: 1em;\n  pointer-events: none;\n}\n\n.twoslash-popup-code,\n.twoslash-popup-docs {\n  padding: 6px 8px;\n}\n\n.twoslash-popup-docs {\n  @apply x:text-sm;\n  color: var(--twoslash-docs-color);\n  font-family: var(--twoslash-docs-font);\n  border-top: 1px solid var(--twoslash-border-color);\n}\n\n.twoslash-popup-docs-tags {\n  display: flex;\n  flex-direction: column;\n  font-family: var(--twoslash-docs-font);\n}\n\n.twoslash-popup-docs-tags,\n.twoslash-popup-docs-tag-name {\n  margin-right: 0.5em;\n}\n\n/* ===== Error Line ===== */\n.twoslash-error-line {\n  position: relative;\n  background-color: var(--twoslash-error-bg);\n  border-left: 3px solid currentColor;\n  color: rgb(var(--twoslash-error-color));\n  padding: 6px 12px;\n  margin: 0.2em 0;\n}\n\n.twoslash-error {\n  background: url(\"data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E\")\n    repeat-x bottom left;\n  padding-bottom: 2px;\n}\n\n/* ===== Completeions ===== */\n.twoslash-completion-cursor {\n  position: relative;\n}\n\n.twoslash-completion-cursor .twoslash-completion-list {\n  @apply x:absolute x:left-0 x:border x:top-1 x:rounded;\n  transform: translate(0, 1.2em);\n  background: var(--twoslash-popup-bg);\n  border-color: var(--twoslash-border-color);\n}\n\n.twoslash-completion-list {\n  @apply x:py-1 x:px-2 x:w-60;\n}\n\n.twoslash-completion-list::before {\n  background-color: var(--twoslash-cursor-color);\n  width: 2px;\n  position: absolute;\n  top: -1.6em;\n  height: 1.4em;\n  left: -1px;\n  content: ' ';\n}\n\n.twoslash-completion-list li {\n  overflow: hidden;\n  display: flex;\n  align-items: center;\n  gap: 0.25em;\n  line-height: 1em;\n}\n\n.twoslash-completion-list li span.twoslash-completions-unmatched {\n  color: var(--twoslash-unmatched-color);\n}\n\n.twoslash-completion-list .deprecated {\n  text-decoration: line-through;\n  opacity: 0.5;\n}\n\n.twoslash-completion-list li span.twoslash-completions-matched {\n  color: var(--twoslash-matched-color);\n}\n\n/* Highlights */\n.twoslash-highlighted {\n  background-color: rgba(var(--twoslash-highlighted-border), 0.13);\n  border: 1px solid rgba(var(--twoslash-highlighted-border), 0.31);\n  padding: 1px 2px;\n  margin: -1px -3px;\n  border-radius: 4px;\n}\n\n/* Icons */\n.twoslash-completion-list .twoslash-completions-icon {\n  color: var(--twoslash-unmatched-color);\n  width: 1em;\n  flex: none;\n}\n\n/* Custom Tags */\n.twoslash-tag-line {\n  position: relative;\n  background-color: rgba(var(--twoslash-tag-color), 0.13);\n  border-left: 3px solid currentColor;\n  color: rgb(var(--twoslash-tag-color));\n  padding: 6px 10px;\n  margin: 0.2em 0;\n  display: flex;\n  align-items: center;\n  gap: 0.3em;\n}\n\n.twoslash-tag-line .twoslash-tag-icon {\n  width: 1.1em;\n  color: inherit;\n}\n\n.twoslash-tag-line.twoslash-tag-error-line {\n  background-color: var(--twoslash-error-bg);\n  color: rgb(var(--twoslash-error-color));\n}\n\n.twoslash-tag-line.twoslash-tag-warn-line {\n  background-color: rgba(var(--twoslash-tag-warn-color), 0.13);\n  color: rgb(var(--twoslash-tag-warn-color));\n}\n\n.twoslash-tag-line.twoslash-tag-annotate-line {\n  background-color: rgba(var(--twoslash-tag-annotate-color), 0.13);\n  color: rgb(var(--twoslash-tag-annotate-color));\n}\n"
  },
  {
    "path": "packages/nextra/styles/default.css",
    "content": "@source '../src/client/icons/*.svg';\n@source '../src/client/{components,hocs,mdx-components}/**/*.tsx';\n@source '../src/server/tsdoc/**/*.tsx';\n@variant dark (&:where(.dark *));\n\n@theme {\n  --color-nextra-bg: rgb(var(--nextra-bg));\n  --color-primary-50: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) + 52%)\n  );\n  --color-primary-100: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) + 49%)\n  );\n  --color-primary-200: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) + 41%)\n  );\n  --color-primary-300: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) + 32%)\n  );\n  --color-primary-400: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) + 21%)\n  );\n  --color-primary-500: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) + 5%)\n  );\n  --color-primary-600: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      var(--nextra-primary-lightness)\n  );\n  --color-primary-700: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) - 6%)\n  );\n  --color-primary-800: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) - 13%)\n  );\n  --color-primary-900: hsl(\n    var(--nextra-primary-hue) var(--nextra-primary-saturation)\n      calc(var(--nextra-primary-lightness) - 21%)\n  );\n}\n\n/* Fixes extra margin-top inside Tabs.Tab\n * https://github.com/shuding/nextra/issues/4303#issuecomment-2695040708\n */\n[data-headlessui-state='selected'] > h3[style^='visibility:'] + * {\n  @apply x:mt-0;\n}\n"
  },
  {
    "path": "packages/nextra/styles/react-medium-image-zoom.css",
    "content": "[data-rmiz-ghost] {\n  position: absolute;\n  pointer-events: none;\n}\n\n[data-rmiz-btn-zoom],\n[data-rmiz-btn-unzoom] {\n  @apply x:bg-black/70 x:text-white x:dark:bg-white/70 x:dark:text-black x:rounded-full x:size-10;\n  outline-offset: 2px;\n  padding: 9px;\n  touch-action: manipulation;\n  appearance: none;\n}\n\n[data-rmiz-btn-zoom] {\n  position: absolute;\n  inset: 10px 10px auto auto;\n  cursor: zoom-in;\n\n  &:not(:focus):not(:active) {\n    position: absolute;\n    clip: rect(0 0 0 0);\n    clip-path: inset(50%);\n    height: 1px;\n    overflow: hidden;\n    pointer-events: none;\n    white-space: nowrap;\n    width: 1px;\n  }\n}\n\n[data-rmiz-btn-unzoom] {\n  position: absolute;\n  inset: 20px 20px auto auto;\n  cursor: zoom-out;\n  z-index: 1;\n}\n\n[data-rmiz-content='found'] {\n  img,\n  svg,\n  [role='img'],\n  [data-zoom] {\n    cursor: zoom-in;\n  }\n}\n\n[data-rmiz-modal]::backdrop {\n  display: none;\n}\n\n[data-rmiz-modal][open] {\n  position: fixed;\n  width: 100vw;\n  width: 100dvw;\n  height: 100vh;\n  height: 100dvh;\n  max-width: none;\n  max-height: none;\n  margin: 0;\n  padding: 0;\n  border: 0;\n  background: transparent;\n  overflow: hidden;\n}\n\n[data-rmiz-modal-overlay] {\n  position: absolute;\n  inset: 0;\n  transition: opacity 0.3s;\n  background: rgba(var(--nextra-bg), 0.8);\n}\n\n[data-rmiz-modal-overlay='hidden'] {\n  opacity: 0%;\n}\n\n[data-rmiz-modal-overlay='visible'] {\n  opacity: 100%;\n}\n\n[data-rmiz-modal-content] {\n  position: relative;\n  width: 100%;\n  height: 100%;\n}\n\n[data-rmiz-modal-img] {\n  position: absolute;\n  cursor: zoom-out;\n  image-rendering: high-quality;\n  transform-origin: top left;\n  transition: transform 0.3s;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  [data-rmiz-modal-overlay],\n  [data-rmiz-modal-img] {\n    transition-duration: 0.01ms;\n  }\n}\n"
  },
  {
    "path": "packages/nextra/styles/scrollbar.css",
    "content": ".nextra-scrollbar {\n  scrollbar-width: thin;\n  scrollbar-gutter: stable;\n}\n\n/* Hide scrollbar */\n.no-scrollbar {\n  scrollbar-width: none; /* Firefox */\n  -ms-overflow-style: none; /* IE and Edge */\n\n  &::-webkit-scrollbar {\n    @apply x:hidden; /* Chrome, Safari and Opera */\n  }\n}\n"
  },
  {
    "path": "packages/nextra/styles/steps.css",
    "content": ".nextra-steps {\n  h2,\n  /* Avoid breaking `<Steps>` component numeration when there is `<Tabs>` component inside */\n  h3:not([style^='visibility:']),\n  h4,\n  h5,\n  h6 {\n    counter-increment: var(--counter-id);\n    /* Resets from nextra-theme-docs */\n    @apply x:border-0 x:pb-0 x:font-semibold x:tracking-tight x:mt-8 x:text-2xl;\n    /* https://github.com/tailwindlabs/tailwindcss/issues/15597#issuecomment-2582673546 */\n    @apply x:before:bg-gray-200 x:dark:before:bg-neutral-800;\n    @apply x:before:text-neutral-800 x:dark:before:text-neutral-300;\n    &:before {\n      @apply x:absolute x:size-[33px];\n      @apply x:border-4 x:border-nextra-bg;\n      @apply x:rounded-full x:text-base x:font-normal x:text-center x:-indent-px;\n      @apply x:ms-[-41px];\n      content: counter(var(--counter-id));\n    }\n  }\n}\n"
  },
  {
    "path": "packages/nextra/styles/subheading-anchor.css",
    "content": ":hover > .subheading-anchor {\n  @apply x:opacity-100;\n}\n\n.subheading-anchor {\n  @apply x:ms-1;\n\n  @apply x:opacity-0 x:transition;\n\n  :target > &,\n  &:focus {\n    @apply x:opacity-100;\n  }\n\n  :target > & {\n    /* https://github.com/tailwindlabs/tailwindcss/issues/15597#issuecomment-2582673546 */\n    @apply x:after:text-gray-600 x:dark:after:text-neutral-400;\n  }\n\n  &:after {\n    @apply x:content-['#'] x:px-1;\n  }\n  /* https://github.com/tailwindlabs/tailwindcss/issues/15597#issuecomment-2582673546 */\n  @apply x:after:text-gray-600 x:dark:after:text-neutral-400;\n}\n"
  },
  {
    "path": "packages/nextra/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2022\",\n    \"module\": \"ESNext\",\n    \"declaration\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": true,\n    \"jsx\": \"react-jsx\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"moduleResolution\": \"node\",\n    \"types\": [\"vitest/globals\"],\n    \"paths\": {\n      \"unified\": [\"./node_modules/unified\"]\n    },\n    \"resolveJsonModule\": true,\n    \"noUncheckedIndexedAccess\": true\n  },\n  \"exclude\": [\"dist\"]\n}\n"
  },
  {
    "path": "packages/nextra/tsup.config.ts",
    "content": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport svgr from 'esbuild-plugin-svgr'\nimport { reactCompilerPlugin } from 'esbuild-react-compiler-plugin'\nimport { defineConfig } from 'tsup'\nimport { defaultEntry } from './default-entry.js'\nimport packageJson from './package.json'\nimport { IS_PRODUCTION } from './src/server/constants.js'\n\nconst SEP = path.sep === '/' ? '/' : '\\\\\\\\'\n\nexport default defineConfig({\n  name: packageJson.name,\n  entry: [...defaultEntry, '!src/icon.ts', 'src/**/*.svg'],\n  format: 'esm',\n  dts: true,\n  splitting: IS_PRODUCTION,\n  clean: IS_PRODUCTION,\n  bundle: false,\n  external: ['shiki', 'webpack'],\n  async onSuccess() {\n    // Fixes hydration errors in client apps due \"type\": \"module\" in root package.json\n    const clientPackageJSON = path.resolve('dist', 'client', 'package.json')\n    await fs.writeFile(clientPackageJSON, '{\"sideEffects\":false}')\n  },\n  esbuildPlugins: [\n    svgr({\n      exportType: 'named',\n      typescript: true,\n      svgoConfig: {\n        plugins: ['removeXMLNS']\n      },\n      plugins: ['@svgr/plugin-svgo']\n    }),\n    reactCompilerPlugin({\n      filter: new RegExp(\n        String.raw`/nextra/src/client/.+$`.replaceAll('/', SEP)\n      )\n    })\n  ],\n  plugins: [\n    {\n      // Strip `node:` prefix from imports\n      // Next.js only polyfills `path` and not `node:path` for browser\n      name: 'strip-node-colon',\n      renderChunk(code) {\n        // (?<= from \")\n        // Positive lookbehind asserts that the pattern we're trying to match is preceded by\n        // ` from \"`, but does not include ` from \"` in the actual match.\n        //\n        // (?=\";)\n        // Positive lookahead asserts that the pattern is followed by `\";`, but does not include\n        // `\";` in the match.\n        const replaced = code.replaceAll(/(?<= from \")node:(.+)(?=\";)/g, '$1')\n        return { code: replaced }\n      }\n    },\n    {\n      // Strip `.svg` suffix from imports\n      name: 'strip-dot-svg',\n      renderChunk(code) {\n        const replaced = code.replaceAll(/(?<= from \")(.+)\\.svg(?=\";)/g, '$1')\n        return { code: replaced }\n      }\n    }\n  ]\n})\n"
  },
  {
    "path": "packages/nextra/vitest.config.ts",
    "content": "import path from 'node:path'\nimport react from '@vitejs/plugin-react'\nimport { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  plugins: [react()],\n  test: {\n    globals: true,\n    environment: 'jsdom',\n    testTimeout: 17_000,\n    alias: {\n      // to make pass `merge-meta-with-page-map.ts` test\n      'next-mdx-import-source-file': path.resolve(\n        'src/client/mdx-components.ts'\n      )\n    },\n    setupFiles: ['./setup-files.ts']\n  },\n  server: {\n    watch: {\n      ignored: [\n        '**/node_modules/**',\n        '**/dist/**',\n        // Otherwise vitest will infinity re-run in watch mode\n        '**/generated-*'\n      ]\n    }\n  }\n})\n"
  },
  {
    "path": "packages/nextra-theme-blog/CHANGELOG.md",
    "content": "# nextra-theme-blog\n\n## 4.6.2\n\n### Patch Changes\n\n- Updated dependencies [9e6f5af]\n  - nextra@4.6.2\n\n## 4.6.1\n\n### Patch Changes\n\n- 261fcdc: - update zod to v4 stable\n  - fix compatibility with Next.js 16\n- Updated dependencies [261fcdc]\n  - nextra@4.6.1\n\n## 4.6.0\n\n### Patch Changes\n\n- nextra@4.6.0\n\n## 4.5.1\n\n### Patch Changes\n\n- Updated dependencies [8a4d176]\n  - nextra@4.5.1\n\n## 4.5.0\n\n### Patch Changes\n\n- Updated dependencies [356a782]\n  - nextra@4.5.0\n\n## 4.4.0\n\n### Patch Changes\n\n- Updated dependencies [26b1281]\n  - nextra@4.4.0\n\n## 4.3.0\n\n### Minor Changes\n\n- eed8328: feat: adapt colors and icons from original GitHub alerts syntax\n\n  feat: new Callout type `important`\n\n  fix: inconsistent built-in Callout's icons size\n\n  feat: improve Callout's accessibility colors\n\n- 0831a1b: Add an `onSearch` callback to the `<Search />` component. This\n  callback, when specified, is called upon every search input change.\n- 94b081c: feat: refactor `<Search>` component styles for improved transitions\n  and visibility\n- b5fab80: add `MDXRemote` component docs page\n  https://nextra.site/docs/built-ins/mdxremote\n- d9dd061: update `tailwindcss` to `4.1.10` and `react-compiler-runtime` to\n  `19.1.0-rc.2`\n- c134abe: feat: improve overall accessibility, makes text/colors easier to read\n  and achieves WCAG Level AAA compliance in many places\n- 83f6c57: feat: introduce new `<TSDoc />` component\n\n  The `<TSDoc>` component from `nextra/tsdoc` generates a properties table that\n  displays:\n  - **Property name**\n  - **TypeScript type**\n  - **Property description** - is parsed from [TSDoc](https://tsdoc.org) inline\n    description or the `@description` tag. You can use any Markdown/MDX syntax\n    here.\n  - **Default value** - are extracted from the `@default` or `@defaultValue`\n    tag.\n  - **Permalink** - a `#` anchor link to the property row for easy reference.\n\n  More info can be found in https://nextra.site/docs/built-ins/tsdoc\n\n  > [!IMPORTANT]\n  >\n  > Huge thanks to\n  > [xyflow - Node Based UIs for React and Svelte](https://xyflow.com/?utm_source=github&utm_campaign=nextra-4.3&utm_content=changelog)\n  > for sponsoring this feature!\n\n- 07debf9: feat(TSDoc): support flattening return object fields\n\n### Patch Changes\n\n- 71f7b3f: Update https://nextra.site/docs/guide/search page\n\n  Fixes extra margin-top inside `Tabs.Tab`\n\n  Fix breaking `<Steps>` component numeration when there is `<Tabs>` component\n  inside\n\n- 47ba5f3: fix: use `em` for padding-y, padding-x and border-radius styles of\n  `<Code>` element\n\n  fix(TSDoc): for return signature without `name` return mobile card instead of\n  table\n\n  feat: use `em` instead `rem` for margins\n\n- 40267dc: split `TSDoc` component logic to `TSDoc` component and\n  `generateDocumentation` function\n\n  update https://nextra.site/docs/built-ins/tsdoc documentation\n\n- 8ac2506: chore: bump `babel-plugin-react-compiler` and\n  `react-compiler-runtime`, remove custom pnpm patch for\n  `babel-plugin-react-compiler`\n- b2cba90: improve TSDoc comments for `getPageMap`, `generateStaticParamsFor`\n  and `importPage` functions. Add new https://nextra.site/docs/guide/api page.\n- d29469e: support Next.js 15.3.0\n- 4547eb9: feat(TSDoc): add support for functions and functions with multiple\n  signatures\n- 407e0c4: feat(TSDoc): add `TSDoc.noParametersContent` prop\n- a506e0b: fix `TypeError: page.generateMetadata is not a function` when using\n  with `withSentryConfig` plugin\n- Updated dependencies [eed8328]\n- Updated dependencies [71f7b3f]\n- Updated dependencies [0831a1b]\n- Updated dependencies [b0afee7]\n- Updated dependencies [c93fc48]\n- Updated dependencies [47ba5f3]\n- Updated dependencies [01ac538]\n- Updated dependencies [94b081c]\n- Updated dependencies [b5fab80]\n- Updated dependencies [40267dc]\n- Updated dependencies [ef35ab9]\n- Updated dependencies [f717156]\n- Updated dependencies [9f449e5]\n- Updated dependencies [8ac2506]\n- Updated dependencies [a6a1f97]\n- Updated dependencies [fda0355]\n- Updated dependencies [b2cba90]\n- Updated dependencies [f40e018]\n- Updated dependencies [d29469e]\n- Updated dependencies [d9dd061]\n- Updated dependencies [6a82e6f]\n- Updated dependencies [c134abe]\n- Updated dependencies [7de40fb]\n- Updated dependencies [c7d25df]\n- Updated dependencies [4547eb9]\n- Updated dependencies [407e0c4]\n- Updated dependencies [83f6c57]\n- Updated dependencies [00f4696]\n- Updated dependencies [31ddba4]\n- Updated dependencies [07debf9]\n- Updated dependencies [a506e0b]\n- Updated dependencies [9690841]\n  - nextra@4.3.0\n\n## 4.3.0-alpha.31\n\n### Patch Changes\n\n- Updated dependencies [f40e018]\n  - nextra@4.3.0-alpha.31\n\n## 4.3.0-alpha.30\n\n### Patch Changes\n\n- Updated dependencies [b0afee7]\n  - nextra@4.3.0-alpha.30\n\n## 4.3.0-alpha.29\n\n### Patch Changes\n\n- Updated dependencies [a6a1f97]\n  - nextra@4.3.0-alpha.29\n\n## 4.3.0-alpha.28\n\n### Patch Changes\n\n- Updated dependencies [ef35ab9]\n  - nextra@4.3.0-alpha.28\n\n## 4.3.0-alpha.27\n\n### Patch Changes\n\n- Updated dependencies [01ac538]\n  - nextra@4.3.0-alpha.27\n\n## 4.3.0-alpha.26\n\n### Patch Changes\n\n- Updated dependencies [c7d25df]\n  - nextra@4.3.0-alpha.26\n\n## 4.3.0-alpha.25\n\n### Minor Changes\n\n- d9dd061: update `tailwindcss` to `4.1.10` and `react-compiler-runtime` to\n  `19.1.0-rc.2`\n\n### Patch Changes\n\n- Updated dependencies [d9dd061]\n  - nextra@4.3.0-alpha.25\n\n## 4.3.0-alpha.24\n\n### Minor Changes\n\n- 0831a1b: Add an `onSearch` callback to the `<Search />` component. This\n  callback, when specified, is called upon every search input change.\n\n### Patch Changes\n\n- Updated dependencies [0831a1b]\n  - nextra@4.3.0-alpha.24\n\n## 4.3.0-alpha.23\n\n### Patch Changes\n\n- Updated dependencies [9690841]\n  - nextra@4.3.0-alpha.23\n\n## 4.3.0-alpha.22\n\n### Minor Changes\n\n- b5fab80: add `MDXRemote` component docs page\n  https://nextra.site/docs/built-ins/mdxremote\n\n### Patch Changes\n\n- Updated dependencies [c93fc48]\n- Updated dependencies [b5fab80]\n  - nextra@4.3.0-alpha.22\n\n## 4.3.0-alpha.21\n\n### Patch Changes\n\n- Updated dependencies [6a82e6f]\n  - nextra@4.3.0-alpha.21\n\n## 4.3.0-alpha.20\n\n### Patch Changes\n\n- nextra@4.3.0-alpha.20\n\n## 4.3.0-alpha.19\n\n### Patch Changes\n\n- 407e0c4: feat(TSDoc): add `TSDoc.noParametersContent` prop\n- Updated dependencies [407e0c4]\n  - nextra@4.3.0-alpha.19\n\n## 4.3.0-alpha.18\n\n### Patch Changes\n\n- Updated dependencies [7de40fb]\n- Updated dependencies [00f4696]\n- Updated dependencies [31ddba4]\n  - nextra@4.3.0-alpha.18\n\n## 4.3.0-alpha.17\n\n### Patch Changes\n\n- nextra@4.3.0-alpha.17\n\n## 4.3.0-alpha.16\n\n### Patch Changes\n\n- nextra@4.3.0-alpha.16\n\n## 4.3.0-alpha.15\n\n### Patch Changes\n\n- b2cba90: improve TSDoc comments for `getPageMap`, `generateStaticParamsFor`\n  and `importPage` functions. Add new https://nextra.site/docs/guide/api page.\n- Updated dependencies [b2cba90]\n  - nextra@4.3.0-alpha.15\n\n## 4.3.0-alpha.14\n\n### Patch Changes\n\n- a506e0b: fix `TypeError: page.generateMetadata is not a function` when using\n  with `withSentryConfig` plugin\n- Updated dependencies [a506e0b]\n  - nextra@4.3.0-alpha.14\n\n## 4.3.0-alpha.13\n\n### Patch Changes\n\n- 47ba5f3: fix: use `em` for padding-y, padding-x and border-radius styles of\n  `<Code>` element\n\n  fix(TSDoc): for return signature without `name` return mobile card instead of\n  table\n\n  feat: use `em` instead `rem` for margins\n\n- d29469e: support Next.js 15.3.0\n- Updated dependencies [47ba5f3]\n- Updated dependencies [d29469e]\n  - nextra@4.3.0-alpha.13\n\n## 4.3.0-alpha.12\n\n### Patch Changes\n\n- 40267dc: split `TSDoc` component logic to `TSDoc` component and\n  `generateDocumentation` function\n\n  update https://nextra.site/docs/built-ins/tsdoc documentation\n\n- Updated dependencies [40267dc]\n  - nextra@4.3.0-alpha.12\n\n## 4.3.0-alpha.11\n\n### Patch Changes\n\n- 71f7b3f: Update https://nextra.site/docs/guide/search page\n\n  Fixes extra margin-top inside `Tabs.Tab`\n\n  Fix breaking `<Steps>` component numeration when there is `<Tabs>` component\n  inside\n\n- Updated dependencies [71f7b3f]\n  - nextra@4.3.0-alpha.11\n\n## 4.3.0-alpha.10\n\n### Patch Changes\n\n- nextra@4.3.0-alpha.10\n\n## 4.3.0-alpha.9\n\n### Minor Changes\n\n- 94b081c: feat: refactor `<Search>` component styles for improved transitions\n  and visibility\n\n### Patch Changes\n\n- Updated dependencies [94b081c]\n  - nextra@4.3.0-alpha.9\n\n## 4.3.0-alpha.8\n\n### Minor Changes\n\n- c134abe: feat: improve overall accessibility, makes text/colors easier to read\n  and achieves WCAG Level AAA compliance in many places\n\n### Patch Changes\n\n- Updated dependencies [c134abe]\n  - nextra@4.3.0-alpha.8\n\n## 4.3.0-alpha.7\n\n### Minor Changes\n\n- 07debf9: feat(TSDoc): support flattening return object fields\n\n### Patch Changes\n\n- Updated dependencies [07debf9]\n  - nextra@4.3.0-alpha.7\n\n## 4.3.0-alpha.6\n\n### Patch Changes\n\n- nextra@4.3.0-alpha.6\n\n## 4.3.0-alpha.5\n\n### Minor Changes\n\n- eed8328: feat: adapt colors and icons from original GitHub alerts syntax\n\n  feat: new Callout type `important`\n\n  fix: inconsistent built-in Callout's icons size\n\n  feat: improve Callout's accessibility colors\n\n### Patch Changes\n\n- Updated dependencies [eed8328]\n  - nextra@4.3.0-alpha.5\n\n## 4.3.0-alpha.4\n\n### Patch Changes\n\n- 4547eb9: feat(TSDoc): add support for functions and functions with multiple\n  signatures\n- Updated dependencies [4547eb9]\n  - nextra@4.3.0-alpha.4\n\n## 4.3.0-alpha.3\n\n### Patch Changes\n\n- Updated dependencies [f717156]\n  - nextra@4.3.0-alpha.3\n\n## 4.3.0-alpha.2\n\n### Patch Changes\n\n- 8ac2506: chore: bump `babel-plugin-react-compiler` and\n  `react-compiler-runtime`, remove custom pnpm patch for\n  `babel-plugin-react-compiler`\n- Updated dependencies [8ac2506]\n  - nextra@4.3.0-alpha.2\n\n## 4.3.0-alpha.1\n\n### Patch Changes\n\n- Updated dependencies [9f449e5]\n  - nextra@4.3.0-alpha.1\n\n## 4.3.0-alpha.0\n\n### Minor Changes\n\n- 83f6c57: feat: introduce new `<TSDoc />` component\n\n  The `<TSDoc>` component from `nextra/tsdoc` generates a properties table that\n  displays:\n  - **Property name**\n  - **TypeScript type**\n  - **Property description** - is parsed from [TSDoc](https://tsdoc.org) inline\n    description or the `@description` tag. You can use any Markdown/MDX syntax\n    here.\n  - **Default value** - are extracted from the `@default` or `@defaultValue`\n    tag.\n  - **Permalink** - a `#` anchor link to the property row for easy reference.\n\n  More info can be found in https://nextra.site/docs/built-ins/tsdoc\n\n  > [!IMPORTANT]\n  >\n  > Huge thanks to\n  > [xyflow - Node Based UIs for React and Svelte](https://xyflow.com/?utm_source=github&utm_campaign=nextra-4.3&utm_content=changelog)\n  > for sponsoring this feature!\n\n### Patch Changes\n\n- Updated dependencies [83f6c57]\n  - nextra@4.3.0-alpha.0\n\n## 4.2.18\n\n### Patch Changes\n\n- Updated dependencies [e1c2b1b]\n  - nextra@4.2.18\n\n## 4.2.17\n\n### Patch Changes\n\n- Updated dependencies [a7db0e6]\n- Updated dependencies [18e7fb9]\n  - nextra@4.2.17\n\n## 4.2.16\n\n### Patch Changes\n\n- 2cfaacc: fix: frozen spinner on loading state in search results by updating\n  Tailwind CSS to v4.0.10\n- Updated dependencies [2cfaacc]\n  - nextra@4.2.16\n\n## 4.2.15\n\n### Patch Changes\n\n- 5617e04: fix: loading state in search results was only visible during the\n  first search\n- Updated dependencies [5617e04]\n  - nextra@4.2.15\n\n## 4.2.14\n\n### Patch Changes\n\n- ccb5da2: removing custom nextra's scrollbar styles, allowing the browser's\n  default scrollbars to be used\n- Updated dependencies [ccb5da2]\n- Updated dependencies [05a202d]\n  - nextra@4.2.14\n\n## 4.2.13\n\n### Patch Changes\n\n- Updated dependencies [fc4035c]\n- Updated dependencies [fc4035c]\n  - nextra@4.2.13\n\n## 4.2.12\n\n### Patch Changes\n\n- nextra@4.2.12\n\n## 4.2.11\n\n### Patch Changes\n\n- nextra@4.2.11\n\n## 4.2.10\n\n### Patch Changes\n\n- Updated dependencies [5c22495]\n  - nextra@4.2.10\n\n## 4.2.9\n\n### Patch Changes\n\n- nextra@4.2.9\n\n## 4.2.8\n\n### Patch Changes\n\n- nextra@4.2.8\n\n## 4.2.7\n\n### Patch Changes\n\n- nextra@4.2.7\n\n## 4.2.6\n\n### Patch Changes\n\n- Updated dependencies [a7906d1]\n  - nextra@4.2.6\n\n## 4.2.5\n\n### Patch Changes\n\n- Updated dependencies [e6c3050]\n  - nextra@4.2.5\n\n## 4.2.4\n\n### Patch Changes\n\n- Updated dependencies [b46d831]\n- Updated dependencies [7949e28]\n  - nextra@4.2.4\n\n## 4.2.3\n\n### Patch Changes\n\n- ca67a19: remove requirement `page.{jsx,tsx}` pages to have exported `metadata`\n  object\n- Updated dependencies [ca67a19]\n  - nextra@4.2.3\n\n## 4.2.2\n\n### Patch Changes\n\n- Updated dependencies [dd32eca]\n  - nextra@4.2.2\n\n## 4.2.1\n\n### Patch Changes\n\n- nextra@4.2.1\n\n## 4.2.0\n\n### Patch Changes\n\n- 427b080: calculate `--nextra-banner-height` after mounting banner, so banner\n  text can be wrapped on multiple lines\n- 6b8053f: fix a sudden height jump on opening for `<detail>` element when his\n  last children contain margins\n- b0e686e: hide default `<summary>` arrow on mobile\n- Updated dependencies [427b080]\n- Updated dependencies [6b8053f]\n- Updated dependencies [b0e686e]\n  - nextra@4.2.0\n\n## 4.1.1\n\n### Patch Changes\n\n- 29a44de: fix regression from Nextra 3 setting\n  [`theme.collapsed?: boolean` in `_meta` file](https://nextra.site/docs/file-conventions/meta-file#theme-option)\n  for folders has no effect in sidebar\n- Updated dependencies [29a44de]\n- Updated dependencies [19578c3]\n  - nextra@4.1.1\n\n## 4.1.0\n\n### Minor Changes\n\n- 7caf059: - generate unique anchor id for `<summary>` elements based on its\n  content at build time\n  - add anchor link icon for `<summary>`\n\n### Patch Changes\n\n- Updated dependencies [7caf059]\n  - nextra@4.1.0\n\n## 4.0.9\n\n### Patch Changes\n\n- Updated dependencies [e78f796]\n- Updated dependencies [ff007b2]\n  - nextra@4.0.9\n\n## 4.0.8\n\n### Patch Changes\n\n- Updated dependencies [267ef81]\n  - nextra@4.0.8\n\n## 4.0.7\n\n### Patch Changes\n\n- Updated dependencies [32e7d55]\n- Updated dependencies [695e428]\n- Updated dependencies [fc78033]\n- Updated dependencies [b2f2458]\n  - nextra@4.0.7\n\n## 4.0.6\n\n### Patch Changes\n\n- Updated dependencies [44ea060]\n  - nextra@4.0.6\n\n## 4.0.5\n\n### Patch Changes\n\n- Updated dependencies [14bf091]\n  - nextra@4.0.5\n\n## 4.0.4\n\n### Patch Changes\n\n- 5132295: fix broken `showLineNumbers` setting on code blocks\n- 5132295: fix unable order \\_meta key with `index` name\n- Updated dependencies [5132295]\n- Updated dependencies [5132295]\n  - nextra@4.0.4\n\n## 4.0.3\n\n### Patch Changes\n\n- nextra@4.0.3\n\n## 4.0.2\n\n### Patch Changes\n\n- nextra@4.0.2\n\n## 4.0.1\n\n### Patch Changes\n\n- 481e0d0: fix syntax highlighting for `mdx` lang and improve docs for\n  `/docs/docs-theme/start`\n- 426cd66: Remove margin-top from `.nextra-steps` `:before` pseudo selector\n- Updated dependencies [481e0d0]\n- Updated dependencies [426cd66]\n  - nextra@4.0.1\n\n## 4.0.0\n\n### Major Changes\n\n- 283320f: remove `\"typesVersions\"` field from `package.json`. You need to set\n  `\"moduleResolution\": \"bundler\"` in your `tsconfig.json` if you are using\n  TypeScript\n- 283320f: move `<Collapse>`, `<Details>`, `<Summary>`, `<SkipNavContent>`,\n  `SkipNavLink`, `<Select>` and `<Bleed>` from `nextra-theme-docs` to\n  `nextra/components`\n- 283320f: remove `<Th>`, `<Tr>` and `<Td>` exports (since they should be always\n  used with `<Table>` component)\n\n  ```diff\n  - import { Table, Th, Tr, Td } from 'nextra/components'\n  + import { Table } from 'nextra/components'\n\n  // ...\n\n  - <Th>\n  + <Table.Th>\n  - <Tr>\n  + <Table.Tr>\n  - <Td>\n  + <Table.Td>\n  ```\n\n- 283320f: make `compileMdx` from `nextra/compile` return a `string` instead of\n  an `object`\n- 283320f: remove `BlogMetadata.draft`, support \\_meta files for\n  `nextra-theme-blog`\n- 283320f: remove `export const title` from generated mdx pages\n- 283320f: The initial version which supports App Router instead of Pages\n  Router, something may be broken, check\n  https://github.com/shuding/nextra/tree/v4-v2/examples for the migration guide\n- 283320f: migrate search from Flexsearch to Pagefind\n- 283320f: - add root `_meta.global.{js,jsx,ts,tsx}` file\n  > See\n  > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts)\n  > based on https://nextra.site website\n  - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2\n    `lang?: string, route?: string = '/'`\n  - remove `createCatchAllMeta` from `nextra/catch-all`\n  - remove `collectCatchAllRoutes`\n  - remove `normalizePageRoute`\n  - add `mergeMetaWithPageMap` to `nextra/page-map`\n  - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime`\n    in remark plugin\n  - refactor recma rewrite plugin and add tests\n    - remove `recmaRewriteJsx`\n    - remove `recmaRewriteFunctionBody`\n  - make `convertPageMapToJs` sync\n- 283320f: improve performance on projects without Turbopack enabled\n- 283320f: release Nextra rc.0\n- 283320f: - migrate to tailwind css v4.beta2\n  - refactor builtin CSS classes from `_` prefix to `x:` prefix\n  - remove `color-primary-750` theme color variant\n- 283320f: replace `export const useTOC = () = [/* your headings */]` by\n  `export const toc = [/* your headings */]`\n- 283320f: move `<Head>` component in `nextra/components`\n- 283320f: remove `nextra-theme-blog/cusdis` export, export `<Comments>`\n  component from `nextra-theme-blog` directly (because `peerDependency` of\n  `react-cusdis` was removed)\n- 283320f: require Next.js minimum v14\n- 283320f: - add `nextra/components` to `experimental.optimizePackageImports` to\n  optimize `nextra/components` by default\n  - remove `<RemoteContent>` from `nextra/components`\n  - rename `<RemoteContent>` to `MDXRemote` and move to `nextra/mdx-remote`\n\n### Minor Changes\n\n- 283320f: add `nextThemes` prop in `<Layout>` component\n- 283320f: - use ReactIcon for code blocks with `jsx`, `tsx` language\n  - add JsonIcon for `json` language\n  - parse language from filename if exist when `diff` language is specified\n  - use JavaScript icon for `cjs` and `mjs`\n  - use TypeScript icon for `cts` and `mts`\n- 283320f: use `next-view-transitions` for transition in `nextra-theme-blog`\n- 283320f: replace `useContentDir` with `contentDirBasePath` option which\n  configure `content` directory under a catch-all subdirectory\n- 283320f: move TOC logic from `recma-rewrite-jsx` plugin to\n  `rehype-extract-toc-content` plugin\n- 283320f: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and\n  also `content` folder files - all add to `pageMap`, but ignore dynamic pages\n  `[[`\n- e11dbe0: set `content` value for `<meta name=\"theme-color\">` based on\n  background value for light and dark themes\n\n### Patch Changes\n\n- 283320f: search tweaks\n- fdd2c6a: fix steps background on dark mode fix headings anchor link color on\n  dark mode\n- 283320f: setup `@typescript-eslint/no-unnecessary-condition` rule and fix\n  warnings\n- aca79fa: Don't focus search input on `Ctrl + k` on non Mac devices. Don't\n  focus search input on `⌘ + Shift + k` or `Ctrl + Shift + k`.\n- 283320f: add helpful error message about not available search on development\n  mode\n- 283320f: remove `react-cusdis` dependency, use\n  https://cusdis.com/doc#/advanced/sdk directly\n- 283320f: add `getPageMap` helper function to `nextra/page-map`\n- 283320f: Fixes when Turbopack is enabled:\n  `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'`\n- 283320f: add `whiteListTagsStyling` nextra config option\n- 283320f: fix unable to select text and `::selection` style\n- 283320f: - allow override/add additional icons for code blocks\n  - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of\n    `mdx-components` file\n- 283320f: - Use Tailwind CSS CLI because CSS processing by `tsup` produce\n  different, weird and broken result\n  - Patch react-compiler with some fixes which isn't fixed\n- 283320f: use `Date.now()` for last edit time on development and git last\n  commit time on production\n- 283320f: move `pagefind` output to `public/_pagefind` directory\n  https://github.com/shuding/nextra/pull/3517\n- 283320f: initialize `transformerTwoslash` only 1 time outside of loader\n- 283320f: fix edit on github and last updated at for catch all routes\n- 283320f: simplify `generatePageMap`\n- 283320f: add `banner` prop for `<Layout>` component\n- 283320f: sync with nextra 3.1.0\n- 283320f: Cache the result of `repository.getFileLatestModifiedDateAsync`\n  because it can slow down Fast Refresh for uncommitted files.\n- 283320f: reduce bundle size of bundled website by compiling svg icons in\n  separated files\n- 283320f: enable page reload of catch-all routes `app/[[...slug]].jsx` on\n  content change\n- 283320f: remove false positive warnings on projects without `content/`\n  directory\n\n  ```\n  ⚠ Compiled with warnings\n\n  ../packages/nextra/dist/client/pages.js\n  Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client'\n  ```\n\n- 283320f: - sync with nextra 3.0.15\n  - bump to Next 15\n  - remove importing of `style.css` in themes, you need to import now manually\n    by\n\n  ```js\n  import 'nextra-theme-docs/style.css' // for docs theme\n  import 'nextra-theme-blog/style.css' // for blog theme\n  ```\n\n- 283320f: add support for turbopack `next dev --turbopack`\n- 283320f: fix `colorSchema` for HEX format with 4 chars, e.g. `#111`\n- 283320f: fix external svg icon was added for span in `<Anchor>`\n- 283320f: make nextThemes optional prop, to avoid ts errors\n- 283320f: sync with nextra 3.0.10\n- 283320f: defer pagefind results update for prioritizing the user input state\n- 283320f: make Nextra works with `src/app` and `src/content` directories\n- 283320f: - fix missing tailwind class for `json` icon in code blocks\n  - capitalize folders in sidebar even without index pages\n  - sync with nextra 3.2.4\n- 283320f: add ↗ char for external links\n- 283320f: sync with nextra 3.0.3\n- 283320f: fix injecting mdx-components into headings and injecting into toc\n- 283320f: - add `disabled` prop for `<Folder>` component when `open` prop was\n  set (to disable click event and remove `cursor: pointer`)\n  - allow `<h5>` and `<h6>` tags be used with `<Steps>`\n  - fix Webpack module rebuild for pageMap when new files where added or removed\n    in `app` dir or `content` dir\n- 283320f: Use `primaryColor` for `::selection` styles\n- 283320f: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean`\n- 283320f: support `GitHub Alert Syntax`\n- 283320f: fix search, didn't work with Next.js' `basePath` set\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [fdd2c6a]\n- Updated dependencies [283320f]\n- Updated dependencies [aca79fa]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [e11dbe0]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n  - nextra@4.0.0\n\n## 4.0.0-rc.0\n\n### Major Changes\n\n- 28796b4: release Nextra rc.0\n\n### Patch Changes\n\n- Updated dependencies [28796b4]\n  - nextra@4.0.0-rc.0\n\n## 4.0.0-app-router.43\n\n### Patch Changes\n\n- 50c2f76: fix `colorSchema` for HEX format with 4 chars, e.g. `#111`\n- 50c2f76: make nextThemes optional prop, to avoid ts errors\n- Updated dependencies [50c2f76]\n- Updated dependencies [50c2f76]\n  - nextra@4.0.0-app-router.43\n\n## 4.0.0-app-router.42\n\n### Patch Changes\n\n- 242e0d0: search tweaks\n- 3fc12a0: - Use Tailwind CSS CLI because CSS processing by `tsup` produce\n  different, weird and broken result\n  - Patch react-compiler with some fixes which isn't fixed\n- Updated dependencies [242e0d0]\n- Updated dependencies [3fc12a0]\n  - nextra@4.0.0-app-router.42\n\n## 4.0.0-app-router.41\n\n### Patch Changes\n\n- nextra@4.0.0-app-router.41\n\n## 4.0.0-app-router.40\n\n### Patch Changes\n\n- Updated dependencies [88135ec]\n  - nextra@4.0.0-app-router.40\n\n## 4.0.0-app-router.39\n\n### Patch Changes\n\n- Updated dependencies [711dbe7]\n  - nextra@4.0.0-app-router.39\n\n## 4.0.0-app-router.38\n\n### Patch Changes\n\n- Updated dependencies [42eb445]\n  - nextra@4.0.0-app-router.38\n\n## 4.0.0-app-router.37\n\n### Patch Changes\n\n- Updated dependencies [ad80ee1]\n  - nextra@4.0.0-app-router.37\n\n## 4.0.0-app-router.36\n\n### Patch Changes\n\n- Updated dependencies [739e9eb]\n- Updated dependencies [d805f2a]\n- Updated dependencies [0ab4ff1]\n  - nextra@4.0.0-app-router.36\n\n## 4.0.0-app-router.35\n\n### Patch Changes\n\n- Updated dependencies [96fb083]\n  - nextra@4.0.0-app-router.35\n\n## 4.0.0-app-router.34\n\n### Patch Changes\n\n- nextra@4.0.0-app-router.34\n\n## 4.0.0-app-router.33\n\n### Patch Changes\n\n- Updated dependencies [dd2e216]\n  - nextra@4.0.0-app-router.33\n\n## 4.0.0-app-router.32\n\n### Patch Changes\n\n- fbeef15: setup `@typescript-eslint/no-unnecessary-condition` rule and fix\n  warnings\n- Updated dependencies [fbeef15]\n  - nextra@4.0.0-app-router.32\n\n## 4.0.0-app-router.31\n\n### Patch Changes\n\n- Updated dependencies [386b620]\n  - nextra@4.0.0-app-router.31\n\n## 4.0.0-app-router.30\n\n### Major Changes\n\n- 39bacdc: remove `BlogMetadata.draft`, support \\_meta files for\n  `nextra-theme-blog`\n\n### Patch Changes\n\n- f277a7a: fix search, didn't work with Next.js' `basePath` set\n- Updated dependencies [f277a7a]\n  - nextra@4.0.0-app-router.30\n\n## 4.0.0-app-router.29\n\n### Major Changes\n\n- 4bdf82d: - migrate to tailwind css v4.beta2\n  - refactor builtin CSS classes from `_` prefix to `x:` prefix\n  - remove `color-primary-750` theme color variant\n\n### Patch Changes\n\n- Updated dependencies [4bdf82d]\n  - nextra@4.0.0-app-router.29\n\n## 4.0.0-app-router.28\n\n### Patch Changes\n\n- 846552e: - fix missing tailwind class for `json` icon in code blocks\n  - capitalize folders in sidebar even without index pages\n  - sync with nextra 3.2.4\n- Updated dependencies [846552e]\n  - nextra@4.0.0-app-router.28\n\n## 4.0.0-app-router.27\n\n### Major Changes\n\n- 8a0ae0f: - add root `_meta.global.{js,jsx,ts,tsx}` file\n  > See\n  > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts)\n  > based on https://nextra.site website\n  - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2\n    `lang?: string, route?: string = '/'`\n  - remove `createCatchAllMeta` from `nextra/catch-all`\n  - remove `collectCatchAllRoutes`\n  - remove `normalizePageRoute`\n  - add `mergeMetaWithPageMap` to `nextra/page-map`\n  - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime`\n    in remark plugin\n  - refactor recma rewrite plugin and add tests\n    - remove `recmaRewriteJsx`\n    - remove `recmaRewriteFunctionBody`\n  - make `convertPageMapToJs` sync\n\n### Patch Changes\n\n- 5e06f57: fix injecting mdx-components into headings and injecting into toc\n- Updated dependencies [8a0ae0f]\n- Updated dependencies [5e06f57]\n  - nextra@4.0.0-app-router.27\n\n## 4.0.0-app-router.26\n\n### Minor Changes\n\n- 0076bad: move TOC logic from `recma-rewrite-jsx` plugin to\n  `rehype-extract-toc-content` plugin\n\n### Patch Changes\n\n- be82724: Fixes when Turbopack is enabled:\n  `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'`\n- Updated dependencies [be82724]\n- Updated dependencies [0076bad]\n  - nextra@4.0.0-app-router.26\n\n## 4.0.0-app-router.25\n\n### Major Changes\n\n- c095f98: make `compileMdx` from `nextra/compile` return a `string` instead of\n  an `object`\n- 79bbab7: remove `export const title` from generated mdx pages\n- 33ee518: replace `export const useTOC = () = [/* your headings */]` by\n  `export const toc = [/* your headings */]`\n\n### Patch Changes\n\n- 3edc6d7: use `Date.now()` for last edit time on development and git last\n  commit time on production\n- fdbae45: initialize `transformerTwoslash` only 1 time outside of loader\n- Updated dependencies [c095f98]\n- Updated dependencies [79bbab7]\n- Updated dependencies [3edc6d7]\n- Updated dependencies [fdbae45]\n- Updated dependencies [33ee518]\n  - nextra@4.0.0-app-router.25\n\n## 4.0.0-app-router.24\n\n### Patch Changes\n\n- e46dbdf: Cache the result of `repository.getFileLatestModifiedDateAsync`\n  because it can slow down Fast Refresh for uncommitted files.\n- Updated dependencies [e46dbdf]\n  - nextra@4.0.0-app-router.24\n\n## 4.0.0-app-router.23\n\n### Patch Changes\n\n- b2e44d3: make Nextra works with `src/app` and `src/content` directories\n- Updated dependencies [b2e44d3]\n  - nextra@4.0.0-app-router.23\n\n## 4.0.0-app-router.22\n\n### Patch Changes\n\n- 5f79b77: fix unable to select text and `::selection` style\n- 57fde3f: reduce bundle size of bundled website by compiling svg icons in\n  separated files\n- Updated dependencies [5f79b77]\n- Updated dependencies [57fde3f]\n  - nextra@4.0.0-app-router.22\n\n## 4.0.0-app-router.21\n\n### Major Changes\n\n- 730899e: - add `nextra/components` to `experimental.optimizePackageImports` to\n  optimize `nextra/components` by default\n  - remove `<RemoteContent>` from `nextra/components`\n  - rename `<RemoteContent>` to `MDXRemote` and move to `nextra/mdx-remote`\n\n### Patch Changes\n\n- 0d74f68: fix external svg icon was added for span in `<Anchor>`\n- Updated dependencies [4e02ef3]\n- Updated dependencies [0d74f68]\n- Updated dependencies [730899e]\n  - nextra@4.0.0-app-router.21\n\n## 4.0.0-app-router.20\n\n### Major Changes\n\n- 16816f2: remove `<Th>`, `<Tr>` and `<Td>` exports (since they should be always\n  used with `<Table>` component)\n\n  ```diff\n  - import { Table, Th, Tr, Td } from 'nextra/components'\n  + import { Table } from 'nextra/components'\n\n  // ...\n\n  - <Th>\n  + <Table.Th>\n  - <Tr>\n  + <Table.Tr>\n  - <Td>\n  + <Table.Td>\n  ```\n\n- 0a63ba3: improve performance on projects without Turbopack enabled\n\n### Patch Changes\n\n- 7cc8ca1: simplify `generatePageMap`\n- 16816f2: remove false positive warnings on projects without `content/`\n  directory\n\n  ```\n  ⚠ Compiled with warnings\n\n  ../packages/nextra/dist/client/pages.js\n  Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client'\n  ```\n\n- Updated dependencies [3d8705c]\n- Updated dependencies [16816f2]\n- Updated dependencies [27454c4]\n- Updated dependencies [7cc8ca1]\n- Updated dependencies [aa94d91]\n- Updated dependencies [0a63ba3]\n- Updated dependencies [71a051b]\n- Updated dependencies [0a63ba3]\n- Updated dependencies [16816f2]\n- Updated dependencies [b873702]\n  - nextra@4.0.0-app-router.20\n\n## 4.0.0-app-router.19\n\n### Patch Changes\n\n- Updated dependencies [a3627e5]\n  - nextra@4.0.0-app-router.19\n\n## 4.0.0-app-router.18\n\n### Minor Changes\n\n- 439466a: replace `useContentDir` with `contentDirBasePath` option which\n  configure `content` directory under a catch-all subdirectory\n- b00a560: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and\n  also `content` folder files - all add to `pageMap`, but ignore dynamic pages\n  `[[`\n\n### Patch Changes\n\n- a074a99: add `whiteListTagsStyling` nextra config option\n- Updated dependencies [a074a99]\n- Updated dependencies [439466a]\n- Updated dependencies [b00a560]\n  - nextra@4.0.0-app-router.18\n\n## 4.0.0-app-router.17\n\n### Patch Changes\n\n- Updated dependencies [33568c1]\n  - nextra@4.0.0-app-router.17\n\n## 4.0.0-app-router.16\n\n### Major Changes\n\n- 5385fd4: remove `nextra-theme-blog/cusdis` export, export `<Comments>`\n  component from `nextra-theme-blog` directly (because `peerDependency` of\n  `react-cusdis` was removed)\n\n### Minor Changes\n\n- ab21db7: - use ReactIcon for code blocks with `jsx`, `tsx` language\n  - add JsonIcon for `json` language\n  - parse language from filename if exist when `diff` language is specified\n  - use JavaScript icon for `cjs` and `mjs`\n  - use TypeScript icon for `cts` and `mts`\n\n### Patch Changes\n\n- 0540e6c: - add `disabled` prop for `<Folder>` component when `open` prop was\n  set (to disable click event and remove `cursor: pointer`)\n  - allow `<h5>` and `<h6>` tags be used with `<Steps>`\n  - fix Webpack module rebuild for pageMap when new files where added or removed\n    in `app` dir or `content` dir\n- Updated dependencies [ab21db7]\n- Updated dependencies [0540e6c]\n- Updated dependencies [5b47509]\n  - nextra@4.0.0-app-router.16\n\n## 4.0.0-app-router.15\n\n### Patch Changes\n\n- nextra@4.0.0-app-router.15\n\n## 4.0.0-app-router.14\n\n### Major Changes\n\n- be19dd4: remove `\"typesVersions\"` field from `package.json`. You need to set\n  `\"moduleResolution\": \"bundler\"` in your `tsconfig.json` if you are using\n  TypeScript\n\n### Patch Changes\n\n- Updated dependencies [be19dd4]\n  - nextra@4.0.0-app-router.14\n\n## 4.0.0-app-router.13\n\n### Major Changes\n\n- 54657e2: require Next.js minimum v15\n\n### Patch Changes\n\n- 07213e2: add `banner` prop for `<Layout>` component\n- 07213e2: add support for turbopack `next dev --turbopack`\n- Updated dependencies [3ade013]\n- Updated dependencies [ddc39cc]\n- Updated dependencies [07213e2]\n- Updated dependencies [54657e2]\n  - nextra@4.0.0-app-router.13\n\n## 4.0.0-app-router.12\n\n### Patch Changes\n\n- b8defc9: sync with nextra 3.1.0\n- Updated dependencies [b8defc9]\n- Updated dependencies [b8defc9]\n  - nextra@4.0.0-app-router.12\n\n## 4.0.0-app-router.11\n\n### Patch Changes\n\n- be15165: move `pagefind` output to `public/_pagefind` directory\n  https://github.com/shuding/nextra/pull/3517\n- Updated dependencies [be15165]\n  - nextra@4.0.0-app-router.11\n\n## 4.0.0-app-router.10\n\n### Patch Changes\n\n- 8b1a7c9: defer pagefind results update for prioritizing the user input state\n- Updated dependencies [8b1a7c9]\n  - nextra@4.0.0-app-router.10\n\n## 4.0.0-app-router.9\n\n### Patch Changes\n\n- 2c8a8ab: - sync with nextra 3.0.15\n  - bump to Next 15\n  - remove importing of `style.css` in themes, you need to import now manually\n    by\n\n  ```js\n  import 'nextra-theme-docs/style.css' // for docs theme\n  import 'nextra-theme-blog/style.css' // for blog theme\n  ```\n\n- Updated dependencies [2c8a8ab]\n  - nextra@4.0.0-app-router.9\n\n## 4.0.0-app-router.8\n\n### Patch Changes\n\n- 875842b: remove `react-cusdis` dependency, use\n  https://cusdis.com/doc#/advanced/sdk directly\n- 9832af9: add ↗ char for external links\n- ec39959: Use `primaryColor` for `::selection` styles\n- 875842b: support `GitHub Alert Syntax`\n- Updated dependencies [9832af9]\n- Updated dependencies [ec39959]\n- Updated dependencies [875842b]\n  - nextra@4.0.0-app-router.8\n\n## 4.0.0-app-router.7\n\n### Patch Changes\n\n- 5201e5f: add helpful error message about not available search on development\n  mode\n- 3ac2c32: add `getPageMap` helper function from `nextra/page-map`\n- b4ca36d: - allow override/add additional icons for code blocks\n  - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of\n    `mdx-components` file\n- 4768dee: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean`\n- Updated dependencies [5201e5f]\n- Updated dependencies [3ac2c32]\n- Updated dependencies [b4ca36d]\n- Updated dependencies [4768dee]\n  - nextra@4.0.0-app-router.7\n\n## 4.0.0-app-router.6\n\n### Patch Changes\n\n- 2092d5e: enable page reload of catch-all routes `app/[[...slug]].jsx` on\n  content change\n- a97e5cf: sync with nextra 3.0.10\n- Updated dependencies [2092d5e]\n- Updated dependencies [a97e5cf]\n  - nextra@4.0.0-app-router.6\n\n## 4.0.0-app-router.5\n\n### Patch Changes\n\n- a15a02d: sync with nextra 3.0.3\n- Updated dependencies [659b36e]\n- Updated dependencies [a15a02d]\n  - nextra@4.0.0-app-router.5\n\n## 4.0.0-app-router.4\n\n### Patch Changes\n\n- nextra@4.0.0-app-router.4\n\n## 4.0.0-app-router.3\n\n### Major Changes\n\n- 1e77fab: move `<Collapse>`, `<Details>`, `<Summary>`, `<SkipNavContent>`,\n  `SkipNavLink`, `<Select>` and `<Bleed>` from `nextra-theme-docs` to\n  `nextra/components`\n\n### Minor Changes\n\n- 1e77fab: use `next-view-transitions` for transition in `nextra-theme-blog`\n\n### Patch Changes\n\n- 1e77fab: fix edit on github and last updated at for catch all routes\n- Updated dependencies [1e77fab]\n- Updated dependencies [1e77fab]\n- Updated dependencies [1e77fab]\n- Updated dependencies [1e77fab]\n  - nextra@4.0.0-app-router.3\n\n## 4.0.0-app-router.2\n\n### Major Changes\n\n- 8ef0f58: move `<Head>` component in `nextra/components`\n\n### Minor Changes\n\n- 8ef0f58: add `nextThemes` prop in `<Layout>` component\n\n### Patch Changes\n\n- Updated dependencies [215aa08]\n- Updated dependencies [8ef0f58]\n  - nextra@4.0.0-app-router.2\n\n## 4.0.0-app-router.1\n\n### Major Changes\n\n- 26851b5: migrate search from Flexsearch to Pagefind\n\n### Patch Changes\n\n- Updated dependencies [26851b5]\n  - nextra@4.0.0-app-router.1\n\n## 4.0.0-app-router.0\n\n### Major Changes\n\n- 99f34d3: The initial version which supports App Router instead of Pages\n  Router, something may be broken, check\n  https://github.com/shuding/nextra/tree/v4-v2/examples for the migration guide\n\n### Patch Changes\n\n- Updated dependencies [99f34d3]\n  - nextra@4.0.0-app-router.0\n\n## 3.3.1\n\n### Patch Changes\n\n- bfa61d9: add `text-overflow: ellipsis` for `<Cards.Card>` component\n- Updated dependencies [bfa61d9]\n  - nextra@3.3.1\n\n## 3.3.0\n\n### Minor Changes\n\n- ee69234: add\n  [image zoom feature](http://nextra.site/docs/guide/image#image-zoom) for all\n  images written via [GFM syntax](https://github.github.com/gfm/#images) in\n  md/mdx files (except images inside links)\n\n### Patch Changes\n\n- Updated dependencies [ee69234]\n  - nextra@3.3.0\n\n## 3.2.5\n\n### Patch Changes\n\n- Updated dependencies [2f5d954]\n  - nextra@3.2.5\n\n## 3.2.4\n\n### Patch Changes\n\n- Updated dependencies [a4b0bbb]\n  - nextra@3.2.4\n\n## 3.2.3\n\n### Patch Changes\n\n- Updated dependencies [50f33f3]\n  - nextra@3.2.3\n\n## 3.2.2\n\n### Patch Changes\n\n- Updated dependencies [45cccd4]\n  - nextra@3.2.2\n\n## 3.2.1\n\n### Patch Changes\n\n- nextra@3.2.1\n\n## 3.2.0\n\n### Patch Changes\n\n- nextra@3.2.0\n\n## 3.1.3\n\n### Patch Changes\n\n- 6e64b16: fix\n  `Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \"exports\" main defined in /path/to/project/node_modules/nextra/package.json`\n  when using `next.config.ts`\n- d44c4bc: requires to have a custom App component (`pages/_app.jsx`)\n- Updated dependencies [6e64b16]\n- Updated dependencies [d44c4bc]\n- Updated dependencies [24f9806]\n  - nextra@3.1.3\n\n## 3.1.2\n\n### Patch Changes\n\n- Updated dependencies [9c78588]\n  - nextra@3.1.2\n\n## 3.1.1\n\n### Patch Changes\n\n- 68633e5: fix: Improve Twoslash Popover Display\n- Updated dependencies [68633e5]\n  - nextra@3.1.1\n\n## 3.1.0\n\n### Patch Changes\n\n- Updated dependencies [035fe48]\n- Updated dependencies [8e9767e]\n- Updated dependencies [fec399a]\n- Updated dependencies [c002118]\n  - nextra@3.1.0\n\n## 3.1.0-canary.1\n\n### Patch Changes\n\n- Updated dependencies [035fe48]\n- Updated dependencies [8e9767e]\n- Updated dependencies [c002118]\n  - nextra@3.1.0-canary.1\n\n## 3.1.0-canary.0\n\n### Patch Changes\n\n- Updated dependencies [fec399a]\n  - nextra@3.1.0-canary.0\n\n## 3.0.15\n\n### Patch Changes\n\n- Updated dependencies [bd498c6]\n  - nextra@3.0.15\n\n## 3.0.14\n\n### Patch Changes\n\n- Updated dependencies [6454938]\n- Updated dependencies [9794e9e]\n- Updated dependencies [9794e9e]\n  - nextra@3.0.14\n\n## 3.0.13\n\n### Patch Changes\n\n- nextra@3.0.13\n\n## 3.0.12\n\n### Patch Changes\n\n- Updated dependencies [7e0093f]\n  - nextra@3.0.12\n\n## 3.0.11\n\n### Patch Changes\n\n- Updated dependencies [e0a9303]\n  - nextra@3.0.11\n\n## 3.0.10\n\n### Patch Changes\n\n- Updated dependencies [31de764]\n- Updated dependencies [161d350]\n  - nextra@3.0.10\n\n## 3.0.9\n\n### Patch Changes\n\n- Updated dependencies [f9cc160]\n  - nextra@3.0.9\n\n## 3.0.8\n\n### Patch Changes\n\n- nextra@3.0.8\n\n## 3.0.7\n\n### Patch Changes\n\n- Updated dependencies [4bbc1fe]\n  - nextra@3.0.7\n\n## 3.0.6\n\n### Patch Changes\n\n- nextra@3.0.6\n\n## 3.0.5\n\n### Patch Changes\n\n- nextra@3.0.5\n\n## 3.0.4\n\n### Patch Changes\n\n- 9b6595d: Ensure the jump link behavior is consistent in Markdown.\n- Updated dependencies [84a8a41]\n- Updated dependencies [659b36e]\n- Updated dependencies [84fc255]\n  - nextra@3.0.4\n\n## 3.0.3\n\n### Patch Changes\n\n- 9d93caf: RTL support for the `<Steps>` component.\n- 5fbce2f: Added golang logo for code blocks.\n- Updated dependencies [82fc267]\n- Updated dependencies [edc6c29]\n- Updated dependencies [9d93caf]\n- Updated dependencies [5fbce2f]\n  - nextra@3.0.3\n\n## 3.0.2\n\n### Patch Changes\n\n- Updated dependencies [b6341f7]\n  - nextra@3.0.2\n\n## 3.0.1\n\n### Patch Changes\n\n- nextra@3.0.1\n\n## 3.0.0\n\n### Major Changes\n\n- c2ad837: update to MDX3\n- 16ab7f7: - remove `legacyBehavior` from `NextLink`\n  - remove `config.cusdis`. Instead, now you need to pass cusdis options as\n    props in `Cusdis` component\n\n- 148278c: rename tailwind prefix `nx-` to `_` to reduce bundle size\n- 919fe97: set `\"peerDependencies.next\": \">=13\"`\n- ba30c6c: use render props for className with `selected`, `disabled` and\n  `hover` state for `<Tab>`\n- d7d8a3e: new styles for code blocks aka in next.js\n- 2872606: remove `image` prop from `<Card>` component, image will be showed\n  based on truthiness `children` prop now\n\n  set `icon` as optional prop\n\n- 128e195: fix React warning, remove PageOpts.toc, use `toc` prop from\n  `components.wrapper`\n- 191e6c4: - use `shikiji` instead of `shiki`\n  - rename `useSSG` to `useData`\n\n- c7f03e5: rename `pageOpts.headings` to `toc`\n\n### Minor Changes\n\n- 6ec3241: Add Terraform/Move icon https://github.com/shuding/nextra/pull/2811\n  https://github.com/shuding/nextra/pull/2808\n- 5a63701: add icons for following languages:\n  - GraphQL (`graphql`)\n  - C++ (`c++`, `cpp`)\n  - C# (`csharp`, `c#`, `cs`)\n  - Python (`python`, `py`)\n\n  allow disallow mobile word wrap button in code blocks with `word-wrap=false`\n  meta data setting\n\n- 6ec3241: Make the `<Tab>` component be crawlable and indexable by search\n  engines by default\n- 3043826: add shikiji twoslash\n\n  Demo feature:\n  https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support\n\n- 440ff42: add MathJax support\n\n### Patch Changes\n\n- 73239c4: To ensure consistent horizontal padding, set the default language as\n  plaintext for code blocks. This prevents any loss of formatting for code\n  blocks without a specified language.\n- 2a3e3e7: Fix first list item in `<FileTree>` not within permitted parent\n  elements\n- cb24790: fix broken `export default` statement in mdx files\n- 7e57ddb: Avoid skipping the heading level in the posts layout, removes\n  `.post-item` and `.post-item-more` classes\n- a8c2196: use dynamic import for loading `mermaid`\n- 0b5cc9d: make nextra compatible with windows\n- 1a634cd: remove explicit `ZodError` assertion\n- ad108ff: use `overflow-x-auto` instead `overflow-x-scroll` for `<Table>`\n- 4f0f6b2: Omit `...{:type}` inline code annotations from search index #2922\n- 150184b: attach heading anchor `id` attribute to heading (like Pagefind do)\n  and fix heading anchor styles when `theme.typesetting: 'article'` is set\n- 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to\n  improve type inference.\n- 9f55bd1: update rehype-pretty-code/shikiji to latest\n- a90b90f: Switch to the dark theme provided by `@tailwindcss/typography` in\n  theme-blog.\n- 49a9627: fix theme-blog heading styles in post layout\n- 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts`\n- 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `<Ident>` and svg\n  icons in `<Folder>` and `<File>`\n- 237c345: Make React 18 as minimal requirement\n- a95e745: Fix the line highlighting background-color does not extend to the\n  full width of the code block when a scrollbar appears with line numbers.\n- Updated dependencies [e7e8e84]\n- Updated dependencies [7188278]\n- Updated dependencies [d1e3e9a]\n- Updated dependencies [73239c4]\n- Updated dependencies [2b9b95b]\n- Updated dependencies [023d37b]\n- Updated dependencies [0fe55db]\n- Updated dependencies [50a52fd]\n- Updated dependencies [c2ad837]\n- Updated dependencies [2a3e3e7]\n- Updated dependencies [a3b67ae]\n- Updated dependencies [1a36469]\n- Updated dependencies [799174f]\n- Updated dependencies [98f439c]\n- Updated dependencies [6ec3241]\n- Updated dependencies [148278c]\n- Updated dependencies [c7f03e5]\n- Updated dependencies [3644e1c]\n- Updated dependencies [919fe97]\n- Updated dependencies [cb24790]\n- Updated dependencies [47b125d]\n- Updated dependencies [982862f]\n- Updated dependencies [a8c2196]\n- Updated dependencies [ba30c6c]\n- Updated dependencies [0b5cc9d]\n- Updated dependencies [5a63701]\n- Updated dependencies [60ec68c]\n- Updated dependencies [d7d8a3e]\n- Updated dependencies [fe5061b]\n- Updated dependencies [2872606]\n- Updated dependencies [a52a869]\n- Updated dependencies [6ec3241]\n- Updated dependencies [1a634cd]\n- Updated dependencies [63ca28b]\n- Updated dependencies [ad108ff]\n- Updated dependencies [ad4823d]\n- Updated dependencies [4f0f6b2]\n- Updated dependencies [1f3e7cd]\n- Updated dependencies [ab07609]\n- Updated dependencies [2f3be33]\n- Updated dependencies [90c129e]\n- Updated dependencies [f71e660]\n- Updated dependencies [150184b]\n- Updated dependencies [66cce1d]\n- Updated dependencies [c74ae90]\n- Updated dependencies [7615b62]\n- Updated dependencies [6070b02]\n- Updated dependencies [7bb18e3]\n- Updated dependencies [b9f88e3]\n- Updated dependencies [8efbb45]\n- Updated dependencies [6f4c83a]\n- Updated dependencies [d8a406b]\n- Updated dependencies [9f55bd1]\n- Updated dependencies [4e55c06]\n- Updated dependencies [128e195]\n- Updated dependencies [8bce16d]\n- Updated dependencies [ccaf3d4]\n- Updated dependencies [3043826]\n- Updated dependencies [2630461]\n- Updated dependencies [576cb6f]\n- Updated dependencies [217f708]\n- Updated dependencies [57bc0e2]\n- Updated dependencies [ca51306]\n- Updated dependencies [f662237]\n- Updated dependencies [3c6193d]\n- Updated dependencies [1f3e7cd]\n- Updated dependencies [198dbcc]\n- Updated dependencies [363b85f]\n- Updated dependencies [fef635e]\n- Updated dependencies [6070b02]\n- Updated dependencies [237c345]\n- Updated dependencies [191e6c4]\n- Updated dependencies [440ff42]\n- Updated dependencies [7faa096]\n- Updated dependencies [9099c35]\n- Updated dependencies [98f439c]\n- Updated dependencies [a95e745]\n- Updated dependencies [80e11e0]\n- Updated dependencies [c7f03e5]\n  - nextra@3.0.0\n\n## 3.0.0-alpha.42\n\n### Patch Changes\n\n- Updated dependencies [ca51306]\n  - nextra@3.0.0-alpha.42\n\n## 3.0.0-alpha.41\n\n### Patch Changes\n\n- 237c345: Make React 18 as minimal requirement\n- Updated dependencies [237c345]\n  - nextra@3.0.0-alpha.41\n\n## 3.0.0-alpha.40\n\n### Patch Changes\n\n- Updated dependencies [982862f]\n  - nextra@3.0.0-alpha.40\n\n## 3.0.0-alpha.39\n\n### Major Changes\n\n- ba30c6c: use render props for className with `selected`, `disabled` and\n  `hover` state for `<Tab>`\n- 2872606: remove `image` prop from `<Card>` component, image will be showed\n  based on truthiness `children` prop now\n\n  set `icon` as optional prop\n\n### Patch Changes\n\n- Updated dependencies [47b125d]\n- Updated dependencies [ba30c6c]\n- Updated dependencies [2872606]\n  - nextra@3.0.0-alpha.39\n\n## 3.0.0-alpha.38\n\n### Patch Changes\n\n- Updated dependencies [ccaf3d4]\n  - nextra@3.0.0-alpha.38\n\n## 3.0.0-alpha.37\n\n### Patch Changes\n\n- 2a3e3e7: Fix first list item in `<FileTree>` not within permitted parent\n  elements\n- Updated dependencies [2a3e3e7]\n  - nextra@3.0.0-alpha.37\n\n## 3.0.0-alpha.36\n\n### Patch Changes\n\n- Updated dependencies [2b9b95b]\n  - nextra@3.0.0-alpha.36\n\n## 3.0.0-alpha.35\n\n### Patch Changes\n\n- Updated dependencies [f662237]\n  - nextra@3.0.0-alpha.35\n\n## 3.0.0-alpha.34\n\n### Patch Changes\n\n- 1a634cd: remove explicit `ZodError` assertion\n- Updated dependencies [1a634cd]\n  - nextra@3.0.0-alpha.34\n\n## 3.0.0-alpha.33\n\n### Patch Changes\n\n- 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to\n  improve type inference.\n- Updated dependencies [7bb18e3]\n  - nextra@3.0.0-alpha.33\n\n## 3.0.0-alpha.32\n\n### Patch Changes\n\n- 73239c4: To ensure consistent horizontal padding, set the default language as\n  plaintext for code blocks. This prevents any loss of formatting for code\n  blocks without a specified language.\n- 7e57ddb: Avoid skipping the heading level in the posts layout, removes\n  `.post-item` and `.post-item-more` classes\n- 150184b: attach heading anchor `id` attribute to heading (like Pagefind do)\n  and fix heading anchor styles when `theme.typesetting: 'article'` is set\n- a90b90f: Switch to the dark theme provided by `@tailwindcss/typography` in\n  theme-blog.\n- 49a9627: fix theme-blog heading styles in post layout\n- 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts`\n- Updated dependencies [73239c4]\n- Updated dependencies [799174f]\n- Updated dependencies [150184b]\n- Updated dependencies [3c6193d]\n  - nextra@3.0.0-alpha.32\n\n## 3.0.0-alpha.31\n\n### Patch Changes\n\n- Updated dependencies [d1e3e9a]\n  - nextra@3.0.0-alpha.31\n\n## 3.0.0-alpha.30\n\n### Patch Changes\n\n- Updated dependencies [7615b62]\n  - nextra@3.0.0-alpha.30\n\n## 3.0.0-alpha.29\n\n### Patch Changes\n\n- Updated dependencies [fef635e]\n  - nextra@3.0.0-alpha.29\n\n## 3.0.0-alpha.28\n\n### Patch Changes\n\n- a8c2196: use dynamic import for loading `mermaid`\n- 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `<Ident />` and svg\n  icons in `<Folder />` and `<File />`\n- Updated dependencies [a8c2196]\n- Updated dependencies [363b85f]\n  - nextra@3.0.0-alpha.28\n\n## 3.0.0-alpha.27\n\n### Patch Changes\n\n- 4f0f6b27: Omit `...{:type}` inline code annotations from search index #2922\n- a95e7454: Fix the line highlighting background-color does not extend to the\n  full width of the code block when a scrollbar appears with line numbers.\n- Updated dependencies [4f0f6b27]\n- Updated dependencies [a95e7454]\n  - nextra@3.0.0-alpha.27\n\n## 3.0.0-alpha.26\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.26\n\n## 3.0.0-alpha.25\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.25\n\n## 3.0.0-alpha.24\n\n### Patch Changes\n\n- Updated dependencies [6f4c83a8]\n  - nextra@3.0.0-alpha.24\n\n## 3.0.0-alpha.23\n\n### Minor Changes\n\n- 6ec3241c: Add Terraform/Move icon https://github.com/shuding/nextra/pull/2811\n  https://github.com/shuding/nextra/pull/2808\n- 6ec3241c: Make the `<Tab />` component be crawlable and indexable by search\n  engines by default\n\n### Patch Changes\n\n- ad108ff7: use `overflow-x-auto` instead `overflow-x-scroll` for `<Table />`\n- Updated dependencies [6ec3241c]\n- Updated dependencies [6ec3241c]\n- Updated dependencies [ad108ff7]\n- Updated dependencies [217f7082]\n  - nextra@3.0.0-alpha.23\n\n## 3.0.0-alpha.22\n\n### Patch Changes\n\n- Updated dependencies [2630461c]\n  - nextra@3.0.0-alpha.22\n\n## 3.0.0-alpha.21\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.21\n\n## 3.0.0-alpha.20\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.20\n\n## 3.0.0-alpha.19\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.19\n\n## 3.0.0-alpha.18\n\n### Patch Changes\n\n- Updated dependencies [98f439ca]\n- Updated dependencies [f71e660e]\n- Updated dependencies [98f439ca]\n  - nextra@3.0.0-alpha.18\n\n## 3.0.0-alpha.17\n\n### Minor Changes\n\n- 30438264: add shikiji twoslash\n\n  Demo feature:\n  https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support\n\n### Patch Changes\n\n- 9f55bd1f: update rehype-pretty-code/shikiji to latest\n- Updated dependencies [9f55bd1f]\n- Updated dependencies [30438264]\n  - nextra@3.0.0-alpha.17\n\n## 3.0.0-alpha.16\n\n### Minor Changes\n\n- 5a637010: add icons for following languages:\n  - GraphQL (`graphql`)\n  - C++ (`c++`, `cpp`)\n  - C# (`csharp`, `c#`, `cs`)\n  - Python (`python`, `py`)\n\n  allow disallow mobile word wrap button in code blocks with `word-wrap=false`\n  meta data setting\n\n### Patch Changes\n\n- Updated dependencies [5a637010]\n- Updated dependencies [90c129e6]\n  - nextra@3.0.0-alpha.16\n\n## 3.0.0-alpha.15\n\n### Patch Changes\n\n- Updated dependencies [1a364694]\n  - nextra@3.0.0-alpha.15\n\n## 3.0.0-alpha.14\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.14\n\n## 3.0.0-alpha.13\n\n### Patch Changes\n\n- Updated dependencies [60ec68c4]\n- Updated dependencies [c74ae90a]\n- Updated dependencies [6070b025]\n- Updated dependencies [8bce16d3]\n- Updated dependencies [6070b025]\n  - nextra@3.0.0-alpha.13\n\n## 3.0.0-alpha.12\n\n### Patch Changes\n\n- Updated dependencies [3644e1c2]\n- Updated dependencies [57bc0e2a]\n  - nextra@3.0.0-alpha.12\n\n## 3.0.0-alpha.11\n\n### Major Changes\n\n- c2ad837d: update to MDX3\n\n### Patch Changes\n\n- Updated dependencies [c2ad837d]\n  - nextra@3.0.0-alpha.11\n\n## 3.0.0-alpha.10\n\n### Patch Changes\n\n- Updated dependencies [9099c354]\n  - nextra@3.0.0-alpha.10\n\n## 3.0.0-alpha.9\n\n### Patch Changes\n\n- Updated dependencies [8efbb45c]\n- Updated dependencies [80e11e04]\n  - nextra@3.0.0-alpha.9\n\n## 3.0.0-alpha.8\n\n### Minor Changes\n\n- 440ff42d: add MathJax support\n\n### Patch Changes\n\n- Updated dependencies [440ff42d]\n  - nextra@3.0.0-alpha.8\n\n## 3.0.0-alpha.7\n\n### Patch Changes\n\n- 0b5cc9d5: make nextra compatible with windows\n- Updated dependencies [0b5cc9d5]\n  - nextra@3.0.0-alpha.7\n\n## 3.0.0-alpha.6\n\n### Patch Changes\n\n- Updated dependencies [03da778a]\n  - nextra@3.0.0-alpha.6\n\n## 3.0.0-alpha.5\n\n### Patch Changes\n\n- Updated dependencies [a3b67aea]\n  - nextra@3.0.0-alpha.5\n\n## 3.0.0-alpha.4\n\n### Patch Changes\n\n- Updated dependencies [7faa0968]\n  - nextra@3.0.0-alpha.4\n\n## 3.0.0-alpha.3\n\n### Patch Changes\n\n- Updated dependencies [fe5061b7]\n  - nextra@3.0.0-alpha.3\n\n## 3.0.0-alpha.2\n\n### Patch Changes\n\n- cb247901: fix broken `export default` statement in mdx files\n- Updated dependencies [cb247901]\n  - nextra@3.0.0-alpha.2\n\n## 3.0.0-alpha.1\n\n### Major Changes\n\n- 148278ce: rename tailwind prefix `nx-` to `_` to reduce bundle size\n- d7d8a3eb: new styles for code blocks aka in next.js\n- 128e195f: fix React warning, remove PageOpts.toc, use `toc` prop from\n  `components.wrapper`\n- 191e6c41: - use `shikiji` instead of `shiki`\n  - rename `useSSG` to `useData`\n\n- c7f03e54: rename `pageOpts.headings` to `toc`\n\n### Patch Changes\n\n- Updated dependencies [e7e8e849]\n- Updated dependencies [71882780]\n- Updated dependencies [023d37b1]\n- Updated dependencies [148278ce]\n- Updated dependencies [c7f03e54]\n- Updated dependencies [d7d8a3eb]\n- Updated dependencies [a52a869e]\n- Updated dependencies [63ca28be]\n- Updated dependencies [1f3e7cd4]\n- Updated dependencies [b9f88e34]\n- Updated dependencies [4e55c064]\n- Updated dependencies [128e195f]\n- Updated dependencies [1f3e7cd4]\n- Updated dependencies [198dbcca]\n- Updated dependencies [191e6c41]\n- Updated dependencies [c7f03e54]\n  - nextra@3.0.0-alpha.1\n\n## 3.0.0-alpha.0\n\n### Major Changes\n\n- 16ab7f78: - remove `legacyBehavior` from `NextLink`\n  - remove `config.cusdis`. Instead, now you need to pass cusdis options as\n    props in `Cusdis` component\n\n- 919fe977: set `\"peerDependencies.next\": \">=13\"`\n\n### Patch Changes\n\n- Updated dependencies [0fe55db2]\n- Updated dependencies [50a52fd1]\n- Updated dependencies [919fe977]\n- Updated dependencies [ad4823d9]\n- Updated dependencies [ab07609c]\n- Updated dependencies [2f3be336]\n- Updated dependencies [66cce1d1]\n- Updated dependencies [d8a406b4]\n- Updated dependencies [576cb6f1]\n  - nextra@3.0.0-alpha.0\n\n## 2.13.4\n\n### Patch Changes\n\n- nextra@2.13.4\n\n## 2.13.3\n\n### Patch Changes\n\n- Updated dependencies [93b57052]\n  - nextra@2.13.3\n\n## 2.13.2\n\n### Patch Changes\n\n- ad7b31b0: downgrade remark-math from `6` to `5.1.1` to fix\n  `TypeError: Cannot read properties of undefined (reading 'mathFlowInside')`\n  error\n\n  fix support of ```math lang that was overridden by `rehype-pretty-code`\n\n- Updated dependencies [ad7b31b0]\n  - nextra@2.13.2\n\n## 2.13.1\n\n### Patch Changes\n\n- Updated dependencies [ee02a483]\n  - nextra@2.13.1\n\n## 2.13.0\n\n### Patch Changes\n\n- nextra@2.13.0\n\n## 2.12.3\n\n### Patch Changes\n\n- Updated dependencies [ffb6d808]\n  - nextra@2.12.3\n\n## 2.12.2\n\n### Patch Changes\n\n- Updated dependencies [7c8c4989]\n  - nextra@2.12.2\n\n## 2.12.1\n\n### Patch Changes\n\n- Updated dependencies [52ae8fc5]\n  - nextra@2.12.1\n\n## 2.12.0\n\n### Minor Changes\n\n- 8962597e: - allow override static image component that was hardcoded to\n  `import Image from 'next/image'` now it's plain `<img />`\n  - support `<details />`/`<summary />` for `.md` files\n\n### Patch Changes\n\n- Updated dependencies [d9820746]\n- Updated dependencies [fbf003cd]\n- Updated dependencies [8962597e]\n  - nextra@2.12.0\n\n## 2.11.1\n\n### Patch Changes\n\n- cf5f91ea: fix footnotes and backlink jump\n- 4dd720ad: remove `font-weight: 500;` from styles of code blocks since it gives\n  no effect\n- Updated dependencies [ddddce95]\n- Updated dependencies [6154e312]\n- Updated dependencies [46743ba4]\n- Updated dependencies [4dd720ad]\n  - nextra@2.11.1\n\n## 2.11.0\n\n### Minor Changes\n\n- 3bb480a4: support draft posts via frontMatter's `draft: true` value\n\n### Patch Changes\n\n- 3bb480a4: use github-slugger for custom heading ids to prevent duplicated\n  headings\n- 3bb480a4: fix code blocks `box-decoration-theme: clone` can create confusing\n  output over line breaks, use `slice` instead\n- Updated dependencies [3bb480a4]\n- Updated dependencies [3bb480a4]\n- Updated dependencies [3bb480a4]\n- Updated dependencies [3bb480a4]\n  - nextra@2.11.0\n\n## 2.10.0\n\n### Minor Changes\n\n- e54b008: - add `@theguild/remark-npm2yarn` package that replaces the code\n  block that has `npm2yarn` metadata with `<Tabs />` and `<Tab />` components\n  from `nextra/components`.\n  - `<Tabs />` now has `selectedKey` prop, the chosen tab is saved in the local\n    storage, which will be chosen in future page renders.\n\n  More info https://nextra.site/docs/guide/advanced/npm2yarn\n\n### Patch Changes\n\n- Updated dependencies [e54b008]\n  - nextra@2.10.0\n\n## 2.9.0\n\n### Minor Changes\n\n- 16bbb88: Move below packages to nextra package\n  - `<Cards />` and `<Card />`\n  - `<Tabs />` and `<Tab />`\n  - `<Steps />`\n  - `<FileTree />`\n\n  to import them you can use the following in your official `nextra-theme-blog`\n  and `nextra-theme-docs`\n\n  ```js\n  import { Card, Cards } from 'nextra/components'\n  ```\n\n  ```js\n  import { Tab, Tabs } from 'nextra/components'\n  ```\n\n  ```js\n  import { Steps } from 'nextra/components'\n  ```\n\n  ```js\n  import { FileTree } from 'nextra/components'\n  ```\n\n### Patch Changes\n\n- b1a7eba: `opens in new tab` span element should have `user-select: none`\n- Updated dependencies [16bbb88]\n- Updated dependencies [23a25b1]\n  - nextra@2.9.0\n\n## 2.8.0\n\n### Patch Changes\n\n- bef7324: accessibility issues for text and navbar in light mode\n- 6c12bf4: fix broken code format while selecting and copying code with\n  `showLineNumbers` option enabled\n- Updated dependencies [6c12bf4]\n  - nextra@2.8.0\n\n## 2.7.1\n\n### Patch Changes\n\n- Updated dependencies [0e53ca51]\n  - nextra@2.7.1\n\n## 2.7.0\n\n### Minor Changes\n\n- 44626e8f: support mermaid diagrams\n\n### Patch Changes\n\n- Updated dependencies [44626e8f]\n  - nextra@2.7.0\n\n## 2.6.2\n\n### Patch Changes\n\n- 9c9625ee: Fix search not working in certain Next.js versions\n- Updated dependencies [9c9625ee]\n  - nextra@2.6.2\n\n## 2.6.1\n\n### Patch Changes\n\n- Updated dependencies [1e9ebabc]\n  - nextra@2.6.1\n\n## 2.6.0\n\n### Patch Changes\n\n- 9d9bc23: accessibility issues for text and navbar in light mode\n- Updated dependencies [15c4092]\n- Updated dependencies [1c6256b]\n  - nextra@2.6.0\n\n## 2.5.2\n\n### Patch Changes\n\n- f85423a: Fix prose styles for small breakpoints\n- Updated dependencies [a3601e5]\n  - nextra@2.5.2\n\n## 2.5.1\n\n### Patch Changes\n\n- 8aae0c9: fix: cusdis comments theme doens't change when resolvedTheme changed\n- Updated dependencies [d408ab0]\n  - nextra@2.5.1\n\n## 2.5.0\n\n### Minor Changes\n\n- 08d393e: support ANSI highlighting\n\n### Patch Changes\n\n- Updated dependencies [08d393e]\n  - nextra@2.5.0\n\n## 2.4.2\n\n### Patch Changes\n\n- Updated dependencies [16e562d]\n  - nextra@2.4.2\n\n## 2.4.1\n\n### Patch Changes\n\n- Updated dependencies [a992ce1]\n  - nextra@2.4.1\n\n## 2.4.0\n\n### Patch Changes\n\n- Updated dependencies [545bd7c]\n- Updated dependencies [0a50cad]\n- Updated dependencies [259bfbc]\n  - nextra@2.4.0\n\n## 2.3.0\n\n### Minor Changes\n\n- 6a79462: add new option `dateFormatter`\n- 76e8b0f: support custom heading id via\n  `# my very long heading... [#my-custom-heading]` syntax\n  https://github.com/shuding/nextra/pull/1645\n\n### Patch Changes\n\n- Updated dependencies [0dd028a]\n- Updated dependencies [6ea1caf]\n- Updated dependencies [76e8b0f]\n  - nextra@2.3.0\n\n## 2.2.20\n\n### Patch Changes\n\n- Updated dependencies [2e48307]\n- Updated dependencies [e4c8b6d]\n  - nextra@2.2.20\n\n## 2.2.19\n\n### Patch Changes\n\n- Updated dependencies [e41cbbc]\n- Updated dependencies [a1e59b2]\n  - nextra@2.2.19\n\n## 2.2.18\n\n### Patch Changes\n\n- Updated dependencies [9bd2d59]\n- Updated dependencies [c2287e1]\n- Updated dependencies [90cb6b8]\n  - nextra@2.2.18\n\n## 2.2.17\n\n### Patch Changes\n\n- Updated dependencies [4a66366]\n  - nextra@2.2.17\n\n## 2.2.16\n\n### Patch Changes\n\n- b94245a: Reverts #1417 \"force theme to light if darkMode: false was set\"\n- d495e5f: introduce `_app.mdx` for better performance and smallest\n  `.next/static/chunks` size\n- Updated dependencies [d495e5f]\n  - nextra@2.2.16\n\n## 2.2.15\n\n### Patch Changes\n\n- 2e441b7: open http:// links in new window\n- da585a8: force theme to `light` if `darkMode: false` was set\n- 3e9e54f: hide unnecessary parts of the pages when being printed\n- Updated dependencies [d5aa17c]\n- Updated dependencies [016828e]\n- Updated dependencies [b3219c3]\n  - nextra@2.2.15\n\n## 2.2.14\n\n### Patch Changes\n\n- Updated dependencies [bcaba9c]\n- Updated dependencies [a683c84]\n- Updated dependencies [a404ef7]\n  - nextra@2.2.14\n\n## 2.2.13\n\n### Patch Changes\n\n- d1d873f: typed frontmatter -> `useConfig<YOUR_FRONTMATTER_TYPE>`\n- 6626356: prefer `import type`\n- 2234a13: fix raw `__esModule` string ☠️\n- Updated dependencies [d1d873f]\n- Updated dependencies [6626356]\n- Updated dependencies [2234a13]\n  - nextra@2.2.13\n\n## 2.2.12\n\n### Patch Changes\n\n- c913ec8: add peer deps\n- Updated dependencies [619ae3a]\n  - nextra@2.2.12\n\n## 2.2.11\n\n## 2.2.10\n\n## 2.2.9\n\n## 2.2.8\n\n## 2.2.7\n\n## 2.2.6\n\n## 2.2.5\n\n### Patch Changes\n\n- 163065c: loader refactor, type-safe `__nextra_resolvePageMap`, avoid code\n  interpolation in loader.ts\n\n## 2.2.4\n\n### Patch Changes\n\n- 091b77b: fix missing filename\n\n  add filename / copy code with \"codeHighlight: false\"\n\n  add unit tests for filename and copy code\n\n## 2.2.3\n\n### Patch Changes\n\n- 11b2870: fix copy code button position\n\n## 2.2.2\n\n### Patch Changes\n\n- 3145f53: extend `plugin:react/recommended`, `plugin:react-hooks/recommended`\n  and `plugin:@next/next/recommended` configs\n- 1834730: fix hydration error produced by cached compiler, fix broken\n  code-blocks styles while setting `nextraConfig.codeHighlight: false`\n\n## 2.2.1\n\n## 2.2.0\n\n### Minor Changes\n\n- e4b20ca: support `transform` in nextra config\n\n### Patch Changes\n\n- af76dbe: fix highlight substring from filename for code blocks\n\n## 2.1.0\n\n### Minor Changes\n\n- e5262d0: improve hmr and internal api for layout (toc and meta files)\n\n### Patch Changes\n\n- 09fc32a: allow changing prefix in `<TagTitle />`\n- c86508c: lint fixes for `eslint:recommended` and\n  `plugin:@typescript-eslint/recommended` configs\n- 329bc8c: fix inline code blocks style regression\n- d6c871a: simplify the custom theme layout api\n- 1ff43c1: use OKLCH colors where possible\n- ef3008d: `•` separator is missing if tags are empty\n- c86508c: allow override components with new options `components` #1201\n- a31678a: improve copy\n\n## 2.0.3\n\n## 2.0.2\n\n### Patch Changes\n\n- 99ec64e: fix indentation for copy code button\n- f488e2e: remove @react/skip-nev #1051\n\n  fix: staticImage should only set blur placeholder for jpeg,png,webp,avif\n\n## 2.0.1\n\n### Patch Changes\n\n- a9748aa: fix: A11y improvements to the docs theme\n- 93af338: feat: static tags for blog theme\n- ac82b1f: make code-blocks buttons focusable if they are visible on page\n- 0ca195c: inform screen readers of externals links that open in a new tabs\n\n## 2.0.0\n\n### Patch Changes\n\n- 94ef0b3: improve 2.0 docs\n- 8f55c80: fix(nextra-theme-blog): unneeded spread for `<a/>`\n- 6644bd5: pass unstable_flexsearch\n- cef5546: allow headings contain links\n- 2217f9c: fix `Warning: Prop `href` did not match. Server: \"#\" Client: ...`\n- fdb2f57: update docs to use next.js 13\n- a0398e0: fix: avoid mutating nextConfig\n- 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible\n  with next 13\n- a5cac21: [blog]: add support for `showLineNumbers` prop in code-blocks\n- fe2b714: upgrade to react 18\n- 1ee3c92: reuse table styles from docs in blog\n- f569d90: missing `nx-` class prefixes in blog fix callout padding in docs\n- b1d7361: improve docs for 2.0\n- 8dab966: fix invisible copy button in code blocks\n- 0518b1b: improve tags styling\n- 29dc746: fix blog build error\n- b7f7cf6: add missing `passHref` for `NextLink`\n- e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add\n  `NextraConfig.unstable_defaultShowCopyCode` option to show button by default,\n  add `copy` and `copy=false` options for code-blocks\n- a5cac21: [docs/blog]: extract code styles and import in both themes\n- 580c433: add nx- to all tailwind classes for style isolation\n- c3e6227: add `overflow-x-scroll` for tables\n- 1c3fedb: add missing `nx-` prefixes to table/th/tr elements\n- 4fd7c53: chore(nextra-theme-blog): refactor `sort-date.ts`.\n- 78f1519: chore: Add strict-peer-dependencies=false\n- 4edca5e: chore(nextra-theme-blog): refactor `traverse.ts`\n- acf3a1f: fix(blog): types is missing in bundle\n- 3de0f41: chore(blog/docs): use `postcss-import` to import css variables styles\n- 74a3398: update docs for 2.0\n- 3ef42cb: fix(nextra-theme-blog): move css to `className`s, fix duplicate id\n  issue\n- bd2cefa: Fix css classes with `eslint-plugin-tailwindcss`\n- ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile)\n- 009bf6a: Fix release workflow.\n- 4157b71: fix: make cusdis a component\n- ff8967c: fix missing `Copy Code` button in code-blocks without language\n- 723d42a: use `lightningcss` instead `cssnano`\n- 64ae4b5: add `nextraConfig.unstable_readingTime` option for blog theme\n- 596ea52: fix(nextra-theme-blog): make nav items center aligned\n- 7d2d5ee: use resolvedTheme instead renderedTheme + theme check\n- 256154a: use \"next/future/image\" if\n  `\"experimental.images.allowFutureImage\": true` is set in next config\n- c8605d6: feat: New layout implementation\n- 4157b71: set lower build target and share code highlight theme through nextra\n- 94a8587: chore: extract `svg` icons in `/icons` folder, reusing same icons\n  `<MoonIcon />` / `<SunIcon />` in blog from docs\n- 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well\n- 256154a: replace images with `<NextImage />` even when url not relative but\n  that starts from `/` (public directory)\n- e573175: Fix release CI\n- 48e0ac2: export `useConfig` and `useTheme`\n- 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader\n- 71528f1: show copy code button only on hover of container\n- 03e90d8: refresh build system with tsup and fix nextra type\n- e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter`\n- e6771ca: move `withLayout` logic directly in nextra loader\n- 43409ad: fix: mdx theme is missing\n- e596d3d: add missing class names to override styles\n- 07e4732: [nextra-theme-blog]: fix\n  `Application error: a client-side exception has occurred` when invalid date\n  was provided in frontmatter + TESTS\n\n## 2.0.0-beta.45\n\n## 2.0.0-beta.44\n\n### Patch Changes\n\n- 94ef0b3: improve 2.0 docs\n- fdb2f57: update docs to use next.js 13\n- b1d7361: improve docs for 2.0\n- 74a3398: update docs for 2.0\n\n## 2.0.0-beta.43\n\n### Patch Changes\n\n- 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible\n  with next 13\n\n## 2.0.0-beta.42\n\n## 2.0.0-beta.41\n\n### Patch Changes\n\n- bd2cefa: Fix css classes with `eslint-plugin-tailwindcss`\n\n## 2.0.0-beta.40\n\n### Patch Changes\n\n- f569d90: missing `nx-` class prefixes in blog fix callout padding in docs\n\n## 2.0.0-beta.39\n\n## 2.0.0-beta.38\n\n## 2.0.0-beta.37\n\n## 2.0.0-beta.36\n\n### Patch Changes\n\n- 1c3fedb: add missing `nx-` prefixes to table/th/tr elements\n\n## 2.0.0-beta.35\n\n## 2.0.0-beta.34\n\n## 2.0.0-beta.33\n\n### Patch Changes\n\n- 580c433: add nx- to all tailwind classes for style isolation\n\n## 2.0.0-beta.32\n\n### Patch Changes\n\n- 723d42a: use `lightningcss` instead `cssnano`\n\n## 2.0.0-beta.31\n\n### Patch Changes\n\n- cef5546: allow headings contain links\n\n## 2.0.0-beta.30\n\n### Patch Changes\n\n- b7f7cf6: add missing `passHref` for `NextLink`\n- 7d2d5ee: use resolvedTheme instead renderedTheme + theme check\n\n## 2.0.0-beta.29\n\n## 2.0.0-beta.28\n\n## 2.0.0-beta.27\n\n## 2.0.0-beta.26\n\n## 2.0.0-beta.25\n\n### Patch Changes\n\n- c3e6227: add `overflow-x-scroll` for tables\n- ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile)\n- ff8967c: fix missing `Copy Code` button in code-blocks without language\n- 256154a: use \"next/future/image\" if\n  `\"experimental.images.allowFutureImage\": true` is set in next config\n- 256154a: replace images with `<NextImage />` even when url not relative but\n  that starts from `/` (public directory)\n\n## 2.0.0-beta.24\n\n## 2.0.0-beta.23\n\n## 2.0.0-beta.22\n\n### Patch Changes\n\n- 8dab966: fix invisible copy button in code blocks\n\n## 2.0.0-beta.21\n\n## 2.0.0-beta.20\n\n### Patch Changes\n\n- 1ee3c92: reuse table styles from docs in blog\n- e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add\n  `NextraConfig.unstable_defaultShowCopyCode` option to show button by default,\n  add `copy` and `copy=false` options for code-blocks\n- 64ae4b5: add `nextraConfig.unstable_readingTime` option for blog theme\n- 71528f1: show copy code button only on hover of container\n- e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter`\n- e6771ca: move `withLayout` logic directly in nextra loader\n\n## 2.0.0-beta.19\n\n## 2.0.0-beta.18\n\n### Patch Changes\n\n- 0518b1b: improve tags styling\n\n## 2.0.0-beta.17\n\n### Patch Changes\n\n- 2217f9c: fix `Warning: Prop`href`did not match. Server: \"#\" Client: ...`\n\n## 2.0.0-beta.16\n\n### Patch Changes\n\n- 48e0ac2: export `useConfig` and `useTheme`\n- 43409ad: fix: mdx theme is missing\n\n## 2.0.0-beta.15\n\n## 2.0.0-beta.14\n\n### Patch Changes\n\n- c8605d6: feat: New layout implementation\n- e596d3d: add missing class names to override styles\n\n## 2.0.0-beta.13\n\n### Patch Changes\n\n- 4157b71: fix: make cusdis a component\n- 4157b71: set lower build target and share code highlight theme through nextra\n\n## 2.0.0-beta.12\n\n### Patch Changes\n\n- a5cac21: [blog]: add support for `showLineNumbers` prop in code-blocks\n- 29dc746: fix blog build error\n- a5cac21: [docs/blog]: extract code styles and import in both themes\n- 3de0f41: chore(blog/docs): use `postcss-import` to import css variables styles\n- 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader\n- 07e4732: [nextra-theme-blog]: fix\n  `Application error: a client-side exception has occurred` when invalid date\n  was provided in frontmatter + TESTS\n\n## 2.0.0-beta.11\n\n### Patch Changes\n\n- a0398e0: fix: avoid mutating nextConfig\n- fe2b714: upgrade to react 18\n- 78f1519: chore: Add strict-peer-dependencies=false\n\n## 2.0.0-beta.10\n\n### Patch Changes\n\n- 3ef42cb: fix(nextra-theme-blog): move css to `className`s, fix duplicate id\n  issue\n- 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well\n- 03e90d8: refresh build system with tsup and fix nextra type\n\n## 2.0.0-beta.9\n\n### Patch Changes\n\n- 6644bd5: pass unstable_flexsearch\n- 4fd7c53: chore(nextra-theme-blog): refactor `sort-date.ts`.\n- 4edca5e: chore(nextra-theme-blog): refactor `traverse.ts`\n- acf3a1f: fix(blog): types is missing in bundle\n- 596ea52: fix(nextra-theme-blog): make nav items center aligned\n- 94a8587: chore: extract `svg` icons in `/icons` folder, reusing same icons\n  `<MoonIcon />` / `<SunIcon />` in blog from docs\n- e573175: Fix release CI\n\n## 2.0.0-beta.8\n\n### Patch Changes\n\n- 009bf6a: Fix release workflow.\n\n## 2.0.0-beta.7\n\n### Patch Changes\n\n- 8f55c80: fix(nextra-theme-blog): unneeded spread for `<a/>`\n"
  },
  {
    "path": "packages/nextra-theme-blog/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Shu Ding\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.\n"
  },
  {
    "path": "packages/nextra-theme-blog/README.md",
    "content": "# nextra-theme-blog\n\nA blog site theme for [Nextra](https://github.com/shuding/nextra).\n\n## Example\n\n[site-icp9uk8zq.vercel.app](https://site-icp9uk8zq.vercel.app)\n"
  },
  {
    "path": "packages/nextra-theme-blog/__test__/is-valid-date.test.ts",
    "content": "import { describe, expect, it } from 'vitest'\nimport { isValidDate } from '../src/is-valid-date'\n\ndescribe('date', () => {\n  describe('isValidDate()', () => {\n    it('should be valid', () => {\n      expect(isValidDate('2022-07-28')).toBe(true)\n      expect(isValidDate('2022-07-28T10:40')).toBe(true)\n\n      expect(isValidDate('2022/10/1')).toBe(true)\n      expect(isValidDate('2016/5/3 10:10')).toBe(true)\n      expect(isValidDate('2022-07-29T20:49:45.112Z')).toBe(true)\n    })\n    it('should be invalid', () => {\n      expect(isValidDate('2022-07-28 10:40')).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/nextra-theme-blog/package.json",
    "content": "{\n  \"name\": \"nextra-theme-blog\",\n  \"version\": \"4.6.2\",\n  \"description\": \"A Nextra theme for blogs.\",\n  \"repository\": \"https://github.com/shuding/nextra\",\n  \"author\": \"Shu Ding <g@shud.in>\",\n  \"license\": \"MIT\",\n  \"types\": \"./dist/index.d.mts\",\n  \"exports\": {\n    \"./style.css\": \"./dist/style.css\",\n    \".\": {\n      \"types\": \"./dist/index.d.mts\",\n      \"import\": \"./dist/index.js\"\n    }\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"build\": \"NODE_ENV=production tsup\",\n    \"dev\": \"tsup --watch . --watch ../nextra/src --watch ../nextra/styles\",\n    \"prepublishOnly\": \"pnpm build\",\n    \"test\": \"vitest run\",\n    \"types:check\": \"tsc --noEmit\"\n  },\n  \"peerDependencies\": {\n    \"next\": \">=14\",\n    \"nextra\": \"workspace:*\",\n    \"react\": \">=18\",\n    \"react-dom\": \">=18\"\n  },\n  \"dependencies\": {\n    \"next-themes\": \"^0.4.0\",\n    \"next-view-transitions\": \"^0.3.0\",\n    \"react-compiler-runtime\": \"^19.1.0-rc.2\"\n  },\n  \"devDependencies\": {\n    \"@tailwindcss/cli\": \"4.1.10\",\n    \"@tailwindcss/postcss\": \"4.1.10\",\n    \"@tailwindcss/typography\": \"^0.5.15\",\n    \"@types/react\": \"^19.1.8\",\n    \"esbuild-react-compiler-plugin\": \"workspace:*\",\n    \"next\": \"^16.0.7\",\n    \"nextra\": \"workspace:*\",\n    \"postcss\": \"^8.4.33\",\n    \"react\": \"19.1.0\",\n    \"tailwindcss\": \"4.1.10\",\n    \"vitest\": \"^3.0.0\",\n    \"zx\": \"^8.2.4\"\n  },\n  \"sideEffects\": false\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/postcss.config.mjs",
    "content": "export { default } from '../nextra-theme-docs/postcss.config.mjs'\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/cusdis.tsx",
    "content": "'use client'\n\nimport { useTheme } from 'next-themes'\nimport { usePathname } from 'next/navigation'\nimport { useMounted } from 'nextra/hooks'\nimport type { FC } from 'react'\nimport { useEffect } from 'react'\n\nexport const Comments: FC<{\n  appId: string\n  host?: string\n}> = ({ appId, host = 'https://cusdis.com' }) => {\n  const pathname = usePathname()\n  const { resolvedTheme } = useTheme()\n  const mounted = useMounted()\n\n  useEffect(() => {\n    try {\n      // update the theme for the cusdis iframe when theme changed\n      if (window.CUSDIS) {\n        // window.CUSDIS? doesn't work with react-compiler\n        window.CUSDIS.setTheme(resolvedTheme as 'dark' | 'light')\n      }\n    } catch (error) {\n      console.error(error)\n    }\n  }, [resolvedTheme])\n\n  if (!appId) {\n    console.warn('[nextra/cusdis] `appId` is required')\n    return null\n  }\n  if (!mounted) {\n    return null\n  }\n\n  return (\n    <div\n      style={{ marginTop: '4rem' }}\n      id=\"cusdis_thread\"\n      data-host={host}\n      data-app-id={appId}\n      data-page-id={pathname}\n      data-page-url={pathname}\n      data-page-title={document.title}\n      data-theme={resolvedTheme}\n    >\n      <script async src=\"https://cusdis.com/js/cusdis.es.js\" />\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/go-back.tsx",
    "content": "'use client'\n\nimport { useTransitionRouter } from 'next-view-transitions'\nimport { usePathname } from 'next/navigation'\nimport { Button } from 'nextra/components'\nimport type { FC } from 'react'\n\nexport const GoBack: FC = () => {\n  const router = useTransitionRouter()\n  const segments = usePathname().split('/')\n\n  const isNestedPage = segments.length > 2\n  if (!isNestedPage) return null\n  return (\n    <Button onClick={router.back} className=\"x:print:hidden x:underline\">\n      Back\n    </Button>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/index.ts",
    "content": "export { Comments } from './cusdis'\nexport { Layout, Footer } from './layout'\nexport { Navbar } from './navbar'\nexport { PostCard } from './post-card'\nexport { ThemeSwitch } from './theme-switch'\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/layout.tsx",
    "content": "import { ThemeProvider } from 'next-themes'\nimport { ViewTransitions } from 'next-view-transitions'\nimport type { ComponentProps, FC, ReactNode } from 'react'\n\n// Fix react compiler error Expression type `TemplateLiteral` cannot be safely reordered\nconst defaultChildren = `CC BY-NC 4.0 ${new Date().getFullYear()} © Shu Ding.`\n\nexport const Footer: FC<{\n  children?: ReactNode\n}> = ({ children = defaultChildren }) => {\n  return (\n    <small className=\"x:mt-32 x:block\" data-pagefind-ignore=\"all\">\n      {children}\n    </small>\n  )\n}\n\nexport const Layout: FC<{\n  children: ReactNode\n  nextThemes?: Omit<ComponentProps<typeof ThemeProvider>, 'children'>\n  banner?: ReactNode\n}> = ({ children, nextThemes, banner }) => {\n  return (\n    <ThemeProvider attribute=\"class\" {...nextThemes}>\n      {banner}\n      <article\n        className=\"x:container x:px-4 x:prose x:max-md:prose-sm x:dark:prose-invert\"\n        dir=\"ltr\"\n        data-pagefind-body\n      >\n        <ViewTransitions>{children}</ViewTransitions>\n      </article>\n    </ThemeProvider>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/meta.tsx",
    "content": "import { Link } from 'next-view-transitions'\nimport type { FC, ReactNode } from 'react'\nimport type { BlogMetadata } from '../types'\nimport { GoBack } from './go-back'\n\nexport const Meta: FC<BlogMetadata & { children: ReactNode }> = ({\n  author,\n  tags,\n  date,\n  readingTime,\n  children\n}) => {\n  const tagsEl = tags?.map(t => (\n    <Link key={t} href={`/tags/${t}`} className=\"nextra-tag\">\n      {t}\n    </Link>\n  ))\n\n  const readingTimeText = readingTime?.text\n\n  return (\n    <div\n      className={\n        'x:mb-8 x:flex x:gap-3 ' +\n        (readingTimeText ? 'x:items-start' : 'x:items-center')\n      }\n    >\n      <div className=\"x:grow x:dark:text-gray-400 x:text-gray-600\">\n        <div className=\"x:flex x:flex-wrap x:items-center x:gap-1\">\n          {author}\n          {author && date && ','}\n\n          {children}\n\n          {\n            // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- fixme\n            (author || date) && (readingTime || tags?.length) && (\n              <span className=\"x:px-1\">•</span>\n            )\n          }\n          {readingTimeText || tagsEl}\n        </div>\n        {readingTime && (\n          <div className=\"x:mt-1 x:flex x:flex-wrap x:items-center x:gap-1\">\n            {tagsEl}\n          </div>\n        )}\n      </div>\n      <GoBack />\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/navbar-link.tsx",
    "content": "'use client'\n\nimport { Link } from 'next-view-transitions'\nimport { useFSRoute } from 'nextra/hooks'\nimport type { ComponentProps, FC } from 'react'\n\nexport const NavbarLink: FC<ComponentProps<typeof Link>> = props => {\n  const pathname = useFSRoute()\n  return (\n    <Link\n      className=\"x:aria-[current]:no-underline x:aria-[current]:opacity-60\"\n      aria-current={props.href === pathname || undefined}\n      {...props}\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/navbar.tsx",
    "content": "import type { PageMapItem } from 'nextra'\nimport { normalizePages } from 'nextra/normalize-pages'\nimport type { FC, ReactNode } from 'react'\nimport { NavbarLink } from './navbar-link'\n\ntype NavbarProps = {\n  children?: ReactNode\n  pageMap: PageMapItem[]\n}\n\nexport const Navbar: FC<NavbarProps> = ({ children, pageMap }) => {\n  const { topLevelNavbarItems } = normalizePages({ list: pageMap, route: '/' })\n  return (\n    <header\n      className=\"x:mb-8 x:flex x:items-center x:gap-3 x:justify-end\"\n      data-pagefind-ignore=\"all\"\n    >\n      {topLevelNavbarItems.map(nav => (\n        <NavbarLink key={nav.route} href={nav.route}>\n          {nav.title}\n        </NavbarLink>\n      ))}\n      {children}\n    </header>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/post-card.tsx",
    "content": "import { Link } from 'next-view-transitions'\nimport type { FC } from 'react'\nimport type { BlogMetadata } from '../types'\n\ntype PostCardProps = {\n  post: {\n    route: string\n    frontMatter: BlogMetadata\n  }\n  readMore?: string\n}\n\nexport const PostCard: FC<PostCardProps> = ({\n  post,\n  readMore = 'Read More →'\n}) => {\n  const { description, date, title } = post.frontMatter\n  const dateObj = date && new Date(date)\n  return (\n    <div key={post.route}>\n      <h2 className=\"x:mt-6 x:mb-2 x:text-xl x:font-semibold\">\n        <Link href={post.route} className=\"x:no-underline!\">\n          {title}\n        </Link>\n      </h2>\n      {description && (\n        <p className=\"x:mb-2 x:dark:text-gray-400 x:text-gray-600\">\n          {description}\n          {readMore && (\n            <Link href={post.route} className=\"x:ml-2\">\n              {readMore}\n            </Link>\n          )}\n        </p>\n      )}\n      {dateObj && (\n        <time\n          className=\"x:text-sm x:dark:text-gray-400 x:text-gray-600\"\n          dateTime={dateObj.toISOString()}\n        >\n          {dateObj.toDateString()}\n        </time>\n      )}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/components/theme-switch.tsx",
    "content": "'use client'\n\nimport { useTheme } from 'next-themes'\nimport { Button } from 'nextra/components'\nimport { useMounted } from 'nextra/hooks'\nimport { MoonIcon, SunIcon } from 'nextra/icons'\n\nexport function ThemeSwitch() {\n  const { setTheme, resolvedTheme } = useTheme()\n  const mounted = useMounted()\n  const isDark = resolvedTheme === 'dark'\n\n  // TODO: system theme\n  const toggleTheme = () => {\n    setTheme(isDark ? 'light' : 'dark')\n  }\n\n  const IconToUse = mounted && isDark ? MoonIcon : SunIcon\n\n  return (\n    <Button\n      aria-label=\"Toggle Dark Mode\"\n      className=\"x:p-2\"\n      onClick={toggleTheme}\n    >\n      <IconToUse height=\"14\" />\n    </Button>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/env.d.ts",
    "content": "interface Window {\n  CUSDIS?: {\n    setTheme(theme: 'dark' | 'light' | 'auto'): void\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/index.ts",
    "content": "export { useMDXComponents } from './mdx-components'\nexport {\n  Comments,\n  PostCard,\n  ThemeSwitch,\n  Navbar,\n  Layout,\n  Footer\n} from './components'\nexport type * from './types'\nexport { useTheme } from 'next-themes'\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/is-valid-date.ts",
    "content": "'use no memo'\n\nconst DATE_RE = /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2})?(:\\d{2}\\.\\d{3}Z)?$/\nconst DATE_RE_WITH_SLASH = /^\\d{4}\\/\\d{1,2}\\/\\d{1,2}( \\d{1,2}:\\d{1,2})?$/\n\nexport const isValidDate = (date: string): boolean =>\n  DATE_RE.test(date) || DATE_RE_WITH_SLASH.test(date)\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/mdx-components.tsx",
    "content": "// throws TypeError: Cannot read properties of null (reading 'useMemo')\n'use no memo'\n\n/* eslint sort-keys: error */\nimport {\n  Callout,\n  Code,\n  Details,\n  Pre,\n  Summary,\n  Table,\n  withGitHubAlert,\n  withIcons\n} from 'nextra/components'\nimport { useMDXComponents as getNextraMDXComponents } from 'nextra/mdx-components'\nimport type { MDXComponents, UseMDXComponents } from 'nextra/mdx-components'\nimport type { ComponentProps, FC } from 'react'\nimport { Meta } from './components/meta'\nimport { isValidDate } from './is-valid-date'\nimport type { BlogMetadata } from './types'\n\nconst createHeading = (\n  Tag: `h${2 | 3 | 4 | 5 | 6}`\n): FC<ComponentProps<typeof Tag>> =>\n  function HeadingLink({ children, id, className, ...props }) {\n    return (\n      <Tag\n        id={id}\n        // can be added by footnotes\n        className={className === 'sr-only' ? 'x:sr-only' : ''}\n        {...props}\n      >\n        {children}\n        {id && (\n          <a\n            href={`#${id}`}\n            className=\"not-prose subheading-anchor\"\n            aria-label=\"Permalink for this section\"\n          />\n        )}\n      </Tag>\n    )\n  }\nconst CALLOUT_TYPE = Object.freeze({\n  caution: 'error',\n  important: 'important',\n  note: 'info',\n  tip: 'default',\n  warning: 'warning'\n})\nconst Blockquote = withGitHubAlert(({ type, ...props }) => (\n  <Callout type={CALLOUT_TYPE[type]} {...props} />\n))\n\ntype BlogMDXComponents = MDXComponents & {\n  DateFormatter?: FC<{ date: Date }>\n}\n\nconst DEFAULT_COMPONENTS = getNextraMDXComponents({\n  blockquote: Blockquote,\n  code: Code,\n  details: Details,\n  h2: createHeading('h2'),\n  h3: createHeading('h3'),\n  h4: createHeading('h4'),\n  h5: createHeading('h5'),\n  h6: createHeading('h6'),\n  pre: withIcons(Pre),\n  summary: Summary,\n  table: Table,\n  td: Table.Td,\n  th: Table.Th,\n  tr: Table.Tr\n})\n\nexport const useMDXComponents: UseMDXComponents<typeof DEFAULT_COMPONENTS> = <\n  T extends BlogMDXComponents\n>(\n  comp?: T\n) => {\n  const { DateFormatter, ...components } = comp ?? {}\n  return {\n    ...DEFAULT_COMPONENTS,\n    // @ts-expect-error -- fixme\n    wrapper({ children, metadata }) {\n      const date = metadata.date as string\n      if (date && !isValidDate(date)) {\n        throw new Error(\n          `Invalid date \"${date}\". Provide date in \"YYYY/M/D\", \"YYYY/M/D H:m\", \"YYYY-MM-DD\", \"[YYYY-MM-DD]T[HH:mm]\" or \"[YYYY-MM-DD]T[HH:mm:ss.SSS]Z\" format.`\n        )\n      }\n      const dateObj = date && new Date(date)\n      return (\n        <>\n          <h1>{metadata.title}</h1>\n          <Meta {...(metadata as BlogMetadata)}>\n            {dateObj && (\n              <time dateTime={dateObj.toISOString()}>\n                {DateFormatter ? (\n                  <DateFormatter date={dateObj} />\n                ) : (\n                  dateObj.toLocaleDateString()\n                )}\n              </time>\n            )}\n          </Meta>\n          {children}\n        </>\n      )\n    },\n    ...components\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/style.css",
    "content": "@import 'tailwindcss' source(none) prefix(x);\n\n@source './**/*.{ts,tsx}';\n\n@plugin '@tailwindcss/typography';\n\n@import '../../nextra/styles/default.css';\n@import '../../nextra/styles/code-block.css';\n@import '../../nextra/styles/subheading-anchor.css';\n@import '../../nextra/styles/scrollbar.css';\n@import '../../nextra/styles/steps.css';\n@import '../../nextra/styles/cards.css';\n@import '../../nextra/styles/react-medium-image-zoom.css';\n\n@theme {\n}\n\nhtml {\n  @apply x:scroll-pt-5;\n}\n\narticle {\n  @apply x:mx-auto x:block x:pt-20 x:pb-32;\n  img {\n    @apply x:mx-auto;\n  }\n}\n\nh1 {\n  letter-spacing: -0.03em;\n}\n\n.x\\:prose code {\n  &:before,\n  &:after {\n    @apply x:hidden;\n  }\n  .line {\n    @apply x:font-normal;\n  }\n}\n\n.x\\:prose .nextra-callout p {\n  @apply x:m-0;\n}\n\n.footnotes a[data-footnote-backref] {\n  font-family: initial;\n}\n\n.nextra-tag {\n  @apply x:px-2.5 x:py-0.5 x:text-sm x:font-semibold x:rounded-md x:transition-colors x:shadow-sm;\n  @apply x:bg-neutral-900 x:text-white;\n  @apply x:dark:bg-gray-50 x:dark:text-black;\n\n  &:hover {\n    @apply x:bg-neutral-700;\n    @apply x:dark:bg-gray-200;\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/src/types.ts",
    "content": "/* eslint typescript-sort-keys/interface: error */\nimport type { ReadingTime } from 'nextra'\n\nexport type BlogMetadata = {\n  author?: string\n  date?: string\n  description?: string\n  readingTime?: ReadingTime\n  tags?: []\n  title?: string\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2021\",\n    \"module\": \"ESNext\",\n    \"declaration\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": true,\n    \"jsx\": \"react-jsx\",\n    \"moduleResolution\": \"bundler\",\n    \"types\": [\"vitest/globals\"],\n    \"noUncheckedIndexedAccess\": true\n  },\n  \"exclude\": [\"dist\"]\n}\n"
  },
  {
    "path": "packages/nextra-theme-blog/tsup.config.ts",
    "content": "import { reactCompilerPlugin } from 'esbuild-react-compiler-plugin'\nimport { defineConfig } from 'tsup'\nimport { $ } from 'zx'\nimport { defaultEntry } from '../nextra/default-entry.js'\nimport packageJson from './package.json'\n\nexport default defineConfig({\n  name: packageJson.name,\n  entry: defaultEntry,\n  format: 'esm',\n  dts: true,\n  outExtension: () => ({ js: '.js' }),\n  bundle: false,\n  esbuildPlugins: [reactCompilerPlugin({ filter: /\\.tsx?$/ })],\n  async onSuccess() {\n    // Use Tailwind CSS CLI because CSS processing by tsup produce different result\n    await $`npx @tailwindcss/cli -i src/style.css -o dist/style.css`\n  }\n})\n"
  },
  {
    "path": "packages/nextra-theme-blog/vitest.config.mts",
    "content": "import { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  test: {\n    globals: true,\n    environment: 'jsdom'\n  }\n})\n"
  },
  {
    "path": "packages/nextra-theme-docs/CHANGELOG.md",
    "content": "# nextra-theme-docs\n\n## 4.6.2\n\n### Patch Changes\n\n- Updated dependencies [9e6f5af]\n  - nextra@4.6.2\n\n## 4.6.1\n\n### Patch Changes\n\n- 261fcdc: - update zod to v4 stable\n  - fix compatibility with Next.js 16\n- Updated dependencies [261fcdc]\n  - nextra@4.6.1\n\n## 4.6.0\n\n### Minor Changes\n\n- e1d0ebd: Support disabling the \"Copy Page\" button through the `theme.copyPage`\n  setting in `_meta` files\n\n### Patch Changes\n\n- nextra@4.6.0\n\n## 4.5.1\n\n### Patch Changes\n\n- 8a4d176: fix TSDoc `@inline` tag to properly expand nested type aliases\n- Updated dependencies [8a4d176]\n  - nextra@4.5.1\n\n## 4.5.0\n\n### Minor Changes\n\n- 356a782: fix copy page button does not return the correct page contents due to\n  cached MDX compiler\n\n  add a `copyPageButton` layout prop which show/hide copy page content button\n\n### Patch Changes\n\n- Updated dependencies [356a782]\n  - nextra@4.5.0\n\n## 4.4.0\n\n### Minor Changes\n\n- 26b1281: feat: add Copy Documentation button/dropdown feature as LLM-Optimized\n  Prompt\n\n  ![](https://private-user-images.githubusercontent.com/7361780/473206831-aa851d94-3b83-46e8-8b00-5bf06c33314f.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTQ0NjgwNzUsIm5iZiI6MTc1NDQ2Nzc3NSwicGF0aCI6Ii83MzYxNzgwLzQ3MzIwNjgzMS1hYTg1MWQ5NC0zYjgzLTQ2ZTgtOGIwMC01YmYwNmMzMzMxNGYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDgwNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTA4MDZUMDgwOTM1WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MjgwZTI3YWMzODYwNjEwNTgwNGUyOTJkMDg5MzNjOGRjZWE0MWYzMWQwZmM3ZDJkMjQzMDc2ZDRjMzQ4ZTRlZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.C7LZXaay7uuPQsDBb3MKLrbiBWxTPM2q9nfSqUGp3_0)\n\n  > **Note**\n  >\n  > If you are using\n  > [`content` directory](https://nextra.site/docs/file-conventions/content-directory),\n  > you **must** pass the `sourceCode` prop to enable this feature.\n  >\n  > ```diff\n  > const {\n  >   default: MDXContent,\n  >   toc,\n  >   metadata,\n  > + sourceCode\n  > } = await importPage(params.mdxPath)\n  > return (\n  > - <Wrapper toc={toc} metadata={metadata}>\n  > + <Wrapper toc={toc} metadata={metadata} sourceCode={sourceCode}>\n  >     <MDXContent {...props} params={params} />\n  >   </Wrapper>\n  > )\n  > ```\n\n### Patch Changes\n\n- Updated dependencies [26b1281]\n  - nextra@4.4.0\n\n## 4.3.0\n\n### Minor Changes\n\n- eed8328: feat: adapt colors and icons from original GitHub alerts syntax\n\n  feat: new Callout type `important`\n\n  fix: inconsistent built-in Callout's icons size\n\n  feat: improve Callout's accessibility colors\n\n- 0831a1b: Add an `onSearch` callback to the `<Search />` component. This\n  callback, when specified, is called upon every search input change.\n- c93fc48: update zod to v4\n\n  feat(TSDoc): rename `generateDocumentation` to `generateDefinition`\n\n  feat(Bleed): pass all props from `div` element to `Bleed`, `Callout`, `Banner`\n  container\n\n  fix(TSDoc): improve TSDoc comments for components\n  - `Banner`\n  - `Head`\n  - `Search`\n  - `Bleed`\n  - `Callout`\n  - `Cards`\n  - `FileTree`\n  - `Steps`\n  - `Table`\n  - `Tabs`\n  - `Playground`\n  - `TSDoc`\n  - `Layout`\n  - `Navbar`\n\n  fix(TSDoc): improve TSDoc comments for functions:\n  - `nextra`\n  - `generateDefinition`\n  - `useMDXComponents`\n\n- 94b081c: feat: refactor `<Search>` component styles for improved transitions\n  and visibility\n- b5fab80: add `MDXRemote` component docs page\n  https://nextra.site/docs/built-ins/mdxremote\n- d9dd061: update `tailwindcss` to `4.1.10` and `react-compiler-runtime` to\n  `19.1.0-rc.2`\n- c134abe: feat: improve overall accessibility, makes text/colors easier to read\n  and achieves WCAG Level AAA compliance in many places\n- 83f6c57: feat: introduce new `<TSDoc />` component\n\n  The `<TSDoc>` component from `nextra/tsdoc` generates a properties table that\n  displays:\n  - **Property name**\n  - **TypeScript type**\n  - **Property description** - is parsed from [TSDoc](https://tsdoc.org) inline\n    description or the `@description` tag. You can use any Markdown/MDX syntax\n    here.\n  - **Default value** - are extracted from the `@default` or `@defaultValue`\n    tag.\n  - **Permalink** - a `#` anchor link to the property row for easy reference.\n\n  More info can be found in https://nextra.site/docs/built-ins/tsdoc\n\n  > [!IMPORTANT]\n  >\n  > Huge thanks to\n  > [xyflow - Node Based UIs for React and Svelte](https://xyflow.com/?utm_source=github&utm_campaign=nextra-4.3&utm_content=changelog)\n  > for sponsoring this feature!\n\n- 07debf9: feat(TSDoc): support flattening return object fields\n- fdeb5fe: feat: add new Layout prop `feedback.link` to customize feedback href\n\n### Patch Changes\n\n- 71f7b3f: Update https://nextra.site/docs/guide/search page\n\n  Fixes extra margin-top inside `Tabs.Tab`\n\n  Fix breaking `<Steps>` component numeration when there is `<Tabs>` component\n  inside\n\n- a070fdc: Fix `[object Object]` text on hovering breadcrumbs and pagination\n  links\n- 47ba5f3: fix: use `em` for padding-y, padding-x and border-radius styles of\n  `<Code>` element\n\n  fix(TSDoc): for return signature without `name` return mobile card instead of\n  table\n\n  feat: use `em` instead `rem` for margins\n\n- 40267dc: split `TSDoc` component logic to `TSDoc` component and\n  `generateDocumentation` function\n\n  update https://nextra.site/docs/built-ins/tsdoc documentation\n\n- b0dde33: Fix collapse behaviour of sidebar\n  - When a nested route item is active, clicking the parent route item should\n    not collapse the section.\n  - When the collapsible section is open, clicking the parent route item should\n    not cause it to collapse.\n  - Switching to another route should not trigger an unexpected reopening.\n\n- 8ac2506: chore: bump `babel-plugin-react-compiler` and\n  `react-compiler-runtime`, remove custom pnpm patch for\n  `babel-plugin-react-compiler`\n- 8edc715: fix phantom scroll when footer is disabled\n- b2cba90: improve TSDoc comments for `getPageMap`, `generateStaticParamsFor`\n  and `importPage` functions. Add new https://nextra.site/docs/guide/api page.\n- d29469e: support Next.js 15.3.0\n- 2b18c66: - Disable prefetch for sidebar/breadcrumb/pagination links\n  - Add extractStringsFromReactNode to extract strings from breadcrumb links and\n    pagination links\n- 6a82e6f: - Fix: Received `false` for a non-boolean attribute `prefetch`.\n  - Allow override `next-mdx-import-source-file` in `turbopack.resolveAlias`\n    option\n- 4547eb9: feat(TSDoc): add support for functions and functions with multiple\n  signatures\n- 407e0c4: feat(TSDoc): add `TSDoc.noParametersContent` prop\n- a506e0b: fix `TypeError: page.generateMetadata is not a function` when using\n  with `withSentryConfig` plugin\n- Updated dependencies [eed8328]\n- Updated dependencies [71f7b3f]\n- Updated dependencies [0831a1b]\n- Updated dependencies [b0afee7]\n- Updated dependencies [c93fc48]\n- Updated dependencies [47ba5f3]\n- Updated dependencies [01ac538]\n- Updated dependencies [94b081c]\n- Updated dependencies [b5fab80]\n- Updated dependencies [40267dc]\n- Updated dependencies [ef35ab9]\n- Updated dependencies [f717156]\n- Updated dependencies [9f449e5]\n- Updated dependencies [8ac2506]\n- Updated dependencies [a6a1f97]\n- Updated dependencies [fda0355]\n- Updated dependencies [b2cba90]\n- Updated dependencies [f40e018]\n- Updated dependencies [d29469e]\n- Updated dependencies [d9dd061]\n- Updated dependencies [6a82e6f]\n- Updated dependencies [c134abe]\n- Updated dependencies [7de40fb]\n- Updated dependencies [c7d25df]\n- Updated dependencies [4547eb9]\n- Updated dependencies [407e0c4]\n- Updated dependencies [83f6c57]\n- Updated dependencies [00f4696]\n- Updated dependencies [31ddba4]\n- Updated dependencies [07debf9]\n- Updated dependencies [a506e0b]\n- Updated dependencies [9690841]\n  - nextra@4.3.0\n\n## 4.3.0-alpha.31\n\n### Patch Changes\n\n- Updated dependencies [f40e018]\n  - nextra@4.3.0-alpha.31\n\n## 4.3.0-alpha.30\n\n### Patch Changes\n\n- Updated dependencies [b0afee7]\n  - nextra@4.3.0-alpha.30\n\n## 4.3.0-alpha.29\n\n### Patch Changes\n\n- Updated dependencies [a6a1f97]\n  - nextra@4.3.0-alpha.29\n\n## 4.3.0-alpha.28\n\n### Patch Changes\n\n- Updated dependencies [ef35ab9]\n  - nextra@4.3.0-alpha.28\n\n## 4.3.0-alpha.27\n\n### Patch Changes\n\n- Updated dependencies [01ac538]\n  - nextra@4.3.0-alpha.27\n\n## 4.3.0-alpha.26\n\n### Patch Changes\n\n- Updated dependencies [c7d25df]\n  - nextra@4.3.0-alpha.26\n\n## 4.3.0-alpha.25\n\n### Minor Changes\n\n- d9dd061: update `tailwindcss` to `4.1.10` and `react-compiler-runtime` to\n  `19.1.0-rc.2`\n\n### Patch Changes\n\n- Updated dependencies [d9dd061]\n  - nextra@4.3.0-alpha.25\n\n## 4.3.0-alpha.24\n\n### Minor Changes\n\n- 0831a1b: Add an `onSearch` callback to the `<Search />` component. This\n  callback, when specified, is called upon every search input change.\n\n### Patch Changes\n\n- Updated dependencies [0831a1b]\n  - nextra@4.3.0-alpha.24\n\n## 4.3.0-alpha.23\n\n### Patch Changes\n\n- Updated dependencies [9690841]\n  - nextra@4.3.0-alpha.23\n\n## 4.3.0-alpha.22\n\n### Minor Changes\n\n- c93fc48: update zod to v4\n\n  feat(TSDoc): rename `generateDocumentation` to `generateDefinition`\n\n  feat(Bleed): pass all props from `div` element to `Bleed`, `Callout`, `Banner`\n  container\n\n  fix(TSDoc): improve TSDoc comments for components\n  - `Banner`\n  - `Head`\n  - `Search`\n  - `Bleed`\n  - `Callout`\n  - `Cards`\n  - `FileTree`\n  - `Steps`\n  - `Table`\n  - `Tabs`\n  - `Playground`\n  - `TSDoc`\n  - `Layout`\n  - `Navbar`\n\n  fix(TSDoc): improve TSDoc comments for functions:\n  - `nextra`\n  - `generateDefinition`\n  - `useMDXComponents`\n\n- b5fab80: add `MDXRemote` component docs page\n  https://nextra.site/docs/built-ins/mdxremote\n\n### Patch Changes\n\n- Updated dependencies [c93fc48]\n- Updated dependencies [b5fab80]\n  - nextra@4.3.0-alpha.22\n\n## 4.3.0-alpha.21\n\n### Patch Changes\n\n- 6a82e6f: - Fix: Received `false` for a non-boolean attribute `prefetch`.\n  - Allow override `next-mdx-import-source-file` in `turbopack.resolveAlias`\n    option\n- Updated dependencies [6a82e6f]\n  - nextra@4.3.0-alpha.21\n\n## 4.3.0-alpha.20\n\n### Patch Changes\n\n- 2b18c66: - Disable prefetch for sidebar/breadcrumb/pagination links\n  - Add extractStringsFromReactNode to extract strings from breadcrumb links and\n    pagination links\n  - nextra@4.3.0-alpha.20\n\n## 4.3.0-alpha.19\n\n### Patch Changes\n\n- 407e0c4: feat(TSDoc): add `TSDoc.noParametersContent` prop\n- Updated dependencies [407e0c4]\n  - nextra@4.3.0-alpha.19\n\n## 4.3.0-alpha.18\n\n### Patch Changes\n\n- Updated dependencies [7de40fb]\n- Updated dependencies [00f4696]\n- Updated dependencies [31ddba4]\n  - nextra@4.3.0-alpha.18\n\n## 4.3.0-alpha.17\n\n### Patch Changes\n\n- 8edc715: fix phantom scroll when footer is disabled\n  - nextra@4.3.0-alpha.17\n\n## 4.3.0-alpha.16\n\n### Patch Changes\n\n- b0dde33: Fix collapse behaviour of sidebar\n  - When a nested route item is active, clicking the parent route item should\n    not collapse the section.\n  - When the collapsible section is open, clicking the parent route item should\n    not cause it to collapse.\n  - Switching to another route should not trigger an unexpected reopening.\n  - nextra@4.3.0-alpha.16\n\n## 4.3.0-alpha.15\n\n### Patch Changes\n\n- b2cba90: improve TSDoc comments for `getPageMap`, `generateStaticParamsFor`\n  and `importPage` functions. Add new https://nextra.site/docs/guide/api page.\n- Updated dependencies [b2cba90]\n  - nextra@4.3.0-alpha.15\n\n## 4.3.0-alpha.14\n\n### Patch Changes\n\n- a506e0b: fix `TypeError: page.generateMetadata is not a function` when using\n  with `withSentryConfig` plugin\n- Updated dependencies [a506e0b]\n  - nextra@4.3.0-alpha.14\n\n## 4.3.0-alpha.13\n\n### Patch Changes\n\n- 47ba5f3: fix: use `em` for padding-y, padding-x and border-radius styles of\n  `<Code>` element\n\n  fix(TSDoc): for return signature without `name` return mobile card instead of\n  table\n\n  feat: use `em` instead `rem` for margins\n\n- d29469e: support Next.js 15.3.0\n- Updated dependencies [47ba5f3]\n- Updated dependencies [d29469e]\n  - nextra@4.3.0-alpha.13\n\n## 4.3.0-alpha.12\n\n### Patch Changes\n\n- 40267dc: split `TSDoc` component logic to `TSDoc` component and\n  `generateDocumentation` function\n\n  update https://nextra.site/docs/built-ins/tsdoc documentation\n\n- Updated dependencies [40267dc]\n  - nextra@4.3.0-alpha.12\n\n## 4.3.0-alpha.11\n\n### Patch Changes\n\n- 71f7b3f: Update https://nextra.site/docs/guide/search page\n\n  Fixes extra margin-top inside `Tabs.Tab`\n\n  Fix breaking `<Steps>` component numeration when there is `<Tabs>` component\n  inside\n\n- Updated dependencies [71f7b3f]\n  - nextra@4.3.0-alpha.11\n\n## 4.3.0-alpha.10\n\n### Minor Changes\n\n- fdeb5fe: feat: add new Layout prop `feedback.link` to customize feedback href\n\n### Patch Changes\n\n- nextra@4.3.0-alpha.10\n\n## 4.3.0-alpha.9\n\n### Minor Changes\n\n- 94b081c: feat: refactor `<Search>` component styles for improved transitions\n  and visibility\n\n### Patch Changes\n\n- Updated dependencies [94b081c]\n  - nextra@4.3.0-alpha.9\n\n## 4.3.0-alpha.8\n\n### Minor Changes\n\n- c134abe: feat: improve overall accessibility, makes text/colors easier to read\n  and achieves WCAG Level AAA compliance in many places\n\n### Patch Changes\n\n- Updated dependencies [c134abe]\n  - nextra@4.3.0-alpha.8\n\n## 4.3.0-alpha.7\n\n### Minor Changes\n\n- 07debf9: feat(TSDoc): support flattening return object fields\n\n### Patch Changes\n\n- Updated dependencies [07debf9]\n  - nextra@4.3.0-alpha.7\n\n## 4.3.0-alpha.6\n\n### Patch Changes\n\n- a070fdc: Fix `[object Object]` text on hovering breadcrumbs and pagination\n  links\n  - nextra@4.3.0-alpha.6\n\n## 4.3.0-alpha.5\n\n### Minor Changes\n\n- eed8328: feat: adapt colors and icons from original GitHub alerts syntax\n\n  feat: new Callout type `important`\n\n  fix: inconsistent built-in Callout's icons size\n\n  feat: improve Callout's accessibility colors\n\n### Patch Changes\n\n- Updated dependencies [eed8328]\n  - nextra@4.3.0-alpha.5\n\n## 4.3.0-alpha.4\n\n### Patch Changes\n\n- 4547eb9: feat(TSDoc): add support for functions and functions with multiple\n  signatures\n- Updated dependencies [4547eb9]\n  - nextra@4.3.0-alpha.4\n\n## 4.3.0-alpha.3\n\n### Patch Changes\n\n- Updated dependencies [f717156]\n  - nextra@4.3.0-alpha.3\n\n## 4.3.0-alpha.2\n\n### Patch Changes\n\n- 8ac2506: chore: bump `babel-plugin-react-compiler` and\n  `react-compiler-runtime`, remove custom pnpm patch for\n  `babel-plugin-react-compiler`\n- Updated dependencies [8ac2506]\n  - nextra@4.3.0-alpha.2\n\n## 4.3.0-alpha.1\n\n### Patch Changes\n\n- Updated dependencies [9f449e5]\n  - nextra@4.3.0-alpha.1\n\n## 4.3.0-alpha.0\n\n### Minor Changes\n\n- 83f6c57: feat: introduce new `<TSDoc />` component\n\n  The `<TSDoc>` component from `nextra/tsdoc` generates a properties table that\n  displays:\n  - **Property name**\n  - **TypeScript type**\n  - **Property description** - is parsed from [TSDoc](https://tsdoc.org) inline\n    description or the `@description` tag. You can use any Markdown/MDX syntax\n    here.\n  - **Default value** - are extracted from the `@default` or `@defaultValue`\n    tag.\n  - **Permalink** - a `#` anchor link to the property row for easy reference.\n\n  More info can be found in https://nextra.site/docs/built-ins/tsdoc\n\n  > [!IMPORTANT]\n  >\n  > Huge thanks to\n  > [xyflow - Node Based UIs for React and Svelte](https://xyflow.com/?utm_source=github&utm_campaign=nextra-4.3&utm_content=changelog)\n  > for sponsoring this feature!\n\n### Patch Changes\n\n- Updated dependencies [83f6c57]\n  - nextra@4.3.0-alpha.0\n\n## 4.2.18\n\n### Patch Changes\n\n- Updated dependencies [e1c2b1b]\n  - nextra@4.2.18\n\n## 4.2.17\n\n### Patch Changes\n\n- a7db0e6: fix: use correct `ReactNode` zod validation for\n  `Layout.footer/banner/editLink/feedback.content/toc.backToTop/toc.extraContent/toc.title/search`\n  and `Navbar.children/projectIcon/chatIcon`\n- aac469e: fix: improve sidebar folder item arrow animation\n- Updated dependencies [a7db0e6]\n- Updated dependencies [18e7fb9]\n  - nextra@4.2.17\n\n## 4.2.16\n\n### Patch Changes\n\n- 2cfaacc: fix: frozen spinner on loading state in search results by updating\n  Tailwind CSS to v4.0.10\n- Updated dependencies [2cfaacc]\n  - nextra@4.2.16\n\n## 4.2.15\n\n### Patch Changes\n\n- 27dcd23: fix: better error message for `Layout#lastUpdated` prop. Ensure\n  `lastUpdated` is React component and not React fragment.\n- 5617e04: fix: loading state in search results was only visible during the\n  first search\n- Updated dependencies [5617e04]\n  - nextra@4.2.15\n\n## 4.2.14\n\n### Patch Changes\n\n- ccb5da2: removing custom nextra's scrollbar styles, allowing the browser's\n  default scrollbars to be used\n- 05a202d: fix: make search results appear above the navbar\n- fd4e6d1: fix: make scroll position in sidebar stable between client-side\n  navigation\n- Updated dependencies [ccb5da2]\n- Updated dependencies [05a202d]\n  - nextra@4.2.14\n\n## 4.2.13\n\n### Patch Changes\n\n- Updated dependencies [fc4035c]\n- Updated dependencies [fc4035c]\n  - nextra@4.2.13\n\n## 4.2.12\n\n### Patch Changes\n\n- 23b1c48: increate z-index for `type: menu` dropdown from `20` to `30`\n  - nextra@4.2.12\n\n## 4.2.11\n\n### Patch Changes\n\n- 8805d3f: - add `overflow: hidden` on `<html>` element instead of `<body>` to\n  lock scroll when mobile nav is open\n  - increase z-index for mobile nav from `10` to `20`, in navbar from `20` to\n    `30`\n  - fix navbar alignement on mobile when `Navbar.align` prop is set to `left`\n  - nextra@4.2.11\n\n## 4.2.10\n\n### Patch Changes\n\n- 5c22495: - add `Navbar.align` prop to align navigation links to the specified\n  side. (default `'right'`)\n  - fix hidden nav links when specified with `type: 'page', href: '...'` in\n    `_meta` files\n- Updated dependencies [5c22495]\n  - nextra@4.2.10\n\n## 4.2.9\n\n### Patch Changes\n\n- 31534cb: add `Navbar.className` prop\n  - nextra@4.2.9\n\n## 4.2.8\n\n### Patch Changes\n\n- e610d1d: fix type of `Navbar.children`, should be `ReactNode`, not\n  `ReactElement`\n  - nextra@4.2.8\n\n## 4.2.7\n\n### Patch Changes\n\n- 9b5eea6: allow change `nextThemes.forcedTheme` prop\n  - nextra@4.2.7\n\n## 4.2.6\n\n### Patch Changes\n\n- Updated dependencies [a7906d1]\n  - nextra@4.2.6\n\n## 4.2.5\n\n### Patch Changes\n\n- Updated dependencies [e6c3050]\n  - nextra@4.2.5\n\n## 4.2.4\n\n### Patch Changes\n\n- Updated dependencies [b46d831]\n- Updated dependencies [7949e28]\n  - nextra@4.2.4\n\n## 4.2.3\n\n### Patch Changes\n\n- ca67a19: remove requirement `page.{jsx,tsx}` pages to have exported `metadata`\n  object\n- Updated dependencies [ca67a19]\n  - nextra@4.2.3\n\n## 4.2.2\n\n### Patch Changes\n\n- Updated dependencies [dd32eca]\n  - nextra@4.2.2\n\n## 4.2.1\n\n### Patch Changes\n\n- 5c51b49: fix allow configuring `theme.toc` in `_meta` file when `toc.float` is\n  set to `false` for pages with `type: 'page'`\n- 996b0b5: fix: show `Scroll to top` link `toc.backToTop` when\n  `toc.float: false` is set\n  - nextra@4.2.1\n\n## 4.2.0\n\n### Minor Changes\n\n- 90b8c66: allow configuring `theme.toc` with `layout: 'default'` in `_meta`\n  files\n\n### Patch Changes\n\n- 0b0db89: better animations for open/closed state for the `<NavbarMenu>`\n  component which is rendered with `type: 'menu'` in `_meta` file\n- 427b080: calculate `--nextra-banner-height` after mounting banner, so banner\n  text can be wrapped on multiple lines\n- 6b8053f: fix a sudden height jump on opening for `<detail>` element when his\n  last children contain margins\n- 5d1e75b: add the missing `transition-opacity` style for the `<BackToTop>`\n  component\n- b0e686e: hide default `<summary>` arrow on mobile\n- 2b0b434: add the missing `cursor-pointer` style in the `<BackToTop>` component\n- bcc34cc: reduce main area padding x to from `24px` to `16px` like in next.js\n  docs\n- Updated dependencies [427b080]\n- Updated dependencies [6b8053f]\n- Updated dependencies [b0e686e]\n  - nextra@4.2.0\n\n## 4.1.1\n\n### Patch Changes\n\n- b9f8bfb: do not render default footer content if the `Footer#children` prop\n  was not provided\n- 8d878dd: fix: show heading anchor when hover on heading itself\n- 20f7aaa: fix\n  `Uncaught Error: Minified React error #418; visit https://react.dev/errors/418`\n  error due mismatch of last updated time date\n- 57e98cd: add `Layout#sidebar.defaultOpen` prop to configure sidebar default\n  open state\n- d586bd6: fix `ThemeSwitch#lite` prop\n- 29a44de: fix regression from Nextra 3 setting\n  [`theme.collapsed?: boolean` in `_meta` file](https://nextra.site/docs/file-conventions/meta-file#theme-option)\n  for folders has no effect in sidebar\n- 5e86a14: add missing transition state for `<Navbar>` links and `<TOC>` extra\n  content links\n- 2ba45de: allow change `_meta` file `theme.toc` property with `type: 'page'`\n- Updated dependencies [29a44de]\n- Updated dependencies [19578c3]\n  - nextra@4.1.1\n\n## 4.1.0\n\n### Minor Changes\n\n- 7caf059: - generate unique anchor id for `<summary>` elements based on its\n  content at build time\n  - add anchor link icon for `<summary>`\n\n### Patch Changes\n\n- fa7f1ee: fix cropped sidebar footer on desktop, when Nextra's `<Banner>` is\n  used\n- Updated dependencies [7caf059]\n  - nextra@4.1.0\n\n## 4.0.9\n\n### Patch Changes\n\n- Updated dependencies [e78f796]\n- Updated dependencies [ff007b2]\n  - nextra@4.0.9\n\n## 4.0.8\n\n### Patch Changes\n\n- Updated dependencies [267ef81]\n  - nextra@4.0.8\n\n## 4.0.7\n\n### Patch Changes\n\n- Updated dependencies [32e7d55]\n- Updated dependencies [695e428]\n- Updated dependencies [fc78033]\n- Updated dependencies [b2f2458]\n  - nextra@4.0.7\n\n## 4.0.6\n\n### Patch Changes\n\n- Updated dependencies [44ea060]\n  - nextra@4.0.6\n\n## 4.0.5\n\n### Patch Changes\n\n- Updated dependencies [14bf091]\n  - nextra@4.0.5\n\n## 4.0.4\n\n### Patch Changes\n\n- 5132295: fix broken `showLineNumbers` setting on code blocks\n- 5132295: fix unable order \\_meta key with `index` name\n- Updated dependencies [5132295]\n- Updated dependencies [5132295]\n  - nextra@4.0.4\n\n## 4.0.3\n\n### Patch Changes\n\n- a0c432f: fix\n  `TypeError: Cannot read properties of null (reading 'querySelector')`\n  - nextra@4.0.3\n\n## 4.0.2\n\n### Patch Changes\n\n- 865e2ab: hide `On This Page` TOC's title `themeConfig.toc.title` when there is\n  no toc links\n  - nextra@4.0.2\n\n## 4.0.1\n\n### Patch Changes\n\n- 481e0d0: fix syntax highlighting for `mdx` lang and improve docs for\n  `/docs/docs-theme/start`\n- 426cd66: Remove margin-top from `.nextra-steps` `:before` pseudo selector\n- Updated dependencies [481e0d0]\n- Updated dependencies [426cd66]\n  - nextra@4.0.1\n\n## 4.0.0\n\n### Major Changes\n\n- 283320f: remove `\"typesVersions\"` field from `package.json`. You need to set\n  `\"moduleResolution\": \"bundler\"` in your `tsconfig.json` if you are using\n  TypeScript\n- 283320f: move `<Collapse>`, `<Details>`, `<Summary>`, `<SkipNavContent>`,\n  `SkipNavLink`, `<Select>` and `<Bleed>` from `nextra-theme-docs` to\n  `nextra/components`\n- 283320f: remove `<Th>`, `<Tr>` and `<Td>` exports (since they should be always\n  used with `<Table>` component)\n\n  ```diff\n  - import { Table, Th, Tr, Td } from 'nextra/components'\n  + import { Table } from 'nextra/components'\n\n  // ...\n\n  - <Th>\n  + <Table.Th>\n  - <Tr>\n  + <Table.Tr>\n  - <Td>\n  + <Table.Td>\n  ```\n\n- 283320f: make `compileMdx` from `nextra/compile` return a `string` instead of\n  an `object`\n- 283320f: remove `i18n.direction` option\n- 283320f: remove `export const title` from generated mdx pages\n- 283320f: The initial version which supports App Router instead of Pages\n  Router, something may be broken, check\n  https://github.com/shuding/nextra/tree/v4-v2/examples for the migration guide\n- 283320f: fix focusing on first search result item\n- 283320f: remove `navbar` and `footer` props, pass `<Navbar>` and `<Footer>` as\n  children of `<Layout>`\n- 283320f: migrate search from Flexsearch to Pagefind\n- 283320f: migrate from react context to zustand\n- 283320f: - add root `_meta.global.{js,jsx,ts,tsx}` file\n  > See\n  > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts)\n  > based on https://nextra.site website\n  - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2\n    `lang?: string, route?: string = '/'`\n  - remove `createCatchAllMeta` from `nextra/catch-all`\n  - remove `collectCatchAllRoutes`\n  - remove `normalizePageRoute`\n  - add `mergeMetaWithPageMap` to `nextra/page-map`\n  - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime`\n    in remark plugin\n  - refactor recma rewrite plugin and add tests\n    - remove `recmaRewriteJsx`\n    - remove `recmaRewriteFunctionBody`\n  - make `convertPageMapToJs` sync\n- 283320f: improve performance on projects without Turbopack enabled\n- 283320f: release Nextra rc.0\n- 283320f: - migrate to tailwind css v4.beta2\n  - refactor builtin CSS classes from `_` prefix to `x:` prefix\n  - remove `color-primary-750` theme color variant\n- 283320f: replace `export const useTOC = () = [/* your headings */]` by\n  `export const toc = [/* your headings */]`\n- 283320f: move `<Head>` component in `nextra/components`\n- 283320f: remove `feedback.useLink` and `editLink.component` option, remove\n  `themeConfig` prop on `<Layout>` component\n\n  change `gitTimestamp` option to boolean\n\n  remove `nextraCofig.transform` option\n\n- 283320f: replace `gitTimestamp` option with `lastUpdated`\n\n  replace `editLink.content` option with `editLink`\n\n- 283320f: support `<Head>`'s `backgroundColor.dark/light` props colors in\n  `rgb(...,...,...)` and `#RRGGBB` formats\n- 283320f: remove `renderComponent` and `renderString`\n- 283320f: require Next.js minimum v14\n- 283320f: - add `nextra/components` to `experimental.optimizePackageImports` to\n  optimize `nextra/components` by default\n  - remove `<RemoteContent>` from `nextra/components`\n  - rename `<RemoteContent>` to `MDXRemote` and move to `nextra/mdx-remote`\n- 283320f: document removed theme config options\n  - `main`\n  - `direction`\n  - `toc.component`\n  - `themeSwitch.component`\n  - `themeSwitch.useOptions`\n  - `search.component`\n  - `feedback.useLink`\n  - `banner.dismissible`\n  - `banner.key`\n  - `banner.content`\n  - `footer.content`\n  - `footer.component`\n  - `head`\n  - `navbar.component`\n  - `navbar.extraContent`\n  - `project.link`\n  - `project.icon`\n  - `chat.link`\n  - `chat.icon`\n  - `search.emptyResult`\n  - `search.loading`\n  - `search.errorText`\n  - `search.placeholder`\n  - `search.className`\n\n  refactor `themeSwitch.useOptions` to `themeSwitch` option\n\n  refactor `editLink.content` to `editLink` option\n\n  rename Search prop `error` to `errorText`\n\n### Minor Changes\n\n- 283320f: content width could be configured via CSS `--nextra-content-width`\n  variable\n- 283320f: add opacity animation for `:target` state for headings h2-h6\n- 283320f: - use ReactIcon for code blocks with `jsx`, `tsx` language\n  - add JsonIcon for `json` language\n  - parse language from filename if exist when `diff` language is specified\n  - use JavaScript icon for `cjs` and `mjs`\n  - use TypeScript icon for `cts` and `mts`\n- 283320f: export a `style-prefixed.css` file with Tailwind CSS v4 prefixed\n  layers for projects using Tailwind CSS v3\n  - `@layer utilities` -> `@layer v4-utilities`\n  - `@layer base` -> `@layer v4-base`\n\n- 283320f: include `document.referrer` in link in `<NotFoundPage>` component\n- 283320f: replace `useContentDir` with `contentDirBasePath` option which\n  configure `content` directory under a catch-all subdirectory\n- 283320f: move TOC logic from `recma-rewrite-jsx` plugin to\n  `rehype-extract-toc-content` plugin\n- 283320f: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and\n  also `content` folder files - all add to `pageMap`, but ignore dynamic pages\n  `[[`\n- 283320f: compile sidebar components with react compiler\n- e11dbe0: set `content` value for `<meta name=\"theme-color\">` based on\n  background value for light and dark themes\n- 283320f: refactor `useMenuActions` to `setMenu`, `useFocusedRouteActions` to\n  `setFocusedRoute`\n\n### Patch Changes\n\n- 283320f: fix mobile nav position\n- 283320f: search tweaks\n- fdd2c6a: fix steps background on dark mode fix headings anchor link color on\n  dark mode\n- 283320f: setup `@typescript-eslint/no-unnecessary-condition` rule and fix\n  warnings\n- aca79fa: Don't focus search input on `Ctrl + k` on non Mac devices. Don't\n  focus search input on `⌘ + Shift + k` or `Ctrl + Shift + k`.\n- 283320f: add helpful error message about not available search on development\n  mode\n- 283320f: add `getPageMap` helper function to `nextra/page-map`\n- 283320f: Fixes when Turbopack is enabled:\n  `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'`\n- 283320f: add `whiteListTagsStyling` nextra config option\n- 283320f: fix unable to select text and `::selection` style\n- 283320f: - allow override/add additional icons for code blocks\n  - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of\n    `mdx-components` file\n- 283320f: - Use Tailwind CSS CLI because CSS processing by `tsup` produce\n  different, weird and broken result\n  - Patch react-compiler with some fixes which isn't fixed\n- 283320f: - Simplify the class-name of the sidebar file item\n  - fix unclosable active folder when it's `<button>` element and not `<a>`\n  - improve `<Collapse>` to add inner `<div>` only if children != 1\n- 283320f: export `setMenu`\n- 283320f: use `Date.now()` for last edit time on development and git last\n  commit time on production\n- 283320f: move `pagefind` output to `public/_pagefind` directory\n  https://github.com/shuding/nextra/pull/3517\n- 283320f: initialize `transformerTwoslash` only 1 time outside of loader\n- 283320f: Add aria attrs to the sidebar collapse button\n- 283320f: - remove `nextra/context`\n  - remove `type NextraThemeLayoutProps`\n- 283320f: fix edit on github and last updated at for catch all routes\n- 283320f: simplify `generatePageMap`\n- 283320f: - if `filePath` is falsy in client wrapper -> do not render\n  `edit on github` link\n  - if `filePath` starts with `http` do not append `docsRepositoryBase` prefix\n- 283320f: Add `nextra-mobile-nav` to `<MobileNav>`\n- 283320f: - parse and transform `_meta` files with zod\n  - remove `_meta` `newWindow` field\n- 283320f: allow `editLink`/`feedback.content`/`search`/`toc.backToTop` be\n  `null` as value\n- 283320f: sync with nextra 3.1.0\n- 283320f: Cache the result of `repository.getFileLatestModifiedDateAsync`\n  because it can slow down Fast Refresh for uncommitted files.\n- 283320f: add `bottomContent` prop for `<Wrapper>` component, e.g. to put some\n  content after pagination in `nextra-theme-docs`\n- 283320f: migrate to zustand v5\n- 283320f: remove `transition` for `transform` property when opening mobile nav\n- 283320f: avoid unnecessary updates to the config store on initial render\n- 283320f: reduce bundle size of bundled website by compiling svg icons in\n  separated files\n- 283320f: enable page reload of catch-all routes `app/[[...slug]].jsx` on\n  content change\n- 283320f: remove default value of `Navbar.logo`, now this prop is required\n- 283320f: remove false positive warnings on projects without `content/`\n  directory\n\n  ```\n  ⚠ Compiled with warnings\n\n  ../packages/nextra/dist/client/pages.js\n  Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client'\n  ```\n\n- 283320f: fix error goes from `playground.js` file when your `mdx-components`\n  file contain server-only components\n\n  ```\n  ./app/layout.tsx\n  'client-only' cannot be imported from a Server Component module. It should only be used from a Client Component.\n\n  Import trace for requested module:\n  ../packages/components/dist/index.js\n  ./mdx-components.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/remote-content.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/playground.js\n  ```\n\n- 283320f: - sync with nextra 3.0.15\n  - bump to Next 15\n  - remove importing of `style.css` in themes, you need to import now manually\n    by\n\n  ```js\n  import 'nextra-theme-docs/style.css' // for docs theme\n  import 'nextra-theme-blog/style.css' // for blog theme\n  ```\n\n- 283320f: add `normalizePagesResult.activeMetadata` to get value of front\n  matter or exported metadata from page\n- 283320f: add support for turbopack `next dev --turbopack`\n- 283320f: fix `colorSchema` for HEX format with 4 chars, e.g. `#111`\n- 283320f: fix external svg icon was added for span in `<Anchor>`\n- 283320f: remove `NormalizedResult.flatDirectories`\n\n  remove `Item.withIndexPage`, use `'frontMatter' in Item`\n\n- 283320f: sync with nextra 3.0.10\n- 283320f: defer pagefind results update for prioritizing the user input state\n- 283320f: make Nextra works with `src/app` and `src/content` directories\n- 283320f: - fix missing tailwind class for `json` icon in code blocks\n  - capitalize folders in sidebar even without index pages\n  - sync with nextra 3.2.4\n- 283320f: add ↗ char for external links\n- 283320f: sync with nextra 3.0.3\n- 283320f: fix injecting mdx-components into headings and injecting into toc\n- 283320f: add required `Layout.navbar`, `Layout.footer` props and optional\n  `Layout.banner` prop, you don't need to pass them as `children` now\n- 283320f: fix unclickable `type: menu` on mobile nav\n- 283320f: - add `disabled` prop for `<Folder>` component when `open` prop was\n  set (to disable click event and remove `cursor: pointer`)\n  - allow `<h5>` and `<h6>` tags be used with `<Steps>`\n  - fix Webpack module rebuild for pageMap when new files where added or removed\n    in `app` dir or `content` dir\n- 283320f: `firstChildRoute` should return \"index\" route as first\n- 283320f: Use `primaryColor` for `::selection` styles\n- 283320f: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean`\n- 283320f: support `GitHub Alert Syntax`\n- 283320f: fix search, didn't work with Next.js' `basePath` set\n- 283320f: fix click on the arrow icon in the folder item in the Sidebar, was\n  always consider clicked on `<a>` or `<button>` due `event.currentTarget`\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [fdd2c6a]\n- Updated dependencies [283320f]\n- Updated dependencies [aca79fa]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [e11dbe0]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n- Updated dependencies [283320f]\n  - nextra@4.0.0\n\n## 4.0.0-rc.0\n\n### Major Changes\n\n- 28796b4: release Nextra rc.0\n\n### Patch Changes\n\n- Updated dependencies [28796b4]\n  - nextra@4.0.0-rc.0\n\n## 4.0.0-app-router.43\n\n### Patch Changes\n\n- 50c2f76: add `bottomContent` prop for `<Wrapper>` component, e.g. to put some\n  content after pagination in `nextra-theme-docs`\n- 50c2f76: fix `colorSchema` for HEX format with 4 chars, e.g. `#111`\n- Updated dependencies [50c2f76]\n- Updated dependencies [50c2f76]\n  - nextra@4.0.0-app-router.43\n\n## 4.0.0-app-router.42\n\n### Patch Changes\n\n- 242e0d0: search tweaks\n- 3fc12a0: - Use Tailwind CSS CLI because CSS processing by `tsup` produce\n  different, weird and broken result\n  - Patch react-compiler with some fixes which isn't fixed\n- 25c33dd: - if `filePath` is falsy in client wrapper -> do not render\n  `edit on github` link\n  - if `filePath` starts with `http` do not append `docsRepositoryBase` prefix\n- Updated dependencies [242e0d0]\n- Updated dependencies [3fc12a0]\n  - nextra@4.0.0-app-router.42\n\n## 4.0.0-app-router.41\n\n### Patch Changes\n\n- 562c2b1: fix unclickable `type: menu` on mobile nav\n  - nextra@4.0.0-app-router.41\n\n## 4.0.0-app-router.40\n\n### Patch Changes\n\n- Updated dependencies [88135ec]\n  - nextra@4.0.0-app-router.40\n\n## 4.0.0-app-router.39\n\n### Patch Changes\n\n- Updated dependencies [711dbe7]\n  - nextra@4.0.0-app-router.39\n\n## 4.0.0-app-router.38\n\n### Patch Changes\n\n- Updated dependencies [42eb445]\n  - nextra@4.0.0-app-router.38\n\n## 4.0.0-app-router.37\n\n### Patch Changes\n\n- Updated dependencies [ad80ee1]\n  - nextra@4.0.0-app-router.37\n\n## 4.0.0-app-router.36\n\n### Patch Changes\n\n- Updated dependencies [739e9eb]\n- Updated dependencies [d805f2a]\n- Updated dependencies [0ab4ff1]\n  - nextra@4.0.0-app-router.36\n\n## 4.0.0-app-router.35\n\n### Minor Changes\n\n- e43a435: content width could be configured via CSS `--nextra-content-width`\n  variable\n\n### Patch Changes\n\n- Updated dependencies [96fb083]\n  - nextra@4.0.0-app-router.35\n\n## 4.0.0-app-router.34\n\n### Minor Changes\n\n- 6d22c8f: export a `style-prefixed.css` file with Tailwind CSS v4 prefixed\n  layers for projects using Tailwind CSS v3\n  - `@layer utilities` -> `@layer v4-utilities`\n  - `@layer base` -> `@layer v4-base`\n\n### Patch Changes\n\n- nextra@4.0.0-app-router.34\n\n## 4.0.0-app-router.33\n\n### Patch Changes\n\n- Updated dependencies [dd2e216]\n  - nextra@4.0.0-app-router.33\n\n## 4.0.0-app-router.32\n\n### Minor Changes\n\n- 2cd964f: compile sidebar components with react compiler\n\n### Patch Changes\n\n- fbeef15: setup `@typescript-eslint/no-unnecessary-condition` rule and fix\n  warnings\n- ea7bece: Add `nextra-mobile-nav` to `<MobileNav>`\n- Updated dependencies [fbeef15]\n  - nextra@4.0.0-app-router.32\n\n## 4.0.0-app-router.31\n\n### Patch Changes\n\n- Updated dependencies [386b620]\n  - nextra@4.0.0-app-router.31\n\n## 4.0.0-app-router.30\n\n### Patch Changes\n\n- f277a7a: fix search, didn't work with Next.js' `basePath` set\n- Updated dependencies [f277a7a]\n  - nextra@4.0.0-app-router.30\n\n## 4.0.0-app-router.29\n\n### Major Changes\n\n- 4bdf82d: - migrate to tailwind css v4.beta2\n  - refactor builtin CSS classes from `_` prefix to `x:` prefix\n  - remove `color-primary-750` theme color variant\n\n### Patch Changes\n\n- Updated dependencies [4bdf82d]\n  - nextra@4.0.0-app-router.29\n\n## 4.0.0-app-router.28\n\n### Patch Changes\n\n- 846552e: - fix missing tailwind class for `json` icon in code blocks\n  - capitalize folders in sidebar even without index pages\n  - sync with nextra 3.2.4\n- Updated dependencies [846552e]\n  - nextra@4.0.0-app-router.28\n\n## 4.0.0-app-router.27\n\n### Major Changes\n\n- 8a0ae0f: - add root `_meta.global.{js,jsx,ts,tsx}` file\n  > See\n  > [working example](https://github.com/shuding/nextra/blob/v4-v2/docs/app/_meta.global.ts)\n  > based on https://nextra.site website\n  - `getPageMap` now receive only 1 argument `root?: string = '/'` instead of 2\n    `lang?: string, route?: string = '/'`\n  - remove `createCatchAllMeta` from `nextra/catch-all`\n  - remove `collectCatchAllRoutes`\n  - remove `normalizePageRoute`\n  - add `mergeMetaWithPageMap` to `nextra/page-map`\n  - move adding `metadata.filePath`, `metadata.title` and `metadata.readingTime`\n    in remark plugin\n  - refactor recma rewrite plugin and add tests\n    - remove `recmaRewriteJsx`\n    - remove `recmaRewriteFunctionBody`\n  - make `convertPageMapToJs` sync\n\n### Patch Changes\n\n- 5e06f57: fix injecting mdx-components into headings and injecting into toc\n- Updated dependencies [8a0ae0f]\n- Updated dependencies [5e06f57]\n  - nextra@4.0.0-app-router.27\n\n## 4.0.0-app-router.26\n\n### Minor Changes\n\n- 0076bad: move TOC logic from `recma-rewrite-jsx` plugin to\n  `rehype-extract-toc-content` plugin\n\n### Patch Changes\n\n- be82724: Fixes when Turbopack is enabled:\n  `Module not found: Can't resolve '@theguild/remark-mermaid/mermaid'`\n- Updated dependencies [be82724]\n- Updated dependencies [0076bad]\n  - nextra@4.0.0-app-router.26\n\n## 4.0.0-app-router.25\n\n### Major Changes\n\n- c095f98: make `compileMdx` from `nextra/compile` return a `string` instead of\n  an `object`\n- 79bbab7: remove `export const title` from generated mdx pages\n- 33ee518: replace `export const useTOC = () = [/* your headings */]` by\n  `export const toc = [/* your headings */]`\n\n### Patch Changes\n\n- 3edc6d7: use `Date.now()` for last edit time on development and git last\n  commit time on production\n- fdbae45: initialize `transformerTwoslash` only 1 time outside of loader\n- Updated dependencies [c095f98]\n- Updated dependencies [79bbab7]\n- Updated dependencies [3edc6d7]\n- Updated dependencies [fdbae45]\n- Updated dependencies [33ee518]\n  - nextra@4.0.0-app-router.25\n\n## 4.0.0-app-router.24\n\n### Patch Changes\n\n- e46dbdf: Cache the result of `repository.getFileLatestModifiedDateAsync`\n  because it can slow down Fast Refresh for uncommitted files.\n- cc33237: avoid unnecessary updates to the config store on initial render\n- Updated dependencies [e46dbdf]\n  - nextra@4.0.0-app-router.24\n\n## 4.0.0-app-router.23\n\n### Patch Changes\n\n- 803e5be: migrate to zustand v5\n- 7212f88: remove `transition` for `transform` property when opening mobile nav\n- b2e44d3: make Nextra works with `src/app` and `src/content` directories\n- Updated dependencies [b2e44d3]\n  - nextra@4.0.0-app-router.23\n\n## 4.0.0-app-router.22\n\n### Patch Changes\n\n- 5f79b77: fix unable to select text and `::selection` style\n- 57fde3f: reduce bundle size of bundled website by compiling svg icons in\n  separated files\n- Updated dependencies [5f79b77]\n- Updated dependencies [57fde3f]\n  - nextra@4.0.0-app-router.22\n\n## 4.0.0-app-router.21\n\n### Major Changes\n\n- 730899e: - add `nextra/components` to `experimental.optimizePackageImports` to\n  optimize `nextra/components` by default\n  - remove `<RemoteContent>` from `nextra/components`\n  - rename `<RemoteContent>` to `MDXRemote` and move to `nextra/mdx-remote`\n\n### Patch Changes\n\n- 4e02ef3: fix error goes from `playground.js` file when your `mdx-components`\n  file contain server-only components\n\n  ```\n  ./app/layout.tsx\n  'client-only' cannot be imported from a Server Component module. It should only be used from a Client Component.\n\n  Import trace for requested module:\n  ../packages/components/dist/index.js\n  ./mdx-components.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/remote-content.js\n  ../node_modules/.pnpm/nextra@4.0.0-app-router.20_@types+react@18.3.12_acorn@8.14.0_next@15.0.2_@babel+core@7.26.0_r_73lkrljx3r7g5vsm2cmbm3erma/node_modules/nextra/dist/client/components/playground.js\n  ```\n\n- 0d74f68: fix external svg icon was added for span in `<Anchor>`\n- Updated dependencies [4e02ef3]\n- Updated dependencies [0d74f68]\n- Updated dependencies [730899e]\n  - nextra@4.0.0-app-router.21\n\n## 4.0.0-app-router.20\n\n### Major Changes\n\n- 16816f2: remove `<Th>`, `<Tr>` and `<Td>` exports (since they should be always\n  used with `<Table>` component)\n\n  ```diff\n  - import { Table, Th, Tr, Td } from 'nextra/components'\n  + import { Table } from 'nextra/components'\n\n  // ...\n\n  - <Th>\n  + <Table.Th>\n  - <Tr>\n  + <Table.Tr>\n  - <Td>\n  + <Table.Td>\n  ```\n\n- 0a63ba3: improve performance on projects without Turbopack enabled\n\n### Minor Changes\n\n- 2bd6f41: include `document.referrer` in link in `<NotFoundPage>` component\n\n### Patch Changes\n\n- 7cc8ca1: simplify `generatePageMap`\n- 16816f2: remove false positive warnings on projects without `content/`\n  directory\n\n  ```\n  ⚠ Compiled with warnings\n\n  ../packages/nextra/dist/client/pages.js\n  Module not found: Can't resolve 'private-next-root-dir/content' in '/Users/dmytro/Desktop/nextra/packages/nextra/dist/client'\n  ```\n\n- b873702: `firstChildRoute` should return \"index\" route as first\n- Updated dependencies [3d8705c]\n- Updated dependencies [16816f2]\n- Updated dependencies [27454c4]\n- Updated dependencies [7cc8ca1]\n- Updated dependencies [aa94d91]\n- Updated dependencies [0a63ba3]\n- Updated dependencies [71a051b]\n- Updated dependencies [0a63ba3]\n- Updated dependencies [16816f2]\n- Updated dependencies [b873702]\n  - nextra@4.0.0-app-router.20\n\n## 4.0.0-app-router.19\n\n### Patch Changes\n\n- Updated dependencies [a3627e5]\n  - nextra@4.0.0-app-router.19\n\n## 4.0.0-app-router.18\n\n### Minor Changes\n\n- 439466a: replace `useContentDir` with `contentDirBasePath` option which\n  configure `content` directory under a catch-all subdirectory\n- b00a560: make `page.{jsx,tsx,mdx}` pages and `_meta` files from `app` dir, and\n  also `content` folder files - all add to `pageMap`, but ignore dynamic pages\n  `[[`\n\n### Patch Changes\n\n- a074a99: add `whiteListTagsStyling` nextra config option\n- Updated dependencies [a074a99]\n- Updated dependencies [439466a]\n- Updated dependencies [b00a560]\n  - nextra@4.0.0-app-router.18\n\n## 4.0.0-app-router.17\n\n### Patch Changes\n\n- 7a48610: export `setMenu`\n- 33568c1: add `normalizePagesResult.activeMetadata` to get value of front\n  matter or exported metadata from page\n- Updated dependencies [33568c1]\n  - nextra@4.0.0-app-router.17\n\n## 4.0.0-app-router.16\n\n### Minor Changes\n\n- ab21db7: - use ReactIcon for code blocks with `jsx`, `tsx` language\n  - add JsonIcon for `json` language\n  - parse language from filename if exist when `diff` language is specified\n  - use JavaScript icon for `cjs` and `mjs`\n  - use TypeScript icon for `cts` and `mts`\n\n### Patch Changes\n\n- 0540e6c: - add `disabled` prop for `<Folder>` component when `open` prop was\n  set (to disable click event and remove `cursor: pointer`)\n  - allow `<h5>` and `<h6>` tags be used with `<Steps>`\n  - fix Webpack module rebuild for pageMap when new files where added or removed\n    in `app` dir or `content` dir\n- Updated dependencies [ab21db7]\n- Updated dependencies [0540e6c]\n- Updated dependencies [5b47509]\n  - nextra@4.0.0-app-router.16\n\n## 4.0.0-app-router.15\n\n### Minor Changes\n\n- 367293e: add opacity animation for `:target` state for headings h2-h6\n\n### Patch Changes\n\n- nextra@4.0.0-app-router.15\n\n## 4.0.0-app-router.14\n\n### Major Changes\n\n- be19dd4: remove `\"typesVersions\"` field from `package.json`. You need to set\n  `\"moduleResolution\": \"bundler\"` in your `tsconfig.json` if you are using\n  TypeScript\n\n### Patch Changes\n\n- 9ca1765: fix mobile nav position\n- 2b41ec7: remove default value of `Navbar.logo`, now this prop is required\n- Updated dependencies [be19dd4]\n  - nextra@4.0.0-app-router.14\n\n## 4.0.0-app-router.13\n\n### Major Changes\n\n- 54657e2: require Next.js minimum v15\n\n### Patch Changes\n\n- 3ade013: - remove `nextra/context`\n  - remove `type NextraThemeLayoutProps`\n- ddc39cc: - parse and transform `_meta` files with zod\n  - remove `_meta` `newWindow` field\n- 54657e2: allow `editLink`/`feedback.content`/`search`/`toc.backToTop` be\n  `null` as value\n- 07213e2: add support for turbopack `next dev --turbopack`\n- 54657e2: add required `Layout.navbar`, `Layout.footer` props and optional\n  `Layout.banner` prop, you don't need to pass them as `children` now\n- Updated dependencies [3ade013]\n- Updated dependencies [ddc39cc]\n- Updated dependencies [07213e2]\n- Updated dependencies [54657e2]\n  - nextra@4.0.0-app-router.13\n\n## 4.0.0-app-router.12\n\n### Patch Changes\n\n- b8defc9: sync with nextra 3.1.0\n- b8defc9: remove `NormalizedResult.flatDirectories`\n\n  remove `Item.withIndexPage`, use `'frontMatter' in Item`\n\n- Updated dependencies [b8defc9]\n- Updated dependencies [b8defc9]\n  - nextra@4.0.0-app-router.12\n\n## 4.0.0-app-router.11\n\n### Patch Changes\n\n- be15165: move `pagefind` output to `public/_pagefind` directory\n  https://github.com/shuding/nextra/pull/3517\n- Updated dependencies [be15165]\n  - nextra@4.0.0-app-router.11\n\n## 4.0.0-app-router.10\n\n### Patch Changes\n\n- 8b1a7c9: defer pagefind results update for prioritizing the user input state\n- Updated dependencies [8b1a7c9]\n  - nextra@4.0.0-app-router.10\n\n## 4.0.0-app-router.9\n\n### Patch Changes\n\n- 2c8a8ab: - sync with nextra 3.0.15\n  - bump to Next 15\n  - remove importing of `style.css` in themes, you need to import now manually\n    by\n\n  ```js\n  import 'nextra-theme-docs/style.css' // for docs theme\n  import 'nextra-theme-blog/style.css' // for blog theme\n  ```\n\n- Updated dependencies [2c8a8ab]\n  - nextra@4.0.0-app-router.9\n\n## 4.0.0-app-router.8\n\n### Patch Changes\n\n- 3ce535b: Add aria attrs to the sidebar collapse button\n- 9832af9: add ↗ char for external links\n- ec39959: Use `primaryColor` for `::selection` styles\n- 875842b: support `GitHub Alert Syntax`\n- 47c62c8: fix click on the arrow icon in the folder item in the Sidebar, was\n  always consider clicked on `<a>` or `<button>` due `event.currentTarget`\n- Updated dependencies [9832af9]\n- Updated dependencies [ec39959]\n- Updated dependencies [875842b]\n  - nextra@4.0.0-app-router.8\n\n## 4.0.0-app-router.7\n\n### Patch Changes\n\n- 5201e5f: add helpful error message about not available search on development\n  mode\n- 3ac2c32: add `getPageMap` helper function from `nextra/page-map`\n- b4ca36d: - allow override/add additional icons for code blocks\n  - remove `nextraConfig.mdxOptions.providerImportSource` option in favour of\n    `mdx-components` file\n- 73726ec: - Simplify the class-name of the sidebar file item\n  - fix unclosable active folder when it's `<button>` element and not `<a>`\n  - improve `<Collapse>` to add inner `<div>` only if children != 1\n- 4768dee: replace `nextraConfig.mdxBaseDir: string` by `useContentDir: boolean`\n- Updated dependencies [5201e5f]\n- Updated dependencies [3ac2c32]\n- Updated dependencies [b4ca36d]\n- Updated dependencies [4768dee]\n  - nextra@4.0.0-app-router.7\n\n## 4.0.0-app-router.6\n\n### Patch Changes\n\n- 2092d5e: enable page reload of catch-all routes `app/[[...slug]].jsx` on\n  content change\n- a97e5cf: sync with nextra 3.0.10\n- Updated dependencies [2092d5e]\n- Updated dependencies [a97e5cf]\n  - nextra@4.0.0-app-router.6\n\n## 4.0.0-app-router.5\n\n### Patch Changes\n\n- a15a02d: sync with nextra 3.0.3\n- Updated dependencies [659b36e]\n- Updated dependencies [a15a02d]\n  - nextra@4.0.0-app-router.5\n\n## 4.0.0-app-router.4\n\n### Major Changes\n\n- 17e6da5: remove `i18n.direction` option\n- 0faa569: replace `gitTimestamp` option with `lastUpdated`\n\n  replace `editLink.content` option with `editLink`\n\n- 17e6da5: document removed theme config options\n  - `main`\n  - `direction`\n  - `toc.component`\n  - `themeSwitch.component`\n  - `themeSwitch.useOptions`\n  - `search.component`\n  - `feedback.useLink`\n  - `banner.dismissible`\n  - `banner.key`\n  - `banner.content`\n  - `footer.content`\n  - `footer.component`\n  - `head`\n  - `navbar.component`\n  - `navbar.extraContent`\n  - `project.link`\n  - `project.icon`\n  - `chat.link`\n  - `chat.icon`\n  - `search.emptyResult`\n  - `search.loading`\n  - `search.errorText`\n  - `search.placeholder`\n  - `search.className`\n\n  refactor `themeSwitch.useOptions` to `themeSwitch` option\n\n  refactor `editLink.content` to `editLink` option\n\n  rename Search prop `error` to `errorText`\n\n### Patch Changes\n\n- nextra@4.0.0-app-router.4\n\n## 4.0.0-app-router.3\n\n### Major Changes\n\n- 1e77fab: move `<Collapse>`, `<Details>`, `<Summary>`, `<SkipNavContent>`,\n  `SkipNavLink`, `<Select>` and `<Bleed>` from `nextra-theme-docs` to\n  `nextra/components`\n- 1e77fab: remove `renderComponent` and `renderString`\n\n### Patch Changes\n\n- 1e77fab: fix edit on github and last updated at for catch all routes\n- Updated dependencies [1e77fab]\n- Updated dependencies [1e77fab]\n- Updated dependencies [1e77fab]\n- Updated dependencies [1e77fab]\n  - nextra@4.0.0-app-router.3\n\n## 4.0.0-app-router.2\n\n### Major Changes\n\n- 215aa08: fix focusing on first search result item\n- 1c83931: remove `navbar` and `footer` props, pass `<Navbar>` and `<Footer>` as\n  children of `<Layout>`\n- 724f851: migrate from react context to zustand\n- 8ef0f58: move `<Head>` component in `nextra/components`\n- ee4a467: remove `feedback.useLink` and `editLink.component` option, remove\n  `themeConfig` prop on `<Layout>` component\n\n  change `gitTimestamp` option to boolean\n\n  remove `nextraCofig.transform` option\n\n- 62f1553: support `<Head>`'s `backgroundColor.dark/light` props colors in\n  `rgb(...,...,...)` and `#RRGGBB` formats\n\n### Minor Changes\n\n- 8f90ed5: refactor `useMenuActions` to `setMenu`, `useFocusedRouteActions` to\n  `setFocusedRoute`\n\n### Patch Changes\n\n- Updated dependencies [215aa08]\n- Updated dependencies [8ef0f58]\n  - nextra@4.0.0-app-router.2\n\n## 4.0.0-app-router.1\n\n### Major Changes\n\n- 26851b5: migrate search from Flexsearch to Pagefind\n\n### Patch Changes\n\n- Updated dependencies [26851b5]\n  - nextra@4.0.0-app-router.1\n\n## 4.0.0-app-router.0\n\n### Major Changes\n\n- 99f34d3: The initial version which supports App Router instead of Pages\n  Router, something may be broken, check\n  https://github.com/shuding/nextra/tree/v4-v2/examples for the migration guide\n\n### Patch Changes\n\n- Updated dependencies [99f34d3]\n  - nextra@4.0.0-app-router.0\n\n## 3.3.1\n\n### Patch Changes\n\n- bfa61d9: add `text-overflow: ellipsis` for `<Cards.Card>` component\n- Updated dependencies [bfa61d9]\n  - nextra@3.3.1\n\n## 3.3.0\n\n### Minor Changes\n\n- ee69234: add\n  [image zoom feature](http://nextra.site/docs/guide/image#image-zoom) for all\n  images written via [GFM syntax](https://github.github.com/gfm/#images) in\n  md/mdx files (except images inside links)\n\n### Patch Changes\n\n- Updated dependencies [ee69234]\n  - nextra@3.3.0\n\n## 3.2.5\n\n### Patch Changes\n\n- Updated dependencies [2f5d954]\n  - nextra@3.2.5\n\n## 3.2.4\n\n### Patch Changes\n\n- Updated dependencies [a4b0bbb]\n  - nextra@3.2.4\n\n## 3.2.3\n\n### Patch Changes\n\n- Updated dependencies [50f33f3]\n  - nextra@3.2.3\n\n## 3.2.2\n\n### Patch Changes\n\n- 45cccd4: allow passing `className` for `<Tabs>` and `<Tabs.Tab>`\n- Updated dependencies [45cccd4]\n  - nextra@3.2.2\n\n## 3.2.1\n\n### Patch Changes\n\n- 9154c2f: fix(nextra-theme-docs): incorrect makePrimaryColor relative value for\n  tailwind primary.900\n- 8a21a77: - Change hamburger menu animation speed\n\n  Google Core Web Vitals rolled out a new\n  [INP](https://developers.google.com/search/blog/2023/05/introducing-inp) score\n  The mobile hamburger menu would occasionally get flagged for \"need\n  improvement\"\n  - nextra@3.2.1\n\n## 3.2.0\n\n### Minor Changes\n\n- d755012: feat(nextra-theme-docs): add new theme config option\n  `color.lightness`\n\n### Patch Changes\n\n- nextra@3.2.0\n\n## 3.1.3\n\n### Patch Changes\n\n- 6e64b16: fix\n  `Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No \"exports\" main defined in /path/to/project/node_modules/nextra/package.json`\n  when using `next.config.ts`\n- d44c4bc: requires to have a custom App component (`pages/_app.jsx`)\n- 24f9806: fix folder's index page was not merged with folder itself for some\n  edge case\n- Updated dependencies [6e64b16]\n- Updated dependencies [d44c4bc]\n- Updated dependencies [24f9806]\n  - nextra@3.1.3\n\n## 3.1.2\n\n### Patch Changes\n\n- Updated dependencies [9c78588]\n  - nextra@3.1.2\n\n## 3.1.1\n\n### Patch Changes\n\n- 68633e5: fix: Improve Twoslash Popover Display\n- Updated dependencies [68633e5]\n  - nextra@3.1.1\n\n## 3.1.0\n\n### Minor Changes\n\n- 8e9767e: `activeType` should be initialized from `meta['*']`\n- fec399a: fix `type: 'separator'`, `type: 'menu'` and `item` with `href` not\n  respecting order when not all pages specified in `_meta` file\n\n### Patch Changes\n\n- 035fe48: - fix empty dropdown menu when \\_meta item with `type: \"menu\"`\n  contains items with local pages\n- c002118: - add tests for should respect order for `type: \"separator\"`,\n  `type: \"menu\"` and item with `href`\n- Updated dependencies [035fe48]\n- Updated dependencies [8e9767e]\n- Updated dependencies [fec399a]\n- Updated dependencies [c002118]\n  - nextra@3.1.0\n\n## 3.1.0-canary.1\n\n### Minor Changes\n\n- 8e9767e: `activeType` should be initialized from `meta['*']`\n\n### Patch Changes\n\n- 035fe48: - fix empty dropdown menu when \\_meta item with `type: \"menu\"`\n  contains items with local pages\n- c002118: - add tests for should respect order for `type: \"separator\"`,\n  `type: \"menu\"` and item with `href`\n- Updated dependencies [035fe48]\n- Updated dependencies [8e9767e]\n- Updated dependencies [c002118]\n  - nextra@3.1.0-canary.1\n\n## 3.1.0-canary.0\n\n### Minor Changes\n\n- fec399a: fix `type: 'separator'`, `type: 'menu'` and `item` with `href` not\n  respecting order when not all pages specified in `_meta` file\n\n### Patch Changes\n\n- Updated dependencies [fec399a]\n  - nextra@3.1.0-canary.0\n\n## 3.0.15\n\n### Patch Changes\n\n- Updated dependencies [bd498c6]\n  - nextra@3.0.15\n\n## 3.0.14\n\n### Patch Changes\n\n- 9794e9e: Fix `frontMatter.sidebarTitle` didn't affect without\n  `frontMatter.title` set\n\n  now priority for sidebar title is:\n  1. `title` property from `_meta` file\n  1. `frontMatter.sidebarTitle`\n  1. `frontMatter.title`\n  1. formatted with [Title](https://title.sh) based on filename\n\n- Updated dependencies [6454938]\n- Updated dependencies [9794e9e]\n- Updated dependencies [9794e9e]\n  - nextra@3.0.14\n\n## 3.0.13\n\n### Patch Changes\n\n- f1815ac: From an accessibility POV (WCAG G13) there's a need of additional\n  visual differentiation factor for hovers. Article achieves this but mdx\n  doesn't.\n\n  So changing the mdx link behaviour so on hover the underline disappears.\n  - nextra@3.0.13\n\n## 3.0.12\n\n### Patch Changes\n\n- 7e0093f: Fix `nextra/locales` middleware, redirect to the docs URL relative to\n  the `/<basePath>`.\n- Updated dependencies [7e0093f]\n  - nextra@3.0.12\n\n## 3.0.11\n\n### Patch Changes\n\n- Updated dependencies [e0a9303]\n  - nextra@3.0.11\n\n## 3.0.10\n\n### Patch Changes\n\n- Updated dependencies [31de764]\n- Updated dependencies [161d350]\n  - nextra@3.0.10\n\n## 3.0.9\n\n### Patch Changes\n\n- Updated dependencies [f9cc160]\n  - nextra@3.0.9\n\n## 3.0.8\n\n### Patch Changes\n\n- 72c84eb: add `max-md:_overflow-hidden` instead of `_overflow-hidden` when\n  hamburger is clicked\n- 1530239: hide `<summary>` marker on Safari\n- 210d68a: trigger scrolling when the TOC item is outside the viewport\n- bf04f96: add ring-inset for navbar links\n  - nextra@3.0.8\n\n## 3.0.7\n\n### Patch Changes\n\n- Updated dependencies [4bbc1fe]\n  - nextra@3.0.7\n\n## 3.0.6\n\n### Patch Changes\n\n- 4ed7b4b: remove extra horizontal margin spacing in toc\n  - nextra@3.0.6\n\n## 3.0.5\n\n### Patch Changes\n\n- 3aac732: Add `.nextra-search-results` class back\n  - nextra@3.0.5\n\n## 3.0.4\n\n### Patch Changes\n\n- 84fc255: should get right `activeType`, `activeThemeContext` even when some\n  parent has `display: 'hidden'`\n- 9b6595d: Ensure the jump link behavior is consistent in Markdown.\n- f3a5575: add a scrollbar for nav links in the header when they exceed\n  available free space\n- Updated dependencies [84a8a41]\n- Updated dependencies [659b36e]\n- Updated dependencies [84fc255]\n  - nextra@3.0.4\n\n## 3.0.3\n\n### Patch Changes\n\n- 9d93caf: RTL support for the `<Steps>` component.\n- 5fbce2f: Added golang logo for code blocks.\n- Updated dependencies [82fc267]\n- Updated dependencies [edc6c29]\n- Updated dependencies [9d93caf]\n- Updated dependencies [5fbce2f]\n  - nextra@3.0.3\n\n## 3.0.2\n\n### Patch Changes\n\n- 991b69a: handle empty `item.route` in `<FolderImpl` in `<Sidebar>` for\n  `item.type: 'menu'`\n- Updated dependencies [b6341f7]\n  - nextra@3.0.2\n\n## 3.0.1\n\n### Patch Changes\n\n- d9d0820: fix unclickable links on mobile\n  - nextra@3.0.1\n\n## 3.0.0\n\n### Major Changes\n\n- e7e8e84: show react components, variable interpolation and latex in toc\n- c7f03e5: remove `toc.headingComponent`\n- ea1a736: remove `next-seo` and `useNextSeoProps`, use `head` option instead\n- c2ad837: update to MDX3\n- 148278c: rename tailwind prefix `nx-` to `_` to reduce bundle size\n- 919fe97: set `\"peerDependencies.next\": \">=13\"`\n- 47b125d: fix global style conflicts for\n  `<a>`/`<button>`/`<summary>`/`<input>`/`[tabindex]:not([tabindex='-1']`\n- ba30c6c: use render props for className with `selected`, `disabled` and\n  `hover` state for `<Tab>`\n- d7d8a3e: new styles for code blocks aka in next.js\n- 2872606: remove `image` prop from `<Card>` component, image will be showed\n  based on truthiness `children` prop now\n\n  set `icon` as optional prop\n\n- 63ca28b: Remove support of \"\\_meta.json\", use \"\\_meta.{js,jsx,ts,tsx}\"\n  instead.\n- ebe652d: remove `sidebar.titleComponent`, use JSX for styling separators and\n  titles\n- eca7535: - remove `Steps`, `Callout`, `Tabs`, `Tab`, `Cards`, `Card`,\n  `FileTree` exports, export them now from `nextra/components`\n  - remove `useMDXComponents` export, export it now from `nextra/mdx`\n  - set by default `sidebar.toggleButton` to true\n\n- 128e195: fix React warning, remove PageOpts.toc, use `toc` prop from\n  `components.wrapper`\n- 63ca28b: remove `config.serverSideError`\n- f2dd18d: - rename theme config options\n\n  `i18n.text` → `i18n.name`\n\n  `banner.text` → `banner.content`\n\n  `editLink.text` → `editLink.content`\n\n  `footer.text` → `footer.content`\n\n- 198dbcc: use toc with JSX elements for remote content\n- 191e6c4: - use `shikiji` instead of `shiki`\n  - rename `useSSG` to `useData`\n\n- 6eb3118: rename `primaryHue` and `primarySaturation` theme options to\n  `color.hue` and `color.saturation`\n- c7f03e5: rename `pageOpts.headings` to `toc`\n- 8c1b9d5: remove `<MatchSorterSearch>`\n\n### Minor Changes\n\n- eb943d0: add `theme.topContent` and `theme.bottomContent`\n- 0fe55db: add `import { useRouter } from 'nextra/hooks'` for fetching `locale`\n  and `defaultLocale`\n- c77485e: set default `head` option as `null`\n- 1dcb91a: export `useThemeConfig`\n- 6ec3241: Add Terraform/Move icon https://github.com/shuding/nextra/pull/2811\n  https://github.com/shuding/nextra/pull/2808\n- 5a63701: add icons for following languages:\n  - GraphQL (`graphql`)\n  - C++ (`c++`, `cpp`)\n  - C# (`csharp`, `c#`, `cs`)\n  - Python (`python`, `py`)\n\n  allow disallow mobile word wrap button in code blocks with `word-wrap=false`\n  meta data setting\n\n- a52a869: add `frontmatter.sidebarTitle` support for setting page label in\n  sidebar via frontmatter\n- 6ec3241: Make the `<Tab>` component be crawlable and indexable by search\n  engines by default\n- b47880d: export `useMenu` hook\n- b776b16: add `backgroundColor.light` and `backgroundColor.dark` theme options\n- 6070b02: rename `frontmatter.sidebar_label` to `frontmatter.sidebarTitle`\n- 3043826: add shikiji twoslash\n\n  Demo feature:\n  https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support\n\n- 6070b02: move `removeLinks` function from `nextra-theme-docs` to\n  `nextra/remove-links`\n- 962cea6: allow `items: Map` for `type: 'menu'` since object can't guaranty the\n  insertion order\n- 440ff42: add MathJax support\n- 1a97327: keep `loading`, `placeholder` and `themeSwitch.useOptions` default\n  theme options only for `en` lang\n\n### Patch Changes\n\n- b045cc3: fix invisible mobile menu after click on hamburger\n- eeb4c4c: enable `outline: 'none'` only for `:focus-visible` state, to fix\n  double ring in Firefox\n- 376b895: fixes case when setting `disabled: true` on the scroll to top button\n  prevents scrolling to most top\n\n  scroll to most top in toc element too\n\n- 34e25cd: migrate search to `@headlessui/react` Combobox\n- 73239c4: To ensure consistent horizontal padding, set the default language as\n  plaintext for code blocks. This prevents any loss of formatting for code\n  blocks without a specified language.\n- 57f3963: Remove intersection-observer polyfill\n- 2b9b95b: migrate to `@headlessui/react` v2\n- 7457d6b: remove `git-url-parse` to keep bundle smaller\n- 2a3e3e7: Fix first list item in `<FileTree>` not within permitted parent\n  elements\n- 6070b02: load `flexsearch` dynamically to reduce bundle size\n- 0b4d43b: Avoid the sidebar collapse having unintended animations when\n  `sidebar.autoCollapse` is set to `true`.\n- 31c2ee7: fix `removeLinks` when input node is link\n- bf963cd: Remove the aria-hidden attribute from scroll-to-top button when it is\n  visible\n- 829c417: - fix overflow when clicking on `<details>` with open state\n  - fix animation on mobile when clicking on `<details>` with open state\n\n- cb24790: fix broken `export default` statement in mdx files\n- de56507: fix vertical margin for nested ordered `<ol>` and unordered `<ul>`\n  lists\n- 8c99baf: enhance search input to better support CJK language users\n- a8c2196: use dynamic import for loading `mermaid`\n- 0b5cc9d: make nextra compatible with windows\n- 7b0b7e9: fix page scroll jump while entering characters in the search input\n- 45471df: fix \"Scroll to top\" is not supposed to be interactable when it is\n  hidden.\n\n  `display:children` doesn't collapse breadcrumbs\n\n  hide external links from pagination\n\n  remove xmlns attribute from icons\n\n- 8ffe2fe: remove focus-visible polyfill\n- fe5061b: fix for remote docs\n- 6945f38: fix not rendered default `<meta name=\"description\" />` and\n  `<meta property=\"og:description\" />`\n- 1a634cd: remove explicit `ZodError` assertion\n- ad108ff: use `overflow-x-auto` instead `overflow-x-scroll` for `<Table>`\n- 4f0f6b2: Omit `...{:type}` inline code annotations from search index #2922\n- 150184b: attach heading anchor `id` attribute to heading (like Pagefind do)\n  and fix heading anchor styles when `theme.typesetting: 'article'` is set\n- 80c9764: ensure zod is removed from production build with `/* @__PURE__ */`\n  comments\n- 9df7f58: Fix nav-links not highlighting on hover in dark mode\n- 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to\n  improve type inference.\n- 9b41180: `backToTop` is hidden when enabled but when `toc.extraContent`,\n  `feedback.content` and `editLink.component` are falsy\n- 6f4c83a: fix unclickable links in TOC\n\n  allow passing `recmaPlugins` in `mdxOptions`\n\n- f255696: Improve styles for reduced motion preferences\n- 9f55bd1: update rehype-pretty-code/shikiji to latest\n- d21634d: export `getComponents`\n- 452e5bd: Add `<Playground>` component\n\n  https://nextra-v2-9x7fp6hti-shud.vercel.app/docs/guide/advanced/playground\n\n- e95faa1: - fixed `<summary>` lost whitespaces when there is some HTML element\n  inside\n  - fixed hydration errors and `<summary>` was not rendered when `<details>`\n    text content follows directly after `<summary>` element\n\n- ccaf3d4: Add the `autoImportThemeStyle` option to the Nextra configuration.\n  This allows users to import the official Nextra theme CSS into a specific\n  cascade layer.\n- cee94a6: Consider the navbar height when setting the root margin for the\n  active anchor intersection observer\n- 2630461: fix\n  `TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))`\n  on dev environment when `frontMatter.searchable: false`\n- 217f708: update next-themes\n\n  fix wrong numbering for nested `<Steps>`\n\n- ca51306: Enhance focus ring style consistency.\n- f662237: avoid focus-visible style being cut off by overflow-hidden\n- 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts`\n- 1a97327: Update the `backToTop` option in the docs theme configuration to\n  support i18n\n- 799174f: fixed react warning\n  `Warning: React has detected a change in the order of Hooks called by Body`\n  when `themeConfig.main` options is used\n- 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `<Ident>` and svg\n  icons in `<Folder>` and `<File>`\n- 237c345: Make React 18 as minimal requirement\n- eb943d0: hardcode flexsearch version to 0.7.31, because package is broken on\n  0.7.41\n- ad108ff: fix `<Bleed>` overflows incorrectly in firefox\n- 4fb2452: fix invisible mobile menu when `layout: \"raw\"` is specified in \\_meta\n  file\n- 7faa096: fix visible hidden pages on mobile which set up with\n  `display: 'hidden'`\n- 315ca82: remove possible links in toc elements\n- a95e745: Fix the line highlighting background-color does not extend to the\n  full width of the code block when a scrollbar appears with line numbers.\n- 363b85f: fix `RangeError: Maximum call stack size exceeded` in `findSummary`\n  when `child.props.children` is `undefined`\n- Updated dependencies [e7e8e84]\n- Updated dependencies [7188278]\n- Updated dependencies [d1e3e9a]\n- Updated dependencies [73239c4]\n- Updated dependencies [2b9b95b]\n- Updated dependencies [023d37b]\n- Updated dependencies [0fe55db]\n- Updated dependencies [50a52fd]\n- Updated dependencies [c2ad837]\n- Updated dependencies [2a3e3e7]\n- Updated dependencies [a3b67ae]\n- Updated dependencies [1a36469]\n- Updated dependencies [799174f]\n- Updated dependencies [98f439c]\n- Updated dependencies [6ec3241]\n- Updated dependencies [148278c]\n- Updated dependencies [c7f03e5]\n- Updated dependencies [3644e1c]\n- Updated dependencies [919fe97]\n- Updated dependencies [cb24790]\n- Updated dependencies [47b125d]\n- Updated dependencies [982862f]\n- Updated dependencies [a8c2196]\n- Updated dependencies [ba30c6c]\n- Updated dependencies [0b5cc9d]\n- Updated dependencies [5a63701]\n- Updated dependencies [60ec68c]\n- Updated dependencies [d7d8a3e]\n- Updated dependencies [fe5061b]\n- Updated dependencies [2872606]\n- Updated dependencies [a52a869]\n- Updated dependencies [6ec3241]\n- Updated dependencies [1a634cd]\n- Updated dependencies [63ca28b]\n- Updated dependencies [ad108ff]\n- Updated dependencies [ad4823d]\n- Updated dependencies [4f0f6b2]\n- Updated dependencies [1f3e7cd]\n- Updated dependencies [ab07609]\n- Updated dependencies [2f3be33]\n- Updated dependencies [90c129e]\n- Updated dependencies [f71e660]\n- Updated dependencies [150184b]\n- Updated dependencies [66cce1d]\n- Updated dependencies [c74ae90]\n- Updated dependencies [7615b62]\n- Updated dependencies [6070b02]\n- Updated dependencies [7bb18e3]\n- Updated dependencies [b9f88e3]\n- Updated dependencies [8efbb45]\n- Updated dependencies [6f4c83a]\n- Updated dependencies [d8a406b]\n- Updated dependencies [9f55bd1]\n- Updated dependencies [4e55c06]\n- Updated dependencies [128e195]\n- Updated dependencies [8bce16d]\n- Updated dependencies [ccaf3d4]\n- Updated dependencies [3043826]\n- Updated dependencies [2630461]\n- Updated dependencies [576cb6f]\n- Updated dependencies [217f708]\n- Updated dependencies [57bc0e2]\n- Updated dependencies [ca51306]\n- Updated dependencies [f662237]\n- Updated dependencies [3c6193d]\n- Updated dependencies [1f3e7cd]\n- Updated dependencies [198dbcc]\n- Updated dependencies [363b85f]\n- Updated dependencies [fef635e]\n- Updated dependencies [6070b02]\n- Updated dependencies [237c345]\n- Updated dependencies [191e6c4]\n- Updated dependencies [440ff42]\n- Updated dependencies [7faa096]\n- Updated dependencies [9099c35]\n- Updated dependencies [98f439c]\n- Updated dependencies [a95e745]\n- Updated dependencies [80e11e0]\n- Updated dependencies [c7f03e5]\n  - nextra@3.0.0\n\n## 3.0.0-alpha.42\n\n### Minor Changes\n\n- 1a97327: keep `loading`, `placeholder` and `themeSwitch.useOptions` default\n  theme options only for `en` lang\n\n### Patch Changes\n\n- ca51306: Enhance focus ring style consistency.\n- 1a97327: Update the `backToTop` option in the docs theme configuration to\n  support i18n\n- Updated dependencies [ca51306]\n  - nextra@3.0.0-alpha.42\n\n## 3.0.0-alpha.41\n\n### Patch Changes\n\n- 237c345: Make React 18 as minimal requirement\n- Updated dependencies [237c345]\n  - nextra@3.0.0-alpha.41\n\n## 3.0.0-alpha.40\n\n### Patch Changes\n\n- bf963cd: Remove the aria-hidden attribute from scroll-to-top button when it is\n  visible\n- cee94a6: Consider the navbar height when setting the root margin for the\n  active anchor intersection observer\n- Updated dependencies [982862f]\n  - nextra@3.0.0-alpha.40\n\n## 3.0.0-alpha.39\n\n### Major Changes\n\n- 47b125d: fix global style conflicts for\n  `<a>`/`<button>`/`<summary>`/`<input>`/`[tabindex]:not([tabindex='-1']`\n- ba30c6c: use render props for className with `selected`, `disabled` and\n  `hover` state for `<Tab>`\n- 2872606: remove `image` prop from `<Card>` component, image will be showed\n  based on truthiness `children` prop now\n\n  set `icon` as optional prop\n\n### Patch Changes\n\n- f255696: Improve styles for reduced motion preferences\n- Updated dependencies [47b125d]\n- Updated dependencies [ba30c6c]\n- Updated dependencies [2872606]\n  - nextra@3.0.0-alpha.39\n\n## 3.0.0-alpha.38\n\n### Patch Changes\n\n- ccaf3d4: Add the `autoImportThemeStyle` option to the Nextra configuration.\n  This allows users to import the official Nextra theme CSS into a specific\n  cascade layer.\n- Updated dependencies [ccaf3d4]\n  - nextra@3.0.0-alpha.38\n\n## 3.0.0-alpha.37\n\n### Patch Changes\n\n- 2a3e3e7: Fix first list item in `<FileTree>` not within permitted parent\n  elements\n- 829c417: - fix overflow when clicking on `<details>` with open state\n  - fix animation on mobile when clicking on `<details>` with open state\n\n- Updated dependencies [2a3e3e7]\n  - nextra@3.0.0-alpha.37\n\n## 3.0.0-alpha.36\n\n### Patch Changes\n\n- 34e25cd: migrate search to `@headlessui/react` Combobox\n- 57f3963: Remove intersection-observer polyfill\n- 2b9b95b: migrate to `@headlessui/react` v2\n- Updated dependencies [2b9b95b]\n  - nextra@3.0.0-alpha.36\n\n## 3.0.0-alpha.35\n\n### Patch Changes\n\n- 0b4d43b: Avoid the sidebar collapse having unintended animations when\n  `sidebar.autoCollapse` is set to `true`.\n- 452e5bd: Add `<Playground />` component\n\n  https://nextra-v2-9x7fp6hti-shud.vercel.app/docs/guide/advanced/playground\n\n- f662237: avoid focus-visible style being cut off by overflow-hidden\n- Updated dependencies [f662237]\n  - nextra@3.0.0-alpha.35\n\n## 3.0.0-alpha.34\n\n### Patch Changes\n\n- 8c99baf: enhance search input to better support CJK language users\n- 8ffe2fe: remove focus-visible polyfill\n- 1a634cd: remove explicit `ZodError` assertion\n- Updated dependencies [1a634cd]\n  - nextra@3.0.0-alpha.34\n\n## 3.0.0-alpha.33\n\n### Patch Changes\n\n- 6945f38: fix not rendered default `<meta name=\"description\" />` and\n  `<meta property=\"og:description\" />`\n- 7bb18e3: Add a generic for `themeConfig` in `NextraThemeLayoutProps` to\n  improve type inference.\n- Updated dependencies [7bb18e3]\n  - nextra@3.0.0-alpha.33\n\n## 3.0.0-alpha.32\n\n### Patch Changes\n\n- 73239c4: To ensure consistent horizontal padding, set the default language as\n  plaintext for code blocks. This prevents any loss of formatting for code\n  blocks without a specified language.\n- 150184b: attach heading anchor `id` attribute to heading (like Pagefind do)\n  and fix heading anchor styles when `theme.typesetting: 'article'` is set\n- 9df7f58: Fix nav-links not highlighting on hover in dark mode\n- 3c6193d: Remove unnecessary `sortPages` from `server/utils.ts`\n- 799174f: fixed react warning\n  `Warning: React has detected a change in the order of Hooks called by Body`\n  when `themeConfig.main` options is used\n- Updated dependencies [73239c4]\n- Updated dependencies [799174f]\n- Updated dependencies [150184b]\n- Updated dependencies [3c6193d]\n  - nextra@3.0.0-alpha.32\n\n## 3.0.0-alpha.31\n\n### Patch Changes\n\n- Updated dependencies [d1e3e9a]\n  - nextra@3.0.0-alpha.31\n\n## 3.0.0-alpha.30\n\n### Patch Changes\n\n- Updated dependencies [7615b62]\n  - nextra@3.0.0-alpha.30\n\n## 3.0.0-alpha.29\n\n### Patch Changes\n\n- Updated dependencies [fef635e]\n  - nextra@3.0.0-alpha.29\n\n## 3.0.0-alpha.28\n\n### Patch Changes\n\n- a8c2196: use dynamic import for loading `mermaid`\n- 363b85f: add `flex-shrink: 0` for indent in `FileTree` for `<Ident />` and svg\n  icons in `<Folder />` and `<File />`\n- 363b85f: fix `RangeError: Maximum call stack size exceeded` in `findSummary`\n  when `child.props.children` is `undefined`\n- Updated dependencies [a8c2196]\n- Updated dependencies [363b85f]\n  - nextra@3.0.0-alpha.28\n\n## 3.0.0-alpha.27\n\n### Patch Changes\n\n- 4f0f6b27: Omit `...{:type}` inline code annotations from search index #2922\n- e95faa16: - fixed `<summary />` lost whitespaces when there is some HTML\n  element inside\n  - fixed hydration errors and `<summary />` was not rendered when `<details />`\n    text content follows directly after `<summary />` element\n\n- a95e7454: Fix the line highlighting background-color does not extend to the\n  full width of the code block when a scrollbar appears with line numbers.\n- Updated dependencies [4f0f6b27]\n- Updated dependencies [a95e7454]\n  - nextra@3.0.0-alpha.27\n\n## 3.0.0-alpha.26\n\n### Patch Changes\n\n- 376b8954: fixes case when setting `disabled: true` on the scroll to top button\n  prevents scrolling to most top\n\n  scroll to most top in toc element too\n\n- 7b0b7e98: fix page scroll jump while entering characters in the search input\n  - nextra@3.0.0-alpha.26\n\n## 3.0.0-alpha.25\n\n### Patch Changes\n\n- de565078: fix vertical margin for nested ordered `<ol />` and unordered\n  `<ul />` lists\n  - nextra@3.0.0-alpha.25\n\n## 3.0.0-alpha.24\n\n### Patch Changes\n\n- 6f4c83a8: fix unclickable links in TOC\n\n  allow passing `recmaPlugins` in `mdxOptions`\n\n- Updated dependencies [6f4c83a8]\n  - nextra@3.0.0-alpha.24\n\n## 3.0.0-alpha.23\n\n### Minor Changes\n\n- 6ec3241c: Add Terraform/Move icon https://github.com/shuding/nextra/pull/2811\n  https://github.com/shuding/nextra/pull/2808\n- 6ec3241c: Make the `<Tab />` component be crawlable and indexable by search\n  engines by default\n- b47880d5: export `useMenu` hook\n\n### Patch Changes\n\n- ad108ff7: use `overflow-x-auto` instead `overflow-x-scroll` for `<Table />`\n- 217f7082: update next-themes\n\n  fix wrong numbering for nested `<Steps />`\n\n- ad108ff7: fix `<Bleed />` overflows incorrectly in firefox\n- Updated dependencies [6ec3241c]\n- Updated dependencies [6ec3241c]\n- Updated dependencies [ad108ff7]\n- Updated dependencies [217f7082]\n  - nextra@3.0.0-alpha.23\n\n## 3.0.0-alpha.22\n\n### Patch Changes\n\n- eeb4c4cd: enable `outline: 'none'` only for `:focus-visible` state, to fix\n  double ring in Firefox\n- 9b411804: `backToTop` is hidden when enabled but when `toc.extraContent`,\n  `feedback.content` and `editLink.component` are falsy\n- 2630461c: fix\n  `TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))`\n  on dev environment when `frontMatter.searchable: false`\n- Updated dependencies [2630461c]\n  - nextra@3.0.0-alpha.22\n\n## 3.0.0-alpha.21\n\n### Minor Changes\n\n- 962cea6b: allow `items: Map` for `type: 'menu'` since object can't guaranty\n  the insertion order\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.21\n\n## 3.0.0-alpha.20\n\n### Minor Changes\n\n- b776b162: add `backgroundColor.light` and `backgroundColor.dark` theme options\n\n### Patch Changes\n\n- nextra@3.0.0-alpha.20\n\n## 3.0.0-alpha.19\n\n### Patch Changes\n\n- d21634d5: export `getComponents`\n  - nextra@3.0.0-alpha.19\n\n## 3.0.0-alpha.18\n\n### Patch Changes\n\n- Updated dependencies [98f439ca]\n- Updated dependencies [f71e660e]\n- Updated dependencies [98f439ca]\n  - nextra@3.0.0-alpha.18\n\n## 3.0.0-alpha.17\n\n### Minor Changes\n\n- 30438264: add shikiji twoslash\n\n  Demo feature:\n  https://nextra-v2-na3obnhub-shuding1.vercel.app/docs/guide/twoslash-support\n\n### Patch Changes\n\n- 9f55bd1f: update rehype-pretty-code/shikiji to latest\n- Updated dependencies [9f55bd1f]\n- Updated dependencies [30438264]\n  - nextra@3.0.0-alpha.17\n\n## 3.0.0-alpha.16\n\n### Minor Changes\n\n- 5a637010: add icons for following languages:\n  - GraphQL (`graphql`)\n  - C++ (`c++`, `cpp`)\n  - C# (`csharp`, `c#`, `cs`)\n  - Python (`python`, `py`)\n\n  allow disallow mobile word wrap button in code blocks with `word-wrap=false`\n  meta data setting\n\n### Patch Changes\n\n- Updated dependencies [5a637010]\n- Updated dependencies [90c129e6]\n  - nextra@3.0.0-alpha.16\n\n## 3.0.0-alpha.15\n\n### Patch Changes\n\n- Updated dependencies [1a364694]\n  - nextra@3.0.0-alpha.15\n\n## 3.0.0-alpha.14\n\n### Patch Changes\n\n- 45471df5: fix \"Scroll to top\" is not supposed to be interactable when it is\n  hidden.\n\n  `display:children` doesn't collapse breadcrumbs\n\n  hide external links from pagination\n\n  remove xmlns attribute from icons\n  - nextra@3.0.0-alpha.14\n\n## 3.0.0-alpha.13\n\n### Minor Changes\n\n- 6070b025: rename `frontmatter.sidebar_label` to `frontmatter.sidebarTitle`\n- 6070b025: move `removeLinks` function from `nextra-theme-docs` to\n  `nextra/remove-links`\n\n### Patch Changes\n\n- 6070b025: load `flexsearch` dynamically to reduce bundle size\n- Updated dependencies [60ec68c4]\n- Updated dependencies [c74ae90a]\n- Updated dependencies [6070b025]\n- Updated dependencies [8bce16d3]\n- Updated dependencies [6070b025]\n  - nextra@3.0.0-alpha.13\n\n## 3.0.0-alpha.12\n\n### Patch Changes\n\n- Updated dependencies [3644e1c2]\n- Updated dependencies [57bc0e2a]\n  - nextra@3.0.0-alpha.12\n\n## 3.0.0-alpha.11\n\n### Major Changes\n\n- c2ad837d: update to MDX3\n\n### Minor Changes\n\n- eb943d00: add `theme.topContent` and `theme.bottomContent`\n\n### Patch Changes\n\n- eb943d00: hardcode flexsearch version to 0.7.31, because package is broken on\n  0.7.41\n- Updated dependencies [c2ad837d]\n  - nextra@3.0.0-alpha.11\n\n## 3.0.0-alpha.10\n\n### Patch Changes\n\n- Updated dependencies [9099c354]\n  - nextra@3.0.0-alpha.10\n\n## 3.0.0-alpha.9\n\n### Patch Changes\n\n- Updated dependencies [8efbb45c]\n- Updated dependencies [80e11e04]\n  - nextra@3.0.0-alpha.9\n\n## 3.0.0-alpha.8\n\n### Minor Changes\n\n- 440ff42d: add MathJax support\n\n### Patch Changes\n\n- Updated dependencies [440ff42d]\n  - nextra@3.0.0-alpha.8\n\n## 3.0.0-alpha.7\n\n### Patch Changes\n\n- 0b5cc9d5: make nextra compatible with windows\n- Updated dependencies [0b5cc9d5]\n  - nextra@3.0.0-alpha.7\n\n## 3.0.0-alpha.6\n\n### Patch Changes\n\n- 31c2ee70: fix `removeLinks` when input node is link\n- 03da778a: fix `*` theme settings for dynamic routes when route is not exist in\n  page map\n- Updated dependencies [03da778a]\n  - nextra@3.0.0-alpha.6\n\n## 3.0.0-alpha.5\n\n### Patch Changes\n\n- 315ca826: remove possible links in toc elements\n- Updated dependencies [a3b67aea]\n  - nextra@3.0.0-alpha.5\n\n## 3.0.0-alpha.4\n\n### Minor Changes\n\n- 1dcb91a0: export `useThemeConfig`\n\n### Patch Changes\n\n- 4fb24524: fix invisible mobile menu when `layout: \"raw\"` is specified in\n  \\_meta file\n- 7faa0968: fix visible hidden pages on mobile which set up with\n  `display: 'hidden'`\n- Updated dependencies [7faa0968]\n  - nextra@3.0.0-alpha.4\n\n## 3.0.0-alpha.3\n\n### Patch Changes\n\n- fe5061b7: fix for remote docs\n- Updated dependencies [fe5061b7]\n  - nextra@3.0.0-alpha.3\n\n## 3.0.0-alpha.2\n\n### Patch Changes\n\n- b045cc3e: fix invisible mobile menu after click on hamburger\n- cb247901: fix broken `export default` statement in mdx files\n- Updated dependencies [cb247901]\n  - nextra@3.0.0-alpha.2\n\n## 3.0.0-alpha.1\n\n### Major Changes\n\n- e7e8e849: show react components, variable interpolation and latex in toc\n- c7f03e54: remove `toc.headingComponent`\n- ea1a7362: remove `next-seo` and `useNextSeoProps`, use `head` option instead\n- 148278ce: rename tailwind prefix `nx-` to `_` to reduce bundle size\n- d7d8a3eb: new styles for code blocks aka in next.js\n- 63ca28be: Remove support of \"\\_meta.json\", use \"\\_meta.{js,jsx,ts,tsx}\"\n  instead.\n- ebe652db: remove `sidebar.titleComponent`, use JSX for styling separators and\n  titles\n- 128e195f: fix React warning, remove PageOpts.toc, use `toc` prop from\n  `components.wrapper`\n- 63ca28be: remove `config.serverSideError`\n- 198dbcca: use toc with JSX elements for remote content\n- 191e6c41: - use `shikiji` instead of `shiki`\n  - rename `useSSG` to `useData`\n\n- 6eb3118f: rename `primaryHue` and `primarySaturation` theme options to\n  `color.hue` and `color.saturation`\n- c7f03e54: rename `pageOpts.headings` to `toc`\n\n### Minor Changes\n\n- c77485ec: set default `head` option as `null`\n- a52a869e: add `frontmatter.sidebar_label` support for setting page label in\n  sidebar via frontmatter\n\n### Patch Changes\n\n- 7457d6b6: remove `git-url-parse` to keep bundle smaller\n- Updated dependencies [e7e8e849]\n- Updated dependencies [71882780]\n- Updated dependencies [023d37b1]\n- Updated dependencies [148278ce]\n- Updated dependencies [c7f03e54]\n- Updated dependencies [d7d8a3eb]\n- Updated dependencies [a52a869e]\n- Updated dependencies [63ca28be]\n- Updated dependencies [1f3e7cd4]\n- Updated dependencies [b9f88e34]\n- Updated dependencies [4e55c064]\n- Updated dependencies [128e195f]\n- Updated dependencies [1f3e7cd4]\n- Updated dependencies [198dbcca]\n- Updated dependencies [191e6c41]\n- Updated dependencies [c7f03e54]\n  - nextra@3.0.0-alpha.1\n\n## 3.0.0-alpha.0\n\n### Major Changes\n\n- 919fe977: set `\"peerDependencies.next\": \">=13\"`\n- eca75354: - remove `Steps`, `Callout`, `Tabs`, `Tab`, `Cards`, `Card`,\n  `FileTree` exports, export them now from `nextra/components`\n  - remove `useMDXComponents` export, export it now from `nextra/mdx`\n  - set by default `sidebar.toggleButton` to true\n\n- f2dd18d2: - rename theme config options\n\n  `i18n.text` → `i18n.name`\n\n  `banner.text` → `banner.content`\n\n  `editLink.text` → `editLink.content`\n\n  `footer.text` → `footer.content`\n\n- 8c1b9d53: remove `<MatchSorterSearch />`\n\n### Minor Changes\n\n- 0fe55db2: add `import { useRouter } from 'nextra/hooks'` for fetching `locale`\n  and `defaultLocale`\n\n### Patch Changes\n\n- 80c9764b: ensure zod is removed from production build with `/* @__PURE__ */`\n  comments\n- Updated dependencies [0fe55db2]\n- Updated dependencies [50a52fd1]\n- Updated dependencies [919fe977]\n- Updated dependencies [ad4823d9]\n- Updated dependencies [ab07609c]\n- Updated dependencies [2f3be336]\n- Updated dependencies [66cce1d1]\n- Updated dependencies [d8a406b4]\n- Updated dependencies [576cb6f1]\n  - nextra@3.0.0-alpha.0\n\n## 2.13.4\n\n### Patch Changes\n\n- f7fc10b4: fix for the memory leak issue in the `highlight-matches.tsx`\n  component when search query contain multiple whitespaces\n  - nextra@2.13.4\n\n## 2.13.3\n\n### Patch Changes\n\n- 93b57052: allow to disable `editLink` by specifying `editLink.component: null`\n  in theme config\n- 93b57052: fix `type: 'separator'` zod validation, mark `title` field as\n  optional\n- Updated dependencies [93b57052]\n  - nextra@2.13.3\n\n## 2.13.2\n\n### Patch Changes\n\n- ad7b31b0: downgrade remark-math from `6` to `5.1.1` to fix\n  `TypeError: Cannot read properties of undefined (reading 'mathFlowInside')`\n  error\n\n  fix support of ```math lang that was overridden by `rehype-pretty-code`\n\n- Updated dependencies [ad7b31b0]\n  - nextra@2.13.2\n\n## 2.13.1\n\n### Patch Changes\n\n- 3e5e1153: fix showing toggle sidebar button when darkmode is turned off and\n  i18n was not set\n- Updated dependencies [ee02a483]\n  - nextra@2.13.1\n\n## 2.13.0\n\n### Minor Changes\n\n- 7aec7bb5: add `primarySaturation` theme option\n- a55e4aa4: update `npm2yarn`, add bun tab\n\n### Patch Changes\n\n- a55e4aa4: do not scroll to top while calling cmd+k in search input\n  - nextra@2.13.0\n\n## 2.12.3\n\n### Patch Changes\n\n- ffb6d808: - Fix\n  `TypeError: Cannot read properties of null (reading 'classList')` while\n  navigating to route that doesn't have toc with `router.push` for example\n  - Add alias `Tabs.Tab` to `Tab` component\n  - Add alias `Cards.Card` to `Card` component\n  - should not attach custom heading id as id attribute if parent is `Tabs.Tab`\n    or `Tab`\n  - should not save to toc list headings of level 1\n\n- Updated dependencies [ffb6d808]\n  - nextra@2.12.3\n\n## 2.12.2\n\n### Patch Changes\n\n- 7c8c4989: fix `Out of Memory` in search while indexing large words\n- Updated dependencies [7c8c4989]\n  - nextra@2.12.2\n\n## 2.12.1\n\n### Patch Changes\n\n- Updated dependencies [52ae8fc5]\n  - nextra@2.12.1\n\n## 2.12.0\n\n### Minor Changes\n\n- d9820746: - show headings for partial md/mdx in toc\n  - hide headings in toc when parent `<Tab />` or `<Tabs.Tab />`\n\n- 63271a41: add toc.backToTop option\n- 8962597e: - allow override static image component that was hardcoded to\n  `import Image from 'next/image'` now it's plain `<img />`\n  - support `<details />`/`<summary />` for `.md` files\n\n### Patch Changes\n\n- cca36d32: do not render mobile sidebar on desktop\n- Updated dependencies [d9820746]\n- Updated dependencies [fbf003cd]\n- Updated dependencies [8962597e]\n  - nextra@2.12.0\n\n## 2.11.1\n\n### Patch Changes\n\n- cf5f91ea: fix footnotes and backlink jump\n- ddddce95: skip search indexing for 404/500 pages\n- 4dd720ad: remove `font-weight: 500;` from styles of code blocks since it gives\n  no effect\n- 29e35d81: fix feedback.labels for gitlab\n- Updated dependencies [ddddce95]\n- Updated dependencies [6154e312]\n- Updated dependencies [46743ba4]\n- Updated dependencies [4dd720ad]\n  - nextra@2.11.1\n\n## 2.11.0\n\n### Minor Changes\n\n- 3bb480a4: export `LocaleSwitch` from `nextra-theme-docs`\n\n### Patch Changes\n\n- 3bb480a4: use github-slugger for custom heading ids to prevent duplicated\n  headings\n- 3bb480a4: fix custom heading id in search result\n- 3bb480a4: fix\n  `Warning: Prop href did not match. Server: \"/blog.en-US#\" Client: \"/blog#\"` in\n  by `normalizePages` from nextra/normalize-pages`\n- 3bb480a4: improve hr contrast\n- 3bb480a4: fix search, trigger the search after the Input is complete for\n  languages like Chinese\n- 3bb480a4: strip `.html` extension from URL route for static export\n- 3bb480a4: fix memory leak in search for case `>  ` replaced previously to\n  `>||` + some character provoke memory leak because `RegExp#exec` will always\n  return a match\n- 3bb480a4: fix code blocks `box-decoration-theme: clone` can create confusing\n  output over line breaks, use `slice` instead\n- Updated dependencies [3bb480a4]\n- Updated dependencies [3bb480a4]\n- Updated dependencies [3bb480a4]\n- Updated dependencies [3bb480a4]\n  - nextra@2.11.0\n\n## 2.10.0\n\n### Minor Changes\n\n- e54b008: - add `@theguild/remark-npm2yarn` package that replaces the code\n  block that has `npm2yarn` metadata with `<Tabs />` and `<Tab />` components\n  from `nextra/components`.\n  - `<Tabs />` now has `selectedKey` prop, the chosen tab is saved in the local\n    storage, which will be chosen in future page renders.\n\n  More info https://nextra.site/docs/guide/advanced/npm2yarn\n\n### Patch Changes\n\n- Updated dependencies [e54b008]\n  - nextra@2.10.0\n\n## 2.9.0\n\n### Minor Changes\n\n- 16bbb88: Move below packages to nextra package\n  - `<Cards />` and `<Card />`\n  - `<Tabs />` and `<Tab />`\n  - `<Steps />`\n  - `<FileTree />`\n\n  to import them you can use the following in your official `nextra-theme-blog`\n  and `nextra-theme-docs`\n\n  ```js\n  import { Card, Cards } from 'nextra/components'\n  ```\n\n  ```js\n  import { Tab, Tabs } from 'nextra/components'\n  ```\n\n  ```js\n  import { Steps } from 'nextra/components'\n  ```\n\n  ```js\n  import { FileTree } from 'nextra/components'\n  ```\n\n### Patch Changes\n\n- b1a7eba: `opens in new tab` span element should have `user-select: none`\n- Updated dependencies [16bbb88]\n- Updated dependencies [23a25b1]\n  - nextra@2.9.0\n\n## 2.8.0\n\n### Minor Changes\n\n- b43f268: add new option `sidebar.autoCollapse` to automatically collapse\n  inactive folders above `defaultMenuCollapseLevel`\n\n### Patch Changes\n\n- 6c12bf4: fix broken code format while selecting and copying code with\n  `showLineNumbers` option enabled\n- Updated dependencies [6c12bf4]\n  - nextra@2.8.0\n\n## 2.7.1\n\n### Patch Changes\n\n- Updated dependencies [0e53ca51]\n  - nextra@2.7.1\n\n## 2.7.0\n\n### Minor Changes\n\n- 44626e8f: support mermaid diagrams\n\n### Patch Changes\n\n- Updated dependencies [44626e8f]\n  - nextra@2.7.0\n\n## 2.6.2\n\n### Patch Changes\n\n- 9c9625ee: Fix search not working in certain Next.js versions\n- Updated dependencies [9c9625ee]\n  - nextra@2.6.2\n\n## 2.6.1\n\n### Patch Changes\n\n- Updated dependencies [1e9ebabc]\n  - nextra@2.6.1\n\n## 2.6.0\n\n### Minor Changes\n\n- 1c6256b: Move Callout component to nextra package\n\n### Patch Changes\n\n- 15c4092: fix inconsistent `font-weight: bold` style for `type: 'menu'`\n- 2d79e20: Resolves dark mode contrast problems in sidebar and breadcrumbs\n- Updated dependencies [15c4092]\n- Updated dependencies [1c6256b]\n  - nextra@2.6.0\n\n## 2.5.2\n\n### Patch Changes\n\n- Updated dependencies [a3601e5]\n  - nextra@2.5.2\n\n## 2.5.1\n\n### Patch Changes\n\n- Updated dependencies [d408ab0]\n  - nextra@2.5.1\n\n## 2.5.0\n\n### Minor Changes\n\n- 08d393e: support ANSI highlighting\n\n### Patch Changes\n\n- 8515349: fix Warning: React has detected a change in the order of Hooks called\n  by Search\n- Updated dependencies [08d393e]\n  - nextra@2.5.0\n\n## 2.4.2\n\n### Patch Changes\n\n- 41d4aa0: remove `nx-overflow-x-hidden` from main content\n- Updated dependencies [16e562d]\n  - nextra@2.4.2\n\n## 2.4.1\n\n### Patch Changes\n\n- 2df6e91: Use config.useOptions text as the Select selected name on Theme\n  Switch\n- 7989cc5: fix regression of sidebar style for folder\n- Updated dependencies [a992ce1]\n  - nextra@2.4.1\n\n## 2.4.0\n\n### Minor Changes\n\n- 6973b21: Add new option `headingComponent` to the TOC\n\n### Patch Changes\n\n- 2ff360f: use `<span />` instead `<div />` inside `<button />` for local switch\n  button\n- e3664c4: fix uncrawable links in sidebar, use button when link don't have href\n  because it impacts on SEO\n\n  remove useless prop children from `<FileTree.File />` component\n\n- 8e00549: export `<Link />` component\n- 61b4f0c: Wrap long section headers in TOC properly\n- Updated dependencies [545bd7c]\n- Updated dependencies [0a50cad]\n- Updated dependencies [259bfbc]\n  - nextra@2.4.0\n\n## 2.3.0\n\n### Minor Changes\n\n- 707a709: Improve sidebar colors accessibility\n- 76e8b0f: support custom heading id via\n  `# my very long heading... [#my-custom-heading]` syntax\n  https://github.com/shuding/nextra/pull/1645\n\n### Patch Changes\n\n- fb0b19b: Do not focus search when currently focusing a HTMLElement with\n  contenteditable active\n- Updated dependencies [0dd028a]\n- Updated dependencies [6ea1caf]\n- Updated dependencies [76e8b0f]\n  - nextra@2.3.0\n\n## 2.2.20\n\n### Patch Changes\n\n- 2e48307: export `normalizePages` from `nextra/normalize-pages`, `useFSRoute`\n  from `nextra/hooks` (can be useful for custom theme)\n- Updated dependencies [2e48307]\n- Updated dependencies [e4c8b6d]\n  - nextra@2.2.20\n\n## 2.2.19\n\n### Patch Changes\n\n- Updated dependencies [e41cbbc]\n- Updated dependencies [a1e59b2]\n  - nextra@2.2.19\n\n## 2.2.18\n\n### Patch Changes\n\n- f29358a: always show `Cmd+K` when search input loses focus\n- 7cbf5d9: rename input placeholder to \"Rechercher documents...\" in french\n- 35d4fd1: fix `<summary />` when children contains `<p />`\n- 89bbe4c: fix filetree for 2 folders\n- Updated dependencies [9bd2d59]\n- Updated dependencies [c2287e1]\n- Updated dependencies [90cb6b8]\n  - nextra@2.2.18\n\n## 2.2.17\n\n### Patch Changes\n\n- Updated dependencies [4a66366]\n  - nextra@2.2.17\n\n## 2.2.16\n\n### Patch Changes\n\n- b94245a: Reverts #1417 \"force theme to light if darkMode: false was set\"\n- d495e5f: introduce `_app.mdx` for better performance and smallest\n  `.next/static/chunks` size\n- Updated dependencies [d495e5f]\n  - nextra@2.2.16\n\n## 2.2.15\n\n### Patch Changes\n\n- 71c1897: export `<Card />`, `<Cards >/`, `<Steps />` and `<FileTree />`\n- 51ec00f: fix white appearing of white square while sidebar was toggled\n- 2e441b7: open http:// links in new window\n- 7f697e9: prefer `asPath` over `route` in `useNextSeoProps` docs, allow `void`\n  as return type of `useNextSeoProps`\n- 016828e: do not redirect .mp4 in locales middleware\n- da585a8: force theme to `light` if `darkMode: false` was set\n- 863a750: Fixed x overflow in Callouts for long latex\n- eae1993: Fix the capital letter M is displayed incorrectly on Xiaomi phones\n- ad8625c: bump @headlessui/react to ^1.7.10\n- 673a125: fix squeezed sidebar when he was hidden -> navigated to page without\n  sidebar -> comeback to page with sidebar\n- 26c7e20: fix: move intersection observe and slugs into ActiveAnchorProvider\n- 3e9e54f: hide unnecessary parts of the pages when being printed\n- Updated dependencies [d5aa17c]\n- Updated dependencies [016828e]\n- Updated dependencies [b3219c3]\n  - nextra@2.2.15\n\n## 2.2.14\n\n### Patch Changes\n\n- bcaba9c: fix capitalizing sidebar links + tests\n- f300fe7: fix missing sidebar nav links while applying `\"display\": \"hidden\"`\n  for folder\n- 71257cd: style improvements\n- efd8c71: fix for `theme: { footer: false }` still showed the footer\n- 086cf7b: fix scrollbar for table and tabs\n- Updated dependencies [bcaba9c]\n- Updated dependencies [a683c84]\n- Updated dependencies [a404ef7]\n  - nextra@2.2.14\n\n## 2.2.13\n\n### Patch Changes\n\n- 089112c: validate `_meta.json` files with zod\n- 23fc5b7: style improvements\n- d1d873f: typed frontmatter -> `useConfig<YOUR_FRONTMATTER_TYPE>`\n- 93b9596: fix overflow for main content on desktop and mobile\n- 6626356: prefer `import type`\n- 2234a13: fix raw `__esModule` string ☠️\n- Updated dependencies [d1d873f]\n- Updated dependencies [6626356]\n- Updated dependencies [2234a13]\n  - nextra@2.2.13\n\n## 2.2.12\n\n### Patch Changes\n\n- c913ec8: add peer deps\n- Updated dependencies [619ae3a]\n  - nextra@2.2.12\n\n## 2.2.11\n\n### Patch Changes\n\n- bcaf84a: fix treeshake of zod validation on prod build\n- e10bf74: add support for remote `[...catchAll]` routes\n\n  support meta keys with `/`\n\n  sanitize remote mdx by removing `import` statements\n\n- 6a0f428: add zod validation for \\_meta.json \"theme\" property\n- 6a0f428: use `z.strictObject` instead `z.object` in zod theme validation,\n  improve zod error messages\n\n## 2.2.10\n\n### Patch Changes\n\n- c97143f: fix search index output location\n- 4b2052f: fix `Module not found: Can't resolve 'nextra-theme-docs/style.css'`\n  for imported markdown files that located outside of CWD\n- 624d6b4: fix when sidebar show non-md folders\n- 0c957db: fix capitalizing of undefined \\_meta.json file/folders\n\n## 2.2.9\n\n## 2.2.8\n\n## 2.2.7\n\n### Patch Changes\n\n- be410bd: fix `<Collapse />` initial animation\n\n## 2.2.6\n\n## 2.2.5\n\n### Patch Changes\n\n- 5daa1c4: fix Collapse element\n- 163065c: loader refactor, type-safe `__nextra_resolvePageMap`, avoid code\n  interpolation in loader.ts\n\n## 2.2.4\n\n### Patch Changes\n\n- 091b77b: fix missing filename\n\n  add filename / copy code with \"codeHighlight: false\"\n\n  add unit tests for filename and copy code\n\n- 917de49: remove `github-slugger` from docs\n- 1b2d7a2: allow hide sidebar, add new option\n  `sidebar.toggleButton?: boolean = false`\n\n## 2.2.3\n\n### Patch Changes\n\n- 11b2870: fix copy code button position\n- 0cab136: pass route to titleComponent\n- cd0cc63: fix defaultMenuCollapseLevel behavior\n\n## 2.2.2\n\n### Patch Changes\n\n- 3145f53: extend `plugin:react/recommended`, `plugin:react-hooks/recommended`\n  and `plugin:@next/next/recommended` configs\n- 1834730: fix hydration error produced by cached compiler, fix broken\n  code-blocks styles while setting `nextraConfig.codeHighlight: false`\n- 8b9a5a0: tweak styling; fix zod checks\n\n## 2.2.1\n\n## 2.2.0\n\n### Minor Changes\n\n- e4b20ca: support `transform` in nextra config\n\n### Patch Changes\n\n- af76dbe: fix highlight substring from filename for code blocks\n\n## 2.1.0\n\n### Minor Changes\n\n- e5262d0: improve hmr and internal api for layout (toc and meta files)\n\n### Patch Changes\n\n- d6b0068: Always close mobile nav when route was changed (e.g. logo click)\n- 9df1d5d: fix `undefined: undefined` property in `useConfig()`\n- c86508c: lint fixes for `eslint:recommended` and\n  `plugin:@typescript-eslint/recommended` configs\n- d6c871a: simplify the custom theme layout api\n- 1ff43c1: use OKLCH colors where possible\n- 0da1258: add new option `feedback.useLink`\n- a3f1a90: validate theme options with `zod`\n- a31678a: improve copy\n\n## 2.0.3\n\n### Patch Changes\n\n- 8060ed3: style improvements\n\n## 2.0.2\n\n### Patch Changes\n\n- 99ec64e: fix indentation for copy code button\n- 3a08fe2: Add Callout border in dark mode\n- 328ad88: support basePath with locale switch\n- f488e2e: remove @react/skip-nev #1051\n\n  fix: staticImage should only set blur placeholder for jpeg,png,webp,avif\n\n- 5c617d4: add `aria-label` for dismiss button in banner\n- b43d775: fix `Navbar />` elements `key` prop\n- 105588d: fix missing border in navbar\n- c1867fd: fix hydration for default `gitTimestamp` component\n\n## 2.0.1\n\n### Patch Changes\n\n- a9748aa: fix: A11y improvements to the docs theme\n- ac82b1f: make code-blocks buttons focusable if they are visible on page\n- 0ca195c: inform screen readers of externals links that open in a new tabs\n\n## 2.0.0\n\n### Minor Changes\n\n- 8f6d377: allow custom github domains\n\n### Patch Changes\n\n- 4731fa7: Style improvements\n- 7a32f8e: remove unneeded wrappers `<div />`s in `<Navbar />`\n- 9ab6dd0: allow adding additional navbar content via `navbar.extraContent`\n- e6771ca: fix search overlay styles on mobile\n- 94ef0b3: improve 2.0 docs\n- 21009c7: fix covered select options\n- bea62a1: make the search input responsive in narrow screens\n- 903ddf0: fix: should update scroll when height is dynamic\n- e6771ca: split css to `hamburger`/`scrollbar`/`typesetting-article` css files\n- 24a02f8: reuse Flexsearch result styles on match-sorter search\n- 1a7cd68: toc anchor links should have `display: inline-block`\n- 6644bd5: pass unstable_flexsearch\n- cef5546: allow headings contain links\n- 2217f9c: fix `Warning: Prop `href` did not match. Server: \"#\" Client: ...`\n- a0c0eb8: allow override `MDXProvider.components`\n- e6771ca: fix edit on github button for cases when filename named as `index`\n- 8bcb5e6: fix sideEffects in package.json\n- 2217f9c: fix `next export` command\n- fdb2f57: update docs to use next.js 13\n- 3e3b0a9: feat: add cursor pointer to locale and theme menu\n- a0398e0: fix: avoid mutating nextConfig\n- e6771ca: BREAKING! various theme config options was renamed, take a look of\n  renamed options\n  [here](https://github.com/shuding/nextra/blob/core/packages/nextra-theme-docs/src/constants.tsx)\n- 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible\n  with next 13\n- 38ccce8: feat(docs): allow `Tabs.items` as `ReadonlyArray<ReactNode>`\n- fc8cca0: add `<InformationCircleIcon />` icon, improve `<Callout />` default\n  emojis\n- fe2b714: upgrade to react 18\n- af72f85: chore(nextra-theme-docs): provide type for\n  `DocsThemeConfig.nextThemes` instead of `object`\n- e4cfb83: define page title in sidebar from `frontMatter.title` if page is not\n  specified in `_meta.json`\n- 1ee3c92: reuse table styles from docs in blog\n- f569d90: missing `nx-` class prefixes in blog fix callout padding in docs\n- 77361da: fix ESC button when still stays after pressed ESC\n- b1d7361: improve docs for 2.0\n- 9064112: make `<Tab />` accept `ComponentProps<'div'>`\n- da2bea7: remove no longer used `icons` folder\n- 4825365: add `@types/github-slugger` instead of manually declaring type\n- 6bdb9bf: fix: broken flexsearch styles\n- fdfe4f8: fix covered theme switch popup when i18n is not setup\n- 66712f0: polish docs\n- 873561b: scrollbar is toc should be same as in sidebar\n- 08a39e6: remove `resizeObserver` for dynamic content since it provoke jumps on\n  tabs switch when there is `#` anchor in url\n- 4e4a37c: add new \"display\" property to \\_meta\n- e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add\n  `NextraConfig.unstable_defaultShowCopyCode` option to show button by default,\n  add `copy` and `copy=false` options for code-blocks\n- a5cac21: [docs/blog]: extract code styles and import in both themes\n- 96ed5c2: [nextra/nextra-theme-docs]: support both\n  `experimental.newNextLinkBehavior` - `true` and `false`\n- 1fef548: allow head to be a ReactNode\n- 580c433: add nx- to all tailwind classes for style isolation\n- c3e6227: add `overflow-x-scroll` for tables\n- dfbe996: extract `<Banner />` from `<Navbar />` to `components/banner.tsx`\n- 1c3fedb: add missing `nx-` prefixes to table/th/tr elements\n- 78f1519: chore: Add strict-peer-dependencies=false\n- c15f570: fix: query should not affect nav highlight\n- 97e6141: fix(nextra/docs): fallback search to `en-US` instead `default`\n- 2b6f3be: add missing border for search container\n- cb87709: Fix flexsearch option being overridden\n- d6d5ab8: Make sure arrows are aligned\n- a007c64: move DEFAULT_THEME and DEFAULT_PAGE_THEME to constants.tsx\n- ab6c0e6: fix disappearing toc issue in Firefox\n- 16bedce: `\"layout\": \"raw\"` should render `all` unstyled elements, except\n  `<a />`\n- a0e5847: Rename some docs theme configurations\n- 351fa45: add missing `nx-` prefix for `grow` class in `<LocaleSwitch />`\n- c09f450: fix CTRL+K, on non non-mac use `e.ctrlKey` instead `e.metaKey`\n- f5bf2e4: fix margin-top for `<Tab />` content\n- 237faa9: add clear button for search input\n- 973ca49: fix rtl/ltr glitch on initial loading\n- c8129a2: fix theme switcher style\n- 3de0f41: chore(blog/docs): use `postcss-import` to import css variables styles\n- 2e2912e: fix project/chat icon could appear without provided link\n- 97ca2e3: New feature: menu type\n- 84d983f: fix(docs): correct query for hash with leading num\n- 32cd385: add new option `search.loading` for control loading text\n- 2533a6c: replace `main.extraContent` theme option with `main` option\n- 4730bdc: chore(nextra-theme-docs): refactor `theme-context.ts`\n- 24a02f8: typescripify `<Flexsearch />`\n- 74a3398: update docs for 2.0\n- bd2cefa: Fix css classes with `eslint-plugin-tailwindcss`\n- ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile)\n- 5d852b6: break words in navlinks, remove unneeded `<div />` wrappers, align\n  text on right side for next link\n- e6771ca: hide search input in navbar on mobile\n- 76d1e30: [nextra-theme-docs]: fix `Warning: A title element received an array`\n  and possible `[object Object]` in title\n- 009bf6a: Fix release workflow.\n- 5238bb4: feat(docs): support logoLink config option\n- e6771ca: fix empty space in navbar when theme option `search.component: null`\n- e6771ca: add `editLink.component`\n- ee270a4: fix extra space in flexsearch input after loading indexes\n- e6771ca: rename `meta.json` to `_meta.json`\n- 24a02f8: fix all RTL broken styles\n- 0c136ad: add missing `nx-` prefix in sidebar\n- ff8967c: fix missing `Copy Code` button in code-blocks without language\n- 2217f9c: replace `classnames` package with `clsx` as he's faster\n- e6771ca: clicking on folder should navigate to first children if `index` page\n  doesn't exist\n- 723d42a: use `lightningcss` instead `cssnano`\n- bf74201: [nextra-theme-docs]: use new opacity modifier syntax for tailwindcss\n- a8c5883: add `config.bodyExtraContent` option\n- e2d603a: remove `getComponents` export, export `useMDXComponents` from\n  `@mdx-js/react` instead\n- 8564919: extract `<Input/>` from `<Search/>` and `<Flexsearch/>`\n- 05d068c: Add button label for hamburger menu\n- 38769ca: prefer `ref.current.querySelector` over `document.querySelector`,\n  remove `load` prop in `<Search />`\n- b219821: fix body overflow\n- d7f2bbc: adjust docs theme; rename options\n- 24a02f8: match-sorter search should highlight every match like flexsearch\n- 2217f9c: remove `locale` prop from theme config, forbid passing in\n  `renderComponent`\n- 7d2d5ee: use resolvedTheme instead renderedTheme + theme check\n- 256154a: use \"next/future/image\" if\n  `\"experimental.images.allowFutureImage\": true` is set in next config\n- 9f5af54: add `_meta.json#theme.collapsed` option for control state sidebar's\n  folders\n- c8605d6: feat: New layout implementation\n- 4157b71: set lower build target and share code highlight theme through nextra\n- c28a7f2: - setup `next-seo`\n  - add new theme option `getNextSeoProps`\n  - remove `titleSuffix` theme option in favor of\n    `getNextSeoProps.titleTemplate`\n  - by default pass `description`, `canonical`, `openGraph` values to\n    `<NextSeo />` component from page `frontMatter`, values can be overridden\n    with return value of `getNextSeoProps`\n- f360f28: add new theme option `banner.dismissible`\n- 7bcbc98: add new `meta.json#theme.timestamp` option to hide\n  `Last updated on ...`\n- 94a8587: chore: extract `svg` icons in `/icons` folder, reusing same icons\n  `<MoonIcon />` / `<SunIcon />` in blog from docs\n- d16b2ba: move contexts to `./contexts` directory\n- 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well\n- 47938b1: remove unneeded `useRef` for `<details />`\n- 256154a: replace images with `<NextImage />` even when url not relative but\n  that starts from `/` (public directory)\n- e573175: Fix release CI\n- 48e0ac2: export `useConfig` and `useTheme`\n- 21009c7: better focus ui, use ring color as theme hue color\n- 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader\n- 71528f1: show copy code button only on hover of container\n- 03e90d8: refresh build system with tsup and fix nextra type\n- afaa26a: refactor toc, fix toc's styles on rtl, use `ref.current` instead\n  `document.getElementsByClassName`\n- c380989: fix(docs): types is missing in bundle\n- 7373c1f: fix `useConfig`/`useRouter` inside `head()`\n- e6771ca: fix callout shrinking from children content\n- fb37b5f: Close selector bracket for compat with old Safari.\n- e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter`\n- ab629e6: Add correct aria values inside nav\n- cdc1c2f: prefer `ref.current` over `document.querySelector` in sidebar\n- 6a4a593: fix: #531 unclickable breadcrumb\n- d34f9f2: feat(nextra-theme-docs): update discord logo to the new one\n- a8a89e9: chore(docs): export ThemeSwitch & custom social\n- f964802: do not hide default logo on mobile\n- 7053959: chore(nextra-theme-docs): remove unneeded `transform-none` css class\n- bc52178: fix `editLink` option was not merged with default config `editLink`\n- 582ad96: feat: bump `rehype-pretty-code` version, support `showLineNumbers`\n- da998e6: move react components to `components` folder and replace exports:\n  ```ts\n  import Bleed from 'nextra-theme-docs/bleed'\n  import Callout from 'nextra-theme-docs/callout'\n  import Collapse from 'nextra-theme-docs/collapse'\n  import { Tab, Tabs } from 'nextra-theme-docs/tabs'\n  ```\n  by\n  ```ts\n  import { Bleed, Callout, Collapse, Tab, Tabs } from 'nextra-theme-docs'\n  ```\n- e6771ca: move `withLayout` logic directly in nextra loader\n- 8ad9507: fix unable expanding folder items in sidebar\n- c2c0d90: fix(search): handle case when value is empty\n- c4a9782: support custom hue theme color via `primaryHue`, `primaryHue.dark`\n  and `primaryHue.light` theme options\n- c8bb94f: UI adjustments\n- a9ca0b9: do not add `basePath` to the links\n- 88f999d: fix: UI improvements\n- 43409ad: fix: mdx theme is missing\n- 416dfe2: add missing `nx-` prefixes in sidebar\n- e6771ca: adjust active breadcrumb color\n- 707fdc2: fix: Anchor links are not wrapping on the sidebar\n- c3e6227: reuse nextra's scrollbar-y styles for scrollbar-x, adjust sidebar's\n  scrollbar-y\n- 0af6e79: `\"layout\": \"raw\"` should have unstyled `<a />` and `<p />` elements\n  as well\n- 2ec8564: add `DocsThemeConfig.navbar` config option for overriding navbar\n- f99bbc2: Add `nextra-body-typesetting-article` back\n- e6771ca: fix search input `ESC` icon vertical alignment\n- 5b01537: Fix full docs directory list and active link\n- 06aa62f: feat: allow `import { getComponents } from 'nextra-theme-docs'`\n\n## 2.0.0-beta.45\n\n### Patch Changes\n\n- 66712f0: polish docs\n\n## 2.0.0-beta.44\n\n### Patch Changes\n\n- 94ef0b3: improve 2.0 docs\n- fdb2f57: update docs to use next.js 13\n- b1d7361: improve docs for 2.0\n- 74a3398: update docs for 2.0\n- d7f2bbc: adjust docs theme; rename options\n\n## 2.0.0-beta.43\n\n### Patch Changes\n\n- 9ab6dd0: allow adding additional navbar content via `navbar.extraContent`\n- 59e18b0: make `nextra`/`nextra-theme-docs`/`nextra-theme-blog` be compatible\n  with next 13\n- 2e2912e: fix project/chat icon could appear without provided link\n\n## 2.0.0-beta.42\n\n### Patch Changes\n\n- 2b6f3be: add missing border for search container\n- 32cd385: add new option `search.loading` for control loading text\n- fb37b5f: Close selector bracket for compat with old Safari.\n\n## 2.0.0-beta.41\n\n### Patch Changes\n\n- bd2cefa: Fix css classes with `eslint-plugin-tailwindcss`\n\n## 2.0.0-beta.40\n\n### Patch Changes\n\n- f569d90: missing `nx-` class prefixes in blog fix callout padding in docs\n\n## 2.0.0-beta.39\n\n### Minor Changes\n\n- 8f6d377: allow custom github domains\n\n### Patch Changes\n\n- f5bf2e4: fix margin-top for `<Tab />` content\n- 0c136ad: add missing `nx-` prefix in sidebar\n- 8ad9507: fix unable expanding folder items in sidebar\n- 416dfe2: add missing `nx-` prefixes in sidebar\n\n## 2.0.0-beta.38\n\n### Patch Changes\n\n- 05d068c: Add button label for hamburger menu\n\n## 2.0.0-beta.37\n\n### Patch Changes\n\n- 5b01537: Fix full docs directory list and active link\n\n## 2.0.0-beta.36\n\n### Patch Changes\n\n- 08a39e6: remove `resizeObserver` for dynamic content since it provoke jumps on\n  tabs switch when there is `#` anchor in url\n- 1c3fedb: add missing `nx-` prefixes to table/th/tr elements\n- 351fa45: add missing `nx-` prefix for `grow` class in `<LocaleSwitch />`\n\n## 2.0.0-beta.35\n\n### Patch Changes\n\n- ab629e6: Add correct aria values inside nav\n\n## 2.0.0-beta.34\n\n### Patch Changes\n\n- 4e4a37c: add new \"display\" property to \\_meta\n\n## 2.0.0-beta.33\n\n### Patch Changes\n\n- 580c433: add nx- to all tailwind classes for style isolation\n- 2533a6c: replace `main.extraContent` theme option with `main` option\n- c28a7f2: - setup `next-seo`\n  - add new theme option `getNextSeoProps`\n  - remove `titleSuffix` theme option in favor of\n    `getNextSeoProps.titleTemplate`\n  - by default pass `description`, `canonical`, `openGraph` values to\n    `<NextSeo />` component from page `frontMatter`, values can be overridden\n    with return value of `getNextSeoProps`\n\n## 2.0.0-beta.32\n\n### Patch Changes\n\n- fc8cca0: add `<InformationCircleIcon />` icon, improve `<Callout />` default\n  emojis\n- 723d42a: use `lightningcss` instead `cssnano`\n- 9f5af54: add `_meta.json#theme.collapsed` option for control state sidebar's\n  folders\n- f360f28: add new theme option `banner.dismissible`\n- a8a89e9: chore(docs): export ThemeSwitch & custom social\n\n## 2.0.0-beta.31\n\n### Patch Changes\n\n- cef5546: allow headings contain links\n- 5238bb4: feat(docs): support logoLink config option\n- f964802: do not hide default logo on mobile\n\n## 2.0.0-beta.30\n\n### Patch Changes\n\n- 1a7cd68: toc anchor links should have `display: inline-block`\n- c09f450: fix CTRL+K, on non non-mac use `e.ctrlKey` instead `e.metaKey`\n- 84d983f: fix(docs): correct query for hash with leading num\n- 7d2d5ee: use resolvedTheme instead renderedTheme + theme check\n\n## 2.0.0-beta.29\n\n### Patch Changes\n\n- 973ca49: fix rtl/ltr glitch on initial loading\n\n## 2.0.0-beta.28\n\n### Patch Changes\n\n- c2c0d90: fix(search): handle case when value is empty\n\n## 2.0.0-beta.27\n\n### Patch Changes\n\n- 21009c7: fix covered select options\n- 21009c7: better focus ui, use ring color as theme hue color\n\n## 2.0.0-beta.26\n\n### Patch Changes\n\n- a0e5847: Rename some docs theme configurations\n\n## 2.0.0-beta.25\n\n### Patch Changes\n\n- 4731fa7: Style improvements\n- e4cfb83: define page title in sidebar from `frontMatter.title` if page is not\n  specified in `_meta.json`\n- 9064112: make `<Tab />` accept `ComponentProps<'div'>`\n- c3e6227: add `overflow-x-scroll` for tables\n- d6d5ab8: Make sure arrows are aligned\n- ab6c0e6: fix disappearing toc issue in Firefox\n- ff8967c: add `Toggle Word Wrap` button for code-blocks (only for mobile)\n- ff8967c: fix missing `Copy Code` button in code-blocks without language\n- e2d603a: remove `getComponents` export, export `useMDXComponents` from\n  `@mdx-js/react` instead\n- 256154a: use \"next/future/image\" if\n  `\"experimental.images.allowFutureImage\": true` is set in next config\n- 256154a: replace images with `<NextImage />` even when url not relative but\n  that starts from `/` (public directory)\n- c4a9782: support custom hue theme color via `primaryHue`, `primaryHue.dark`\n  and `primaryHue.light` theme options\n- c3e6227: reuse nextra's scrollbar-y styles for scrollbar-x, adjust sidebar's\n  scrollbar-y\n\n## 2.0.0-beta.24\n\n### Patch Changes\n\n- bc52178: fix `editLink` option was not merged with default config `editLink`\n\n## 2.0.0-beta.23\n\n### Patch Changes\n\n- c8129a2: fix theme switcher style\n- 2ec8564: add `DocsThemeConfig.navbar` config option for overriding navbar\n\n## 2.0.0-beta.22\n\n### Patch Changes\n\n- 77361da: fix ESC button when still stays after pressed ESC\n- fdfe4f8: fix covered theme switch popup when i18n is not setup\n- 873561b: scrollbar is toc should be same as in sidebar\n\n## 2.0.0-beta.21\n\n## 2.0.0-beta.20\n\n### Patch Changes\n\n- e6771ca: fix search overlay styles on mobile\n- e6771ca: split css to `hamburger`/`scrollbar`/`typesetting-article` css files\n- e6771ca: fix edit on github button for cases when filename named as `index`\n- e6771ca: BREAKING! various theme config options was renamed, take a look of\n  renamed options\n  [here](https://github.com/shuding/nextra/blob/core/packages/nextra-theme-docs/src/constants.tsx)\n- 1ee3c92: reuse table styles from docs in blog\n- e6771ca: [Blog/Docs] Add copy to clipboard button for code-blocks. Add\n  `NextraConfig.unstable_defaultShowCopyCode` option to show button by default,\n  add `copy` and `copy=false` options for code-blocks\n- 5d852b6: break words in navlinks, remove unneeded `<div />` wrappers, align\n  text on right side for next link\n- e6771ca: hide search input in navbar on mobile\n- e6771ca: fix empty space in navbar when theme option `search.component: null`\n- e6771ca: add `editLink.component`\n- e6771ca: rename `meta.json` to `_meta.json`\n- e6771ca: clicking on folder should navigate to first children if `index` page\n  doesn't exist\n- 71528f1: show copy code button only on hover of container\n- e6771ca: fix callout shrinking from children content\n- e6771ca: rename `PageOpts.meta` to `PageOpts.frontMatter`\n- e6771ca: move `withLayout` logic directly in nextra loader\n- e6771ca: adjust active breadcrumb color\n- e6771ca: fix search input `ESC` icon vertical alignment\n\n## 2.0.0-beta.19\n\n### Patch Changes\n\n- 1fef548: allow head to be a ReactNode\n- ee270a4: fix extra space in flexsearch input after loading indexes\n- afaa26a: refactor toc, fix toc's styles on rtl, use `ref.current` instead\n  `document.getElementsByClassName`\n- cdc1c2f: prefer `ref.current` over `document.querySelector` in sidebar\n\n## 2.0.0-beta.18\n\n### Patch Changes\n\n- 7a32f8e: remove unneeded wrappers `<div />`s in `<Navbar />`\n- bea62a1: make the search input responsive in narrow screens\n- 24a02f8: reuse Flexsearch result styles on match-sorter search\n- a0c0eb8: allow override `MDXProvider.components`\n- 16bedce: `\"layout\": \"raw\"` should render `all` unstyled elements, except\n  `<a />`\n- 237faa9: add clear button for search input\n- 24a02f8: typescripify `<Flexsearch />`\n- 24a02f8: fix all RTL broken styles\n- a8c5883: add `config.bodyExtraContent` option\n- 8564919: extract `<Input/>` from `<Search/>` and `<Flexsearch/>`\n- 38769ca: prefer `ref.current.querySelector` over `document.querySelector`,\n  remove `load` prop in `<Search />`\n- 24a02f8: match-sorter search should highlight every match like flexsearch\n- 7bcbc98: add new `meta.json#theme.timestamp` option to hide\n  `Last updated on ...`\n- d16b2ba: move contexts to `./contexts` directory\n- 47938b1: remove unneeded `useRef` for `<details />`\n- 7373c1f: fix `useConfig`/`useRouter` inside `head()`\n- a9ca0b9: do not add `basePath` to the links\n- 0af6e79: `\"layout\": \"raw\"` should have unstyled `<a />` and `<p />` elements\n  as well\n- f99bbc2: Add `nextra-body-typesetting-article` back\n\n## 2.0.0-beta.17\n\n### Patch Changes\n\n- 2217f9c: fix `Warning: Prop`href`did not match. Server: \"#\" Client: ...`\n- 2217f9c: fix `next export` command\n- 2217f9c: replace `classnames` package with `clsx` as he's faster\n- 2217f9c: remove `locale` prop from theme config, forbid passing in\n  `renderComponent`\n\n## 2.0.0-beta.16\n\n### Patch Changes\n\n- 8bcb5e6: fix sideEffects in package.json\n- da2bea7: remove no longer used `icons` folder\n- 4825365: add `@types/github-slugger` instead of manually declaring type\n- dfbe996: extract `<Banner />` from `<Navbar />` to `components/banner.tsx`\n- a007c64: move DEFAULT_THEME and DEFAULT_PAGE_THEME to constants.tsx\n- b219821: fix body overflow\n- 48e0ac2: export `useConfig` and `useTheme`\n- da998e6: move react components to `components` folder and replace exports:\n  ```ts\n  import Bleed from 'nextra-theme-docs/bleed'\n  import Callout from 'nextra-theme-docs/callout'\n  import Collapse from 'nextra-theme-docs/collapse'\n  import { Tab, Tabs } from 'nextra-theme-docs/tabs'\n  ```\n  by\n  ```ts\n  import { Bleed, Callout, Collapse, Tab, Tabs } from 'nextra-theme-docs'\n  ```\n- 43409ad: fix: mdx theme is missing\n\n## 2.0.0-beta.15\n\n### Patch Changes\n\n- 88f999d: fix: UI improvements\n\n## 2.0.0-beta.14\n\n### Patch Changes\n\n- 96ed5c2: [nextra/nextra-theme-docs]: support both\n  `experimental.newNextLinkBehavior` - `true` and `false`\n- c8605d6: feat: New layout implementation\n\n## 2.0.0-beta.13\n\n### Patch Changes\n\n- cb87709: Fix flexsearch option being overridden\n- 4157b71: set lower build target and share code highlight theme through nextra\n- 6a4a593: fix: #531 unclickable breadcrumb\n- 06aa62f: feat: allow `import { getComponents } from 'nextra-theme-docs'`\n\n## 2.0.0-beta.12\n\n### Patch Changes\n\n- a5cac21: [docs/blog]: extract code styles and import in both themes\n- 3de0f41: chore(blog/docs): use `postcss-import` to import css variables styles\n- 97ca2e3: New feature: menu type\n- 76d1e30: [nextra-theme-docs]: fix `Warning: A title element received an array`\n  and possible `[object Object]` in title\n- bf74201: [nextra-theme-docs]: use new opacity modifier syntax for tailwindcss\n- 0f4795f: chore(nextra/blog/docs): provide types for PageOpts in loader\n\n## 2.0.0-beta.11\n\n### Patch Changes\n\n- 903ddf0: fix: should update scroll when height is dynamic\n- 3e3b0a9: feat: add cursor pointer to locale and theme menu\n- a0398e0: fix: avoid mutating nextConfig\n- 38ccce8: feat(docs): allow `Tabs.items` as `ReadonlyArray<ReactNode>`\n- fe2b714: upgrade to react 18\n- 6bdb9bf: fix: broken flexsearch styles\n- 78f1519: chore: Add strict-peer-dependencies=false\n- 582ad96: feat: bump `rehype-pretty-code` version, support `showLineNumbers`\n- c8bb94f: UI adjustments\n- 707fdc2: fix: Anchor links are not wrapping on the sidebar\n\n## 2.0.0-beta.10\n\n### Patch Changes\n\n- af72f85: chore(nextra-theme-docs): provide type for\n  `DocsThemeConfig.nextThemes` instead of `object`\n- 97e6141: fix(nextra/docs): fallback search to `en-US` instead `default`\n- 699d131: feat(nextra/docs/blog): allow import `.md`/`.mdx` as well\n- 03e90d8: refresh build system with tsup and fix nextra type\n\n## 2.0.0-beta.9\n\n### Patch Changes\n\n- 6644bd5: pass unstable_flexsearch\n- c15f570: fix: query should not affect nav highlight\n- 4730bdc: chore(nextra-theme-docs): refactor `theme-context.ts`\n- 94a8587: chore: extract `svg` icons in `/icons` folder, reusing same icons\n  `<MoonIcon />` / `<SunIcon />` in blog from docs\n- e573175: Fix release CI\n- c380989: fix(docs): types is missing in bundle\n- d34f9f2: feat(nextra-theme-docs): update discord logo to the new one\n- 7053959: chore(nextra-theme-docs): remove unneeded `transform-none` css class\n\n## 2.0.0-beta.8\n\n### Patch Changes\n\n- 009bf6a: Fix release workflow.\n\n## 2.0.0-beta.7\n"
  },
  {
    "path": "packages/nextra-theme-docs/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Shu Ding\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.\n"
  },
  {
    "path": "packages/nextra-theme-docs/README.md",
    "content": "# nextra-theme-docs\n\nA documentation site theme for [Nextra](https://github.com/shuding/nextra).\n\n## Example\n\nhttps://nextra.site\n"
  },
  {
    "path": "packages/nextra-theme-docs/css/hamburger.css",
    "content": ".nextra-hamburger svg {\n  g,\n  path {\n    @apply x:motion-reduce:transition-none!;\n  }\n\n  --animation: transform 0.15s cubic-bezier(0.25, 1, 0.5, 1);\n\n  g {\n    @apply x:origin-center;\n    transition: var(--animation);\n  }\n\n  path {\n    opacity: 1;\n    transition:\n      var(--animation) 0.15s,\n      opacity 0.15s ease 0.15s;\n  }\n\n  &.open {\n    path {\n      transition:\n        var(--animation),\n        opacity 0s ease 0.15s;\n    }\n\n    & > path {\n      opacity: 0;\n    }\n\n    g {\n      transition: var(--animation) 0.15s;\n\n      &:nth-of-type(1) {\n        transform: rotate(45deg);\n\n        path {\n          transform: translate3d(0, 6px, 0);\n        }\n      }\n\n      &:nth-of-type(2) {\n        transform: rotate(-45deg);\n\n        path {\n          transform: translate3d(0, -6px, 0);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/css/typesetting-article.css",
    "content": "article.nextra-body-typesetting-article {\n  font-size: 17px;\n  font-feature-settings:\n    'rlig' 1,\n    'calt' 1;\n  h1 {\n    @apply x:mt-6 x:mb-4 x:text-center;\n    font-size: 2.5rem;\n  }\n  h2 {\n    @apply x:border-none;\n  }\n  a {\n    @apply x:no-underline x:hover:underline;\n  }\n  p {\n    @apply x:leading-8;\n  }\n  code {\n    @apply x:border-none x:dark:bg-neutral-700;\n  }\n  pre code {\n    @apply x:dark:bg-transparent;\n  }\n  .subheading-anchor {\n    @apply x:hover:no-underline;\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/package.json",
    "content": "{\n  \"name\": \"nextra-theme-docs\",\n  \"version\": \"4.6.2\",\n  \"description\": \"A Nextra theme for documentation sites.\",\n  \"repository\": \"https://github.com/shuding/nextra\",\n  \"author\": \"Shu Ding <g@shud.in>\",\n  \"license\": \"MIT\",\n  \"types\": \"./dist/index.d.mts\",\n  \"exports\": {\n    \"./style.css\": \"./dist/style.css\",\n    \"./style-prefixed.css\": \"./dist/style-prefixed.css\",\n    \".\": {\n      \"types\": \"./dist/index.d.mts\",\n      \"import\": \"./dist/index.js\"\n    }\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"build\": \"NODE_ENV=production tsup\",\n    \"dev\": \"tsup --watch . --watch ../nextra/src --watch ../nextra/styles\",\n    \"prepublishOnly\": \"pnpm build\",\n    \"test\": \"vitest --typecheck\",\n    \"types:check\": \"tsc --noEmit\"\n  },\n  \"peerDependencies\": {\n    \"next\": \">=14\",\n    \"nextra\": \"workspace:*\",\n    \"react\": \">=18\",\n    \"react-dom\": \">=18\"\n  },\n  \"dependencies\": {\n    \"@headlessui/react\": \"^2.1.2\",\n    \"clsx\": \"^2.1.0\",\n    \"next-themes\": \"^0.4.0\",\n    \"react-compiler-runtime\": \"^19.1.0-rc.2\",\n    \"scroll-into-view-if-needed\": \"^3.1.0\",\n    \"zod\": \"^4.1.12\",\n    \"zustand\": \"^5.0.1\"\n  },\n  \"devDependencies\": {\n    \"@tailwindcss/cli\": \"4.1.10\",\n    \"@tailwindcss/postcss\": \"4.1.10\",\n    \"@testing-library/react\": \"^16.0.0\",\n    \"@types/react\": \"^19.1.8\",\n    \"@vitejs/plugin-react\": \"^4.3.4\",\n    \"esbuild-react-compiler-plugin\": \"workspace:*\",\n    \"jsdom\": \"^26.0.0\",\n    \"next\": \"^16.0.7\",\n    \"nextra\": \"workspace:*\",\n    \"postcss\": \"^8.4.49\",\n    \"react\": \"19.1.0\",\n    \"tailwindcss\": \"4.1.10\",\n    \"vitest\": \"^3.0.0\",\n    \"zx\": \"^8.2.4\"\n  },\n  \"sideEffects\": false\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/postcss.config.mjs",
    "content": "/** @type {import('postcss').Postcss} */\nexport default {\n  plugins: {\n    '@tailwindcss/postcss': {}\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/setup-files.ts",
    "content": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { generateTsFromZod } from '../nextra/src/server/tsdoc/zod-to-ts'\nimport { LayoutPropsSchema } from './src/schemas'\n\nawait fs.writeFile(\n  path.resolve('src', 'types.generated.ts'),\n  `export interface LayoutProps ${generateTsFromZod(LayoutPropsSchema)}`\n)\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/__tests__/git-url-parse.test.ts",
    "content": "import { gitUrlParse } from '../utils/git-url-parse'\n\ndescribe('gitUrlParse', () => {\n  it('should work', () => {\n    const result = gitUrlParse(\n      'https://github.com/B2o5T/graphql-eslint/tree/master/website'\n    )\n    expect(result).toEqual({\n      href: 'https://github.com/B2o5T/graphql-eslint/tree/master/website',\n      name: 'graphql-eslint',\n      origin: 'https://github.com',\n      owner: 'B2o5T'\n    })\n  })\n})\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/__tests__/layout-props.test-d.ts",
    "content": "import type { z } from 'zod'\nimport type { IsEqual } from '../../../nextra/src/server/__tests__/test-utils'\nimport type { LayoutPropsSchema } from '../schemas'\nimport type { LayoutProps } from '../types.generated'\n\ndescribe('Assert types', () => {\n  test('LayoutProps should be identical', () => {\n    type Expected = z.input<typeof LayoutPropsSchema>\n    type Actual = LayoutProps\n    assertType<IsEqual<Expected, Actual>>(true)\n    return expectTypeOf<Actual>().toEqualTypeOf<Expected>\n  })\n})\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/__tests__/mdx-components.test-d.ts",
    "content": "import { useMDXComponents } from '../mdx-components'\n\ndescribe('useMDXComponents', () => {\n  test('when `MDXComponent`s are provided', () => {\n    const components = useMDXComponents({ figcaption: () => null })\n    expectTypeOf(components['img']).toBeFunction()\n    expectTypeOf(components['a']).toBeFunction()\n    expectTypeOf(components['h1']).toBeFunction()\n    expectTypeOf(components['figcaption']).toBeFunction()\n\n    // @ts-expect-error -- assert does not exist on type\n    expectTypeOf(components['figure']).not.toBeFunction()\n  })\n  test('when `MDXComponent`s are not provided', () => {\n    const components = useMDXComponents()\n    expectTypeOf(components['img']).toBeFunction()\n    expectTypeOf(components['a']).toBeFunction()\n    expectTypeOf(components['h1']).toBeFunction()\n\n    // @ts-expect-error -- assert does not exist on type\n    expectTypeOf(components['figure']).not.toBeFunction()\n  })\n})\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/404/index.client.tsx",
    "content": "'use client'\n\nimport { usePathname } from 'next/navigation'\nimport { useMounted } from 'nextra/hooks'\nimport type { FC, ReactNode } from 'react'\nimport { Link } from '../../mdx-components/link'\nimport { useThemeConfig } from '../../stores'\nimport { getGitIssueUrl } from '../../utils'\n\nexport const NotFoundLink: FC<{\n  children: ReactNode\n  labels: string\n}> = ({ children, labels }) => {\n  const config = useThemeConfig()\n  const pathname = usePathname()\n  const mounted = useMounted()\n  const ref = mounted && document.referrer\n  const referrer = ref ? ` from \"${ref}\"` : ''\n\n  return (\n    <Link\n      className=\"x:mt-[1.25em]\"\n      href={getGitIssueUrl({\n        repository: config.docsRepositoryBase,\n        title: `Found broken \"${mounted ? pathname : ''}\" link${referrer}. Please fix!`,\n        labels\n      })}\n    >\n      {children}\n    </Link>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/404/index.tsx",
    "content": "import cn from 'clsx'\nimport type { FC, ReactNode } from 'react'\nimport { H1 } from '../../mdx-components/heading'\nimport { NotFoundLink } from './index.client'\n\ntype NotFoundPageProps = {\n  /**\n   * Content of the link.\n   * @default 'Submit an issue about broken link'\n   */\n  content?: ReactNode\n  /**\n   * Labels that can be added to the newly created issue.\n   * @default 'bug'\n   */\n  labels?: string\n  /**\n   * Top content of the page.\n   * @default <H1>404: Page Not Found</H1>\n   */\n  children?: ReactNode\n  /** CSS class name. */\n  className?: string\n}\n\n// Fixes react compiler error Expression type `JSXElement` cannot be safely reordered\nconst defaultChildren = <H1>404: Page Not Found</H1>\n\nexport const NotFoundPage: FC<NotFoundPageProps> = ({\n  content = 'Submit an issue about broken link',\n  labels = 'bug',\n  children = defaultChildren,\n  className\n}) => {\n  return (\n    <div\n      className={cn(\n        'x:flex x:flex-col x:justify-center x:items-center x:h-[calc(100dvh-var(--nextra-navbar-height))]',\n        className\n      )}\n    >\n      {children}\n      <NotFoundLink labels={labels}>{content}</NotFoundLink>\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/back-to-top.tsx",
    "content": "import cn from 'clsx'\nimport { Button } from 'nextra/components'\nimport { ArrowRightIcon } from 'nextra/icons'\nimport type { ComponentProps, FC, ReactNode } from 'react'\n\nconst SCROLL_TO_OPTIONS = { top: 0, behavior: 'smooth' } as const\n\nconst scrollToTop: ComponentProps<'button'>['onClick'] = event => {\n  const buttonElement = event.currentTarget\n  const tocElement = buttonElement.parentElement!.parentElement!\n\n  window.scrollTo(SCROLL_TO_OPTIONS)\n  tocElement.scrollTo(SCROLL_TO_OPTIONS)\n\n  // Fixes https://github.com/facebook/react/issues/20770\n  // Fixes https://github.com/shuding/nextra/issues/2917\n  buttonElement.disabled = true\n}\n\nexport const BackToTop: FC<{\n  children: ReactNode\n  className?: string\n  hidden: boolean\n}> = ({ children, className, hidden }) => {\n  return (\n    <Button\n      // elements with `aria-hidden: true` must not be focusable or contain focusable elements\n      aria-hidden={hidden ? 'true' : undefined}\n      onClick={scrollToTop}\n      disabled={hidden}\n      className={({ disabled }) =>\n        cn(\n          'x:flex x:items-center x:gap-1.5',\n          'x:whitespace-nowrap', // Safari\n          disabled ? 'x:opacity-0' : 'x:opacity-100',\n          className\n        )\n      }\n    >\n      {children}\n      <ArrowRightIcon\n        height=\"1.1em\"\n        className=\"x:-rotate-90 x:border x:rounded-full x:border-current\"\n      />\n    </Button>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/breadcrumb.tsx",
    "content": "import cn from 'clsx'\n// eslint-disable-next-line no-restricted-imports -- since we don't need newWindow prop\nimport NextLink from 'next/link'\nimport { ArrowRightIcon } from 'nextra/icons'\nimport type { Item } from 'nextra/normalize-pages'\nimport type { FC } from 'react'\nimport { Fragment } from 'react'\nimport { extractStringsFromReactNode } from '../utils'\n\nexport const Breadcrumb: FC<{\n  activePath: Item[]\n}> = ({ activePath }) => {\n  return (\n    <div className=\"nextra-breadcrumb x:mt-1.5 x:flex x:items-center x:gap-1 x:overflow-hidden x:text-sm x:text-gray-600 x:dark:text-gray-400 x:contrast-more:text-current\">\n      {activePath.map((item, index, arr) => {\n        const nextItem = arr[index + 1]\n        const href = nextItem\n          ? 'frontMatter' in item\n            ? item.route\n            : // @ts-expect-error -- fixme\n              item.children[0].route === nextItem.route\n              ? ''\n              : // @ts-expect-error -- fixme\n                item.children[0].route\n          : ''\n\n        const ComponentToUse = href ? NextLink : 'span'\n\n        return (\n          <Fragment key={item.route + item.name}>\n            {index > 0 && (\n              <ArrowRightIcon\n                height=\"14\"\n                className=\"x:shrink-0 x:rtl:rotate-180\"\n              />\n            )}\n            <ComponentToUse\n              className={cn(\n                'x:whitespace-nowrap x:transition-colors',\n                nextItem\n                  ? 'x:min-w-6 x:overflow-hidden x:text-ellipsis'\n                  : 'x:font-medium x:text-black x:dark:text-gray-100',\n                href &&\n                  'x:focus-visible:nextra-focus x:ring-inset x:hover:text-gray-900 x:dark:hover:text-gray-100'\n              )}\n              title={extractStringsFromReactNode(item.title)}\n              {...(href && { href, prefetch: false })}\n            >\n              {item.title}\n            </ComponentToUse>\n          </Fragment>\n        )\n      })}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/copy-page.tsx",
    "content": "import cn from 'clsx'\nimport { Button, Select } from 'nextra/components'\nimport { useCopy } from 'nextra/hooks'\nimport {\n  ArrowRightIcon,\n  ChatGPTIcon,\n  ClaudeIcon,\n  CopyIcon,\n  LinkArrowIcon\n} from 'nextra/icons'\nimport type { FC, SVGProps } from 'react'\n\nconst Item: FC<{\n  icon: FC<SVGProps<SVGElement>>\n  title: string\n  description: string\n  isExternal?: boolean\n}> = ({ icon: Icon, title, description, isExternal }) => {\n  return (\n    <div className=\"x:flex x:gap-3 x:items-center\">\n      <Icon width=\"16\" />\n      <div className=\"x:flex x:flex-col\">\n        <span className=\"x:font-medium x:flex x:gap-1\">\n          {title}\n          {isExternal && <LinkArrowIcon height=\"1em\" />}\n        </span>\n        <span className=\"x:text-xs\">{description}</span>\n      </div>\n    </div>\n  )\n}\n\nexport const CopyPage: FC<{ sourceCode: string }> = ({ sourceCode }) => {\n  const { copy, isCopied } = useCopy()\n\n  function handleCopy() {\n    copy(sourceCode)\n  }\n\n  return (\n    <div className=\"x:border x:inline-flex x:rounded-md x:items-stretch nextra-border x:float-end x:overflow-hidden\">\n      <Button\n        className={({ hover }) =>\n          cn(\n            'x:ps-2 x:pe-1 x:flex x:gap-2 x:text-sm x:font-medium x:items-center',\n            isCopied && 'x:opacity-70',\n            hover &&\n              'x:bg-gray-200 x:text-gray-900 x:dark:bg-primary-100/5 x:dark:text-gray-50'\n          )\n        }\n        onClick={handleCopy}\n      >\n        <CopyIcon width=\"16\" />\n        {isCopied ? 'Copied' : 'Copy page'}\n      </Button>\n      <Select\n        anchor={{ to: 'bottom end', gap: 10 }}\n        className=\"x:rounded-none\"\n        options={[\n          {\n            id: 'copy',\n            name: (\n              <Item\n                icon={CopyIcon}\n                title=\"Copy page\"\n                description=\"Copy page as Markdown for LLMs\"\n              />\n            )\n          },\n          {\n            id: 'chatgpt',\n            name: (\n              <Item\n                icon={ChatGPTIcon}\n                title=\"Open in ChatGPT\"\n                description=\"Ask questions about this page\"\n                isExternal\n              />\n            )\n          },\n          {\n            id: 'claude',\n            name: (\n              <Item\n                icon={ClaudeIcon}\n                title=\"Open in Claude\"\n                description=\"Ask questions about this page\"\n                isExternal\n              />\n            )\n          }\n        ]}\n        value=\"\"\n        selectedOption={<ArrowRightIcon width=\"12\" className=\"x:rotate-90\" />}\n        onChange={value => {\n          if (value === 'copy') {\n            handleCopy()\n            return\n          }\n          const url =\n            value === 'chatgpt'\n              ? 'chatgpt.com/?hints=search&prompt'\n              : 'claude.ai/new?q'\n          const query = `Read from ${location.href} so I can ask questions about it.`\n          window.open(`https://${url}=${encodeURIComponent(query)}`, '_blank')\n        }}\n      />\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/footer/index.tsx",
    "content": "import cn from 'clsx'\nimport type { ComponentProps, FC } from 'react'\nimport { LocaleSwitch } from '../locale-switch'\nimport { ThemeSwitch } from '../theme-switch'\nimport { Switchers } from './switchers'\n\nexport const Footer: FC<ComponentProps<'footer'>> = ({\n  className,\n  children,\n  ...props\n}) => {\n  return (\n    <div className=\"x:bg-gray-100 x:pb-[env(safe-area-inset-bottom)] x:dark:bg-neutral-900 x:print:bg-transparent\">\n      <Switchers>\n        <div className=\"x:mx-auto x:flex x:max-w-(--nextra-content-width) x:gap-2 x:py-2 x:px-4\">\n          <LocaleSwitch />\n          <ThemeSwitch />\n        </div>\n      </Switchers>\n      <hr className=\"nextra-border\" />\n      {children && (\n        <footer\n          className={cn(\n            'x:mx-auto x:flex x:max-w-(--nextra-content-width) x:justify-center x:py-12 x:text-gray-600 x:dark:text-gray-400 x:md:justify-start',\n            'x:pl-[max(env(safe-area-inset-left),1.5rem)] x:pr-[max(env(safe-area-inset-right),1.5rem)]',\n            className\n          )}\n          {...props}\n        >\n          {children}\n        </footer>\n      )}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/footer/switchers.ts",
    "content": "'use client'\n\nimport type { FC, ReactNode } from 'react'\nimport { useConfig, useThemeConfig } from '../../stores'\n\nexport const Switchers: FC<{ children: ReactNode }> = ({ children }) => {\n  const { hideSidebar } = useConfig()\n  const { i18n, darkMode } = useThemeConfig()\n\n  if (hideSidebar && (darkMode || i18n.length)) {\n    return children\n  }\n  return null\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/index.ts",
    "content": "export { Breadcrumb } from './breadcrumb'\nexport { CopyPage } from './copy-page'\nexport { Footer } from './footer'\nexport { LastUpdated } from './last-updated'\nexport { LocaleSwitch } from './locale-switch'\nexport { Pagination } from './pagination'\nexport { Navbar } from './navbar'\nexport { NotFoundPage } from './404/index.js'\nexport { Sidebar, MobileNav } from './sidebar'\nexport { ThemeSwitch } from './theme-switch'\nexport { TOC } from './toc'\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/last-updated.tsx",
    "content": "'use client'\n\nimport { usePathname } from 'next/navigation'\nimport type { FC, ReactNode } from 'react'\nimport { useThemeConfig } from '../stores'\n\nexport const LastUpdated: FC<{\n  date?: Date\n  children?: ReactNode\n  locale?: string\n}> = ({ date, children = 'Last updated on', locale = 'en' }) => {\n  const { i18n } = useThemeConfig()\n  const pathname = usePathname()\n\n  if (!date) {\n    return null\n  }\n\n  const dateLocale = i18n.length ? pathname.split('/', 2)[1] : locale\n  return (\n    <>\n      {children}{' '}\n      <time\n        dateTime={date.toISOString()}\n        // Can provoke React 418 error https://react.dev/errors/418\n        suppressHydrationWarning\n      >\n        {date.toLocaleDateString(dateLocale, {\n          day: 'numeric',\n          month: 'long',\n          year: 'numeric'\n        })}\n      </time>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/locale-switch.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport { addBasePath } from 'next/dist/client/add-base-path'\nimport { usePathname } from 'next/navigation'\nimport { Select } from 'nextra/components'\nimport { GlobeIcon } from 'nextra/icons'\nimport type { FC } from 'react'\nimport { useThemeConfig } from '../stores'\n\nconst ONE_YEAR = 365 * 24 * 60 * 60 * 1000\n\ninterface LocaleSwitchProps {\n  lite?: boolean\n  className?: string\n}\n\nexport const LocaleSwitch: FC<LocaleSwitchProps> = ({ lite, className }) => {\n  const { i18n } = useThemeConfig()\n  const pathname = usePathname()\n  if (!i18n.length) return null\n\n  const [, locale] = pathname.split('/', 2)\n  return (\n    <Select\n      title=\"Change language\"\n      className={cn('x:flex x:items-center x:gap-2', className)}\n      onChange={lang => {\n        const date = new Date(Date.now() + ONE_YEAR)\n        document.cookie = `NEXT_LOCALE=${lang}; expires=${date.toUTCString()}; path=/`\n        location.href = addBasePath(pathname.replace(`/${locale}`, `/${lang}`))\n      }}\n      value={locale!}\n      selectedOption={\n        <>\n          <GlobeIcon height=\"12\" />\n          {!lite && i18n.find(l => locale === l.locale)?.name}\n        </>\n      }\n      options={i18n.map(l => ({\n        id: l.locale,\n        name: l.name\n      }))}\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/navbar/index.client.tsx",
    "content": "'use client'\n\nimport {\n  MenuItem as _MenuItem,\n  Menu,\n  MenuButton,\n  MenuItems\n} from '@headlessui/react'\nimport cn from 'clsx'\nimport { Anchor, Button } from 'nextra/components'\nimport { useFSRoute } from 'nextra/hooks'\nimport { ArrowRightIcon, MenuIcon } from 'nextra/icons'\nimport type { MenuItem } from 'nextra/normalize-pages'\nimport type { FC, ReactNode } from 'react'\nimport { setMenu, useConfig, useMenu, useThemeConfig } from '../../stores'\n\nconst classes = {\n  link: cn(\n    'x:text-sm x:contrast-more:text-gray-700 x:contrast-more:dark:text-gray-100 x:whitespace-nowrap',\n    'x:text-gray-600 x:hover:text-black x:dark:text-gray-400 x:dark:hover:text-gray-200',\n    'x:ring-inset x:transition-colors'\n  )\n}\n\nconst NavbarMenu: FC<{\n  menu: MenuItem\n  children: ReactNode\n}> = ({ menu, children }) => {\n  const routes = Object.fromEntries(\n    (menu.children || []).map(route => [route.name, route])\n  )\n  return (\n    <Menu>\n      <MenuButton\n        className={({ focus }) =>\n          cn(\n            classes.link,\n            'x:items-center x:flex x:gap-1.5 x:cursor-pointer',\n            focus && 'x:nextra-focus'\n          )\n        }\n      >\n        {children}\n        <ArrowRightIcon\n          height=\"14\"\n          className=\"x:*:origin-center x:*:transition-transform x:*:rotate-90\"\n        />\n      </MenuButton>\n      <MenuItems\n        transition\n        className={cn(\n          'x:focus-visible:nextra-focus',\n          'nextra-scrollbar x:motion-reduce:transition-none',\n          // From https://headlessui.com/react/menu#adding-transitions\n          'x:origin-top x:transition x:duration-200 x:ease-out x:data-closed:scale-95 x:data-closed:opacity-0',\n          'x:border x:border-black/5 x:dark:border-white/20',\n          'x:z-30 x:rounded-md x:py-1 x:text-sm x:shadow-lg',\n          'x:backdrop-blur-md x:bg-nextra-bg/70',\n          // headlessui adds max-height as style, use !important to override\n          'x:max-h-[min(calc(100vh-5rem),256px)]!'\n        )}\n        anchor={{ to: 'bottom', gap: 10, padding: 16 }}\n      >\n        {Object.entries(\n          // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- fixme\n          (menu.items as Record<string, { title: string; href?: string }>) || {}\n        ).map(([key, item]) => (\n          <_MenuItem\n            key={key}\n            as={Anchor}\n            href={item.href || routes[key]?.route}\n            className={({ focus }) =>\n              cn(\n                'x:block x:py-1.5 x:transition-colors x:ps-3 x:pe-9',\n                focus\n                  ? 'x:text-gray-900 x:dark:text-gray-100'\n                  : 'x:text-gray-600 x:dark:text-gray-400'\n              )\n            }\n          >\n            {item.title}\n          </_MenuItem>\n        ))}\n      </MenuItems>\n    </Menu>\n  )\n}\n\nconst isMenu = (page: any): page is MenuItem => page.type === 'menu'\n\nexport const ClientNavbar: FC<{\n  children: ReactNode\n  className?: string\n}> = ({ children, className }) => {\n  const items = useConfig().normalizePagesResult.topLevelNavbarItems\n  const themeConfig = useThemeConfig()\n\n  const pathname = useFSRoute()\n  const menu = useMenu()\n\n  return (\n    <>\n      <div\n        className={cn(\n          'x:flex x:gap-4 x:overflow-x-auto nextra-scrollbar x:py-1.5 x:max-md:hidden',\n          className\n        )}\n      >\n        {items.map((page, _index, arr) => {\n          if ('display' in page && page.display === 'hidden') return\n          if (isMenu(page)) {\n            return (\n              <NavbarMenu key={page.name} menu={page}>\n                {page.title}\n              </NavbarMenu>\n            )\n          }\n          const href =\n            // If it's a directory\n            ('frontMatter' in page ? page.route : page.firstChildRoute) ||\n            page.href ||\n            page.route\n\n          const isCurrentPage =\n            href === pathname ||\n            (pathname.startsWith(page.route + '/') &&\n              arr.every(item => !('href' in item) || item.href !== pathname)) ||\n            undefined\n\n          return (\n            <Anchor\n              href={href}\n              key={page.name}\n              className={cn(\n                classes.link,\n                'x:aria-[current]:font-medium x:aria-[current]:subpixel-antialiased x:aria-[current]:text-current'\n              )}\n              aria-current={isCurrentPage}\n            >\n              {page.title}\n            </Anchor>\n          )\n        })}\n      </div>\n      {themeConfig.search && (\n        <div className=\"x:max-md:hidden\">{themeConfig.search}</div>\n      )}\n\n      {children}\n\n      <Button\n        aria-label=\"Menu\"\n        className={({ active }) =>\n          cn('nextra-hamburger x:md:hidden', active && 'x:bg-gray-400/20')\n        }\n        onClick={() => setMenu(prev => !prev)}\n      >\n        <MenuIcon height=\"24\" className={cn({ open: menu })} />\n      </Button>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/navbar/index.tsx",
    "content": "/* TODO: eslint typescript-sort-keys/interface: error */\nimport cn from 'clsx'\n// eslint-disable-next-line no-restricted-imports -- since we don't need `newWindow` prop\nimport NextLink from 'next/link'\nimport { Anchor } from 'nextra/components'\nimport { DiscordIcon, GitHubIcon } from 'nextra/icons'\nimport type { FC, ReactNode } from 'react'\nimport { ClientNavbar } from './index.client'\n\ninterface NavbarProps {\n  /**\n   * Extra content after the last icon.\n   */\n  children?: ReactNode\n  /**\n   * Specifies whether the logo should have a link or provides the URL for the logo's link.\n   * @default true\n   */\n  logoLink?: string | boolean\n  /**\n   * Logo of the website.\n   */\n  logo: ReactNode\n  /**\n   * URL of the project homepage.\n   */\n  projectLink?: string\n  /**\n   * Icon of the project link.\n   * @default <GitHubIcon />\n   */\n  projectIcon?: ReactNode\n  /**\n   * URL of the chat link.\n   */\n  chatLink?: string\n  /**\n   * Icon of the chat link.\n   * @default <DiscordIcon />\n   */\n  chatIcon?: ReactNode\n  /**\n   * CSS class name.\n   */\n  className?: string\n  /**\n   * Aligns navigation links to the specified side.\n   * @default 'right'\n   */\n  align?: 'left' | 'right'\n}\n\n// Fix compiler error\n// Expression type `JSXElement` cannot be safely reordered\nconst defaultGitHubIcon = (\n  <GitHubIcon height=\"24\" aria-label=\"Project repository\" />\n)\nconst defaultChatIcon = <DiscordIcon width=\"24\" />\n\nexport const Navbar: FC<NavbarProps> = ({\n  children,\n  logoLink = true,\n  logo,\n  projectLink,\n  projectIcon = defaultGitHubIcon,\n  chatLink,\n  chatIcon = defaultChatIcon,\n  className,\n  align = 'right'\n}) => {\n  const logoClass = cn(\n    'x:flex x:items-center',\n    align === 'left' ? 'x:max-md:me-auto' : 'x:me-auto'\n  )\n  return (\n    <header\n      className={cn(\n        'nextra-navbar x:sticky x:top-0 x:z-30 x:w-full x:bg-transparent x:print:hidden',\n        'x:max-md:[.nextra-banner:not([class$=hidden])~&]:top-(--nextra-banner-height)'\n      )}\n    >\n      <div\n        className={cn(\n          'nextra-navbar-blur',\n          'x:absolute x:-z-1 x:size-full',\n          'nextra-border x:border-b',\n          'x:backdrop-blur-md x:bg-nextra-bg/70'\n        )}\n      />\n      <nav\n        style={{ height: 'var(--nextra-navbar-height)' }}\n        className={cn(\n          'x:mx-auto x:flex x:max-w-(--nextra-content-width) x:items-center x:gap-4 x:pl-[max(env(safe-area-inset-left),1.5rem)] x:pr-[max(env(safe-area-inset-right),1.5rem)]',\n          'x:justify-end',\n          className\n        )}\n      >\n        {logoLink ? (\n          <NextLink\n            href={typeof logoLink === 'string' ? logoLink : '/'}\n            className={cn(\n              logoClass,\n              'x:transition-opacity x:focus-visible:nextra-focus x:hover:opacity-75'\n            )}\n            aria-label=\"Home page\"\n          >\n            {logo}\n          </NextLink>\n        ) : (\n          <div className={logoClass}>{logo}</div>\n        )}\n        <ClientNavbar className={align === 'left' ? 'x:me-auto' : ''}>\n          {projectLink && <Anchor href={projectLink}>{projectIcon}</Anchor>}\n          {chatLink && <Anchor href={chatLink}>{chatIcon}</Anchor>}\n          {children}\n        </ClientNavbar>\n      </nav>\n    </header>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/pagination.tsx",
    "content": "import cn from 'clsx'\n// eslint-disable-next-line no-restricted-imports -- since we don't need `newWindow` prop\nimport NextLink from 'next/link'\nimport { ArrowRightIcon } from 'nextra/icons'\nimport type { FC } from 'react'\nimport { useConfig, useThemeConfig } from '../stores'\nimport { extractStringsFromReactNode } from '../utils'\n\nconst classes = {\n  link: cn(\n    'x:focus-visible:nextra-focus x:text-gray-600 x:dark:text-gray-400',\n    'x:hover:text-gray-800 x:dark:hover:text-gray-200',\n    'x:contrast-more:text-gray-700 x:contrast-more:dark:text-gray-100',\n    'x:flex x:max-w-[50%] x:items-center x:gap-1 x:py-4 x:text-base x:font-medium x:transition-colors x:[word-break:break-word] x:md:text-lg'\n  ),\n  icon: cn('x:inline x:shrink-0')\n}\n\nexport const Pagination: FC = () => {\n  const { flatDocsDirectories, activeIndex } = useConfig().normalizePagesResult\n  const { navigation } = useThemeConfig()\n\n  // @ts-expect-error -- fixme\n  let prev = navigation.prev && flatDocsDirectories[activeIndex - 1]\n  // @ts-expect-error -- fixme\n  let next = navigation.next && flatDocsDirectories[activeIndex + 1]\n\n  if (prev && !prev.isUnderCurrentDocsTree) prev = false\n  if (next && !next.isUnderCurrentDocsTree) next = false\n\n  if (!prev && !next) return null\n\n  return (\n    <div\n      className={cn(\n        'x:mb-8 x:flex x:items-center x:border-t x:pt-8 nextra-border',\n        'x:print:hidden'\n      )}\n    >\n      {prev && (\n        <NextLink\n          href={prev.route}\n          title={extractStringsFromReactNode(prev.title)}\n          className={cn(classes.link, 'x:pe-4')}\n          prefetch={false}\n        >\n          <ArrowRightIcon\n            height=\"20\"\n            className={cn(classes.icon, 'x:ltr:rotate-180')}\n          />\n          {prev.title}\n        </NextLink>\n      )}\n      {next && (\n        <NextLink\n          href={next.route}\n          title={extractStringsFromReactNode(next.title)}\n          className={cn(classes.link, 'x:ps-4 x:ms-auto x:text-end')}\n          prefetch={false}\n        >\n          {next.title}\n          <ArrowRightIcon\n            height=\"20\"\n            className={cn(classes.icon, 'x:rtl:rotate-180')}\n          />\n        </NextLink>\n      )}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/sidebar.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport { usePathname } from 'next/navigation'\nimport type { Heading } from 'nextra'\nimport { Anchor, Button, Collapse } from 'nextra/components'\nimport { useFSRoute, useHash } from 'nextra/hooks'\nimport { ArrowRightIcon, ExpandIcon } from 'nextra/icons'\nimport type { Item, MenuItem, PageItem } from 'nextra/normalize-pages'\nimport type {\n  ComponentProps,\n  FC,\n  FocusEventHandler,\n  MouseEventHandler,\n  ReactNode\n} from 'react'\nimport { forwardRef, useEffect, useId, useRef, useState } from 'react'\nimport scrollIntoView from 'scroll-into-view-if-needed'\nimport {\n  setFocusedRoute,\n  setMenu,\n  useActiveAnchor,\n  useConfig,\n  useFocusedRoute,\n  useMenu,\n  useThemeConfig,\n  useTOC\n} from '../stores'\nimport { LocaleSwitch } from './locale-switch'\nimport { ThemeSwitch } from './theme-switch'\n\nconst TreeState: Record<string, boolean> = Object.create(null)\n\nconst classes = {\n  link: cn(\n    'x:flex x:rounded x:px-2 x:py-1.5 x:text-sm x:transition-colors x:[word-break:break-word]',\n    'x:cursor-pointer x:contrast-more:border'\n  ),\n  inactive: cn(\n    'x:text-gray-600 x:hover:bg-gray-100 x:hover:text-gray-900',\n    'x:dark:text-neutral-400 x:dark:hover:bg-primary-100/5 x:dark:hover:text-gray-50',\n    'x:contrast-more:text-gray-900 x:contrast-more:dark:text-gray-50',\n    'x:contrast-more:border-transparent x:contrast-more:hover:border-gray-900 x:contrast-more:dark:hover:border-gray-50'\n  ),\n  active: cn(\n    'x:bg-primary-100 x:font-semibold x:text-primary-800 x:dark:bg-primary-400/10 x:dark:text-primary-600',\n    'x:contrast-more:border-primary-500!'\n  ),\n  list: cn('x:grid x:gap-1'),\n  border: cn(\n    'x:relative x:before:absolute x:before:inset-y-1',\n    'x:before:w-px x:before:bg-gray-200 x:before:content-[\"\"] x:dark:before:bg-neutral-800',\n    'x:ps-3 x:before:start-0 x:pt-1 x:ms-3'\n  ),\n  wrapper: cn('x:p-4 x:overflow-y-auto nextra-scrollbar nextra-mask'),\n  footer: cn(\n    'nextra-sidebar-footer x:border-t nextra-border x:flex x:items-center x:gap-2 x:py-4 x:mx-4'\n  )\n}\n\ntype FolderProps = {\n  item: PageItem | MenuItem | Item\n  anchors: Heading[]\n  onFocus: FocusEventHandler\n  level: number\n}\n\nconst Folder: FC<FolderProps> = ({ item: _item, anchors, onFocus, level }) => {\n  const routeOriginal = useFSRoute()\n  const route = routeOriginal.split('#', 1)[0]!\n\n  const item = {\n    ..._item,\n    children:\n      _item.type === 'menu' ? getMenuChildren(_item as any) : _item.children\n  }\n\n  const hasRoute = !!item.route // for item.type === 'menu' will be ''\n  const active = hasRoute && [route, route + '/'].includes(item.route + '/')\n  const activeRouteInside =\n    active || (hasRoute && route.startsWith(item.route + '/'))\n\n  const focusedRoute = useFocusedRoute()\n  const focusedRouteInside = focusedRoute.startsWith(item.route + '/')\n\n  const { theme } = item as Item\n  const { defaultMenuCollapseLevel, autoCollapse } = useThemeConfig().sidebar\n\n  const open =\n    TreeState[item.route] === undefined\n      ? active ||\n        activeRouteInside ||\n        focusedRouteInside ||\n        (theme && 'collapsed' in theme\n          ? !theme.collapsed\n          : level < defaultMenuCollapseLevel)\n      : TreeState[item.route] || focusedRouteInside\n\n  const [, rerender] = useState<object>()\n\n  const handleClick: MouseEventHandler<\n    HTMLAnchorElement | HTMLButtonElement\n  > = event => {\n    const el = event.currentTarget\n    const isClickOnIcon =\n      el /* will be always <a> or <button> */ !==\n      event.target /* can be <svg> or <path> */\n    if (isClickOnIcon) {\n      event.preventDefault()\n    }\n    const isOpen = el.parentElement!.classList.contains('open')\n    // We don't toggle it if it's:\n    // - a link\n    // - not a click on icon\n    // - not active link\n    TreeState[item.route] = (isLink && !isClickOnIcon && !active) || !isOpen\n    rerender({})\n  }\n\n  useEffect(() => {\n    function updateTreeState() {\n      if (activeRouteInside || focusedRouteInside) {\n        TreeState[item.route] = true\n      }\n    }\n\n    function updateAndPruneTreeState() {\n      if (activeRouteInside && focusedRouteInside) {\n        TreeState[item.route] = true\n      } else {\n        delete TreeState[item.route]\n      }\n    }\n\n    if (autoCollapse) {\n      updateAndPruneTreeState()\n    } else {\n      updateTreeState()\n    }\n  }, [activeRouteInside, focusedRouteInside, item.route, autoCollapse])\n\n  const isLink = 'frontMatter' in item\n  // Use a button when a link doesn't have `href` because it impacts on SEO\n  const ComponentToUse = isLink ? Anchor : Button\n\n  return (\n    <li className={cn({ open, active })}>\n      <ComponentToUse\n        {...(isLink\n          ? { href: item.route, prefetch: false }\n          : { 'data-href': item.route })}\n        className={cn(\n          'x:items-center x:justify-between x:gap-2',\n          !isLink && 'x:text-start x:w-full',\n          classes.link,\n          active ? classes.active : classes.inactive\n        )}\n        onClick={handleClick}\n        onFocus={onFocus}\n      >\n        {item.title}\n        <ArrowRightIcon\n          height=\"18\"\n          className={cn(\n            'x:shrink-0',\n            'x:rounded-sm x:p-0.5 x:hover:bg-gray-800/5 x:dark:hover:bg-gray-100/5',\n            'x:motion-reduce:transition-none x:origin-center x:transition-all x:rtl:-rotate-180',\n            open && 'x:ltr:rotate-90 x:rtl:-rotate-270'\n          )}\n        />\n      </ComponentToUse>\n      {item.children && (\n        <Collapse isOpen={open}>\n          <Menu\n            className={classes.border}\n            // @ts-expect-error -- fixme\n            directories={item.children}\n            anchors={anchors}\n            level={level}\n          />\n        </Collapse>\n      )}\n    </li>\n  )\n}\n\nfunction getMenuChildren(menu: MenuItem) {\n  const routes = Object.fromEntries(\n    (menu.children || []).map(route => [route.name, route])\n  )\n  return Object.entries(menu.items || {}) // eslint-disable-line @typescript-eslint/no-unnecessary-condition -- fixme\n    .map(([key, item]) => ({\n      ...(routes[key] || { name: key /* for React key prop */ }),\n      ...(item as object)\n    }))\n}\n\nconst Separator: FC<{ title: ReactNode }> = ({ title }) => {\n  return (\n    <li\n      className={cn(\n        '[word-break:break-word]',\n        title\n          ? 'x:not-first:mt-5 x:mb-2 x:px-2 x:py-1.5 x:text-sm x:font-semibold x:text-gray-900 x:dark:text-gray-100'\n          : 'x:my-4'\n      )}\n    >\n      {title || <hr className=\"x:mx-2 x:border-t nextra-border\" />}\n    </li>\n  )\n}\n\nconst handleClick = () => {\n  setMenu(false)\n}\n\nconst File: FC<{\n  item: PageItem | Item\n  anchors: Heading[]\n  onFocus: FocusEventHandler\n}> = ({ item, anchors, onFocus }) => {\n  const route = useFSRoute()\n  // It is possible that the item doesn't have any route - for example, an external link.\n  const active = item.route && [route, route + '/'].includes(item.route + '/')\n  const activeSlug = useActiveAnchor()\n\n  if (item.type === 'separator') {\n    return <Separator title={item.title} />\n  }\n  const href = (item as PageItem).href || item.route\n  return (\n    <li className={cn({ active })}>\n      <Anchor\n        href={href}\n        className={cn(classes.link, active ? classes.active : classes.inactive)}\n        onFocus={onFocus}\n        prefetch={false}\n      >\n        {item.title}\n      </Anchor>\n      {active && anchors.length > 0 && (\n        <ul className={cn(classes.list, classes.border)}>\n          {anchors.map(({ id, value }) => (\n            <li key={id}>\n              <a\n                href={`#${id}`}\n                className={cn(\n                  classes.link,\n                  'x:focus-visible:nextra-focus x:flex x:gap-2 x:before:opacity-25 x:before:content-[\"#\"]',\n                  id === activeSlug ? classes.active : classes.inactive\n                )}\n                onClick={handleClick}\n              >\n                {value}\n              </a>\n            </li>\n          ))}\n        </ul>\n      )}\n    </li>\n  )\n}\n\ninterface MenuProps {\n  directories: PageItem[] | Item[]\n  anchors: Heading[]\n  className?: string\n  level: number\n}\n\nconst handleFocus: FocusEventHandler<HTMLAnchorElement> = event => {\n  const route =\n    event.target.getAttribute('href') || event.target.dataset.href || ''\n  setFocusedRoute(route)\n}\n\nconst Menu = forwardRef<HTMLUListElement, MenuProps>(\n  ({ directories, anchors, className, level }, forwardedRef) => (\n    <ul className={cn(classes.list, className)} ref={forwardedRef}>\n      {directories.map(item => {\n        const ComponentToUse =\n          item.type === 'menu' || item.children?.length ? Folder : File\n\n        return (\n          <ComponentToUse\n            key={item.name}\n            item={item}\n            anchors={anchors}\n            onFocus={handleFocus}\n            level={level + 1}\n          />\n        )\n      })}\n    </ul>\n  )\n)\nMenu.displayName = 'Menu'\n\nexport const MobileNav: FC = () => {\n  const { directories } = useConfig().normalizePagesResult\n  const toc = useTOC()\n\n  const menu = useMenu()\n  const pathname = usePathname()\n  const hash = useHash()\n\n  useEffect(() => {\n    setMenu(false)\n    // Close mobile menu when path changes or hash changes (e.g. clicking on search result which points to the current page)\n  }, [pathname, hash])\n\n  const anchors = toc.filter(v => v.depth === 2)\n  const sidebarRef = useRef<HTMLUListElement>(null!)\n\n  useEffect(() => {\n    const sidebar = sidebarRef.current\n    const activeLink = sidebar.querySelector('li.active')\n\n    if (activeLink && menu) {\n      scrollIntoView(activeLink, {\n        block: 'center',\n        inline: 'center',\n        scrollMode: 'always',\n        boundary: sidebar.parentNode as HTMLElement\n      })\n    }\n  }, [menu])\n\n  const themeConfig = useThemeConfig()\n  const hasI18n = themeConfig.i18n.length > 0\n  const hasMenu = themeConfig.darkMode || hasI18n\n\n  return (\n    <aside\n      className={cn(\n        'nextra-mobile-nav', // targeted from userspace\n        'x:flex x:flex-col',\n        'x:fixed x:inset-0 x:pt-(--nextra-navbar-height) x:z-20 x:overscroll-contain',\n        'x:[contain:layout_style]',\n        'x:md:hidden',\n        'x:[.nextra-banner:not([class$=hidden])~&]:pt-[calc(var(--nextra-banner-height)+var(--nextra-navbar-height))]',\n        'x:bg-nextra-bg',\n        menu\n          ? 'x:[transform:translate3d(0,0,0)]'\n          : 'x:[transform:translate3d(0,-100%,0)]'\n      )}\n    >\n      {themeConfig.search && (\n        <div className=\"x:px-4 x:pt-4\">{themeConfig.search}</div>\n      )}\n      <Menu\n        ref={sidebarRef}\n        className={classes.wrapper}\n        // The mobile dropdown menu, shows all the directories.\n        directories={directories}\n        // Always show the anchor links on mobile (`md`).\n        anchors={anchors}\n        level={0}\n      />\n\n      {hasMenu && (\n        <div className={cn(classes.footer, 'x:mt-auto')}>\n          <ThemeSwitch className=\"x:grow\" />\n          <LocaleSwitch className=\"x:grow x:justify-end\" />\n        </div>\n      )}\n    </aside>\n  )\n}\n\nlet lastScrollPosition = 0\n\nconst handleScrollEnd: ComponentProps<'div'>['onScrollEnd'] = event => {\n  lastScrollPosition = event.currentTarget.scrollTop\n}\n\nexport const Sidebar: FC = () => {\n  const toc = useTOC()\n  const { normalizePagesResult, hideSidebar } = useConfig()\n  const themeConfig = useThemeConfig()\n  const [isExpanded, setIsExpanded] = useState(themeConfig.sidebar.defaultOpen)\n  const [showToggleAnimation, setToggleAnimation] = useState(false)\n  const sidebarRef = useRef<HTMLDivElement>(null!)\n  const sidebarControlsId = useId()\n\n  const { docsDirectories, activeThemeContext } = normalizePagesResult\n  const includePlaceholder = activeThemeContext.layout === 'default'\n\n  useEffect(() => {\n    if (window.innerWidth < 768) {\n      return\n    }\n    const sidebar = sidebarRef.current\n\n    // Since `<Sidebar>` is placed in `useMDXComponents.wrapper` on client side navigation he will\n    // be remounted, this is a workaround to restore the scroll position, and will be fixed in Nextra 5\n    if (lastScrollPosition) {\n      sidebar.scrollTop = lastScrollPosition\n      return\n    }\n\n    const activeLink = sidebar.querySelector('li.active')\n    if (activeLink) {\n      scrollIntoView(activeLink, {\n        block: 'center',\n        inline: 'center',\n        scrollMode: 'always',\n        boundary: sidebar.parentNode as HTMLDivElement\n      })\n    }\n  }, [])\n\n  const anchors =\n    // hide the anchors in the sidebar when `floatTOC` is enabled.\n    themeConfig.toc.float ? [] : toc.filter(v => v.depth === 2)\n\n  const hasI18n = themeConfig.i18n.length > 0\n  const hasMenu =\n    themeConfig.darkMode || hasI18n || themeConfig.sidebar.toggleButton\n\n  return (\n    <>\n      {includePlaceholder && hideSidebar && (\n        <div className=\"x:max-xl:hidden x:h-0 x:w-64 x:shrink-0\" />\n      )}\n      <aside\n        id={sidebarControlsId}\n        className={cn(\n          'nextra-sidebar x:print:hidden',\n          'x:transition-all x:ease-in-out',\n          'x:max-md:hidden x:flex x:flex-col',\n          'x:h-[calc(100dvh-var(--nextra-navbar-height))]',\n          'x:top-(--nextra-navbar-height) x:shrink-0',\n          isExpanded ? 'x:w-64' : 'x:w-20',\n          hideSidebar ? 'x:hidden' : 'x:sticky'\n        )}\n      >\n        <div\n          className={cn(\n            classes.wrapper,\n            'x:grow',\n            !isExpanded && 'no-scrollbar'\n          )}\n          ref={sidebarRef}\n          onScrollEnd={handleScrollEnd} // eslint-disable-line react/no-unknown-property\n        >\n          {/* without !hideSidebar check <Collapse />'s inner.clientWidth on `layout: \"raw\"` will be 0 and element will not have width on initial loading */}\n          {(!hideSidebar || !isExpanded) && (\n            <Collapse isOpen={isExpanded} horizontal>\n              <Menu\n                // The sidebar menu, shows only the docs directories.\n                directories={docsDirectories}\n                anchors={anchors}\n                level={0}\n              />\n            </Collapse>\n          )}\n        </div>\n        {hasMenu && (\n          <div\n            className={cn(\n              'x:sticky x:bottom-0 x:bg-nextra-bg',\n              classes.footer,\n              !isExpanded && 'x:flex-wrap x:justify-center',\n              showToggleAnimation && [\n                'x:*:opacity-0',\n                isExpanded\n                  ? 'x:*:animate-[fade-in_1s_ease_.2s_forwards]'\n                  : 'x:*:animate-[fade-in2_1s_ease_.2s_forwards]'\n              ]\n            )}\n          >\n            <LocaleSwitch\n              lite={!isExpanded}\n              className={isExpanded ? 'x:grow' : ''}\n            />\n            <ThemeSwitch\n              lite={!isExpanded || hasI18n}\n              className={!isExpanded || hasI18n ? '' : 'x:grow'}\n            />\n            {themeConfig.sidebar.toggleButton && (\n              <Button\n                aria-expanded={isExpanded}\n                aria-controls={sidebarControlsId}\n                title={isExpanded ? 'Collapse sidebar' : 'Expand sidebar'}\n                className={({ hover }) =>\n                  cn(\n                    'x:rounded-md x:p-2',\n                    hover\n                      ? 'x:bg-gray-200 x:text-gray-900 x:dark:bg-primary-100/5 x:dark:text-gray-50'\n                      : 'x:text-gray-600 x:dark:text-gray-400'\n                  )\n                }\n                onClick={() => {\n                  setIsExpanded(prev => !prev)\n                  setToggleAnimation(true)\n                }}\n              >\n                <ExpandIcon\n                  height=\"12\"\n                  className={cn(\n                    !isExpanded && 'x:*:first:origin-[35%] x:*:first:rotate-180'\n                  )}\n                />\n              </Button>\n            )}\n          </div>\n        )}\n      </aside>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/theme-switch.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport { useTheme } from 'next-themes'\nimport { Select } from 'nextra/components'\nimport { useMounted } from 'nextra/hooks'\nimport { MoonIcon, SunIcon } from 'nextra/icons'\nimport type { FC } from 'react'\nimport { useThemeConfig } from '../stores'\n\ntype ThemeSwitchProps = {\n  lite?: boolean\n  className?: string\n}\n\nexport const ThemeSwitch: FC<ThemeSwitchProps> = ({ lite, className }) => {\n  const { setTheme, resolvedTheme, theme } = useTheme()\n  const mounted = useMounted()\n  const { darkMode, themeSwitch } = useThemeConfig()\n  if (!darkMode) {\n    return null\n  }\n  const IconToUse = mounted && resolvedTheme === 'dark' ? MoonIcon : SunIcon\n  const id = mounted ? (theme as keyof typeof themeSwitch) : 'light'\n  return (\n    <Select\n      className={cn('x:flex x:items-center x:gap-2', className)}\n      title=\"Change theme\"\n      options={[\n        { id: 'light', name: themeSwitch.light },\n        { id: 'dark', name: themeSwitch.dark },\n        { id: 'system', name: themeSwitch.system }\n      ]}\n      onChange={setTheme}\n      value={id}\n      selectedOption={\n        <>\n          <IconToUse height=\"12\" />\n          {!lite && themeSwitch[id]}\n        </>\n      }\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/components/toc.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport { Anchor } from 'nextra/components'\nimport type { FC } from 'react'\nimport { useEffect, useRef } from 'react'\nimport scrollIntoView from 'scroll-into-view-if-needed'\nimport { useActiveAnchor, useConfig, useThemeConfig, useTOC } from '../stores'\nimport { getGitIssueUrl, gitUrlParse } from '../utils'\nimport { BackToTop } from './back-to-top'\n\ntype TOCProps = {\n  filePath: string\n  pageTitle: string\n}\n\nconst linkClassName = cn(\n  'x:text-xs x:font-medium x:transition',\n  'x:text-gray-600 x:dark:text-gray-400',\n  'x:hover:text-gray-800 x:dark:hover:text-gray-200',\n  'x:contrast-more:text-gray-700 x:contrast-more:dark:text-gray-100'\n)\n\nexport const TOC: FC<TOCProps> = ({ filePath, pageTitle }) => {\n  const activeSlug = useActiveAnchor()\n  const tocRef = useRef<HTMLUListElement>(null)\n  const themeConfig = useThemeConfig()\n  const toc = useTOC()\n  const hasMetaInfo =\n    themeConfig.feedback.content ||\n    themeConfig.editLink ||\n    themeConfig.toc.extraContent ||\n    themeConfig.toc.backToTop\n\n  const { activeType } = useConfig().normalizePagesResult\n  const anchors = themeConfig.toc.float || activeType === 'page' ? toc : []\n\n  const hasHeadings = anchors.length > 0\n  const activeIndex = toc.findIndex(({ id }) => id === activeSlug)\n\n  useEffect(() => {\n    if (!activeSlug) return\n    const anchor = tocRef.current?.querySelector(`a[href=\"#${activeSlug}\"]`)\n    if (!anchor) return\n\n    scrollIntoView(anchor, {\n      behavior: 'smooth',\n      block: 'center',\n      inline: 'center',\n      scrollMode: 'if-needed',\n      boundary: tocRef.current\n    })\n  }, [activeSlug])\n\n  const feedbackLink =\n    themeConfig.feedback.link ??\n    getGitIssueUrl({\n      labels: themeConfig.feedback.labels,\n      repository: themeConfig.docsRepositoryBase,\n      title: `Feedback for “${pageTitle}”`\n    })\n\n  return (\n    <div\n      className={cn(\n        'x:grid x:grid-rows-[min-content_1fr_min-content]', // 1fr: toc headings, min-content: title/footer\n        'x:sticky x:top-(--nextra-navbar-height) x:text-sm',\n        'x:max-h-[calc(100vh-var(--nextra-navbar-height))]'\n      )}\n    >\n      {hasHeadings && (\n        <>\n          <p className=\"x:pt-6 x:px-4 x:font-semibold x:tracking-tight\">\n            {themeConfig.toc.title}\n          </p>\n          <ul\n            ref={tocRef}\n            className={cn(\n              'x:p-4 nextra-scrollbar x:overscroll-y-contain x:overflow-y-auto x:hyphens-auto',\n              'nextra-mask' // for title/footer shadow\n            )}\n          >\n            {anchors.map(({ id, value, depth }) => (\n              <li className=\"x:my-2 x:scroll-my-6 x:scroll-py-6\" key={id}>\n                <a\n                  href={`#${id}`}\n                  className={cn(\n                    'x:focus-visible:nextra-focus',\n                    {\n                      2: 'x:font-semibold',\n                      3: 'x:ms-3',\n                      4: 'x:ms-6',\n                      5: 'x:ms-9',\n                      6: 'x:ms-12'\n                    }[depth],\n                    'x:block x:transition-colors x:subpixel-antialiased',\n                    id === activeSlug\n                      ? 'x:text-primary-600 x:contrast-more:text-primary-600!'\n                      : 'x:text-gray-600 x:hover:text-gray-900 x:dark:text-gray-400 x:dark:hover:text-gray-300',\n                    'x:contrast-more:text-gray-900 x:contrast-more:underline x:contrast-more:dark:text-gray-50 x:break-words'\n                  )}\n                >\n                  {value}\n                </a>\n              </li>\n            ))}\n          </ul>\n        </>\n      )}\n\n      {hasMetaInfo && (\n        <div\n          className={cn(\n            'x:grid x:gap-2 x:py-4 x:mx-4',\n            hasHeadings && 'x:border-t nextra-border'\n          )}\n        >\n          {themeConfig.feedback.content && (\n            <Anchor className={linkClassName} href={feedbackLink}>\n              {themeConfig.feedback.content}\n            </Anchor>\n          )}\n\n          {filePath && themeConfig.editLink && (\n            <Anchor\n              className={linkClassName}\n              href={\n                filePath.startsWith('http')\n                  ? filePath\n                  : `${gitUrlParse(themeConfig.docsRepositoryBase).href}/${filePath}`\n              }\n            >\n              {themeConfig.editLink}\n            </Anchor>\n          )}\n\n          {themeConfig.toc.extraContent}\n\n          {themeConfig.toc.backToTop && (\n            <BackToTop className={linkClassName} hidden={activeIndex < 2}>\n              {themeConfig.toc.backToTop}\n            </BackToTop>\n          )}\n        </div>\n      )}\n    </div>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/index.ts",
    "content": "export { useTheme } from 'next-themes'\nexport { useThemeConfig, useConfig, useMenu, setMenu } from './stores'\nexport { useMDXComponents } from './mdx-components'\nexport { Link } from './mdx-components/link'\nexport { Layout } from './layout'\nexport {\n  NotFoundPage,\n  Navbar,\n  ThemeSwitch,\n  LocaleSwitch,\n  LastUpdated,\n  Footer\n} from './components'\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/layout.tsx",
    "content": "/* eslint sort-keys: error */\nimport { ThemeProvider } from 'next-themes'\nimport { SkipNavLink } from 'nextra/components'\nimport type { FC } from 'react'\nimport { z } from 'zod'\nimport { MobileNav } from './components/sidebar'\nimport { LayoutPropsSchema } from './schemas'\nimport { ConfigProvider, ThemeConfigProvider } from './stores'\nimport type { LayoutProps } from './types.generated'\n\nexport type ThemeConfigProps = z.infer<typeof LayoutPropsSchema>\n\nexport const Layout: FC<LayoutProps> = ({ children, ...themeConfig }) => {\n  const { data, error } = LayoutPropsSchema.safeParse(themeConfig)\n  if (error) {\n    throw z.prettifyError(error)\n  }\n  const { footer, navbar, pageMap, nextThemes, banner, ...rest } = data\n\n  return (\n    <ThemeConfigProvider value={rest}>\n      <ThemeProvider {...nextThemes}>\n        <SkipNavLink />\n        {banner}\n        <ConfigProvider pageMap={pageMap} navbar={navbar} footer={footer}>\n          {/*\n           * MobileNav should be in layout and not in mdx wrapper, otherwise for non mdx pages will\n           * be not rendered\n           */}\n          <MobileNav />\n          {children}\n        </ConfigProvider>\n      </ThemeProvider>\n    </ThemeConfigProvider>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/mdx-components/heading-anchor.client.tsx",
    "content": "'use client'\n\nimport { useEffect, useRef } from 'react'\nimport type { FC } from 'react'\nimport { setActiveSlug } from '../stores'\n\nconst callback: IntersectionObserverCallback = entries => {\n  const entry = entries.find(entry => entry.isIntersecting)\n\n  if (entry) {\n    const slug = (entry.target as HTMLAnchorElement).hash.slice(1)\n    setActiveSlug(decodeURI(slug))\n  }\n}\n\nconst observer: IntersectionObserver =\n  typeof window === 'undefined'\n    ? null!\n    : new IntersectionObserver(callback, {\n        rootMargin: `-${\n          getComputedStyle(document.body).getPropertyValue(\n            '--nextra-navbar-height'\n          ) ||\n          // can be '' on 404 page\n          '0%'\n        } 0% -80%`\n      })\n\nexport const HeadingAnchor: FC<{ id: string }> = ({ id }) => {\n  const anchorRef = useRef<HTMLAnchorElement>(null!)\n\n  useEffect(() => {\n    const el = anchorRef.current\n    observer.observe(el)\n    return () => {\n      observer.unobserve(el)\n    }\n  }, [])\n\n  return (\n    <a\n      href={`#${id}`}\n      className=\"x:focus-visible:nextra-focus subheading-anchor\"\n      aria-label=\"Permalink for this section\"\n      ref={anchorRef}\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/mdx-components/heading.tsx",
    "content": "// TODO: check why isn't optimized\n'use no memo'\n\nimport cn from 'clsx'\nimport type { ComponentProps, FC } from 'react'\nimport { HeadingAnchor } from './heading-anchor.client'\n\nconst createHeading = (\n  Tag: `h${1 | 2 | 3 | 4 | 5 | 6}`\n): FC<ComponentProps<typeof Tag>> =>\n  function Heading({ children, id, className, ...props }) {\n    const _class = // can be added by footnotes\n      className === 'sr-only'\n        ? 'x:sr-only'\n        : cn(\n            'x:tracking-tight x:text-slate-900 x:dark:text-slate-100',\n            Tag === 'h1'\n              ? 'x:font-bold'\n              : 'x:font-semibold x:target:animate-[fade-in_1.5s]',\n            {\n              h1: 'x:mt-2 x:text-4xl',\n              h2: 'x:mt-10 x:border-b x:pb-1 x:text-3xl nextra-border',\n              h3: 'x:mt-8 x:text-2xl',\n              h4: 'x:mt-8 x:text-xl',\n              h5: 'x:mt-8 x:text-lg',\n              h6: 'x:mt-8 x:text-base'\n            }[Tag],\n            className\n          )\n\n    return (\n      <Tag id={id} className={_class} {...props}>\n        {children}\n        {id && <HeadingAnchor id={id} />}\n      </Tag>\n    )\n  }\n\nexport const H1 = createHeading('h1')\nexport const H2 = createHeading('h2')\nexport const H3 = createHeading('h3')\nexport const H4 = createHeading('h4')\nexport const H5 = createHeading('h5')\nexport const H6 = createHeading('h6')\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/mdx-components/index.tsx",
    "content": "// TODO: check why components in object aren't optimized\n'use no memo'\n\n/* eslint sort-keys: error */\nimport cn from 'clsx'\nimport {\n  Callout,\n  Code,\n  Details,\n  Pre,\n  SkipNavContent,\n  Summary,\n  Table,\n  withGitHubAlert,\n  withIcons\n} from 'nextra/components'\nimport { useMDXComponents as getNextraMDXComponents } from 'nextra/mdx-components'\nimport type { UseMDXComponents } from 'nextra/mdx-components'\nimport { removeLinks } from 'nextra/remove-links'\nimport type { FC, HTMLAttributes } from 'react'\nimport { Sidebar } from '../components'\nimport { TOCProvider } from '../stores'\nimport { H1, H2, H3, H4, H5, H6 } from './heading'\nimport { Link } from './link'\nimport { ClientWrapper } from './wrapper.client'\n\nconst Blockquote: FC<HTMLAttributes<HTMLQuoteElement>> = props => (\n  <blockquote\n    className={cn(\n      'x:not-first:mt-[1.25em] x:border-gray-300 x:italic x:text-gray-700 x:dark:border-gray-700 x:dark:text-gray-400',\n      'x:border-s-2 x:ps-[1.5em]'\n    )}\n    {...props}\n  />\n)\n\nconst CALLOUT_TYPE = Object.freeze({\n  caution: 'error',\n  important: 'important',\n  note: 'info',\n  tip: 'default',\n  warning: 'warning'\n})\n\nconst DEFAULT_COMPONENTS = getNextraMDXComponents({\n  a: Link,\n  blockquote: withGitHubAlert(\n    ({ type, ...props }) => <Callout type={CALLOUT_TYPE[type]} {...props} />,\n    Blockquote\n  ),\n  code: Code,\n  details: Details,\n  h1: H1,\n  h2: H2,\n  h3: H3,\n  h4: H4,\n  h5: H5,\n  h6: H6,\n  hr: props => <hr className=\"x:my-[2em] nextra-border\" {...props} />,\n  li: props => <li className=\"x:my-[.5em]\" {...props} />,\n  ol: props => (\n    <ol\n      className=\"x:[:is(ol,ul)_&]:my-[.75em] x:not-first:mt-[1.25em] x:list-decimal x:ms-6\"\n      {...props}\n    />\n  ),\n  p: props => <p className=\"x:not-first:mt-[1.25em] x:leading-7\" {...props} />,\n  pre: withIcons(Pre),\n  summary: Summary,\n  table: ({ className, ...props }) => (\n    <Table\n      className={cn(\n        'nextra-scrollbar x:not-first:mt-[1.25em] x:p-0',\n        className\n      )}\n      {...props}\n    />\n  ),\n  td: Table.Td,\n  th: Table.Th,\n  tr: Table.Tr,\n  ul: props => (\n    <ul\n      className=\"x:[:is(ol,ul)_&]:my-[.75em] x:not-first:mt-[1.25em] x:list-disc x:ms-[1.5em]\"\n      {...props}\n    />\n  ),\n  wrapper({ toc, children, metadata, bottomContent, sourceCode, ...props }) {\n    // @ts-expect-error fixme\n    toc = toc.map(item => ({\n      ...item,\n      value: removeLinks(item.value)\n    }))\n    return (\n      <div\n        className=\"x:mx-auto x:flex x:max-w-(--nextra-content-width)\"\n        // Attach user-defined props to wrapper container, e.g. `data-pagefind-filter`\n        {...props}\n      >\n        <TOCProvider value={toc}>\n          <Sidebar />\n          <ClientWrapper\n            metadata={metadata}\n            bottomContent={bottomContent}\n            sourceCode={sourceCode}\n          >\n            <SkipNavContent />\n            <main\n              data-pagefind-body={\n                (metadata as any).searchable !== false || undefined\n              }\n            >\n              {children}\n            </main>\n          </ClientWrapper>\n        </TOCProvider>\n      </div>\n    )\n  }\n})\n\nexport const useMDXComponents: UseMDXComponents<typeof DEFAULT_COMPONENTS> = <\n  T,\n>(\n  components?: T\n) => {\n  return {\n    ...DEFAULT_COMPONENTS,\n    ...components\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/mdx-components/link.tsx",
    "content": "import cn from 'clsx'\nimport { Anchor } from 'nextra/components'\n\nexport const Link: typeof Anchor = ({ className, ...props }) => {\n  return (\n    <Anchor\n      className={cn(\n        'x:text-primary-600 x:underline x:hover:no-underline x:decoration-from-font x:[text-underline-position:from-font]',\n        className\n      )}\n      {...props}\n    />\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/mdx-components/wrapper.client.tsx",
    "content": "'use client'\n\nimport cn from 'clsx'\nimport type { MDXWrapper } from 'nextra'\nimport type { ComponentProps, FC } from 'react'\nimport { cloneElement } from 'react'\nimport { Breadcrumb, CopyPage, Pagination, TOC } from '../components'\nimport { useConfig, useThemeConfig } from '../stores'\n\nexport const ClientWrapper: FC<Omit<ComponentProps<MDXWrapper>, 'toc'>> = ({\n  children,\n  metadata,\n  bottomContent,\n  sourceCode\n}) => {\n  const {\n    activeType,\n    activeThemeContext: themeContext,\n    activePath\n  } = useConfig().normalizePagesResult\n  const themeConfig = useThemeConfig()\n  const date = themeContext.timestamp && metadata.timestamp\n\n  return (\n    <>\n      {(themeContext.layout === 'default' || themeContext.toc) && (\n        <nav\n          className=\"nextra-toc x:order-last x:max-xl:hidden x:w-64 x:shrink-0 x:print:hidden\"\n          aria-label=\"table of contents\"\n        >\n          {themeContext.toc && (\n            <TOC filePath={metadata.filePath} pageTitle={metadata.title} />\n          )}\n        </nav>\n      )}\n      <article\n        className={cn(\n          'x:w-full x:min-w-0 x:break-words x:min-h-[calc(100vh-var(--nextra-navbar-height))]',\n          'x:text-slate-700 x:dark:text-slate-200 x:pb-8 x:px-4 x:pt-4 x:md:px-12',\n          themeContext.typesetting === 'article' &&\n            'nextra-body-typesetting-article'\n        )}\n      >\n        {themeContext.breadcrumb && activeType !== 'page' && (\n          <Breadcrumb activePath={activePath} />\n        )}\n        {themeConfig.copyPageButton && themeContext.copyPage && sourceCode && (\n          <CopyPage sourceCode={sourceCode} />\n        )}\n        {children}\n        {date ? (\n          <div className=\"x:mt-12 x:mb-8 x:text-xs x:text-gray-600 x:text-end x:dark:text-gray-400\">\n            {/* @ts-expect-error -- fixme */}\n            {cloneElement(themeConfig.lastUpdated, { date: new Date(date) })}\n          </div>\n        ) : (\n          <div className=\"x:mt-16\" />\n        )}\n        {themeContext.pagination && activeType !== 'page' && <Pagination />}\n        {bottomContent}\n      </article>\n    </>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/schemas.tsx",
    "content": "import type { PageMapItem } from 'nextra'\nimport { Search } from 'nextra/components'\nimport { element, reactNode } from 'nextra/schemas'\nimport { Fragment } from 'react'\nimport { z } from 'zod'\nimport { LastUpdated } from './components'\n\nconst attributeSchema = z\n  .custom<\n    'class' | `data-${string}`\n  >(value => value === 'class' || (value as string).startsWith('data-'))\n  .meta({ type: \"'class' | `data-${string}`\" })\n\nconst feedbackSchema = z.strictObject({\n  content: reactNode.default('Question? Give us feedback').meta({\n    description: 'Content of the feedback link.'\n  }),\n  labels: z.string().default('feedback').meta({\n    description: 'Labels that can be added to the new created issue.'\n  }),\n  link: z\n    .string()\n    .optional()\n    .meta({\n      description: `Feedback link URL.\n\nBy default, it's a link to the issue creation form of the docs repository, with the current page title prefilled:\n[example](https://github.com/shuding/nextra/issues/new?title=Feedback%20for%20%E2%80%9CTheme%20Configuration%E2%80%9D&labels=feedback).`\n    })\n})\n\nconst nextThemesSchema = z.strictObject({\n  attribute: z\n    .union([attributeSchema, z.array(attributeSchema)])\n    .default('class'),\n  defaultTheme: z.string().default('system'),\n  disableTransitionOnChange: z.boolean().default(true),\n  forcedTheme: z.string().optional(),\n  storageKey: z.string().default('theme')\n})\n\nconst sidebarSchema = z.strictObject({\n  autoCollapse: z.boolean().optional().meta({\n    description:\n      'If `true`, automatically collapse inactive folders above `defaultMenuCollapseLevel`.'\n  }),\n  defaultMenuCollapseLevel: z.number().int().min(1).default(2).meta({\n    description:\n      'Specifies the folder level at which the menu on the left is collapsed by default.'\n  }),\n  defaultOpen: z.boolean().default(true).meta({\n    description: 'Hide/show sidebar by default.'\n  }),\n  toggleButton: z.boolean().default(true).meta({\n    description: 'Hide/show sidebar toggle button.'\n  })\n})\n\nconst themeSwitchSchema = z.strictObject({\n  dark: z.string().default('Dark'),\n  light: z.string().default('Light'),\n  system: z.string().default('System')\n})\n\nconst tocSchema = z.strictObject({\n  backToTop: reactNode.default('Scroll to top').meta({\n    description: 'Text of back to top button.'\n  }),\n  extraContent: reactNode\n    // @TODO added in zod v4\n    .optional()\n    .meta({\n      description: 'Display extra content below the TOC content.'\n    }),\n  float: z.boolean().default(true).meta({\n    description: 'Float the TOC next to the content.'\n  }),\n  title: reactNode.default('On This Page').meta({\n    description: 'Title of the TOC sidebar.'\n  })\n})\n\nexport const LayoutPropsSchema = z.strictObject({\n  banner: reactNode\n    // @TODO added in zod v4\n    .optional()\n    .meta({\n      description:\n        'Rendered [`<Banner>` component](/docs/built-ins/banner). E.g. `<Banner {...bannerProps} />`'\n    }),\n  children: reactNode,\n  copyPageButton: z.boolean().default(true).meta({\n    description: 'Hide/show copy page content button.'\n  }),\n  darkMode: z.boolean().default(true).meta({\n    description: 'Show or hide the dark mode select button.'\n  }),\n  docsRepositoryBase: z\n    .string()\n    .startsWith('https://')\n    .default('https://github.com/shuding/nextra')\n    .meta({\n      description: 'URL of the documentation repository.'\n    }),\n  editLink: reactNode.default('Edit this page').meta({\n    description: 'Content of the edit link.'\n  }),\n  feedback: feedbackSchema.default(feedbackSchema.parse({})),\n  footer: reactNode\n    // @TODO added in zod v4\n    .optional()\n    .meta({\n      description:\n        'Rendered [`<Footer>` component](/docs/docs-theme/built-ins/footer). E.g. `<Footer {...footerProps} />`'\n    }),\n  i18n: z\n    .array(\n      z.strictObject({\n        locale: z.string().meta({\n          description: 'Locale from `i18n.locales` field in `next.config` file.'\n        }),\n        name: z.string().meta({\n          description: 'Locale name in dropdown.'\n        })\n      })\n    )\n    .default([])\n    .meta({\n      description:\n        'Options to configure the language dropdown for [the i18n docs website](/docs/guide/i18n).'\n    }),\n  lastUpdated: element\n    .default(() => <LastUpdated />)\n    .refine(el => el.type !== Fragment && typeof el.type !== 'string', {\n      error: `\\`Layout#lastUpdated\\` must be a \\`<LastUpdated />\\` component:\n\n\\`\\`\\`js\nimport { Layout, LastUpdated } from 'nextra-theme-docs'\n\n<Layout\n  lastUpdated={<LastUpdated locale=\"YOUR_LOCALE\">YOUR_CONTENT</LastUpdated>}\n>\n  {children}\n</Layout>\n\\`\\`\\`\n`\n    })\n    .meta({\n      default: '<LastUpdated />',\n      description: 'Component to render the last updated info.'\n    }),\n  navbar: reactNode\n    // @TODO added in zod v4\n    .optional()\n    .meta({\n      description:\n        'Rendered [`<Navbar>` component](/docs/docs-theme/built-ins/navbar). E.g. `<Navbar {...navbarProps} />`'\n    }),\n  navigation: z\n    .union([\n      z.boolean(),\n      z.strictObject({\n        next: z.boolean(),\n        prev: z.boolean()\n      })\n    ])\n    .default(true)\n    .overwrite(v => (typeof v === 'boolean' ? { next: v, prev: v } : v))\n    .meta({\n      description: 'Enable or disable navigation link.'\n    }),\n  nextThemes: nextThemesSchema.default(nextThemesSchema.parse({})).meta({\n    description:\n      'Configuration for the [next-themes](https://github.com/pacocoursey/next-themes#themeprovider) package.'\n  }),\n  pageMap: z\n    .array(\n      z.custom<PageMapItem>().meta({\n        type: 'import(\"nextra\").PageMapItem'\n      })\n    )\n    .meta({\n      description: \"Page map list. Result of `getPageMap(route = '/')` call.\"\n    }),\n  search: reactNode\n    .default(() => <Search />)\n    .meta({\n      default: '<Search />',\n      description:\n        'Rendered [`<Search>` component](/docs/built-ins/search). E.g. `<Search {...searchProps} />`'\n    }),\n  sidebar: sidebarSchema.default(sidebarSchema.parse({})),\n  themeSwitch: themeSwitchSchema.default(themeSwitchSchema.parse({})).meta({\n    description: 'Translation of options in the theme switch.'\n  }),\n  toc: tocSchema.default(tocSchema.parse({}))\n})\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/stores/active-anchor.ts",
    "content": "'use no memo'\n\nimport type { Dispatch } from 'react'\nimport { create } from 'zustand'\n\nconst useActiveAnchorStore = create<{\n  activeSlug: string\n}>(() => ({\n  activeSlug: ''\n}))\n\nexport const useActiveAnchor = () =>\n  useActiveAnchorStore(state => state.activeSlug)\n\nexport const setActiveSlug: Dispatch<string> = activeSlug => {\n  useActiveAnchorStore.setState({ activeSlug })\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/stores/config.tsx",
    "content": "'use client'\n\nimport type { PageMapItem } from 'nextra'\nimport { useFSRoute } from 'nextra/hooks'\nimport { normalizePages } from 'nextra/normalize-pages'\nimport type { FC, ReactNode } from 'react'\nimport { createContext, useContext } from 'react'\n\ntype NormalizePagesResult = ReturnType<typeof normalizePages>\n\nconst ConfigContext = createContext<NormalizePagesResult | null>(null)\n\n/**\n * Provides normalized data for the current page from `ConfigContext`.\n *\n * This includes the full result of `normalizePages`, along with a derived value `hideSidebar`\n * that determines whether the sidebar should be hidden on the current page.\n *\n * @returns An object containing the `normalizePagesResult` and a `hideSidebar` value.\n * @throws If used outside of a `ConfigContext.Provider`.\n */\nexport function useConfig(): {\n  normalizePagesResult: NormalizePagesResult\n  /**\n   * Whether the sidebar is shown. If `false`, the theme and locale switchers are displayed in the\n   * `<Footer>`.\n   */\n  hideSidebar: boolean\n} {\n  const normalizePagesResult = useContext(ConfigContext)\n  if (!normalizePagesResult) {\n    throw new Error('Missing ConfigContext.Provider')\n  }\n  const { activeThemeContext, activeType } = normalizePagesResult\n  return {\n    normalizePagesResult,\n    hideSidebar: !activeThemeContext.sidebar || activeType === 'page'\n  }\n}\n\nexport const ConfigProvider: FC<{\n  children: ReactNode\n  pageMap: PageMapItem[]\n  navbar: ReactNode\n  footer: ReactNode\n}> = ({ children, pageMap, navbar, footer }) => {\n  const pathname = useFSRoute()\n\n  const normalizedPages = normalizePages({\n    list: pageMap,\n    route: pathname\n  })\n  const { activeThemeContext } = normalizedPages\n\n  return (\n    <ConfigContext.Provider value={normalizedPages}>\n      {activeThemeContext.navbar && navbar}\n      {children}\n      {activeThemeContext.footer && footer}\n    </ConfigContext.Provider>\n  )\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/stores/focused-route.ts",
    "content": "'use no memo'\n\nimport type { Dispatch } from 'react'\nimport { create } from 'zustand'\n\nconst useFocusedRouteStore = create<{\n  focused: string\n}>(() => ({\n  focused: ''\n}))\n\nexport const useFocusedRoute = () =>\n  useFocusedRouteStore(state => state.focused)\n\nexport const setFocusedRoute: Dispatch<string> = focused => {\n  useFocusedRouteStore.setState({ focused })\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/stores/index.ts",
    "content": "export { useActiveAnchor, setActiveSlug } from './active-anchor'\nexport { useConfig, ConfigProvider } from './config'\nexport { useFocusedRoute, setFocusedRoute } from './focused-route'\nexport { useMenu, setMenu } from './menu'\nexport { ThemeConfigProvider, useThemeConfig } from './theme-config'\nexport { useTOC, TOCProvider } from './toc'\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/stores/menu.ts",
    "content": "'use no memo'\n\nimport type { Dispatch, SetStateAction } from 'react'\nimport { create } from 'zustand'\n\nconst useMenuStore = create<{\n  hasMenu: boolean\n}>(() => ({\n  hasMenu: false\n}))\n\nexport const useMenu = () => useMenuStore(state => state.hasMenu)\n\nexport const setMenu: Dispatch<SetStateAction<boolean>> = fn => {\n  useMenuStore.setState(state => {\n    const hasMenu = typeof fn === 'function' ? fn(state.hasMenu) : fn\n    // Lock background scroll when menu is opened\n    document.documentElement.classList.toggle(\n      'x:max-md:overflow-hidden',\n      hasMenu\n    )\n    return { hasMenu }\n  })\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/stores/theme-config.ts",
    "content": "'use client'\n\nimport type { ComponentProps } from 'react'\nimport { createContext, createElement, useContext } from 'react'\nimport type { ThemeConfigProps } from '../layout'\n\nconst ThemeConfigContext = createContext<\n  Omit<\n    ThemeConfigProps,\n    | 'footer'\n    //\n    | 'navbar'\n    | 'pageMap'\n    | 'nextThemes'\n    | 'banner'\n    | 'children'\n  >\n>(null!)\n\n/**\n * Accesses the current [theme configuration](https://nextra.site/docs/docs-theme/theme-configuration)\n * values, excluding layout-specific elements like:\n * - `footer`\n * - `navbar`\n * - `pageMap`\n * - `nextThemes`\n * - `banner`\n * - `children`\n *\n * This hook is useful for dynamically configuring your project based on shared theme values.\n *\n * @returns A subset of your theme configuration context.\n */\nexport const useThemeConfig = () => useContext(ThemeConfigContext)\n\nexport const ThemeConfigProvider = (\n  props: ComponentProps<typeof ThemeConfigContext.Provider>\n) => createElement(ThemeConfigContext.Provider, props)\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/stores/toc.ts",
    "content": "'use no memo'\n'use client'\n\nimport type { Heading } from 'nextra'\nimport type { ComponentProps } from 'react'\nimport { createContext, createElement, useContext } from 'react'\n\nconst TOCContext = createContext<Heading[]>([])\n\nexport const useTOC = () => useContext(TOCContext)\n\nexport const TOCProvider = (\n  props: ComponentProps<typeof TOCContext.Provider>\n) => createElement(TOCContext.Provider, props)\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/style.css",
    "content": "@import 'tailwindcss' source(none) prefix(x);\n\n@source './**/*.{ts,tsx}';\n\n@import '../../nextra/styles/default.css';\n@import '../../nextra/styles/code-block.css';\n@import '../../nextra/styles/subheading-anchor.css';\n@import '../../nextra/styles/scrollbar.css';\n@import '../../nextra/styles/steps.css';\n@import '../../nextra/styles/cards.css';\n@import '../../nextra/styles/react-medium-image-zoom.css';\n@import '../css/hamburger.css';\n@import '../css/typesetting-article.css';\n\n@theme {\n}\n\n@utility nextra-focus {\n  @apply x:focus-visible:outline-none x:ring-2 x:ring-primary-200 x:ring-offset-1 x:ring-offset-primary-300 x:dark:ring-primary-800 x:dark:ring-offset-primary-700;\n}\n\nhtml {\n  --nextra-navbar-height: 64px;\n\n  @apply x:antialiased x:text-base;\n  font-feature-settings:\n    'rlig' 1,\n    'calt' 1,\n    'ss01' 1;\n  -webkit-tap-highlight-color: transparent;\n\n  &:not(:has(*:focus)) {\n    /* adding `:not` with `:has` otherwise page jumps while focusing or while tapping in input https://github.com/shuding/nextra/issues/2840 */\n    @apply x:scroll-pt-(--nextra-navbar-height);\n  }\n}\n\n.contains-task-list {\n  @apply x:mt-[1.25em];\n\n  input[type='checkbox'] {\n    @apply x:me-1;\n  }\n}\n\n.footnotes a[data-footnote-backref] {\n  font-family: initial;\n}\n\n@keyframes fade-in2 {\n  0% {\n    opacity: 0;\n  }\n  100% {\n    opacity: 1;\n  }\n}\n\n.nextra-border {\n  @apply x:border-gray-200 x:dark:border-neutral-800 x:contrast-more:border-neutral-400!;\n}\n\n.nextra-mask {\n  mask-image:\n    linear-gradient(to bottom, transparent, #000 20px, transparent 100%),\n    linear-gradient(to top, transparent, #000 20px, transparent 100%);\n  @apply x:contrast-more:[mask-image:none];\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/types.generated.ts",
    "content": "export interface LayoutProps {\n  /**\n   * Rendered [`<Banner>` component](/docs/built-ins/banner). E.g. `<Banner {...bannerProps} />`\n   */\n  banner?: React.ReactNode\n\n  children: React.ReactNode\n\n  /**\n   * Hide/show copy page content button.\n   * @default true\n   */\n  copyPageButton?: boolean\n\n  /**\n   * Show or hide the dark mode select button.\n   * @default true\n   */\n  darkMode?: boolean\n\n  /**\n   * URL of the documentation repository.\n   * @default \"https://github.com/shuding/nextra\"\n   */\n  docsRepositoryBase?: string\n\n  /**\n   * Content of the edit link.\n   * @default \"Edit this page\"\n   */\n  editLink?: React.ReactNode\n\n  /**\n   * @default {\n   *   \"content\": \"Question? Give us feedback\",\n   *   \"labels\": \"feedback\"\n   * }\n   */\n  feedback?: {\n    /**\n     * Content of the feedback link.\n     * @default \"Question? Give us feedback\"\n     */\n    content?: React.ReactNode\n\n    /**\n     * Labels that can be added to the new created issue.\n     * @default \"feedback\"\n     */\n    labels?: string\n\n    /**\n     * Feedback link URL.\n     * \n     * By default, it's a link to the issue creation form of the docs repository, with the current page title prefilled:\n     * [example](https://github.com/shuding/nextra/issues/new?title=Feedback%20for%20%E2%80%9CTheme%20Configuration%E2%80%9D&labels=feedback).\n     */\n    link?: string\n  }\n\n  /**\n   * Rendered [`<Footer>` component](/docs/docs-theme/built-ins/footer). E.g. `<Footer {...footerProps} />`\n   */\n  footer?: React.ReactNode\n\n  /**\n   * Options to configure the language dropdown for [the i18n docs website](/docs/guide/i18n).\n   * @default []\n   */\n  i18n?: {\n    /**\n     * Locale from `i18n.locales` field in `next.config` file.\n     */\n    locale: string\n\n    /**\n     * Locale name in dropdown.\n     */\n    name: string\n  }[]\n\n  /**\n   * Component to render the last updated info.\n   * @default <LastUpdated />\n   */\n  lastUpdated?: React.ReactElement\n\n  /**\n   * Rendered [`<Navbar>` component](/docs/docs-theme/built-ins/navbar). E.g. `<Navbar {...navbarProps} />`\n   */\n  navbar?: React.ReactNode\n\n  /**\n   * Enable or disable navigation link.\n   * @default true\n   */\n  navigation?: boolean | {\n    next: boolean\n\n    prev: boolean\n  }\n\n  /**\n   * Configuration for the [next-themes](https://github.com/pacocoursey/next-themes#themeprovider) package.\n   * @default {\n   *   \"attribute\": \"class\",\n   *   \"defaultTheme\": \"system\",\n   *   \"disableTransitionOnChange\": true,\n   *   \"storageKey\": \"theme\"\n   * }\n   */\n  nextThemes?: {\n    /**\n     * @default \"class\"\n     */\n    attribute?: 'class' | `data-${string}` | ('class' | `data-${string}`)[]\n\n    /**\n     * @default \"system\"\n     */\n    defaultTheme?: string\n\n    /**\n     * @default true\n     */\n    disableTransitionOnChange?: boolean\n\n    forcedTheme?: string\n\n    /**\n     * @default \"theme\"\n     */\n    storageKey?: string\n  }\n\n  /**\n   * Page map list. Result of `getPageMap(route = '/')` call.\n   */\n  pageMap: import(\"nextra\").PageMapItem[]\n\n  /**\n   * Rendered [`<Search>` component](/docs/built-ins/search). E.g. `<Search {...searchProps} />`\n   * @default <Search />\n   */\n  search?: React.ReactNode\n\n  /**\n   * @default {\n   *   \"defaultMenuCollapseLevel\": 2,\n   *   \"defaultOpen\": true,\n   *   \"toggleButton\": true\n   * }\n   */\n  sidebar?: {\n    /**\n     * If `true`, automatically collapse inactive folders above `defaultMenuCollapseLevel`.\n     */\n    autoCollapse?: boolean\n\n    /**\n     * Specifies the folder level at which the menu on the left is collapsed by default.\n     * @default 2\n     */\n    defaultMenuCollapseLevel?: number\n\n    /**\n     * Hide/show sidebar by default.\n     * @default true\n     */\n    defaultOpen?: boolean\n\n    /**\n     * Hide/show sidebar toggle button.\n     * @default true\n     */\n    toggleButton?: boolean\n  }\n\n  /**\n   * Translation of options in the theme switch.\n   * @default {\n   *   \"dark\": \"Dark\",\n   *   \"light\": \"Light\",\n   *   \"system\": \"System\"\n   * }\n   */\n  themeSwitch?: {\n    /**\n     * @default \"Dark\"\n     */\n    dark?: string\n\n    /**\n     * @default \"Light\"\n     */\n    light?: string\n\n    /**\n     * @default \"System\"\n     */\n    system?: string\n  }\n\n  /**\n   * @default {\n   *   \"backToTop\": \"Scroll to top\",\n   *   \"float\": true,\n   *   \"title\": \"On This Page\"\n   * }\n   */\n  toc?: {\n    /**\n     * Text of back to top button.\n     * @default \"Scroll to top\"\n     */\n    backToTop?: React.ReactNode\n\n    /**\n     * Display extra content below the TOC content.\n     */\n    extraContent?: React.ReactNode\n\n    /**\n     * Float the TOC next to the content.\n     * @default true\n     */\n    float?: boolean\n\n    /**\n     * Title of the TOC sidebar.\n     * @default \"On This Page\"\n     */\n    title?: React.ReactNode\n  }\n}"
  },
  {
    "path": "packages/nextra-theme-docs/src/utils/extract-only-strings-from-react-node.ts",
    "content": "import type { ReactNode } from 'react'\n\nexport function extractStringsFromReactNode(node: ReactNode): string {\n  if (typeof node === 'string') return node\n  if (typeof node === 'number') return String(node)\n  if (Array.isArray(node))\n    return node.map(n => extractStringsFromReactNode(n)).join('')\n\n  const children = (node as any)?.props?.children as ReactNode\n  if (!children) return ''\n  return extractStringsFromReactNode(children)\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/utils/get-git-issue-url.ts",
    "content": "'use no memo'\n\nimport { gitUrlParse } from './git-url-parse'\n\nexport function getGitIssueUrl({\n  repository = '',\n  title,\n  labels\n}: {\n  repository?: string\n  title: string\n  labels?: string\n}): string {\n  const repo = gitUrlParse(repository)\n  if (repo.origin.includes('gitlab')) {\n    return `${repo.origin}/${repo.owner}/${\n      repo.name\n    }/-/issues/new?issue[title]=${encodeURIComponent(title)}${\n      labels\n        ? `&issue[description]=/label${encodeURIComponent(` ~${labels}\\n`)}`\n        : ''\n    }`\n  }\n  if (repo.origin.includes('github')) {\n    return `${repo.origin}/${repo.owner}/${\n      repo.name\n    }/issues/new?title=${encodeURIComponent(title)}&labels=${labels || ''}`\n  }\n  return '#'\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/utils/git-url-parse.ts",
    "content": "'use no memo'\n\nexport function gitUrlParse(url: string) {\n  const { href, origin, pathname } = new URL(url)\n\n  const [, owner, name] = pathname.split('/', 3)\n  return {\n    href,\n    origin,\n    owner,\n    name\n  }\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/src/utils/index.ts",
    "content": "export { getGitIssueUrl } from './get-git-issue-url'\nexport { gitUrlParse } from './git-url-parse'\nexport { extractStringsFromReactNode } from './extract-only-strings-from-react-node'\n"
  },
  {
    "path": "packages/nextra-theme-docs/tailwind.config.ts",
    "content": "import type { Config } from 'tailwindcss'\n\nexport default {\n  theme: {\n    fontSize: {\n      xs: '.75rem',\n      sm: '.875rem',\n      base: '1rem',\n      lg: '1.125rem',\n      xl: '1.25rem',\n      '2xl': '1.5rem',\n      '3xl': '1.875rem',\n      '4xl': '2.25rem',\n      '5xl': '3rem',\n      '6xl': '4rem'\n    },\n    letterSpacing: {\n      tight: '-0.015em'\n    },\n    colors: {\n      transparent: 'transparent',\n      current: 'currentColor',\n      black: '#000',\n      white: '#fff'\n    }\n  }\n} satisfies Config\n"
  },
  {
    "path": "packages/nextra-theme-docs/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2021\",\n    \"module\": \"ESNext\",\n    \"declaration\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"skipLibCheck\": true,\n    \"strictNullChecks\": true,\n    \"jsx\": \"react-jsx\",\n    \"moduleResolution\": \"bundler\",\n    \"lib\": [\"ESNext\", \"DOM\"],\n    \"types\": [\"vitest/globals\"],\n    \"noUncheckedIndexedAccess\": true,\n    \"paths\": {\n      // For type tests\n      \"unified\": [\"../nextra/node_modules/unified\"],\n      \"rehype-katex\": [\"../nextra/node_modules/rehype-katex/lib/index.d.js\"]\n    }\n  },\n  \"exclude\": [\"dist\"]\n}\n"
  },
  {
    "path": "packages/nextra-theme-docs/tsup.config.ts",
    "content": "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { reactCompilerPlugin } from 'esbuild-react-compiler-plugin'\nimport { defineConfig } from 'tsup'\nimport { $ } from 'zx'\nimport { defaultEntry } from '../nextra/default-entry.js'\nimport packageJson from './package.json'\n\nexport default defineConfig({\n  name: packageJson.name,\n  entry: defaultEntry,\n  format: 'esm',\n  dts: true,\n  outExtension: () => ({ js: '.js' }),\n  bundle: false,\n  esbuildPlugins: [reactCompilerPlugin({ filter: /\\.tsx?$/ })],\n  async onSuccess() {\n    // Use Tailwind CSS CLI because CSS processing by tsup produce different result\n    await $`npx @tailwindcss/cli -i src/style.css -o dist/style.css`\n    const styleContent = await fs.readFile(\n      path.resolve('dist', 'style.css'),\n      'utf8'\n    )\n    await fs.writeFile(\n      path.resolve('dist', 'style-prefixed.css'),\n      styleContent\n        .replaceAll('@layer utilities', '@layer v4-utilities')\n        .replaceAll('@layer base', '@layer v4-base')\n        .replace(\n          '@layer theme, base, components, utilities',\n          '@layer theme, v4-base, components, v4-utilities'\n        )\n    )\n    console.log('✅ `dist/style-prefixed.css` successfully created')\n  }\n})\n"
  },
  {
    "path": "packages/nextra-theme-docs/vitest.config.mts",
    "content": "import react from '@vitejs/plugin-react'\nimport { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  plugins: [react()],\n  test: {\n    globals: true,\n    setupFiles: ['./setup-files.ts']\n  }\n})\n"
  },
  {
    "path": "packages/prettier-config/CHANGELOG.md",
    "content": "# @nextra/prettier-config\n\n## 0.0.1\n"
  },
  {
    "path": "packages/prettier-config/package.json",
    "content": "{\n  \"name\": \"@nextra/prettier-config\",\n  \"version\": \"0.0.1\",\n  \"type\": \"module\",\n  \"private\": true,\n  \"exports\": {\n    \".\": \"./src/index.js\"\n  },\n  \"dependencies\": {\n    \"@ianvs/prettier-plugin-sort-imports\": \"4.7.0\",\n    \"prettier-plugin-pkg\": \"0.21.2\",\n    \"prettier-plugin-tailwindcss\": \"0.7.2\"\n  }\n}\n"
  },
  {
    "path": "packages/prettier-config/src/index.js",
    "content": "export default {\n  semi: false,\n  singleQuote: true,\n  trailingComma: 'none',\n  arrowParens: 'avoid',\n  plugins: [\n    // For sort fields in package.json\n    'prettier-plugin-pkg',\n    // For sorting imports\n    '@ianvs/prettier-plugin-sort-imports',\n    'prettier-plugin-tailwindcss' // MUST come last\n  ],\n  overrides: [\n    {\n      files: '*.svg',\n      options: {\n        parser: 'html'\n      }\n    }\n  ],\n  proseWrap: 'always' // printWidth line breaks in md/mdx\n}\n"
  },
  {
    "path": "packages/tsdoc/README.md",
    "content": "# `@nextra/tsdoc`\n\n[TSDoc](https://tsdoc.org) integration for Nextra.\n"
  },
  {
    "path": "packages/tsdoc/package.json",
    "content": "{\n  \"name\": \"@nextra/tsdoc\",\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"description\": \"TSDoc integration for Nextra\",\n  \"repository\": \"github:shuding/nextra\",\n  \"homepage\": \"https://nextra.site\",\n  \"author\": \"Dimitri POSTOLOV\",\n  \"license\": \"MIT\",\n  \"private\": true,\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/index.js\",\n      \"types\": \"./dist/index.d.ts\"\n    }\n  },\n  \"files\": [\n    \"dist\"\n  ],\n  \"keywords\": [\n    \"next.js\",\n    \"nextra\",\n    \"docs\",\n    \"typescript\",\n    \"tsdoc\"\n  ],\n  \"scripts\": {\n    \"build\": \"NODE_ENV=production tsup\",\n    \"dev\": \"tsup --watch\",\n    \"test\": \"vitest\",\n    \"types:check\": \"tsc --noEmit\"\n  },\n  \"peerDependencies\": {\n    \"nextra\": \">=4.3.0-alpha.0\",\n    \"nextra-theme-docs\": \">=4.3.0-alpha.0\",\n    \"typescript\": \"*\"\n  },\n  \"dependencies\": {\n    \"clsx\": \"^2.1.1\",\n    \"zod\": \"^4.1.12\"\n  },\n  \"devDependencies\": {\n    \"@tsconfig/strictest\": \"^2.0.5\",\n    \"@types/react\": \"^19.1.8\",\n    \"@xyflow/react\": \"12.8.5\",\n    \"nextra\": \"workspace:*\",\n    \"nextra-theme-docs\": \"workspace:*\",\n    \"tsup\": \"^8.4.0\",\n    \"vitest\": \"^3.0.9\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "packages/tsdoc/src/__tests__/base.test.ts",
    "content": "import { LayoutPropsSchema } from '../../../nextra-theme-docs/src/schemas.js'\nimport { HeadPropsSchema } from '../../../nextra/src/client/components/head.js'\nimport { NextraConfigSchema } from '../../../nextra/src/server/schemas.js'\nimport { generateDefinition } from '../../../nextra/src/server/tsdoc/base.js'\nimport { generateTsFromZod } from '../../../nextra/src/server/tsdoc/zod-to-ts.js'\nimport typesFixture from './fixtures/flattened?raw'\n\ndescribe('generateDefinition()', () => {\n  test('useMDXComponents', () => {\n    const code =\n      \"export { useMDXComponents as default } from 'nextra/mdx-components'\"\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"description\": \"Get current MDX components.\",\n        \"filePath\": \"../nextra/dist/client/mdx-components.d.ts\",\n        \"name\": \"useMDXComponents\",\n        \"signatures\": [\n          {\n            \"params\": [\n              {\n                \"description\": \"An object where:\n      - The key is the name of the HTML element to override.\n      - The value is the component to render instead.\",\n                \"name\": \"components\",\n                \"tags\": {\n                  \"remarks\": \"\\`MDXComponents\\`\",\n                },\n                \"type\": \"MDXComponents\",\n              },\n            ],\n            \"returns\": {\n              \"type\": \"DefaultMDXComponents & components\",\n            },\n          },\n          {\n            \"params\": [],\n            \"returns\": {\n              \"type\": \"DefaultMDXComponents\",\n            },\n          },\n        ],\n        \"tags\": {\n          \"returns\": \"The current set of MDX components.\",\n        },\n      }\n    `)\n  })\n  test('Should parse type tags', () => {\n    const code = `\n/**\n * MyType description\n * @tag MyTag\n */\ntype MyType = {\n  /** MyType.foo */\n  foo?: string\n}\nexport default MyType`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"description\": \"MyType description\",\n        \"entries\": [\n          {\n            \"description\": \"MyType.foo\",\n            \"name\": \"foo\",\n            \"optional\": true,\n            \"type\": \"string\",\n          },\n        ],\n        \"name\": \"MyType\",\n        \"tags\": {\n          \"tag\": \"MyTag\",\n        },\n      }\n    `)\n  })\n  test('<Tabs />', async () => {\n    const code = \"export type { Tabs as default } from 'nextra/components'\"\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"description\": \"A built-in component for creating tabbed content, helping organize related information in a\n      compact, interactive layout.\",\n        \"filePath\": \"../nextra/dist/client/components/tabs/index.d.ts\",\n        \"name\": \"Tabs\",\n        \"signatures\": [\n          {\n            \"params\": [\n              {\n                \"name\": \"props\",\n                \"type\": \"{ items: (TabItem | TabObjectItem)[]; children: ReactNode; storageKey?: string; className?: string | ((bag: ListRenderPropArg) => string) | undefined; tabClassName?: string | ... 1 more ... | undefined; } & Pick<...>\",\n              },\n            ],\n            \"returns\": {\n              \"type\": \"react_jsx_runtime_js.JSX.Element\",\n            },\n          },\n        ],\n        \"tags\": {\n          \"example\": \"<Tabs items={['pnpm', 'npm', 'yarn']}>\n        <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n        <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n        <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n      </Tabs>\",\n          \"usage\": \"\\`\\`\\`mdx\n      import { Tabs } from 'nextra/components'\n\n      <Tabs items={['pnpm', 'npm', 'yarn']}>\n        <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n        <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n        <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n      </Tabs>\n      \\`\\`\\`\n\n      ### Default Selected Index\n\n      You can use the \\`defaultIndex\\` prop to set the default tab index:\n\n      \\`\\`\\`mdx /defaultIndex=\"1\"/\n      import { Tabs } from 'nextra/components'\n\n      <Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\"1\">\n        ...\n      </Tabs>\n      \\`\\`\\`\n\n      And you will have \\`npm\\` as the default tab:\n\n      <Tabs items={['pnpm', 'npm', 'yarn']} defaultIndex=\"1\">\n        <Tabs.Tab>**pnpm**: Fast, disk space efficient package manager.</Tabs.Tab>\n        <Tabs.Tab>**npm** is a package manager for the JavaScript programming language.</Tabs.Tab>\n        <Tabs.Tab>**Yarn** is a software packaging system.</Tabs.Tab>\n      </Tabs>\",\n        },\n      }\n    `)\n  })\n  test('<Steps />', async () => {\n    const code = \"export type { Steps as default } from 'nextra/components'\"\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"description\": \"A built-in component to turn a numbered list into a visual representation of\n      steps.\",\n        \"filePath\": \"../nextra/dist/client/components/steps.d.ts\",\n        \"name\": \"Steps\",\n        \"signatures\": [\n          {\n            \"params\": [\n              {\n                \"name\": \"props\",\n                \"type\": \"HTMLAttributes<HTMLDivElement>\",\n              },\n            ],\n            \"returns\": {\n              \"type\": \"ReactNode | Promise<ReactNode>\",\n            },\n          },\n        ],\n        \"tags\": {\n          \"example\": \"<Steps>\n\n      ### This is the first step\n\n      This is the first step description.\n\n      ### This is the second step\n\n      This is the second step description.\n\n      ### This is the third step\n\n      This is the third step description.\n\n      </Steps>\",\n          \"usage\": \"Wrap a set of Markdown headings (from \\`<h2>\\` to \\`<h6>\\`) with the \\`<Steps>\\`\n      component to display them as visual steps. You can choose the appropriate\n      heading level based on the content hierarchy on the page.\n\n      \\`\\`\\`mdx filename=\"MDX\" {7-15}\n      import { Steps } from 'nextra/components'\n\n      ## Getting Started\n\n      Here is some description.\n\n      <Steps>\n      ### Step 1\n\n      Contents for step 1.\n\n      ### Step 2\n\n      Contents for step 2.\n      </Steps>\n      \\`\\`\\`\n\n      ### Excluding Headings from Table of Contents\n\n      To exclude the headings from the \\`<Steps>\\` component (or any other headings)\n      to appear in the Table of Contents, replace the Markdown headings \\`### ...\\`\n      with \\`<h3>\\` HTML element wrapped in curly braces.\n\n      \\`\\`\\`diff filename=\"MDX\"\n      <Steps>\n      - ### Step 1\n      + {<h3>Step 1</h3>}\n\n      Contents for step 1.\n      </Steps>\n      \\`\\`\\`\",\n        },\n      }\n    `)\n  })\n  test('<Banner />', async () => {\n    // TODO check `tw` prop\n    const groupKeys = 'React.HTMLAttributes<HTMLDivElement>'\n    const code = `import type { Banner } from 'nextra/components'\ntype $ = React.ComponentProps<typeof Banner>\ntype $$ = Omit<$, keyof ${groupKeys} | 'tw'> & { '...props': ${groupKeys} }>\nexport default $$`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"description\": \"Closable banner or not.\",\n            \"name\": \"dismissible\",\n            \"optional\": true,\n            \"tags\": {\n              \"default\": \"true\",\n            },\n            \"type\": \"boolean\",\n          },\n          {\n            \"description\": \"Storage key to keep the banner state.\",\n            \"name\": \"storageKey\",\n            \"optional\": true,\n            \"tags\": {\n              \"default\": \"'nextra-banner'\",\n            },\n            \"type\": \"string\",\n          },\n          {\n            \"name\": \"...props\",\n            \"type\": \"HTMLAttributes<HTMLDivElement>\",\n          },\n        ],\n        \"name\": \"$$\",\n      }\n    `)\n  })\n  test('<Search />', async () => {\n    const code = `import type { Search } from 'nextra/components'\ntype $ = React.ComponentProps<typeof Search>\nexport default $`\n    const result = generateDefinition({ code })\n    await expect(result).toMatchFileSnapshot('./snapshots/search.json')\n  })\n  test('<Callout />', async () => {\n    // TODO check `tw` prop\n    const groupKeys = 'React.HTMLAttributes<HTMLDivElement>'\n    const code = `import type { Callout } from 'nextra/components'\ntype $ = React.ComponentProps<typeof Callout>\ntype $$ = Omit<$, keyof ${groupKeys} | 'tw'> & { '...props': ${groupKeys} }>\nexport default $$`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"description\": \"Defines the style of the callout and determines the default icon if \\`emoji\\` is not provided.\n\n      If set to \\`null\\`, no border, background, or text styling will be applied.\",\n            \"name\": \"type\",\n            \"optional\": true,\n            \"tags\": {\n              \"default\": \"'default'\",\n            },\n            \"type\": \"\"default\" | \"error\" | \"info\" | \"warning\" | \"important\" | null\",\n          },\n          {\n            \"description\": \"Icon displayed in the callout. Can be a string emoji or a custom React element.\n\n      Default values based on \\`type\\`:\n      - \\`<GitHubTipIcon />\\` for \\`type: 'default'\\`\n      - \\`<GitHubCautionIcon />\\` for \\`type: 'error'\\`\n      - \\`<GitHubNoteIcon />\\` for \\`type: 'info'\\`\n      - \\`<GitHubWarningIcon />\\` for \\`type: 'warning'\\`\n      - \\`<GitHubImportantIcon />\\` for \\`type: 'important'\\`\",\n            \"name\": \"emoji\",\n            \"optional\": true,\n            \"tags\": {\n              \"default\": \"Determined by \\`type\\`\",\n            },\n            \"type\": \"ReactNode\",\n          },\n          {\n            \"name\": \"...props\",\n            \"type\": \"HTMLAttributes<HTMLDivElement>\",\n          },\n        ],\n        \"name\": \"$$\",\n      }\n    `)\n  })\n  test('<NotFoundPage />', async () => {\n    const code = `import type { NotFoundPage } from 'nextra-theme-docs'\ntype $ = React.ComponentProps<typeof NotFoundPage>\nexport default $`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"description\": \"Content of the link.\",\n            \"name\": \"content\",\n            \"optional\": true,\n            \"tags\": {\n              \"default\": \"'Submit an issue about broken link'\",\n            },\n            \"type\": \"ReactNode\",\n          },\n          {\n            \"description\": \"Labels that can be added to the newly created issue.\",\n            \"name\": \"labels\",\n            \"optional\": true,\n            \"tags\": {\n              \"default\": \"'bug'\",\n            },\n            \"type\": \"string\",\n          },\n          {\n            \"description\": \"Top content of the page.\",\n            \"name\": \"children\",\n            \"optional\": true,\n            \"tags\": {\n              \"default\": \"<H1>404: Page Not Found</H1>\",\n            },\n            \"type\": \"ReactNode\",\n          },\n          {\n            \"description\": \"CSS class name.\",\n            \"name\": \"className\",\n            \"optional\": true,\n            \"type\": \"string\",\n          },\n        ],\n        \"name\": \"$\",\n      }\n    `)\n  })\n  test('<Navbar />', async () => {\n    const code = `import { Navbar } from 'nextra-theme-docs'\ntype $ = React.ComponentProps<typeof Navbar>\nexport default $`\n    const result = generateDefinition({ code })\n    await expect(result).toMatchFileSnapshot('./snapshots/navbar.json')\n  })\n  test('<Head /> with `flattened: true`', async () => {\n    const code = `type $ = ${generateTsFromZod(HeadPropsSchema)}\nexport default $`\n    const result = generateDefinition({ code, flattened: true })\n    await expect(result).toMatchFileSnapshot('./snapshots/head.json')\n  })\n  test('DocsLayoutProps with `flattened: true`', async () => {\n    const code = `type $ = ${generateTsFromZod(LayoutPropsSchema)}\nexport default $`\n    const result = generateDefinition({ code, flattened: true })\n    await expect(result).toMatchFileSnapshot('./snapshots/layout-props.json')\n  })\n  test('NextraConfig with `flattened: true`', async () => {\n    const code = `type $ = ${generateTsFromZod(NextraConfigSchema)}\nexport default $`\n    const result = generateDefinition({ code, flattened: true })\n    await expect(result).toMatchFileSnapshot('./snapshots/nextra-config.json')\n  })\n  test('two declarations', async () => {\n    const code = `\ntype A = { foo: string }\ntype A = { bar: string }\nexport default A`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"name\": \"foo\",\n            \"type\": \"string\",\n          },\n        ],\n        \"name\": \"A\",\n      }\n    `)\n  })\n  test('inline description and @description as tag', async () => {\n    const code = `type $ = {\n/**\n * @description Show or hide breadcrumb navigation.\n */\nbreadcrumb?: boolean\n\n/**\n * Indicates whether the item in sidebar is collapsed by default.\n */\ncollapsed?: boolean\n}\nexport default $`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"name\": \"breadcrumb\",\n            \"optional\": true,\n            \"tags\": {\n              \"description\": \"Show or hide breadcrumb navigation.\",\n            },\n            \"type\": \"boolean\",\n          },\n          {\n            \"description\": \"Indicates whether the item in sidebar is collapsed by default.\",\n            \"name\": \"collapsed\",\n            \"optional\": true,\n            \"type\": \"boolean\",\n          },\n        ],\n        \"name\": \"$\",\n      }\n    `)\n  })\n  test('should show null type', async () => {\n    const code = `\ntype Connection = {\n  targetHandle: string | null;\n};\nexport default Connection`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"name\": \"targetHandle\",\n            \"type\": \"string | null\",\n          },\n        ],\n        \"name\": \"Connection\",\n      }\n    `)\n  })\n\n  describe('functions', () => {\n    test('should flatten return type for useThemeConfig', async () => {\n      const code =\n        'export { useThemeConfig as default } from \"../nextra-theme-docs/src\"'\n      const result = generateDefinition({ code, flattened: true })\n      await expect(result).toMatchFileSnapshot(\n        './snapshots/use-theme-config.json'\n      )\n    })\n    test('ReactFlowInstance', async () => {\n      const code =\n        'export { ReactFlowInstance as default } from \"@xyflow/react\"'\n      const { filePath: _, ...result } = generateDefinition({\n        code,\n        flattened: true\n      })\n      await expect(result).toMatchFileSnapshot(\n        './snapshots/react-flow-instance.json'\n      )\n    })\n\n    test('should flatten return type for useConfig', async () => {\n      const code = 'export { useConfig as default } from \"nextra-theme-docs\"'\n      const result = generateDefinition({ code, flattened: true })\n      await expect(result).toMatchFileSnapshot('./snapshots/use-config.json')\n    })\n\n    test('should be parsed in object field', () => {\n      const code = `type $ = {\n  useNodeConnections: typeof import('@xyflow/react').useNodeConnections\n}\nexport default $\n`\n      const result = generateDefinition({ code })\n      expect(result).toMatchInlineSnapshot(`\n        {\n          \"entries\": [\n            {\n              \"name\": \"useNodeConnections\",\n              \"type\": \"({ id, handleType, handleId, onConnect, onDisconnect, }?: UseNodeConnectionsParams | undefined) => NodeConnection[]\",\n            },\n          ],\n          \"name\": \"$\",\n        }\n      `)\n    })\n    test('should be parsed as function type', () => {\n      const code =\n        \"export { useNodeConnections as default } from '@xyflow/react'\"\n      const { filePath: _, ...result } = generateDefinition({\n        code,\n        flattened: true\n      })\n      expect(result).toMatchInlineSnapshot(`\n        {\n          \"description\": \"This hook returns an array of connections on a specific node, handle type ('source', 'target') or handle ID.\",\n          \"name\": \"useNodeConnections\",\n          \"signatures\": [\n            {\n              \"params\": [\n                {\n                  \"description\": \"ID of the node, filled in automatically if used inside custom node.\",\n                  \"name\": \"[0]?.id\",\n                  \"optional\": true,\n                  \"type\": \"string\",\n                },\n                {\n                  \"description\": \"What type of handle connections do you want to observe?\",\n                  \"name\": \"[0]?.handleType\",\n                  \"optional\": true,\n                  \"type\": \"'source' | 'target'\",\n                },\n                {\n                  \"description\": \"Filter by handle id (this is only needed if the node has multiple handles of the same type).\",\n                  \"name\": \"[0]?.handleId\",\n                  \"optional\": true,\n                  \"type\": \"string\",\n                },\n                {\n                  \"description\": \"Gets called when a connection is established.\",\n                  \"name\": \"[0]?.onConnect\",\n                  \"optional\": true,\n                  \"type\": \"(connections: HandleConnection[]) => void\",\n                },\n                {\n                  \"description\": \"Gets called when a connection is removed.\",\n                  \"name\": \"[0]?.onDisconnect\",\n                  \"optional\": true,\n                  \"type\": \"(connections: HandleConnection[]) => void\",\n                },\n              ],\n              \"returns\": {\n                \"type\": \"NodeConnection[]\",\n              },\n            },\n          ],\n          \"tags\": {\n            \"example\": \"\\`\\`\\`jsx\n        import { useNodeConnections } from '@xyflow/react';\n\n        export default function () {\n         const connections = useNodeConnections({\n           handleType: 'target',\n           handleId: 'my-handle',\n         });\n\n         return (\n           <div>There are currently {connections.length} incoming connections!</div>\n         );\n        }\n        \\`\\`\\`\",\n            \"public\": \"\",\n            \"returns\": \"An array with connections.\",\n          },\n        }\n      `)\n    })\n    test('as function with description', () => {\n      const code = \"export { useInternalNode as default } from '@xyflow/react'\"\n      const { filePath: _, ...result } = generateDefinition({\n        code,\n        flattened: true\n      })\n      expect(result).toMatchInlineSnapshot(`\n        {\n          \"description\": \"This hook returns the internal representation of a specific node.\n        Components that use this hook will re-render **whenever the node changes**,\n        including when a node is selected or moved.\",\n          \"name\": \"useInternalNode\",\n          \"signatures\": [\n            {\n              \"params\": [\n                {\n                  \"description\": \"The ID of a node you want to observe.\",\n                  \"name\": \"id\",\n                  \"tags\": {\n                    \"param\": \"id - The ID of a node you want to observe.\",\n                  },\n                  \"type\": \"string\",\n                },\n              ],\n              \"returns\": {\n                \"type\": \"InternalNode<NodeType> | undefined\",\n              },\n            },\n          ],\n          \"tags\": {\n            \"example\": \"\\`\\`\\`tsx\n        import { useInternalNode } from '@xyflow/react';\n\n        export default function () {\n         const internalNode = useInternalNode('node-1');\n         const absolutePosition = internalNode.internals.positionAbsolute;\n\n         return (\n           <div>\n             The absolute position of the node is at:\n             <p>x: {absolutePosition.x}</p>\n             <p>y: {absolutePosition.y}</p>\n           </div>\n         );\n        }\n        \\`\\`\\`\",\n            \"param\": \"id - The ID of a node you want to observe.\",\n            \"public\": \"\",\n            \"returns\": \"The \\`InternalNode\\` object for the node with the given ID.\",\n          },\n        }\n      `)\n    })\n\n    test(\"should not throw when symbol isn't found\", () => {\n      const code = \"export { isEdge as default } from '@xyflow/react'\"\n      const { filePath: _, ...result } = generateDefinition({\n        code,\n        flattened: true\n      })\n      expect(result).toMatchInlineSnapshot(`\n        {\n          \"description\": \"Test whether an object is usable as an [\\`Edge\\`](/api-reference/types/edge).\n        In TypeScript this is a type guard that will narrow the type of whatever you pass in to\n        [\\`Edge\\`](/api-reference/types/edge) if it returns \\`true\\`.\",\n          \"name\": \"isEdge\",\n          \"signatures\": [\n            {\n              \"params\": [\n                {\n                  \"description\": \"The element to test\",\n                  \"name\": \"element\",\n                  \"tags\": {\n                    \"param\": \"element - The element to test\",\n                  },\n                  \"type\": \"unknown\",\n                },\n              ],\n              \"returns\": {\n                \"type\": \"boolean\",\n              },\n            },\n          ],\n          \"tags\": {\n            \"example\": \"\\`\\`\\`js\n        import { isEdge } from '@xyflow/react';\n\n        if (isEdge(edge)) {\n        // ...\n        }\n        \\`\\`\\`\",\n            \"param\": \"element - The element to test\",\n            \"public\": \"\",\n            \"remarks\": \"In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true\",\n            \"returns\": \"Tests whether the provided value can be used as an \\`Edge\\`. If you're using TypeScript,\n        this function acts as a type guard and will narrow the type of the value to \\`Edge\\` if it returns\n        \\`true\\`.\",\n          },\n        }\n      `)\n    })\n\n    test('should parse multiple function signatures', () => {\n      const code = \"export { useNodesData as default } from '@xyflow/react'\"\n      const { filePath: _, ...result } = generateDefinition({\n        code,\n        flattened: true\n      })\n      expect(result).toMatchInlineSnapshot(`\n        {\n          \"description\": \"This hook lets you subscribe to changes of a specific nodes \\`data\\` object.\",\n          \"name\": \"useNodesData\",\n          \"signatures\": [\n            {\n              \"params\": [\n                {\n                  \"description\": \"The id of the node to get the data from.\",\n                  \"name\": \"nodeId\",\n                  \"type\": \"string\",\n                },\n              ],\n              \"returns\": {\n                \"type\": \"Pick<NodeType, \"id\" | \"type\" | \"data\"> | null\",\n              },\n            },\n            {\n              \"params\": [\n                {\n                  \"description\": \"The ids of the nodes to get the data from.\",\n                  \"name\": \"nodeIds\",\n                  \"type\": \"string[]\",\n                },\n              ],\n              \"returns\": {\n                \"type\": \"Pick<NodeType, \"id\" | \"type\" | \"data\">[]\",\n              },\n            },\n          ],\n          \"tags\": {\n            \"example\": \"\\`\\`\\`jsx\n        import { useNodesData } from '@xyflow/react';\n\n        export default function() {\n         const nodeData = useNodesData('nodeId-1');\n         const nodesData = useNodesData(['nodeId-1', 'nodeId-2']);\n\n         return null;\n        }\n        \\`\\`\\`\",\n            \"public\": \"\",\n            \"returns\": \"An object (or array of object) with \\`id\\`, \\`type\\`, \\`data\\` representing each node.\",\n          },\n        }\n      `)\n    })\n\n    test('should parse optional parameters', () => {\n      const code =\n        'function foo(a: string, b?: number, c = true) {}\\nexport default foo'\n      const result = generateDefinition({ code, flattened: true })\n      expect(result).toMatchInlineSnapshot(`\n        {\n          \"name\": \"foo\",\n          \"signatures\": [\n            {\n              \"params\": [\n                {\n                  \"name\": \"a\",\n                  \"type\": \"string\",\n                },\n                {\n                  \"name\": \"b\",\n                  \"optional\": true,\n                  \"type\": \"number\",\n                },\n                {\n                  \"name\": \"c\",\n                  \"optional\": true,\n                  \"type\": \"boolean\",\n                },\n              ],\n              \"returns\": {\n                \"type\": \"void\",\n              },\n            },\n          ],\n        }\n      `)\n    })\n\n    test('should not flatten tuple type, set, map', () => {\n      const code = `\ntype foo = (params: {\n  tuple?: [number, number],\n  set?: Set<string>,\n  map?: Map<string, number>,\n}) => void\nexport default foo`\n      const result = generateDefinition({ code, flattened: true })\n      expect(result).toMatchInlineSnapshot(`\n        {\n          \"name\": \"foo\",\n          \"signatures\": [\n            {\n              \"params\": [\n                {\n                  \"name\": \"params.tuple\",\n                  \"optional\": true,\n                  \"type\": \"[number, number]\",\n                },\n                {\n                  \"name\": \"params.set\",\n                  \"optional\": true,\n                  \"type\": \"Set<string>\",\n                },\n                {\n                  \"name\": \"params.map\",\n                  \"optional\": true,\n                  \"type\": \"Map<string, number>\",\n                },\n              ],\n              \"returns\": {\n                \"type\": \"void\",\n              },\n            },\n          ],\n        }\n      `)\n    })\n  })\n\n  test('should exclude {@link ...}', async () => {\n    const code =\n      \"export { getViewportForBounds as default } from '@xyflow/react'\"\n    const { filePath: _, ...result } = generateDefinition({\n      code,\n      flattened: true\n    })\n    await expect(result).toMatchFileSnapshot(\n      './snapshots/get-viewport-for-bounds.json'\n    )\n  })\n\n  test('should flatten array return type', async () => {\n    const code = 'export { useEdgesState as default } from \"@xyflow/react\"'\n    const { filePath: _, ...result } = generateDefinition({\n      code,\n      flattened: true\n    })\n    await expect(result).toMatchFileSnapshot('./snapshots/use-edges-state.json')\n  })\n\n  test('should parse `unknown` type', () => {\n    const code = 'function foo(a?: unknown) {}\\nexport default foo'\n    const result = generateDefinition({ code, flattened: true })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"name\": \"foo\",\n        \"signatures\": [\n          {\n            \"params\": [\n              {\n                \"name\": \"a\",\n                \"optional\": true,\n                \"type\": \"unknown\",\n              },\n            ],\n            \"returns\": {\n              \"type\": \"void\",\n            },\n          },\n        ],\n      }\n    `)\n  })\n\n  test('should flatten params', async () => {\n    const { filePath: _, ...result } = generateDefinition({\n      code: \"export { getSmoothStepPath as default } from '@xyflow/react'\",\n      flattened: true\n    })\n    await expect(result).toMatchFileSnapshot(\n      './snapshots/get-smooth-step-path.json'\n    )\n  })\n\n  test('should remove `undefined` from optional fields', () => {\n    const result = generateDefinition({\n      code: `\ntype $ = {\n  a?: string\n  b: string | undefined\n  c?: string | undefined\n}\nexport default $`,\n      flattened: true\n    })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"name\": \"a\",\n            \"optional\": true,\n            \"type\": \"string\",\n          },\n          {\n            \"name\": \"b\",\n            \"type\": \"string | undefined\",\n          },\n          {\n            \"name\": \"c\",\n            \"optional\": true,\n            \"type\": \"string | undefined\",\n          },\n        ],\n        \"name\": \"$\",\n      }\n    `)\n  })\n\n  test('should flatten only object', async () => {\n    const result = generateDefinition({\n      code: typesFixture,\n      flattened: true\n    })\n    await expect(result).toMatchFileSnapshot('./snapshots/flattened.json')\n  })\n\n  test('should exclude JSDoc @link in description', () => {\n    const code = `type $ = {\n  /**\n   * By default, we render a small attribution in the corner of your flows that links back to the project.\n   *\n   * Anyone is free to remove this attribution whether they're a Pro subscriber or not\n   * but we ask that you take a quick look at our {@link https://reactflow.dev/learn/troubleshooting/remove-attribution | removing attribution guide}\n   * before doing so.\n   */\n  proOptions?: unknown;\n}\n\nexport default $`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"description\": \"By default, we render a small attribution in the corner of your flows that links back to the project.\n\n      Anyone is free to remove this attribution whether they're a Pro subscriber or not\n      but we ask that you take a quick look at our https://reactflow.dev/learn/troubleshooting/remove-attribution removing attribution guide\n      before doing so.\",\n            \"name\": \"proOptions\",\n            \"optional\": true,\n            \"type\": \"unknown\",\n          },\n        ],\n        \"name\": \"$\",\n      }\n    `)\n  })\n\n  it('should not flatten Partial', () => {\n    const code = `\nimport { ReactFlowProps } from '@xyflow/react'\n\ntype $ = Pick<ReactFlowProps, 'ariaLabelConfig'>\n\nexport default $`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"description\": \"Configuration for customizable labels, descriptions, and UI text. Provided keys will override the corresponding defaults.\n      Allows localization, customization of ARIA descriptions, control labels, minimap labels, and other UI strings.\",\n            \"name\": \"ariaLabelConfig\",\n            \"optional\": true,\n            \"type\": \"Partial<AriaLabelConfig>\",\n          },\n        ],\n        \"name\": \"$\",\n      }\n    `)\n  })\n\n  it('supports @inline tag', () => {\n    const code = `\nimport { ReactFlowInstance } from '@xyflow/react'\n\ntype Foo = {\n  bar: string\n}\n\n\n/**\n * @inline\n */\ntype InlineOnType = () => Promise<boolean>;\n\n/**\n * @inline\n * @remarks \\`1337\\`\n */\ntype InlineAndRemarksOnType = () => Promise<boolean>;\n\n/**\n * @inline\n */\ntype InlineParam = {\n  baz: string\n}\n\n/**\n * @inline\n */\ntype InlineFunctionParamOnType = (options?: InlineParam) => Promise<boolean>;\n\ntype $ = {\n  /**\n   * @inline\n   */\n  setViewport: ReactFlowInstance['setViewport']\n  /**\n   * @inline\n   */\n  foo: Foo\n  bar: InlineOnType\n  quz: InlineAndRemarksOnType\n  zz: InlineFunctionParamOnType\n}\n\nexport default $`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"name\": \"setViewport\",\n            \"tags\": {\n              \"inline\": \"\",\n            },\n            \"type\": \"(viewport: Viewport, options?: { duration?: number; ease?: (t: number) => number; interpolate?: \"smooth\" | \"linear\"; }) => Promise<boolean>\",\n          },\n          {\n            \"name\": \"foo\",\n            \"tags\": {\n              \"inline\": \"\",\n            },\n            \"type\": \"{\n        bar: string\n      }\",\n          },\n          {\n            \"name\": \"bar\",\n            \"type\": \"() => Promise<boolean>\",\n          },\n          {\n            \"name\": \"quz\",\n            \"type\": \"1337\",\n          },\n          {\n            \"name\": \"zz\",\n            \"type\": \"(options?: { baz: string; }) => Promise<boolean>\",\n          },\n        ],\n        \"name\": \"$\",\n      }\n    `)\n  })\n\n  it('should recursively @inline', () => {\n    const code = `\nimport { ReactFlowInstance } from '@xyflow/react'\n\ntype $ = Pick<ReactFlowInstance, 'fitView'>\n\nexport default $`\n    const result = generateDefinition({ code })\n    expect(result).toMatchInlineSnapshot(`\n      {\n        \"entries\": [\n          {\n            \"name\": \"fitView\",\n            \"type\": \"(fitViewOptions?: { padding?: Padding; includeHiddenNodes?: boolean; minZoom?: number; maxZoom?: number; duration?: number; ease?: (t: number) => number; interpolate?: \"smooth\" | \"linear\"; nodes?: (NodeType | { id: string; })[]; }) => Promise<boolean>\",\n          },\n        ],\n        \"name\": \"$\",\n      }\n    `)\n  })\n\n  it.skip('should work with anonymous type', async () => {\n    const code = `\ntype $ = {\n  /**\n   * test\n   * @default null\n   */\n  foo: React.ReactNode\n}\nexport default $`\n    const result = generateDefinition({ code })\n    const result2 = generateDefinition({\n      code: code\n        .replace('export default $', '')\n        .replace('type $ =', 'export default')\n    })\n    expect(result).toMatchInlineSnapshot(`\n      [\n        {\n          \"entries\": [\n            {\n              \"description\": \"test\",\n              \"name\": \"foo\",\n              \"required\": true,\n              \"tags\": {\n                \"default\": \"null\",\n              },\n              \"type\": \"ReactNode\",\n            },\n          ],\n          \"name\": \"default\",\n        },\n      ]\n    `)\n    expect(result2).toEqual(result)\n  })\n})\n"
  },
  {
    "path": "packages/tsdoc/src/__tests__/fixtures/flattened.ts",
    "content": "import type { JSX, ReactElement, ReactNode } from 'react'\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\ninterface EmptyInterface {}\n\nclass Class {\n  foo = 123\n}\n\ntype $ = {\n  any: any\n  unknown: unknown\n  array: unknown[]\n  boolean: boolean\n  string: string\n  number: number\n  symbol: symbol\n  readonlyArray: readonly unknown[]\n  tuple: [unknown, unknown]\n  function: (a: unknown) => unknown\n  map: Map<unknown, unknown>\n  readonlyMap: ReadonlyMap<unknown, unknown>\n  set: Set<unknown>\n  readonlySet: ReadonlySet<unknown>\n  weakSet: WeakSet<any>\n  weakMap: WeakMap<any, unknown>\n  reactElement: ReactElement\n  reactNode: ReactNode\n  promise: Promise<unknown>\n  date: Date\n  regex: RegExp\n  jsx: JSX.Element\n  object: object\n  emptyObject: EmptyInterface\n  class: Class\n  ok: {\n    a: {\n      b: unknown\n    }\n  }\n}\n\nexport default $\n"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/flattened.json",
    "content": "{\n  \"entries\": [\n    {\n      \"name\": \"any\",\n      \"type\": \"any\",\n    },\n    {\n      \"name\": \"unknown\",\n      \"type\": \"unknown\",\n    },\n    {\n      \"name\": \"array\",\n      \"type\": \"unknown[]\",\n    },\n    {\n      \"name\": \"boolean\",\n      \"type\": \"boolean\",\n    },\n    {\n      \"name\": \"string\",\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"number\",\n      \"type\": \"number\",\n    },\n    {\n      \"name\": \"symbol\",\n      \"type\": \"symbol\",\n    },\n    {\n      \"name\": \"readonlyArray\",\n      \"type\": \"readonly unknown[]\",\n    },\n    {\n      \"name\": \"tuple\",\n      \"type\": \"[unknown, unknown]\",\n    },\n    {\n      \"name\": \"function\",\n      \"type\": \"(a: unknown) => unknown\",\n    },\n    {\n      \"name\": \"map\",\n      \"type\": \"Map<unknown, unknown>\",\n    },\n    {\n      \"name\": \"readonlyMap\",\n      \"type\": \"ReadonlyMap<unknown, unknown>\",\n    },\n    {\n      \"name\": \"set\",\n      \"type\": \"Set<unknown>\",\n    },\n    {\n      \"name\": \"readonlySet\",\n      \"type\": \"ReadonlySet<unknown>\",\n    },\n    {\n      \"name\": \"weakSet\",\n      \"type\": \"WeakSet<any>\",\n    },\n    {\n      \"name\": \"weakMap\",\n      \"type\": \"WeakMap<any, unknown>\",\n    },\n    {\n      \"name\": \"reactElement\",\n      \"type\": \"ReactElement<unknown, string | JSXElementConstructor<any>>\",\n    },\n    {\n      \"name\": \"reactNode\",\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"name\": \"promise\",\n      \"type\": \"Promise<unknown>\",\n    },\n    {\n      \"name\": \"date\",\n      \"type\": \"Date\",\n    },\n    {\n      \"name\": \"regex\",\n      \"type\": \"RegExp\",\n    },\n    {\n      \"name\": \"jsx\",\n      \"type\": \"Element\",\n    },\n    {\n      \"name\": \"object\",\n      \"type\": \"object\",\n    },\n    {\n      \"name\": \"emptyObject\",\n      \"type\": \"EmptyInterface\",\n    },\n    {\n      \"name\": \"class\",\n      \"type\": \"Class\",\n    },\n    {\n      \"name\": \"ok.a.b\",\n      \"type\": \"unknown\",\n    },\n  ],\n  \"name\": \"$\",\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/get-smooth-step-path.json",
    "content": "{\n  \"description\": \"The `getSmoothStepPath` util returns everything you need to render a stepped path\nbetween two nodes. The `borderRadius` property can be used to choose how rounded\nthe corners of those steps are.\",\n  \"name\": \"getSmoothStepPath\",\n  \"signatures\": [\n    {\n      \"params\": [\n        {\n          \"description\": \"The `x` position of the source handle.\",\n          \"name\": \"[0].sourceX\",\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"The `y` position of the source handle.\",\n          \"name\": \"[0].sourceY\",\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"The position of the source handle.\",\n          \"name\": \"[0].sourcePosition\",\n          \"optional\": true,\n          \"tags\": {\n            \"default\": \"Position.Bottom\",\n          },\n          \"type\": \"Position\",\n        },\n        {\n          \"description\": \"The `x` position of the target handle.\",\n          \"name\": \"[0].targetX\",\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"The `y` position of the target handle.\",\n          \"name\": \"[0].targetY\",\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"The position of the target handle.\",\n          \"name\": \"[0].targetPosition\",\n          \"optional\": true,\n          \"tags\": {\n            \"default\": \"Position.Top\",\n          },\n          \"type\": \"Position\",\n        },\n        {\n          \"name\": \"[0].borderRadius\",\n          \"optional\": true,\n          \"tags\": {\n            \"default\": \"5\",\n          },\n          \"type\": \"number\",\n        },\n        {\n          \"name\": \"[0].centerX\",\n          \"optional\": true,\n          \"type\": \"number\",\n        },\n        {\n          \"name\": \"[0].centerY\",\n          \"optional\": true,\n          \"type\": \"number\",\n        },\n        {\n          \"name\": \"[0].offset\",\n          \"optional\": true,\n          \"tags\": {\n            \"default\": \"20\",\n          },\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"Controls where the bend occurs along the path.\n0 = at source, 1 = at target, 0.5 = midpoint\",\n          \"name\": \"[0].stepPosition\",\n          \"optional\": true,\n          \"tags\": {\n            \"default\": \"0.5\",\n          },\n          \"type\": \"number\",\n        },\n      ],\n      \"returns\": {\n        \"type\": \"[path: string, labelX: number, labelY: number, offsetX: number, offsetY: number]\",\n      },\n    },\n  ],\n  \"tags\": {\n    \"example\": \"```js\n const source = { x: 0, y: 20 };\n const target = { x: 150, y: 100 };\n\n const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({\n   sourceX: source.x,\n   sourceY: source.y,\n   sourcePosition: Position.Right,\n   targetX: target.x,\n   targetY: target.y,\n   targetPosition: Position.Left,\n });\n```\",\n    \"public\": \"\",\n    \"remarks\": \"This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once.\",\n    \"returns\": \"A path string you can use in an SVG, the `labelX` and `labelY` position (center of path)\nand `offsetX`, `offsetY` between source handle and label.\n\n- `path`: the path to use in an SVG `<path>` element.\n- `labelX`: the `x` position you can use to render a label for this edge.\n- `labelY`: the `y` position you can use to render a label for this edge.\n- `offsetX`: the absolute difference between the source `x` position and the `x` position of the\nmiddle of this path.\n- `offsetY`: the absolute difference between the source `y` position and the `y` position of the\nmiddle of this path.\",\n  },\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/get-viewport-for-bounds.json",
    "content": "{\n  \"description\": \"Returns a viewport that encloses the given bounds with padding.\",\n  \"name\": \"getViewportForBounds\",\n  \"signatures\": [\n    {\n      \"params\": [\n        {\n          \"description\": \"Bounds to fit inside viewport.\",\n          \"name\": \"bounds\",\n          \"tags\": {\n            \"param\": \"bounds - Bounds to fit inside viewport.\",\n          },\n          \"type\": \"Rect\",\n        },\n        {\n          \"description\": \"Width of the viewport.\",\n          \"name\": \"width\",\n          \"tags\": {\n            \"param\": \"width - Width of the viewport.\",\n          },\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"Height of the viewport.\",\n          \"name\": \"height\",\n          \"tags\": {\n            \"param\": \"height - Height of the viewport.\",\n          },\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"Minimum zoom level of the resulting viewport.\",\n          \"name\": \"minZoom\",\n          \"tags\": {\n            \"param\": \"minZoom - Minimum zoom level of the resulting viewport.\",\n          },\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"Maximum zoom level of the resulting viewport.\",\n          \"name\": \"maxZoom\",\n          \"tags\": {\n            \"param\": \"maxZoom - Maximum zoom level of the resulting viewport.\",\n          },\n          \"type\": \"number\",\n        },\n        {\n          \"description\": \"Padding around the bounds.\",\n          \"name\": \"padding\",\n          \"tags\": {\n            \"param\": \"padding - Padding around the bounds.\",\n          },\n          \"type\": \"Padding\",\n        },\n      ],\n      \"returns\": [\n        {\n          \"name\": \"x\",\n          \"type\": \"number\",\n        },\n        {\n          \"name\": \"y\",\n          \"type\": \"number\",\n        },\n        {\n          \"name\": \"zoom\",\n          \"type\": \"number\",\n        },\n      ],\n    },\n  ],\n  \"tags\": {\n    \"example\": \"const { x, y, zoom } = getViewportForBounds(\n{ x: 0, y: 0, width: 100, height: 100},\n1200, 800, 0.5, 2);\",\n    \"param\": \"bounds - Bounds to fit inside viewport.\nwidth - Width of the viewport.\nheight - Height of the viewport.\nminZoom - Minimum zoom level of the resulting viewport.\nmaxZoom - Maximum zoom level of the resulting viewport.\npadding - Padding around the bounds.\",\n    \"public\": \"\",\n    \"remarks\": \"You can determine bounds of nodes with {@link getNodesBounds } and {@link getBoundsOfRects}\",\n    \"returns\": \"A transformed Viewport that encloses the given bounds which you can pass to e.g. setViewport .\",\n  },\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/head-props.ts",
    "content": "interface $$ {\n  /**\n   * @default {\n   *   \"hue\": {\n   *     \"dark\": 204,\n   *     \"light\": 212\n   *   },\n   *   \"saturation\": {\n   *     \"dark\": 100,\n   *     \"light\": 100\n   *   },\n   *   \"lightness\": {\n   *     \"dark\": 55,\n   *     \"light\": 45\n   *   }\n   * }\n   */\n  color?: {\n    /**\n     * The hue of the primary theme color.<br/>Range: `0 - 360`\n     * @default {\n     *   \"dark\": 204,\n     *   \"light\": 212\n     * }\n     */\n    hue?: number | {\n      dark: number\n\n      light: number\n    }\n\n    /**\n     * The saturation of the primary theme color.<br/>Range: `0 - 100`\n     * @default 100\n     */\n    saturation?: number | {\n      dark: number\n\n      light: number\n    }\n\n    /**\n     * The lightness of the primary theme color.<br/>Range: `0 - 100`\n     * @default {\n     *   \"dark\": 55,\n     *   \"light\": 45\n     * }\n     */\n    lightness?: number | {\n      dark: number\n\n      light: number\n    }\n  }\n\n  /**\n   * The glyph to use as the favicon.\n   */\n  faviconGlyph?: string\n\n  /**\n   * @default {\n   *   \"dark\": \"17,17,17\",\n   *   \"light\": \"250,250,250\"\n   * }\n   */\n  backgroundColor?: {\n    /**\n     * Background color for dark theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`\n     * @default \"rgb(17,17,17)\"\n     */\n    dark?: string\n\n    /**\n     * Background color for light theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`\n     * @default \"rgb(250,250,250)\"\n     */\n    light?: string\n  }\n\n  /**\n   * Content of `<head>`.\n   */\n  children?: React.ReactNode\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/head.json",
    "content": "{\n  \"entries\": [\n    {\n      \"description\": \"The hue of the primary theme color.<br/>Range: `0 - 360`\",\n      \"name\": \"color.hue\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"{\n\"dark\": 204,\n\"light\": 212\n}\",\n      },\n      \"type\": \"number | { dark: number; light: number; }\",\n    },\n    {\n      \"description\": \"The saturation of the primary theme color.<br/>Range: `0 - 100`\",\n      \"name\": \"color.saturation\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"100\",\n      },\n      \"type\": \"number | { dark: number; light: number; }\",\n    },\n    {\n      \"description\": \"The lightness of the primary theme color.<br/>Range: `0 - 100`\",\n      \"name\": \"color.lightness\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"{\n\"dark\": 55,\n\"light\": 45\n}\",\n      },\n      \"type\": \"number | { dark: number; light: number; }\",\n    },\n    {\n      \"description\": \"The glyph to use as the favicon.\",\n      \"name\": \"faviconGlyph\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Background color for dark theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`\",\n      \"name\": \"backgroundColor.dark\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"rgb(17,17,17)\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Background color for light theme.<br/>Format: `\"rgb(RRR,GGG,BBB)\" | \"#RRGGBB\"`\",\n      \"name\": \"backgroundColor.light\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"rgb(250,250,250)\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Content of `<head>`.\",\n      \"name\": \"children\",\n      \"optional\": true,\n      \"type\": \"React.ReactNode\",\n    },\n  ],\n  \"name\": \"$\",\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/layout-props.json",
    "content": "{\n  \"entries\": [\n    {\n      \"description\": \"Rendered [`<Banner>` component](/docs/built-ins/banner). E.g. `<Banner {...bannerProps} />`\",\n      \"name\": \"banner\",\n      \"optional\": true,\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"name\": \"children\",\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"Hide/show copy page content button.\",\n      \"name\": \"copyPageButton\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"Show or hide the dark mode select button.\",\n      \"name\": \"darkMode\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"URL of the documentation repository.\",\n      \"name\": \"docsRepositoryBase\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"https://github.com/shuding/nextra\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Content of the edit link.\",\n      \"name\": \"editLink\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"Edit this page\"\",\n      },\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"Content of the feedback link.\",\n      \"name\": \"feedback.content\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"Question? Give us feedback\"\",\n      },\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"Labels that can be added to the new created issue.\",\n      \"name\": \"feedback.labels\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"feedback\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Feedback link URL.\n\nBy default, it's a link to the issue creation form of the docs repository, with the current page title prefilled:\n[example](https://github.com/shuding/nextra/issues/new?title=Feedback%20for%20%E2%80%9CTheme%20Configuration%E2%80%9D&labels=feedback).\",\n      \"name\": \"feedback.link\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Rendered [`<Footer>` component](/docs/docs-theme/built-ins/footer). E.g. `<Footer {...footerProps} />`\",\n      \"name\": \"footer\",\n      \"optional\": true,\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"Options to configure the language dropdown for [the i18n docs website](/docs/guide/i18n).\",\n      \"name\": \"i18n\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"[]\",\n      },\n      \"type\": \"{ locale: string; name: string; }[]\",\n    },\n    {\n      \"description\": \"Component to render the last updated info.\",\n      \"name\": \"lastUpdated\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"<LastUpdated />\",\n      },\n      \"type\": \"React.ReactElement\",\n    },\n    {\n      \"description\": \"Rendered [`<Navbar>` component](/docs/docs-theme/built-ins/navbar). E.g. `<Navbar {...navbarProps} />`\",\n      \"name\": \"navbar\",\n      \"optional\": true,\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"Enable or disable navigation link.\",\n      \"name\": \"navigation\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean | { next: boolean; prev: boolean; }\",\n    },\n    {\n      \"name\": \"nextThemes.attribute\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"class\"\",\n      },\n      \"type\": \"\"class\" | `data-${string}` | (\"class\" | `data-${string}`)[]\",\n    },\n    {\n      \"name\": \"nextThemes.defaultTheme\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"system\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"nextThemes.disableTransitionOnChange\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"name\": \"nextThemes.forcedTheme\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"nextThemes.storageKey\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"theme\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Page map list. Result of `getPageMap(route = '/')` call.\",\n      \"name\": \"pageMap\",\n      \"type\": \"PageMapItem[]\",\n    },\n    {\n      \"description\": \"Rendered [`<Search>` component](/docs/built-ins/search). E.g. `<Search {...searchProps} />`\",\n      \"name\": \"search\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"<Search />\",\n      },\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"If `true`, automatically collapse inactive folders above `defaultMenuCollapseLevel`.\",\n      \"name\": \"sidebar.autoCollapse\",\n      \"optional\": true,\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"Specifies the folder level at which the menu on the left is collapsed by default.\",\n      \"name\": \"sidebar.defaultMenuCollapseLevel\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"2\",\n      },\n      \"type\": \"number\",\n    },\n    {\n      \"description\": \"Hide/show sidebar by default.\",\n      \"name\": \"sidebar.defaultOpen\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"Hide/show sidebar toggle button.\",\n      \"name\": \"sidebar.toggleButton\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"name\": \"themeSwitch.dark\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"Dark\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"themeSwitch.light\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"Light\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"themeSwitch.system\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"System\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Text of back to top button.\",\n      \"name\": \"toc.backToTop\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"Scroll to top\"\",\n      },\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"Display extra content below the TOC content.\",\n      \"name\": \"toc.extraContent\",\n      \"optional\": true,\n      \"type\": \"React.ReactNode\",\n    },\n    {\n      \"description\": \"Float the TOC next to the content.\",\n      \"name\": \"toc.float\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"Title of the TOC sidebar.\",\n      \"name\": \"toc.title\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"On This Page\"\",\n      },\n      \"type\": \"React.ReactNode\",\n    },\n  ],\n  \"name\": \"$\",\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/layout-props.ts",
    "content": "interface $ {\n  /**\n   * Rendered [`<Banner>` component](/docs/built-ins/banner). E.g. `<Banner {...bannerProps} />`\n   */\n  banner?: React.ReactNode\n\n  children: React.ReactNode\n\n  /**\n   * Hide/show copy page content button.\n   * @default true\n   */\n  copyPageButton?: boolean\n\n  /**\n   * Show or hide the dark mode select button.\n   * @default true\n   */\n  darkMode?: boolean\n\n  /**\n   * URL of the documentation repository.\n   * @default \"https://github.com/shuding/nextra\"\n   */\n  docsRepositoryBase?: string\n\n  /**\n   * Content of the edit link.\n   * @default \"Edit this page\"\n   */\n  editLink?: React.ReactNode\n\n  /**\n   * @default {\n   *   \"content\": \"Question? Give us feedback\",\n   *   \"labels\": \"feedback\"\n   * }\n   */\n  feedback?: {\n    /**\n     * Content of the feedback link.\n     * @default \"Question? Give us feedback\"\n     */\n    content?: React.ReactNode\n\n    /**\n     * Labels that can be added to the new created issue.\n     * @default \"feedback\"\n     */\n    labels?: string\n\n    /**\n     * Feedback link URL.\n     * \n     * By default, it's a link to the issue creation form of the docs repository, with the current page title prefilled:\n     * [example](https://github.com/shuding/nextra/issues/new?title=Feedback%20for%20%E2%80%9CTheme%20Configuration%E2%80%9D&labels=feedback).\n     */\n    link?: string\n  }\n\n  /**\n   * Rendered [`<Footer>` component](/docs/docs-theme/built-ins/footer). E.g. `<Footer {...footerProps} />`\n   */\n  footer?: React.ReactNode\n\n  /**\n   * Options to configure the language dropdown for [the i18n docs website](/docs/guide/i18n).\n   * @default []\n   */\n  i18n?: {\n    /**\n     * Locale from `i18n.locales` field in `next.config` file.\n     */\n    locale: string\n\n    /**\n     * Locale name in dropdown.\n     */\n    name: string\n  }[]\n\n  /**\n   * Component to render the last updated info.\n   * @default <LastUpdated />\n   */\n  lastUpdated?: React.ReactElement\n\n  /**\n   * Rendered [`<Navbar>` component](/docs/docs-theme/built-ins/navbar). E.g. `<Navbar {...navbarProps} />`\n   */\n  navbar?: React.ReactNode\n\n  /**\n   * Enable or disable navigation link.\n   * @default true\n   */\n  navigation?: boolean | {\n    next: boolean\n\n    prev: boolean\n  }\n\n  /**\n   * Configuration for the [next-themes](https://github.com/pacocoursey/next-themes#themeprovider) package.\n   * @default {\n   *   \"attribute\": \"class\",\n   *   \"defaultTheme\": \"system\",\n   *   \"disableTransitionOnChange\": true,\n   *   \"storageKey\": \"theme\"\n   * }\n   */\n  nextThemes?: {\n    /**\n     * @default \"class\"\n     */\n    attribute?: 'class' | `data-${string}` | ('class' | `data-${string}`)[]\n\n    /**\n     * @default \"system\"\n     */\n    defaultTheme?: string\n\n    /**\n     * @default true\n     */\n    disableTransitionOnChange?: boolean\n\n    forcedTheme?: string\n\n    /**\n     * @default \"theme\"\n     */\n    storageKey?: string\n  }\n\n  /**\n   * Page map list. Result of `getPageMap(route = '/')` call.\n   */\n  pageMap: import(\"nextra\").PageMapItem[]\n\n  /**\n   * Rendered [`<Search>` component](/docs/built-ins/search). E.g. `<Search {...searchProps} />`\n   * @default <Search />\n   */\n  search?: React.ReactNode\n\n  /**\n   * @default {\n   *   \"defaultMenuCollapseLevel\": 2,\n   *   \"defaultOpen\": true,\n   *   \"toggleButton\": true\n   * }\n   */\n  sidebar?: {\n    /**\n     * If `true`, automatically collapse inactive folders above `defaultMenuCollapseLevel`.\n     */\n    autoCollapse?: boolean\n\n    /**\n     * Specifies the folder level at which the menu on the left is collapsed by default.\n     * @default 2\n     */\n    defaultMenuCollapseLevel?: number\n\n    /**\n     * Hide/show sidebar by default.\n     * @default true\n     */\n    defaultOpen?: boolean\n\n    /**\n     * Hide/show sidebar toggle button.\n     * @default true\n     */\n    toggleButton?: boolean\n  }\n\n  /**\n   * Translation of options in the theme switch.\n   * @default {\n   *   \"dark\": \"Dark\",\n   *   \"light\": \"Light\",\n   *   \"system\": \"System\"\n   * }\n   */\n  themeSwitch?: {\n    /**\n     * @default \"Dark\"\n     */\n    dark?: string\n\n    /**\n     * @default \"Light\"\n     */\n    light?: string\n\n    /**\n     * @default \"System\"\n     */\n    system?: string\n  }\n\n  /**\n   * @default {\n   *   \"backToTop\": \"Scroll to top\",\n   *   \"float\": true,\n   *   \"title\": \"On This Page\"\n   * }\n   */\n  toc?: {\n    /**\n     * Text of back to top button.\n     * @default \"Scroll to top\"\n     */\n    backToTop?: React.ReactNode\n\n    /**\n     * Display extra content below the TOC content.\n     */\n    extraContent?: React.ReactNode\n\n    /**\n     * Float the TOC next to the content.\n     * @default true\n     */\n    float?: boolean\n\n    /**\n     * Title of the TOC sidebar.\n     * @default \"On This Page\"\n     */\n    title?: React.ReactNode\n  }\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/navbar.json",
    "content": "{\n  \"entries\": [\n    {\n      \"description\": \"Extra content after the last icon.\",\n      \"name\": \"children\",\n      \"optional\": true,\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"description\": \"Specifies whether the logo should have a link or provides the URL for the logo's link.\",\n      \"name\": \"logoLink\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"string | boolean\",\n    },\n    {\n      \"description\": \"Logo of the website.\",\n      \"name\": \"logo\",\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"description\": \"URL of the project homepage.\",\n      \"name\": \"projectLink\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Icon of the project link.\",\n      \"name\": \"projectIcon\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"<GitHubIcon />\",\n      },\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"description\": \"URL of the chat link.\",\n      \"name\": \"chatLink\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Icon of the chat link.\",\n      \"name\": \"chatIcon\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"<DiscordIcon />\",\n      },\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"description\": \"CSS class name.\",\n      \"name\": \"className\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Aligns navigation links to the specified side.\",\n      \"name\": \"align\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"'right'\",\n      },\n      \"type\": \"\"left\" | \"right\"\",\n    },\n  ],\n  \"name\": \"$\",\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/nextra-config.json",
    "content": "{\n  \"entries\": [\n    {\n      \"description\": \"Enable the copy button for all code blocks by default, without needing to set `copy=true` attribute in the code block metadata.\n> [!TIP]\n>\n> You could still disable the button for specific blocks using `copy=false` attribute.\",\n      \"name\": \"defaultShowCopyCode\",\n      \"optional\": true,\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"Option to enable search functionality. When enabled, it sets the `data-pagefind-body` attribute on the `<main>` element.\n> [!TIP]\n>\n> When set to `codeblocks: false`, it adds the `data-pagefind-ignore=\"all\"` attribute to all code blocks (`<pre>` elements).\",\n      \"name\": \"search\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"{\n\"codeblocks\": false\n}\",\n      },\n      \"type\": \"boolean | { codeblocks: boolean; }\",\n    },\n    {\n      \"description\": \"Option to automatically optimizing your static image imports with the Markdown syntax.\n> [!TIP]\n>\n> Example: `![Hello](/demo.png)`.\",\n      \"name\": \"staticImage\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"Adds estimated reading time of `.md` and `.mdx` files using [readingTime](https://npmjs.com/package/reading-time) package.\n> [!TIP]\n>\n> The reading time is added to the front matter under the `readingTime` key.\",\n      \"name\": \"readingTime\",\n      \"optional\": true,\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"Enable LaTeX either with [KaTeX](https://katex.org) to pre-render LaTeX expressions directly in MDX or [MathJax](https://mathjax.org) to dynamically render math in the browser.\",\n      \"name\": \"latex\",\n      \"optional\": true,\n      \"type\": \"boolean | { renderer: \"mathjax\"; options?: { src?: string; config?: any; }; } | { renderer: \"katex\"; options: any; }\",\n    },\n    {\n      \"description\": \"Enable or disable syntax highlighting.\",\n      \"name\": \"codeHighlight\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"true\",\n      },\n      \"type\": \"boolean\",\n    },\n    {\n      \"description\": \"List of rehype plugins.\",\n      \"name\": \"mdxOptions.rehypePlugins\",\n      \"optional\": true,\n      \"type\": \"any\",\n    },\n    {\n      \"description\": \"List of remark plugins.\",\n      \"name\": \"mdxOptions.remarkPlugins\",\n      \"optional\": true,\n      \"type\": \"any\",\n    },\n    {\n      \"description\": \"List of recma plugins. This is a new ecosystem, currently in beta, to transform esast trees (JavaScript).\",\n      \"name\": \"mdxOptions.recmaPlugins\",\n      \"optional\": true,\n      \"type\": \"any\",\n    },\n    {\n      \"description\": \"Format of the file.\n- `'md'` means treat as markdown\n- `'mdx'` means treat as MDX\n- `'detect'` means try to detect the format based on file path.\",\n      \"name\": \"mdxOptions.format\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"detect\"\",\n      },\n      \"type\": \"\"detect\" | \"mdx\" | \"md\"\",\n    },\n    {\n      \"description\": \"Configuration options for [Rehype Pretty Code](https://github.com/rehype-pretty/rehype-pretty-code).\",\n      \"name\": \"mdxOptions.rehypePrettyCodeOptions\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"{}\",\n        \"remarks\": \"`RehypePrettyCodeOptions`\",\n      },\n      \"type\": \"RehypePrettyCodeOptions\",\n    },\n    {\n      \"description\": \"Allows you to whitelist HTML elements to be replaced with components defined in the `mdx-components.js` file.\n> [!TIP]\n>\n> By default, Nextra only replaces `<details>` and `<summary>` elements.\",\n      \"name\": \"whiteListTagsStyling\",\n      \"optional\": true,\n      \"type\": \"string[]\",\n    },\n    {\n      \"description\": \"Option to serve your `.md` and `.mdx` files from the `content` directory at a custom path instead of the root (`/`).\",\n      \"name\": \"contentDirBasePath\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"\"/\"\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Prefixes locale to all links in the page map information. Useful for i18n when you don't want to use Nextra's `middleware` function.\",\n      \"name\": \"unstable_shouldAddLocaleToLinks\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"false\",\n      },\n      \"type\": \"boolean\",\n    },\n  ],\n  \"name\": \"$\",\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/react-flow-instance.json",
    "content": "{\n  \"description\": \"The `ReactFlowInstance` provides a collection of methods to query and manipulate\nthe internal state of your flow. You can get an instance by using the\n[`useReactFlow`](/api-reference/hooks/use-react-flow) hook or attaching a listener\nto the [`onInit`](/api-reference/react-flow#event-oninit) event.\",\n  \"entries\": [\n    {\n      \"description\": \"Returns nodes.\",\n      \"name\": \"getNodes\",\n      \"tags\": {\n        \"returns\": \"nodes array\",\n      },\n      \"type\": \"() => NodeType[]\",\n    },\n    {\n      \"description\": \"Set your nodes array to something else by either overwriting it with a new array or by passing\nin a function to update the existing array. If using a function, it is important to make sure a\nnew array is returned instead of mutating the existing array. Calling this function will\ntrigger the `onNodesChange` handler in a controlled flow.\",\n      \"name\": \"setNodes\",\n      \"tags\": {\n        \"param\": \"payload - the nodes to set or a function that receives the current nodes and returns the new nodes\",\n      },\n      \"type\": \"(payload: NodeType[] | ((nodes: NodeType[]) => NodeType[])) => void\",\n    },\n    {\n      \"description\": \"Add one or many nodes to your existing nodes array. Calling this function will trigger the\n`onNodesChange` handler in a controlled flow.\",\n      \"name\": \"addNodes\",\n      \"tags\": {\n        \"param\": \"payload - the nodes to add\",\n      },\n      \"type\": \"(payload: NodeType | NodeType[]) => void\",\n    },\n    {\n      \"description\": \"Returns a node by id.\",\n      \"name\": \"getNode\",\n      \"tags\": {\n        \"param\": \"id - the node id\",\n        \"returns\": \"the node or undefined if no node was found\",\n      },\n      \"type\": \"(id: string) => NodeType | undefined\",\n    },\n    {\n      \"description\": \"Returns an internal node by id.\",\n      \"name\": \"getInternalNode\",\n      \"tags\": {\n        \"param\": \"id - the node id\",\n        \"returns\": \"the internal node or undefined if no node was found\",\n      },\n      \"type\": \"(id: string) => InternalNode<NodeType> | undefined\",\n    },\n    {\n      \"description\": \"Returns edges.\",\n      \"name\": \"getEdges\",\n      \"tags\": {\n        \"returns\": \"edges array\",\n      },\n      \"type\": \"() => EdgeType[]\",\n    },\n    {\n      \"description\": \"Set your edges array to something else by either overwriting it with a new array or by passing\nin a function to update the existing array. If using a function, it is important to make sure a\nnew array is returned instead of mutating the existing array. Calling this function will\ntrigger the `onEdgesChange` handler in a controlled flow.\",\n      \"name\": \"setEdges\",\n      \"tags\": {\n        \"param\": \"payload - the edges to set or a function that receives the current edges and returns the new edges\",\n      },\n      \"type\": \"(payload: EdgeType[] | ((edges: EdgeType[]) => EdgeType[])) => void\",\n    },\n    {\n      \"description\": \"Add one or many edges to your existing edges array. Calling this function will trigger the\n`onEdgesChange` handler in a controlled flow.\",\n      \"name\": \"addEdges\",\n      \"tags\": {\n        \"param\": \"payload - the edges to add\",\n      },\n      \"type\": \"(payload: EdgeType | EdgeType[]) => void\",\n    },\n    {\n      \"description\": \"Returns an edge by id.\",\n      \"name\": \"getEdge\",\n      \"tags\": {\n        \"param\": \"id - the edge id\",\n        \"returns\": \"the edge or undefined if no edge was found\",\n      },\n      \"type\": \"(id: string) => EdgeType | undefined\",\n    },\n    {\n      \"description\": \"Returns the nodes, edges and the viewport as a JSON object.\",\n      \"name\": \"toObject\",\n      \"tags\": {\n        \"returns\": \"the nodes, edges and the viewport as a JSON object\",\n      },\n      \"type\": \"() => ReactFlowJsonObject<NodeType, EdgeType>\",\n    },\n    {\n      \"description\": \"Deletes nodes and edges.\",\n      \"name\": \"deleteElements\",\n      \"tags\": {\n        \"param\": \"params.nodes - optional nodes array to delete\nparams.edges - optional edges array to delete\",\n        \"returns\": \"a promise that resolves with the deleted nodes and edges\",\n      },\n      \"type\": \"(params: DeleteElementsOptions) => Promise<{ deletedNodes: Node[]; deletedEdges: Edge[]; }>\",\n    },\n    {\n      \"description\": \"Find all the nodes currently intersecting with a given node or rectangle. The `partially`\nparameter can be set to `true` to include nodes that are only partially intersecting.\",\n      \"name\": \"getIntersectingNodes\",\n      \"tags\": {\n        \"param\": \"node - the node or rect to check for intersections\npartially - true by default, if set to false, only nodes that are fully intersecting will be returned\nnodes - optional nodes array to check for intersections\",\n        \"returns\": \"an array of intersecting nodes\",\n      },\n      \"type\": \"(node: NodeType | Rect | { id: string; }, partially?: boolean | undefined, nodes?: NodeType[] | undefined) => NodeType[]\",\n    },\n    {\n      \"description\": \"Determine if a given node or rectangle is intersecting with another rectangle. The `partially`\nparameter can be set to true return `true` even if the node is only partially intersecting.\",\n      \"name\": \"isNodeIntersecting\",\n      \"tags\": {\n        \"param\": \"node - the node or rect to check for intersections\narea - the rect to check for intersections\npartially - if true, the node is considered to be intersecting if it partially overlaps with the passed react\",\n        \"returns\": \"true if the node or rect intersects with the given area\",\n      },\n      \"type\": \"(node: NodeType | Rect | { id: string; }, area: Rect, partially?: boolean | undefined) => boolean\",\n    },\n    {\n      \"description\": \"Updates a node.\",\n      \"name\": \"updateNode\",\n      \"tags\": {\n        \"example\": \"updateNode('node-1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }));\",\n        \"param\": \"id - id of the node to update\nnodeUpdate - the node update as an object or a function that receives the current node and returns the node update\noptions.replace - if true, the node is replaced with the node update, otherwise the changes get merged\",\n      },\n      \"type\": \"(id: string, nodeUpdate: Partial<NodeType> | ((node: NodeType) => Partial<NodeType>), options?: { replace: boolean; } | undefined) => void\",\n    },\n    {\n      \"description\": \"Updates the data attribute of a node.\",\n      \"name\": \"updateNodeData\",\n      \"tags\": {\n        \"example\": \"updateNodeData('node-1', { label: 'A new label' });\",\n        \"param\": \"id - id of the node to update\ndataUpdate - the data update as an object or a function that receives the current data and returns the data update\noptions.replace - if true, the data is replaced with the data update, otherwise the changes get merged\",\n      },\n      \"type\": \"(id: string, dataUpdate: Partial<NodeType[\"data\"]> | ((node: NodeType) => Partial<NodeType[\"data\"]>), options?: { replace: boolean; } | undefined) => void\",\n    },\n    {\n      \"description\": \"Updates an edge.\",\n      \"name\": \"updateEdge\",\n      \"tags\": {\n        \"example\": \"updateEdge('edge-1', (edge) => ({ label: 'A new label' }));\",\n        \"param\": \"id - id of the edge to update\nedgeUpdate - the edge update as an object or a function that receives the current edge and returns the edge update\noptions.replace - if true, the edge is replaced with the edge update, otherwise the changes get merged\",\n      },\n      \"type\": \"(id: string, edgeUpdate: Partial<EdgeType> | ((edge: EdgeType) => Partial<EdgeType>), options?: { replace: boolean; } | undefined) => void\",\n    },\n    {\n      \"description\": \"Updates the data attribute of a edge.\",\n      \"name\": \"updateEdgeData\",\n      \"tags\": {\n        \"example\": \"updateEdgeData('edge-1', { label: 'A new label' });\",\n        \"param\": \"id - id of the edge to update\ndataUpdate - the data update as an object or a function that receives the current data and returns the data update\noptions.replace - if true, the data is replaced with the data update, otherwise the changes get merged\",\n      },\n      \"type\": \"(id: string, dataUpdate: Partial<EdgeType[\"data\"]> | ((edge: EdgeType) => Partial<EdgeType[\"data\"]>), options?: { replace: boolean; } | undefined) => void\",\n    },\n    {\n      \"description\": \"Returns the bounds of the given nodes or node ids.\",\n      \"name\": \"getNodesBounds\",\n      \"tags\": {\n        \"param\": \"nodes - the nodes or node ids to calculate the bounds for\",\n        \"returns\": \"the bounds of the given nodes\",\n      },\n      \"type\": \"(nodes: (string | NodeType | InternalNode)[]) => Rect\",\n    },\n    {\n      \"description\": \"Get all the connections of a handle belonging to a specific node. The type parameter be either\n`'source'` or `'target'`.\",\n      \"name\": \"getHandleConnections\",\n      \"tags\": {\n        \"deprecated\": \"\",\n        \"param\": \"type - handle type 'source' or 'target'\nid - the handle id (this is only needed if you have multiple handles of the same type, meaning you have to provide a unique id for each handle)\nnodeId - the node id the handle belongs to\",\n        \"returns\": \"an array with handle connections\",\n      },\n      \"type\": \"({ type, id, nodeId, }: { type: HandleType; nodeId: string; id?: string | null; }) => HandleConnection[]\",\n    },\n    {\n      \"description\": \"Gets all connections to a node. Can be filtered by handle type and id.\",\n      \"name\": \"getNodeConnections\",\n      \"tags\": {\n        \"param\": \"type - handle type 'source' or 'target'\nhandleId - the handle id (this is only needed if you have multiple handles of the same type, meaning you have to provide a unique id for each handle)\nnodeId - the node id the handle belongs to\",\n        \"returns\": \"an array with handle connections\",\n      },\n      \"type\": \"({ type, handleId, nodeId, }: { type?: HandleType; nodeId: string; handleId?: string | null; }) => NodeConnection[]\",\n    },\n    {\n      \"name\": \"fitView\",\n      \"type\": \"(fitViewOptions?: { padding?: Padding; includeHiddenNodes?: boolean; minZoom?: number; maxZoom?: number; duration?: number; ease?: (t: number) => number; interpolate?: \"smooth\" | \"linear\"; nodes?: (NodeType | { id: string; })[]; }) => Promise<boolean>\",\n    },\n    {\n      \"description\": \"Zooms viewport in by 1.2.\",\n      \"name\": \"zoomIn\",\n      \"tags\": {\n        \"param\": \"options.duration - optional duration. If set, a transition will be applied\",\n      },\n      \"type\": \"(options?: { duration?: number; ease?: (t: number) => number; interpolate?: \"smooth\" | \"linear\"; }) => Promise<boolean>\",\n    },\n    {\n      \"description\": \"Zooms viewport out by 1 / 1.2.\",\n      \"name\": \"zoomOut\",\n      \"tags\": {\n        \"param\": \"options.duration - optional duration. If set, a transition will be applied\",\n      },\n      \"type\": \"(options?: { duration?: number; ease?: (t: number) => number; interpolate?: \"smooth\" | \"linear\"; }) => Promise<boolean>\",\n    },\n    {\n      \"description\": \"Zoom the viewport to a given zoom level. Passing in a `duration` will animate the viewport to\nthe new zoom level.\",\n      \"name\": \"zoomTo\",\n      \"tags\": {\n        \"param\": \"zoomLevel - the zoom level to set\noptions.duration - optional duration. If set, a transition will be applied\",\n      },\n      \"type\": \"(zoomLevel: number, options?: { duration?: number; ease?: (t: number) => number; interpolate?: \"smooth\" | \"linear\"; }) => Promise<boolean>\",\n    },\n    {\n      \"description\": \"Get the current zoom level of the viewport.\",\n      \"name\": \"getZoom\",\n      \"tags\": {\n        \"returns\": \"current zoom as a number\",\n      },\n      \"type\": \"() => number\",\n    },\n    {\n      \"description\": \"Sets the current viewport.\",\n      \"name\": \"setViewport\",\n      \"tags\": {\n        \"param\": \"viewport - the viewport to set\noptions.duration - optional duration. If set, a transition will be applied\noptions.ease - optional ease function.\",\n      },\n      \"type\": \"(viewport: Viewport, options?: { duration?: number; ease?: (t: number) => number; interpolate?: \"smooth\" | \"linear\"; }) => Promise<boolean>\",\n    },\n    {\n      \"description\": \"Returns the current viewport.\",\n      \"name\": \"getViewport\",\n      \"tags\": {\n        \"returns\": \"Viewport\",\n      },\n      \"type\": \"() => Viewport\",\n    },\n    {\n      \"description\": \"Center the viewport on a given position. Passing in a `duration` will animate the viewport to\nthe new position.\",\n      \"name\": \"setCenter\",\n      \"tags\": {\n        \"param\": \"x - x position\ny - y position\noptions.zoom - optional zoom\noptions.duration - optional duration. If set, a transition will be applied\noptions.ease - optional ease function.\",\n      },\n      \"type\": \"(x: number, y: number, options?: ViewportHelperFunctionOptions & { zoom?: number; }) => Promise<boolean>\",\n    },\n    {\n      \"description\": \"A low-level utility function to fit the viewport to a given rectangle. By passing in a\n`duration`, the viewport will animate from its current position to the new position. The\n`padding` option can be used to add space around the bounds.\",\n      \"name\": \"fitBounds\",\n      \"tags\": {\n        \"param\": \"bounds - the bounds ({ x: number, y: number, width: number, height: number }) to fit the view to\noptions.padding - optional padding\noptions.duration - optional duration. If set, a transition will be applied\noptions.ease - optional ease function.\",\n      },\n      \"type\": \"(bounds: Rect, options?: ViewportHelperFunctionOptions & { padding?: number; }) => Promise<boolean>\",\n    },\n    {\n      \"description\": \"With this function you can translate a screen pixel position to a flow position. It is useful\nfor implementing drag and drop from a sidebar for example.\",\n      \"name\": \"screenToFlowPosition\",\n      \"tags\": {\n        \"example\": \"const flowPosition = screenToFlowPosition({ x: event.clientX, y: event.clientY })\",\n        \"param\": \"clientPosition - the screen / client position. When you are working with events you can use event.clientX and event.clientY\noptions.snapToGrid - if true, the converted position will be snapped to the grid\",\n        \"returns\": \"position as { x: number, y: number }\",\n      },\n      \"type\": \"(clientPosition: XYPosition, options?: { snapToGrid: boolean; } | undefined) => XYPosition\",\n    },\n    {\n      \"description\": \"Translate a position inside the flow's canvas to a screen pixel position.\",\n      \"name\": \"flowToScreenPosition\",\n      \"tags\": {\n        \"example\": \"const clientPosition = flowToScreenPosition({ x: node.position.x, y: node.position.y })\",\n        \"param\": \"flowPosition - the screen / client position. When you are working with events you can use event.clientX and event.clientY\",\n        \"returns\": \"position as { x: number, y: number }\",\n      },\n      \"type\": \"(flowPosition: XYPosition) => XYPosition\",\n    },\n    {\n      \"description\": \"React Flow needs to mount the viewport to the DOM and initialize its zoom and pan behavior.\nThis property tells you when viewport is initialized.\",\n      \"name\": \"viewportInitialized\",\n      \"type\": \"boolean\",\n    },\n  ],\n  \"name\": \"ReactFlowInstance\",\n  \"tags\": {\n    \"public\": \"\",\n  },\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/search.json",
    "content": "{\n  \"entries\": [\n    {\n      \"description\": \"Not found text.\",\n      \"name\": \"emptyResult\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"'No results found.'\",\n      },\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"description\": \"Error text.\",\n      \"name\": \"errorText\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"'Failed to load search index.'\",\n      },\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"description\": \"Loading text.\",\n      \"name\": \"loading\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"'Loading…'\",\n      },\n      \"type\": \"ReactNode\",\n    },\n    {\n      \"description\": \"Placeholder text.\",\n      \"name\": \"placeholder\",\n      \"optional\": true,\n      \"tags\": {\n        \"default\": \"'Search documentation…'\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Input container CSS class name.\",\n      \"name\": \"className\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"searchOptions\",\n      \"optional\": true,\n      \"type\": \"PagefindSearchOptions\",\n    },\n    {\n      \"description\": \"Callback function that triggers whenever the search input changes.\n\nThis prop is **not serializable** and cannot be used directly in a server-side layout.\n\nTo use this prop, wrap the component in a **client-side** wrapper. Example:\n\n```tsx filename=\"search-with-callback.jsx\"\n'use client'\n\nimport { Search } from 'nextra/components'\n\nexport function SearchWithCallback() {\n  return (\n    <Search\n      onSearch={query => {\n        console.log('Search query:', query)\n      }}\n    />\n  )\n}\n```\n\nThen pass the wrapper to the layout:\n\n```tsx filename=\"app/layout.jsx\"\nimport { SearchWithCallback } from '../path/to/your/search-with-callback'\n// ...\n<Layout search={<SearchWithCallback />} {...rest} />\n```\",\n      \"name\": \"onSearch\",\n      \"optional\": true,\n      \"tags\": {\n        \"param\": \"query - The current search input string.\",\n      },\n      \"type\": \"(query: string) => void\",\n    },\n    {\n      \"name\": \"form\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"slot\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"style\",\n      \"optional\": true,\n      \"type\": \"CSSProperties | undefined\",\n    },\n    {\n      \"name\": \"title\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"pattern\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"as\",\n      \"optional\": true,\n      \"type\": \"\"input\"\",\n    },\n    {\n      \"name\": \"children\",\n      \"optional\": true,\n      \"type\": \"ReactNode | ((bag: InputRenderPropArg) => ReactElement<unknown, string | JSXElementConstructor<any>>)\",\n    },\n    {\n      \"name\": \"refName\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"disabled\",\n      \"optional\": true,\n      \"type\": \"boolean\",\n    },\n    {\n      \"name\": \"defaultValue\",\n      \"optional\": true,\n      \"type\": \"string\",\n    },\n    {\n      \"name\": \"displayValue\",\n      \"optional\": true,\n      \"type\": \"(item: string) => string\",\n    },\n    {\n      \"name\": \"autoFocus\",\n      \"optional\": true,\n      \"type\": \"boolean\",\n    },\n    {\n      \"name\": \"key\",\n      \"optional\": true,\n      \"type\": \"Key | null | undefined\",\n    },\n    {\n      \"name\": \"accept\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"alt\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"autoComplete\",\n      \"optional\": true,\n      \"type\": \"HTMLInputAutoCompleteAttribute | undefined\",\n    },\n    {\n      \"name\": \"capture\",\n      \"optional\": true,\n      \"type\": \"boolean | \"user\" | \"environment\" | undefined\",\n    },\n    {\n      \"name\": \"checked\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"formAction\",\n      \"optional\": true,\n      \"type\": \"string | ((formData: FormData) => void | Promise<void>) | undefined\",\n    },\n    {\n      \"name\": \"formEncType\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"formMethod\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"formNoValidate\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"formTarget\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"height\",\n      \"optional\": true,\n      \"type\": \"string | number | undefined\",\n    },\n    {\n      \"name\": \"list\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"max\",\n      \"optional\": true,\n      \"type\": \"string | number | undefined\",\n    },\n    {\n      \"name\": \"maxLength\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"name\": \"min\",\n      \"optional\": true,\n      \"type\": \"string | number | undefined\",\n    },\n    {\n      \"name\": \"minLength\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"name\": \"multiple\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"name\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"readOnly\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"required\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"size\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"name\": \"src\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"step\",\n      \"optional\": true,\n      \"type\": \"string | number | undefined\",\n    },\n    {\n      \"name\": \"type\",\n      \"optional\": true,\n      \"type\": \"HTMLInputTypeAttribute | undefined\",\n    },\n    {\n      \"name\": \"width\",\n      \"optional\": true,\n      \"type\": \"string | number | undefined\",\n    },\n    {\n      \"name\": \"defaultChecked\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"suppressContentEditableWarning\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"suppressHydrationWarning\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"accessKey\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"autoCapitalize\",\n      \"optional\": true,\n      \"type\": \"\"off\" | \"on\" | (string & {}) | \"none\" | \"sentences\" | \"words\" | \"characters\" | undefined\",\n    },\n    {\n      \"name\": \"contentEditable\",\n      \"optional\": true,\n      \"type\": \"Booleanish | \"inherit\" | \"plaintext-only\" | undefined\",\n    },\n    {\n      \"name\": \"contextMenu\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"dir\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"draggable\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"name\": \"enterKeyHint\",\n      \"optional\": true,\n      \"type\": \"\"search\" | \"enter\" | \"done\" | \"go\" | \"next\" | \"previous\" | \"send\" | undefined\",\n    },\n    {\n      \"name\": \"hidden\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"id\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"lang\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"nonce\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"spellCheck\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"name\": \"tabIndex\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"name\": \"translate\",\n      \"optional\": true,\n      \"type\": \"\"yes\" | \"no\" | undefined\",\n    },\n    {\n      \"name\": \"radioGroup\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"about\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"content\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"datatype\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"inlist\",\n      \"optional\": true,\n      \"type\": \"any\",\n    },\n    {\n      \"name\": \"prefix\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"property\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"rel\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"resource\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"rev\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"typeof\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"vocab\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"autoCorrect\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"autoSave\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"color\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"itemProp\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"itemScope\",\n      \"optional\": true,\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"name\": \"itemType\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"itemID\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"itemRef\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"results\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"name\": \"security\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"unselectable\",\n      \"optional\": true,\n      \"type\": \"\"off\" | \"on\" | undefined\",\n    },\n    {\n      \"name\": \"popover\",\n      \"optional\": true,\n      \"type\": \"\"\" | \"auto\" | \"manual\" | undefined\",\n    },\n    {\n      \"name\": \"popoverTargetAction\",\n      \"optional\": true,\n      \"type\": \"\"toggle\" | \"show\" | \"hide\" | undefined\",\n    },\n    {\n      \"name\": \"popoverTarget\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"inert\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/inert\",\n      },\n      \"type\": \"boolean | undefined\",\n    },\n    {\n      \"description\": \"Hints at the type of data that might be entered by the user while editing the element or its contents\",\n      \"name\": \"inputMode\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"{@link https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-inputmode-attribute}\",\n      },\n      \"type\": \"\"search\" | \"text\" | \"email\" | \"tel\" | \"url\" | \"none\" | \"numeric\" | \"decimal\" | undefined\",\n    },\n    {\n      \"description\": \"Specify that a standard HTML element should behave like a defined custom built-in element\",\n      \"name\": \"is\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"{@link https://html.spec.whatwg.org/multipage/custom-elements.html#attr-is}\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"exportparts\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"{@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/exportparts}\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"part\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"{@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/part}\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Specify styles using Tailwind CSS classes. This feature is currently experimental.\nIf `style` prop is also specified, styles generated with `tw` prop will be overridden.\n\nExample:\n- `tw='w-full h-full bg-blue-200'`\n- `tw='text-9xl'`\n- `tw='text-[80px]'`\",\n      \"name\": \"tw\",\n      \"optional\": true,\n      \"tags\": {\n        \"type\": \"{string}\",\n      },\n      \"type\": \"string\",\n    },\n    {\n      \"description\": \"Indicates whether assistive technologies will present all, or only parts of, the changed region based on the change notifications defined by the aria-relevant attribute.\",\n      \"name\": \"aria-atomic\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Defines a string value that labels the current element, which is intended to be converted into Braille.\",\n      \"name\": \"aria-braillelabel\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-label.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines a human-readable, author-localized abbreviated description for the role of an element, which is intended to be converted into Braille.\",\n      \"name\": \"aria-brailleroledescription\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-roledescription.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"aria-busy\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates the current \"checked\" state of checkboxes, radio buttons, and other widgets.\",\n      \"name\": \"aria-checked\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-pressed\naria-selected.\",\n      },\n      \"type\": \"boolean | \"true\" | \"false\" | \"mixed\" | undefined\",\n    },\n    {\n      \"description\": \"Defines the total number of columns in a table, grid, or treegrid.\",\n      \"name\": \"aria-colcount\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-colindex.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Defines an element's column index or position with respect to the total number of columns within a table, grid, or treegrid.\",\n      \"name\": \"aria-colindex\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-colcount\naria-colspan.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Defines a human readable text alternative of aria-colindex.\",\n      \"name\": \"aria-colindextext\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-rowindextext.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines the number of columns spanned by a cell or gridcell within a table, grid, or treegrid.\",\n      \"name\": \"aria-colspan\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-colindex\naria-rowspan.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Indicates the element that represents the current item within a container or set of related elements.\",\n      \"name\": \"aria-current\",\n      \"optional\": true,\n      \"type\": \"boolean | \"time\" | \"step\" | \"date\" | \"true\" | \"false\" | \"page\" | \"location\" | undefined\",\n    },\n    {\n      \"description\": \"Identifies the element (or elements) that describes the object.\",\n      \"name\": \"aria-describedby\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-labelledby\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines a string value that describes or annotates the current element.\",\n      \"name\": \"aria-description\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"related aria-describedby.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Identifies the element that provides a detailed, extended description for the object.\",\n      \"name\": \"aria-details\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-describedby.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable.\",\n      \"name\": \"aria-disabled\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-hidden\naria-readonly.\",\n      },\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates what functions can be performed when a dragged object is released on the drop target.\",\n      \"name\": \"aria-dropeffect\",\n      \"optional\": true,\n      \"tags\": {\n        \"deprecated\": \"in ARIA 1.1\",\n      },\n      \"type\": \"\"link\" | \"none\" | \"copy\" | \"execute\" | \"move\" | \"popup\" | undefined\",\n    },\n    {\n      \"description\": \"Identifies the element that provides an error message for the object.\",\n      \"name\": \"aria-errormessage\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-invalid\naria-describedby.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Identifies the next element (or elements) in an alternate reading order of content which, at the user's discretion,\nallows assistive technology to override the general default of reading in document source order.\",\n      \"name\": \"aria-flowto\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Indicates an element's \"grabbed\" state in a drag-and-drop operation.\",\n      \"name\": \"aria-grabbed\",\n      \"optional\": true,\n      \"tags\": {\n        \"deprecated\": \"in ARIA 1.1\",\n      },\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by an element.\",\n      \"name\": \"aria-haspopup\",\n      \"optional\": true,\n      \"type\": \"boolean | \"dialog\" | \"menu\" | \"true\" | \"false\" | \"listbox\" | \"tree\" | \"grid\" | undefined\",\n    },\n    {\n      \"description\": \"Indicates whether the element is exposed to an accessibility API.\",\n      \"name\": \"aria-hidden\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-disabled.\",\n      },\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates the entered value does not conform to the format expected by the application.\",\n      \"name\": \"aria-invalid\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-errormessage.\",\n      },\n      \"type\": \"boolean | \"true\" | \"false\" | \"grammar\" | \"spelling\" | undefined\",\n    },\n    {\n      \"description\": \"Indicates keyboard shortcuts that an author has implemented to activate or give focus to an element.\",\n      \"name\": \"aria-keyshortcuts\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines a string value that labels the current element.\",\n      \"name\": \"aria-label\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-labelledby.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines the hierarchical level of an element within a structure.\",\n      \"name\": \"aria-level\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Indicates that an element will be updated, and describes the types of updates the user agents, assistive technologies, and user can expect from the live region.\",\n      \"name\": \"aria-live\",\n      \"optional\": true,\n      \"type\": \"\"off\" | \"assertive\" | \"polite\" | undefined\",\n    },\n    {\n      \"description\": \"Indicates whether an element is modal when displayed.\",\n      \"name\": \"aria-modal\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates whether a text box accepts multiple lines of input or only a single line.\",\n      \"name\": \"aria-multiline\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates that the user may select more than one item from the current selectable descendants.\",\n      \"name\": \"aria-multiselectable\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates whether the element's orientation is horizontal, vertical, or unknown/ambiguous.\",\n      \"name\": \"aria-orientation\",\n      \"optional\": true,\n      \"type\": \"\"horizontal\" | \"vertical\" | undefined\",\n    },\n    {\n      \"description\": \"Identifies an element (or elements) in order to define a visual, functional, or contextual parent/child relationship\nbetween DOM elements where the DOM hierarchy cannot be used to represent the relationship.\",\n      \"name\": \"aria-owns\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-controls.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines a short hint (a word or short phrase) intended to aid the user with data entry when the control has no value.\nA hint could be a sample value or a brief description of the expected format.\",\n      \"name\": \"aria-placeholder\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines an element's number or position in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM.\",\n      \"name\": \"aria-posinset\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-setsize.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Indicates the current \"pressed\" state of toggle buttons.\",\n      \"name\": \"aria-pressed\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-checked\naria-selected.\",\n      },\n      \"type\": \"boolean | \"true\" | \"false\" | \"mixed\" | undefined\",\n    },\n    {\n      \"description\": \"Indicates that the element is not editable, but is otherwise operable.\",\n      \"name\": \"aria-readonly\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-disabled.\",\n      },\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Indicates what notifications the user agent will trigger when the accessibility tree within a live region is modified.\",\n      \"name\": \"aria-relevant\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-atomic.\",\n      },\n      \"type\": \"\"text\" | \"additions\" | \"additions removals\" | \"additions text\" | \"all\" | \"removals\" | \"removals additions\" | \"removals text\" | \"text additions\" | \"text removals\" | undefined\",\n    },\n    {\n      \"description\": \"Indicates that user input is required on the element before a form may be submitted.\",\n      \"name\": \"aria-required\",\n      \"optional\": true,\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Defines a human-readable, author-localized description for the role of an element.\",\n      \"name\": \"aria-roledescription\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines the total number of rows in a table, grid, or treegrid.\",\n      \"name\": \"aria-rowcount\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-rowindex.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Defines an element's row index or position with respect to the total number of rows within a table, grid, or treegrid.\",\n      \"name\": \"aria-rowindex\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-rowcount\naria-rowspan.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Defines a human readable text alternative of aria-rowindex.\",\n      \"name\": \"aria-rowindextext\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-colindextext.\",\n      },\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"description\": \"Defines the number of rows spanned by a cell or gridcell within a table, grid, or treegrid.\",\n      \"name\": \"aria-rowspan\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-rowindex\naria-colspan.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Indicates the current \"selected\" state of various widgets.\",\n      \"name\": \"aria-selected\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-checked\naria-pressed.\",\n      },\n      \"type\": \"Booleanish | undefined\",\n    },\n    {\n      \"description\": \"Defines the number of items in the current set of listitems or treeitems. Not required if all elements in the set are present in the DOM.\",\n      \"name\": \"aria-setsize\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-posinset.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Indicates if items in a table or grid are sorted in ascending or descending order.\",\n      \"name\": \"aria-sort\",\n      \"optional\": true,\n      \"type\": \"\"none\" | \"ascending\" | \"descending\" | \"other\" | undefined\",\n    },\n    {\n      \"description\": \"Defines the maximum allowed value for a range widget.\",\n      \"name\": \"aria-valuemax\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Defines the minimum allowed value for a range widget.\",\n      \"name\": \"aria-valuemin\",\n      \"optional\": true,\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Defines the current value for a range widget.\",\n      \"name\": \"aria-valuenow\",\n      \"optional\": true,\n      \"tags\": {\n        \"see\": \"aria-valuetext.\",\n      },\n      \"type\": \"number | undefined\",\n    },\n    {\n      \"description\": \"Defines the human readable text alternative of aria-valuenow for a range widget.\",\n      \"name\": \"aria-valuetext\",\n      \"optional\": true,\n      \"type\": \"string | undefined\",\n    },\n    {\n      \"name\": \"dangerouslySetInnerHTML\",\n      \"optional\": true,\n      \"type\": \"{ __html: string | TrustedHTML; } | undefined\",\n    },\n    {\n      \"name\": \"onCopy\",\n      \"optional\": true,\n      \"type\": \"ClipboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCopyCapture\",\n      \"optional\": true,\n      \"type\": \"ClipboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCut\",\n      \"optional\": true,\n      \"type\": \"ClipboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCutCapture\",\n      \"optional\": true,\n      \"type\": \"ClipboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPaste\",\n      \"optional\": true,\n      \"type\": \"ClipboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPasteCapture\",\n      \"optional\": true,\n      \"type\": \"ClipboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCompositionEnd\",\n      \"optional\": true,\n      \"type\": \"CompositionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCompositionEndCapture\",\n      \"optional\": true,\n      \"type\": \"CompositionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCompositionStart\",\n      \"optional\": true,\n      \"type\": \"CompositionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCompositionStartCapture\",\n      \"optional\": true,\n      \"type\": \"CompositionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCompositionUpdate\",\n      \"optional\": true,\n      \"type\": \"CompositionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCompositionUpdateCapture\",\n      \"optional\": true,\n      \"type\": \"CompositionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onFocusCapture\",\n      \"optional\": true,\n      \"type\": \"FocusEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onBlurCapture\",\n      \"optional\": true,\n      \"type\": \"FocusEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onChangeCapture\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onBeforeInput\",\n      \"optional\": true,\n      \"type\": \"InputEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onBeforeInputCapture\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onInput\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onInputCapture\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onReset\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onResetCapture\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSubmit\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSubmitCapture\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onInvalid\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onInvalidCapture\",\n      \"optional\": true,\n      \"type\": \"FormEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoad\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoadCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onError\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onErrorCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onKeyDown\",\n      \"optional\": true,\n      \"type\": \"KeyboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onKeyDownCapture\",\n      \"optional\": true,\n      \"type\": \"KeyboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onKeyPress\",\n      \"optional\": true,\n      \"tags\": {\n        \"deprecated\": \"Use `onKeyUp` or `onKeyDown` instead\",\n      },\n      \"type\": \"KeyboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onKeyPressCapture\",\n      \"optional\": true,\n      \"tags\": {\n        \"deprecated\": \"Use `onKeyUpCapture` or `onKeyDownCapture` instead\",\n      },\n      \"type\": \"KeyboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onKeyUp\",\n      \"optional\": true,\n      \"type\": \"KeyboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onKeyUpCapture\",\n      \"optional\": true,\n      \"type\": \"KeyboardEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAbort\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAbortCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCanPlay\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCanPlayCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCanPlayThrough\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onCanPlayThroughCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDurationChange\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDurationChangeCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onEmptied\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onEmptiedCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onEncrypted\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onEncryptedCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onEnded\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onEndedCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoadedData\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoadedDataCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoadedMetadata\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoadedMetadataCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoadStart\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLoadStartCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPause\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPauseCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPlay\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPlayCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPlaying\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPlayingCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onProgress\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onProgressCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onRateChange\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onRateChangeCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSeeked\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSeekedCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSeeking\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSeekingCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onStalled\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onStalledCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSuspend\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSuspendCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTimeUpdate\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTimeUpdateCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onVolumeChange\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onVolumeChangeCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onWaiting\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onWaitingCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAuxClick\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAuxClickCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onClick\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onClickCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onContextMenu\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onContextMenuCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDoubleClick\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDoubleClickCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDrag\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragEnd\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragEndCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragEnter\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragEnterCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragExit\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragExitCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragLeave\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragLeaveCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragOver\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragOverCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragStart\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDragStartCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDrop\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onDropCapture\",\n      \"optional\": true,\n      \"type\": \"DragEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseDown\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseDownCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseEnter\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseLeave\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseMove\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseMoveCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseOut\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseOutCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseOver\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseOverCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseUp\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onMouseUpCapture\",\n      \"optional\": true,\n      \"type\": \"MouseEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSelect\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onSelectCapture\",\n      \"optional\": true,\n      \"type\": \"ReactEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchCancel\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchCancelCapture\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchEnd\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchEndCapture\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchMove\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchMoveCapture\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchStart\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTouchStartCapture\",\n      \"optional\": true,\n      \"type\": \"TouchEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerDown\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerDownCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerMove\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerMoveCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerUp\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerUpCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerCancel\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerCancelCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerEnter\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerLeave\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerOver\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerOverCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerOut\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onPointerOutCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onGotPointerCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onGotPointerCaptureCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLostPointerCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onLostPointerCaptureCapture\",\n      \"optional\": true,\n      \"type\": \"PointerEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onScroll\",\n      \"optional\": true,\n      \"type\": \"UIEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onScrollCapture\",\n      \"optional\": true,\n      \"type\": \"UIEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onScrollEnd\",\n      \"optional\": true,\n      \"type\": \"UIEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onScrollEndCapture\",\n      \"optional\": true,\n      \"type\": \"UIEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onWheel\",\n      \"optional\": true,\n      \"type\": \"WheelEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onWheelCapture\",\n      \"optional\": true,\n      \"type\": \"WheelEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAnimationStart\",\n      \"optional\": true,\n      \"type\": \"AnimationEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAnimationStartCapture\",\n      \"optional\": true,\n      \"type\": \"AnimationEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAnimationEnd\",\n      \"optional\": true,\n      \"type\": \"AnimationEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAnimationEndCapture\",\n      \"optional\": true,\n      \"type\": \"AnimationEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAnimationIteration\",\n      \"optional\": true,\n      \"type\": \"AnimationEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onAnimationIterationCapture\",\n      \"optional\": true,\n      \"type\": \"AnimationEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onToggle\",\n      \"optional\": true,\n      \"type\": \"ToggleEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onBeforeToggle\",\n      \"optional\": true,\n      \"type\": \"ToggleEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionCancel\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionCancelCapture\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionEnd\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionEndCapture\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionRun\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionRunCapture\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionStart\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n    {\n      \"name\": \"onTransitionStartCapture\",\n      \"optional\": true,\n      \"type\": \"TransitionEventHandler<HTMLInputElement> | undefined\",\n    },\n  ],\n  \"name\": \"$\",\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/use-config.json",
    "content": "{\n  \"description\": \"Provides normalized data for the current page from `ConfigContext`.\n\nThis includes the full result of `normalizePages`, along with a derived value `hideSidebar`\nthat determines whether the sidebar should be hidden on the current page.\",\n  \"filePath\": \"../nextra-theme-docs/dist/stores/config.d.mts\",\n  \"name\": \"useConfig\",\n  \"signatures\": [\n    {\n      \"params\": [],\n      \"returns\": [\n        {\n          \"description\": \"Active type for current page, used to determine layout in theme.\",\n          \"name\": \"normalizePagesResult.activeType\",\n          \"optional\": true,\n          \"type\": \"\"doc\" | \"page\" | \"menu\"\",\n        },\n        {\n          \"description\": \"Active index for current page, used for pagination in combination with `flatDocsDirectories`\nitems.\",\n          \"name\": \"normalizePagesResult.activeIndex\",\n          \"type\": \"number\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.breadcrumb\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.collapsed\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.copyPage\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.footer\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.layout\",\n          \"optional\": true,\n          \"type\": \"\"default\" | \"full\" | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.navbar\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.pagination\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.sidebar\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.timestamp\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.toc\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"normalizePagesResult.activeThemeContext.typesetting\",\n          \"optional\": true,\n          \"type\": \"\"default\" | \"article\" | undefined\",\n        },\n        {\n          \"description\": \"Parsed [front matter](https://jekyllrb.com/docs/front-matter) or exported\n[Metadata](https://nextjs.org/docs/app/building-your-application/optimizing/metadata) from page.\",\n          \"name\": \"normalizePagesResult.activeMetadata\",\n          \"optional\": true,\n          \"type\": \"FrontMatter\",\n        },\n        {\n          \"description\": \"Active path for current page, used for breadcrumb navigation.\",\n          \"name\": \"normalizePagesResult.activePath\",\n          \"type\": \"Item[]\",\n        },\n        {\n          \"description\": \"All directories in the tree structure.\",\n          \"name\": \"normalizePagesResult.directories\",\n          \"type\": \"Item[]\",\n        },\n        {\n          \"description\": \"Directories with `type: 'doc'` in `_meta` file.\",\n          \"name\": \"normalizePagesResult.docsDirectories\",\n          \"type\": \"DocsItem[]\",\n        },\n        {\n          \"description\": \"Flattened directories with `type: 'doc'` in `_meta` file.\",\n          \"name\": \"normalizePagesResult.flatDocsDirectories\",\n          \"type\": \"DocsItem[]\",\n        },\n        {\n          \"description\": \"Navbar items, items which have `type: 'page'` in `_meta` file.\",\n          \"name\": \"normalizePagesResult.topLevelNavbarItems\",\n          \"type\": \"(PageItem | MenuItem)[]\",\n        },\n        {\n          \"description\": \"Whether the sidebar is shown. If `false`, the theme and locale switchers are displayed in the\n`<Footer>`.\",\n          \"name\": \"hideSidebar\",\n          \"type\": \"boolean\",\n        },\n      ],\n    },\n  ],\n  \"tags\": {\n    \"returns\": \"An object containing the `normalizePagesResult` and a `hideSidebar` value.\",\n    \"throws\": \"If used outside of a `ConfigContext.Provider`.\",\n  },\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/use-edges-state.json",
    "content": "{\n  \"description\": \"This hook makes it easy to prototype a controlled flow where you manage the\nstate of nodes and edges outside the `ReactFlowInstance`. You can think of it\nlike React's `useState` hook with an additional helper callback.\",\n  \"name\": \"useEdgesState\",\n  \"signatures\": [\n    {\n      \"params\": [\n        {\n          \"name\": \"initialEdges\",\n          \"type\": \"EdgeType[]\",\n        },\n      ],\n      \"returns\": {\n        \"type\": \"[edges: EdgeType[], setEdges: Dispatch<SetStateAction<EdgeType[]>>, onEdgesChange: OnEdgesChange<EdgeType>]\",\n      },\n    },\n  ],\n  \"tags\": {\n    \"example\": \"```tsx\nimport { ReactFlow, useNodesState, useEdgesState } from '@xyflow/react';\n\nconst initialNodes = [];\nconst initialEdges = [];\n\nexport default function () {\n const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);\n const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);\n\n return (\n   <ReactFlow\n     nodes={nodes}\n     edges={edges}\n     onNodesChange={onNodesChange}\n     onEdgesChange={onEdgesChange}\n   />\n );\n}\n```\",\n    \"public\": \"\",\n    \"remarks\": \"This hook was created to make prototyping easier and our documentation\nexamples clearer. Although it is OK to use this hook in production, in\npractice you may want to use a more sophisticated state management solution\nlike Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead.\",\n    \"returns\": \"- `edges`: The current array of edges. You might pass this directly to the `edges` prop of your\n`<ReactFlow />` component, or you may want to manipulate it first to perform some layouting,\nfor example.\n\n- `setEdges`: A function that you can use to update the edges. You can pass it a new array of\nedges or a callback that receives the current array of edges and returns a new array of edges.\nThis is the same as the second element of the tuple returned by React's `useState` hook.\n\n- `onEdgesChange`: A handy callback that can take an array of `EdgeChanges` and update the edges\nstate accordingly. You'll typically pass this directly to the `onEdgesChange` prop of your\n`<ReactFlow />` component.\",\n  },\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/snapshots/use-theme-config.json",
    "content": "{\n  \"description\": \"Accesses the current [theme configuration](https://nextra.site/docs/docs-theme/theme-configuration)\nvalues, excluding layout-specific elements like:\n- `footer`\n- `navbar`\n- `pageMap`\n- `nextThemes`\n- `banner`\n- `children`\n\nThis hook is useful for dynamically configuring your project based on shared theme values.\",\n  \"filePath\": \"../nextra-theme-docs/src/stores/theme-config.ts\",\n  \"name\": \"useThemeConfig\",\n  \"signatures\": [\n    {\n      \"params\": [],\n      \"returns\": [\n        {\n          \"name\": \"copyPageButton\",\n          \"type\": \"boolean\",\n        },\n        {\n          \"name\": \"darkMode\",\n          \"type\": \"boolean\",\n        },\n        {\n          \"name\": \"docsRepositoryBase\",\n          \"type\": \"string\",\n        },\n        {\n          \"name\": \"editLink\",\n          \"type\": \"string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...> | null\",\n        },\n        {\n          \"name\": \"feedback.content\",\n          \"type\": \"string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...> | null\",\n        },\n        {\n          \"name\": \"feedback.labels\",\n          \"type\": \"string\",\n        },\n        {\n          \"name\": \"feedback.link\",\n          \"optional\": true,\n          \"type\": \"string | undefined\",\n        },\n        {\n          \"name\": \"i18n\",\n          \"type\": \"{ locale: string; name: string; }[]\",\n        },\n        {\n          \"name\": \"lastUpdated\",\n          \"type\": \"ReactElement<unknown, string | JSXElementConstructor<any>>\",\n        },\n        {\n          \"name\": \"navigation\",\n          \"type\": \"boolean | { next: boolean; prev: boolean; }\",\n        },\n        {\n          \"name\": \"search\",\n          \"type\": \"string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...> | null\",\n        },\n        {\n          \"name\": \"sidebar.defaultMenuCollapseLevel\",\n          \"type\": \"number\",\n        },\n        {\n          \"name\": \"sidebar.defaultOpen\",\n          \"type\": \"boolean\",\n        },\n        {\n          \"name\": \"sidebar.toggleButton\",\n          \"type\": \"boolean\",\n        },\n        {\n          \"name\": \"sidebar.autoCollapse\",\n          \"optional\": true,\n          \"type\": \"boolean | undefined\",\n        },\n        {\n          \"name\": \"themeSwitch.dark\",\n          \"type\": \"string\",\n        },\n        {\n          \"name\": \"themeSwitch.light\",\n          \"type\": \"string\",\n        },\n        {\n          \"name\": \"themeSwitch.system\",\n          \"type\": \"string\",\n        },\n        {\n          \"name\": \"toc.backToTop\",\n          \"type\": \"string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...> | null\",\n        },\n        {\n          \"name\": \"toc.float\",\n          \"type\": \"boolean\",\n        },\n        {\n          \"name\": \"toc.title\",\n          \"type\": \"string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...> | null\",\n        },\n        {\n          \"name\": \"toc.extraContent\",\n          \"optional\": true,\n          \"type\": \"ReactNode\",\n        },\n      ],\n    },\n  ],\n  \"tags\": {\n    \"returns\": \"A subset of your theme configuration context.\",\n  },\n}"
  },
  {
    "path": "packages/tsdoc/src/__tests__/zod-to-ts.test.ts",
    "content": "import { reactNode } from 'nextra/schemas'\nimport { z } from 'zod'\nimport { LayoutPropsSchema } from '../../../nextra-theme-docs/src/schemas.js'\nimport { HeadPropsSchema } from '../../../nextra/src/client/components/head.js'\nimport { NextraConfigSchema } from '../../../nextra/src/server/schemas.js'\nimport { generateTsFromZod } from '../../../nextra/src/server/tsdoc/zod-to-ts.js'\n\ndescribe('generateTsFromZod', () => {\n  it('should generate TypeScript with @description and @default for primitive types', () => {\n    const schema = z.strictObject({\n      id: z.string().describe('The unique identifier'),\n      name: z.string().default('Anonymous').describe(\"The user's name\"),\n      age: z.number().optional().describe(\"User's age\"),\n      isAdmin: z.boolean().default(false).describe('Admin status')\n    })\n    const expected = `{\n  /**\n   * The unique identifier\n   */\n  id: string\n\n  /**\n   * The user's name\n   * @default \"Anonymous\"\n   */\n  name?: string\n\n  /**\n   * User's age\n   */\n  age?: number\n\n  /**\n   * Admin status\n   * @default false\n   */\n  isAdmin?: boolean\n}`\n    expect(generateTsFromZod(schema)).toBe(expected)\n  })\n\n  it('should handle nested objects correctly', () => {\n    const schema = z.strictObject({\n      user: z\n        .strictObject({\n          id: z.string().describe('User ID'),\n          profile: z\n            .strictObject({\n              bio: z.string().optional().describe('User bio'),\n              age: z.number().default(25).describe(\"User's age\")\n            })\n            .describe('Profile')\n        })\n        .describe('User')\n    })\n    const expected = `{\n  /**\n   * User\n   */\n  user: {\n    /**\n     * User ID\n     */\n    id: string\n\n    /**\n     * Profile\n     */\n    profile: {\n      /**\n       * User bio\n       */\n      bio?: string\n\n      /**\n       * User's age\n       * @default 25\n       */\n      age?: number\n    }\n  }\n}`\n    expect(generateTsFromZod(schema)).toBe(expected)\n  })\n\n  it('should handle arrays and unions', () => {\n    const schema = z.strictObject({\n      tags: z.array(z.string()).describe('User tags'),\n      status: z\n        .union([z.literal('active'), z.literal('inactive')])\n        .describe('User status')\n    })\n    const expected = `{\n  /**\n   * User tags\n   */\n  tags: string[]\n\n  /**\n   * User status\n   */\n  status: \"active\" | \"inactive\"\n}`\n    expect(generateTsFromZod(schema)).toBe(expected)\n  })\n\n  it('should handle nullable and optional types', () => {\n    const schema = z.strictObject({\n      nickname: z.string().nullable().describe('User nickname'),\n      country: z.string().optional().describe(\"User's country\")\n    })\n    const expected = `{\n  /**\n   * User nickname\n   */\n  nickname: string | null\n\n  /**\n   * User's country\n   */\n  country?: string\n}`\n    expect(generateTsFromZod(schema)).toBe(expected)\n  })\n\n  it('should handle default values correctly', () => {\n    const schema = z.strictObject({\n      active: z.boolean().default(true).describe('User active status'),\n      count: z.number().default(0).describe('User count')\n    })\n    const expected = `{\n  /**\n   * User active status\n   * @default true\n   */\n  active?: boolean\n\n  /**\n   * User count\n   * @default 0\n   */\n  count?: number\n}`\n    expect(generateTsFromZod(schema)).toBe(expected)\n  })\n\n  it('should handle enum', () => {\n    const schema = z.strictObject({\n      layout: z\n        .enum(['default', 'full'])\n        .optional()\n        .default('default')\n        .describe('Defines the layout style.')\n    })\n    expect(generateTsFromZod(schema)).toMatchInlineSnapshot(`\n      \"{\n        /**\n         * Defines the layout style.\n         * @default \"default\"\n         */\n        layout?: \"default\" | \"full\"\n      }\"\n    `)\n  })\n\n  it('should handle ReactNode', () => {\n    const schema = z.strictObject({\n      children: reactNode\n        .describe('Extra content after last icon.')\n        .default(null)\n    })\n    expect(generateTsFromZod(schema)).toMatchInlineSnapshot(`\n      \"{\n        /**\n         * Extra content after last icon.\n         * @default null\n         */\n        children?: React.ReactNode\n      }\"\n    `)\n  })\n\n  it('should convert LayoutPropsSchema', () => {\n    return expect(\n      'interface $ ' + generateTsFromZod(LayoutPropsSchema)\n    ).toMatchFileSnapshot('./snapshots/layout-props.ts')\n  })\n  it('should convert HeadPropsSchema', () => {\n    return expect(\n      'interface $$ ' + generateTsFromZod(HeadPropsSchema)\n    ).toMatchFileSnapshot('./snapshots/head-props.ts')\n  })\n  it('should convert NextraConfigSchema and HeadPropsSchema', () => {\n    return expect(\n      `export interface NextraConfig ${generateTsFromZod(NextraConfigSchema)}\n\nexport interface HeadProps ${generateTsFromZod(HeadPropsSchema)}`\n    ).toMatchFileSnapshot('../../../nextra/src/types.generated.ts')\n  })\n})\n"
  },
  {
    "path": "packages/tsdoc/src/env.d.ts",
    "content": "declare module '*?raw' {\n  const content: string\n  export default content\n}\n"
  },
  {
    "path": "packages/tsdoc/src/index.ts",
    "content": "/* eslint-disable unicorn/no-empty-file */\n"
  },
  {
    "path": "packages/tsdoc/tsconfig.json",
    "content": "{\n  \"extends\": [\"@tsconfig/strictest/tsconfig.json\"],\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"moduleResolution\": \"bundler\",\n    \"target\": \"es2022\",\n    \"module\": \"esnext\",\n    \"noPropertyAccessFromIndexSignature\": false,\n    \"types\": [\"vitest/globals\"]\n  },\n  \"exclude\": [\"node_modules\", \"dist\"]\n}\n"
  },
  {
    "path": "packages/tsdoc/tsup.config.ts",
    "content": "import { defineConfig } from 'tsup'\nimport { defaultEntry } from '../nextra/default-entry.js'\nimport { IS_PRODUCTION } from '../nextra/src/server/constants.js'\nimport packageJson from './package.json'\n\nexport default defineConfig({\n  name: packageJson.name,\n  format: 'esm',\n  dts: true,\n  bundle: false,\n  entry: defaultEntry,\n  splitting: IS_PRODUCTION,\n  clean: IS_PRODUCTION\n})\n"
  },
  {
    "path": "packages/tsdoc/vitest.config.ts",
    "content": "import { defineProject } from 'vitest/config'\n\nexport default defineProject({\n  test: {\n    globals: true,\n    testTimeout: 10_000\n  }\n})\n"
  },
  {
    "path": "patches/@changesets__assemble-release-plan.patch",
    "content": "diff --git a/dist/changesets-assemble-release-plan.cjs.js b/dist/changesets-assemble-release-plan.cjs.js\nindex d352e376e1bf591f67510ce341b1fbf785039914..07f7487c5ce3a4206a7b35dd7049121a98295a3c 100644\n--- a/dist/changesets-assemble-release-plan.cjs.js\n+++ b/dist/changesets-assemble-release-plan.cjs.js\n@@ -319,8 +319,7 @@ function shouldBumpMajor({\n   return depType === \"peerDependencies\" && nextRelease.type !== \"none\" && nextRelease.type !== \"patch\" && (\n   // 1. If onlyUpdatePeerDependentsWhenOutOfRange set to true, bump major if the version is leaving the range.\n   // 2. If onlyUpdatePeerDependentsWhenOutOfRange set to false, bump major regardless whether or not the version is leaving the range.\n-  !onlyUpdatePeerDependentsWhenOutOfRange || !semverSatisfies__default[\"default\"](incrementVersion(nextRelease, preInfo), versionRange)) && (\n-  // bump major only if the dependent doesn't already has a major release.\n+  !onlyUpdatePeerDependentsWhenOutOfRange) && ( // bump major only if the dependent doesn't already has a major release.\n   !releases.has(dependent) || releases.has(dependent) && releases.get(dependent).type !== \"major\");\n }\n \n@@ -409,7 +408,7 @@ function matchFixedConstraint(releases, packagesByName, config) {\n \n function getPreVersion(version) {\n   let parsed = semverParse__default[\"default\"](version);\n-  let preVersion = parsed.prerelease[1] === undefined ? -1 : parsed.prerelease[1];\n+  let preVersion = parsed?.prerelease[1] === undefined ? -1 : parsed.prerelease[1];\n   if (typeof preVersion !== \"number\") {\n     throw new errors.InternalError(\"preVersion is not a number\");\n   }\n"
  },
  {
    "path": "patches/esbuild-plugin-svgr.patch",
    "content": "diff --git a/src/index.js b/src/index.js\nindex 02250dd82792f436704e894e8d0a793cf88e9322..0d26da3f54311ed906f463a46be522f04f0d11e8 100644\n--- a/src/index.js\n+++ b/src/index.js\n@@ -1,11 +1,13 @@\n const { readFile } = require('node:fs/promises')\n const { transform } = require('@svgr/core')\n+const path = require('node:path')\n \n const svgrPlugin = (options = {\n     markExternal: true\n }) => ({\n     name: 'svgr',\n     setup(build) {\n+      if (build.bundle) {\n         build.onResolve({ filter: /\\.svg$/ }, async (args) => {\n             switch (args.kind) {\n                 case 'import-statement':\n@@ -21,8 +23,11 @@ const svgrPlugin = (options = {\n                     }\n             }\n         })\n+      }\n \n-        build.onLoad({ filter: /\\.svg$/ }, async (args) => {\n+        // esbuild do not run next `onLoad` callbacks if some already returned `contents`,\n+        // but we use react-compiler plugin, which should be executed after this plugin\n+        build.onResolve({ filter: /\\.svg$/ }, async (args) => {\n             const svg = await readFile(args.path, { encoding: 'utf8' })\n \n             if (options.plugins && !options.plugins.includes('@svgr/plugin-jsx')) {\n@@ -41,8 +46,11 @@ const svgrPlugin = (options = {\n             }\n \n             return {\n+              path: path.join(args.resolveDir, args.path),\n+              pluginData: {\n                 contents,\n                 loader: options.typescript ? 'tsx' : 'jsx',\n+              }\n             }\n         })\n     },\n"
  },
  {
    "path": "patches/eslint-plugin-tailwindcss.patch",
    "content": "diff --git a/lib/util/customConfig.js b/lib/util/customConfig.js\nindex 9bc6a40330df0a9a4318685ebb750f9c1c4dbd0b..bc6e15b5684e14aa9c38d15444cd53df17b95f63 100644\n--- a/lib/util/customConfig.js\n+++ b/lib/util/customConfig.js\n@@ -31,7 +31,8 @@ function requireUncached(module) {\n   }\n }\n \n-function loadConfig(config) {\n+// https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/357\n+function loadConfig(config, options) {\n   let loadedConfig = null;\n   if (typeof config === 'string') {\n     const resolvedPath = path.isAbsolute(config) ? config : path.join(path.resolve(), config);\n@@ -39,7 +40,7 @@ function loadConfig(config) {\n       const stats = fs.statSync(resolvedPath);\n       if (stats === null) {\n         loadedConfig = {};\n-      } else if (lastModifiedDate !== stats.mtime) {\n+      } else if (options.newConfig || lastModifiedDate !== stats.mtime) {\n         lastModifiedDate = stats.mtime;\n         loadedConfig = requireUncached(resolvedPath);\n       } else {\n@@ -76,7 +77,7 @@ function resolve(twConfig) {\n   if (newConfig || expired) {\n     previousConfig = twConfig;\n     lastCheck = now;\n-    const userConfig = loadConfig(twConfig);\n+    const userConfig = loadConfig(twConfig, { newConfig });\n     // userConfig is null when config file was not modified\n     if (userConfig !== null) {\n       mergedConfig = resolveConfig(userConfig);\n"
  },
  {
    "path": "patches/next.patch",
    "content": "diff --git a/dist/lib/pretty-bytes.js b/dist/lib/pretty-bytes.js\nindex 7815ec39d7288b7aa79b1c81a3126175aa7a0f7f..480c2389cdc97235083e97f0c1ed1eff25c10170 100644\n--- a/dist/lib/pretty-bytes.js\n+++ b/dist/lib/pretty-bytes.js\n@@ -44,6 +44,7 @@ Formats the given number using `Number#toLocaleString`.\n     return result;\n };\n function prettyBytes(number, options) {\n+    return number/1000 + ' Kb'\n     if (!Number.isFinite(number)) {\n         throw Object.defineProperty(new TypeError(`Expected a finite number, got ${typeof number}: ${number}`), \"__NEXT_ERROR_CODE\", {\n             value: \"E572\",\n"
  },
  {
    "path": "patches/tsup.patch",
    "content": "diff --git a/dist/rollup.js b/dist/rollup.js\nindex cc82363277fe849c9460937773d9bc8b5c86beb6..c39cd59993034062a67eb07e4c9b043498633d12 100644\n--- a/dist/rollup.js\n+++ b/dist/rollup.js\n@@ -6787,6 +6787,10 @@ var getRollupConfig = async (options) => {\n         tsResolveOptions && tsResolvePlugin(tsResolveOptions),\n         json(),\n         ignoreFiles,\n+        // https://stackoverflow.com/a/72679927\n+        require('@rollup/plugin-alias')({\n+          entries: [{ find: /^.*\\.svg$/, replacement: 'src/icon.ts' }]\n+        }),\n         dtsPlugin.default({\n           tsconfig: options.tsconfig,\n           compilerOptions: {\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - packages/*\n  - examples/*\n  - docs\n"
  },
  {
    "path": "prettier.config.mjs",
    "content": "export { default } from '@nextra/prettier-config'\n"
  },
  {
    "path": "renovate.json5",
    "content": "{\n  $schema: 'https://docs.renovatebot.com/renovate-schema.json',\n  extends: ['config:recommended'],\n  schedule: ['every weekend'],\n  packageRules: [\n    {\n      groupName: 'lint',\n      matchPackageNames: [\n        'typescript-eslint',\n        'eslint',\n        'eslint-config-prettier',\n        'eslint-plugin-import',\n        'eslint-plugin-react',\n        'eslint-plugin-react-hooks',\n        'eslint-plugin-sonarjs',\n        // 'eslint-plugin-tailwindcss',\n        'eslint-plugin-typescript-sort-keys',\n        'eslint-plugin-unicorn',\n        'prettier',\n        'prettier-plugin-pkg',\n        'prettier-plugin-tailwindcss',\n        '@ianvs/prettier-plugin-sort-imports'\n      ]\n    },\n    {\n      groupName: 'latex',\n      matchPackageNames: ['remark-math', 'rehype-katex']\n    },\n    {\n      groupName: 'next',\n      matchPackageNames: ['next', '@next/eslint-plugin-next']\n    },\n    {\n      groupName: 'tailwindcss',\n      matchPackageNames: [\n        '@tailwindcss/cli',\n        '@tailwindcss/postcss',\n        'tailwindcss'\n      ]\n    }\n  ],\n  baseBranches: ['main']\n}\n"
  },
  {
    "path": "turbo.jsonc",
    "content": "{\n  \"$schema\": \"https://turbo.build/schema.json\",\n  \"globalDependencies\": [\"pnpm-lock.yaml\", \"patches/*\"],\n  \"tasks\": {\n    \"build\": {\n      \"dependsOn\": [\n        // Run `build` in workspaces I depend on first\n        \"^build\"\n      ],\n      // Cache all files emitted to the packages's directories\n      \"outputs\": [\"dist/**\", \".next/**\", \"public/_pagefind/**\"]\n    },\n    \"test\": {\n      \"outputs\": [\"dist/**\"]\n    },\n    \"types:check\": {\n      \"dependsOn\": [\n        // Run `build` in workspaces I depend on first\n        \"^build\"\n      ],\n      \"outputs\": [\"dist/**\", \".next/**\"]\n    },\n    \"dev\": {\n      \"dependsOn\": [\n        // Run `build` in workspaces I depend on first\n        \"^build\"\n      ],\n      \"cache\": false\n    }\n  }\n}\n"
  }
]