{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "error-pages",
  "title": "Error Pages",
  "type": "registry:block",
  "description": "Pack of four status screens — 404, 500, 403, and 503 — each with a matching isometric illustration, code, copy, and actions. `variant` picks a single screen, `size` compacts it. Override title, description, image, code, tag, labels, hrefs, disabled flags, and callbacks. Pass `image=\"\"` to hide the art.",
  "categories": [
    "layout",
    "marketing",
    "utility"
  ],
  "deprecated": true,
  "replacedBy": "error-page",
  "files": [
    {
      "path": "packages/elements-lit/src/blocks/error-pages/error-pages.ts",
      "content": "import { LitElement, css, html, nothing } from 'lit'\nimport { Clock, RotateCcw } from 'lucide'\nimport { cn } from '../../lib/utils'\nimport { tailwind } from '../../lib/styles'\nimport { ThemeController } from '../../lib/theme'\nimport { icon } from '../../lib/icon'\n// Side-effect import: registers <uip-button> for standalone use (consumers\n// who install only this block still get a working button).\nimport '../../components/button/button'\n\nexport type ErrorPagesVariant = '404' | '500' | '403' | 'maintenance'\n\nconst falseConverter = { fromAttribute: (v: string | null) => v !== null && v !== 'false' }\n\n/**\n * <uip-error-pages> — the registry ErrorPages block as a web component.\n *\n * Class strings are React's ErrorPages verbatim. `heading` is React's `title`\n * (`title` is taken by HTMLElement). `onHome` / `onSearch` / `onRetry` /\n * `onStatus` / `onSwitchAccount` / `onRequestAccess` / `onSubscribe` become\n * `home` / `search` / `retry` / `status` / `switch-account` / `request-access`\n * / `subscribe` CustomEvents (bubbles, composed).\n *\n * Deviation: React's `image === undefined` HTTP-panel branches are\n * unreachable (every variant has a default image), so they are not ported:\n * omit `image` for the default art, pass `image=\"\"` to hide it.\n */\nexport class UipErrorPages extends LitElement {\n  static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }\n  // :host display can't be a utility class (the host has no template of its own).\n  static styles = [tailwind, css`:host { display: block; }`]\n\n  static properties = {\n    variant: {},\n    size: { reflect: true },\n    heading: {},\n    description: {},\n    code: {},\n    tag: {},\n    image: {},\n    imageAlt: { attribute: 'image-alt' },\n    primaryLabel: { attribute: 'primary-label' },\n    secondaryLabel: { attribute: 'secondary-label' },\n    primaryHref: { attribute: 'primary-href' },\n    secondaryHref: { attribute: 'secondary-href' },\n    showPrimary: { type: Boolean, attribute: 'show-primary', converter: falseConverter },\n    showSecondary: { type: Boolean, attribute: 'show-secondary', converter: falseConverter },\n    primaryDisabled: { type: Boolean, attribute: 'primary-disabled' },\n    secondaryDisabled: { type: Boolean, attribute: 'secondary-disabled' },\n  }\n\n  variant: ErrorPagesVariant | 'all' = 'all'\n  size: 'sm' | 'default' = 'default'\n  heading?: string\n  description?: string\n  code?: string\n  tag?: string\n  image?: string\n  imageAlt = ''\n  primaryLabel?: string\n  secondaryLabel?: string\n  primaryHref?: string\n  secondaryHref?: string\n  showPrimary = true\n  showSecondary = true\n  primaryDisabled = false\n  secondaryDisabled = false\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'error-pages')\n    this.setAttribute('data-size', this.size)\n  }\n\n  willUpdate() {\n    this.setAttribute('data-size', this.size)\n  }\n\n  private emit(\n    name: 'home' | 'search' | 'retry' | 'status' | 'switch-account' | 'request-access' | 'subscribe',\n  ) {\n    this.dispatchEvent(new CustomEvent(name, { bubbles: true, composed: true }))\n  }\n\n  private action(opts: {\n    label: string\n    size: 'xs' | 'sm'\n    variant?: string\n    disabled: boolean\n    href?: string\n    event: 'home' | 'search' | 'retry' | 'status' | 'switch-account' | 'request-access' | 'subscribe'\n    leadingIcon?: boolean\n  }) {\n    return html`<uip-button\n      size=${opts.size}\n      variant=${opts.variant ?? nothing}\n      ?disabled=${opts.disabled}\n      href=${opts.href ?? nothing}\n      @click=${() => this.emit(opts.event)}\n    >\n      ${opts.leadingIcon ? icon(RotateCcw, 'rotate-ccw') : nothing}${opts.label}\n    </uip-button>`\n  }\n\n  render() {\n    const sm = this.size === 'sm'\n    const single = (v: ErrorPagesVariant) => this.variant === v\n    const pick = (v: ErrorPagesVariant, fallback: string, override?: string) =>\n      single(v) ? (override ?? fallback) : fallback\n    const frameClass = cn(\n      'border-border bg-card overflow-hidden rounded-xl border text-left',\n      sm && 'rounded-lg',\n    )\n    const imgClass = 'aspect-[16/10] w-full object-cover'\n    const bodyClass = sm ? 'p-5' : 'p-6'\n    const codeClass = cn('font-semibold tracking-tighter', sm ? 'text-2xl' : 'text-4xl')\n    const titleClass = cn('mt-1.5 font-semibold tracking-tight', sm ? 'text-base' : 'text-xl')\n    const descClass = 'text-muted-foreground mt-2 max-w-sm text-sm'\n    const actionsClass = cn('flex flex-wrap items-center gap-2', sm ? 'mt-4' : 'mt-5')\n    const actionSize = sm ? ('xs' as const) : ('sm' as const)\n    const show = (v: ErrorPagesVariant) => this.variant === 'all' || single(v)\n\n    const title404 = pick('404', 'Page not found', this.heading)\n    const desc404 = pick(\n      '404',\n      \"The page you're looking for doesn't exist or was moved. Check the URL or head back home.\",\n      this.description,\n    )\n    const code404 = pick('404', '404', this.code)\n    const image404 = pick('404', '/illustrations/error-404.jpg', this.image)\n    const primary404 = pick('404', 'Go home', this.primaryLabel)\n    const secondary404 = pick('404', 'Search docs', this.secondaryLabel)\n\n    const title500 = pick('500', 'Internal server error', this.heading)\n    const desc500 = pick(\n      '500',\n      'Something went wrong on our end. The team has been notified — try again in a moment.',\n      this.description,\n    )\n    const code500 = pick('500', '500', this.code)\n    const image500 = pick('500', '/illustrations/error-500.jpg', this.image)\n    const primary500 = pick('500', 'Retry', this.primaryLabel)\n    const secondary500 = pick('500', 'Status page', this.secondaryLabel)\n\n    const title403 = pick('403', 'Access denied', this.heading)\n    const desc403 = pick(\n      '403',\n      \"You don't have permission to view this page. Switch accounts or ask an admin to request access.\",\n      this.description,\n    )\n    const code403 = pick('403', '403', this.code)\n    const image403 = pick('403', '/illustrations/error-403.jpg', this.image)\n    const primary403 = pick('403', 'Request access', this.primaryLabel)\n    const secondary403 = pick('403', 'Switch account', this.secondaryLabel)\n\n    const title503 = pick('maintenance', 'Scheduled maintenance', this.heading)\n    const desc503 = pick(\n      'maintenance',\n      \"We're upgrading our systems. The service will be back online shortly.\",\n      this.description,\n    )\n    const code503 = pick('maintenance', '503', this.code)\n    const image503 = pick('maintenance', '/illustrations/error-maintenance.jpg', this.image)\n    const tag503 = pick('maintenance', 'Back online around 14:00 UTC', this.tag)\n    const primary503 = pick('maintenance', 'Subscribe for updates', this.primaryLabel)\n    const secondary503 = this.secondaryLabel ?? ''\n\n    return html`\n      <div data-slot=\"error-pages\" data-size=${this.size} class=${cn(this.variant === 'all' && 'grid gap-4 sm:grid-cols-2')}>\n        ${show('404')\n          ? html`<article class=${frameClass} data-slot=\"error-page\" data-variant=\"404\" role=\"status\">\n              ${image404 ? html`<img src=${image404} alt=${this.imageAlt} class=${imgClass} />` : nothing}\n              <div class=${bodyClass}>\n                ${code404 ? html`<p class=${codeClass}>${code404}</p>` : nothing}\n                <h3 class=${titleClass}>${title404}</h3>\n                <p class=${descClass}>${desc404}</p>\n                ${single('404') && this.tag\n                  ? html`<p class=\"text-muted-foreground mt-3 inline-flex items-center rounded-full border px-3 py-1 text-xs\">\n                      ${this.tag}\n                    </p>`\n                  : nothing}\n                ${this.showPrimary || this.showSecondary\n                  ? html`<div class=${actionsClass}>\n                      ${this.showPrimary\n                        ? this.action({\n                            label: primary404,\n                            size: actionSize,\n                            disabled: this.primaryDisabled,\n                            href: this.primaryHref,\n                            event: 'home',\n                          })\n                        : nothing}\n                      ${this.showSecondary\n                        ? this.action({\n                            label: secondary404,\n                            size: actionSize,\n                            variant: 'ghost',\n                            disabled: this.secondaryDisabled,\n                            href: this.secondaryHref,\n                            event: 'search',\n                          })\n                        : nothing}\n                    </div>`\n                  : nothing}\n              </div>\n            </article>`\n          : nothing}\n        ${show('500')\n          ? html`<article class=${frameClass} data-slot=\"error-page\" data-variant=\"500\" role=\"alert\">\n              ${image500 ? html`<img src=${image500} alt=${this.imageAlt} class=${imgClass} />` : nothing}\n              <div class=${bodyClass}>\n                ${code500 ? html`<p class=${codeClass}>${code500}</p>` : nothing}\n                <h3 class=${titleClass}>${title500}</h3>\n                <p class=${descClass}>${desc500}</p>\n                ${single('500') && this.tag\n                  ? html`<p class=\"text-muted-foreground mt-3 inline-flex items-center rounded-full border px-3 py-1 text-xs\">\n                      ${this.tag}\n                    </p>`\n                  : nothing}\n                ${this.showPrimary || this.showSecondary\n                  ? html`<div class=${actionsClass}>\n                      ${this.showPrimary\n                        ? this.action({\n                            label: primary500,\n                            size: actionSize,\n                            disabled: this.primaryDisabled,\n                            href: this.primaryHref,\n                            event: 'retry',\n                            leadingIcon: true,\n                          })\n                        : nothing}\n                      ${this.showSecondary\n                        ? this.action({\n                            label: secondary500,\n                            size: actionSize,\n                            variant: 'outline',\n                            disabled: this.secondaryDisabled,\n                            href: this.secondaryHref,\n                            event: 'status',\n                          })\n                        : nothing}\n                    </div>`\n                  : nothing}\n              </div>\n            </article>`\n          : nothing}\n        ${show('403')\n          ? html`<article class=${frameClass} data-slot=\"error-page\" data-variant=\"403\" role=\"alert\">\n              ${image403 ? html`<img src=${image403} alt=${this.imageAlt} class=${imgClass} />` : nothing}\n              <div class=${bodyClass}>\n                ${code403 ? html`<p class=${codeClass}>${code403}</p>` : nothing}\n                <h3 class=${titleClass}>${title403}</h3>\n                <p class=${descClass}>${desc403}</p>\n                ${single('403') && this.tag\n                  ? html`<p class=\"text-muted-foreground mt-3 inline-flex items-center rounded-full border px-3 py-1 text-xs\">\n                      ${this.tag}\n                    </p>`\n                  : nothing}\n                ${this.showPrimary || this.showSecondary\n                  ? html`<div class=${actionsClass}>\n                      ${this.showSecondary\n                        ? this.action({\n                            label: secondary403,\n                            size: actionSize,\n                            variant: 'outline',\n                            disabled: this.secondaryDisabled,\n                            href: this.secondaryHref,\n                            event: 'switch-account',\n                          })\n                        : nothing}\n                      ${this.showPrimary\n                        ? this.action({\n                            label: primary403,\n                            size: actionSize,\n                            disabled: this.primaryDisabled,\n                            href: this.primaryHref,\n                            event: 'request-access',\n                          })\n                        : nothing}\n                    </div>`\n                  : nothing}\n              </div>\n            </article>`\n          : nothing}\n        ${show('maintenance')\n          ? html`<article class=${frameClass} data-slot=\"error-page\" data-variant=\"maintenance\" role=\"status\">\n              ${image503 ? html`<img src=${image503} alt=${this.imageAlt} class=${imgClass} />` : nothing}\n              <div class=${bodyClass}>\n                ${code503 ? html`<p class=${codeClass}>${code503}</p>` : nothing}\n                <h3 class=${titleClass}>${title503}</h3>\n                <p class=${descClass}>${desc503}</p>\n                ${tag503\n                  ? html`<p class=\"text-muted-foreground mt-3 inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs\">\n                      ${icon(Clock, 'clock', 'size-3.5')} ${tag503}\n                    </p>`\n                  : nothing}\n                ${this.showPrimary || (this.showSecondary && secondary503)\n                  ? html`<div class=${actionsClass}>\n                      ${this.showPrimary\n                        ? this.action({\n                            label: primary503,\n                            size: actionSize,\n                            variant: 'ghost',\n                            disabled: this.primaryDisabled,\n                            href: this.primaryHref,\n                            event: 'subscribe',\n                          })\n                        : nothing}\n                      ${this.showSecondary && secondary503\n                        ? this.action({\n                            label: secondary503,\n                            size: actionSize,\n                            variant: 'outline',\n                            disabled: this.secondaryDisabled,\n                            href: this.secondaryHref,\n                            event: 'status',\n                          })\n                        : nothing}\n                    </div>`\n                  : nothing}\n              </div>\n            </article>`\n          : nothing}\n      </div>\n    `\n  }\n}\n\ncustomElements.get('uip-error-pages') || customElements.define('uip-error-pages', UipErrorPages)\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'uip-error-pages': UipErrorPages\n  }\n}\n",
      "type": "registry:file",
      "target": "src/uip/blocks/error-pages/error-pages.ts"
    }
  ],
  "dependencies": [
    "lit",
    "lucide"
  ],
  "registryDependencies": [
    "https://uipkge.dev/r/lit/button.json",
    "https://uipkge.dev/r/lit/lit-core.json"
  ]
}
