@ossido-labs/ossido-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +19 -0
- package/dist/esm/components/BaseStyles.d.ts +8 -0
- package/dist/esm/components/BaseStyles.js +17 -0
- package/dist/esm/components/BaseStyles.js.map +1 -0
- package/dist/esm/components/DefaultError.d.ts +9 -0
- package/dist/esm/components/DefaultError.js +30 -0
- package/dist/esm/components/DefaultError.js.map +1 -0
- package/dist/esm/components/DefaultLoading.d.ts +6 -0
- package/dist/esm/components/DefaultLoading.js +13 -0
- package/dist/esm/components/DefaultLoading.js.map +1 -0
- package/dist/esm/components/DefaultScreen.d.ts +19 -0
- package/dist/esm/components/DefaultScreen.js +96 -0
- package/dist/esm/components/DefaultScreen.js.map +1 -0
- package/dist/esm/components/DevBuildErrorContent.d.ts +11 -0
- package/dist/esm/components/DevBuildErrorContent.js +56 -0
- package/dist/esm/components/DevBuildErrorContent.js.map +1 -0
- package/dist/esm/components/DevErrorContent.d.ts +4 -0
- package/dist/esm/components/DevErrorContent.js +192 -0
- package/dist/esm/components/DevErrorContent.js.map +1 -0
- package/dist/esm/components/DevErrorOverlay.d.ts +13 -0
- package/dist/esm/components/DevErrorOverlay.js +53 -0
- package/dist/esm/components/DevErrorOverlay.js.map +1 -0
- package/dist/esm/components/DevErrorOverlayHost.d.ts +2 -0
- package/dist/esm/components/DevErrorOverlayHost.js +295 -0
- package/dist/esm/components/DevErrorOverlayHost.js.map +1 -0
- package/dist/esm/components/DevErrorReporter.d.ts +13 -0
- package/dist/esm/components/DevErrorReporter.js +28 -0
- package/dist/esm/components/DevErrorReporter.js.map +1 -0
- package/dist/esm/components/base.js +6 -0
- package/dist/esm/components/base.js.map +1 -0
- package/dist/esm/components/devErrorSource.d.ts +96 -0
- package/dist/esm/components/devErrorSource.js +321 -0
- package/dist/esm/components/devErrorSource.js.map +1 -0
- package/dist/esm/components/devErrorStore.d.ts +105 -0
- package/dist/esm/components/devErrorStore.js +186 -0
- package/dist/esm/components/devErrorStore.js.map +1 -0
- package/dist/esm/components/devErrorStyles.d.ts +6 -0
- package/dist/esm/components/devErrorStyles.js +426 -0
- package/dist/esm/components/devErrorStyles.js.map +1 -0
- package/dist/esm/index.d.ts +11 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/types.d.ts +26 -0
- package/dist/esm/vite/error-overlay.d.ts +32 -0
- package/dist/esm/vite/error-overlay.js +49 -0
- package/dist/esm/vite/error-overlay.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devErrorStore.js","names":[],"sources":["../../../src/components/devErrorStore.ts"],"sourcesContent":["/**\n * Development-only store that aggregates every kind of dev error behind one\n * overlay: React render errors (and SSR/Rust panics) caught by the route error\n * boundary, uncaught `window` errors, unhandled promise rejections, and Vite\n * build/compile errors. {@link DevErrorOverlayHost} subscribes to it via\n * `useSyncExternalStore` and renders a persistent dev indicator + browsable\n * error overlay.\n *\n * The store is a module singleton (not React state) so it exists before the\n * overlay mounts and independently of which subtree threw. It is also published\n * on `window.__OSSIDO_DEV_ERRORS__` so the Vite HMR client — patched by\n * `ErrorOverlayVitePlugin`, which runs outside the module system — can report\n * build errors into it without needing `import.meta.hot`.\n */\n\n/** The distinct sources an aggregated error can come from. */\nexport type DevErrorKind =\n | 'runtime'\n | 'uncaught'\n | 'unhandledrejection'\n | 'build';\n\n/**\n * A Vite build/compile error (a subset of Vite's `ErrorPayload['err']`). Kept\n * structural rather than importing from `vite` so this module carries no build\n * dependency.\n */\nexport interface DevBuildError {\n message: string;\n stack?: string;\n id?: string;\n frame?: string;\n plugin?: string;\n loc?: { file?: string; line?: number; column?: number };\n}\n\nexport interface DevErrorEntry {\n id: number;\n kind: DevErrorKind;\n /** Present for JS errors (`runtime` / `uncaught` / `unhandledrejection`). */\n error?: Error;\n /** Present for `build` errors. */\n build?: DevBuildError;\n /** Only in-place-resettable errors (the route boundary) carry a reset. */\n reset?: () => void;\n /** How many times this identical error has been reported (dedup counter). */\n occurrences: number;\n /** Dedup key — identical errors collapse to a single entry. */\n signature: string;\n}\n\n/** Which screen corner the dev indicator sits in. */\nexport type DevOverlayCorner =\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right';\n\nexport const DEV_OVERLAY_CORNERS: ReadonlyArray<DevOverlayCorner> = [\n 'top-left',\n 'top-right',\n 'bottom-left',\n 'bottom-right',\n];\n\nexport interface DevErrorState {\n entries: ReadonlyArray<DevErrorEntry>;\n /** Index of the entry currently shown in the pager. */\n activeIndex: number;\n /** The full error overlay is open (only meaningful when there are errors). */\n overlayOpen: boolean;\n /** The indicator's menu popover is open. */\n menuOpen: boolean;\n /** The user hid the idle indicator for this session (errors still force it). */\n badgeHidden: boolean;\n /** Which corner the indicator sits in (persisted across reloads). */\n position: DevOverlayCorner;\n}\n\nconst DEFAULT_CORNER: DevOverlayCorner = 'bottom-left';\nconst CORNER_STORAGE_KEY = 'ossido:dev-overlay-corner';\n\n/** The corner is a persisted preference; hiding the badge is per-session. */\nfunction loadCorner(): DevOverlayCorner {\n try {\n const stored = globalThis.localStorage?.getItem(CORNER_STORAGE_KEY);\n if (\n stored &&\n (DEV_OVERLAY_CORNERS as ReadonlyArray<string>).includes(stored)\n )\n return stored as DevOverlayCorner;\n } catch {\n // localStorage can be unavailable (SSR, privacy mode) — use the default.\n }\n return DEFAULT_CORNER;\n}\n\nfunction saveCorner(corner: DevOverlayCorner): void {\n try {\n globalThis.localStorage?.setItem(CORNER_STORAGE_KEY, corner);\n } catch {\n // Best-effort — a failed write just means the corner isn't remembered.\n }\n}\n\nconst EMPTY_STATE: DevErrorState = {\n entries: [],\n activeIndex: 0,\n overlayOpen: false,\n menuOpen: false,\n badgeHidden: false,\n position: DEFAULT_CORNER,\n};\n\nconst BRIDGE_KEY = '__OSSIDO_DEV_ERRORS__';\nconst BUFFER_KEY = '__OSSIDO_DEV_ERRORS_BUFFER__';\n\n// Deliberately kind-agnostic: React rethrows a caught render error to\n// `window.onerror` in dev, so the same error arrives as both `runtime` (from the\n// boundary) and `uncaught`. Keying on the error identity collapses them into one\n// entry (upgraded to `runtime` so it keeps a working \"Try again\").\nfunction jsSignature(error: Error): string {\n return `${error.name}:${error.message}:${(error.stack ?? '').slice(0, 200)}`;\n}\n\n// Build errors replace one another (Vite reports the latest), so they share a\n// single signature — a new build error overwrites the previous one.\nconst BUILD_SIGNATURE = 'build';\n\nclass DevErrorStore {\n private entries: Array<DevErrorEntry> = [];\n private activeIndex = 0;\n private overlayOpen = false;\n private menuOpen = false;\n private badgeHidden = false;\n private position: DevOverlayCorner = loadCorner();\n private nextId = 1;\n private listeners = new Set<() => void>();\n // Cached immutable snapshot for `useSyncExternalStore` referential stability.\n private snapshot: DevErrorState = EMPTY_STATE;\n\n constructor() {\n // Build the initial snapshot from the loaded fields (notably the persisted\n // corner) so the first render already reflects it.\n this.commit();\n }\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return (): void => {\n this.listeners.delete(listener);\n };\n };\n\n getSnapshot = (): DevErrorState => this.snapshot;\n\n getServerSnapshot = (): DevErrorState => EMPTY_STATE;\n\n private commit(): void {\n this.activeIndex = Math.min(\n Math.max(this.activeIndex, 0),\n Math.max(this.entries.length - 1, 0),\n );\n this.snapshot = {\n entries: this.entries.slice(),\n activeIndex: this.activeIndex,\n // The overlay is only meaningful when there is something to show.\n overlayOpen: this.overlayOpen && this.entries.length > 0,\n menuOpen: this.menuOpen,\n badgeHidden: this.badgeHidden,\n position: this.position,\n };\n for (const listener of this.listeners) listener();\n }\n\n /** Add (or refresh) a JS error. Returns its id so the reporter can remove it. */\n addJsError = (\n kind: Exclude<DevErrorKind, 'build'>,\n error: Error,\n reset?: () => void,\n ): number => {\n const signature = jsSignature(error);\n const existing = this.entries.find((e) => e.signature === signature);\n if (existing) {\n // A `runtime` report (from the boundary) carries a reset and is the\n // richer representation — let it win over a bare `uncaught` duplicate.\n if (kind === 'runtime') {\n existing.kind = 'runtime';\n existing.reset = reset ?? existing.reset;\n }\n // Identical errors dedupe (so a re-render loop can't flood the pager), but\n // a recurrence still counts and re-opens the overlay.\n existing.occurrences += 1;\n this.activeIndex = this.entries.indexOf(existing);\n this.overlayOpen = true;\n this.commit();\n return existing.id;\n }\n const entry: DevErrorEntry = {\n id: this.nextId++,\n kind,\n error,\n reset,\n occurrences: 1,\n signature,\n };\n this.entries.push(entry);\n this.activeIndex = this.entries.length - 1;\n // A genuinely new error opens the overlay.\n this.overlayOpen = true;\n this.commit();\n return entry.id;\n };\n\n /** Report a Vite build error — replaces any previous one. */\n addBuildError = (build: DevBuildError): number => {\n this.entries = this.entries.filter((e) => e.kind !== 'build');\n const entry: DevErrorEntry = {\n id: this.nextId++,\n kind: 'build',\n build,\n occurrences: 1,\n signature: BUILD_SIGNATURE,\n };\n this.entries.push(entry);\n this.activeIndex = this.entries.length - 1;\n this.overlayOpen = true;\n this.commit();\n return entry.id;\n };\n\n /** Clear the current build error (called when Vite reports a successful update). */\n clearBuildErrors = (): void => {\n if (!this.entries.some((e) => e.kind === 'build')) return;\n this.entries = this.entries.filter((e) => e.kind !== 'build');\n this.commit();\n };\n\n removeById = (id: number): void => {\n const next = this.entries.filter((e) => e.id !== id);\n if (next.length === this.entries.length) return;\n this.entries = next;\n this.commit();\n };\n\n setActiveIndex = (index: number): void => {\n this.activeIndex = index;\n this.commit();\n };\n\n next = (): void => {\n if (this.entries.length === 0) return;\n this.activeIndex = (this.activeIndex + 1) % this.entries.length;\n this.commit();\n };\n\n prev = (): void => {\n if (this.entries.length === 0) return;\n this.activeIndex =\n (this.activeIndex - 1 + this.entries.length) % this.entries.length;\n this.commit();\n };\n\n /** Open the full error overlay (from the indicator menu's \"View errors\"). */\n openOverlay = (): void => {\n this.overlayOpen = true;\n this.menuOpen = false;\n this.commit();\n };\n\n /** Close the overlay back to the indicator (X / Esc / click-away). */\n closeOverlay = (): void => {\n this.overlayOpen = false;\n this.commit();\n };\n\n toggleMenu = (): void => {\n this.menuOpen = !this.menuOpen;\n this.commit();\n };\n\n closeMenu = (): void => {\n if (!this.menuOpen) return;\n this.menuOpen = false;\n this.commit();\n };\n\n /** Hide the idle indicator for this session (a new error still forces it back). */\n hideBadge = (): void => {\n this.badgeHidden = true;\n this.menuOpen = false;\n this.commit();\n };\n\n setPosition = (corner: DevOverlayCorner): void => {\n this.position = corner;\n saveCorner(corner);\n this.commit();\n };\n\n /**\n * Publish the store on `window` and drain any errors buffered by the Vite\n * client before this module loaded. Safe to call repeatedly.\n */\n installBridge(): void {\n if (typeof window === 'undefined') return;\n const globalWindow = window as unknown as Record<string, unknown>;\n globalWindow[BRIDGE_KEY] = this;\n const buffered = globalWindow[BUFFER_KEY] as\n | Array<DevBuildError>\n | undefined;\n if (buffered?.length) {\n for (const build of buffered) this.addBuildError(build);\n globalWindow[BUFFER_KEY] = [];\n }\n }\n}\n\nexport const devErrorStore = new DevErrorStore();\n\n// Publish immediately on import (client only) so build errors reported by the\n// patched Vite client always have a target.\ndevErrorStore.installBridge();\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styles for the dev error overlay. The overlay presents as a floating window
|
|
3
|
+
* over a dimmed backdrop (like Vite/Next) rather than an opaque full-screen
|
|
4
|
+
* page, using the shared ossido-ui design tokens (see base.css).
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEV_ERROR_STYLES = "\n.ossido-err-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n overflow: auto;\n padding: var(--ossido-space-8);\n background: rgba(0, 0, 0, 0.62);\n font-family: var(--ossido-font-sans);\n font-size: var(--ossido-font-size);\n line-height: var(--ossido-line-height);\n color: var(--ossido-color-text);\n}\n.ossido-err-window {\n position: relative;\n width: 100%;\n max-width: 960px;\n margin: auto;\n background: var(--ossido-color-bg);\n color: var(--ossido-color-text);\n border: 1px solid var(--ossido-color-border);\n border-top: 4px solid var(--ossido-color-accent);\n border-radius: var(--ossido-radius);\n box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);\n overflow: hidden;\n}\n/* Apply the sans token to every overlay element (0-1-0 beats an app-level\n * \"* { font-family }\" reset at 0-0-0). */\n.ossido-err-window * { font-family: var(--ossido-font-sans); }\n\n/* Pager header: prev/next through the collected errors, plus a dismiss. */\n.ossido-err-pager {\n display: flex;\n align-items: center;\n gap: var(--ossido-space-3);\n padding: 10px 14px;\n border-bottom: 1px solid var(--ossido-color-border);\n background: var(--ossido-color-surface);\n}\n.ossido-err-pager-count {\n font-variant-numeric: tabular-nums;\n font-size: var(--ossido-font-size-sm);\n color: var(--ossido-color-text-muted);\n}\n.ossido-err-pager-kind {\n font-size: var(--ossido-font-size-xs);\n text-transform: uppercase;\n letter-spacing: var(--ossido-letter-spacing-wide);\n color: var(--ossido-color-text-subtle);\n}\n.ossido-err-pager-occurrences {\n flex: none;\n padding: 1px 7px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n font-variant-numeric: tabular-nums;\n}\n.ossido-err-pager-spacer { flex: 1 1 auto; }\n.ossido-err-nav {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: var(--ossido-radius-sm);\n background: var(--ossido-color-surface-raised);\n color: var(--ossido-color-text);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n}\n.ossido-err-nav:hover:not(:disabled) { background: var(--ossido-color-surface-hover); }\n.ossido-err-nav:disabled { opacity: 0.4; cursor: default; }\n.ossido-err-nav svg { width: 15px; height: 15px; display: block; }\n.ossido-err-dismiss {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid transparent;\n border-radius: var(--ossido-radius-sm);\n background: transparent;\n color: var(--ossido-color-text-muted);\n font: inherit;\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n}\n.ossido-err-dismiss:hover { background: var(--ossido-color-surface-hover); color: var(--ossido-color-text); }\n\n.ossido-err-body { padding: var(--ossido-space-8); }\n\n.ossido-err-badge {\n display: inline-block;\n padding: 2px 10px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n letter-spacing: var(--ossido-letter-spacing-wide);\n text-transform: uppercase;\n}\n.ossido-err-name {\n margin: var(--ossido-space-3) 0 var(--ossido-space-4);\n font-size: var(--ossido-font-size-xl);\n font-weight: var(--ossido-font-weight-bold);\n color: var(--ossido-color-accent-text);\n word-break: break-word;\n}\n.ossido-err-message-card {\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n background: var(--ossido-color-surface);\n padding: 14px;\n margin-bottom: var(--ossido-space-6);\n gap: var(--ossido-space-2);\n display: flex;\n}\n.ossido-err-message-card svg {\n width: 1.5rem;\n height: 1.5rem;\n fill: var(--ossido-color-accent-text);\n flex: none;\n}\n.ossido-err-message {\n margin: 0;\n color: var(--ossido-color-accent-text);\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.5rem;\n font-size: 1rem;\n}\n.ossido-err-source,\n.ossido-err-source *,\n.ossido-err-stack,\n.ossido-err-stack *,\n.ossido-err-frame-code,\n.ossido-err-rawstack {\n font-family: var(--ossido-font-mono);\n}\n.ossido-err-source {\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n overflow: hidden;\n margin-bottom: var(--ossido-space-6);\n}\n.ossido-err-source-file {\n padding: 8px 14px;\n background: var(--ossido-color-surface);\n border-bottom: 1px solid var(--ossido-color-border);\n color: var(--ossido-color-text-muted);\n font-size: var(--ossido-font-size-sm);\n word-break: break-all;\n}\n.ossido-err-code { margin: 0; overflow-x: auto; }\n.ossido-err-skel-bar {\n display: inline-block;\n height: 0.7em;\n vertical-align: middle;\n border-radius: 3px;\n background: var(--ossido-color-border-strong);\n animation: ossido-err-skel-pulse 1.3s ease-in-out infinite;\n}\n@keyframes ossido-err-skel-pulse {\n 0%, 100% { opacity: 0.45; }\n 50% { opacity: 0.9; }\n}\n.ossido-err-code-line { display: flex; white-space: pre; }\n.ossido-err-code-line--error { background: var(--ossido-color-danger-surface); }\n.ossido-err-gutter {\n width: 3.5rem;\n flex: none;\n padding: 0 12px;\n text-align: right;\n color: var(--ossido-color-text-faint);\n user-select: none;\n}\n.ossido-err-code-line--error .ossido-err-gutter { color: var(--ossido-color-accent-text); }\n.ossido-err-code-text { padding-right: 14px; color: var(--ossido-color-text); }\n.ossido-err-frame-code {\n margin: 0 0 var(--ossido-space-6);\n padding: 12px 14px;\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n background: var(--ossido-color-surface);\n overflow-x: auto;\n color: var(--ossido-color-text);\n font-size: var(--ossido-font-size-sm);\n white-space: pre;\n}\n.ossido-err-rawstack {\n margin: 0;\n padding: 12px 14px;\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n overflow-x: auto;\n color: var(--ossido-color-text-muted);\n white-space: pre-wrap;\n word-break: break-word;\n}\n.ossido-err-stack { border: 1px solid var(--ossido-color-border); border-radius: var(--ossido-radius); overflow: hidden; }\n.ossido-err-frame { padding: 8px 14px; border-top: 1px solid var(--ossido-color-border); }\n.ossido-err-frame:first-child { border-top: none; }\n.ossido-err-frame--app { background: var(--ossido-color-surface); }\n.ossido-err-frame--vendor { opacity: 0.55; }\n.ossido-err-fn { color: var(--ossido-color-text); }\n.ossido-err-loc { color: var(--ossido-color-text-subtle); font-size: var(--ossido-font-size-sm); word-break: break-all; }\n.ossido-err-actions { margin-top: var(--ossido-space-6); display: flex; gap: var(--ossido-space-3); }\n.ossido-err-btn {\n padding: 6px 16px;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: var(--ossido-radius-sm);\n background: var(--ossido-color-surface-raised);\n color: var(--ossido-color-text);\n font: inherit;\n cursor: pointer;\n}\n.ossido-err-btn:hover { background: var(--ossido-color-surface-hover); }\n.ossido-err-hint { margin-top: var(--ossido-space-4); color: var(--ossido-color-text-faint); font-size: var(--ossido-font-size-xs); }\n.ossido-err-frame-toggle {\n display: block;\n width: 100%;\n padding: 8px 14px;\n text-align: left;\n border: none;\n border-top: 1px solid var(--ossido-color-border);\n background: var(--ossido-color-surface-raised);\n color: var(--ossido-color-text-subtle);\n font: inherit;\n font-size: var(--ossido-font-size-sm);\n cursor: pointer;\n}\n.ossido-err-frame-toggle:hover { background: var(--ossido-color-surface-hover); }\n.ossido-err-frame-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.ossido-err-frame-badge {\n flex: none;\n padding: 0 10px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-success-surface);\n border: 1px solid var(--ossido-color-success);\n color: var(--ossido-color-success-text);\n font-family: var(--ossido-font-sans);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n letter-spacing: var(--ossido-letter-spacing-wide);\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n/* The persistent dev indicator: a fixed container in a chosen corner holding a\n * circular lightning badge (Next-style) with an error-count bubble, plus its\n * pop-up menu. */\n.ossido-err-indicator {\n position: fixed;\n z-index: 2147483647;\n}\n.ossido-err-indicator--top-left { top: var(--ossido-space-6); left: var(--ossido-space-6); }\n.ossido-err-indicator--top-right { top: var(--ossido-space-6); right: var(--ossido-space-6); }\n.ossido-err-indicator--bottom-left { bottom: var(--ossido-space-6); left: var(--ossido-space-6); }\n.ossido-err-indicator--bottom-right { bottom: var(--ossido-space-6); right: var(--ossido-space-6); }\n\n.ossido-err-fab {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n padding: 0;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: 50%;\n background: var(--ossido-color-bg);\n color: var(--ossido-color-text);\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);\n cursor: pointer;\n transition: transform 0.12s ease;\n}\n.ossido-err-fab:hover { transform: scale(1.06); }\n.ossido-err-fab svg { width: 22px; height: 22px; display: block; }\n.ossido-err-fab-count {\n position: absolute;\n top: -5px;\n right: -5px;\n box-sizing: border-box;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n border: 2px solid var(--ossido-color-bg);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-family: var(--ossido-font-sans);\n font-size: 11px;\n font-weight: var(--ossido-font-weight-bold);\n font-variant-numeric: tabular-nums;\n line-height: 1;\n}\n\n/* Click-away catcher behind the open menu. */\n.ossido-err-menu-scrim {\n position: fixed;\n inset: 0;\n z-index: 2147483646;\n}\n\n/* The indicator's pop-up menu, anchored to the badge and opening toward the\n * screen centre based on the chosen corner. */\n.ossido-err-menu {\n position: absolute;\n min-width: 232px;\n padding: 6px;\n background: var(--ossido-color-surface);\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);\n font-family: var(--ossido-font-sans);\n color: var(--ossido-color-text);\n}\n.ossido-err-menu--top-left { top: calc(100% + 10px); left: 0; }\n.ossido-err-menu--top-right { top: calc(100% + 10px); right: 0; }\n.ossido-err-menu--bottom-left { bottom: calc(100% + 10px); left: 0; }\n.ossido-err-menu--bottom-right { bottom: calc(100% + 10px); right: 0; }\n\n.ossido-err-menu-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ossido-space-3);\n width: 100%;\n padding: 8px 10px;\n border: none;\n border-radius: var(--ossido-radius-sm);\n background: transparent;\n color: var(--ossido-color-text);\n font: inherit;\n font-size: var(--ossido-font-size-sm);\n text-align: left;\n cursor: pointer;\n}\n.ossido-err-menu-item:hover:not(:disabled) { background: var(--ossido-color-surface-hover); }\n.ossido-err-menu-item:disabled { color: var(--ossido-color-text-faint); cursor: default; }\n.ossido-err-menu-count {\n flex: none;\n min-width: 20px;\n padding: 0 7px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n font-variant-numeric: tabular-nums;\n text-align: center;\n}\n.ossido-err-menu-muted { color: var(--ossido-color-text-faint); font-size: var(--ossido-font-size-xs); }\n.ossido-err-menu-sep {\n height: 1px;\n margin: 6px 4px;\n background: var(--ossido-color-border);\n}\n.ossido-err-menu-section { padding: 4px 10px 8px; }\n.ossido-err-menu-label {\n display: block;\n margin-bottom: 8px;\n color: var(--ossido-color-text-subtle);\n font-size: var(--ossido-font-size-xs);\n text-transform: uppercase;\n letter-spacing: var(--ossido-letter-spacing-wide);\n}\n.ossido-err-menu-corners {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n}\n.ossido-err-corner {\n position: relative;\n height: 30px;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: var(--ossido-radius-sm);\n background: var(--ossido-color-surface-raised);\n cursor: pointer;\n}\n.ossido-err-corner:hover { background: var(--ossido-color-surface-hover); }\n.ossido-err-corner--active {\n border-color: var(--ossido-color-accent);\n background: var(--ossido-color-surface-hover);\n}\n.ossido-err-corner-dot {\n position: absolute;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--ossido-color-text-subtle);\n}\n.ossido-err-corner--active .ossido-err-corner-dot { background: var(--ossido-color-accent); }\n.ossido-err-corner-dot--top-left { top: 5px; left: 5px; }\n.ossido-err-corner-dot--top-right { top: 5px; right: 5px; }\n.ossido-err-corner-dot--bottom-left { bottom: 5px; left: 5px; }\n.ossido-err-corner-dot--bottom-right { bottom: 5px; right: 5px; }\n";
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
//#region src/components/devErrorStyles.ts
|
|
2
|
+
/**
|
|
3
|
+
* Styles for the dev error overlay. The overlay presents as a floating window
|
|
4
|
+
* over a dimmed backdrop (like Vite/Next) rather than an opaque full-screen
|
|
5
|
+
* page, using the shared ossido-ui design tokens (see base.css).
|
|
6
|
+
*/
|
|
7
|
+
const DEV_ERROR_STYLES = `
|
|
8
|
+
.ossido-err-backdrop {
|
|
9
|
+
position: fixed;
|
|
10
|
+
inset: 0;
|
|
11
|
+
z-index: 2147483647;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: flex-start;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
overflow: auto;
|
|
16
|
+
padding: var(--ossido-space-8);
|
|
17
|
+
background: rgba(0, 0, 0, 0.62);
|
|
18
|
+
font-family: var(--ossido-font-sans);
|
|
19
|
+
font-size: var(--ossido-font-size);
|
|
20
|
+
line-height: var(--ossido-line-height);
|
|
21
|
+
color: var(--ossido-color-text);
|
|
22
|
+
}
|
|
23
|
+
.ossido-err-window {
|
|
24
|
+
position: relative;
|
|
25
|
+
width: 100%;
|
|
26
|
+
max-width: 960px;
|
|
27
|
+
margin: auto;
|
|
28
|
+
background: var(--ossido-color-bg);
|
|
29
|
+
color: var(--ossido-color-text);
|
|
30
|
+
border: 1px solid var(--ossido-color-border);
|
|
31
|
+
border-top: 4px solid var(--ossido-color-accent);
|
|
32
|
+
border-radius: var(--ossido-radius);
|
|
33
|
+
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
}
|
|
36
|
+
/* Apply the sans token to every overlay element (0-1-0 beats an app-level
|
|
37
|
+
* "* { font-family }" reset at 0-0-0). */
|
|
38
|
+
.ossido-err-window * { font-family: var(--ossido-font-sans); }
|
|
39
|
+
|
|
40
|
+
/* Pager header: prev/next through the collected errors, plus a dismiss. */
|
|
41
|
+
.ossido-err-pager {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: var(--ossido-space-3);
|
|
45
|
+
padding: 10px 14px;
|
|
46
|
+
border-bottom: 1px solid var(--ossido-color-border);
|
|
47
|
+
background: var(--ossido-color-surface);
|
|
48
|
+
}
|
|
49
|
+
.ossido-err-pager-count {
|
|
50
|
+
font-variant-numeric: tabular-nums;
|
|
51
|
+
font-size: var(--ossido-font-size-sm);
|
|
52
|
+
color: var(--ossido-color-text-muted);
|
|
53
|
+
}
|
|
54
|
+
.ossido-err-pager-kind {
|
|
55
|
+
font-size: var(--ossido-font-size-xs);
|
|
56
|
+
text-transform: uppercase;
|
|
57
|
+
letter-spacing: var(--ossido-letter-spacing-wide);
|
|
58
|
+
color: var(--ossido-color-text-subtle);
|
|
59
|
+
}
|
|
60
|
+
.ossido-err-pager-occurrences {
|
|
61
|
+
flex: none;
|
|
62
|
+
padding: 1px 7px;
|
|
63
|
+
border-radius: var(--ossido-radius-pill);
|
|
64
|
+
background: var(--ossido-color-accent);
|
|
65
|
+
color: var(--ossido-color-on-accent);
|
|
66
|
+
font-size: var(--ossido-font-size-xs);
|
|
67
|
+
font-weight: var(--ossido-font-weight-bold);
|
|
68
|
+
font-variant-numeric: tabular-nums;
|
|
69
|
+
}
|
|
70
|
+
.ossido-err-pager-spacer { flex: 1 1 auto; }
|
|
71
|
+
.ossido-err-nav {
|
|
72
|
+
display: inline-flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
width: 28px;
|
|
76
|
+
height: 28px;
|
|
77
|
+
border: 1px solid var(--ossido-color-border-strong);
|
|
78
|
+
border-radius: var(--ossido-radius-sm);
|
|
79
|
+
background: var(--ossido-color-surface-raised);
|
|
80
|
+
color: var(--ossido-color-text);
|
|
81
|
+
font: inherit;
|
|
82
|
+
line-height: 1;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
}
|
|
85
|
+
.ossido-err-nav:hover:not(:disabled) { background: var(--ossido-color-surface-hover); }
|
|
86
|
+
.ossido-err-nav:disabled { opacity: 0.4; cursor: default; }
|
|
87
|
+
.ossido-err-nav svg { width: 15px; height: 15px; display: block; }
|
|
88
|
+
.ossido-err-dismiss {
|
|
89
|
+
display: inline-flex;
|
|
90
|
+
align-items: center;
|
|
91
|
+
justify-content: center;
|
|
92
|
+
width: 28px;
|
|
93
|
+
height: 28px;
|
|
94
|
+
border: 1px solid transparent;
|
|
95
|
+
border-radius: var(--ossido-radius-sm);
|
|
96
|
+
background: transparent;
|
|
97
|
+
color: var(--ossido-color-text-muted);
|
|
98
|
+
font: inherit;
|
|
99
|
+
font-size: 18px;
|
|
100
|
+
line-height: 1;
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
}
|
|
103
|
+
.ossido-err-dismiss:hover { background: var(--ossido-color-surface-hover); color: var(--ossido-color-text); }
|
|
104
|
+
|
|
105
|
+
.ossido-err-body { padding: var(--ossido-space-8); }
|
|
106
|
+
|
|
107
|
+
.ossido-err-badge {
|
|
108
|
+
display: inline-block;
|
|
109
|
+
padding: 2px 10px;
|
|
110
|
+
border-radius: var(--ossido-radius-pill);
|
|
111
|
+
background: var(--ossido-color-accent);
|
|
112
|
+
color: var(--ossido-color-on-accent);
|
|
113
|
+
font-size: var(--ossido-font-size-xs);
|
|
114
|
+
font-weight: var(--ossido-font-weight-bold);
|
|
115
|
+
letter-spacing: var(--ossido-letter-spacing-wide);
|
|
116
|
+
text-transform: uppercase;
|
|
117
|
+
}
|
|
118
|
+
.ossido-err-name {
|
|
119
|
+
margin: var(--ossido-space-3) 0 var(--ossido-space-4);
|
|
120
|
+
font-size: var(--ossido-font-size-xl);
|
|
121
|
+
font-weight: var(--ossido-font-weight-bold);
|
|
122
|
+
color: var(--ossido-color-accent-text);
|
|
123
|
+
word-break: break-word;
|
|
124
|
+
}
|
|
125
|
+
.ossido-err-message-card {
|
|
126
|
+
border: 1px solid var(--ossido-color-border);
|
|
127
|
+
border-radius: var(--ossido-radius);
|
|
128
|
+
background: var(--ossido-color-surface);
|
|
129
|
+
padding: 14px;
|
|
130
|
+
margin-bottom: var(--ossido-space-6);
|
|
131
|
+
gap: var(--ossido-space-2);
|
|
132
|
+
display: flex;
|
|
133
|
+
}
|
|
134
|
+
.ossido-err-message-card svg {
|
|
135
|
+
width: 1.5rem;
|
|
136
|
+
height: 1.5rem;
|
|
137
|
+
fill: var(--ossido-color-accent-text);
|
|
138
|
+
flex: none;
|
|
139
|
+
}
|
|
140
|
+
.ossido-err-message {
|
|
141
|
+
margin: 0;
|
|
142
|
+
color: var(--ossido-color-accent-text);
|
|
143
|
+
white-space: pre-wrap;
|
|
144
|
+
word-break: break-word;
|
|
145
|
+
line-height: 1.5rem;
|
|
146
|
+
font-size: 1rem;
|
|
147
|
+
}
|
|
148
|
+
.ossido-err-source,
|
|
149
|
+
.ossido-err-source *,
|
|
150
|
+
.ossido-err-stack,
|
|
151
|
+
.ossido-err-stack *,
|
|
152
|
+
.ossido-err-frame-code,
|
|
153
|
+
.ossido-err-rawstack {
|
|
154
|
+
font-family: var(--ossido-font-mono);
|
|
155
|
+
}
|
|
156
|
+
.ossido-err-source {
|
|
157
|
+
border: 1px solid var(--ossido-color-border);
|
|
158
|
+
border-radius: var(--ossido-radius);
|
|
159
|
+
overflow: hidden;
|
|
160
|
+
margin-bottom: var(--ossido-space-6);
|
|
161
|
+
}
|
|
162
|
+
.ossido-err-source-file {
|
|
163
|
+
padding: 8px 14px;
|
|
164
|
+
background: var(--ossido-color-surface);
|
|
165
|
+
border-bottom: 1px solid var(--ossido-color-border);
|
|
166
|
+
color: var(--ossido-color-text-muted);
|
|
167
|
+
font-size: var(--ossido-font-size-sm);
|
|
168
|
+
word-break: break-all;
|
|
169
|
+
}
|
|
170
|
+
.ossido-err-code { margin: 0; overflow-x: auto; }
|
|
171
|
+
.ossido-err-skel-bar {
|
|
172
|
+
display: inline-block;
|
|
173
|
+
height: 0.7em;
|
|
174
|
+
vertical-align: middle;
|
|
175
|
+
border-radius: 3px;
|
|
176
|
+
background: var(--ossido-color-border-strong);
|
|
177
|
+
animation: ossido-err-skel-pulse 1.3s ease-in-out infinite;
|
|
178
|
+
}
|
|
179
|
+
@keyframes ossido-err-skel-pulse {
|
|
180
|
+
0%, 100% { opacity: 0.45; }
|
|
181
|
+
50% { opacity: 0.9; }
|
|
182
|
+
}
|
|
183
|
+
.ossido-err-code-line { display: flex; white-space: pre; }
|
|
184
|
+
.ossido-err-code-line--error { background: var(--ossido-color-danger-surface); }
|
|
185
|
+
.ossido-err-gutter {
|
|
186
|
+
width: 3.5rem;
|
|
187
|
+
flex: none;
|
|
188
|
+
padding: 0 12px;
|
|
189
|
+
text-align: right;
|
|
190
|
+
color: var(--ossido-color-text-faint);
|
|
191
|
+
user-select: none;
|
|
192
|
+
}
|
|
193
|
+
.ossido-err-code-line--error .ossido-err-gutter { color: var(--ossido-color-accent-text); }
|
|
194
|
+
.ossido-err-code-text { padding-right: 14px; color: var(--ossido-color-text); }
|
|
195
|
+
.ossido-err-frame-code {
|
|
196
|
+
margin: 0 0 var(--ossido-space-6);
|
|
197
|
+
padding: 12px 14px;
|
|
198
|
+
border: 1px solid var(--ossido-color-border);
|
|
199
|
+
border-radius: var(--ossido-radius);
|
|
200
|
+
background: var(--ossido-color-surface);
|
|
201
|
+
overflow-x: auto;
|
|
202
|
+
color: var(--ossido-color-text);
|
|
203
|
+
font-size: var(--ossido-font-size-sm);
|
|
204
|
+
white-space: pre;
|
|
205
|
+
}
|
|
206
|
+
.ossido-err-rawstack {
|
|
207
|
+
margin: 0;
|
|
208
|
+
padding: 12px 14px;
|
|
209
|
+
border: 1px solid var(--ossido-color-border);
|
|
210
|
+
border-radius: var(--ossido-radius);
|
|
211
|
+
overflow-x: auto;
|
|
212
|
+
color: var(--ossido-color-text-muted);
|
|
213
|
+
white-space: pre-wrap;
|
|
214
|
+
word-break: break-word;
|
|
215
|
+
}
|
|
216
|
+
.ossido-err-stack { border: 1px solid var(--ossido-color-border); border-radius: var(--ossido-radius); overflow: hidden; }
|
|
217
|
+
.ossido-err-frame { padding: 8px 14px; border-top: 1px solid var(--ossido-color-border); }
|
|
218
|
+
.ossido-err-frame:first-child { border-top: none; }
|
|
219
|
+
.ossido-err-frame--app { background: var(--ossido-color-surface); }
|
|
220
|
+
.ossido-err-frame--vendor { opacity: 0.55; }
|
|
221
|
+
.ossido-err-fn { color: var(--ossido-color-text); }
|
|
222
|
+
.ossido-err-loc { color: var(--ossido-color-text-subtle); font-size: var(--ossido-font-size-sm); word-break: break-all; }
|
|
223
|
+
.ossido-err-actions { margin-top: var(--ossido-space-6); display: flex; gap: var(--ossido-space-3); }
|
|
224
|
+
.ossido-err-btn {
|
|
225
|
+
padding: 6px 16px;
|
|
226
|
+
border: 1px solid var(--ossido-color-border-strong);
|
|
227
|
+
border-radius: var(--ossido-radius-sm);
|
|
228
|
+
background: var(--ossido-color-surface-raised);
|
|
229
|
+
color: var(--ossido-color-text);
|
|
230
|
+
font: inherit;
|
|
231
|
+
cursor: pointer;
|
|
232
|
+
}
|
|
233
|
+
.ossido-err-btn:hover { background: var(--ossido-color-surface-hover); }
|
|
234
|
+
.ossido-err-hint { margin-top: var(--ossido-space-4); color: var(--ossido-color-text-faint); font-size: var(--ossido-font-size-xs); }
|
|
235
|
+
.ossido-err-frame-toggle {
|
|
236
|
+
display: block;
|
|
237
|
+
width: 100%;
|
|
238
|
+
padding: 8px 14px;
|
|
239
|
+
text-align: left;
|
|
240
|
+
border: none;
|
|
241
|
+
border-top: 1px solid var(--ossido-color-border);
|
|
242
|
+
background: var(--ossido-color-surface-raised);
|
|
243
|
+
color: var(--ossido-color-text-subtle);
|
|
244
|
+
font: inherit;
|
|
245
|
+
font-size: var(--ossido-font-size-sm);
|
|
246
|
+
cursor: pointer;
|
|
247
|
+
}
|
|
248
|
+
.ossido-err-frame-toggle:hover { background: var(--ossido-color-surface-hover); }
|
|
249
|
+
.ossido-err-frame-head {
|
|
250
|
+
display: flex;
|
|
251
|
+
align-items: center;
|
|
252
|
+
justify-content: space-between;
|
|
253
|
+
gap: 8px;
|
|
254
|
+
}
|
|
255
|
+
.ossido-err-frame-badge {
|
|
256
|
+
flex: none;
|
|
257
|
+
padding: 0 10px;
|
|
258
|
+
border-radius: var(--ossido-radius-pill);
|
|
259
|
+
background: var(--ossido-color-success-surface);
|
|
260
|
+
border: 1px solid var(--ossido-color-success);
|
|
261
|
+
color: var(--ossido-color-success-text);
|
|
262
|
+
font-family: var(--ossido-font-sans);
|
|
263
|
+
font-size: var(--ossido-font-size-xs);
|
|
264
|
+
font-weight: var(--ossido-font-weight-bold);
|
|
265
|
+
letter-spacing: var(--ossido-letter-spacing-wide);
|
|
266
|
+
text-transform: uppercase;
|
|
267
|
+
white-space: nowrap;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* The persistent dev indicator: a fixed container in a chosen corner holding a
|
|
271
|
+
* circular lightning badge (Next-style) with an error-count bubble, plus its
|
|
272
|
+
* pop-up menu. */
|
|
273
|
+
.ossido-err-indicator {
|
|
274
|
+
position: fixed;
|
|
275
|
+
z-index: 2147483647;
|
|
276
|
+
}
|
|
277
|
+
.ossido-err-indicator--top-left { top: var(--ossido-space-6); left: var(--ossido-space-6); }
|
|
278
|
+
.ossido-err-indicator--top-right { top: var(--ossido-space-6); right: var(--ossido-space-6); }
|
|
279
|
+
.ossido-err-indicator--bottom-left { bottom: var(--ossido-space-6); left: var(--ossido-space-6); }
|
|
280
|
+
.ossido-err-indicator--bottom-right { bottom: var(--ossido-space-6); right: var(--ossido-space-6); }
|
|
281
|
+
|
|
282
|
+
.ossido-err-fab {
|
|
283
|
+
position: relative;
|
|
284
|
+
display: inline-flex;
|
|
285
|
+
align-items: center;
|
|
286
|
+
justify-content: center;
|
|
287
|
+
width: 44px;
|
|
288
|
+
height: 44px;
|
|
289
|
+
padding: 0;
|
|
290
|
+
border: 1px solid var(--ossido-color-border-strong);
|
|
291
|
+
border-radius: 50%;
|
|
292
|
+
background: var(--ossido-color-bg);
|
|
293
|
+
color: var(--ossido-color-text);
|
|
294
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
|
|
295
|
+
cursor: pointer;
|
|
296
|
+
transition: transform 0.12s ease;
|
|
297
|
+
}
|
|
298
|
+
.ossido-err-fab:hover { transform: scale(1.06); }
|
|
299
|
+
.ossido-err-fab svg { width: 22px; height: 22px; display: block; }
|
|
300
|
+
.ossido-err-fab-count {
|
|
301
|
+
position: absolute;
|
|
302
|
+
top: -5px;
|
|
303
|
+
right: -5px;
|
|
304
|
+
box-sizing: border-box;
|
|
305
|
+
min-width: 20px;
|
|
306
|
+
height: 20px;
|
|
307
|
+
padding: 0 5px;
|
|
308
|
+
display: inline-flex;
|
|
309
|
+
align-items: center;
|
|
310
|
+
justify-content: center;
|
|
311
|
+
border-radius: 10px;
|
|
312
|
+
border: 2px solid var(--ossido-color-bg);
|
|
313
|
+
background: var(--ossido-color-accent);
|
|
314
|
+
color: var(--ossido-color-on-accent);
|
|
315
|
+
font-family: var(--ossido-font-sans);
|
|
316
|
+
font-size: 11px;
|
|
317
|
+
font-weight: var(--ossido-font-weight-bold);
|
|
318
|
+
font-variant-numeric: tabular-nums;
|
|
319
|
+
line-height: 1;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/* Click-away catcher behind the open menu. */
|
|
323
|
+
.ossido-err-menu-scrim {
|
|
324
|
+
position: fixed;
|
|
325
|
+
inset: 0;
|
|
326
|
+
z-index: 2147483646;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* The indicator's pop-up menu, anchored to the badge and opening toward the
|
|
330
|
+
* screen centre based on the chosen corner. */
|
|
331
|
+
.ossido-err-menu {
|
|
332
|
+
position: absolute;
|
|
333
|
+
min-width: 232px;
|
|
334
|
+
padding: 6px;
|
|
335
|
+
background: var(--ossido-color-surface);
|
|
336
|
+
border: 1px solid var(--ossido-color-border);
|
|
337
|
+
border-radius: var(--ossido-radius);
|
|
338
|
+
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
|
|
339
|
+
font-family: var(--ossido-font-sans);
|
|
340
|
+
color: var(--ossido-color-text);
|
|
341
|
+
}
|
|
342
|
+
.ossido-err-menu--top-left { top: calc(100% + 10px); left: 0; }
|
|
343
|
+
.ossido-err-menu--top-right { top: calc(100% + 10px); right: 0; }
|
|
344
|
+
.ossido-err-menu--bottom-left { bottom: calc(100% + 10px); left: 0; }
|
|
345
|
+
.ossido-err-menu--bottom-right { bottom: calc(100% + 10px); right: 0; }
|
|
346
|
+
|
|
347
|
+
.ossido-err-menu-item {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
justify-content: space-between;
|
|
351
|
+
gap: var(--ossido-space-3);
|
|
352
|
+
width: 100%;
|
|
353
|
+
padding: 8px 10px;
|
|
354
|
+
border: none;
|
|
355
|
+
border-radius: var(--ossido-radius-sm);
|
|
356
|
+
background: transparent;
|
|
357
|
+
color: var(--ossido-color-text);
|
|
358
|
+
font: inherit;
|
|
359
|
+
font-size: var(--ossido-font-size-sm);
|
|
360
|
+
text-align: left;
|
|
361
|
+
cursor: pointer;
|
|
362
|
+
}
|
|
363
|
+
.ossido-err-menu-item:hover:not(:disabled) { background: var(--ossido-color-surface-hover); }
|
|
364
|
+
.ossido-err-menu-item:disabled { color: var(--ossido-color-text-faint); cursor: default; }
|
|
365
|
+
.ossido-err-menu-count {
|
|
366
|
+
flex: none;
|
|
367
|
+
min-width: 20px;
|
|
368
|
+
padding: 0 7px;
|
|
369
|
+
border-radius: var(--ossido-radius-pill);
|
|
370
|
+
background: var(--ossido-color-accent);
|
|
371
|
+
color: var(--ossido-color-on-accent);
|
|
372
|
+
font-size: var(--ossido-font-size-xs);
|
|
373
|
+
font-weight: var(--ossido-font-weight-bold);
|
|
374
|
+
font-variant-numeric: tabular-nums;
|
|
375
|
+
text-align: center;
|
|
376
|
+
}
|
|
377
|
+
.ossido-err-menu-muted { color: var(--ossido-color-text-faint); font-size: var(--ossido-font-size-xs); }
|
|
378
|
+
.ossido-err-menu-sep {
|
|
379
|
+
height: 1px;
|
|
380
|
+
margin: 6px 4px;
|
|
381
|
+
background: var(--ossido-color-border);
|
|
382
|
+
}
|
|
383
|
+
.ossido-err-menu-section { padding: 4px 10px 8px; }
|
|
384
|
+
.ossido-err-menu-label {
|
|
385
|
+
display: block;
|
|
386
|
+
margin-bottom: 8px;
|
|
387
|
+
color: var(--ossido-color-text-subtle);
|
|
388
|
+
font-size: var(--ossido-font-size-xs);
|
|
389
|
+
text-transform: uppercase;
|
|
390
|
+
letter-spacing: var(--ossido-letter-spacing-wide);
|
|
391
|
+
}
|
|
392
|
+
.ossido-err-menu-corners {
|
|
393
|
+
display: grid;
|
|
394
|
+
grid-template-columns: 1fr 1fr;
|
|
395
|
+
gap: 6px;
|
|
396
|
+
}
|
|
397
|
+
.ossido-err-corner {
|
|
398
|
+
position: relative;
|
|
399
|
+
height: 30px;
|
|
400
|
+
border: 1px solid var(--ossido-color-border-strong);
|
|
401
|
+
border-radius: var(--ossido-radius-sm);
|
|
402
|
+
background: var(--ossido-color-surface-raised);
|
|
403
|
+
cursor: pointer;
|
|
404
|
+
}
|
|
405
|
+
.ossido-err-corner:hover { background: var(--ossido-color-surface-hover); }
|
|
406
|
+
.ossido-err-corner--active {
|
|
407
|
+
border-color: var(--ossido-color-accent);
|
|
408
|
+
background: var(--ossido-color-surface-hover);
|
|
409
|
+
}
|
|
410
|
+
.ossido-err-corner-dot {
|
|
411
|
+
position: absolute;
|
|
412
|
+
width: 7px;
|
|
413
|
+
height: 7px;
|
|
414
|
+
border-radius: 50%;
|
|
415
|
+
background: var(--ossido-color-text-subtle);
|
|
416
|
+
}
|
|
417
|
+
.ossido-err-corner--active .ossido-err-corner-dot { background: var(--ossido-color-accent); }
|
|
418
|
+
.ossido-err-corner-dot--top-left { top: 5px; left: 5px; }
|
|
419
|
+
.ossido-err-corner-dot--top-right { top: 5px; right: 5px; }
|
|
420
|
+
.ossido-err-corner-dot--bottom-left { bottom: 5px; left: 5px; }
|
|
421
|
+
.ossido-err-corner-dot--bottom-right { bottom: 5px; right: 5px; }
|
|
422
|
+
`;
|
|
423
|
+
|
|
424
|
+
//#endregion
|
|
425
|
+
export { DEV_ERROR_STYLES };
|
|
426
|
+
//# sourceMappingURL=devErrorStyles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devErrorStyles.js","names":[],"sources":["../../../src/components/devErrorStyles.ts"],"sourcesContent":["/**\n * Styles for the dev error overlay. The overlay presents as a floating window\n * over a dimmed backdrop (like Vite/Next) rather than an opaque full-screen\n * page, using the shared ossido-ui design tokens (see base.css).\n */\nexport const DEV_ERROR_STYLES = `\n.ossido-err-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n overflow: auto;\n padding: var(--ossido-space-8);\n background: rgba(0, 0, 0, 0.62);\n font-family: var(--ossido-font-sans);\n font-size: var(--ossido-font-size);\n line-height: var(--ossido-line-height);\n color: var(--ossido-color-text);\n}\n.ossido-err-window {\n position: relative;\n width: 100%;\n max-width: 960px;\n margin: auto;\n background: var(--ossido-color-bg);\n color: var(--ossido-color-text);\n border: 1px solid var(--ossido-color-border);\n border-top: 4px solid var(--ossido-color-accent);\n border-radius: var(--ossido-radius);\n box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);\n overflow: hidden;\n}\n/* Apply the sans token to every overlay element (0-1-0 beats an app-level\n * \"* { font-family }\" reset at 0-0-0). */\n.ossido-err-window * { font-family: var(--ossido-font-sans); }\n\n/* Pager header: prev/next through the collected errors, plus a dismiss. */\n.ossido-err-pager {\n display: flex;\n align-items: center;\n gap: var(--ossido-space-3);\n padding: 10px 14px;\n border-bottom: 1px solid var(--ossido-color-border);\n background: var(--ossido-color-surface);\n}\n.ossido-err-pager-count {\n font-variant-numeric: tabular-nums;\n font-size: var(--ossido-font-size-sm);\n color: var(--ossido-color-text-muted);\n}\n.ossido-err-pager-kind {\n font-size: var(--ossido-font-size-xs);\n text-transform: uppercase;\n letter-spacing: var(--ossido-letter-spacing-wide);\n color: var(--ossido-color-text-subtle);\n}\n.ossido-err-pager-occurrences {\n flex: none;\n padding: 1px 7px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n font-variant-numeric: tabular-nums;\n}\n.ossido-err-pager-spacer { flex: 1 1 auto; }\n.ossido-err-nav {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: var(--ossido-radius-sm);\n background: var(--ossido-color-surface-raised);\n color: var(--ossido-color-text);\n font: inherit;\n line-height: 1;\n cursor: pointer;\n}\n.ossido-err-nav:hover:not(:disabled) { background: var(--ossido-color-surface-hover); }\n.ossido-err-nav:disabled { opacity: 0.4; cursor: default; }\n.ossido-err-nav svg { width: 15px; height: 15px; display: block; }\n.ossido-err-dismiss {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid transparent;\n border-radius: var(--ossido-radius-sm);\n background: transparent;\n color: var(--ossido-color-text-muted);\n font: inherit;\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n}\n.ossido-err-dismiss:hover { background: var(--ossido-color-surface-hover); color: var(--ossido-color-text); }\n\n.ossido-err-body { padding: var(--ossido-space-8); }\n\n.ossido-err-badge {\n display: inline-block;\n padding: 2px 10px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n letter-spacing: var(--ossido-letter-spacing-wide);\n text-transform: uppercase;\n}\n.ossido-err-name {\n margin: var(--ossido-space-3) 0 var(--ossido-space-4);\n font-size: var(--ossido-font-size-xl);\n font-weight: var(--ossido-font-weight-bold);\n color: var(--ossido-color-accent-text);\n word-break: break-word;\n}\n.ossido-err-message-card {\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n background: var(--ossido-color-surface);\n padding: 14px;\n margin-bottom: var(--ossido-space-6);\n gap: var(--ossido-space-2);\n display: flex;\n}\n.ossido-err-message-card svg {\n width: 1.5rem;\n height: 1.5rem;\n fill: var(--ossido-color-accent-text);\n flex: none;\n}\n.ossido-err-message {\n margin: 0;\n color: var(--ossido-color-accent-text);\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.5rem;\n font-size: 1rem;\n}\n.ossido-err-source,\n.ossido-err-source *,\n.ossido-err-stack,\n.ossido-err-stack *,\n.ossido-err-frame-code,\n.ossido-err-rawstack {\n font-family: var(--ossido-font-mono);\n}\n.ossido-err-source {\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n overflow: hidden;\n margin-bottom: var(--ossido-space-6);\n}\n.ossido-err-source-file {\n padding: 8px 14px;\n background: var(--ossido-color-surface);\n border-bottom: 1px solid var(--ossido-color-border);\n color: var(--ossido-color-text-muted);\n font-size: var(--ossido-font-size-sm);\n word-break: break-all;\n}\n.ossido-err-code { margin: 0; overflow-x: auto; }\n.ossido-err-skel-bar {\n display: inline-block;\n height: 0.7em;\n vertical-align: middle;\n border-radius: 3px;\n background: var(--ossido-color-border-strong);\n animation: ossido-err-skel-pulse 1.3s ease-in-out infinite;\n}\n@keyframes ossido-err-skel-pulse {\n 0%, 100% { opacity: 0.45; }\n 50% { opacity: 0.9; }\n}\n.ossido-err-code-line { display: flex; white-space: pre; }\n.ossido-err-code-line--error { background: var(--ossido-color-danger-surface); }\n.ossido-err-gutter {\n width: 3.5rem;\n flex: none;\n padding: 0 12px;\n text-align: right;\n color: var(--ossido-color-text-faint);\n user-select: none;\n}\n.ossido-err-code-line--error .ossido-err-gutter { color: var(--ossido-color-accent-text); }\n.ossido-err-code-text { padding-right: 14px; color: var(--ossido-color-text); }\n.ossido-err-frame-code {\n margin: 0 0 var(--ossido-space-6);\n padding: 12px 14px;\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n background: var(--ossido-color-surface);\n overflow-x: auto;\n color: var(--ossido-color-text);\n font-size: var(--ossido-font-size-sm);\n white-space: pre;\n}\n.ossido-err-rawstack {\n margin: 0;\n padding: 12px 14px;\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n overflow-x: auto;\n color: var(--ossido-color-text-muted);\n white-space: pre-wrap;\n word-break: break-word;\n}\n.ossido-err-stack { border: 1px solid var(--ossido-color-border); border-radius: var(--ossido-radius); overflow: hidden; }\n.ossido-err-frame { padding: 8px 14px; border-top: 1px solid var(--ossido-color-border); }\n.ossido-err-frame:first-child { border-top: none; }\n.ossido-err-frame--app { background: var(--ossido-color-surface); }\n.ossido-err-frame--vendor { opacity: 0.55; }\n.ossido-err-fn { color: var(--ossido-color-text); }\n.ossido-err-loc { color: var(--ossido-color-text-subtle); font-size: var(--ossido-font-size-sm); word-break: break-all; }\n.ossido-err-actions { margin-top: var(--ossido-space-6); display: flex; gap: var(--ossido-space-3); }\n.ossido-err-btn {\n padding: 6px 16px;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: var(--ossido-radius-sm);\n background: var(--ossido-color-surface-raised);\n color: var(--ossido-color-text);\n font: inherit;\n cursor: pointer;\n}\n.ossido-err-btn:hover { background: var(--ossido-color-surface-hover); }\n.ossido-err-hint { margin-top: var(--ossido-space-4); color: var(--ossido-color-text-faint); font-size: var(--ossido-font-size-xs); }\n.ossido-err-frame-toggle {\n display: block;\n width: 100%;\n padding: 8px 14px;\n text-align: left;\n border: none;\n border-top: 1px solid var(--ossido-color-border);\n background: var(--ossido-color-surface-raised);\n color: var(--ossido-color-text-subtle);\n font: inherit;\n font-size: var(--ossido-font-size-sm);\n cursor: pointer;\n}\n.ossido-err-frame-toggle:hover { background: var(--ossido-color-surface-hover); }\n.ossido-err-frame-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.ossido-err-frame-badge {\n flex: none;\n padding: 0 10px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-success-surface);\n border: 1px solid var(--ossido-color-success);\n color: var(--ossido-color-success-text);\n font-family: var(--ossido-font-sans);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n letter-spacing: var(--ossido-letter-spacing-wide);\n text-transform: uppercase;\n white-space: nowrap;\n}\n\n/* The persistent dev indicator: a fixed container in a chosen corner holding a\n * circular lightning badge (Next-style) with an error-count bubble, plus its\n * pop-up menu. */\n.ossido-err-indicator {\n position: fixed;\n z-index: 2147483647;\n}\n.ossido-err-indicator--top-left { top: var(--ossido-space-6); left: var(--ossido-space-6); }\n.ossido-err-indicator--top-right { top: var(--ossido-space-6); right: var(--ossido-space-6); }\n.ossido-err-indicator--bottom-left { bottom: var(--ossido-space-6); left: var(--ossido-space-6); }\n.ossido-err-indicator--bottom-right { bottom: var(--ossido-space-6); right: var(--ossido-space-6); }\n\n.ossido-err-fab {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n padding: 0;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: 50%;\n background: var(--ossido-color-bg);\n color: var(--ossido-color-text);\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);\n cursor: pointer;\n transition: transform 0.12s ease;\n}\n.ossido-err-fab:hover { transform: scale(1.06); }\n.ossido-err-fab svg { width: 22px; height: 22px; display: block; }\n.ossido-err-fab-count {\n position: absolute;\n top: -5px;\n right: -5px;\n box-sizing: border-box;\n min-width: 20px;\n height: 20px;\n padding: 0 5px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n border: 2px solid var(--ossido-color-bg);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-family: var(--ossido-font-sans);\n font-size: 11px;\n font-weight: var(--ossido-font-weight-bold);\n font-variant-numeric: tabular-nums;\n line-height: 1;\n}\n\n/* Click-away catcher behind the open menu. */\n.ossido-err-menu-scrim {\n position: fixed;\n inset: 0;\n z-index: 2147483646;\n}\n\n/* The indicator's pop-up menu, anchored to the badge and opening toward the\n * screen centre based on the chosen corner. */\n.ossido-err-menu {\n position: absolute;\n min-width: 232px;\n padding: 6px;\n background: var(--ossido-color-surface);\n border: 1px solid var(--ossido-color-border);\n border-radius: var(--ossido-radius);\n box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);\n font-family: var(--ossido-font-sans);\n color: var(--ossido-color-text);\n}\n.ossido-err-menu--top-left { top: calc(100% + 10px); left: 0; }\n.ossido-err-menu--top-right { top: calc(100% + 10px); right: 0; }\n.ossido-err-menu--bottom-left { bottom: calc(100% + 10px); left: 0; }\n.ossido-err-menu--bottom-right { bottom: calc(100% + 10px); right: 0; }\n\n.ossido-err-menu-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--ossido-space-3);\n width: 100%;\n padding: 8px 10px;\n border: none;\n border-radius: var(--ossido-radius-sm);\n background: transparent;\n color: var(--ossido-color-text);\n font: inherit;\n font-size: var(--ossido-font-size-sm);\n text-align: left;\n cursor: pointer;\n}\n.ossido-err-menu-item:hover:not(:disabled) { background: var(--ossido-color-surface-hover); }\n.ossido-err-menu-item:disabled { color: var(--ossido-color-text-faint); cursor: default; }\n.ossido-err-menu-count {\n flex: none;\n min-width: 20px;\n padding: 0 7px;\n border-radius: var(--ossido-radius-pill);\n background: var(--ossido-color-accent);\n color: var(--ossido-color-on-accent);\n font-size: var(--ossido-font-size-xs);\n font-weight: var(--ossido-font-weight-bold);\n font-variant-numeric: tabular-nums;\n text-align: center;\n}\n.ossido-err-menu-muted { color: var(--ossido-color-text-faint); font-size: var(--ossido-font-size-xs); }\n.ossido-err-menu-sep {\n height: 1px;\n margin: 6px 4px;\n background: var(--ossido-color-border);\n}\n.ossido-err-menu-section { padding: 4px 10px 8px; }\n.ossido-err-menu-label {\n display: block;\n margin-bottom: 8px;\n color: var(--ossido-color-text-subtle);\n font-size: var(--ossido-font-size-xs);\n text-transform: uppercase;\n letter-spacing: var(--ossido-letter-spacing-wide);\n}\n.ossido-err-menu-corners {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n}\n.ossido-err-corner {\n position: relative;\n height: 30px;\n border: 1px solid var(--ossido-color-border-strong);\n border-radius: var(--ossido-radius-sm);\n background: var(--ossido-color-surface-raised);\n cursor: pointer;\n}\n.ossido-err-corner:hover { background: var(--ossido-color-surface-hover); }\n.ossido-err-corner--active {\n border-color: var(--ossido-color-accent);\n background: var(--ossido-color-surface-hover);\n}\n.ossido-err-corner-dot {\n position: absolute;\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--ossido-color-text-subtle);\n}\n.ossido-err-corner--active .ossido-err-corner-dot { background: var(--ossido-color-accent); }\n.ossido-err-corner-dot--top-left { top: 5px; left: 5px; }\n.ossido-err-corner-dot--top-right { top: 5px; right: 5px; }\n.ossido-err-corner-dot--bottom-left { bottom: 5px; left: 5px; }\n.ossido-err-corner-dot--bottom-right { bottom: 5px; right: 5px; }\n`;\n"],"mappings":";;;;;;AAKA,MAAa,mBAAmB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { BaseStyles } from './components/BaseStyles';
|
|
2
|
+
export { DefaultScreen } from './components/DefaultScreen';
|
|
3
|
+
export { DefaultError } from './components/DefaultError';
|
|
4
|
+
export { DefaultLoading } from './components/DefaultLoading';
|
|
5
|
+
export { DevErrorOverlay } from './components/DevErrorOverlay';
|
|
6
|
+
export { DevErrorOverlayHost } from './components/DevErrorOverlayHost';
|
|
7
|
+
export { DevErrorReporter } from './components/DevErrorReporter';
|
|
8
|
+
export { devErrorStore } from './components/devErrorStore';
|
|
9
|
+
export type { DevErrorKind, DevBuildError } from './components/devErrorStore';
|
|
10
|
+
export { warmDevErrorSource } from './components/devErrorSource';
|
|
11
|
+
export type { OssidoErrorProps, OssidoErrorWithSource, ServerErrorSource, ErrorComponent, } from './types';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseStyles } from "./components/BaseStyles.js";
|
|
2
|
+
import { DefaultScreen } from "./components/DefaultScreen.js";
|
|
3
|
+
import { DefaultError } from "./components/DefaultError.js";
|
|
4
|
+
import { DefaultLoading } from "./components/DefaultLoading.js";
|
|
5
|
+
import { warmDevErrorSource } from "./components/devErrorSource.js";
|
|
6
|
+
import { DevErrorOverlay } from "./components/DevErrorOverlay.js";
|
|
7
|
+
import { devErrorStore } from "./components/devErrorStore.js";
|
|
8
|
+
import { DevErrorOverlayHost } from "./components/DevErrorOverlayHost.js";
|
|
9
|
+
import { DevErrorReporter } from "./components/DevErrorReporter.js";
|
|
10
|
+
|
|
11
|
+
export { BaseStyles, DefaultError, DefaultLoading, DefaultScreen, DevErrorOverlay, DevErrorOverlayHost, DevErrorReporter, devErrorStore, warmDevErrorSource };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The panic-site source file, embedded by the server (dev only) so the overlay
|
|
4
|
+
* can show a highlighted excerpt — Rust has no sourcemap to resolve one from.
|
|
5
|
+
* @see crates/ossido/src/server_error.rs (`ErrorSource`)
|
|
6
|
+
*/
|
|
7
|
+
export interface ServerErrorSource {
|
|
8
|
+
file: string;
|
|
9
|
+
line: number;
|
|
10
|
+
column: number;
|
|
11
|
+
content: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* An `Error` carrying the server-provided panic-site source, used by the overlay
|
|
15
|
+
* to render the excerpt. Attached by `serverErrorToError` in ossido-router.
|
|
16
|
+
*/
|
|
17
|
+
export interface OssidoErrorWithSource extends Error {
|
|
18
|
+
ossidoServerSource?: ServerErrorSource;
|
|
19
|
+
}
|
|
20
|
+
/** Props passed to a user `error.tsx` component (and the default error UI). */
|
|
21
|
+
export interface OssidoErrorProps {
|
|
22
|
+
error: Error;
|
|
23
|
+
reset: () => void;
|
|
24
|
+
}
|
|
25
|
+
/** An `error.tsx` component. Rendered by the route error boundary. */
|
|
26
|
+
export type ErrorComponent = ComponentType<OssidoErrorProps>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridges Vite's HMR error overlay into Ossido's unified dev error overlay.
|
|
3
|
+
*
|
|
4
|
+
* Vite's client creates an `ErrorOverlay` custom element on a build/compile
|
|
5
|
+
* error and calls `.close()` on it once the error clears. Rather than let Vite
|
|
6
|
+
* render its own overlay, `ErrorOverlayVitePlugin` patches the client so that
|
|
7
|
+
* `ErrorOverlay` is *this* class — which renders nothing and instead forwards
|
|
8
|
+
* the error to the ossido dev error store (`window.__OSSIDO_DEV_ERRORS__`). Build
|
|
9
|
+
* errors then appear in the same browsable React overlay as runtime errors.
|
|
10
|
+
*
|
|
11
|
+
* The patch matches on the exact class declaration string (which only appears
|
|
12
|
+
* in Vite's client) instead of a module id, so it survives changes to how the
|
|
13
|
+
* client is resolved/served.
|
|
14
|
+
*
|
|
15
|
+
* @see packages/ossido-ui/src/components/devErrorStore.ts (the bridge target)
|
|
16
|
+
* @see https://github.com/tuono-labs/tuono/pull/607
|
|
17
|
+
*/
|
|
18
|
+
import type { ErrorPayload, Plugin } from 'vite';
|
|
19
|
+
declare const HTMLElement: typeof globalThis.HTMLElement;
|
|
20
|
+
/**
|
|
21
|
+
* The element Vite instantiates on a build error. It never renders; it reports
|
|
22
|
+
* the error to the ossido store (buffering if the store hasn't loaded yet) and
|
|
23
|
+
* clears it on `.close()`. This class's *source* (via `toString()`) is what the
|
|
24
|
+
* plugin injects into Vite's client, so it must not reference anything outside
|
|
25
|
+
* its own body other than browser globals.
|
|
26
|
+
*/
|
|
27
|
+
export declare class ErrorOverlay extends HTMLElement {
|
|
28
|
+
constructor(err: ErrorPayload['err']);
|
|
29
|
+
close(): void;
|
|
30
|
+
}
|
|
31
|
+
export declare const ErrorOverlayVitePlugin: Plugin;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/vite/error-overlay.ts
|
|
2
|
+
const HTMLElement = globalThis.HTMLElement ?? class {};
|
|
3
|
+
/**
|
|
4
|
+
* The element Vite instantiates on a build error. It never renders; it reports
|
|
5
|
+
* the error to the ossido store (buffering if the store hasn't loaded yet) and
|
|
6
|
+
* clears it on `.close()`. This class's *source* (via `toString()`) is what the
|
|
7
|
+
* plugin injects into Vite's client, so it must not reference anything outside
|
|
8
|
+
* its own body other than browser globals.
|
|
9
|
+
*/
|
|
10
|
+
var ErrorOverlay = class extends HTMLElement {
|
|
11
|
+
constructor(err) {
|
|
12
|
+
super();
|
|
13
|
+
const globalWindow = window;
|
|
14
|
+
const build = {
|
|
15
|
+
message: err.message,
|
|
16
|
+
stack: err.stack,
|
|
17
|
+
id: err.id,
|
|
18
|
+
frame: err.frame,
|
|
19
|
+
plugin: err.plugin,
|
|
20
|
+
loc: err.loc
|
|
21
|
+
};
|
|
22
|
+
const store = globalWindow["__OSSIDO_DEV_ERRORS__"];
|
|
23
|
+
if (typeof store?.addBuildError === "function") store.addBuildError(build);
|
|
24
|
+
else (globalWindow["__OSSIDO_DEV_ERRORS_BUFFER__"] ??= []).push(build);
|
|
25
|
+
}
|
|
26
|
+
close() {
|
|
27
|
+
window["__OSSIDO_DEV_ERRORS__"]?.clearBuildErrors?.();
|
|
28
|
+
this.parentNode?.removeChild(this);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function getOverlayCode() {
|
|
32
|
+
return `const ErrorOverlay = ${ErrorOverlay.toString()};`;
|
|
33
|
+
}
|
|
34
|
+
const VITE_OVERLAY_CLASS_DECL = "var ErrorOverlay = class extends HTMLElement";
|
|
35
|
+
function patchOverlay(code) {
|
|
36
|
+
return code.replace(VITE_OVERLAY_CLASS_DECL, getOverlayCode() + "\nvar ViteErrorOverlay = class extends HTMLElement");
|
|
37
|
+
}
|
|
38
|
+
const ErrorOverlayVitePlugin = {
|
|
39
|
+
name: "ossido-error-overlay-plugin",
|
|
40
|
+
transform(code, _id, opts) {
|
|
41
|
+
if (opts?.ssr) return;
|
|
42
|
+
if (!code.includes(VITE_OVERLAY_CLASS_DECL)) return;
|
|
43
|
+
return patchOverlay(code);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { ErrorOverlay, ErrorOverlayVitePlugin };
|
|
49
|
+
//# sourceMappingURL=error-overlay.js.map
|