@effect-tui/react 0.15.1 → 0.15.2
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/dist/src/hosts/codeblock.d.ts +5 -2
- package/dist/src/hosts/codeblock.d.ts.map +1 -1
- package/dist/src/hosts/codeblock.js +24 -7
- package/dist/src/hosts/codeblock.js.map +1 -1
- package/dist/src/hosts/spacer.d.ts +1 -2
- package/dist/src/hosts/spacer.d.ts.map +1 -1
- package/dist/src/hosts/spacer.js +0 -3
- package/dist/src/hosts/spacer.js.map +1 -1
- package/dist/src/renderer.d.ts.map +1 -1
- package/dist/src/renderer.js +28 -1
- package/dist/src/renderer.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/hosts/codeblock.ts +28 -9
- package/src/hosts/spacer.ts +1 -5
- package/src/renderer.ts +30 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-tui/react",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.2",
|
|
4
4
|
"description": "React bindings for @effect-tui/core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"prepublishOnly": "bun run typecheck && bun run build"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@effect-tui/core": "^0.15.
|
|
86
|
+
"@effect-tui/core": "^0.15.2",
|
|
87
87
|
"@effect/platform": "^0.94.1",
|
|
88
88
|
"@effect/platform-bun": "^0.87.0",
|
|
89
89
|
"@effect/rpc": "^0.73.0",
|
package/src/hosts/codeblock.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type CellBuffer, type Color, Colors, displayWidth, type Palette } from "@effect-tui/core"
|
|
2
2
|
import type { HighlightLine } from "../highlight.js"
|
|
3
|
-
import type { CommonProps, HostContext,
|
|
3
|
+
import type { CommonProps, HostContext, Size } from "../reconciler/types.js"
|
|
4
4
|
import { type Padding, type PaddingInput, resolveBgStyle, resolvePadding, styleIdFromProps } from "../utils/index.js"
|
|
5
5
|
import { BaseHost } from "./base.js"
|
|
6
6
|
|
|
@@ -27,6 +27,7 @@ export class CodeBlockHost extends BaseHost {
|
|
|
27
27
|
|
|
28
28
|
private cachedLineWidths: number[] = []
|
|
29
29
|
private gutterWidth = 0
|
|
30
|
+
private prepared = false
|
|
30
31
|
|
|
31
32
|
constructor(props: CodeBlockProps, ctx: HostContext) {
|
|
32
33
|
super("codeblock", props, ctx)
|
|
@@ -49,10 +50,24 @@ export class CodeBlockHost extends BaseHost {
|
|
|
49
50
|
return this.padding.top + this.padding.bottom
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
private prepareMetrics(): void {
|
|
54
|
+
this.cachedLineWidths = this.lines.map((line) => lineDisplayWidth(line))
|
|
55
|
+
this.gutterWidth = this.computeGutterWidth()
|
|
56
|
+
this.prepared = true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private ensurePrepared(): void {
|
|
60
|
+
if (this.prepared) return
|
|
61
|
+
this.prepareMetrics()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected override prepareSelf(): void {
|
|
65
|
+
this.ensurePrepared()
|
|
66
|
+
}
|
|
67
|
+
|
|
52
68
|
measure(maxW: number, maxH: number): Size {
|
|
53
69
|
const constrained = this.constrainProposal(maxW, maxH)
|
|
54
|
-
this.
|
|
55
|
-
this.gutterWidth = this.computeGutterWidth()
|
|
70
|
+
this.ensurePrepared()
|
|
56
71
|
|
|
57
72
|
const maxLineW = this.cachedLineWidths.reduce((max, w) => (w > max ? w : max), 0)
|
|
58
73
|
const contentW = maxLineW + this.insetX
|
|
@@ -65,10 +80,6 @@ export class CodeBlockHost extends BaseHost {
|
|
|
65
80
|
})
|
|
66
81
|
}
|
|
67
82
|
|
|
68
|
-
override layout(rect: Rect): void {
|
|
69
|
-
super.layout(rect)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
83
|
render(buffer: CellBuffer, palette: Palette): void {
|
|
73
84
|
if (!this.rect) return
|
|
74
85
|
|
|
@@ -120,11 +131,19 @@ export class CodeBlockHost extends BaseHost {
|
|
|
120
131
|
|
|
121
132
|
override updateProps(props: Record<string, unknown>): void {
|
|
122
133
|
super.updateProps(props)
|
|
123
|
-
|
|
124
|
-
if (props.
|
|
134
|
+
let invalidate = false
|
|
135
|
+
if (props.lines !== undefined) {
|
|
136
|
+
this.lines = props.lines as HighlightLine[]
|
|
137
|
+
invalidate = true
|
|
138
|
+
}
|
|
139
|
+
if (props.lineNumbers !== undefined) {
|
|
140
|
+
this.lineNumbers = !!props.lineNumbers
|
|
141
|
+
invalidate = true
|
|
142
|
+
}
|
|
125
143
|
if (props.padding !== undefined) this.padding = resolvePadding(props.padding as CodeBlockProps["padding"])
|
|
126
144
|
if (props.background !== undefined) this.background = props.background as Color
|
|
127
145
|
if (props.lineNumberColor !== undefined) this.lineNumberColor = props.lineNumberColor as Color
|
|
128
146
|
if (props.lineNumberBackground !== undefined) this.lineNumberBackground = props.lineNumberBackground as Color
|
|
147
|
+
if (invalidate) this.prepared = false
|
|
129
148
|
}
|
|
130
149
|
}
|
package/src/hosts/spacer.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CellBuffer, Palette } from "@effect-tui/core"
|
|
2
|
-
import type { CommonProps, HostContext,
|
|
2
|
+
import type { CommonProps, HostContext, Size } from "../reconciler/types.js"
|
|
3
3
|
import { BaseHost } from "./base.js"
|
|
4
4
|
|
|
5
5
|
export interface SpacerProps extends CommonProps {
|
|
@@ -26,10 +26,6 @@ export class SpacerHost extends BaseHost {
|
|
|
26
26
|
return { w: this.minWidth, h: this.minHeight }
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
override layout(rect: Rect): void {
|
|
30
|
-
super.layout(rect)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
render(_buffer: CellBuffer, _palette: Palette): void {
|
|
34
30
|
// Spacers render nothing
|
|
35
31
|
}
|
package/src/renderer.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { performance } from "node:perf_hooks"
|
|
|
2
2
|
import { fileURLToPath } from "node:url"
|
|
3
3
|
import { ANSI, bufferToString, type KeyMsg, type MouseMsg } from "@effect-tui/core"
|
|
4
4
|
import React, { type ReactNode } from "react"
|
|
5
|
-
import { createTerminalWriter } from "./console/ConsoleCapture.js"
|
|
5
|
+
import { createTerminalWriter, writeToTerminal } from "./console/ConsoleCapture.js"
|
|
6
6
|
import { DEFAULT_FPS } from "./constants.js"
|
|
7
7
|
import { requestExit } from "./exit.js"
|
|
8
8
|
import * as Prof from "./profiler.js"
|
|
@@ -272,6 +272,8 @@ export function createRenderer(options?: RendererOptions): TuiRenderer {
|
|
|
272
272
|
|
|
273
273
|
let onExit: (() => void) | null = null
|
|
274
274
|
let onSignal: ((signal: NodeJS.Signals) => void) | null = null
|
|
275
|
+
let onUncaughtException: ((err: Error) => void) | null = null
|
|
276
|
+
let onUnhandledRejection: ((reason: unknown) => void) | null = null
|
|
275
277
|
|
|
276
278
|
// Build renderer object
|
|
277
279
|
const renderer: TuiRenderer = {
|
|
@@ -300,6 +302,14 @@ export function createRenderer(options?: RendererOptions): TuiRenderer {
|
|
|
300
302
|
process.off("SIGTERM", onSignal)
|
|
301
303
|
onSignal = null
|
|
302
304
|
}
|
|
305
|
+
if (onUncaughtException) {
|
|
306
|
+
process.off("uncaughtException", onUncaughtException)
|
|
307
|
+
onUncaughtException = null
|
|
308
|
+
}
|
|
309
|
+
if (onUnhandledRejection) {
|
|
310
|
+
process.off("unhandledRejection", onUnhandledRejection)
|
|
311
|
+
onUnhandledRejection = null
|
|
312
|
+
}
|
|
303
313
|
if (state.loop) {
|
|
304
314
|
clearInterval(state.loop)
|
|
305
315
|
state.loop = null
|
|
@@ -333,6 +343,7 @@ export function createRenderer(options?: RendererOptions): TuiRenderer {
|
|
|
333
343
|
if (!manualMode) renderFrame()
|
|
334
344
|
},
|
|
335
345
|
dispatchResize(width: number, height: number) {
|
|
346
|
+
renderMode.handleResize(width, height, state.lastWidth)
|
|
336
347
|
state.updateDimensions(width, height)
|
|
337
348
|
state.invalidateBuffers()
|
|
338
349
|
state.markDirty()
|
|
@@ -403,6 +414,24 @@ export function createRenderer(options?: RendererOptions): TuiRenderer {
|
|
|
403
414
|
}
|
|
404
415
|
process.on("SIGINT", onSignal)
|
|
405
416
|
process.on("SIGTERM", onSignal)
|
|
417
|
+
|
|
418
|
+
// Handle uncaught exceptions - ensure error is visible before exit
|
|
419
|
+
onUncaughtException = (err: Error) => {
|
|
420
|
+
cleanup()
|
|
421
|
+
// Write directly to terminal, bypassing console capture
|
|
422
|
+
writeToTerminal(`\n[effect-tui] Uncaught exception:\n${err.stack || err.message}\n`)
|
|
423
|
+
process.exit(1)
|
|
424
|
+
}
|
|
425
|
+
process.on("uncaughtException", onUncaughtException)
|
|
426
|
+
|
|
427
|
+
// Handle unhandled promise rejections
|
|
428
|
+
onUnhandledRejection = (reason: unknown) => {
|
|
429
|
+
cleanup()
|
|
430
|
+
const message = reason instanceof Error ? reason.stack || reason.message : String(reason)
|
|
431
|
+
writeToTerminal(`\n[effect-tui] Unhandled rejection:\n${message}\n`)
|
|
432
|
+
process.exit(1)
|
|
433
|
+
}
|
|
434
|
+
process.on("unhandledRejection", onUnhandledRejection)
|
|
406
435
|
}
|
|
407
436
|
|
|
408
437
|
;(renderer as TuiRendererInternal)._container = null
|