shelving
Version:
Toolkit for using data in JavaScript.
62 lines (61 loc) • 2.72 kB
JavaScript
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { ArrowPathIcon } from "@heroicons/react/24/solid";
import { Component, createContext, use } from "react";
import { getMessage } from "../../util/error.js";
import { Card } from "../block/Card.js";
import { Subheading } from "../block/Subheading.js";
import { Button } from "../form/Button.js";
import { CenteredLayout } from "../layout/CenteredLayout.js";
import { Notice } from "../notice/Notice.js";
import { Page } from "../page/Page.js";
import { Flex } from "../style/Flex.js";
import { StatusIcon } from "./StatusIcon.js";
const RetryContext = createContext(undefined);
RetryContext.displayName = "RetryContext";
const RETRY_CHILDREN = (_jsxs(_Fragment, { children: [_jsx(ArrowPathIcon, {}), "Retry"] }));
export function RetryButton({ children = RETRY_CHILDREN, ...props }) {
const retry = use(RetryContext);
if (!retry)
return null;
return (_jsx(Button, { onClick: retry, ...props, children: children }));
}
/**
* React component that provides an Error Boundary.
* If an error occurs in any component under this, a general error will be shown to the user.
*/
export class Catcher extends Component {
static defaultProps = {
as: ErrorNotice,
};
state = {
reason: undefined,
};
retry = () => {
this.setState({ reason: undefined });
};
static getDerivedStateFromError(reason) {
return { reason };
}
render() {
const { retry, state, props } = this;
const { reason } = state;
const { as: ErrorComponent, children } = props;
if (!reason)
return children;
return (_jsx(RetryContext, { value: retry, children: _jsx(ErrorComponent, { reason: reason }) }));
}
}
/** Catch errors in a page. */
export function PageCatcher({ children }) {
return _jsx(Catcher, { as: ErrorPage, children: children });
}
/** Output a `<Notice>` for an unknown error reason. */
export function ErrorNotice({ reason }) {
const message = getMessage(reason) ?? "Unknown error";
return (_jsxs(Notice, { status: "error", children: [_jsx("p", { children: message }), _jsx(RetryButton, { small: true, fit: true })] }));
}
/** Output a `<Page>` with an error `<Card>` for an unknown error reason. */
export function ErrorPage({ reason }) {
const message = getMessage(reason) ?? "Unknown error";
return (_jsx(Page, { title: "Error", children: _jsx(CenteredLayout, { children: _jsx(Card, { status: "error", children: _jsxs(Subheading, { children: [_jsxs(Flex, { left: true, children: [_jsx(StatusIcon, { status: "error", xlarge: true }), " ", message] }), _jsx(RetryButton, {})] }) }) }) }));
}