@genesislcap/foundation-react-utils 15.47.0 → 15.48.0-alpha-830388687.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/README.md +55 -0
- package/dist/custom-elements.json +117 -0
- package/dist/dts/error-boundary/error-boundary-styles.d.ts +6 -0
- package/dist/dts/error-boundary/error-boundary-styles.d.ts.map +1 -0
- package/dist/dts/error-boundary/error-boundary.d.ts +105 -0
- package/dist/dts/error-boundary/error-boundary.d.ts.map +1 -0
- package/dist/dts/error-boundary/index.d.ts +3 -0
- package/dist/dts/error-boundary/index.d.ts.map +1 -0
- package/dist/dts/index.d.ts +3 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/error-boundary/error-boundary-styles.js +149 -0
- package/dist/esm/error-boundary/error-boundary.js +221 -0
- package/dist/esm/error-boundary/index.js +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/foundation-react-utils.api.json +452 -0
- package/dist/foundation-react-utils.d.ts +115 -0
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -47,6 +47,61 @@ resolving a second copy of the library, which breaks the `instanceof` checks `fl
|
|
|
47
47
|
relies on internally; the entry point logs a warning when the version it loads differs from the one
|
|
48
48
|
the theme was generated against.
|
|
49
49
|
|
|
50
|
+
## Error boundaries
|
|
51
|
+
|
|
52
|
+
`AppErrorBoundary` wraps the whole app, and `TileErrorBoundary` (or the `withTileErrorBoundary`
|
|
53
|
+
HOC) wraps a single tile, so a crash replaces only that tile. Both render a fallback with a
|
|
54
|
+
reference ID, copyable diagnostics and a Retry button that remounts the children.
|
|
55
|
+
|
|
56
|
+
With `setupErrorMonitoring` from `@genesislcap/foundation-utils`, caught errors are reported with
|
|
57
|
+
their reference ID, scope, title, tile registration and component stack, and nothing else is
|
|
58
|
+
needed:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { AppErrorBoundary, onCaughtError } from '@genesislcap/foundation-react-utils';
|
|
62
|
+
|
|
63
|
+
createRoot(el, { onCaughtError }).render(
|
|
64
|
+
<AppErrorBoundary>
|
|
65
|
+
<App />
|
|
66
|
+
</AppErrorBoundary>,
|
|
67
|
+
);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { TileErrorBoundary, withTileErrorBoundary } from '@genesislcap/foundation-react-utils';
|
|
72
|
+
|
|
73
|
+
<TileErrorBoundary title="Trade Blotter" tileRegistration="tradeBlotter">
|
|
74
|
+
<TradeBlotter />
|
|
75
|
+
</TileErrorBoundary>;
|
|
76
|
+
|
|
77
|
+
export const TradeBlotterTile = withTileErrorBoundary(TradeBlotter, 'Trade Blotter', 'tradeBlotter');
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
To handle caught errors yourself, pass `onError`. It receives an `ErrorBoundaryReport` (`error`,
|
|
81
|
+
`componentStack`, `referenceId`, `scope`, `title`, `tileRegistration`). `withTileErrorBoundary`
|
|
82
|
+
takes it as a fourth argument.
|
|
83
|
+
|
|
84
|
+
Pass `onCaughtError` to `createRoot`. By default React 19 logs every error a boundary catches to
|
|
85
|
+
`console.error` before the boundary runs, so a console-capturing monitoring tool reports the bare
|
|
86
|
+
error first and can drop or duplicate the boundary's own report. `onCaughtError` skips that log
|
|
87
|
+
for these boundaries, and still logs errors caught by any other boundary, with their component
|
|
88
|
+
stack.
|
|
89
|
+
|
|
90
|
+
Without `onError`, a boundary logs each caught error through a foundation logger named
|
|
91
|
+
`ERROR_BOUNDARY_LOGGER_NAME`: the error, then an object with its reference ID, scope, title, tile
|
|
92
|
+
registration and component stack. A global log reporter (`addGlobalLogReporter` from
|
|
93
|
+
`@genesislcap/foundation-logger`) receives it, which is how `setupErrorMonitoring` reports it. With
|
|
94
|
+
`onError` set, the boundary doesn't log the error, so it isn't reported twice. If `onError` throws,
|
|
95
|
+
the boundary logs the original error and the handler's error, so neither is lost.
|
|
96
|
+
|
|
97
|
+
The fallback takes its colours, font and corner radius from the design system's tokens
|
|
98
|
+
(`--neutral-layer-1`, `--neutral-foreground-rest`, `--accent-fill-rest`, `--error-color`,
|
|
99
|
+
`--body-font`, `--control-corner-radius` and others), so it follows the app's theme, including light
|
|
100
|
+
and dark mode. To override them, set `--eb-*` custom properties (`--eb-bg`, `--eb-surface`,
|
|
101
|
+
`--eb-text`, `--eb-text-muted`, `--eb-border`, `--eb-accent`, `--eb-error`, `--eb-font`, and others)
|
|
102
|
+
on an ancestor. Without a design system it uses its own light palette. The last 20 reports are also kept
|
|
103
|
+
on `window.__GENESIS_ERROR_BOUNDARY_REPORTS__` for dev tooling such as the Genesis Create preview.
|
|
104
|
+
|
|
50
105
|
## License
|
|
51
106
|
|
|
52
107
|
Note: this project provides front-end dependencies and uses licensed components listed in the next section; thus, licenses for those components are required during development. Contact [Genesis Global](https://genesis.global/contact-us/) for more details.
|
|
@@ -254,6 +254,14 @@
|
|
|
254
254
|
"module": "./create-grid-pro-cell-renderer"
|
|
255
255
|
}
|
|
256
256
|
},
|
|
257
|
+
{
|
|
258
|
+
"kind": "js",
|
|
259
|
+
"name": "*",
|
|
260
|
+
"declaration": {
|
|
261
|
+
"name": "*",
|
|
262
|
+
"package": "./error-boundary"
|
|
263
|
+
}
|
|
264
|
+
},
|
|
257
265
|
{
|
|
258
266
|
"kind": "js",
|
|
259
267
|
"name": "RendererControlProps",
|
|
@@ -264,6 +272,115 @@
|
|
|
264
272
|
}
|
|
265
273
|
]
|
|
266
274
|
},
|
|
275
|
+
{
|
|
276
|
+
"kind": "javascript-module",
|
|
277
|
+
"path": "src/error-boundary/error-boundary-styles.ts",
|
|
278
|
+
"declarations": [
|
|
279
|
+
{
|
|
280
|
+
"kind": "variable",
|
|
281
|
+
"name": "errorBoundaryStyles",
|
|
282
|
+
"default": "`\n.error-boundary {\n --_eb-bg: var(--eb-bg, var(--neutral-layer-1, #f6f8fb));\n --_eb-surface: var(--eb-surface, var(--neutral-layer-2, #ffffff));\n --_eb-surface-hover: var(--eb-surface-hover, var(--neutral-fill-stealth-hover, #eef2f8));\n --_eb-text: var(--eb-text, var(--neutral-foreground-rest, #18212f));\n --_eb-text-muted: var(--eb-text-muted, var(--neutral-foreground-hint, #5f6f84));\n --_eb-border: var(--eb-border, var(--neutral-stroke-rest, #d3dae6));\n --_eb-accent: var(--eb-accent, var(--accent-fill-rest, #2f6fed));\n --_eb-accent-hover: var(--eb-accent-hover, var(--accent-fill-hover, #255dcc));\n --_eb-accent-foreground: var(--eb-accent-foreground, var(--foreground-on-accent-rest, #ffffff));\n --_eb-error: var(--eb-error, var(--error-color, #c53d3d));\n --_eb-error-bg: var(--eb-error-bg, color-mix(in srgb, var(--_eb-error) 8%, var(--_eb-surface)));\n --_eb-error-text: var(--eb-error-text, color-mix(in srgb, var(--_eb-error) 50%, var(--_eb-text)));\n --_eb-focus: var(--eb-focus, var(--focus-stroke-outer, #2f6fed));\n --_eb-font: var(--eb-font, var(--body-font, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif));\n --_eb-mono-font: var(--eb-mono-font, 'Menlo', 'Consolas', 'Liberation Mono', monospace);\n\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: flex-start;\n width: 100%;\n height: 100%;\n padding: 16px;\n background: var(--_eb-bg);\n color: var(--_eb-text);\n font-family: var(--_eb-font);\n}\n\n.error-boundary__top,\n.error-boundary__title,\n.error-boundary__subtitle,\n.error-boundary__details,\n.error-boundary__actions,\n.error-boundary__manual-copy-help {\n width: 100%;\n}\n\n.error-boundary__top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.error-boundary__status {\n display: inline-flex;\n align-items: center;\n border: 1px solid var(--_eb-error);\n border-radius: 999px;\n padding: 5px 10px;\n text-transform: uppercase;\n letter-spacing: 0.13em;\n font-size: 11px;\n font-weight: 700;\n color: var(--_eb-error-text);\n background: var(--_eb-error-bg);\n}\n\n.error-boundary__reference {\n font-family: var(--_eb-mono-font);\n font-size: 11px;\n letter-spacing: 0.08em;\n color: var(--_eb-text-muted);\n text-transform: uppercase;\n}\n\n.error-boundary__title {\n margin: 0;\n font-size: clamp(22px, 3vw, 30px);\n line-height: 1.15;\n font-weight: 700;\n text-wrap: balance;\n}\n\n.error-boundary__subtitle {\n margin: 0;\n max-width: 80ch;\n line-height: 1.45;\n}\n\n.error-boundary__details {\n box-sizing: border-box;\n min-height: 190px;\n max-height: 360px;\n padding: 12px;\n border: 1px solid var(--_eb-border);\n border-radius: calc(var(--control-corner-radius, 10) * 1px);\n background: var(--_eb-surface);\n color: inherit;\n font-family: var(--_eb-mono-font);\n font-size: 12px;\n line-height: 1.5;\n resize: vertical;\n}\n\n.error-boundary__actions {\n display: flex;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.error-boundary__button {\n border: 1px solid var(--_eb-accent);\n border-radius: calc(var(--control-corner-radius, 999) * 1px);\n background: var(--_eb-accent);\n color: var(--_eb-accent-foreground);\n cursor: pointer;\n padding: 9px 16px;\n font: inherit;\n font-size: 12px;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.error-boundary__button:hover {\n background: var(--_eb-accent-hover);\n}\n\n.error-boundary__button--secondary {\n border-color: var(--_eb-border);\n background: var(--_eb-surface);\n color: inherit;\n}\n\n.error-boundary__button--secondary:hover {\n background: var(--_eb-surface-hover);\n}\n\n.error-boundary__button:focus-visible {\n outline: 2px solid var(--_eb-focus);\n outline-offset: 2px;\n}\n\n.error-boundary__manual-copy-help {\n margin: 2px 0 0;\n font-size: 13px;\n color: var(--_eb-text-muted);\n line-height: 1.4;\n}\n`",
|
|
283
|
+
"description": "Fallback UI styles. Each colour and font resolves from an `--eb-*` override set on any ancestor,\nthen the matching design token, then a built-in value for apps without a design system."
|
|
284
|
+
}
|
|
285
|
+
],
|
|
286
|
+
"exports": [
|
|
287
|
+
{
|
|
288
|
+
"kind": "js",
|
|
289
|
+
"name": "errorBoundaryStyles",
|
|
290
|
+
"declaration": {
|
|
291
|
+
"name": "errorBoundaryStyles",
|
|
292
|
+
"module": "src/error-boundary/error-boundary-styles.ts"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"kind": "javascript-module",
|
|
299
|
+
"path": "src/error-boundary/index.ts",
|
|
300
|
+
"declarations": [],
|
|
301
|
+
"exports": [
|
|
302
|
+
{
|
|
303
|
+
"kind": "js",
|
|
304
|
+
"name": "AppErrorBoundary",
|
|
305
|
+
"declaration": {
|
|
306
|
+
"name": "AppErrorBoundary",
|
|
307
|
+
"module": "./error-boundary"
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"kind": "js",
|
|
312
|
+
"name": "ERROR_BOUNDARY_LOGGER_NAME",
|
|
313
|
+
"declaration": {
|
|
314
|
+
"name": "ERROR_BOUNDARY_LOGGER_NAME",
|
|
315
|
+
"module": "./error-boundary"
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"kind": "js",
|
|
320
|
+
"name": "onCaughtError",
|
|
321
|
+
"declaration": {
|
|
322
|
+
"name": "onCaughtError",
|
|
323
|
+
"module": "./error-boundary"
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"kind": "js",
|
|
328
|
+
"name": "TileErrorBoundary",
|
|
329
|
+
"declaration": {
|
|
330
|
+
"name": "TileErrorBoundary",
|
|
331
|
+
"module": "./error-boundary"
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"kind": "js",
|
|
336
|
+
"name": "withTileErrorBoundary",
|
|
337
|
+
"declaration": {
|
|
338
|
+
"name": "withTileErrorBoundary",
|
|
339
|
+
"module": "./error-boundary"
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
"kind": "js",
|
|
344
|
+
"name": "AppErrorBoundaryProps",
|
|
345
|
+
"declaration": {
|
|
346
|
+
"name": "AppErrorBoundaryProps",
|
|
347
|
+
"module": "./error-boundary"
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"kind": "js",
|
|
352
|
+
"name": "ErrorBoundaryErrorHandler",
|
|
353
|
+
"declaration": {
|
|
354
|
+
"name": "ErrorBoundaryErrorHandler",
|
|
355
|
+
"module": "./error-boundary"
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"kind": "js",
|
|
360
|
+
"name": "ErrorBoundaryReport",
|
|
361
|
+
"declaration": {
|
|
362
|
+
"name": "ErrorBoundaryReport",
|
|
363
|
+
"module": "./error-boundary"
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"kind": "js",
|
|
368
|
+
"name": "ErrorBoundaryScope",
|
|
369
|
+
"declaration": {
|
|
370
|
+
"name": "ErrorBoundaryScope",
|
|
371
|
+
"module": "./error-boundary"
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"kind": "js",
|
|
376
|
+
"name": "TileErrorBoundaryProps",
|
|
377
|
+
"declaration": {
|
|
378
|
+
"name": "TileErrorBoundaryProps",
|
|
379
|
+
"module": "./error-boundary"
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
]
|
|
383
|
+
},
|
|
267
384
|
{
|
|
268
385
|
"kind": "javascript-module",
|
|
269
386
|
"path": "src/flexlayout/index.ts",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback UI styles. Each colour and font resolves from an `--eb-*` override set on any ancestor,
|
|
3
|
+
* then the matching design token, then a built-in value for apps without a design system.
|
|
4
|
+
*/
|
|
5
|
+
export declare const errorBoundaryStyles = "\n.error-boundary {\n --_eb-bg: var(--eb-bg, var(--neutral-layer-1, #f6f8fb));\n --_eb-surface: var(--eb-surface, var(--neutral-layer-2, #ffffff));\n --_eb-surface-hover: var(--eb-surface-hover, var(--neutral-fill-stealth-hover, #eef2f8));\n --_eb-text: var(--eb-text, var(--neutral-foreground-rest, #18212f));\n --_eb-text-muted: var(--eb-text-muted, var(--neutral-foreground-hint, #5f6f84));\n --_eb-border: var(--eb-border, var(--neutral-stroke-rest, #d3dae6));\n --_eb-accent: var(--eb-accent, var(--accent-fill-rest, #2f6fed));\n --_eb-accent-hover: var(--eb-accent-hover, var(--accent-fill-hover, #255dcc));\n --_eb-accent-foreground: var(--eb-accent-foreground, var(--foreground-on-accent-rest, #ffffff));\n --_eb-error: var(--eb-error, var(--error-color, #c53d3d));\n --_eb-error-bg: var(--eb-error-bg, color-mix(in srgb, var(--_eb-error) 8%, var(--_eb-surface)));\n --_eb-error-text: var(--eb-error-text, color-mix(in srgb, var(--_eb-error) 50%, var(--_eb-text)));\n --_eb-focus: var(--eb-focus, var(--focus-stroke-outer, #2f6fed));\n --_eb-font: var(--eb-font, var(--body-font, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif));\n --_eb-mono-font: var(--eb-mono-font, 'Menlo', 'Consolas', 'Liberation Mono', monospace);\n\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: flex-start;\n width: 100%;\n height: 100%;\n padding: 16px;\n background: var(--_eb-bg);\n color: var(--_eb-text);\n font-family: var(--_eb-font);\n}\n\n.error-boundary__top,\n.error-boundary__title,\n.error-boundary__subtitle,\n.error-boundary__details,\n.error-boundary__actions,\n.error-boundary__manual-copy-help {\n width: 100%;\n}\n\n.error-boundary__top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.error-boundary__status {\n display: inline-flex;\n align-items: center;\n border: 1px solid var(--_eb-error);\n border-radius: 999px;\n padding: 5px 10px;\n text-transform: uppercase;\n letter-spacing: 0.13em;\n font-size: 11px;\n font-weight: 700;\n color: var(--_eb-error-text);\n background: var(--_eb-error-bg);\n}\n\n.error-boundary__reference {\n font-family: var(--_eb-mono-font);\n font-size: 11px;\n letter-spacing: 0.08em;\n color: var(--_eb-text-muted);\n text-transform: uppercase;\n}\n\n.error-boundary__title {\n margin: 0;\n font-size: clamp(22px, 3vw, 30px);\n line-height: 1.15;\n font-weight: 700;\n text-wrap: balance;\n}\n\n.error-boundary__subtitle {\n margin: 0;\n max-width: 80ch;\n line-height: 1.45;\n}\n\n.error-boundary__details {\n box-sizing: border-box;\n min-height: 190px;\n max-height: 360px;\n padding: 12px;\n border: 1px solid var(--_eb-border);\n border-radius: calc(var(--control-corner-radius, 10) * 1px);\n background: var(--_eb-surface);\n color: inherit;\n font-family: var(--_eb-mono-font);\n font-size: 12px;\n line-height: 1.5;\n resize: vertical;\n}\n\n.error-boundary__actions {\n display: flex;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.error-boundary__button {\n border: 1px solid var(--_eb-accent);\n border-radius: calc(var(--control-corner-radius, 999) * 1px);\n background: var(--_eb-accent);\n color: var(--_eb-accent-foreground);\n cursor: pointer;\n padding: 9px 16px;\n font: inherit;\n font-size: 12px;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.error-boundary__button:hover {\n background: var(--_eb-accent-hover);\n}\n\n.error-boundary__button--secondary {\n border-color: var(--_eb-border);\n background: var(--_eb-surface);\n color: inherit;\n}\n\n.error-boundary__button--secondary:hover {\n background: var(--_eb-surface-hover);\n}\n\n.error-boundary__button:focus-visible {\n outline: 2px solid var(--_eb-focus);\n outline-offset: 2px;\n}\n\n.error-boundary__manual-copy-help {\n margin: 2px 0 0;\n font-size: 13px;\n color: var(--_eb-text-muted);\n line-height: 1.4;\n}\n";
|
|
6
|
+
//# sourceMappingURL=error-boundary-styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-boundary-styles.d.ts","sourceRoot":"","sources":["../../../src/error-boundary/error-boundary-styles.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,mBAAmB,w4HAgJ/B,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ComponentType, FC, ReactNode } from 'react';
|
|
2
|
+
import type { RootOptions } from 'react-dom/client';
|
|
3
|
+
/**
|
|
4
|
+
* Name of the logger the error boundaries log through. They log a caught error, followed by its
|
|
5
|
+
* reference ID, scope, title, tile registration and component stack, only when no `onError`
|
|
6
|
+
* handler is set or when the handler throws. `setupErrorMonitoring` from foundation-utils reports
|
|
7
|
+
* these logs, so apps using it don't need an `onError`.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare const ERROR_BOUNDARY_LOGGER_NAME = "foundation-react-utils:error-boundary";
|
|
11
|
+
/**
|
|
12
|
+
* Where a boundary sits: around the whole app, or around a single tile.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export type ErrorBoundaryScope = 'application' | 'tile';
|
|
16
|
+
/**
|
|
17
|
+
* What an error boundary passes to `onError` when it catches an error.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
export type ErrorBoundaryReport = {
|
|
21
|
+
error: Error;
|
|
22
|
+
componentStack: string;
|
|
23
|
+
/** Shown in the fallback UI, so support can match a user's screen to a reported event. */
|
|
24
|
+
referenceId: string;
|
|
25
|
+
scope: ErrorBoundaryScope;
|
|
26
|
+
title: string;
|
|
27
|
+
tileRegistration?: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Callback that receives every error a boundary catches, for example to send it to an
|
|
31
|
+
* error-monitoring service.
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
export type ErrorBoundaryErrorHandler = (report: ErrorBoundaryReport) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Props for {@link AppErrorBoundary}.
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
export type AppErrorBoundaryProps = {
|
|
40
|
+
onError?: ErrorBoundaryErrorHandler;
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Props for {@link TileErrorBoundary}.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export type TileErrorBoundaryProps = {
|
|
48
|
+
/** Human-readable tile name shown in the fallback UI. */
|
|
49
|
+
title: string;
|
|
50
|
+
/** The tile's key in the layout. */
|
|
51
|
+
tileRegistration: string;
|
|
52
|
+
onError?: ErrorBoundaryErrorHandler;
|
|
53
|
+
children: ReactNode;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Top-level error boundary. Wrap the whole app in one instance; use {@link TileErrorBoundary}
|
|
57
|
+
* inside it.
|
|
58
|
+
*
|
|
59
|
+
* @remarks
|
|
60
|
+
* Renders a fallback with a reference ID, copyable diagnostics and a Retry button that remounts
|
|
61
|
+
* the children. Each caught error is passed to `onError`. Without one, it's logged through the
|
|
62
|
+
* {@link ERROR_BOUNDARY_LOGGER_NAME} logger instead, which a global log reporter receives. Pair with {@link onCaughtError} on the root so React doesn't log the
|
|
63
|
+
* error a second time.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```tsx
|
|
67
|
+
* createRoot(el, { onCaughtError }).render(
|
|
68
|
+
* <AppErrorBoundary onError={({ error, ...extra }) => Sentry.captureException(error, { extra })}>
|
|
69
|
+
* <App />
|
|
70
|
+
* </AppErrorBoundary>,
|
|
71
|
+
* );
|
|
72
|
+
* ```
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export declare const AppErrorBoundary: FC<AppErrorBoundaryProps>;
|
|
76
|
+
/**
|
|
77
|
+
* Error boundary for a single tile, so a crash replaces only that tile with the fallback UI and
|
|
78
|
+
* the rest of the app keeps running.
|
|
79
|
+
* @public
|
|
80
|
+
*/
|
|
81
|
+
export declare const TileErrorBoundary: FC<TileErrorBoundaryProps>;
|
|
82
|
+
/**
|
|
83
|
+
* Wraps a component in a {@link TileErrorBoundary}.
|
|
84
|
+
*
|
|
85
|
+
* @param WrappedComponent - The tile component.
|
|
86
|
+
* @param title - Human-readable tile name shown in the fallback UI.
|
|
87
|
+
* @param tileRegistration - The tile's key in the layout.
|
|
88
|
+
* @param onError - Optional callback for caught errors.
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
export declare const withTileErrorBoundary: <P extends object>(WrappedComponent: ComponentType<P>, title: string, tileRegistration: string, onError?: ErrorBoundaryErrorHandler) => FC<P>;
|
|
92
|
+
/**
|
|
93
|
+
* Root `onCaughtError` for `createRoot`.
|
|
94
|
+
*
|
|
95
|
+
* @remarks
|
|
96
|
+
* By default React 19 logs every error a boundary catches to `console.error`, before the
|
|
97
|
+
* boundary's `componentDidCatch` runs. Console-capturing monitoring tools then report that bare
|
|
98
|
+
* error first, and can drop or duplicate the boundary's own report. {@link AppErrorBoundary} and
|
|
99
|
+
* {@link TileErrorBoundary} report or log errors themselves, so this skips them. Errors caught by
|
|
100
|
+
* any other boundary are still logged to `console.error`, with their component stack.
|
|
101
|
+
*
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export declare const onCaughtError: NonNullable<RootOptions['onCaughtError']>;
|
|
105
|
+
//# sourceMappingURL=error-boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-boundary.d.ts","sourceRoot":"","sources":["../../../src/error-boundary/error-boundary.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAa,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,0CAA0C,CAAC;AAIlF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,aAAa,GAAG,MAAM,CAAC;AAExD;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAE9E;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAmPF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAItD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAcxD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAAI,CAAC,SAAS,MAAM,EACpD,kBAAkB,aAAa,CAAC,CAAC,CAAC,EAClC,OAAO,MAAM,EACb,kBAAkB,MAAM,EACxB,UAAU,yBAAyB,KAClC,EAAE,CAAC,CAAC,CAUN,CAAC;AAOF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,WAAW,CAAC,eAAe,CAAC,CASnE,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { AppErrorBoundary, ERROR_BOUNDARY_LOGGER_NAME, onCaughtError, TileErrorBoundary, withTileErrorBoundary, } from './error-boundary';
|
|
2
|
+
export type { AppErrorBoundaryProps, ErrorBoundaryErrorHandler, ErrorBoundaryReport, ErrorBoundaryScope, TileErrorBoundaryProps, } from './error-boundary';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/error-boundary/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,aAAa,EACb,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC"}
|
package/dist/dts/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* grid's `gridComponents` property).
|
|
13
13
|
* - `reactFactory` / `reactFactoryWithProvider` — mount React component trees into
|
|
14
14
|
* Genesis Foundation layout regions.
|
|
15
|
+
* - `AppErrorBoundary` / `TileErrorBoundary` / `withTileErrorBoundary` — error boundaries with a
|
|
16
|
+
* fallback UI and an `onError` reporting hook; pair with `onCaughtError` on the React root.
|
|
15
17
|
*
|
|
16
18
|
* Subpath entry points:
|
|
17
19
|
* - `./flexlayout` — `flexlayout-react` at the version this package pins, re-exported with the
|
|
@@ -25,5 +27,6 @@ export { createGridProCellRenderer } from './create-grid-pro-cell-renderer';
|
|
|
25
27
|
export { createGridProCellPortals } from './create-grid-pro-cell-portals';
|
|
26
28
|
export type { GridProCellPortals } from './create-grid-pro-cell-portals';
|
|
27
29
|
export type { GridProCellRendererOptions, GridProCellRendererProps, GridProReactCellRenderer, } from './create-grid-pro-cell-renderer';
|
|
30
|
+
export * from './error-boundary';
|
|
28
31
|
export type { RendererControlProps } from '@genesislcap/foundation-forms';
|
|
29
32
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/dts/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,YAAY,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,YAAY,EACV,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,iCAAiC,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,YAAY,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback UI styles. Each colour and font resolves from an `--eb-*` override set on any ancestor,
|
|
3
|
+
* then the matching design token, then a built-in value for apps without a design system.
|
|
4
|
+
*/
|
|
5
|
+
export const errorBoundaryStyles = `
|
|
6
|
+
.error-boundary {
|
|
7
|
+
--_eb-bg: var(--eb-bg, var(--neutral-layer-1, #f6f8fb));
|
|
8
|
+
--_eb-surface: var(--eb-surface, var(--neutral-layer-2, #ffffff));
|
|
9
|
+
--_eb-surface-hover: var(--eb-surface-hover, var(--neutral-fill-stealth-hover, #eef2f8));
|
|
10
|
+
--_eb-text: var(--eb-text, var(--neutral-foreground-rest, #18212f));
|
|
11
|
+
--_eb-text-muted: var(--eb-text-muted, var(--neutral-foreground-hint, #5f6f84));
|
|
12
|
+
--_eb-border: var(--eb-border, var(--neutral-stroke-rest, #d3dae6));
|
|
13
|
+
--_eb-accent: var(--eb-accent, var(--accent-fill-rest, #2f6fed));
|
|
14
|
+
--_eb-accent-hover: var(--eb-accent-hover, var(--accent-fill-hover, #255dcc));
|
|
15
|
+
--_eb-accent-foreground: var(--eb-accent-foreground, var(--foreground-on-accent-rest, #ffffff));
|
|
16
|
+
--_eb-error: var(--eb-error, var(--error-color, #c53d3d));
|
|
17
|
+
--_eb-error-bg: var(--eb-error-bg, color-mix(in srgb, var(--_eb-error) 8%, var(--_eb-surface)));
|
|
18
|
+
--_eb-error-text: var(--eb-error-text, color-mix(in srgb, var(--_eb-error) 50%, var(--_eb-text)));
|
|
19
|
+
--_eb-focus: var(--eb-focus, var(--focus-stroke-outer, #2f6fed));
|
|
20
|
+
--_eb-font: var(--eb-font, var(--body-font, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif));
|
|
21
|
+
--_eb-mono-font: var(--eb-mono-font, 'Menlo', 'Consolas', 'Liberation Mono', monospace);
|
|
22
|
+
|
|
23
|
+
box-sizing: border-box;
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
gap: 12px;
|
|
27
|
+
align-items: flex-start;
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 100%;
|
|
30
|
+
padding: 16px;
|
|
31
|
+
background: var(--_eb-bg);
|
|
32
|
+
color: var(--_eb-text);
|
|
33
|
+
font-family: var(--_eb-font);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.error-boundary__top,
|
|
37
|
+
.error-boundary__title,
|
|
38
|
+
.error-boundary__subtitle,
|
|
39
|
+
.error-boundary__details,
|
|
40
|
+
.error-boundary__actions,
|
|
41
|
+
.error-boundary__manual-copy-help {
|
|
42
|
+
width: 100%;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.error-boundary__top {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: space-between;
|
|
49
|
+
gap: 10px;
|
|
50
|
+
flex-wrap: wrap;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.error-boundary__status {
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
border: 1px solid var(--_eb-error);
|
|
57
|
+
border-radius: 999px;
|
|
58
|
+
padding: 5px 10px;
|
|
59
|
+
text-transform: uppercase;
|
|
60
|
+
letter-spacing: 0.13em;
|
|
61
|
+
font-size: 11px;
|
|
62
|
+
font-weight: 700;
|
|
63
|
+
color: var(--_eb-error-text);
|
|
64
|
+
background: var(--_eb-error-bg);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.error-boundary__reference {
|
|
68
|
+
font-family: var(--_eb-mono-font);
|
|
69
|
+
font-size: 11px;
|
|
70
|
+
letter-spacing: 0.08em;
|
|
71
|
+
color: var(--_eb-text-muted);
|
|
72
|
+
text-transform: uppercase;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.error-boundary__title {
|
|
76
|
+
margin: 0;
|
|
77
|
+
font-size: clamp(22px, 3vw, 30px);
|
|
78
|
+
line-height: 1.15;
|
|
79
|
+
font-weight: 700;
|
|
80
|
+
text-wrap: balance;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.error-boundary__subtitle {
|
|
84
|
+
margin: 0;
|
|
85
|
+
max-width: 80ch;
|
|
86
|
+
line-height: 1.45;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.error-boundary__details {
|
|
90
|
+
box-sizing: border-box;
|
|
91
|
+
min-height: 190px;
|
|
92
|
+
max-height: 360px;
|
|
93
|
+
padding: 12px;
|
|
94
|
+
border: 1px solid var(--_eb-border);
|
|
95
|
+
border-radius: calc(var(--control-corner-radius, 10) * 1px);
|
|
96
|
+
background: var(--_eb-surface);
|
|
97
|
+
color: inherit;
|
|
98
|
+
font-family: var(--_eb-mono-font);
|
|
99
|
+
font-size: 12px;
|
|
100
|
+
line-height: 1.5;
|
|
101
|
+
resize: vertical;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.error-boundary__actions {
|
|
105
|
+
display: flex;
|
|
106
|
+
gap: 10px;
|
|
107
|
+
flex-wrap: wrap;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.error-boundary__button {
|
|
111
|
+
border: 1px solid var(--_eb-accent);
|
|
112
|
+
border-radius: calc(var(--control-corner-radius, 999) * 1px);
|
|
113
|
+
background: var(--_eb-accent);
|
|
114
|
+
color: var(--_eb-accent-foreground);
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
padding: 9px 16px;
|
|
117
|
+
font: inherit;
|
|
118
|
+
font-size: 12px;
|
|
119
|
+
font-weight: 700;
|
|
120
|
+
letter-spacing: 0.04em;
|
|
121
|
+
text-transform: uppercase;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.error-boundary__button:hover {
|
|
125
|
+
background: var(--_eb-accent-hover);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.error-boundary__button--secondary {
|
|
129
|
+
border-color: var(--_eb-border);
|
|
130
|
+
background: var(--_eb-surface);
|
|
131
|
+
color: inherit;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.error-boundary__button--secondary:hover {
|
|
135
|
+
background: var(--_eb-surface-hover);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.error-boundary__button:focus-visible {
|
|
139
|
+
outline: 2px solid var(--_eb-focus);
|
|
140
|
+
outline-offset: 2px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.error-boundary__manual-copy-help {
|
|
144
|
+
margin: 2px 0 0;
|
|
145
|
+
font-size: 13px;
|
|
146
|
+
color: var(--_eb-text-muted);
|
|
147
|
+
line-height: 1.4;
|
|
148
|
+
}
|
|
149
|
+
`;
|