@effect-tui/react 0.2.2 → 0.2.3
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/components/MultilineTextInput.js +1 -1
- package/dist/src/components/MultilineTextInput.js.map +1 -1
- package/dist/src/components/TextInput.js +1 -1
- package/dist/src/components/TextInput.js.map +1 -1
- package/dist/src/components/text-editing.js +1 -1
- package/dist/src/components/text-editing.js.map +1 -1
- package/dist/src/console/ConsoleCapture.d.ts +1 -1
- package/dist/src/console/ConsoleCapture.d.ts.map +1 -1
- package/dist/src/console/ConsoleCapture.js +1 -1
- package/dist/src/console/ConsoleCapture.js.map +1 -1
- package/dist/src/console/ConsolePopover.js +1 -1
- package/dist/src/console/ConsolePopover.js.map +1 -1
- package/dist/src/debug/DebugOverlay.d.ts +2 -2
- package/dist/src/debug/DebugOverlay.d.ts.map +1 -1
- package/dist/src/debug/DebugOverlay.js +2 -2
- package/dist/src/debug/DebugOverlay.js.map +1 -1
- package/dist/src/dev.js +5 -5
- package/dist/src/dev.js.map +1 -1
- package/dist/src/highlight.d.ts.map +1 -1
- package/dist/src/highlight.js +2 -4
- package/dist/src/highlight.js.map +1 -1
- package/dist/src/hmr-plugin.d.ts +14 -0
- package/dist/src/hmr-plugin.d.ts.map +1 -1
- package/dist/src/hmr-plugin.js +1 -1
- package/dist/src/hmr-plugin.js.map +1 -1
- package/dist/src/hosts/base.d.ts +1 -1
- package/dist/src/hosts/base.d.ts.map +1 -1
- package/dist/src/hosts/base.js +1 -1
- package/dist/src/hosts/base.js.map +1 -1
- package/dist/src/hosts/single-child.d.ts +1 -2
- package/dist/src/hosts/single-child.d.ts.map +1 -1
- package/dist/src/hosts/single-child.js +0 -3
- package/dist/src/hosts/single-child.js.map +1 -1
- package/dist/src/motion/hooks.d.ts.map +1 -1
- package/dist/src/motion/hooks.js +4 -2
- package/dist/src/motion/hooks.js.map +1 -1
- package/dist/src/renderer/modes/InlineRenderer.js +1 -1
- package/dist/src/renderer/modes/InlineRenderer.js.map +1 -1
- package/dist/src/renderer/modes/StaticContentRenderer.js +1 -1
- package/dist/src/renderer/modes/StaticContentRenderer.js.map +1 -1
- package/dist/src/utils/flex-layout.d.ts.map +1 -1
- package/dist/src/utils/flex-layout.js +2 -4
- package/dist/src/utils/flex-layout.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/components/MultilineTextInput.tsx +1 -1
- package/src/components/TextInput.tsx +1 -1
- package/src/components/text-editing.ts +1 -1
- package/src/console/ConsoleCapture.ts +1 -1
- package/src/console/ConsolePopover.tsx +2 -2
- package/src/debug/DebugOverlay.ts +2 -2
- package/src/dev.tsx +7 -7
- package/src/highlight.ts +5 -7
- package/src/hmr-plugin.ts +2 -1
- package/src/hosts/base.ts +1 -1
- package/src/hosts/single-child.ts +1 -5
- package/src/motion/hooks.ts +5 -2
- package/src/renderer/modes/InlineRenderer.ts +1 -1
- package/src/renderer/modes/StaticContentRenderer.ts +1 -1
- package/src/utils/flex-layout.ts +3 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-tui/react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
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.2.
|
|
86
|
+
"@effect-tui/core": "^0.2.3",
|
|
87
87
|
"@effect/platform": "^0.94.0",
|
|
88
88
|
"@effect/platform-bun": "^0.87.0",
|
|
89
89
|
"@effect/rpc": "^0.73.0",
|
|
@@ -335,7 +335,7 @@ export function MultilineTextInput({
|
|
|
335
335
|
if (newRow !== cursor.row || newCol !== cursor.col) {
|
|
336
336
|
setCursor({ row: newRow, col: newCol })
|
|
337
337
|
}
|
|
338
|
-
}, [
|
|
338
|
+
}, [logicalLines, layout.lines, cursor.row, cursor.col])
|
|
339
339
|
|
|
340
340
|
// Keep scroll in bounds (visual lines)
|
|
341
341
|
useEffect(() => {
|
|
@@ -219,7 +219,7 @@ export function deleteWordBackwardMultiline(state: MultilineState): EditResult<M
|
|
|
219
219
|
const match = matchPrevWord(prevLine)
|
|
220
220
|
|
|
221
221
|
if (match) {
|
|
222
|
-
const killed = match
|
|
222
|
+
const killed = `${match}\n`
|
|
223
223
|
const newPrevLine = prevLine.slice(0, prevLine.length - match.length)
|
|
224
224
|
const newLines = [...lines]
|
|
225
225
|
newLines[cursor.row - 1] = newPrevLine + currentLine
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Intercepts console.log/info/warn/error/debug and stores entries for display
|
|
3
3
|
|
|
4
4
|
import { Console } from "node:console"
|
|
5
|
+
import { EventEmitter } from "node:events"
|
|
5
6
|
import { Writable } from "node:stream"
|
|
6
7
|
import * as util from "node:util"
|
|
7
|
-
import { EventEmitter } from "events"
|
|
8
8
|
|
|
9
9
|
// ─────────────────────────────────────────────────────────────
|
|
10
10
|
// Types
|
|
@@ -451,11 +451,11 @@ export function ConsolePopover({
|
|
|
451
451
|
{/* Title bar */}
|
|
452
452
|
<hstack height={1} bg={TITLE_BG}>
|
|
453
453
|
<text fg={feedback ? Colors.green : TITLE_FG} bg={TITLE_BG}>
|
|
454
|
-
{
|
|
454
|
+
{` ${titleText}`}
|
|
455
455
|
</text>
|
|
456
456
|
<spacer />
|
|
457
457
|
<text fg={Colors.gray(14)} bg={TITLE_BG}>
|
|
458
|
-
{
|
|
458
|
+
{`${mode === "inline" ? inlineHints : hints} `}
|
|
459
459
|
</text>
|
|
460
460
|
</hstack>
|
|
461
461
|
|
|
@@ -162,7 +162,7 @@ export class DebugOverlay {
|
|
|
162
162
|
// Key handling - returns true if event was consumed
|
|
163
163
|
// ─────────────────────────────────────────────────────────────
|
|
164
164
|
|
|
165
|
-
handleKey(key: KeyMsg,
|
|
165
|
+
handleKey(key: KeyMsg, _width: number, height: number): boolean {
|
|
166
166
|
// Ctrl+Shift+D - toggle overlay (handled even when hidden)
|
|
167
167
|
if (key.ctrl && key.shift && key.name === "char" && key.text === "d") {
|
|
168
168
|
this.toggle()
|
|
@@ -246,7 +246,7 @@ export class DebugOverlay {
|
|
|
246
246
|
// Mouse handling - returns true if event was consumed
|
|
247
247
|
// ─────────────────────────────────────────────────────────────
|
|
248
248
|
|
|
249
|
-
handleMouse(mouse: MouseMsg,
|
|
249
|
+
handleMouse(mouse: MouseMsg, _width: number, height: number): boolean {
|
|
250
250
|
if (!this._visible) return false
|
|
251
251
|
|
|
252
252
|
const popoverHeight = this.getPopoverHeight(height)
|
package/src/dev.tsx
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
* - Remote control when EFFECT_TUI_REMOTE=1
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { readFileSync } from "node:fs"
|
|
13
|
+
import { stat } from "node:fs/promises"
|
|
14
|
+
import { dirname } from "node:path"
|
|
12
15
|
import { Colors } from "@effect-tui/core"
|
|
13
16
|
import * as watcher from "@parcel/watcher"
|
|
14
17
|
import { globalValue } from "effect/GlobalValue"
|
|
15
|
-
import { readFileSync } from "fs"
|
|
16
|
-
import { stat } from "fs/promises"
|
|
17
|
-
import { dirname } from "path"
|
|
18
18
|
import React from "react"
|
|
19
19
|
import { Overlay } from "./components/Overlay.js"
|
|
20
20
|
import { ConsolePopover } from "./console/ConsolePopover.js"
|
|
@@ -363,10 +363,10 @@ function DevWrapper({
|
|
|
363
363
|
<ToastProvider>
|
|
364
364
|
<Overlay>
|
|
365
365
|
{/* Base - determines container size */}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
366
|
+
|
|
367
|
+
<ScreenshotHandler />
|
|
368
|
+
{children}
|
|
369
|
+
|
|
370
370
|
{/* Overlays */}
|
|
371
371
|
{visible && (
|
|
372
372
|
<Overlay.Item alignment={{ v: "bottom" }}>
|
package/src/highlight.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Color } from "@effect-tui/core"
|
|
2
|
-
import { type BundledLanguage, type BundledTheme, createHighlighter, type Highlighter } from "shiki"
|
|
2
|
+
import { type BundledLanguage, type BundledTheme, createHighlighter, type Highlighter, type ThemedToken } from "shiki"
|
|
3
3
|
|
|
4
4
|
export interface HighlightTokenStyle {
|
|
5
5
|
fg?: Color
|
|
@@ -48,17 +48,15 @@ export async function highlightCode(
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const tokensResult = await highlighter.codeToTokens(code, { lang, theme })
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
: // Shiki v3 returns { tokens, theme }
|
|
54
|
-
(tokensResult as any).tokens
|
|
51
|
+
// Shiki v3 returns { tokens: ThemedToken[][], ... }
|
|
52
|
+
const tokenLines: ThemedToken[][] = tokensResult.tokens
|
|
55
53
|
|
|
56
54
|
if (!Array.isArray(tokenLines)) return toPlainLines(code)
|
|
57
55
|
|
|
58
|
-
return tokenLines.map((line
|
|
56
|
+
return tokenLines.map((line) =>
|
|
59
57
|
line.map((token) => {
|
|
60
58
|
const style: HighlightTokenStyle = {}
|
|
61
|
-
if (token.color) style.fg = token.color
|
|
59
|
+
if (token.color) style.fg = token.color as Color
|
|
62
60
|
const fs = token.fontStyle ?? 0
|
|
63
61
|
// fontStyle bitmask is: 1 = Italic, 2 = Bold, 4 = Underline
|
|
64
62
|
if (fs & 2) style.bold = true
|
package/src/hmr-plugin.ts
CHANGED
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
* [run]
|
|
13
13
|
* preload = ["./node_modules/@effect-tui/react/dist/hmr-plugin.js"]
|
|
14
14
|
*/
|
|
15
|
+
|
|
16
|
+
import { relative } from "node:path"
|
|
15
17
|
import { plugin } from "bun"
|
|
16
|
-
import { relative } from "path"
|
|
17
18
|
|
|
18
19
|
// Only enable in development
|
|
19
20
|
if (process.env.NODE_ENV !== "production") {
|
package/src/hosts/base.ts
CHANGED
|
@@ -54,7 +54,7 @@ export abstract class BaseHost implements HostInstance {
|
|
|
54
54
|
|
|
55
55
|
protected ctx: HostContext
|
|
56
56
|
|
|
57
|
-
constructor(type: string,
|
|
57
|
+
constructor(type: string, _props: CommonProps, ctx: HostContext) {
|
|
58
58
|
this.id = `${type}-${idCounter++}`
|
|
59
59
|
this.type = type
|
|
60
60
|
this.ctx = ctx
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HostInstance } from "../reconciler/types.js"
|
|
2
2
|
import { BaseHost } from "./base.js"
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -8,10 +8,6 @@ import { BaseHost } from "./base.js"
|
|
|
8
8
|
export abstract class SingleChildHost extends BaseHost {
|
|
9
9
|
private warned = false
|
|
10
10
|
|
|
11
|
-
constructor(type: string, props: CommonProps, ctx: HostContext) {
|
|
12
|
-
super(type, props, ctx)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
protected get child(): HostInstance | null {
|
|
16
12
|
return this.children[0] ?? null
|
|
17
13
|
}
|
package/src/motion/hooks.ts
CHANGED
|
@@ -34,8 +34,11 @@ export function useMotionValue<T>(initial: T): MotionValue<T> {
|
|
|
34
34
|
* If no renderer is passed, it will use the nearest RendererContext (useRenderer()).
|
|
35
35
|
*/
|
|
36
36
|
export function useSpringRenderer(renderer?: { requestRender: () => void }) {
|
|
37
|
-
//
|
|
38
|
-
const
|
|
37
|
+
// Always call useRenderer to satisfy rules of hooks
|
|
38
|
+
const contextRenderer = useRenderer()
|
|
39
|
+
// Prefer explicit renderer; otherwise use context
|
|
40
|
+
const inferred = renderer ?? contextRenderer
|
|
41
|
+
|
|
39
42
|
useEffect(() => {
|
|
40
43
|
if (!inferred) return
|
|
41
44
|
// Store the bound function so we can compare for cleanup
|
|
@@ -139,7 +139,7 @@ export class InlineRenderer implements RendererMode {
|
|
|
139
139
|
|
|
140
140
|
// Clear any extra lines if content shrank
|
|
141
141
|
for (let screenY = rowCount; screenY < this.previousHeight; screenY++) {
|
|
142
|
-
output += palette.sgr(0) + ANSI.line.clear
|
|
142
|
+
output += `${palette.sgr(0) + ANSI.line.clear}\r\n`
|
|
143
143
|
this.printedWidths[screenY] = 0
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -45,7 +45,7 @@ export class StaticContentRenderer {
|
|
|
45
45
|
for (let y = 0; y < staticSize.h; y++) {
|
|
46
46
|
const trimmedWidth = rowContentWidth(staticBuffer, y, frameWidth)
|
|
47
47
|
const line = emitRowWithReset(staticBuffer, this.palette, y, frameWidth, 0, trimmedWidth)
|
|
48
|
-
contentLines += line
|
|
48
|
+
contentLines += `${line}\n`
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// Cache the content for replay on resize
|
package/src/utils/flex-layout.ts
CHANGED
|
@@ -68,9 +68,8 @@ export function measureFlex(
|
|
|
68
68
|
|
|
69
69
|
if (greedyWeight > 0) {
|
|
70
70
|
// Greedy: measure with proportional share of remaining space
|
|
71
|
-
const greedyMain =
|
|
72
|
-
? (remainingForGreedy * greedyWeight) / totalGreedyWeight
|
|
73
|
-
: remainingForGreedy
|
|
71
|
+
const greedyMain =
|
|
72
|
+
totalGreedyWeight > 0 ? (remainingForGreedy * greedyWeight) / totalGreedyWeight : remainingForGreedy
|
|
74
73
|
const childMaxW = axis === "vertical" ? maxCross : greedyMain
|
|
75
74
|
const childMaxH = axis === "vertical" ? greedyMain : maxCross
|
|
76
75
|
const size = child.measure(childMaxW, childMaxH)
|
|
@@ -82,7 +81,7 @@ export function measureFlex(
|
|
|
82
81
|
|
|
83
82
|
// Calculate total main dimension
|
|
84
83
|
// Use actual measured sizes, not the constraint
|
|
85
|
-
|
|
84
|
+
const totalMain = nonGreedyTotal + greedyMeasuredTotal + totalSpacing
|
|
86
85
|
|
|
87
86
|
// Build total size from main/cross dimensions
|
|
88
87
|
const totalW = axis === "vertical" ? maxChildCross : totalMain
|