Full Code of bvaughn/react-error-boundary for AI

main ecaf9257e11c cached
122 files
129.2 KB
36.3k tokens
130 symbols
1 requests
Download .txt
Repository: bvaughn/react-error-boundary
Branch: main
Commit: ecaf9257e11c
Files: 122
Total size: 129.2 KB

Directory structure:
gitextract_msysdob0/

├── .gitattributes
├── .github/
│   └── workflows/
│       ├── eslint.yml
│       ├── pending-changes.yml
│       ├── prettier.yml
│       ├── typescript.yml
│       └── vitest.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── eslint.config.js
├── index.css
├── index.html
├── index.tsx
├── integrations/
│   └── vite/
│       ├── README.md
│       ├── eslint.config.js
│       ├── index.html
│       ├── package.json
│       ├── playwright.config.ts
│       ├── src/
│       │   ├── components/
│       │   │   ├── Children.tsx
│       │   │   ├── Container.tsx
│       │   │   ├── DebugData.tsx
│       │   │   └── Resizer.tsx
│       │   ├── index.css
│       │   ├── main.tsx
│       │   ├── routes/
│       │   │   └── Home.tsx
│       │   ├── utils/
│       │   │   ├── assert.ts
│       │   │   └── cn.ts
│       │   └── vite-env.d.ts
│       ├── test-results/
│       │   └── .last-run.json
│       ├── tests/
│       │   └── utils/
│       │       ├── calculateBoxBetween.ts
│       │       ├── calculateHitArea.ts
│       │       ├── debugging/
│       │       │   ├── logDebugState.ts
│       │       │   └── logGroup.ts
│       │       ├── expectLayout.ts
│       │       ├── expectPanelSize.ts
│       │       ├── getCenterCoordinates.ts
│       │       ├── getSeparatorAriaAttributes.ts
│       │       ├── goToUrl.ts
│       │       ├── goToUrlWithIframe.ts
│       │       ├── pointer-interactions/
│       │       │   └── resizeHelper.ts
│       │       ├── serializer/
│       │       │   ├── decode.ts
│       │       │   ├── encode.ts
│       │       │   └── types.ts
│       │       ├── types.ts
│       │       └── updateUrl.ts
│       ├── tsconfig.json
│       └── vite.config.ts
├── lib/
│   ├── components/
│   │   ├── ErrorBoundary.test.tsx
│   │   └── ErrorBoundary.tsx
│   ├── context/
│   │   └── ErrorBoundaryContext.ts
│   ├── hooks/
│   │   ├── useErrorBoundary.test.tsx
│   │   └── useErrorBoundary.ts
│   ├── index.ts
│   ├── types.ts
│   └── utils/
│       ├── assert.ts
│       ├── assertErrorBoundaryContext.ts
│       ├── getErrorMessage.ts
│       ├── isErrorBoundaryContext.ts
│       ├── withErrorBoundary.test.tsx
│       └── withErrorBoundary.ts
├── package.json
├── pnpm-workspace.yaml
├── public/
│   ├── generated/
│   │   └── examples/
│   │       ├── AsyncUserCodeErrors.json
│   │       ├── ErrorLogging.json
│   │       ├── FallbackComponent.json
│   │       ├── FallbackContent.json
│   │       ├── GetErrorMessage.json
│   │       ├── NpmResolution.json
│   │       ├── RenderProp.json
│   │       ├── ResetWithUseErrorBoundary.json
│   │       ├── UseClient.json
│   │       ├── UseErrorBoundary.json
│   │       ├── WithErrorBoundaryA.json
│   │       ├── WithErrorBoundaryB.json
│   │       ├── WithErrorBoundaryC.json
│   │       └── YarnResolution.json
│   └── robots.txt
├── scripts/
│   ├── compile-docs.ts
│   ├── compile-examples.ts
│   └── compress-og-image
├── src/
│   ├── App.tsx
│   ├── components/
│   │   ├── ContinueLink.tsx
│   │   ├── Divider.tsx
│   │   ├── Link.tsx
│   │   └── NavLink.tsx
│   ├── routes/
│   │   ├── AsyncUserCodeErrorsRoute.tsx
│   │   ├── ErrorBoundaryPropsRoute.tsx
│   │   ├── ErrorLoggingRoute.tsx
│   │   ├── FallbackComponentRoute.tsx
│   │   ├── FallbackContentRoute.tsx
│   │   ├── GetErrorMessageRoute.tsx
│   │   ├── RenderPropRoute.tsx
│   │   ├── ResetNearestBoundaryRoute.tsx
│   │   ├── UseErrorBoundaryRoute.tsx
│   │   ├── WithErrorBoundaryRoute.tsx
│   │   └── examples/
│   │       ├── AsyncUserCodeErrors.tsx
│   │       ├── ErrorLogging.tsx
│   │       ├── FallbackComponent.tsx
│   │       ├── FallbackContent.tsx
│   │       ├── GetErrorMessage.ts
│   │       ├── NpmResolution.json
│   │       ├── RenderProp.tsx
│   │       ├── ResetWithUseErrorBoundary.tsx
│   │       ├── UseClient.ts
│   │       ├── UseErrorBoundary.tsx
│   │       ├── WithErrorBoundaryA.tsx
│   │       ├── WithErrorBoundaryB.tsx
│   │       ├── WithErrorBoundaryC.tsx
│   │       └── YarnResolution.json
│   ├── routes.ts
│   └── vite-env.d.ts
├── tsconfig.json
├── vercel.json
├── vite.config.ts
├── vitest.config.ts
├── vitest.d.ts
└── vitest.setup.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
* text=auto eol=lf


================================================
FILE: .github/workflows/eslint.yml
================================================
name: "ESLint"
on: [pull_request]
jobs:
  eslint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 10
      - name: Install dependencies
        run: pnpm install --frozen-lockfile --recursive
      - name: Run ESLint
        run: pnpm lint


================================================
FILE: .github/workflows/pending-changes.yml
================================================
name: "Pending changes"
on: [pull_request]
jobs:
  pending-changes:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 10
      - name: Install dependencies
        run: pnpm install --frozen-lockfile --recursive
      - uses: nickcharlton/diff-check@main
        with:
          command: pnpm run compile


================================================
FILE: .github/workflows/prettier.yml
================================================
name: "Prettier"
on: [pull_request]
jobs:
  prettier:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 10
      - name: Install dependencies
        run: pnpm install --frozen-lockfile --recursive
      - name: Run Prettier
        run: pnpm run prettier:ci


================================================
FILE: .github/workflows/typescript.yml
================================================
name: "TypeScript"
on: [pull_request]
jobs:
  typescript:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 10
      - name: Install dependencies
        run: pnpm install --frozen-lockfile --recursive
      - name: Build NPM package
        run: pnpm build
      - name: Run TypeScript
        run: pnpm tsc


================================================
FILE: .github/workflows/vitest.yml
================================================
name: "Vitest"
on: [pull_request]
jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 10
      - name: Install dependencies
        run: pnpm install --frozen-lockfile --recursive
      - name: Build NPM packages
        run: pnpm run build
      - name: Run tests
        run: pnpm run test:ci


================================================
FILE: .gitignore
================================================
dist
docs
node_modules

.DS_Store
.cache
*.log
.parcel-cache
.pnp.*

================================================
FILE: .nvmrc
================================================
18


================================================
FILE: .prettierignore
================================================
/dist
/docs
/generated
/public
/src/routes/examples


================================================
FILE: CHANGELOG.md
================================================
# CHANGELOG

See the [releases page](../../releases).


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity and
orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall
  community

Examples of unacceptable behavior include:

- The use of sexualized language or imagery, and sexual attention or advances of
  any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
  without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
me+coc@kentcdodds.com. All complaints will be reviewed and investigated promptly
and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series of
actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within the
community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

Thanks for your interest in contributing to this project!

Here are a couple of guidelines to keep in mind before opening a Pull Request:

- Please open a GitHub issue for discussion _before_ submitting any significant changes to this API (including new features or functionality).
- Please don't submit code that has been written by code-generation tools such as Copilot or Claude. (There's nothing wrong with these tools, but I'd prefer them not be a part of this project.)

## Local development

To get started:
```sh
pnpm install
```

### Running the documentation site locally

The documentation site is a great place to test pending changes. It runs on localhost port 3000 and can be started by running:
```sh
pnpm dev 
```

### Running tests locally

To run unit tests locally:
```sh
pnpm test
```

### Updating assets

Before submitting, also make sure to update generated docs/examples:
```
pnpm compile
pnpm prettier
pnpm lint
```

> [!NOTE]
> If you forget this step, CI will remind you!

================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2020 Brian Vaughn

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
<img src="https://react-error-boundary-lib.vercel.app/og.png" alt="react-error-boundary logo" width="400" height="210" />

`react-error-boundary`: Reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component. Supports all React renderers (including React DOM and React Native).

### If you like this project, 🎉 [become a sponsor](https://github.com/sponsors/bvaughn/) or ☕ [buy me a coffee](http://givebrian.coffee/)

## Getting started

```sh
# npm
npm install react-error-boundary

# pnpm
pnpm add react-error-boundary

# yarn
yarn add react-error-boundary
```

## FAQs

Frequently asked questions can be found [here](https://react-error-boundary-lib.vercel.app/common-questions).

## API

### ErrorBoundary

<!-- ErrorBoundary:description:begin -->
A reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component.
Wrap this component around other React components to "catch" errors and render a fallback UI.

This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),
so it has all of the advantages and constraints of that API.
This means that it can't catch errors during:
- Server side rendering</li>
- Event handlers
- Asynchronous code (including effects)

ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.
Refer to the documentation to determine which is best for your application.

ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `"use client";` directive.
<!-- ErrorBoundary:description:end -->

#### Required props

<!-- ErrorBoundary:required-props:begin -->
None
<!-- ErrorBoundary:required-props:end -->

#### Optional props

<!-- ErrorBoundary:optional-props:begin -->

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>onError</td>
      <td><p>Optional callback to enable e.g. logging error information to a server.
@param error Value that was thrown; typically an instance of <code>Error</code>
@param info React &quot;component stack&quot; identifying where the error was thrown</p>
</td>
    </tr>
    <tr>
      <td>onReset</td>
      <td><p>Optional callback to to be notified when an error boundary is &quot;reset&quot; so React can retry the failed render.</p>
</td>
    </tr>
    <tr>
      <td>resetKeys</td>
      <td><p>When changed, these keys will reset a triggered error boundary.
This can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).
See the the documentation for examples of how to use this prop.</p>
</td>
    </tr>
    <tr>
      <td>fallback</td>
      <td><p>Static content to render in place of an error if one is thrown.</p>
<pre><code class="language-tsx">&lt;ErrorBoundary fallback={&lt;div className=&quot;text-red&quot;&gt;Something went wrong&lt;/div&gt;} /&gt;
</code></pre>
</td>
    </tr>
    <tr>
      <td>FallbackComponent</td>
      <td><p>React component responsible for returning a fallback UI based on a thrown value.</p>
<pre><code class="language-tsx">&lt;ErrorBoundary FallbackComponent={Fallback} /&gt;
</code></pre>
</td>
    </tr>
    <tr>
      <td>fallbackRender</td>
      <td><p><a href="https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering">Render prop</a> function responsible for returning a fallback UI based on a thrown value.</p>
<pre><code class="language-tsx">&lt;ErrorBoundary fallbackRender={({ error, resetErrorBoundary }) =&gt; &lt;div&gt;...&lt;/div&gt;} /&gt;
</code></pre>
</td>
    </tr>
  </tbody>
</table>

<!-- ErrorBoundary:optional-props:end -->

# FAQ
## `ErrorBoundary` cannot be used as a JSX component
This error can be caused by a version mismatch between [react](https://npmjs.com/package/react) and [@types/react](https://npmjs.com/package/@types/react). To fix this, ensure that both match exactly, e.g.:

If using NPM:
```json
{
  ...
  "overrides": {
    "@types/react": "17.0.60"
  },
  ...
}
```

If using Yarn:
```json
{
  ...
  "resolutions": {
    "@types/react": "17.0.60"
  },
  ...
}
```

---

[This blog post](https://kentcdodds.com/blog/use-react-error-boundary-to-handle-errors-in-react) shows more examples of how this package can be used, although it was written for the [version 3 API](https://github.com/bvaughn/react-error-boundary/releases/tag/v3.1.4).


================================================
FILE: eslint.config.js
================================================
import js from "@eslint/js";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import { globalIgnores } from "eslint/config";
import globals from "globals";
import tseslint from "typescript-eslint";

export default tseslint.config([
  globalIgnores(["dist", "docs", "public/generated"]),
  {
    files: ["**/*.{ts,tsx}"],
    ignores: ["**/examples/*.{ts,tsx}"],
    extends: [
      js.configs.recommended,
      tseslint.configs.recommended,
      reactHooks.configs["recommended-latest"],
      reactRefresh.configs.vite,
    ],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
      parserOptions: {
        tsconfigRootDir: import.meta.dirname,
      },
    },
    rules: {
      "no-restricted-imports": [
        "error",
        {
          patterns: ["*/../lib/*", "node:test"],
        },
      ],
      "no-restricted-properties": [
        "error",
        {
          property: "clientHeight",
          message:
            "Using clientHeight is restricted; prefer offsetHeight or getBoundingClientRect()",
        },
        {
          property: "clientWidth",
          message:
            "Using clientWidth is restricted; prefer offsetWidth or getBoundingClientRect()",
        },
      ],
      "react-hooks/exhaustive-deps": [
        "error",
        {
          additionalHooks: "useIsomorphicLayoutEffect",
        },
      ],
      "@typescript-eslint/no-unused-vars": [
        "error",
        {
          args: "all",
          argsIgnorePattern: "^_",
          caughtErrors: "all",
          caughtErrorsIgnorePattern: "^_",
          destructuredArrayIgnorePattern: "^_",
          varsIgnorePattern: "^_",
          ignoreRestSiblings: true,
        },
      ],
    },
  },
]);


================================================
FILE: index.css
================================================
@source "node_modules/react-lib-tools";

@import "tailwindcss";
@import "react-lib-tools/styles.css";

@theme {
  --color-background-gradient-1: var(--color-fuchsia-400);
  --color-background-gradient-2: var(--color-purple-700);
  --color-background-gradient-3: var(--color-pink-500);
  --color-common-question-header: var(--color-fuchsia-200);
  --color-focus-1: var(--color-sky-300);
  --color-focus-2: var(--color-sky-400);
  --color-focus-3: var(--color-sky-600);
}


================================================
FILE: index.html
================================================
<!doctype html>
<html lang="en">
  <head>
    <title>react-error-boundary | runtime error handler</title>

    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />

    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
    />

    <meta property="og:type" content="website" />
    <meta property="og:site_name" content="react-error-boundary" />
    <meta
      property="og:title"
      content="react-error-boundary: runtime error handler"
    />
    <meta
      name="description"
      content="Documentation for the react-error-boundary NPM package"
    />
    <meta
      property="og:url"
      content="https://react-error-boundary-lib.vercel.app/"
    />
    <meta
      property="og:image"
      content="https://react-error-boundary-lib.vercel.app/og.png"
    />
    <meta property="og:image:width" content="1200" />
    <meta property="og:image:height" content="630" />
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/index.tsx"></script>
  </body>
</html>


================================================
FILE: index.tsx
================================================
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./src/App.tsx";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);


================================================
FILE: integrations/vite/README.md
================================================
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default tseslint.config({
  extends: [
    // Remove ...tseslint.configs.recommended and replace with this
    ...tseslint.configs.recommendedTypeChecked,
    // Alternatively, use this for stricter rules
    ...tseslint.configs.strictTypeChecked,
    // Optionally, add this for stylistic rules
    ...tseslint.configs.stylisticTypeChecked,
  ],
  languageOptions: {
    // other options...
    parserOptions: {
      project: ['./tsconfig.node.json', './tsconfig.app.json'],
      tsconfigRootDir: import.meta.dirname,
    },
  },
})
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default tseslint.config({
  plugins: {
    // Add the react-x and react-dom plugins
    'react-x': reactX,
    'react-dom': reactDom,
  },
  rules: {
    // other rules...
    // Enable its recommended typescript rules
    ...reactX.configs['recommended-typescript'].rules,
    ...reactDom.configs.recommended.rules,
  },
})
```


================================================
FILE: integrations/vite/eslint.config.js
================================================
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
  { ignores: ["dist"] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
      parserOptions: {
        tsconfigRootDir: import.meta.dirname,
      },
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "@typescript-eslint/no-unused-vars": [
        "error",
        {
          args: "all",
          argsIgnorePattern: "^_",
          caughtErrors: "all",
          caughtErrorsIgnorePattern: "^_",
          destructuredArrayIgnorePattern: "^_",
          varsIgnorePattern: "^_",
          ignoreRestSiblings: true,
        },
      ],
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
    },
  },
);


================================================
FILE: integrations/vite/index.html
================================================
<!doctype html>
<html class="dark" lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>[Vite] react-error-boundary integration</title>
  </head>
  <body class="bg-black text-white">
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>


================================================
FILE: integrations/vite/package.json
================================================
{
  "name": "vite",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite --port 3012",
    "build": "tsc -b && vite build",
    "test": "npx playwright test",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^19.2.3",
    "react-dom": "^19.2.3",
    "react-error-boundary": "workspace:*",
    "react-router": "^7"
  },
  "devDependencies": {
    "@eslint/js": "^9.25.0",
    "@playwright/test": "^1",
    "@tailwindcss/vite": "^4.1.17",
    "@types/react": "^19.1.2",
    "@types/react-dom": "^19.1.2",
    "@vitejs/plugin-react": "^4.4.1",
    "eslint": "^9.25.0",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.19",
    "globals": "^16.0.0",
    "tailwindcss": "^4.1.17",
    "typescript": "~5.8.3",
    "typescript-eslint": "^8.30.1",
    "vite": "^6.3.5"
  }
}


================================================
FILE: integrations/vite/playwright.config.ts
================================================
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  projects: [
    {
      name: "chromium",
      timeout: 5_000,
      use: {
        ...devices["Desktop Chrome"],
        viewport: { width: 1000, height: 600 },

        // Uncomment to visually debug
        // headless: false,
        // launchOptions: {
        //   slowMo: 500
        // }
      },
    },
  ],
});


================================================
FILE: integrations/vite/src/components/Children.tsx
================================================
import { useLayoutEffect, useState } from "react";

export type SizeProps = {
  height: number | undefined;
  width: number | undefined;
};

export const Children = function Children({
  height,
  onCommitLogsChange,
  width,
}: SizeProps & {
  onCommitLogsChange: (logs: SizeProps[]) => void;
}) {
  const [commitLogs, setCommitLogs] = useState<SizeProps[]>([]);

  useLayoutEffect(() => {
    setCommitLogs((prev) => [
      ...prev,
      {
        height:
          height === undefined ? undefined : parseFloat(height.toFixed(1)),
        width: width === undefined ? undefined : parseFloat(width.toFixed(1)),
      } as SizeProps,
    ]);
  }, [height, width]);

  useLayoutEffect(() => onCommitLogsChange(commitLogs));

  // Account for StrictMode double rendering on mount
  useLayoutEffect(
    () => () => {
      setCommitLogs([]);
    },
    [],
  );

  return (
    <div className="w-full h-full flex flex-col items-center justify-center p-1 text-white">
      {width} x {height} pixels
    </div>
  );
};


================================================
FILE: integrations/vite/src/components/Container.tsx
================================================
import { type PropsWithChildren } from "react";

export type ContainerProps = PropsWithChildren<{
  className?: string | undefined;
}>;

export function Container({ children, className }: ContainerProps) {
  return <div className={className}>{children}</div>;
}


================================================
FILE: integrations/vite/src/components/DebugData.tsx
================================================
import { cn } from "../utils/cn";

export function DebugData({ data }: { data: object }) {
  return (
    <pre
      className={cn(
        "p-2 resize-none rounded-md font-mono text-xs",
        "border border-2 border-slate-800 focus:outline-none focus:border-sky-700",
      )}
    >
      <code className="text-xs">{JSON.stringify(data, replacer, 2)}</code>
    </pre>
  );
}

function replacer(_key: string, value: unknown) {
  if (typeof value === "number") {
    return Math.round(value);
  }

  return value;
}


================================================
FILE: integrations/vite/src/components/Resizer.tsx
================================================
import { type PropsWithChildren } from "react";

export type ResizerProps = PropsWithChildren;

export function Resizer({ children: childrenProp }: ResizerProps) {
  // TODO
  return childrenProp;
}


================================================
FILE: integrations/vite/src/index.css
================================================
@import "tailwindcss";

@layer base {
  h1 {
    @apply mb-4 text-4xl font-bold tracking-tight text-gray-900;
  }
  ul {
    @apply list-disc pl-6;
  }
  ol {
    @apply list-decimal pl-6;
  }
  p {
    @apply mb-2 mt-2;
  }
  a {
    @apply text-blue-600 hover:text-pink-400 visited:text-blue-900;
  }
}

#root {
  height: 100vh;
}


================================================
FILE: integrations/vite/src/main.tsx
================================================
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter, Route, Routes } from "react-router";
import "./index.css";
import { Home } from "./routes/Home";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
      </Routes>
    </BrowserRouter>
  </StrictMode>,
);


================================================
FILE: integrations/vite/src/routes/Home.tsx
================================================
export function Home() {
  return <div className="w-full h-full">Coming soon...</div>;
}


================================================
FILE: integrations/vite/src/utils/assert.ts
================================================
export function assert(
  expectedCondition: unknown,
  message: string = "Assertion error",
): asserts expectedCondition {
  if (!expectedCondition) {
    console.error(message);

    throw Error(message);
  }
}


================================================
FILE: integrations/vite/src/utils/cn.ts
================================================
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}


================================================
FILE: integrations/vite/src/vite-env.d.ts
================================================
/// <reference types="vite/client" />


================================================
FILE: integrations/vite/test-results/.last-run.json
================================================
{
  "status": "passed",
  "failedTests": []
}


================================================
FILE: integrations/vite/tests/utils/calculateBoxBetween.ts
================================================
import type { Box } from "./types";

export function calculateBoxBetween(boxA: Box, boxB: Box): Box {
  if (boxA.y === boxB.y) {
    return {
      x: boxA.x + boxA.width,
      y: boxA.y,
      height: boxA.height,
      width: boxB.x - (boxA.x + boxA.width),
    };
  } else {
    return {
      x: boxA.x,
      y: boxA.y + boxA.height,
      height: boxB.y - (boxA.y + boxA.height),
      width: boxA.width,
    };
  }
}


================================================
FILE: integrations/vite/tests/utils/calculateHitArea.ts
================================================
import type { Page } from "@playwright/test";
import { calculateBoxBetween } from "./calculateBoxBetween";

export async function calculateHitArea(page: Page, panelIds: [string, string]) {
  const panelA = page.getByText(`id: ${panelIds[0]}`);
  const panelB = page.getByText(`id: ${panelIds[1]}`);

  const panelBoxA = (await panelA.boundingBox())!;
  const panelBoxB = (await panelB.boundingBox())!;

  return calculateBoxBetween(panelBoxA, panelBoxB);
}


================================================
FILE: integrations/vite/tests/utils/debugging/logDebugState.ts
================================================
import type { Page } from "@playwright/test";

export async function logDebugState(page: Page, prefix?: string) {
  const string = await page.evaluate(() =>
    Array.from(document.querySelectorAll("code"))
      .map((element) => element.outerHTML)
      .join("\n\n"),
  );

  console.log(prefix ? `${prefix}\n\n${string}` : string);
}


================================================
FILE: integrations/vite/tests/utils/debugging/logGroup.ts
================================================
import type { Page } from "@playwright/test";

export async function logGroup(page: Page) {
  console.log(
    await page.evaluate(
      () => document.querySelector("[data-group]")?.outerHTML,
    ),
  );
}


================================================
FILE: integrations/vite/tests/utils/expectLayout.ts
================================================
import { expect, type Page } from "@playwright/test";
import type { Layout } from "react-resizable-panels";

export async function expectLayout({
  layout,
  mainPage,
  onLayoutCount,
}: {
  layout: Layout;
  mainPage: Page;
  onLayoutCount: number;
}) {
  await expect(mainPage.getByText('"layout"')).toHaveText(
    JSON.stringify(
      {
        layout,
        onLayoutCount,
      },
      null,
      2,
    ),
  );
}


================================================
FILE: integrations/vite/tests/utils/expectPanelSize.ts
================================================
import { expect, type Page } from "@playwright/test";
import type { PanelSize } from "react-resizable-panels";

export async function expectPanelSize({
  mainPage,
  onResizeCount,
  panelId,
  panelSize,
  prevPanelSize,
}: {
  mainPage: Page;
  onResizeCount: number;
  panelId: string | number;
  panelSize: PanelSize;
  prevPanelSize?: PanelSize | undefined;
}) {
  const locator = mainPage.getByText(`"panelId": "${panelId}"`);

  const text = JSON.stringify(
    {
      panelId,
      onResizeCount,
      panelSize,
      prevPanelSize,
    },
    null,
    2,
  );

  await expect(locator).toHaveText(text);
}


================================================
FILE: integrations/vite/tests/utils/getCenterCoordinates.ts
================================================
import type { Box, Coordinates } from "./types";

export function getCenterCoordinates(box: Box): Coordinates {
  return {
    x: box.x + box.width / 2,
    y: box.y + box.height / 2,
  };
}


================================================
FILE: integrations/vite/tests/utils/getSeparatorAriaAttributes.ts
================================================
import type { Page } from "@playwright/test";

export async function getSeparatorAriaAttributes(page: Page, id?: string) {
  return page.evaluate(
    ([id]) => {
      const element = document.querySelector(
        id ? `[data-testid="${id}"]` : '[role="separator"]',
      );

      return {
        "aria-controls": element?.getAttribute("aria-controls"),
        "aria-valuemax": element?.getAttribute("aria-valuemax"),
        "aria-valuemin": element?.getAttribute("aria-valuemin"),
        "aria-valuenow": element?.getAttribute("aria-valuenow"),
      };
    },
    [id],
  );
}


================================================
FILE: integrations/vite/tests/utils/goToUrl.ts
================================================
import type { Page } from "@playwright/test";
import { createElement, type ReactElement } from "react";
import { PopupWindow } from "../../src/components/PopupWindow";
import { encode } from "./serializer/encode";

export async function goToUrl(
  page: Page,
  elementProp: ReactElement<unknown>,
  config: {
    useGroupCallbackRef?: boolean | undefined;
    useGroupRef?: boolean | undefined;
    usePanelCallbackRef?: boolean | undefined;
    usePanelRef?: boolean | undefined;
    usePopUpWindow?: boolean | undefined;
  } = {},
): Promise<Page> {
  const {
    useGroupCallbackRef = false,
    useGroupRef = false,
    usePanelCallbackRef = false,
    usePanelRef = false,
    usePopUpWindow = false,
  } = config;

  let element = elementProp;
  let encodedString = "";
  if (element) {
    if (usePopUpWindow) {
      element = createElement(PopupWindow, {
        children: element,
        className: "dark",
      });
    }

    encodedString = encode(element);
  }

  const queryParams = [
    useGroupCallbackRef ? "useGroupCallbackRef" : undefined,
    useGroupRef ? "useGroupRef" : undefined,
    usePanelCallbackRef ? "usePanelCallbackRef" : undefined,
    usePanelRef ? "usePanelRef" : undefined,
  ]
    .filter(Boolean)
    .join("&");

  const url = new URL(
    `http://localhost:3012/e2e/decoder/${encodedString}?${queryParams}`,
  );

  // Uncomment when testing for easier repro
  console.log("\n\n" + url.toString());

  await page.goto(url.toString());

  if (usePopUpWindow) {
    const popupPromise = page.waitForEvent("popup");

    await page.getByRole("button").click();

    return await popupPromise;
  }

  return page;
}


================================================
FILE: integrations/vite/tests/utils/goToUrlWithIframe.ts
================================================
import type { Page } from "@playwright/test";
import type { ReactElement } from "react";
import type { GroupProps } from "react-resizable-panels";
import { encode } from "./serializer/encode";

export async function goToUrlWithIframe(
  page: Page,
  element: ReactElement<GroupProps>,
  sameOrigin: boolean,
) {
  const encodedString = encode(element);

  const url = new URL("http://localhost:3012/e2e/decoder/iframe");
  url.searchParams.set("urlPanelGroup", encodedString);
  if (sameOrigin) {
    url.searchParams.set("sameOrigin", "");
  }

  // Uncomment when testing for easier repros
  // console.log(url.toString());

  await page.goto(url.toString());
}


================================================
FILE: integrations/vite/tests/utils/pointer-interactions/resizeHelper.ts
================================================
import type { Page } from "@playwright/test";
import { calculateHitArea } from "../calculateHitArea";
import { getCenterCoordinates } from "../getCenterCoordinates";

export async function resizeHelper(
  page: Page,
  panelIds: [string, string],
  deltaX: number = 0,
  deltaY: number = 0,
) {
  const hitAreaBox = await calculateHitArea(page, panelIds);

  const centerCoordinates = getCenterCoordinates(hitAreaBox);
  const destinationCoordinates = {
    x: centerCoordinates.x + deltaX,
    y: centerCoordinates.y + deltaY,
  };

  await page.mouse.move(centerCoordinates.x, centerCoordinates.y);
  await page.mouse.down();
  await page.mouse.move(destinationCoordinates.x, destinationCoordinates.y, {
    steps: 1,
  });
  await page.mouse.up();
}


================================================
FILE: integrations/vite/tests/utils/serializer/decode.ts
================================================
import { createElement, type ReactElement } from "react";
import type {
  GroupProps,
  PanelProps,
  SeparatorProps,
} from "react-resizable-panels";
import { Container } from "../../../src/components/Container";
import { DisplayModeToggle } from "../../../src/components/DisplayModeToggle";
import { Group } from "../../../src/components/Group";
import { Panel } from "../../../src/components/Panel";
import { PopupWindow } from "../../../src/components/PopupWindow";
import { Separator } from "../../../src/components/Separator";
import type {
  EncodedContainerElement,
  EncodedDisplayModeToggleElement,
  EncodedElement,
  EncodedGroupElement,
  EncodedPanelElement,
  EncodedPopupWindowElement,
  EncodedSeparatorElement,
  EncodedTextElement,
  TextProps,
} from "./types";

type Config = {
  groupProps?: Partial<GroupProps>;
  panelProps?: Partial<PanelProps>;
};

let key = 0;

export function decode(stringified: string, config: Config = {}) {
  const json = JSON.parse(stringified) as EncodedElement[];

  return decodeChildren(json, config);
}

function decodeChildren(
  children: EncodedElement[],
  config: Config,
): ReactElement<unknown>[] {
  const elements: ReactElement<unknown>[] = [];

  children.forEach((current) => {
    if (!current) {
      return;
    }

    switch (current.type) {
      case "Container": {
        elements.push(decodeContainer(current, config));
        break;
      }
      case "DisplayModeToggle": {
        elements.push(decodeDisplayModeToggle(current, config));
        break;
      }
      case "Group": {
        elements.push(decodeGroup(current, config));
        break;
      }
      case "Panel": {
        elements.push(decodePanel(current, config));
        break;
      }
      case "PopupWindow": {
        elements.push(decodePopupWindow(current, config));
        break;
      }
      case "Separator": {
        elements.push(decodeSeparator(current));
        break;
      }
      case "Text": {
        elements.push(decodeText(current));
        break;
      }
      default: {
        console.warn("Could not decode type:", current);
      }
    }
  });

  return elements;
}

function decodeContainer(
  json: EncodedContainerElement,
  config: Config,
): ReactElement<unknown> {
  const { children, ...props } = json.props;

  return createElement(Container, {
    key: ++key,
    ...props,
    ...config.panelProps,
    children: children ? decodeChildren(children, config) : undefined,
  });
}

function decodeDisplayModeToggle(
  json: EncodedDisplayModeToggleElement,
  config: Config,
): ReactElement<unknown> {
  const { children, ...props } = json.props;

  return createElement(DisplayModeToggle, {
    key: ++key,
    ...props,
    ...config.panelProps,
    children: children ? decodeChildren(children, config) : undefined,
  });
}

function decodeGroup(
  json: EncodedGroupElement,
  config: Config,
): ReactElement<PanelProps> {
  const { children, ...props } = json.props;

  return createElement(Group, {
    key: ++key,
    ...props,
    ...config.groupProps,
    children: children ? decodeChildren(children, config) : undefined,
  });
}

function decodePanel(
  json: EncodedPanelElement,
  config: Config,
): ReactElement<PanelProps> {
  const { children, ...props } = json.props;

  return createElement(Panel, {
    key: ++key,
    ...props,
    ...config.panelProps,
    children: children ? decodeChildren(children, config) : undefined,
  });
}

function decodePopupWindow(
  json: EncodedPopupWindowElement,
  config: Config,
): ReactElement<unknown> {
  const { children, ...props } = json.props;

  return createElement(PopupWindow, {
    key: ++key,
    ...props,
    ...config.panelProps,
    children: children ? decodeChildren(children, config) : undefined,
  });
}

function decodeSeparator(
  json: EncodedSeparatorElement,
): ReactElement<SeparatorProps> {
  return createElement(Separator, {
    key: ++key,
    ...json.props,
  });
}

function decodeText(json: EncodedTextElement): ReactElement<TextProps> {
  return createElement("div", {
    key: ++key,
    ...json.props,
  });
}


================================================
FILE: integrations/vite/tests/utils/serializer/encode.ts
================================================
import { type PropsWithChildren, type ReactElement } from "react";
import {
  Group,
  Panel,
  Separator,
  type GroupProps,
  type PanelProps,
  type SeparatorProps,
} from "react-resizable-panels";
import {
  Container,
  type ContainerProps,
} from "../../../src/components/Container";
import {
  DisplayModeToggle,
  type DisplayModeToggleProps,
} from "../../../src/components/DisplayModeToggle";
import {
  PopupWindow,
  type PopupWindowProps,
} from "../../../src/components/PopupWindow";
import type {
  EncodedContainerElement,
  EncodedDisplayModeToggleElement,
  EncodedElement,
  EncodedGroupElement,
  EncodedPanelElement,
  EncodedPopupWindowElement,
  EncodedSeparatorElement,
  EncodedTextElement,
  TextProps,
} from "./types";

export function encode(element: ReactElement<unknown>) {
  const json = encodeChildren([element]);
  const stringified = JSON.stringify(json);

  return encodeURIComponent(stringified);
}

function encodeChildren(children: ReactElement<unknown>[]): EncodedElement[] {
  const elements: EncodedElement[] = [];

  children.forEach((current) => {
    if (!current) {
      return;
    }

    switch (current.type) {
      case Container: {
        elements.push(encodeContainer(current as ReactElement<ContainerProps>));
        break;
      }
      case DisplayModeToggle: {
        elements.push(
          encodeDisplayModeToggle(
            current as ReactElement<DisplayModeToggleProps>,
          ),
        );
        break;
      }
      case Group: {
        elements.push(encodeGroup(current as ReactElement<GroupProps>));
        break;
      }
      case Panel: {
        elements.push(encodePanel(current as ReactElement<PanelProps>));
        break;
      }
      case PopupWindow: {
        elements.push(
          encodePopupWindow(current as ReactElement<PropsWithChildren>),
        );
        break;
      }
      case Separator: {
        elements.push(encodeSeparator(current as ReactElement<SeparatorProps>));
        break;
      }
      default: {
        if (typeof current === "object") {
          const { children } = current.props as TextProps;
          if (typeof children === "string") {
            elements.push(encodeTextChild(current as ReactElement<TextProps>));
          } else {
            console.warn("Could not encode type:", current);
          }
        }
      }
    }
  });

  return elements;
}

function encodeContainer(
  element: ReactElement<ContainerProps>,
): EncodedContainerElement {
  const { children, ...props } = element.props;

  const encodedChildren = encodeChildren(
    Array.isArray(children) ? children : [children],
  );

  return {
    props: {
      ...props,
      children: encodedChildren.length > 0 ? encodedChildren : undefined,
    },
    type: "Container",
  };
}

function encodeDisplayModeToggle(
  element: ReactElement<DisplayModeToggleProps>,
): EncodedDisplayModeToggleElement {
  const { children, ...props } = element.props;

  const encodedChildren = encodeChildren(
    Array.isArray(children) ? children : [children],
  );

  return {
    props: {
      ...props,
      children: encodedChildren.length > 0 ? encodedChildren : undefined,
    },
    type: "DisplayModeToggle",
  };
}

function encodeGroup(element: ReactElement<GroupProps>): EncodedGroupElement {
  const { children, onLayoutChange: _, ...props } = element.props;

  const encodedChildren = encodeChildren(
    Array.isArray(children) ? children : [children],
  );

  return {
    props: {
      ...props,
      children: encodedChildren.length > 0 ? encodedChildren : undefined,
    },
    type: "Group",
  };
}

function encodePanel(element: ReactElement<PanelProps>): EncodedPanelElement {
  const { children, onResize: __, ...props } = element.props;

  const encodedChildren = encodeChildren(
    Array.isArray(children) ? children : [children],
  );

  return {
    props: {
      ...props,
      children: encodedChildren.length > 0 ? encodedChildren : undefined,
    },
    type: "Panel",
  };
}

function encodePopupWindow(
  element: ReactElement<PopupWindowProps>,
): EncodedPopupWindowElement {
  const { children, ...props } = element.props;

  const encodedChildren = encodeChildren(
    Array.isArray(children) ? children : [children],
  );

  return {
    props: {
      ...props,
      children: encodedChildren.length > 0 ? encodedChildren : undefined,
    },
    type: "PopupWindow",
  };
}

function encodeSeparator(
  element: ReactElement<SeparatorProps>,
): EncodedSeparatorElement {
  const { children: _, ...props } = element.props;

  return {
    type: "Separator",
    props,
  };
}

function encodeTextChild(element: ReactElement<TextProps>): EncodedTextElement {
  return {
    props: {
      children: element.props.children,
      className: element.props.className,
    },
    type: "Text",
  };
}


================================================
FILE: integrations/vite/tests/utils/serializer/types.ts
================================================
import type {
  GroupProps,
  PanelProps,
  SeparatorProps,
} from "react-resizable-panels";
import type { ContainerProps } from "../../../src/components/Container";
import type { DisplayModeToggleProps } from "../../../src/components/DisplayModeToggle";
import type { PopupWindowProps } from "../../../src/components/PopupWindow";

type EncodedElementWithChildren<Props extends object = object> = Omit<
  Props,
  "children"
> & { children?: EncodedElement[] | undefined };

export interface EncodedContainerElement {
  props: EncodedElementWithChildren<ContainerProps>;
  type: "Container";
}

export interface EncodedDisplayModeToggleElement {
  props: EncodedElementWithChildren<DisplayModeToggleProps>;
  type: "DisplayModeToggle";
}

export interface EncodedGroupElement {
  props: EncodedElementWithChildren<GroupProps>;
  type: "Group";
}

export interface EncodedPanelElement {
  props: EncodedElementWithChildren<PanelProps>;
  type: "Panel";
}

export interface EncodedPopupWindowElement {
  props: EncodedElementWithChildren<PopupWindowProps>;
  type: "PopupWindow";
}

export interface EncodedSeparatorElement {
  props: SeparatorProps;
  type: "Separator";
}

export type TextProps = {
  children: string;
  className?: string | undefined;
};

export interface EncodedTextElement {
  props: TextProps;
  type: "Text";
}

export type EncodedElement =
  | EncodedContainerElement
  | EncodedDisplayModeToggleElement
  | EncodedGroupElement
  | EncodedPanelElement
  | EncodedPopupWindowElement
  | EncodedSeparatorElement
  | EncodedTextElement;


================================================
FILE: integrations/vite/tests/utils/types.ts
================================================
export type Box = {
  x: number;
  y: number;
  width: number;
  height: number;
};

export type Coordinates = {
  x: number;
  y: number;
};


================================================
FILE: integrations/vite/tests/utils/updateUrl.ts
================================================
import type { Page } from "@playwright/test";
import type { ReactElement } from "react";
import type { GroupProps } from "react-resizable-panels";
import { encode } from "./serializer/encode";

export async function updateUrl(
  page: Page,
  element: ReactElement<GroupProps> | null,
) {
  const encodedString = element ? encode(element) : "";

  await page.evaluate(
    ([encodedString]) => {
      const url = new URL(window.location.href);
      url.searchParams.set("urlPanelGroup", encodedString ?? "");

      window.history.pushState(
        { urlPanelGroup: encodedString },
        "",
        url.toString(),
      );

      window.dispatchEvent(new Event("popstate"));
    },
    [encodedString],
  );
}


================================================
FILE: integrations/vite/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "erasableSyntaxOnly": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true
  },
  "include": ["src"]
}


================================================
FILE: integrations/vite/vite.config.ts
================================================
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

// https://vite.dev/config/
export default defineConfig({
  plugins: [react(), tailwindcss()],
  server: {
    cors: true,
  },
});


================================================
FILE: lib/components/ErrorBoundary.test.tsx
================================================
import {
  createRef,
  type PropsWithChildren,
  type ReactElement,
  type RefObject,
} from "react";
import { createRoot } from "react-dom/client";
import { act } from "react-dom/test-utils";
import { beforeEach, describe, expect, it, vi, type Mock } from "vitest";
import { assert } from "../utils/assert";
import { ErrorBoundary } from "./ErrorBoundary";
import type {
  ErrorBoundaryPropsWithComponent,
  ErrorBoundaryPropsWithFallback,
  ErrorBoundaryPropsWithRender,
  FallbackProps,
  OnErrorCallback,
} from "../types";
import { getErrorMessage } from "../utils/getErrorMessage";

describe("ErrorBoundary", () => {
  let container: HTMLDivElement;
  let root: ReturnType<typeof createRoot>;
  let shouldThrow = true;
  let valueToThrow: unknown;

  beforeEach(() => {
    // @ts-expect-error This is a React internal
    global.IS_REACT_ACT_ENVIRONMENT = true;

    // Don't clutter the console with expected error text
    vi.spyOn(console, "error").mockImplementation(() => {
      // No-op
    });

    container = document.createElement("div");
    root = createRoot(container);
    shouldThrow = false;
    valueToThrow = new Error("💥💥💥");
  });

  function MaybeThrows({ children }: PropsWithChildren) {
    if (shouldThrow) {
      throw valueToThrow;
    }
    return children;
  }

  it("should render children", () => {
    const container = document.createElement("div");
    const root = createRoot(container);
    act(() => {
      root.render(
        <ErrorBoundary fallback={<div>Error</div>}>
          <MaybeThrows>Content</MaybeThrows>
        </ErrorBoundary>,
      );
    });

    expect(container.textContent).toBe("Content");
  });

  describe("fallback props", () => {
    let errorBoundaryRef: RefObject<ErrorBoundary | null>;

    beforeEach(() => {
      errorBoundaryRef = createRef<ErrorBoundary | null>();
    });

    function render(props: Omit<ErrorBoundaryPropsWithFallback, "fallback">) {
      act(() => {
        root.render(
          <ErrorBoundary {...props} fallback="Error" ref={errorBoundaryRef}>
            <MaybeThrows>Content</MaybeThrows>
          </ErrorBoundary>,
        );
      });
    }

    it('should call "onError" prop if one is provided', () => {
      shouldThrow = true;

      const onError: Mock<OnErrorCallback> = vi.fn();

      render({ onError });

      expect(onError).toHaveBeenCalledTimes(1);
      expect(getErrorMessage(onError.mock.calls[0][0])).toEqual("💥💥💥");
    });

    it('should call "onReset" when boundary reset via imperative API', () => {
      shouldThrow = true;

      const onReset: Mock<(...args: unknown[]) => unknown> = vi.fn();

      render({ onReset });
      expect(onReset).not.toHaveBeenCalled();

      act(() => errorBoundaryRef.current?.resetErrorBoundary("abc", 123));

      expect(onReset).toHaveBeenCalledTimes(1);
    });

    it('should call "onReset" when boundary reset via "resetKeys"', () => {
      shouldThrow = false;

      const onReset: Mock<(...args: unknown[]) => unknown> = vi.fn();

      render({ onReset, resetKeys: [1] });
      expect(onReset).not.toHaveBeenCalled();

      // It should not be called if the keys change without an error
      render({ onReset, resetKeys: [2] });
      expect(onReset).not.toHaveBeenCalled();

      shouldThrow = true;

      render({ onReset, resetKeys: [2] });
      expect(onReset).not.toHaveBeenCalled();

      shouldThrow = false;

      render({ onReset, resetKeys: [3] });
      expect(onReset).toHaveBeenCalledTimes(1);
    });
  });

  describe('"fallback" element', () => {
    function render(
      props: Omit<ErrorBoundaryPropsWithFallback, "fallback"> = {},
    ) {
      act(() => {
        root.render(
          <ErrorBoundary {...props} fallback={<div>Error</div>}>
            <MaybeThrows>Content</MaybeThrows>
          </ErrorBoundary>,
        );
      });
    }

    it("should render fallback in the event of an error", () => {
      shouldThrow = true;
      render();
      expect(container.textContent).toBe("Error");
    });

    it("should re-render children if boundary is reset reset keys", () => {
      shouldThrow = true;
      render({ resetKeys: [1] });

      shouldThrow = false;
      expect(container.textContent).toBe("Error");

      render({ resetKeys: [2] });
      expect(container.textContent).toBe("Content");
    });

    it("should render a null fallback if specified", () => {
      shouldThrow = true;
      act(() => {
        root.render(
          <ErrorBoundary fallback={null}>
            <MaybeThrows>Content</MaybeThrows>
          </ErrorBoundary>,
        );
      });
      expect(container.textContent).toBe("");
    });
  });

  describe('"FallbackComponent"', () => {
    let fallbackComponent: Mock<(props: FallbackProps) => ReactElement>;
    let lastRenderedError: unknown | null = null;
    let lastRenderedResetErrorBoundary:
      | FallbackProps["resetErrorBoundary"]
      | null = null;

    function render(
      props: Omit<ErrorBoundaryPropsWithComponent, "FallbackComponent"> = {},
    ) {
      act(() => {
        root.render(
          <ErrorBoundary {...props} FallbackComponent={fallbackComponent}>
            <MaybeThrows>Content</MaybeThrows>
          </ErrorBoundary>,
        );
      });
    }

    beforeEach(() => {
      lastRenderedError = null;
      lastRenderedResetErrorBoundary = null;

      fallbackComponent = vi.fn();
      fallbackComponent.mockImplementation(
        ({ error, resetErrorBoundary }: FallbackProps) => {
          lastRenderedError = error;
          lastRenderedResetErrorBoundary = resetErrorBoundary;

          return <div>FallbackComponent</div>;
        },
      );
    });

    it("should render fallback in the event of an error", () => {
      shouldThrow = true;
      render();
      expect(getErrorMessage(lastRenderedError)).toBe("💥💥💥");
      expect(container.textContent).toBe("FallbackComponent");
    });

    it("should re-render children if boundary is reset via prop", () => {
      shouldThrow = true;
      render();
      expect(container.textContent).toBe("FallbackComponent");

      expect(lastRenderedResetErrorBoundary).not.toBeNull();
      act(() => {
        shouldThrow = false;
        assert(lastRenderedResetErrorBoundary !== null);
        lastRenderedResetErrorBoundary();
      });

      expect(container.textContent).toBe("Content");
    });

    it("should re-render children if boundary is reset reset keys", () => {
      shouldThrow = true;
      render({ resetKeys: [1] });
      expect(container.textContent).toBe("FallbackComponent");

      shouldThrow = false;
      render({ resetKeys: [2] });
      expect(container.textContent).toBe("Content");
    });
  });

  describe('"fallbackRender" render prop', () => {
    let lastRenderedError: unknown | null = null;
    let lastRenderedResetErrorBoundary:
      | FallbackProps["resetErrorBoundary"]
      | null = null;
    let fallbackRender: Mock<(props: FallbackProps) => ReactElement>;

    function render(
      props: Omit<ErrorBoundaryPropsWithRender, "fallbackRender"> = {},
    ) {
      act(() => {
        root.render(
          <ErrorBoundary {...props} fallbackRender={fallbackRender}>
            <MaybeThrows>Content</MaybeThrows>
          </ErrorBoundary>,
        );
      });
    }

    beforeEach(() => {
      lastRenderedError = null;
      lastRenderedResetErrorBoundary = null;

      fallbackRender = vi.fn();
      fallbackRender.mockImplementation(
        ({ error, resetErrorBoundary }: FallbackProps) => {
          lastRenderedError = error;
          lastRenderedResetErrorBoundary = resetErrorBoundary;

          return <div>fallbackRender</div>;
        },
      );
    });

    it("should render fallback in the event of an error", () => {
      shouldThrow = true;
      render();
      expect(getErrorMessage(lastRenderedError)).toBe("💥💥💥");
      expect(fallbackRender).toHaveBeenCalled();
      expect(container.textContent).toBe("fallbackRender");
    });

    it("should re-render children if boundary is reset via prop", () => {
      shouldThrow = true;
      render();
      expect(getErrorMessage(lastRenderedError)).toBe("💥💥💥");
      expect(fallbackRender).toHaveBeenCalled();
      expect(container.textContent).toBe("fallbackRender");

      act(() => {
        shouldThrow = false;
        assert(lastRenderedResetErrorBoundary !== null);
        lastRenderedResetErrorBoundary();
      });

      expect(container.textContent).toBe("Content");
    });

    it("should re-render children if boundary is reset reset keys", () => {
      shouldThrow = true;
      render({ resetKeys: [1] });
      expect(getErrorMessage(lastRenderedError)).toBe("💥💥💥");
      expect(fallbackRender).toHaveBeenCalled();
      expect(container.textContent).toBe("fallbackRender");

      shouldThrow = false;
      render({ resetKeys: [2] });
      expect(container.textContent).toBe("Content");
    });
  });

  describe("thrown values", () => {
    let lastRenderedError: unknown | null = null;
    let fallbackRender: (props: FallbackProps) => ReactElement;
    let onError: Mock<(...args: unknown[]) => unknown>;

    beforeEach(() => {
      lastRenderedError = null;

      onError = vi.fn();

      fallbackRender = ({ error }: FallbackProps) => {
        lastRenderedError = error;

        return <div>Error</div>;
      };
    });

    function render() {
      act(() => {
        root.render(
          <ErrorBoundary fallbackRender={fallbackRender} onError={onError}>
            <MaybeThrows>Content</MaybeThrows>
          </ErrorBoundary>,
        );
      });
    }

    it("should support thrown strings", () => {
      shouldThrow = true;
      valueToThrow = "String error";

      render();

      expect(lastRenderedError).toBe("String error");
      expect(onError).toHaveBeenCalledTimes(1);
      expect(onError.mock.calls[0][0]).toEqual("String error");
      expect(container.textContent).toBe("Error");
    });

    it("should support thrown null or undefined values", () => {
      shouldThrow = true;
      valueToThrow = null;

      render();

      expect(lastRenderedError).toBe(null);
      expect(onError).toHaveBeenCalledTimes(1);
      expect(onError.mock.calls[0][0]).toEqual(null);
      expect(container.textContent).toBe("Error");
    });
  });

  // TODO Various cases with resetKeys changing (length, order, etc)
  // TODO Errors thrown again after reset are caught
  // TODO Nested error boundaries if a fallback throws
});


================================================
FILE: lib/components/ErrorBoundary.tsx
================================================
import { Component, createElement, type ErrorInfo } from "react";
import { ErrorBoundaryContext } from "../context/ErrorBoundaryContext";
import type { ErrorBoundaryProps, FallbackProps } from "../types";

const isDevelopment = import.meta.env.DEV;

type ErrorBoundaryState =
  | {
      didCatch: true;
      error: unknown;
    }
  | {
      didCatch: false;
      error: null;
    };

const initialState: ErrorBoundaryState = {
  didCatch: false,
  error: null,
};

/**
 * A reusable React [error boundary](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) component.
 * Wrap this component around other React components to "catch" errors and render a fallback UI.
 *
 * This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),
 * so it has all of the advantages and constraints of that API.
 * This means that it can't catch errors during:
 * - Server side rendering</li>
 * - Event handlers
 * - Asynchronous code (including effects)
 *
 * ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.
 * Refer to the documentation to determine which is best for your application.
 *
 * ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `"use client";` directive.
 */
export class ErrorBoundary extends Component<
  ErrorBoundaryProps,
  ErrorBoundaryState
> {
  constructor(props: ErrorBoundaryProps) {
    super(props);

    this.resetErrorBoundary = this.resetErrorBoundary.bind(this);
    this.state = initialState;
  }

  static getDerivedStateFromError(error: Error) {
    return { didCatch: true, error };
  }

  resetErrorBoundary(...args: unknown[]) {
    const { error } = this.state;

    if (error !== null) {
      this.props.onReset?.({
        args,
        reason: "imperative-api",
      });

      this.setState(initialState);
    }
  }

  componentDidCatch(error: unknown, info: ErrorInfo) {
    this.props.onError?.(error, info);
  }

  componentDidUpdate(
    prevProps: ErrorBoundaryProps,
    prevState: ErrorBoundaryState,
  ) {
    const { didCatch } = this.state;
    const { resetKeys } = this.props;

    // There's an edge case where if the thing that triggered the error happens to *also* be in the resetKeys array,
    // we'd end up resetting the error boundary immediately.
    // This would likely trigger a second error to be thrown.
    // So we make sure that we don't check the resetKeys on the first call of cDU after the error is set.

    if (
      didCatch &&
      prevState.error !== null &&
      hasArrayChanged(prevProps.resetKeys, resetKeys)
    ) {
      this.props.onReset?.({
        next: resetKeys,
        prev: prevProps.resetKeys,
        reason: "keys",
      });

      this.setState(initialState);
    }
  }

  render() {
    const { children, fallbackRender, FallbackComponent, fallback } =
      this.props;
    const { didCatch, error } = this.state;

    let childToRender = children;

    if (didCatch) {
      const props: FallbackProps = {
        error,
        resetErrorBoundary: this.resetErrorBoundary,
      };

      if (typeof fallbackRender === "function") {
        childToRender = fallbackRender(props);
      } else if (FallbackComponent) {
        childToRender = createElement(FallbackComponent, props);
      } else if (fallback !== undefined) {
        childToRender = fallback;
      } else {
        if (isDevelopment) {
          console.error(
            "react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop",
          );
        }

        throw error;
      }
    }

    return createElement(
      ErrorBoundaryContext.Provider,
      {
        value: {
          didCatch,
          error,
          resetErrorBoundary: this.resetErrorBoundary,
        },
      },
      childToRender,
    );
  }
}

function hasArrayChanged(a: unknown[] = [], b: unknown[] = []) {
  return (
    a.length !== b.length || a.some((item, index) => !Object.is(item, b[index]))
  );
}


================================================
FILE: lib/context/ErrorBoundaryContext.ts
================================================
import { createContext } from "react";

export type ErrorBoundaryContextType = {
  didCatch: boolean;
  error: unknown | null;
  resetErrorBoundary: (...args: unknown[]) => void;
};

export const ErrorBoundaryContext =
  createContext<ErrorBoundaryContextType | null>(null);


================================================
FILE: lib/hooks/useErrorBoundary.test.tsx
================================================
import { act, useLayoutEffect, type ReactNode } from "react";
import { createRoot } from "react-dom/client";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { ErrorBoundary } from "../components/ErrorBoundary";
import { assert } from "../utils/assert";
import { getErrorMessage } from "../utils/getErrorMessage";
import { useErrorBoundary, type UseErrorBoundaryApi } from "./useErrorBoundary";

describe("useErrorBoundary", () => {
  let container: HTMLDivElement;

  beforeEach(() => {
    vi.spyOn(console, "error").mockImplementation(() => {
      // Don't clutter the console with expected error text
    });

    container = document.createElement("div");
  });

  function render(content: ReactNode) {
    const root = createRoot(container);
    act(() => {
      root.render(content);
    });
    return root;
  }

  it("should activate and deactivate the nearest error boundary", () => {
    let resetBoundaryFn: UseErrorBoundaryApi["resetBoundary"] | null = null;
    let showBoundaryFn: UseErrorBoundaryApi["showBoundary"] | null = null;

    function Child() {
      const { resetBoundary, showBoundary } = useErrorBoundary();

      useLayoutEffect(() => {
        resetBoundaryFn = resetBoundary;
        showBoundaryFn = showBoundary;
      }, [resetBoundary, showBoundary]);

      return <div>Child</div>;
    }

    render(
      <ErrorBoundary
        fallbackRender={({ error }) => (
          <div>Fallback: {getErrorMessage(error)}</div>
        )}
      >
        <Child />
      </ErrorBoundary>,
    );
    expect(container.textContent).toBe("Child");

    act(() => {
      assert(showBoundaryFn != null);
      showBoundaryFn(new Error("Example"));
    });
    expect(container.textContent).toBe("Fallback: Example");

    act(() => {
      assert(resetBoundaryFn != null);
      resetBoundaryFn();
    });
    expect(container.textContent).toBe("Child");
  });

  it("should expose the current error to a fallback component", () => {
    const errorToThrow = new Error("Thrown");

    function Child() {
      const { error } = useErrorBoundary();
      expect(error).toBe(null);

      throw errorToThrow;

      return null;
    }

    function Fallback() {
      const { error } = useErrorBoundary();
      expect(error).toBe(errorToThrow);

      return "Fallback";
    }

    render(
      <ErrorBoundary FallbackComponent={Fallback}>
        <Child />
      </ErrorBoundary>,
    );

    expect(container.textContent).toBe("Fallback");
  });
});


================================================
FILE: lib/hooks/useErrorBoundary.ts
================================================
import { useContext, useMemo, useState } from "react";
import { ErrorBoundaryContext } from "../context/ErrorBoundaryContext";
import { assertErrorBoundaryContext } from "../utils/assertErrorBoundaryContext";

type UseErrorBoundaryState =
  | { error: unknown; hasError: true }
  | { error: null; hasError: false };

export type UseErrorBoundaryApi = {
  error: unknown | null;
  resetBoundary: () => void;
  showBoundary: (error: unknown) => void;
};

/**
 * Convenience hook for imperatively showing or dismissing error boundaries.
 *
 * ⚠️ This hook must only be used within an `ErrorBoundary` subtree.
 */
export function useErrorBoundary(): {
  /**
   * The currently visible `Error` (if one has been thrown).
   */
  error: unknown | null;

  /**
   * Method to reset and retry the nearest active error boundary (if one is active).
   */
  resetBoundary: () => void;

  /**
   * Trigger the nearest error boundary to display the error provided.
   *
   * ℹ️ React only handles errors thrown during render or during component lifecycle methods (e.g. effects and did-mount/did-update).
   * Errors thrown in event handlers, or after async code has run, will not be caught.
   * This method is a way to imperatively trigger an error boundary during these phases.
   */
  showBoundary: (error: unknown) => void;
} {
  const context = useContext(ErrorBoundaryContext);

  assertErrorBoundaryContext(context);

  const { error, resetErrorBoundary } = context;

  const [state, setState] = useState<UseErrorBoundaryState>({
    error: null,
    hasError: false,
  });

  const memoized = useMemo(
    () => ({
      error,
      resetBoundary: () => {
        resetErrorBoundary();
        setState({ error: null, hasError: false });
      },
      showBoundary: (error: unknown) =>
        setState({
          error,
          hasError: true,
        }),
    }),
    [error, resetErrorBoundary],
  );

  if (state.hasError) {
    throw state.error;
  }

  return memoized;
}


================================================
FILE: lib/index.ts
================================================
"use client";

export { ErrorBoundary } from "./components/ErrorBoundary";
export { ErrorBoundaryContext } from "./context/ErrorBoundaryContext";
export { useErrorBoundary } from "./hooks/useErrorBoundary";
export { getErrorMessage } from "./utils/getErrorMessage";
export { withErrorBoundary } from "./utils/withErrorBoundary";

export type { ErrorBoundaryContextType } from "./context/ErrorBoundaryContext";
export type { UseErrorBoundaryApi } from "./hooks/useErrorBoundary";
export type {
  ErrorBoundaryProps,
  ErrorBoundaryPropsWithComponent,
  ErrorBoundaryPropsWithFallback,
  ErrorBoundaryPropsWithRender,
  FallbackProps,
  OnErrorCallback,
} from "./types";


================================================
FILE: lib/types.ts
================================================
import type {
  ComponentType,
  ErrorInfo,
  PropsWithChildren,
  ReactNode,
} from "react";

export type FallbackProps = {
  error: unknown;
  resetErrorBoundary: (...args: unknown[]) => void;
};

export type OnErrorCallback = (error: unknown, info: ErrorInfo) => void;

type ErrorBoundarySharedProps = PropsWithChildren<{
  /**
   * Optional callback to enable e.g. logging error information to a server.
   *
   * @param error Value that was thrown; typically an instance of `Error`
   * @param info React "component stack" identifying where the error was thrown
   */
  onError?: (error: unknown, info: ErrorInfo) => void;

  /**
   * Optional callback to to be notified when an error boundary is "reset" so React can retry the failed render.
   */
  onReset?: (
    details:
      | { reason: "imperative-api"; args: unknown[] }
      | {
          reason: "keys";
          prev: unknown[] | undefined;
          next: unknown[] | undefined;
        },
  ) => void;

  /**
   * When changed, these keys will reset a triggered error boundary.
   * This can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).
   * See the the documentation for examples of how to use this prop.
   */
  resetKeys?: unknown[];
}>;

export type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
  fallback?: never;
  /**
   * React component responsible for returning a fallback UI based on a thrown value.
   *
   * ```tsx
   * <ErrorBoundary FallbackComponent={Fallback} />
   * ```
   */
  FallbackComponent: ComponentType<FallbackProps>;
  fallbackRender?: never;
};

export type ErrorBoundaryPropsWithRender = ErrorBoundarySharedProps & {
  fallback?: never;
  FallbackComponent?: never;
  /**
   * [Render prop](https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering) function responsible for returning a fallback UI based on a thrown value.
   *
   * ```tsx
   * <ErrorBoundary fallbackRender={({ error, resetErrorBoundary }) => <div>...</div>} />
   * ```
   */
  fallbackRender: (props: FallbackProps) => ReactNode;
};

export type ErrorBoundaryPropsWithFallback = ErrorBoundarySharedProps & {
  /**
   * Static content to render in place of an error if one is thrown.
   *
   * ```tsx
   * <ErrorBoundary fallback={<div className="text-red">Something went wrong</div>} />
   * ```
   */
  fallback: ReactNode;
  FallbackComponent?: never;
  fallbackRender?: never;
};

export type ErrorBoundaryProps =
  | ErrorBoundaryPropsWithFallback
  | ErrorBoundaryPropsWithComponent
  | ErrorBoundaryPropsWithRender;


================================================
FILE: lib/utils/assert.ts
================================================
export function assert(
  expectedCondition: unknown,
  message: string = "Assertion error",
): asserts expectedCondition {
  if (!expectedCondition) {
    throw Error(message);
  }
}


================================================
FILE: lib/utils/assertErrorBoundaryContext.ts
================================================
import type { ErrorBoundaryContextType } from "../context/ErrorBoundaryContext";
import { isErrorBoundaryContext } from "./isErrorBoundaryContext";

export function assertErrorBoundaryContext(
  value: unknown,
): asserts value is ErrorBoundaryContextType {
  if (!isErrorBoundaryContext(value)) {
    throw new Error("ErrorBoundaryContext not found");
  }
}


================================================
FILE: lib/utils/getErrorMessage.ts
================================================
export function getErrorMessage(thrown: unknown): string | undefined {
  switch (typeof thrown) {
    case "object": {
      if (
        thrown !== null &&
        "message" in thrown &&
        typeof thrown.message === "string"
      ) {
        return thrown.message;
      }
      break;
    }
    case "string": {
      return thrown;
    }
  }
}


================================================
FILE: lib/utils/isErrorBoundaryContext.ts
================================================
import type { ErrorBoundaryContextType } from "../context/ErrorBoundaryContext";

export function isErrorBoundaryContext(
  value: unknown,
): value is ErrorBoundaryContextType {
  return (
    value !== null &&
    typeof value === "object" &&
    "didCatch" in value &&
    typeof value.didCatch === "boolean" &&
    "error" in value &&
    "resetErrorBoundary" in value &&
    typeof value.resetErrorBoundary === "function"
  );
}


================================================
FILE: lib/utils/withErrorBoundary.test.tsx
================================================
import { Component, createRef, type PropsWithChildren } from "react";
import { createRoot } from "react-dom/client";
import { act } from "react-dom/test-utils";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { withErrorBoundary } from "./withErrorBoundary";

describe("withErrorBoundary", () => {
  let container: HTMLDivElement;
  let root: ReturnType<typeof createRoot>;
  let shouldThrow = true;
  let valueToThrow: unknown;

  beforeEach(() => {
    // @ts-expect-error This is a React internal
    global.IS_REACT_ACT_ENVIRONMENT = true;

    // Don't clutter the console with expected error text
    vi.spyOn(console, "error").mockImplementation(() => {
      // No-op
    });

    container = document.createElement("div");
    root = createRoot(container);
    shouldThrow = false;
    valueToThrow = new Error("💥💥💥");
  });

  function MaybeThrows({ children = "Children" }: PropsWithChildren) {
    if (shouldThrow) {
      throw valueToThrow;
    }
    return children;
  }

  function render() {
    const ErrorBoundary = withErrorBoundary(MaybeThrows, {
      fallback: <div>Error</div>,
    });

    act(() => {
      root.render(<ErrorBoundary />);
    });
  }

  it("should render children within the created HOC", () => {
    render();
    expect(container.textContent).toBe("Children");
  });

  it("should catch errors with the created HOC", () => {
    shouldThrow = true;
    render();
    expect(container.textContent).toBe("Error");
  });

  it("should forward refs", () => {
    type Props = { foo: string };

    class Inner extends Component<Props> {
      test() {
        // No-op
      }
      render() {
        return this.props.foo;
      }
    }

    const Wrapped = withErrorBoundary(Inner, {
      fallback: <div>Error</div>,
    });

    const ref = createRef<Inner>();

    act(() => {
      root.render(<Wrapped foo="abc" ref={ref} />);
    });

    expect(ref.current).not.toBeNull();
    expect(typeof ref.current?.test).toBe("function");
  });
});


================================================
FILE: lib/utils/withErrorBoundary.ts
================================================
import {
  createElement,
  forwardRef,
  type ComponentClass,
  type ComponentType,
} from "react";
import { ErrorBoundary } from "../components/ErrorBoundary";
import type { ErrorBoundaryProps } from "../types";

export function withErrorBoundary<
  Type extends ComponentClass<unknown>,
  Props extends object,
>(Component: ComponentType<Props>, errorBoundaryProps: ErrorBoundaryProps) {
  const Wrapped = forwardRef<InstanceType<Type>, Props>((props, ref) =>
    createElement(
      ErrorBoundary,
      errorBoundaryProps,
      createElement(Component, { ...props, ref } as Props),
    ),
  );

  // Format for display in DevTools
  const name = Component.displayName || Component.name || "Unknown";
  Wrapped.displayName = `withErrorBoundary(${name})`;

  return Wrapped;
}


================================================
FILE: package.json
================================================
{
  "name": "react-error-boundary",
  "version": "6.1.1",
  "type": "module",
  "description": "Simple reusable React error boundary component",
  "author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/bvaughn/react-error-boundary"
  },
  "contributors": [
    "Brian Vaughn <brian.david.vaughn@gmail.com> (https://github.com/bvaughn/)"
  ],
  "homepage": "https://react-error-boundary-lib.vercel.app/",
  "keywords": [
    "react",
    "reactjs",
    "virtual",
    "window",
    "windowed",
    "list",
    "scrolling",
    "infinite",
    "virtualized",
    "table",
    "grid",
    "spreadsheet"
  ],
  "main": "dist/react-error-boundary.cjs",
  "module": "dist/react-error-boundary.js",
  "types": "dist/react-error-boundary.d.ts",
  "files": [
    "dist"
  ],
  "scripts": {
    "dev": "vite",
    "dev:integrations": "pnpm -C integrations/vite/ run dev",
    "build": "pnpm run build:lib && pnpm run build:docs",
    "build:docs": "TARGET=docs vite build",
    "build:lib": "TARGET=lib vite build",
    "compile": "pnpm run compile:docs && pnpm run compile:examples",
    "compile:docs": "tsx ./scripts/compile-docs",
    "compile:examples": "tsx ./scripts/compile-examples",
    "compress:og-image": "tsx ./scripts/compress-og-image",
    "lint": "eslint .",
    "prerelease": "rm -rf dist && pnpm run build:lib",
    "prettier": "prettier --write \"**/*.{css,html,js,json,jsx,ts,tsx}\"",
    "prettier:ci": "prettier --check \"**/*.{css,html,js,json,jsx,ts,tsx}\"",
    "preview": "vite preview",
    "test": "vitest",
    "test:ci": "vitest run",
    "test:debug": "vitest --inspect-brk=127.0.0.1:3000 --no-file-parallelism",
    "tsc": "tsc -b"
  },
  "lint-staged": {
    "**/*": "prettier --write --ignore-unknown"
  },
  "peerDependencies": {
    "react": "^18.0.0 || ^19.0.0"
  },
  "devDependencies": {
    "@csstools/postcss-oklab-function": "^4.0.11",
    "@eslint/js": "^9.30.1",
    "@headlessui/react": "^2.2.4",
    "@headlessui/tailwindcss": "^0.2.2",
    "@heroicons/react": "^2.2.0",
    "@tailwindcss/vite": "^4.1.11",
    "@tailwindplus/elements": "^1.0.5",
    "@testing-library/jest-dom": "^6.6.4",
    "@testing-library/react": "^16.3.0",
    "@testing-library/user-event": "^14.6.1",
    "@types/bytes": "^3.1.5",
    "@types/compression": "^1.8.1",
    "@types/markdown-it": "^14.1.2",
    "@types/node": "^24.2.0",
    "@types/react": "^19.1.8",
    "@types/react-dom": "^19.2.3",
    "@types/sharp": "^0.32.0",
    "@vitejs/plugin-react-swc": "^3.10.2",
    "bytes": "^3.1.2",
    "clsx": "^2.1.1",
    "compression": "^1.8.1",
    "csstype": "^3.1.3",
    "eslint": "^9.30.1",
    "eslint-plugin-react-hooks": "^5.2.0",
    "eslint-plugin-react-refresh": "^0.4.20",
    "globals": "^16.3.0",
    "husky": "^9.1.7",
    "jsdom": "^26.1.0",
    "lint-staged": "^16.1.4",
    "markdown-it": "^14.1.0",
    "marked": "^16.4.1",
    "postcss": "^8.5.6",
    "prettier": "3.6.2",
    "prettier-plugin-tailwindcss": "^0.7.1",
    "react": "^19.2.3",
    "react-docgen-typescript": "^2.4.0",
    "react-dom": "^19.2.3",
    "react-error-boundary": "^6.0.0",
    "react-lib-tools": "^0.0.34",
    "react-router-dom": "^7.6.3",
    "rollup-plugin-terser": "^7.0.2",
    "rollup-plugin-visualizer": "^6.0.3",
    "rollup-preserve-directives": "^1.1.3",
    "sharp": "^0.34.5",
    "sirv": "^3.0.2",
    "tailwind-merge": "^3.3.1",
    "tailwindcss": "^4.1.11",
    "terser": "^5.43.1",
    "ts-blank-space": "^0.6.2",
    "ts-node": "^10.9.2",
    "tsx": "^4.21.0",
    "typescript": "~5.8.3",
    "typescript-eslint": "^8.35.1",
    "typescript-json-schema": "^0.65.1",
    "vite": "^7.0.4",
    "vite-plugin-dts": "^4.5.4",
    "vite-plugin-svgr": "^4.3.0",
    "vitest": "^3.2.4",
    "vitest-fail-on-console": "^0.10.1",
    "zustand": "^5.0.7"
  }
}


================================================
FILE: pnpm-workspace.yaml
================================================
packages:
  - integrations/*
  - lib/*
  - src/*

================================================
FILE: public/generated/examples/AsyncUserCodeErrors.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">useErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">function</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">useUserProfileInfo</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName\">username</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">username</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">string</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-keyword\">const</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName\">showBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-operator\">=</span><span class=\"\"> </span><span class=\"tok-variableName\">useErrorBoundary</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\">  </span><span class=\"tok-variableName\">useEffect</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">=&#62;</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-variableName\">fetchGreeting</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName\">username</span><span class=\"tok-punctuation\">)</span><span class=\"tok-operator\">.</span><span class=\"tok-propertyName\">then</span><span class=\"tok-punctuation\">(</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName tok-definition\">response</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">=&#62;</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">        </span><span class=\"tok-comment\">// Set data in state and re-render ...</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">,</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName tok-definition\">error</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">=&#62;</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">        </span><span class=\"tok-comment\">// Show error boundary</span><span class=\"\"></span></div>\n<div><span class=\"\">        </span><span class=\"tok-variableName\">showBoundary</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName\">error</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span></div>"
}

================================================
FILE: public/generated/examples/ErrorLogging.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-keyword\">type</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">ErrorInfo</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">ErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">function</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">logError</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName tok-definition\">error</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">unknown</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">info</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">ErrorInfo</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-comment\">// Do something with the error, e.g. log to an external API</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"\"> </span><span class=\"tok-propertyName\">FallbackComponent</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-variableName\">ErrorFallback</span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-propertyName\">onError</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-variableName\">logError</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">YourApplication</span><span class=\"\"> </span><span class=\"tok-punctuation\">/&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">;</span></div>"
}

================================================
FILE: public/generated/examples/FallbackComponent.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">ErrorBoundary</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">getErrorMessage</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-keyword\">type</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">FallbackProps</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">function</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">Fallback</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName\">error</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-propertyName\">resetErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">FallbackProps</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-keyword\">return</span><span class=\"\"> </span><span class=\"tok-punctuation\">(</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">div</span><span class=\"\"> </span><span class=\"tok-propertyName\">role</span><span class=\"tok-operator\">=</span><span class=\"tok-string\">\"alert\"</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">p</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\">Something went wrong:</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">p</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">pre</span><span class=\"\"> </span><span class=\"tok-propertyName\">style</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">color</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-string\">\"red\"</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">{</span><span class=\"tok-variableName\">getErrorMessage</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName\">error</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">pre</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">button</span><span class=\"\"> </span><span class=\"tok-propertyName\">onClick</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-variableName\">resetErrorBoundary</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\">Retry</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">button</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">div</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName\">FallbackComponent</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-variableName\">Fallback</span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName\">onReset</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName tok-definition\">details</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">=&#62;</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-comment\">// Reset the state of your app so the error doesn't happen again</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">YourApplication</span><span class=\"\"> </span><span class=\"tok-punctuation\">/&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">;</span></div>"
}

================================================
FILE: public/generated/examples/FallbackContent.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">ErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"\"> </span><span class=\"tok-propertyName\">fallback</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">div</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\">Something went wrong</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">div</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">YourApplication</span><span class=\"\"> </span><span class=\"tok-punctuation\">/&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">;</span></div>"
}

================================================
FILE: public/generated/examples/GetErrorMessage.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">getErrorMessage</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-keyword\">type</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">FallbackProps</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">function</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">Fallback</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName\">error</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">FallbackProps</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-comment\">// Because 'error' can be anything, it's safest not to assume it's an Error</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-comment\">// Use the getErrorMessage helper method to extract the message instead.</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-keyword\">const</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">message</span><span class=\"\"> </span><span class=\"tok-operator\">=</span><span class=\"\"> </span><span class=\"tok-variableName\">getErrorMessage</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName\">error</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-operator\">??</span><span class=\"\"> </span><span class=\"tok-string\">\"Unknown error\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\">  </span><span class=\"tok-comment\">// Render fallback UI...</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span></div>"
}

================================================
FILE: public/generated/examples/NpmResolution.json
================================================
{
  "html": "<div><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName\">\"overrides\"</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-propertyName\">\"@types/react\"</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-string\">\"17.0.60\"</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span></div>"
}

================================================
FILE: public/generated/examples/RenderProp.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">ErrorBoundary</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">getErrorMessage</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName\">fallbackRender</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName\">error</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-propertyName\">resetErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">=&#62;</span><span class=\"\"> </span><span class=\"tok-punctuation\">(</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">div</span><span class=\"\"> </span><span class=\"tok-propertyName\">role</span><span class=\"tok-operator\">=</span><span class=\"tok-string\">\"alert\"</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">p</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\">Something went wrong:</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">p</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">pre</span><span class=\"\"> </span><span class=\"tok-propertyName\">style</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">color</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-string\">\"red\"</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">{</span><span class=\"tok-variableName\">getErrorMessage</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName\">error</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">pre</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">      </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">button</span><span class=\"\"> </span><span class=\"tok-propertyName\">onClick</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-variableName\">resetErrorBoundary</span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\">Retry</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">button</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">div</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName\">onReset</span><span class=\"tok-operator\">=</span><span class=\"tok-punctuation\">{</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName tok-definition\">details</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">=&#62;</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-comment\">// Reset the state of your app so the error doesn't happen again</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">YourApplication</span><span class=\"\"> </span><span class=\"tok-punctuation\">/&#62;</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">ErrorBoundary</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">;</span></div>"
}

================================================
FILE: public/generated/examples/ResetWithUseErrorBoundary.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">useErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">function</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">Example</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-keyword\">const</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName\">resetBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-operator\">=</span><span class=\"\"> </span><span class=\"tok-variableName\">useErrorBoundary</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\">  </span><span class=\"tok-comment\">// Call resetBoundary() to reset the nearest ErrorBoundary and retry a failed render</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span></div>"
}

================================================
FILE: public/generated/examples/UseClient.json
================================================
{
  "html": "<div><span class=\"tok-string\">\"use client\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-comment\">// Imports and components code go here...</span></div>"
}

================================================
FILE: public/generated/examples/UseErrorBoundary.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">useErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">function</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">Example</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-keyword\">const</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-comment\">// The currently visible Error (if one has been thrown).</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-propertyName\">error</span><span class=\"tok-punctuation\">,</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\">    </span><span class=\"tok-comment\">// Method to reset and retry the nearest active error boundary (if one is active).</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-propertyName\">resetBoundary</span><span class=\"tok-punctuation\">,</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\">    </span><span class=\"tok-comment\">// Trigger the nearest error boundary to display the error provided.</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-propertyName\">showBoundary</span><span class=\"tok-punctuation\">,</span><span class=\"\"></span></div>\n<div><span class=\"\">   </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-operator\">=</span><span class=\"\"> </span><span class=\"tok-variableName\">useErrorBoundary</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\">  </span><span class=\"tok-comment\">// ...</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span></div>"
}

================================================
FILE: public/generated/examples/WithErrorBoundaryA.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">function</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">UserProfile</span><span class=\"tok-punctuation\">(</span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName\">username</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">username</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">string</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-comment\">// Render...</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span></div>"
}

================================================
FILE: public/generated/examples/WithErrorBoundaryB.json
================================================
{
  "html": "<div><span class=\"tok-keyword\">import</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">withErrorBoundary</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-keyword\">from</span><span class=\"\"> </span><span class=\"tok-string\">\"react-error-boundary\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"></span></div>\n<div>&nbsp;</div>\n<div><span class=\"\"></span><span class=\"tok-keyword\">const</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">UserProfileWithErrorBoundary</span><span class=\"\"> </span><span class=\"tok-operator\">=</span><span class=\"\"> </span><span class=\"tok-variableName\">withErrorBoundary</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName\">UserProfile</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName tok-definition\">fallback</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">div</span><span class=\"tok-punctuation\">&#62;</span><span class=\"\">Something went wrong</span><span class=\"tok-punctuation\">&#60;/</span><span class=\"tok-typeName\">div</span><span class=\"tok-punctuation\">&#62;</span><span class=\"tok-punctuation\">,</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName tok-definition\">onError</span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName tok-definition\">error</span><span class=\"tok-punctuation\">,</span><span class=\"\"> </span><span class=\"tok-variableName tok-definition\">info</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-comment\">// Do something with the error</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-comment\">// E.g. log to an error logging client here</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">,</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">)</span><span class=\"tok-punctuation\">;</span></div>"
}

================================================
FILE: public/generated/examples/WithErrorBoundaryC.json
================================================
{
  "html": "<div><span class=\"tok-punctuation\">&#60;</span><span class=\"tok-typeName\">UserProfileWithErrorBoundary</span><span class=\"\"> </span><span class=\"tok-propertyName\">username</span><span class=\"tok-operator\">=</span><span class=\"tok-string\">\"Brian\"</span><span class=\"\"> </span><span class=\"tok-punctuation\">/&#62;</span><span class=\"tok-punctuation\">;</span></div>"
}

================================================
FILE: public/generated/examples/YarnResolution.json
================================================
{
  "html": "<div><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-propertyName\">\"resolutions\"</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"></span></div>\n<div><span class=\"\">    </span><span class=\"tok-propertyName\">\"@types/react\"</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-string\">\"17.0.60\"</span><span class=\"\"></span></div>\n<div><span class=\"\">  </span><span class=\"tok-punctuation\">}</span><span class=\"\"></span></div>\n<div><span class=\"\"></span><span class=\"tok-punctuation\">}</span></div>"
}

================================================
FILE: public/robots.txt
================================================
User-agent: *
Allow: /

================================================
FILE: scripts/compile-docs.ts
================================================
import { compileDocs } from "react-lib-tools/scripts/compile-docs.ts";

await compileDocs({
  componentNames: ["ErrorBoundary"],
  imperativeHandleNames: [],
});


================================================
FILE: scripts/compile-examples.ts
================================================
import { compileExamples } from "react-lib-tools/scripts/compile-examples.ts";

await compileExamples();


================================================
FILE: scripts/compress-og-image
================================================
import { compressOgImage } from "react-lib-tools/scripts/compress-og-image.ts";

await compressOgImage();

================================================
FILE: src/App.tsx
================================================
import {
  AppRoot,
  Callout,
  Code,
  ExternalLink,
  NavSection,
  type CommonQuestion,
} from "react-lib-tools";
import { repository } from "../package.json";
import { html as htmlNpmResolution } from "../public/generated/examples/NpmResolution.json";
import { html as htmlYarnResolution } from "../public/generated/examples/YarnResolution.json";
import { Link } from "./components/Link";
import { NavLink } from "./components/NavLink";
import { routes } from "./routes";

export default function App() {
  return (
    <AppRoot
      commonQuestions={commonQuestions}
      navLinks={
        <div>
          <NavLink path="/">Getting started</NavLink>
          <NavSection label="Examples">
            <NavLink path="/examples/fallback">Fallback content</NavLink>
            <NavLink path="/examples/render-prop">Render prop</NavLink>
            <NavLink path="/examples/fallback-component">
              Fallback component
            </NavLink>
            <NavLink path="/examples/error-logging">Error logging</NavLink>
            <NavLink path="/examples/async-user-code-errors">
              Async user code errors
            </NavLink>
            <NavLink path="/examples/retry-nearest-boundary">
              Retry nearest boundary
            </NavLink>
          </NavSection>
          <NavSection label="API">
            <NavLink path="/api/error-boundary-props">ErrorBoundary</NavLink>
            <NavLink path="/api/use-error-boundary-hook">
              useErrorBoundary hook
            </NavLink>
            <NavLink path="/api/with-error-boundary-hoc">
              withErrorBoundary HOC
            </NavLink>
            <NavLink path="/api/get-error-message">
              getErrorMessage helper
            </NavLink>
          </NavSection>
          <NavLink path="/common-questions">Common questions</NavLink>
          <NavLink path="/support">Support</NavLink>
        </div>
      }
      overview={
        <>
          <div>
            React components and utils for managing runtime errors. Supports all
            React renderers (including React DOM and React Native).
          </div>
          <Callout children={clientSideWarning} intent="warning" />
        </>
      }
      packageDescription="runtime error handling"
      packageName="react-error-boundary"
      repositoryUrl={repository.url}
      routes={routes}
    />
  );
}

const clientSideWarning = (
  <div className="flex flex-col gap-2">
    <div>
      This package is built on top of React{" "}
      <ExternalLink href="https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary">
        error boundaries
      </ExternalLink>
      , so it has all of the advantages and constraints of that API.
    </div>
    <div>This means that it can't catch errors during:</div>
    <ul className="pl-8">
      <li className="list-disc">Server side rendering</li>
      <li className="list-disc">Event handlers</li>
      <li className="list-disc">Asynchronous code (including effects)</li>
    </ul>
    <div>
      You <em>can</em> show an error boundary for asynchronous code, but you
      have to catch the error yourself.{" "}
      <Link to="/examples/async-user-code-errors">Learn more</Link>.
    </div>
  </div>
);

const commonQuestions: CommonQuestion[] = [
  {
    id: "uncaught-error",
    question: "Why didn't the boundary catch my error?",
    answer: clientSideWarning,
  },
  {
    id: "react-types-mismatch",
    question: (
      <>
        <code>ErrorBoundary</code> cannot be used as a JSX component
      </>
    ),
    answer: (
      <>
        <p>
          This error can be caused by a version mismatch between{" "}
          <code>react</code> and <code>@types/react</code>. To fix this, ensure
          that both match exactly.
        </p>
        <p>
          For NPM, you may need to use an{" "}
          <ExternalLink href="https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides">
            override
          </ExternalLink>
          :
        </p>
        <Code html={htmlNpmResolution} />
        <p>
          Yarn has a similar mechanism called a{" "}
          <ExternalLink href="https://yarnpkg.com/cli/set/resolution">
            resolution
          </ExternalLink>
          :
        </p>
        <Code html={htmlYarnResolution} />
      </>
    ),
  },
];


================================================
FILE: src/components/ContinueLink.tsx
================================================
import type { Path } from "../routes";
import { Link } from "./Link";

export function ContinueLink({ title, to }: { title: string; to: Path }) {
  return (
    <div>
      Continue to <Link to={to}>{title}</Link>…
    </div>
  );
}


================================================
FILE: src/components/Divider.tsx
================================================
export function Divider() {
  return <hr className="h-px bg-slate-800 border-0" />;
}


================================================
FILE: src/components/Link.tsx
================================================
import type { HTMLAttributes } from "react";
import { Link as ExternalLink } from "react-lib-tools";
import type { Path } from "../routes";

export function Link({
  to,
  ...rest
}: HTMLAttributes<HTMLSpanElement> & {
  to: Path;
}) {
  return <ExternalLink to={to} {...rest} />;
}


================================================
FILE: src/components/NavLink.tsx
================================================
import { type PropsWithChildren } from "react";
import { NavLink as NavLinkExternal, type DefaultPath } from "react-lib-tools";
import { type Path } from "../routes";

export function NavLink({
  children,
  className,
  path,
}: PropsWithChildren<{
  className?: string | undefined;
  path: Path | DefaultPath;
}>) {
  return (
    <NavLinkExternal children={children} className={className} path={path} />
  );
}


================================================
FILE: src/routes/AsyncUserCodeErrorsRoute.tsx
================================================
import { Box, Code, Header, Link } from "react-lib-tools";
import { html } from "../../public/generated/examples/AsyncUserCodeErrors.json";

export default function AsyncUserCodeErrorsRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="Examples" title="Async user code errors" />
      <div>
        React only handles errors thrown during render or during component
        lifecycle methods (e.g. effects and did-mount/did-update). Errors thrown
        in event handlers, or after async code has run, will not be caught.
      </div>
      <div>
        The <Link to="/api/use-error-boundary-hook">useErrorBoundary</Link> hook
        can be used to pass those errors to the nearest error boundary:
      </div>
      <Code html={html} />
    </Box>
  );
}


================================================
FILE: src/routes/ErrorBoundaryPropsRoute.tsx
================================================
import { Box, ComponentProps, type ComponentMetadata } from "react-lib-tools";
import json from "../../public/generated/docs/ErrorBoundary.json";

export default function ErrorBoundaryPropsRoute() {
  return (
    <Box direction="column" gap={4}>
      <ComponentProps json={json as ComponentMetadata} section="API" />
    </Box>
  );
}


================================================
FILE: src/routes/ErrorLoggingRoute.tsx
================================================
import { Box, Code, Header } from "react-lib-tools";
import { html } from "../../public/generated/examples/ErrorLogging.json";

export default function ErrorLoggingRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="Examples" title="Error logging" />
      <div>
        Use the <code>onError</code> callback to log errors to a service like
        Sentry.
      </div>
      <Code html={html} />
    </Box>
  );
}


================================================
FILE: src/routes/FallbackComponentRoute.tsx
================================================
import { Box, Code, Header } from "react-lib-tools";
import { html } from "../../public/generated/examples/FallbackComponent.json";

export default function FallbackComponentRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="Examples" title="Fallback component" />
      <div>
        React component responsible for returning a fallback UI based on a
        thrown value.
      </div>
      <Code html={html} />
    </Box>
  );
}


================================================
FILE: src/routes/FallbackContentRoute.tsx
================================================
import { Box, Code, Header } from "react-lib-tools";
import { html } from "../../public/generated/examples/FallbackContent.json";

export default function RenderPropRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="Examples" title="Fallback content" />
      <div>The simplest way to render a default error message.</div>
      <Code html={html} />
    </Box>
  );
}


================================================
FILE: src/routes/GetErrorMessageRoute.tsx
================================================
import { Box, Code, ExternalLink, Header } from "react-lib-tools";
import { html } from "../../public/generated/examples/GetErrorMessage.json";

export default function GetErrorMessageRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="API" title="getErrorMessage helper" />
      <div>
        Typically <em>thrown</em> errors in JavaScript are instances of type{" "}
        <code>Error</code>, but{" "}
        <ExternalLink href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw">
          this is not always the case
        </ExternalLink>
        . Any value can be thrown- strings, numbers, even <code>null</code> or{" "}
        <code>undefined</code>.
      </div>
      <div>
        To simplify working with thrown values, this library exports a utility
        method called <code>getErrorMessage</code>.
      </div>
      <Code html={html} />
    </Box>
  );
}


================================================
FILE: src/routes/RenderPropRoute.tsx
================================================
import { Box, Code, ExternalLink, Header } from "react-lib-tools";
import { html } from "../../public/generated/examples/RenderProp.json";

export default function RenderPropRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="Examples" title="Render props" />
      <div>
        <ExternalLink href="https://react.dev/reference/react/Children#calling-a-render-prop-to-customize-rendering">
          Render prop
        </ExternalLink>{" "}
        function responsible for returning a fallback UI based on a thrown
        value.
      </div>
      <Code html={html} />
    </Box>
  );
}


================================================
FILE: src/routes/ResetNearestBoundaryRoute.tsx
================================================
import { Box, Code, Header } from "react-lib-tools";
import { html } from "../../public/generated/examples/ResetWithUseErrorBoundary.json";
import { Link } from "../components/Link";

export default function ResetNearestBoundaryRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="Examples" title="Reset nearest boundary" />
      <div>
        The <Link to="/api/use-error-boundary-hook">useErrorBoundary</Link> hook
        can be used to reset the nearest error boundary and retry a failed
        render attempt.
      </div>
      <Code html={html} />
    </Box>
  );
}


================================================
FILE: src/routes/UseErrorBoundaryRoute.tsx
================================================
import { Box, Callout, Code, Header } from "react-lib-tools";
import { html } from "../../public/generated/examples/UseErrorBoundary.json";

export default function UseErrorBoundaryRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="API" title="useErrorBoundary hook" />
      <div>
        Convenience hook for imperatively showing or dismissing error
        boundaries.
      </div>
      <Code html={html} />
      <Callout intent="warning">
        This hook must only be used within an <code>ErrorBoundary</code>{" "}
        subtree.
      </Callout>
    </Box>
  );
}


================================================
FILE: src/routes/WithErrorBoundaryRoute.tsx
================================================
import { Box, Code, ExternalLink, Header } from "react-lib-tools";
import { html as htmlA } from "../../public/generated/examples/WithErrorBoundaryA.json";
import { html as htmlB } from "../../public/generated/examples/WithErrorBoundaryB.json";
import { html as htmlC } from "../../public/generated/examples/WithErrorBoundaryC.json";

export default function WithErrorBoundaryRoute() {
  return (
    <Box direction="column" gap={4}>
      <Header section="API" title="withErrorBoundary HOC" />
      <div>
        This package can also be used as a{" "}
        <ExternalLink href="https://legacy.reactjs.org/docs/higher-order-components.html">
          higher-order component
        </ExternalLink>
        . For example, given a component like this:
      </div>
      <Code html={htmlA} />
      <div>
        You could use the <code>withErrorBoundary</code> HOC to create a wrapper
        component:
      </div>
      <Code html={htmlB} />
      <div>And then render it like this</div>
      <Code html={htmlC} />
      <div>
        This might be useful for certain types of reusable/library components.
      </div>
    </Box>
  );
}


================================================
FILE: src/routes/examples/AsyncUserCodeErrors.tsx
================================================
import { useEffect } from "react"; // hidden
import { useErrorBoundary } from "react-error-boundary";

function useUserProfileInfo({ username }: { username: string }) {
  const { showBoundary } = useErrorBoundary();

  useEffect(() => {
    fetchGreeting(username).then(
      (response) => {
        // Set data in state and re-render ...
        response; // hidden
      },
      (error) => {
        // Show error boundary
        showBoundary(error);
      }
    );
  });
}

// <end>

export { useUserProfileInfo };

async function fetchGreeting(_: string) {}


================================================
FILE: src/routes/examples/ErrorLogging.tsx
================================================
import type { ErrorInfo } from "react";
import { ErrorBoundary } from "react-error-boundary";

function logError(error: unknown, info: ErrorInfo) {
  // Do something with the error, e.g. log to an external API
  error; // hidden
  info; // hidden
}

<ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}>
  <YourApplication />
</ErrorBoundary>;

// <end>

function ErrorFallback() {
  return null;
}

function YourApplication() {
  return null;
}


================================================
FILE: src/routes/examples/FallbackComponent.tsx
================================================
import { ErrorBoundary, getErrorMessage, type FallbackProps } from "react-error-boundary";

function Fallback({ error, resetErrorBoundary }: FallbackProps) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre style={{ color: "red" }}>{getErrorMessage(error)}</pre>
      <button onClick={resetErrorBoundary}>Retry</button>
    </div>
  );
}

<ErrorBoundary
  FallbackComponent={Fallback}
  onReset={(details) => {
    // Reset the state of your app so the error doesn't happen again
    details; // hidden
  }}
>
  <YourApplication />
</ErrorBoundary>;

// <end>

function YourApplication() {
  return null;
}


================================================
FILE: src/routes/examples/FallbackContent.tsx
================================================
import { ErrorBoundary } from "react-error-boundary";

<ErrorBoundary fallback={<div>Something went wrong</div>}>
  <YourApplication />
</ErrorBoundary>;

// <end>

function YourApplication() {
  return null;
}


================================================
FILE: src/routes/examples/GetErrorMessage.ts
================================================
import { getErrorMessage, type FallbackProps } from "react-error-boundary";

function Fallback({ error }: FallbackProps) {
  // Because 'error' can be anything, it's safest not to assume it's an Error
  // Use the getErrorMessage helper method to extract the message instead.
  const message = getErrorMessage(error) ?? "Unknown error";

  // Render fallback UI...
  return message; // hidden
}

// <end>

export { Fallback };


================================================
FILE: src/routes/examples/NpmResolution.json
================================================
{
  "overrides": {
    "@types/react": "17.0.60"
  }
}

================================================
FILE: src/routes/examples/RenderProp.tsx
================================================
import { ErrorBoundary, getErrorMessage } from "react-error-boundary";

<ErrorBoundary
  fallbackRender={({ error, resetErrorBoundary }) => (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre style={{ color: "red" }}>{getErrorMessage(error)}</pre>
      <button onClick={resetErrorBoundary}>Retry</button>
    </div>
  )}
  onReset={(details) => {
    // Reset the state of your app so the error doesn't happen again
    details; // hidden
  }}
>
  <YourApplication />
</ErrorBoundary>;

// <end>

function YourApplication() {
  return null;
}


================================================
FILE: src/routes/examples/ResetWithUseErrorBoundary.tsx
================================================
import { useErrorBoundary } from "react-error-boundary";

function Example() {
  const { resetBoundary } = useErrorBoundary();

  // Call resetBoundary() to reset the nearest ErrorBoundary and retry a failed render
  resetBoundary; // hidden
}

// <end>

export { Example };


================================================
FILE: src/routes/examples/UseClient.ts
================================================
"use client";

// Imports and components code go here...

================================================
FILE: src/routes/examples/UseErrorBoundary.tsx
================================================
import { useErrorBoundary } from "react-error-boundary";

function Example() {
  const {
    // The currently visible Error (if one has been thrown).
    error,

    // Method to reset and retry the nearest active error boundary (if one is active).
    resetBoundary,

    // Trigger the nearest error boundary to display the error provided.
    showBoundary,
   } = useErrorBoundary();

  // ...
  error; // hidden
  resetBoundary; // hidden
  showBoundary; // hidden
}

// <end>

export { Example };


================================================
FILE: src/routes/examples/WithErrorBoundaryA.tsx
================================================
function UserProfile({ username }: { username: string }) {
  username; // hidden
  return null; // hidden
  // Render...
}

// <end>

export { UserProfile };


================================================
FILE: src/routes/examples/WithErrorBoundaryB.tsx
================================================
import { UserProfile } from "./WithErrorBoundaryA";

// <begin>

import { withErrorBoundary } from "react-error-boundary";

const UserProfileWithErrorBoundary = withErrorBoundary(UserProfile, {
  fallback: <div>Something went wrong</div>,
  onError(error, info) {
    // Do something with the error
    // E.g. log to an error logging client here
    error; // hidden
    info; // hidden
  },
});

// <end>

export { UserProfileWithErrorBoundary };


================================================
FILE: src/routes/examples/WithErrorBoundaryC.tsx
================================================
import { UserProfileWithErrorBoundary } from "./WithErrorBoundaryB";

// <begin>

<UserProfileWithErrorBoundary username="Brian" />;


================================================
FILE: src/routes/examples/YarnResolution.json
================================================
{
  "resolutions": {
    "@types/react": "17.0.60"
  }
}

================================================
FILE: src/routes.ts
================================================
import { lazy, type ComponentType, type LazyExoticComponent } from "react";

export type Route = LazyExoticComponent<ComponentType<unknown>>;

export const routes = {
  "/examples/fallback": lazy(() => import("./routes/FallbackContentRoute")),
  "/examples/render-prop": lazy(() => import("./routes/RenderPropRoute")),
  "/examples/fallback-component": lazy(
    () => import("./routes/FallbackComponentRoute"),
  ),
  "/examples/error-logging": lazy(() => import("./routes/ErrorLoggingRoute")),
  "/examples/async-user-code-errors": lazy(
    () => import("./routes/AsyncUserCodeErrorsRoute"),
  ),
  "/examples/retry-nearest-boundary": lazy(
    () => import("./routes/ResetNearestBoundaryRoute"),
  ),
  "/api/error-boundary-props": lazy(
    () => import("./routes/ErrorBoundaryPropsRoute"),
  ),
  "/api/use-error-boundary-hook": lazy(
    () => import("./routes/UseErrorBoundaryRoute"),
  ),
  "/api/with-error-boundary-hoc": lazy(
    () => import("./routes/WithErrorBoundaryRoute"),
  ),
  "/api/get-error-message": lazy(() => import("./routes/GetErrorMessageRoute")),
} satisfies Record<string, Route>;

export type Routes = Record<keyof typeof routes, Route>;
export type Path = keyof Routes;


================================================
FILE: src/vite-env.d.ts
================================================
/// <reference types="vite/client" />
/// <reference types="vite-plugin-svgr/client" />


================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
    "target": "ES2022",
    "useDefineForClassFields": true,
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,

    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "moduleDetection": "force",
    "noEmit": true,
    "jsx": "react-jsx",

    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "erasableSyntaxOnly": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,
    "exactOptionalPropertyTypes": true,

    "paths": {
      "react-error-boundary": ["./lib"]
    },
    "types": [
      "csstype",
      "@testing-library/jest-dom",
      "@testing-library/jest-dom/vitest"
    ]
  },
  "include": ["vitest.d.ts", "lib", "scripts", "src", "index.tsx"],
  "exclude": []
}


================================================
FILE: vercel.json
================================================
{
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/index.html"
    }
  ]
}


================================================
FILE: vite.config.ts
================================================
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react-swc";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { visualizer } from "rollup-plugin-visualizer";
import preserveDirectives from "rollup-preserve-directives";
import { defineConfig, type UserConfig } from "vite";
import dts from "vite-plugin-dts";
import svgr from "vite-plugin-svgr";

const __dirname = dirname(fileURLToPath(import.meta.url));

const libraryConfig: UserConfig = {
  build: {
    lib: {
      entry: resolve(__dirname, "lib/index.ts"),
      name: "react-error-boundary",
      fileName: "react-error-boundary",
      formats: ["cjs", "es"],
    },
    rollupOptions: {
      external: ["react", "react-dom", "react/jsx-runtime"],
    },
    sourcemap: true,
    terserOptions: {
      compress: {
        directives: false,
      },
    },
  },
  plugins: [react(), dts({ rollupTypes: true }), preserveDirectives()],
  publicDir: false,
};

const websiteConfig: UserConfig = {
  base: "/",
  build: {
    minify: "terser",
    outDir: "docs",
    sourcemap: true,
    terserOptions: {
      format: {
        comments: false,
      },
    },
  },
  plugins: [
    react(),
    svgr(),
    tailwindcss(),
    visualizer({
      emitFile: true,
      filename: "stats.html",
    }),
  ],
  resolve: {
    alias: {
      "react-error-boundary": resolve(__dirname, "lib"),
    },
  },
};

// Allow iPhone to connect to the DEV site using a local IP
if (process.env.NODE_ENV === "development") {
  websiteConfig.server = {
    host: true,
    port: 3000,
  };
}

let config: UserConfig = {};
switch (process.env.TARGET) {
  case "lib": {
    config = libraryConfig;
    break;
  }
  default: {
    config = websiteConfig;
    break;
  }
}

// https://vite.dev/config/
export default defineConfig(config);


================================================
FILE: vitest.config.ts
================================================
import { defineConfig, mergeConfig } from "vitest/config";
import viteConfig from "./vite.config";

export default mergeConfig(
  viteConfig,
  defineConfig({
    test: {
      // onConsoleLog(log, type) {
      //   console.log("[config] onConsoleLog:", type, log);
      //   switch (type) {
      //     case "stderr": {
      //       throw Error("Unexpected console error: " + log);
      //     }
      //   }
      // },
      environment: "jsdom",
      setupFiles: "./vitest.setup.js",
      exclude: ["node_modules", "integrations"],
    },
  }),
);


================================================
FILE: vitest.d.ts
================================================
import "vitest";

declare module "vitest" {
  interface Matchers {
    toLogError: (expectedError: string) => ReturnType;
  }
}


================================================
FILE: vitest.setup.ts
================================================
import "@testing-library/jest-dom/vitest";
import { cleanup } from "@testing-library/react";
import { afterAll, afterEach, beforeAll, expect, vi } from "vitest";
import failOnConsole from "vitest-fail-on-console";

const PROTOTYPE_PROPS = [
  "clientHeight",
  "clientWidth",
  "offsetHeight",
  "offsetWidth",
];

failOnConsole({
  shouldFailOnError: true,
});

expect.addSnapshotSerializer({
  serialize(value) {
    const rect = value as DOMRect;
    return `${rect.x}, ${rect.y} (${rect.width} x ${rect.height})`;
  },
  test(value) {
    return (
      value !== null &&
      typeof value === "object" &&
      "x" in value &&
      "y" in value &&
      "width" in value &&
      "height" in value
    );
  },
});

expect.extend({
  toLogError: (callback: () => unknown, expectedError: string) => {
    const spy = vi.spyOn(console, "error").mockImplementation(() => {});

    callback();

    expect(console.error).toHaveBeenCalledWith(expectedError);

    spy.mockReset();

    return {
      pass: true,
      message: () => "",
    };
  },
});

beforeAll(() => {
  PROTOTYPE_PROPS.forEach((propertyKey) => {
    Object.defineProperty(HTMLElement.prototype, propertyKey, {
      configurable: true,
      value: 0,
    });
  });

  vi.spyOn(console, "warn").mockImplementation(() => {
    throw Error("Unexpectec console warning");
  });
});

afterAll(() => {
  PROTOTYPE_PROPS.forEach((propertyKey) => {
    delete HTMLElement.prototype[
      propertyKey as keyof typeof HTMLElement.prototype
    ];
  });
});

afterEach(() => {
  cleanup();
});
Download .txt
gitextract_msysdob0/

├── .gitattributes
├── .github/
│   └── workflows/
│       ├── eslint.yml
│       ├── pending-changes.yml
│       ├── prettier.yml
│       ├── typescript.yml
│       └── vitest.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── eslint.config.js
├── index.css
├── index.html
├── index.tsx
├── integrations/
│   └── vite/
│       ├── README.md
│       ├── eslint.config.js
│       ├── index.html
│       ├── package.json
│       ├── playwright.config.ts
│       ├── src/
│       │   ├── components/
│       │   │   ├── Children.tsx
│       │   │   ├── Container.tsx
│       │   │   ├── DebugData.tsx
│       │   │   └── Resizer.tsx
│       │   ├── index.css
│       │   ├── main.tsx
│       │   ├── routes/
│       │   │   └── Home.tsx
│       │   ├── utils/
│       │   │   ├── assert.ts
│       │   │   └── cn.ts
│       │   └── vite-env.d.ts
│       ├── test-results/
│       │   └── .last-run.json
│       ├── tests/
│       │   └── utils/
│       │       ├── calculateBoxBetween.ts
│       │       ├── calculateHitArea.ts
│       │       ├── debugging/
│       │       │   ├── logDebugState.ts
│       │       │   └── logGroup.ts
│       │       ├── expectLayout.ts
│       │       ├── expectPanelSize.ts
│       │       ├── getCenterCoordinates.ts
│       │       ├── getSeparatorAriaAttributes.ts
│       │       ├── goToUrl.ts
│       │       ├── goToUrlWithIframe.ts
│       │       ├── pointer-interactions/
│       │       │   └── resizeHelper.ts
│       │       ├── serializer/
│       │       │   ├── decode.ts
│       │       │   ├── encode.ts
│       │       │   └── types.ts
│       │       ├── types.ts
│       │       └── updateUrl.ts
│       ├── tsconfig.json
│       └── vite.config.ts
├── lib/
│   ├── components/
│   │   ├── ErrorBoundary.test.tsx
│   │   └── ErrorBoundary.tsx
│   ├── context/
│   │   └── ErrorBoundaryContext.ts
│   ├── hooks/
│   │   ├── useErrorBoundary.test.tsx
│   │   └── useErrorBoundary.ts
│   ├── index.ts
│   ├── types.ts
│   └── utils/
│       ├── assert.ts
│       ├── assertErrorBoundaryContext.ts
│       ├── getErrorMessage.ts
│       ├── isErrorBoundaryContext.ts
│       ├── withErrorBoundary.test.tsx
│       └── withErrorBoundary.ts
├── package.json
├── pnpm-workspace.yaml
├── public/
│   ├── generated/
│   │   └── examples/
│   │       ├── AsyncUserCodeErrors.json
│   │       ├── ErrorLogging.json
│   │       ├── FallbackComponent.json
│   │       ├── FallbackContent.json
│   │       ├── GetErrorMessage.json
│   │       ├── NpmResolution.json
│   │       ├── RenderProp.json
│   │       ├── ResetWithUseErrorBoundary.json
│   │       ├── UseClient.json
│   │       ├── UseErrorBoundary.json
│   │       ├── WithErrorBoundaryA.json
│   │       ├── WithErrorBoundaryB.json
│   │       ├── WithErrorBoundaryC.json
│   │       └── YarnResolution.json
│   └── robots.txt
├── scripts/
│   ├── compile-docs.ts
│   ├── compile-examples.ts
│   └── compress-og-image
├── src/
│   ├── App.tsx
│   ├── components/
│   │   ├── ContinueLink.tsx
│   │   ├── Divider.tsx
│   │   ├── Link.tsx
│   │   └── NavLink.tsx
│   ├── routes/
│   │   ├── AsyncUserCodeErrorsRoute.tsx
│   │   ├── ErrorBoundaryPropsRoute.tsx
│   │   ├── ErrorLoggingRoute.tsx
│   │   ├── FallbackComponentRoute.tsx
│   │   ├── FallbackContentRoute.tsx
│   │   ├── GetErrorMessageRoute.tsx
│   │   ├── RenderPropRoute.tsx
│   │   ├── ResetNearestBoundaryRoute.tsx
│   │   ├── UseErrorBoundaryRoute.tsx
│   │   ├── WithErrorBoundaryRoute.tsx
│   │   └── examples/
│   │       ├── AsyncUserCodeErrors.tsx
│   │       ├── ErrorLogging.tsx
│   │       ├── FallbackComponent.tsx
│   │       ├── FallbackContent.tsx
│   │       ├── GetErrorMessage.ts
│   │       ├── NpmResolution.json
│   │       ├── RenderProp.tsx
│   │       ├── ResetWithUseErrorBoundary.tsx
│   │       ├── UseClient.ts
│   │       ├── UseErrorBoundary.tsx
│   │       ├── WithErrorBoundaryA.tsx
│   │       ├── WithErrorBoundaryB.tsx
│   │       ├── WithErrorBoundaryC.tsx
│   │       └── YarnResolution.json
│   ├── routes.ts
│   └── vite-env.d.ts
├── tsconfig.json
├── vercel.json
├── vite.config.ts
├── vitest.config.ts
├── vitest.d.ts
└── vitest.setup.ts
Download .txt
SYMBOL INDEX (130 symbols across 63 files)

FILE: integrations/vite/src/components/Children.tsx
  type SizeProps (line 3) | type SizeProps = {

FILE: integrations/vite/src/components/Container.tsx
  type ContainerProps (line 3) | type ContainerProps = PropsWithChildren<{
  function Container (line 7) | function Container({ children, className }: ContainerProps) {

FILE: integrations/vite/src/components/DebugData.tsx
  function DebugData (line 3) | function DebugData({ data }: { data: object }) {
  function replacer (line 16) | function replacer(_key: string, value: unknown) {

FILE: integrations/vite/src/components/Resizer.tsx
  type ResizerProps (line 3) | type ResizerProps = PropsWithChildren;
  function Resizer (line 5) | function Resizer({ children: childrenProp }: ResizerProps) {

FILE: integrations/vite/src/routes/Home.tsx
  function Home (line 1) | function Home() {

FILE: integrations/vite/src/utils/assert.ts
  function assert (line 1) | function assert(

FILE: integrations/vite/src/utils/cn.ts
  function cn (line 4) | function cn(...inputs: ClassValue[]) {

FILE: integrations/vite/tests/utils/calculateBoxBetween.ts
  function calculateBoxBetween (line 3) | function calculateBoxBetween(boxA: Box, boxB: Box): Box {

FILE: integrations/vite/tests/utils/calculateHitArea.ts
  function calculateHitArea (line 4) | async function calculateHitArea(page: Page, panelIds: [string, string]) {

FILE: integrations/vite/tests/utils/debugging/logDebugState.ts
  function logDebugState (line 3) | async function logDebugState(page: Page, prefix?: string) {

FILE: integrations/vite/tests/utils/debugging/logGroup.ts
  function logGroup (line 3) | async function logGroup(page: Page) {

FILE: integrations/vite/tests/utils/expectLayout.ts
  function expectLayout (line 4) | async function expectLayout({

FILE: integrations/vite/tests/utils/expectPanelSize.ts
  function expectPanelSize (line 4) | async function expectPanelSize({

FILE: integrations/vite/tests/utils/getCenterCoordinates.ts
  function getCenterCoordinates (line 3) | function getCenterCoordinates(box: Box): Coordinates {

FILE: integrations/vite/tests/utils/getSeparatorAriaAttributes.ts
  function getSeparatorAriaAttributes (line 3) | async function getSeparatorAriaAttributes(page: Page, id?: string) {

FILE: integrations/vite/tests/utils/goToUrl.ts
  function goToUrl (line 6) | async function goToUrl(

FILE: integrations/vite/tests/utils/goToUrlWithIframe.ts
  function goToUrlWithIframe (line 6) | async function goToUrlWithIframe(

FILE: integrations/vite/tests/utils/pointer-interactions/resizeHelper.ts
  function resizeHelper (line 5) | async function resizeHelper(

FILE: integrations/vite/tests/utils/serializer/decode.ts
  type Config (line 25) | type Config = {
  function decode (line 32) | function decode(stringified: string, config: Config = {}) {
  function decodeChildren (line 38) | function decodeChildren(
  function decodeContainer (line 87) | function decodeContainer(
  function decodeDisplayModeToggle (line 101) | function decodeDisplayModeToggle(
  function decodeGroup (line 115) | function decodeGroup(
  function decodePanel (line 129) | function decodePanel(
  function decodePopupWindow (line 143) | function decodePopupWindow(
  function decodeSeparator (line 157) | function decodeSeparator(
  function decodeText (line 166) | function decodeText(json: EncodedTextElement): ReactElement<TextProps> {

FILE: integrations/vite/tests/utils/serializer/encode.ts
  function encode (line 34) | function encode(element: ReactElement<unknown>) {
  function encodeChildren (line 41) | function encodeChildren(children: ReactElement<unknown>[]): EncodedEleme...
  function encodeContainer (line 96) | function encodeContainer(
  function encodeDisplayModeToggle (line 114) | function encodeDisplayModeToggle(
  function encodeGroup (line 132) | function encodeGroup(element: ReactElement<GroupProps>): EncodedGroupEle...
  function encodePanel (line 148) | function encodePanel(element: ReactElement<PanelProps>): EncodedPanelEle...
  function encodePopupWindow (line 164) | function encodePopupWindow(
  function encodeSeparator (line 182) | function encodeSeparator(
  function encodeTextChild (line 193) | function encodeTextChild(element: ReactElement<TextProps>): EncodedTextE...

FILE: integrations/vite/tests/utils/serializer/types.ts
  type EncodedElementWithChildren (line 10) | type EncodedElementWithChildren<Props extends object = object> = Omit<
  type EncodedContainerElement (line 15) | interface EncodedContainerElement {
  type EncodedDisplayModeToggleElement (line 20) | interface EncodedDisplayModeToggleElement {
  type EncodedGroupElement (line 25) | interface EncodedGroupElement {
  type EncodedPanelElement (line 30) | interface EncodedPanelElement {
  type EncodedPopupWindowElement (line 35) | interface EncodedPopupWindowElement {
  type EncodedSeparatorElement (line 40) | interface EncodedSeparatorElement {
  type TextProps (line 45) | type TextProps = {
  type EncodedTextElement (line 50) | interface EncodedTextElement {
  type EncodedElement (line 55) | type EncodedElement =

FILE: integrations/vite/tests/utils/types.ts
  type Box (line 1) | type Box = {
  type Coordinates (line 8) | type Coordinates = {

FILE: integrations/vite/tests/utils/updateUrl.ts
  function updateUrl (line 6) | async function updateUrl(

FILE: lib/components/ErrorBoundary.test.tsx
  function MaybeThrows (line 42) | function MaybeThrows({ children }: PropsWithChildren) {
  function render (line 70) | function render(props: Omit<ErrorBoundaryPropsWithFallback, "fallback">) {
  function render (line 129) | function render(
  function render (line 178) | function render(
  function render (line 245) | function render(
  function render (line 326) | function render() {

FILE: lib/components/ErrorBoundary.tsx
  type ErrorBoundaryState (line 7) | type ErrorBoundaryState =
  class ErrorBoundary (line 38) | class ErrorBoundary extends Component<
    method constructor (line 42) | constructor(props: ErrorBoundaryProps) {
    method getDerivedStateFromError (line 49) | static getDerivedStateFromError(error: Error) {
    method resetErrorBoundary (line 53) | resetErrorBoundary(...args: unknown[]) {
    method componentDidCatch (line 66) | componentDidCatch(error: unknown, info: ErrorInfo) {
    method componentDidUpdate (line 70) | componentDidUpdate(
    method render (line 97) | render() {
  function hasArrayChanged (line 141) | function hasArrayChanged(a: unknown[] = [], b: unknown[] = []) {

FILE: lib/context/ErrorBoundaryContext.ts
  type ErrorBoundaryContextType (line 3) | type ErrorBoundaryContextType = {

FILE: lib/hooks/useErrorBoundary.test.tsx
  function render (line 20) | function render(content: ReactNode) {
  function Child (line 32) | function Child() {
  function Child (line 70) | function Child() {
  function Fallback (line 79) | function Fallback() {

FILE: lib/hooks/useErrorBoundary.ts
  type UseErrorBoundaryState (line 5) | type UseErrorBoundaryState =
  type UseErrorBoundaryApi (line 9) | type UseErrorBoundaryApi = {
  function useErrorBoundary (line 20) | function useErrorBoundary(): {

FILE: lib/types.ts
  type FallbackProps (line 8) | type FallbackProps = {
  type OnErrorCallback (line 13) | type OnErrorCallback = (error: unknown, info: ErrorInfo) => void;
  type ErrorBoundarySharedProps (line 15) | type ErrorBoundarySharedProps = PropsWithChildren<{
  type ErrorBoundaryPropsWithComponent (line 45) | type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
  type ErrorBoundaryPropsWithRender (line 58) | type ErrorBoundaryPropsWithRender = ErrorBoundarySharedProps & {
  type ErrorBoundaryPropsWithFallback (line 71) | type ErrorBoundaryPropsWithFallback = ErrorBoundarySharedProps & {
  type ErrorBoundaryProps (line 84) | type ErrorBoundaryProps =

FILE: lib/utils/assert.ts
  function assert (line 1) | function assert(

FILE: lib/utils/assertErrorBoundaryContext.ts
  function assertErrorBoundaryContext (line 4) | function assertErrorBoundaryContext(

FILE: lib/utils/getErrorMessage.ts
  function getErrorMessage (line 1) | function getErrorMessage(thrown: unknown): string | undefined {

FILE: lib/utils/isErrorBoundaryContext.ts
  function isErrorBoundaryContext (line 3) | function isErrorBoundaryContext(

FILE: lib/utils/withErrorBoundary.test.tsx
  function MaybeThrows (line 28) | function MaybeThrows({ children = "Children" }: PropsWithChildren) {
  function render (line 35) | function render() {
  type Props (line 57) | type Props = { foo: string };
  class Inner (line 59) | class Inner extends Component<Props> {
    method test (line 60) | test() {
    method render (line 63) | render() {

FILE: lib/utils/withErrorBoundary.ts
  function withErrorBoundary (line 10) | function withErrorBoundary<

FILE: src/App.tsx
  function App (line 16) | function App() {

FILE: src/components/ContinueLink.tsx
  function ContinueLink (line 4) | function ContinueLink({ title, to }: { title: string; to: Path }) {

FILE: src/components/Divider.tsx
  function Divider (line 1) | function Divider() {

FILE: src/components/Link.tsx
  function Link (line 5) | function Link({

FILE: src/components/NavLink.tsx
  function NavLink (line 5) | function NavLink({

FILE: src/routes.ts
  type Route (line 3) | type Route = LazyExoticComponent<ComponentType<unknown>>;
  type Routes (line 30) | type Routes = Record<keyof typeof routes, Route>;
  type Path (line 31) | type Path = keyof Routes;

FILE: src/routes/AsyncUserCodeErrorsRoute.tsx
  function AsyncUserCodeErrorsRoute (line 4) | function AsyncUserCodeErrorsRoute() {

FILE: src/routes/ErrorBoundaryPropsRoute.tsx
  function ErrorBoundaryPropsRoute (line 4) | function ErrorBoundaryPropsRoute() {

FILE: src/routes/ErrorLoggingRoute.tsx
  function ErrorLoggingRoute (line 4) | function ErrorLoggingRoute() {

FILE: src/routes/FallbackComponentRoute.tsx
  function FallbackComponentRoute (line 4) | function FallbackComponentRoute() {

FILE: src/routes/FallbackContentRoute.tsx
  function RenderPropRoute (line 4) | function RenderPropRoute() {

FILE: src/routes/GetErrorMessageRoute.tsx
  function GetErrorMessageRoute (line 4) | function GetErrorMessageRoute() {

FILE: src/routes/RenderPropRoute.tsx
  function RenderPropRoute (line 4) | function RenderPropRoute() {

FILE: src/routes/ResetNearestBoundaryRoute.tsx
  function ResetNearestBoundaryRoute (line 5) | function ResetNearestBoundaryRoute() {

FILE: src/routes/UseErrorBoundaryRoute.tsx
  function UseErrorBoundaryRoute (line 4) | function UseErrorBoundaryRoute() {

FILE: src/routes/WithErrorBoundaryRoute.tsx
  function WithErrorBoundaryRoute (line 6) | function WithErrorBoundaryRoute() {

FILE: src/routes/examples/AsyncUserCodeErrors.tsx
  function useUserProfileInfo (line 4) | function useUserProfileInfo({ username }: { username: string }) {
  function fetchGreeting (line 25) | async function fetchGreeting(_: string) {}

FILE: src/routes/examples/ErrorLogging.tsx
  function logError (line 4) | function logError(error: unknown, info: ErrorInfo) {
  function ErrorFallback (line 16) | function ErrorFallback() {
  function YourApplication (line 20) | function YourApplication() {

FILE: src/routes/examples/FallbackComponent.tsx
  function Fallback (line 3) | function Fallback({ error, resetErrorBoundary }: FallbackProps) {
  function YourApplication (line 25) | function YourApplication() {

FILE: src/routes/examples/FallbackContent.tsx
  function YourApplication (line 9) | function YourApplication() {

FILE: src/routes/examples/GetErrorMessage.ts
  function Fallback (line 3) | function Fallback({ error }: FallbackProps) {

FILE: src/routes/examples/RenderProp.tsx
  function YourApplication (line 21) | function YourApplication() {

FILE: src/routes/examples/ResetWithUseErrorBoundary.tsx
  function Example (line 3) | function Example() {

FILE: src/routes/examples/UseErrorBoundary.tsx
  function Example (line 3) | function Example() {

FILE: src/routes/examples/WithErrorBoundaryA.tsx
  function UserProfile (line 1) | function UserProfile({ username }: { username: string }) {

FILE: src/routes/examples/WithErrorBoundaryB.tsx
  method onError (line 9) | onError(error, info) {

FILE: vitest.d.ts
  type Matchers (line 4) | interface Matchers {

FILE: vitest.setup.ts
  constant PROTOTYPE_PROPS (line 6) | const PROTOTYPE_PROPS = [
  method serialize (line 18) | serialize(value) {
  method test (line 22) | test(value) {
Condensed preview — 122 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (149K chars).
[
  {
    "path": ".gitattributes",
    "chars": 19,
    "preview": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/workflows/eslint.yml",
    "chars": 368,
    "preview": "name: \"ESLint\"\non: [pull_request]\njobs:\n  eslint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v"
  },
  {
    "path": ".github/workflows/pending-changes.yml",
    "chars": 431,
    "preview": "name: \"Pending changes\"\non: [pull_request]\njobs:\n  pending-changes:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: "
  },
  {
    "path": ".github/workflows/prettier.yml",
    "chars": 385,
    "preview": "name: \"Prettier\"\non: [pull_request]\njobs:\n  prettier:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checko"
  },
  {
    "path": ".github/workflows/typescript.yml",
    "chars": 435,
    "preview": "name: \"TypeScript\"\non: [pull_request]\njobs:\n  typescript:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/ch"
  },
  {
    "path": ".github/workflows/vitest.yml",
    "chars": 439,
    "preview": "name: \"Vitest\"\non: [pull_request]\njobs:\n  unit-tests:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checko"
  },
  {
    "path": ".gitignore",
    "chars": 67,
    "preview": "dist\ndocs\nnode_modules\n\n.DS_Store\n.cache\n*.log\n.parcel-cache\n.pnp.*"
  },
  {
    "path": ".nvmrc",
    "chars": 3,
    "preview": "18\n"
  },
  {
    "path": ".prettierignore",
    "chars": 52,
    "preview": "/dist\n/docs\n/generated\n/public\n/src/routes/examples\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 54,
    "preview": "# CHANGELOG\n\nSee the [releases page](../../releases).\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5222,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1014,
    "preview": "# Contributing\n\nThanks for your interest in contributing to this project!\n\nHere are a couple of guidelines to keep in mi"
  },
  {
    "path": "LICENSE",
    "chars": 1078,
    "preview": "The MIT License (MIT)\nCopyright (c) 2020 Brian Vaughn\n\nPermission is hereby granted, free of charge, to any person obtai"
  },
  {
    "path": "README.md",
    "chars": 4620,
    "preview": "<img src=\"https://react-error-boundary-lib.vercel.app/og.png\" alt=\"react-error-boundary logo\" width=\"400\" height=\"210\" /"
  },
  {
    "path": "eslint.config.js",
    "chars": 1801,
    "preview": "import js from \"@eslint/js\";\nimport reactHooks from \"eslint-plugin-react-hooks\";\nimport reactRefresh from \"eslint-plugin"
  },
  {
    "path": "index.css",
    "chars": 470,
    "preview": "@source \"node_modules/react-lib-tools\";\n\n@import \"tailwindcss\";\n@import \"react-lib-tools/styles.css\";\n\n@theme {\n  --colo"
  },
  {
    "path": "index.html",
    "chars": 1103,
    "preview": "<!doctype html>\n<html lang=\"en\">\n  <head>\n    <title>react-error-boundary | runtime error handler</title>\n\n    <link rel"
  },
  {
    "path": "index.tsx",
    "chars": 239,
    "preview": "import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport \"./index.css\";\nimport App from"
  },
  {
    "path": "integrations/vite/README.md",
    "chars": 1942,
    "preview": "# React + TypeScript + Vite\n\nThis template provides a minimal setup to get React working in Vite with HMR and some ESLin"
  },
  {
    "path": "integrations/vite/eslint.config.js",
    "chars": 1161,
    "preview": "import js from \"@eslint/js\";\nimport globals from \"globals\";\nimport reactHooks from \"eslint-plugin-react-hooks\";\nimport r"
  },
  {
    "path": "integrations/vite/index.html",
    "chars": 367,
    "preview": "<!doctype html>\n<html class=\"dark\" lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"w"
  },
  {
    "path": "integrations/vite/package.json",
    "chars": 862,
    "preview": "{\n  \"name\": \"vite\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vite --port "
  },
  {
    "path": "integrations/vite/playwright.config.ts",
    "chars": 413,
    "preview": "import { defineConfig, devices } from \"@playwright/test\";\n\nexport default defineConfig({\n  projects: [\n    {\n      name:"
  },
  {
    "path": "integrations/vite/src/components/Children.tsx",
    "chars": 1019,
    "preview": "import { useLayoutEffect, useState } from \"react\";\n\nexport type SizeProps = {\n  height: number | undefined;\n  width: num"
  },
  {
    "path": "integrations/vite/src/components/Container.tsx",
    "chars": 262,
    "preview": "import { type PropsWithChildren } from \"react\";\n\nexport type ContainerProps = PropsWithChildren<{\n  className?: string |"
  },
  {
    "path": "integrations/vite/src/components/DebugData.tsx",
    "chars": 519,
    "preview": "import { cn } from \"../utils/cn\";\n\nexport function DebugData({ data }: { data: object }) {\n  return (\n    <pre\n      cla"
  },
  {
    "path": "integrations/vite/src/components/Resizer.tsx",
    "chars": 199,
    "preview": "import { type PropsWithChildren } from \"react\";\n\nexport type ResizerProps = PropsWithChildren;\n\nexport function Resizer("
  },
  {
    "path": "integrations/vite/src/index.css",
    "chars": 333,
    "preview": "@import \"tailwindcss\";\n\n@layer base {\n  h1 {\n    @apply mb-4 text-4xl font-bold tracking-tight text-gray-900;\n  }\n  ul {"
  },
  {
    "path": "integrations/vite/src/main.tsx",
    "chars": 411,
    "preview": "import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { BrowserRouter, Route, Routes"
  },
  {
    "path": "integrations/vite/src/routes/Home.tsx",
    "chars": 89,
    "preview": "export function Home() {\n  return <div className=\"w-full h-full\">Coming soon...</div>;\n}\n"
  },
  {
    "path": "integrations/vite/src/utils/assert.ts",
    "chars": 213,
    "preview": "export function assert(\n  expectedCondition: unknown,\n  message: string = \"Assertion error\",\n): asserts expectedConditio"
  },
  {
    "path": "integrations/vite/src/utils/cn.ts",
    "chars": 169,
    "preview": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: C"
  },
  {
    "path": "integrations/vite/src/vite-env.d.ts",
    "chars": 38,
    "preview": "/// <reference types=\"vite/client\" />\n"
  },
  {
    "path": "integrations/vite/test-results/.last-run.json",
    "chars": 46,
    "preview": "{\n  \"status\": \"passed\",\n  \"failedTests\": []\n}\n"
  },
  {
    "path": "integrations/vite/tests/utils/calculateBoxBetween.ts",
    "chars": 425,
    "preview": "import type { Box } from \"./types\";\n\nexport function calculateBoxBetween(boxA: Box, boxB: Box): Box {\n  if (boxA.y === b"
  },
  {
    "path": "integrations/vite/tests/utils/calculateHitArea.ts",
    "chars": 457,
    "preview": "import type { Page } from \"@playwright/test\";\nimport { calculateBoxBetween } from \"./calculateBoxBetween\";\n\nexport async"
  },
  {
    "path": "integrations/vite/tests/utils/debugging/logDebugState.ts",
    "chars": 338,
    "preview": "import type { Page } from \"@playwright/test\";\n\nexport async function logDebugState(page: Page, prefix?: string) {\n  cons"
  },
  {
    "path": "integrations/vite/tests/utils/debugging/logGroup.ts",
    "chars": 209,
    "preview": "import type { Page } from \"@playwright/test\";\n\nexport async function logGroup(page: Page) {\n  console.log(\n    await pag"
  },
  {
    "path": "integrations/vite/tests/utils/expectLayout.ts",
    "chars": 426,
    "preview": "import { expect, type Page } from \"@playwright/test\";\nimport type { Layout } from \"react-resizable-panels\";\n\nexport asyn"
  },
  {
    "path": "integrations/vite/tests/utils/expectPanelSize.ts",
    "chars": 619,
    "preview": "import { expect, type Page } from \"@playwright/test\";\nimport type { PanelSize } from \"react-resizable-panels\";\n\nexport a"
  },
  {
    "path": "integrations/vite/tests/utils/getCenterCoordinates.ts",
    "chars": 191,
    "preview": "import type { Box, Coordinates } from \"./types\";\n\nexport function getCenterCoordinates(box: Box): Coordinates {\n  return"
  },
  {
    "path": "integrations/vite/tests/utils/getSeparatorAriaAttributes.ts",
    "chars": 588,
    "preview": "import type { Page } from \"@playwright/test\";\n\nexport async function getSeparatorAriaAttributes(page: Page, id?: string)"
  },
  {
    "path": "integrations/vite/tests/utils/goToUrl.ts",
    "chars": 1656,
    "preview": "import type { Page } from \"@playwright/test\";\nimport { createElement, type ReactElement } from \"react\";\nimport { PopupWi"
  },
  {
    "path": "integrations/vite/tests/utils/goToUrlWithIframe.ts",
    "chars": 665,
    "preview": "import type { Page } from \"@playwright/test\";\nimport type { ReactElement } from \"react\";\nimport type { GroupProps } from"
  },
  {
    "path": "integrations/vite/tests/utils/pointer-interactions/resizeHelper.ts",
    "chars": 753,
    "preview": "import type { Page } from \"@playwright/test\";\nimport { calculateHitArea } from \"../calculateHitArea\";\nimport { getCenter"
  },
  {
    "path": "integrations/vite/tests/utils/serializer/decode.ts",
    "chars": 4093,
    "preview": "import { createElement, type ReactElement } from \"react\";\nimport type {\n  GroupProps,\n  PanelProps,\n  SeparatorProps,\n} "
  },
  {
    "path": "integrations/vite/tests/utils/serializer/encode.ts",
    "chars": 4834,
    "preview": "import { type PropsWithChildren, type ReactElement } from \"react\";\nimport {\n  Group,\n  Panel,\n  Separator,\n  type GroupP"
  },
  {
    "path": "integrations/vite/tests/utils/serializer/types.ts",
    "chars": 1558,
    "preview": "import type {\n  GroupProps,\n  PanelProps,\n  SeparatorProps,\n} from \"react-resizable-panels\";\nimport type { ContainerProp"
  },
  {
    "path": "integrations/vite/tests/utils/types.ts",
    "chars": 142,
    "preview": "export type Box = {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n};\n\nexport type Coordinates = {\n  x: nu"
  },
  {
    "path": "integrations/vite/tests/utils/updateUrl.ts",
    "chars": 718,
    "preview": "import type { Page } from \"@playwright/test\";\nimport type { ReactElement } from \"react\";\nimport type { GroupProps } from"
  },
  {
    "path": "integrations/vite/tsconfig.json",
    "chars": 588,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"useDefineForClassFields\": true,\n    \"lib\": [\"ES2020\", \"DOM\", \"DOM."
  },
  {
    "path": "integrations/vite/vite.config.ts",
    "chars": 257,
    "preview": "import tailwindcss from \"@tailwindcss/vite\";\nimport { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-reac"
  },
  {
    "path": "lib/components/ErrorBoundary.test.tsx",
    "chars": 10494,
    "preview": "import {\n  createRef,\n  type PropsWithChildren,\n  type ReactElement,\n  type RefObject,\n} from \"react\";\nimport { createRo"
  },
  {
    "path": "lib/components/ErrorBoundary.tsx",
    "chars": 4163,
    "preview": "import { Component, createElement, type ErrorInfo } from \"react\";\nimport { ErrorBoundaryContext } from \"../context/Error"
  },
  {
    "path": "lib/context/ErrorBoundaryContext.ts",
    "chars": 275,
    "preview": "import { createContext } from \"react\";\n\nexport type ErrorBoundaryContextType = {\n  didCatch: boolean;\n  error: unknown |"
  },
  {
    "path": "lib/hooks/useErrorBoundary.test.tsx",
    "chars": 2501,
    "preview": "import { act, useLayoutEffect, type ReactNode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { be"
  },
  {
    "path": "lib/hooks/useErrorBoundary.ts",
    "chars": 1976,
    "preview": "import { useContext, useMemo, useState } from \"react\";\nimport { ErrorBoundaryContext } from \"../context/ErrorBoundaryCon"
  },
  {
    "path": "lib/index.ts",
    "chars": 670,
    "preview": "\"use client\";\n\nexport { ErrorBoundary } from \"./components/ErrorBoundary\";\nexport { ErrorBoundaryContext } from \"./conte"
  },
  {
    "path": "lib/types.ts",
    "chars": 2609,
    "preview": "import type {\n  ComponentType,\n  ErrorInfo,\n  PropsWithChildren,\n  ReactNode,\n} from \"react\";\n\nexport type FallbackProps"
  },
  {
    "path": "lib/utils/assert.ts",
    "chars": 184,
    "preview": "export function assert(\n  expectedCondition: unknown,\n  message: string = \"Assertion error\",\n): asserts expectedConditio"
  },
  {
    "path": "lib/utils/assertErrorBoundaryContext.ts",
    "chars": 359,
    "preview": "import type { ErrorBoundaryContextType } from \"../context/ErrorBoundaryContext\";\nimport { isErrorBoundaryContext } from "
  },
  {
    "path": "lib/utils/getErrorMessage.ts",
    "chars": 353,
    "preview": "export function getErrorMessage(thrown: unknown): string | undefined {\n  switch (typeof thrown) {\n    case \"object\": {\n "
  },
  {
    "path": "lib/utils/isErrorBoundaryContext.ts",
    "chars": 434,
    "preview": "import type { ErrorBoundaryContextType } from \"../context/ErrorBoundaryContext\";\n\nexport function isErrorBoundaryContext"
  },
  {
    "path": "lib/utils/withErrorBoundary.test.tsx",
    "chars": 2012,
    "preview": "import { Component, createRef, type PropsWithChildren } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimp"
  },
  {
    "path": "lib/utils/withErrorBoundary.ts",
    "chars": 782,
    "preview": "import {\n  createElement,\n  forwardRef,\n  type ComponentClass,\n  type ComponentType,\n} from \"react\";\nimport { ErrorBound"
  },
  {
    "path": "package.json",
    "chars": 3869,
    "preview": "{\n  \"name\": \"react-error-boundary\",\n  \"version\": \"6.1.1\",\n  \"type\": \"module\",\n  \"description\": \"Simple reusable React er"
  },
  {
    "path": "pnpm-workspace.yaml",
    "chars": 48,
    "preview": "packages:\n  - integrations/*\n  - lib/*\n  - src/*"
  },
  {
    "path": "public/generated/examples/AsyncUserCodeErrors.json",
    "chars": 4640,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/ErrorLogging.json",
    "chars": 3224,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-keyword\\\">type</sp"
  },
  {
    "path": "public/generated/examples/FallbackComponent.json",
    "chars": 6358,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/FallbackContent.json",
    "chars": 1651,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/GetErrorMessage.json",
    "chars": 2543,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/NpmResolution.json",
    "chars": 723,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-punctuation\\\">{</span><span class=\\\"\\\"></span></div>\\n<div><span class=\\\"\\\">  </span"
  },
  {
    "path": "public/generated/examples/RenderProp.json",
    "chars": 5545,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/ResetWithUseErrorBoundary.json",
    "chars": 1712,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/UseClient.json",
    "chars": 271,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-string\\\">\\\"use client\\\"</span><span class=\\\"tok-punctuation\\\">;</span><span class=\\\""
  },
  {
    "path": "public/generated/examples/UseErrorBoundary.json",
    "chars": 2604,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/WithErrorBoundaryA.json",
    "chars": 1060,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">function</span><span class=\\\"\\\"> </span><span class=\\\"tok-variableName tok"
  },
  {
    "path": "public/generated/examples/WithErrorBoundaryB.json",
    "chars": 2631,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-keyword\\\">import</span><span class=\\\"\\\"> </span><span class=\\\"tok-punctuation\\\">{</s"
  },
  {
    "path": "public/generated/examples/WithErrorBoundaryC.json",
    "chars": 398,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-punctuation\\\">&#60;</span><span class=\\\"tok-typeName\\\">UserProfileWithErrorBoundary<"
  },
  {
    "path": "public/generated/examples/YarnResolution.json",
    "chars": 725,
    "preview": "{\n  \"html\": \"<div><span class=\\\"tok-punctuation\\\">{</span><span class=\\\"\\\"></span></div>\\n<div><span class=\\\"\\\">  </span"
  },
  {
    "path": "public/robots.txt",
    "chars": 22,
    "preview": "User-agent: *\nAllow: /"
  },
  {
    "path": "scripts/compile-docs.ts",
    "chars": 162,
    "preview": "import { compileDocs } from \"react-lib-tools/scripts/compile-docs.ts\";\n\nawait compileDocs({\n  componentNames: [\"ErrorBou"
  },
  {
    "path": "scripts/compile-examples.ts",
    "chars": 105,
    "preview": "import { compileExamples } from \"react-lib-tools/scripts/compile-examples.ts\";\n\nawait compileExamples();\n"
  },
  {
    "path": "scripts/compress-og-image",
    "chars": 105,
    "preview": "import { compressOgImage } from \"react-lib-tools/scripts/compress-og-image.ts\";\n\nawait compressOgImage();"
  },
  {
    "path": "src/App.tsx",
    "chars": 4378,
    "preview": "import {\n  AppRoot,\n  Callout,\n  Code,\n  ExternalLink,\n  NavSection,\n  type CommonQuestion,\n} from \"react-lib-tools\";\nim"
  },
  {
    "path": "src/components/ContinueLink.tsx",
    "chars": 233,
    "preview": "import type { Path } from \"../routes\";\nimport { Link } from \"./Link\";\n\nexport function ContinueLink({ title, to }: { tit"
  },
  {
    "path": "src/components/Divider.tsx",
    "chars": 86,
    "preview": "export function Divider() {\n  return <hr className=\"h-px bg-slate-800 border-0\" />;\n}\n"
  },
  {
    "path": "src/components/Link.tsx",
    "chars": 283,
    "preview": "import type { HTMLAttributes } from \"react\";\nimport { Link as ExternalLink } from \"react-lib-tools\";\nimport type { Path "
  },
  {
    "path": "src/components/NavLink.tsx",
    "chars": 414,
    "preview": "import { type PropsWithChildren } from \"react\";\nimport { NavLink as NavLinkExternal, type DefaultPath } from \"react-lib-"
  },
  {
    "path": "src/routes/AsyncUserCodeErrorsRoute.tsx",
    "chars": 789,
    "preview": "import { Box, Code, Header, Link } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples/AsyncUs"
  },
  {
    "path": "src/routes/ErrorBoundaryPropsRoute.tsx",
    "chars": 337,
    "preview": "import { Box, ComponentProps, type ComponentMetadata } from \"react-lib-tools\";\nimport json from \"../../public/generated/"
  },
  {
    "path": "src/routes/ErrorLoggingRoute.tsx",
    "chars": 444,
    "preview": "import { Box, Code, Header } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples/ErrorLogging."
  },
  {
    "path": "src/routes/FallbackComponentRoute.tsx",
    "chars": 462,
    "preview": "import { Box, Code, Header } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples/FallbackCompo"
  },
  {
    "path": "src/routes/FallbackContentRoute.tsx",
    "chars": 398,
    "preview": "import { Box, Code, Header } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples/FallbackConte"
  },
  {
    "path": "src/routes/GetErrorMessageRoute.tsx",
    "chars": 940,
    "preview": "import { Box, Code, ExternalLink, Header } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples"
  },
  {
    "path": "src/routes/RenderPropRoute.tsx",
    "chars": 618,
    "preview": "import { Box, Code, ExternalLink, Header } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples"
  },
  {
    "path": "src/routes/ResetNearestBoundaryRoute.tsx",
    "chars": 603,
    "preview": "import { Box, Code, Header } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples/ResetWithUseE"
  },
  {
    "path": "src/routes/UseErrorBoundaryRoute.tsx",
    "chars": 605,
    "preview": "import { Box, Callout, Code, Header } from \"react-lib-tools\";\nimport { html } from \"../../public/generated/examples/UseE"
  },
  {
    "path": "src/routes/WithErrorBoundaryRoute.tsx",
    "chars": 1145,
    "preview": "import { Box, Code, ExternalLink, Header } from \"react-lib-tools\";\nimport { html as htmlA } from \"../../public/generated"
  },
  {
    "path": "src/routes/examples/AsyncUserCodeErrors.tsx",
    "chars": 565,
    "preview": "import { useEffect } from \"react\"; // hidden\nimport { useErrorBoundary } from \"react-error-boundary\";\n\nfunction useUserP"
  },
  {
    "path": "src/routes/examples/ErrorLogging.tsx",
    "chars": 461,
    "preview": "import type { ErrorInfo } from \"react\";\nimport { ErrorBoundary } from \"react-error-boundary\";\n\nfunction logError(error: "
  },
  {
    "path": "src/routes/examples/FallbackComponent.tsx",
    "chars": 639,
    "preview": "import { ErrorBoundary, getErrorMessage, type FallbackProps } from \"react-error-boundary\";\n\nfunction Fallback({ error, r"
  },
  {
    "path": "src/routes/examples/FallbackContent.tsx",
    "chars": 211,
    "preview": "import { ErrorBoundary } from \"react-error-boundary\";\n\n<ErrorBoundary fallback={<div>Something went wrong</div>}>\n  <You"
  },
  {
    "path": "src/routes/examples/GetErrorMessage.ts",
    "chars": 427,
    "preview": "import { getErrorMessage, type FallbackProps } from \"react-error-boundary\";\n\nfunction Fallback({ error }: FallbackProps)"
  },
  {
    "path": "src/routes/examples/NpmResolution.json",
    "chars": 54,
    "preview": "{\n  \"overrides\": {\n    \"@types/react\": \"17.0.60\"\n  }\n}"
  },
  {
    "path": "src/routes/examples/RenderProp.tsx",
    "chars": 563,
    "preview": "import { ErrorBoundary, getErrorMessage } from \"react-error-boundary\";\n\n<ErrorBoundary\n  fallbackRender={({ error, reset"
  },
  {
    "path": "src/routes/examples/ResetWithUseErrorBoundary.tsx",
    "chars": 275,
    "preview": "import { useErrorBoundary } from \"react-error-boundary\";\n\nfunction Example() {\n  const { resetBoundary } = useErrorBound"
  },
  {
    "path": "src/routes/examples/UseClient.ts",
    "chars": 56,
    "preview": "\"use client\";\n\n// Imports and components code go here..."
  },
  {
    "path": "src/routes/examples/UseErrorBoundary.tsx",
    "chars": 502,
    "preview": "import { useErrorBoundary } from \"react-error-boundary\";\n\nfunction Example() {\n  const {\n    // The currently visible Er"
  },
  {
    "path": "src/routes/examples/WithErrorBoundaryA.tsx",
    "chars": 158,
    "preview": "function UserProfile({ username }: { username: string }) {\n  username; // hidden\n  return null; // hidden\n  // Render..."
  },
  {
    "path": "src/routes/examples/WithErrorBoundaryB.tsx",
    "chars": 449,
    "preview": "import { UserProfile } from \"./WithErrorBoundaryA\";\n\n// <begin>\n\nimport { withErrorBoundary } from \"react-error-boundary"
  },
  {
    "path": "src/routes/examples/WithErrorBoundaryC.tsx",
    "chars": 133,
    "preview": "import { UserProfileWithErrorBoundary } from \"./WithErrorBoundaryB\";\n\n// <begin>\n\n<UserProfileWithErrorBoundary username"
  },
  {
    "path": "src/routes/examples/YarnResolution.json",
    "chars": 56,
    "preview": "{\n  \"resolutions\": {\n    \"@types/react\": \"17.0.60\"\n  }\n}"
  },
  {
    "path": "src/routes.ts",
    "chars": 1203,
    "preview": "import { lazy, type ComponentType, type LazyExoticComponent } from \"react\";\n\nexport type Route = LazyExoticComponent<Com"
  },
  {
    "path": "src/vite-env.d.ts",
    "chars": 88,
    "preview": "/// <reference types=\"vite/client\" />\n/// <reference types=\"vite-plugin-svgr/client\" />\n"
  },
  {
    "path": "tsconfig.json",
    "chars": 942,
    "preview": "{\n  \"compilerOptions\": {\n    \"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n    \"target\": \"ES2022\",\n"
  },
  {
    "path": "vercel.json",
    "chars": 96,
    "preview": "{\n  \"rewrites\": [\n    {\n      \"source\": \"/(.*)\",\n      \"destination\": \"/index.html\"\n    }\n  ]\n}\n"
  },
  {
    "path": "vite.config.ts",
    "chars": 1854,
    "preview": "import tailwindcss from \"@tailwindcss/vite\";\nimport react from \"@vitejs/plugin-react-swc\";\nimport { dirname, resolve } f"
  },
  {
    "path": "vitest.config.ts",
    "chars": 560,
    "preview": "import { defineConfig, mergeConfig } from \"vitest/config\";\nimport viteConfig from \"./vite.config\";\n\nexport default merge"
  },
  {
    "path": "vitest.d.ts",
    "chars": 128,
    "preview": "import \"vitest\";\n\ndeclare module \"vitest\" {\n  interface Matchers {\n    toLogError: (expectedError: string) => ReturnType"
  },
  {
    "path": "vitest.setup.ts",
    "chars": 1558,
    "preview": "import \"@testing-library/jest-dom/vitest\";\nimport { cleanup } from \"@testing-library/react\";\nimport { afterAll, afterEac"
  }
]

About this extraction

This page contains the full source code of the bvaughn/react-error-boundary GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 122 files (129.2 KB), approximately 36.3k tokens, and a symbol index with 130 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!