@gridland/web 0.1.0 → 0.2.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/dist/core.d.ts +42 -3
- package/dist/core.js +217 -41
- package/dist/core.js.map +1 -1
- package/dist/index.d.ts +42 -3
- package/dist/index.js +217 -41
- package/dist/index.js.map +1 -1
- package/dist/next.d.ts +11 -2
- package/dist/next.js +213 -41
- package/dist/next.js.map +1 -1
- package/dist/vite-plugin.js +3 -0
- package/dist/vite-plugin.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -290,7 +290,10 @@ declare class BrowserRenderer {
|
|
|
290
290
|
private isDragOver;
|
|
291
291
|
private cleanupListeners;
|
|
292
292
|
private mouseDownCell;
|
|
293
|
-
|
|
293
|
+
private backgroundColor;
|
|
294
|
+
constructor(canvas: HTMLCanvasElement, cols: number, rows: number, options?: {
|
|
295
|
+
backgroundColor?: string;
|
|
296
|
+
});
|
|
294
297
|
private pixelToCell;
|
|
295
298
|
private setupDomListeners;
|
|
296
299
|
start(): void;
|
|
@@ -315,8 +318,14 @@ interface TUIProps {
|
|
|
315
318
|
fontFamily?: string;
|
|
316
319
|
/** Auto-focus the canvas for keyboard input (default: true) */
|
|
317
320
|
autoFocus?: boolean;
|
|
321
|
+
/** Background color for the canvas (default: transparent) */
|
|
322
|
+
backgroundColor?: string;
|
|
318
323
|
/** Called when the renderer is ready */
|
|
319
324
|
onReady?: (renderer: BrowserRenderer) => void;
|
|
325
|
+
/** Columns to use for SSR headless render (default: 80) */
|
|
326
|
+
fallbackCols?: number;
|
|
327
|
+
/** Rows to use for SSR headless render (default: 24) */
|
|
328
|
+
fallbackRows?: number;
|
|
320
329
|
}
|
|
321
330
|
/**
|
|
322
331
|
* A single React component that renders TUI content to an HTML5 Canvas.
|
|
@@ -333,7 +342,7 @@ interface TUIProps {
|
|
|
333
342
|
*
|
|
334
343
|
* No dynamic imports, no wrapper chains. Just a component.
|
|
335
344
|
*/
|
|
336
|
-
declare function TUI({ children, style, className, fontSize, fontFamily, autoFocus, onReady, }: TUIProps): react_jsx_runtime.JSX.Element;
|
|
345
|
+
declare function TUI({ children, style, className, fontSize, fontFamily, autoFocus, backgroundColor, onReady, fallbackCols, fallbackRows, }: TUIProps): react_jsx_runtime.JSX.Element;
|
|
337
346
|
|
|
338
347
|
interface MountOptions {
|
|
339
348
|
/** Number of columns (auto-calculated from canvas size if omitted) */
|
|
@@ -443,6 +452,7 @@ declare class BrowserTextBufferView {
|
|
|
443
452
|
private _viewportWidth;
|
|
444
453
|
private _viewportHeight;
|
|
445
454
|
private _truncate;
|
|
455
|
+
textAlign: "left" | "center" | "right";
|
|
446
456
|
private _selection;
|
|
447
457
|
private _selectionBg;
|
|
448
458
|
private _selectionFg;
|
|
@@ -540,6 +550,35 @@ interface BrowserContextValue {
|
|
|
540
550
|
declare const BrowserContext: react.Context<BrowserContextValue | null>;
|
|
541
551
|
declare function useBrowserContext(): BrowserContextValue;
|
|
542
552
|
|
|
553
|
+
interface ReadableCharBuffer {
|
|
554
|
+
width: number;
|
|
555
|
+
height: number;
|
|
556
|
+
char: Uint32Array;
|
|
557
|
+
}
|
|
558
|
+
declare function bufferToText(buffer: ReadableCharBuffer): string;
|
|
559
|
+
|
|
560
|
+
declare function setHeadlessRootRenderableClass(cls: any): void;
|
|
561
|
+
interface HeadlessRendererOptions {
|
|
562
|
+
cols: number;
|
|
563
|
+
rows: number;
|
|
564
|
+
}
|
|
565
|
+
declare class HeadlessRenderer {
|
|
566
|
+
buffer: BrowserBuffer;
|
|
567
|
+
renderContext: BrowserRenderContext;
|
|
568
|
+
root: any;
|
|
569
|
+
constructor(options: HeadlessRendererOptions);
|
|
570
|
+
renderOnce(): void;
|
|
571
|
+
toText(): string;
|
|
572
|
+
resize(cols: number, rows: number): void;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
interface HeadlessRoot {
|
|
576
|
+
render(node: ReactNode): void;
|
|
577
|
+
renderToText(node: ReactNode): string;
|
|
578
|
+
unmount(): void;
|
|
579
|
+
}
|
|
580
|
+
declare function createHeadlessRoot(renderer: HeadlessRenderer): HeadlessRoot;
|
|
581
|
+
|
|
543
582
|
/**
|
|
544
583
|
* SSR-safe utilities for @gridland/web.
|
|
545
584
|
* These can be imported in any environment (Node.js, browser, edge).
|
|
@@ -554,4 +593,4 @@ declare function calculateGridSize(widthPx: number, heightPx: number, cellWidth:
|
|
|
554
593
|
rows: number;
|
|
555
594
|
};
|
|
556
595
|
|
|
557
|
-
export { type BorderDrawOptions, BrowserBuffer, BrowserContext, type BrowserContextValue, BrowserRenderContext, BrowserRenderer, type BrowserRoot, BrowserSyntaxStyle, BrowserTextBuffer, BrowserTextBufferView, CanvasPainter, type CanvasPainterOptions, type DroppedFile, type MountOptions, type MountResult, SelectionManager, type StyledTextInput, TUI, type TUIProps, type TextChunk, type VisibleLine, type VisibleLineChunk, type WidthMethod, calculateGridSize, createBrowserRoot, isBrowser, isCanvasSupported, mountGridland, useBrowserContext, useFileDrop, usePaste };
|
|
596
|
+
export { type BorderDrawOptions, BrowserBuffer, BrowserContext, type BrowserContextValue, BrowserRenderContext, BrowserRenderer, type BrowserRoot, BrowserSyntaxStyle, BrowserTextBuffer, BrowserTextBufferView, CanvasPainter, type CanvasPainterOptions, type DroppedFile, HeadlessRenderer, type HeadlessRendererOptions, type HeadlessRoot, type MountOptions, type MountResult, SelectionManager, type StyledTextInput, TUI, type TUIProps, type TextChunk, type VisibleLine, type VisibleLineChunk, type WidthMethod, bufferToText, calculateGridSize, createBrowserRoot, createHeadlessRoot, isBrowser, isCanvasSupported, mountGridland, setHeadlessRootRenderableClass, useBrowserContext, useFileDrop, usePaste };
|
package/dist/index.js
CHANGED
|
@@ -405,6 +405,7 @@ import * as LineNumberRenderable_star from "../../../../opentui/packages/core/sr
|
|
|
405
405
|
import * as Markdown_star from "../../../../opentui/packages/core/src/renderables/Markdown";
|
|
406
406
|
import * as FrameBuffer_star from "../../../../opentui/packages/core/src/renderables/FrameBuffer";
|
|
407
407
|
import * as TextBufferRenderable_star from "../../../../opentui/packages/core/src/renderables/TextBufferRenderable";
|
|
408
|
+
import { TextBufferRenderable } from "../../../../opentui/packages/core/src/renderables/TextBufferRenderable";
|
|
408
409
|
|
|
409
410
|
// src/browser-text-buffer.ts
|
|
410
411
|
var BrowserTextBuffer = class _BrowserTextBuffer {
|
|
@@ -569,6 +570,7 @@ var BrowserTextBufferView = class _BrowserTextBufferView {
|
|
|
569
570
|
_viewportWidth = 0;
|
|
570
571
|
_viewportHeight = 0;
|
|
571
572
|
_truncate = false;
|
|
573
|
+
textAlign = "left";
|
|
572
574
|
_selection = null;
|
|
573
575
|
_selectionBg;
|
|
574
576
|
_selectionFg;
|
|
@@ -653,12 +655,18 @@ var BrowserTextBufferView = class _BrowserTextBufferView {
|
|
|
653
655
|
setViewportSize(width, height) {
|
|
654
656
|
this._viewportWidth = width;
|
|
655
657
|
this._viewportHeight = height;
|
|
658
|
+
if (this._wrapMode !== "none" && width > 0 && this._wrapWidth !== width) {
|
|
659
|
+
this._wrapWidth = width;
|
|
660
|
+
}
|
|
656
661
|
}
|
|
657
662
|
setViewport(x, y, width, height) {
|
|
658
663
|
this._viewportX = x;
|
|
659
664
|
this._viewportY = y;
|
|
660
665
|
this._viewportWidth = width;
|
|
661
666
|
this._viewportHeight = height;
|
|
667
|
+
if (this._wrapMode !== "none" && width > 0 && this._wrapWidth !== width) {
|
|
668
|
+
this._wrapWidth = width;
|
|
669
|
+
}
|
|
662
670
|
}
|
|
663
671
|
setTabIndicator(_indicator) {
|
|
664
672
|
}
|
|
@@ -1000,6 +1008,19 @@ import {
|
|
|
1000
1008
|
createTimeline
|
|
1001
1009
|
} from "../../../../opentui/packages/core/src/animation/Timeline";
|
|
1002
1010
|
import * as Yoga from "yoga-layout";
|
|
1011
|
+
Object.defineProperty(TextBufferRenderable.prototype, "textAlign", {
|
|
1012
|
+
get() {
|
|
1013
|
+
return this.textBufferView?.textAlign ?? "left";
|
|
1014
|
+
},
|
|
1015
|
+
set(value) {
|
|
1016
|
+
if (this.textBufferView) {
|
|
1017
|
+
this.textBufferView.textAlign = value;
|
|
1018
|
+
this.requestRender();
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
enumerable: true,
|
|
1022
|
+
configurable: true
|
|
1023
|
+
});
|
|
1003
1024
|
function resolveRenderLib() {
|
|
1004
1025
|
return null;
|
|
1005
1026
|
}
|
|
@@ -1404,10 +1425,20 @@ var BrowserBuffer = class _BrowserBuffer {
|
|
|
1404
1425
|
if (!view || !view.getVisibleLines) return;
|
|
1405
1426
|
const lines = view.getVisibleLines();
|
|
1406
1427
|
if (!lines) return;
|
|
1428
|
+
const textAlign = view.textAlign;
|
|
1429
|
+
const viewWidth = view._viewportWidth;
|
|
1407
1430
|
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
1408
1431
|
const line = lines[lineIdx];
|
|
1409
1432
|
if (!line) continue;
|
|
1410
1433
|
let curX = x;
|
|
1434
|
+
if (textAlign && textAlign !== "left" && viewWidth) {
|
|
1435
|
+
const lineWidth = line.chunks.reduce((sum, c) => sum + c.text.length, 0);
|
|
1436
|
+
if (textAlign === "center") {
|
|
1437
|
+
curX = x + Math.floor((viewWidth - lineWidth) / 2);
|
|
1438
|
+
} else if (textAlign === "right") {
|
|
1439
|
+
curX = x + viewWidth - lineWidth;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1411
1442
|
for (const chunk of line.chunks) {
|
|
1412
1443
|
const text = chunk.text;
|
|
1413
1444
|
const fgColor = chunk.fg;
|
|
@@ -2150,6 +2181,41 @@ var SelectionManager = class {
|
|
|
2150
2181
|
}
|
|
2151
2182
|
};
|
|
2152
2183
|
|
|
2184
|
+
// src/render-pipeline.ts
|
|
2185
|
+
function executeRenderPipeline(buffer, renderContext, root, deltaTime) {
|
|
2186
|
+
buffer.clear();
|
|
2187
|
+
const lifecyclePasses = renderContext.getLifecyclePasses();
|
|
2188
|
+
for (const renderable of lifecyclePasses) {
|
|
2189
|
+
if (renderable.onLifecyclePass) {
|
|
2190
|
+
renderable.onLifecyclePass();
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
root.calculateLayout();
|
|
2194
|
+
const renderList = [];
|
|
2195
|
+
root.updateLayout(deltaTime, renderList);
|
|
2196
|
+
for (const cmd of renderList) {
|
|
2197
|
+
switch (cmd.action) {
|
|
2198
|
+
case "pushScissorRect":
|
|
2199
|
+
buffer.pushScissorRect(cmd.x, cmd.y, cmd.width, cmd.height);
|
|
2200
|
+
break;
|
|
2201
|
+
case "popScissorRect":
|
|
2202
|
+
buffer.popScissorRect();
|
|
2203
|
+
break;
|
|
2204
|
+
case "pushOpacity":
|
|
2205
|
+
buffer.pushOpacity(cmd.opacity);
|
|
2206
|
+
break;
|
|
2207
|
+
case "popOpacity":
|
|
2208
|
+
buffer.popOpacity();
|
|
2209
|
+
break;
|
|
2210
|
+
case "render":
|
|
2211
|
+
cmd.renderable.render(buffer, deltaTime);
|
|
2212
|
+
break;
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
buffer.clearScissorRects();
|
|
2216
|
+
buffer.clearOpacity();
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2153
2219
|
// src/browser-renderer.ts
|
|
2154
2220
|
var RootRenderableClass = null;
|
|
2155
2221
|
function setRootRenderableClass(cls) {
|
|
@@ -2174,7 +2240,8 @@ var BrowserRenderer = class _BrowserRenderer {
|
|
|
2174
2240
|
isDragOver = false;
|
|
2175
2241
|
cleanupListeners = [];
|
|
2176
2242
|
mouseDownCell = null;
|
|
2177
|
-
|
|
2243
|
+
backgroundColor = null;
|
|
2244
|
+
constructor(canvas, cols, rows, options) {
|
|
2178
2245
|
this.canvas = canvas;
|
|
2179
2246
|
this.cols = cols;
|
|
2180
2247
|
this.rows = rows;
|
|
@@ -2191,6 +2258,7 @@ var BrowserRenderer = class _BrowserRenderer {
|
|
|
2191
2258
|
canvas.style.width = `${cols * this.cellWidth}px`;
|
|
2192
2259
|
canvas.style.height = `${rows * this.cellHeight}px`;
|
|
2193
2260
|
this.ctx2d.scale(dpr, dpr);
|
|
2261
|
+
this.backgroundColor = options?.backgroundColor ?? null;
|
|
2194
2262
|
canvas.style.cursor = "text";
|
|
2195
2263
|
this.buffer = BrowserBuffer.create(cols, rows, "wcwidth");
|
|
2196
2264
|
this.renderContext = new BrowserRenderContext(cols, rows);
|
|
@@ -2337,40 +2405,15 @@ var BrowserRenderer = class _BrowserRenderer {
|
|
|
2337
2405
|
this.lastTime = now;
|
|
2338
2406
|
if (!this.needsRender) return;
|
|
2339
2407
|
this.needsRender = false;
|
|
2340
|
-
this.buffer.
|
|
2341
|
-
const lifecyclePasses = this.renderContext.getLifecyclePasses();
|
|
2342
|
-
for (const renderable of lifecyclePasses) {
|
|
2343
|
-
if (renderable.onLifecyclePass) {
|
|
2344
|
-
renderable.onLifecyclePass();
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
this.root.calculateLayout();
|
|
2348
|
-
const renderList = [];
|
|
2349
|
-
this.root.updateLayout(deltaTime, renderList);
|
|
2350
|
-
for (const cmd of renderList) {
|
|
2351
|
-
switch (cmd.action) {
|
|
2352
|
-
case "pushScissorRect":
|
|
2353
|
-
this.buffer.pushScissorRect(cmd.x, cmd.y, cmd.width, cmd.height);
|
|
2354
|
-
break;
|
|
2355
|
-
case "popScissorRect":
|
|
2356
|
-
this.buffer.popScissorRect();
|
|
2357
|
-
break;
|
|
2358
|
-
case "pushOpacity":
|
|
2359
|
-
this.buffer.pushOpacity(cmd.opacity);
|
|
2360
|
-
break;
|
|
2361
|
-
case "popOpacity":
|
|
2362
|
-
this.buffer.popOpacity();
|
|
2363
|
-
break;
|
|
2364
|
-
case "render":
|
|
2365
|
-
cmd.renderable.render(this.buffer, deltaTime);
|
|
2366
|
-
break;
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
2369
|
-
this.buffer.clearScissorRects();
|
|
2370
|
-
this.buffer.clearOpacity();
|
|
2408
|
+
executeRenderPipeline(this.buffer, this.renderContext, this.root, deltaTime);
|
|
2371
2409
|
const dpr = window.devicePixelRatio || 1;
|
|
2372
2410
|
this.ctx2d.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
2373
|
-
|
|
2411
|
+
if (this.backgroundColor) {
|
|
2412
|
+
this.ctx2d.fillStyle = this.backgroundColor;
|
|
2413
|
+
this.ctx2d.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
2414
|
+
} else {
|
|
2415
|
+
this.ctx2d.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
2416
|
+
}
|
|
2374
2417
|
this.painter.paint(this.ctx2d, this.buffer, this.selection);
|
|
2375
2418
|
};
|
|
2376
2419
|
resize(cols, rows) {
|
|
@@ -2487,13 +2530,14 @@ function useBrowserContext() {
|
|
|
2487
2530
|
// src/create-browser-root.tsx
|
|
2488
2531
|
import { _render } from "../../../opentui/packages/react/src/reconciler/reconciler";
|
|
2489
2532
|
import { AppContext } from "../../../opentui/packages/react/src/components/app";
|
|
2490
|
-
import { ErrorBoundary } from "../../../opentui/packages/react/src/components/error-boundary";
|
|
2533
|
+
import { ErrorBoundary as _ErrorBoundary } from "../../../opentui/packages/react/src/components/error-boundary";
|
|
2491
2534
|
import { jsx } from "react/jsx-runtime";
|
|
2535
|
+
var ErrorBoundary = _ErrorBoundary;
|
|
2492
2536
|
function createBrowserRoot(renderer) {
|
|
2493
2537
|
let unmountFn = null;
|
|
2494
2538
|
return {
|
|
2495
2539
|
render(node) {
|
|
2496
|
-
const element = /* @__PURE__ */ jsx(BrowserContext.Provider, { value: { renderContext: renderer.renderContext }, children: /* @__PURE__ */ jsx(AppContext.Provider, { value: { keyHandler: renderer.renderContext.keyInput, renderer:
|
|
2540
|
+
const element = /* @__PURE__ */ jsx(BrowserContext.Provider, { value: { renderContext: renderer.renderContext }, children: /* @__PURE__ */ jsx(AppContext.Provider, { value: { keyHandler: renderer.renderContext.keyInput, renderer: renderer.renderContext }, children: /* @__PURE__ */ jsx(ErrorBoundary, { children: node }) }) });
|
|
2497
2541
|
unmountFn = _render(element, renderer.root);
|
|
2498
2542
|
},
|
|
2499
2543
|
unmount() {
|
|
@@ -2505,7 +2549,105 @@ function createBrowserRoot(renderer) {
|
|
|
2505
2549
|
|
|
2506
2550
|
// src/TUI.tsx
|
|
2507
2551
|
import { RootRenderable as RootRenderable2 } from "@opentui/core";
|
|
2552
|
+
|
|
2553
|
+
// src/buffer-to-text.ts
|
|
2554
|
+
function bufferToText(buffer) {
|
|
2555
|
+
const lines = [];
|
|
2556
|
+
for (let row = 0; row < buffer.height; row++) {
|
|
2557
|
+
let line = "";
|
|
2558
|
+
for (let col = 0; col < buffer.width; col++) {
|
|
2559
|
+
const idx = row * buffer.width + col;
|
|
2560
|
+
const charCode = buffer.char[idx];
|
|
2561
|
+
line += charCode === 0 ? " " : String.fromCodePoint(charCode);
|
|
2562
|
+
}
|
|
2563
|
+
lines.push(line.trimEnd());
|
|
2564
|
+
}
|
|
2565
|
+
while (lines.length > 0 && lines[lines.length - 1] === "") {
|
|
2566
|
+
lines.pop();
|
|
2567
|
+
}
|
|
2568
|
+
return lines.join("\n");
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
// src/headless-renderer.ts
|
|
2572
|
+
var RootRenderableClass2 = null;
|
|
2573
|
+
function setHeadlessRootRenderableClass(cls) {
|
|
2574
|
+
RootRenderableClass2 = cls;
|
|
2575
|
+
}
|
|
2576
|
+
var HeadlessRenderer = class {
|
|
2577
|
+
buffer;
|
|
2578
|
+
renderContext;
|
|
2579
|
+
root;
|
|
2580
|
+
// RootRenderable
|
|
2581
|
+
constructor(options) {
|
|
2582
|
+
const { cols, rows } = options;
|
|
2583
|
+
this.buffer = BrowserBuffer.create(cols, rows, "wcwidth");
|
|
2584
|
+
this.renderContext = new BrowserRenderContext(cols, rows);
|
|
2585
|
+
this.renderContext.setOnRenderRequest(() => {
|
|
2586
|
+
});
|
|
2587
|
+
if (!RootRenderableClass2) {
|
|
2588
|
+
throw new Error(
|
|
2589
|
+
"RootRenderableClass not set. Call setHeadlessRootRenderableClass before creating HeadlessRenderer."
|
|
2590
|
+
);
|
|
2591
|
+
}
|
|
2592
|
+
this.root = new RootRenderableClass2(this.renderContext);
|
|
2593
|
+
}
|
|
2594
|
+
renderOnce() {
|
|
2595
|
+
executeRenderPipeline(this.buffer, this.renderContext, this.root, 0);
|
|
2596
|
+
}
|
|
2597
|
+
toText() {
|
|
2598
|
+
return bufferToText(this.buffer);
|
|
2599
|
+
}
|
|
2600
|
+
resize(cols, rows) {
|
|
2601
|
+
this.buffer.resize(cols, rows);
|
|
2602
|
+
this.renderContext.resize(cols, rows);
|
|
2603
|
+
this.root.resize(cols, rows);
|
|
2604
|
+
}
|
|
2605
|
+
};
|
|
2606
|
+
|
|
2607
|
+
// src/create-headless-root.tsx
|
|
2608
|
+
import { _render as _render2, reconciler } from "../../../opentui/packages/react/src/reconciler/reconciler";
|
|
2609
|
+
import { AppContext as AppContext2 } from "../../../opentui/packages/react/src/components/app";
|
|
2610
|
+
import { ErrorBoundary as _ErrorBoundary2 } from "../../../opentui/packages/react/src/components/error-boundary";
|
|
2508
2611
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
2612
|
+
var ErrorBoundary2 = _ErrorBoundary2;
|
|
2613
|
+
var _r = reconciler;
|
|
2614
|
+
var flushSync = _r.flushSyncFromReconciler ?? _r.flushSync;
|
|
2615
|
+
function createHeadlessRoot(renderer) {
|
|
2616
|
+
let container = null;
|
|
2617
|
+
return {
|
|
2618
|
+
render(node) {
|
|
2619
|
+
const element = /* @__PURE__ */ jsx2(BrowserContext.Provider, { value: { renderContext: renderer.renderContext }, children: /* @__PURE__ */ jsx2(
|
|
2620
|
+
AppContext2.Provider,
|
|
2621
|
+
{
|
|
2622
|
+
value: {
|
|
2623
|
+
keyHandler: renderer.renderContext.keyInput,
|
|
2624
|
+
renderer: renderer.renderContext
|
|
2625
|
+
},
|
|
2626
|
+
children: /* @__PURE__ */ jsx2(ErrorBoundary2, { children: node })
|
|
2627
|
+
}
|
|
2628
|
+
) });
|
|
2629
|
+
container = _render2(element, renderer.root);
|
|
2630
|
+
},
|
|
2631
|
+
renderToText(node) {
|
|
2632
|
+
flushSync(() => {
|
|
2633
|
+
this.render(node);
|
|
2634
|
+
});
|
|
2635
|
+
renderer.renderOnce();
|
|
2636
|
+
return renderer.toText();
|
|
2637
|
+
},
|
|
2638
|
+
unmount() {
|
|
2639
|
+
if (container) {
|
|
2640
|
+
reconciler.updateContainer(null, container, null, () => {
|
|
2641
|
+
});
|
|
2642
|
+
reconciler.flushSyncWork();
|
|
2643
|
+
container = null;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
// src/TUI.tsx
|
|
2650
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
2509
2651
|
function TUI({
|
|
2510
2652
|
children,
|
|
2511
2653
|
style,
|
|
@@ -2513,7 +2655,10 @@ function TUI({
|
|
|
2513
2655
|
fontSize = 14,
|
|
2514
2656
|
fontFamily = "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace",
|
|
2515
2657
|
autoFocus = true,
|
|
2516
|
-
|
|
2658
|
+
backgroundColor,
|
|
2659
|
+
onReady,
|
|
2660
|
+
fallbackCols = 80,
|
|
2661
|
+
fallbackRows = 24
|
|
2517
2662
|
}) {
|
|
2518
2663
|
const containerRef = useRef(null);
|
|
2519
2664
|
const canvasRef = useRef(null);
|
|
@@ -2535,7 +2680,7 @@ function TUI({
|
|
|
2535
2680
|
const containerRect = container.getBoundingClientRect();
|
|
2536
2681
|
const cols = Math.max(1, Math.floor(containerRect.width / cellSize.width));
|
|
2537
2682
|
const rows = Math.max(1, Math.floor(containerRect.height / cellSize.height));
|
|
2538
|
-
const renderer = new BrowserRenderer(canvas, cols, rows);
|
|
2683
|
+
const renderer = new BrowserRenderer(canvas, cols, rows, { backgroundColor });
|
|
2539
2684
|
rendererRef.current = renderer;
|
|
2540
2685
|
const root = createBrowserRoot(renderer);
|
|
2541
2686
|
rootRef.current = root;
|
|
@@ -2567,16 +2712,43 @@ function TUI({
|
|
|
2567
2712
|
rendererRef.current = null;
|
|
2568
2713
|
rootRef.current = null;
|
|
2569
2714
|
};
|
|
2570
|
-
}, [isClient, fontSize, fontFamily]);
|
|
2715
|
+
}, [isClient, fontSize, fontFamily, backgroundColor]);
|
|
2571
2716
|
useEffect(() => {
|
|
2572
2717
|
if (rootRef.current) {
|
|
2573
2718
|
rootRef.current.render(children);
|
|
2574
2719
|
}
|
|
2575
2720
|
}, [children]);
|
|
2576
2721
|
if (!isClient) {
|
|
2577
|
-
|
|
2722
|
+
const isServer = typeof window === "undefined";
|
|
2723
|
+
let text = "";
|
|
2724
|
+
if (isServer) {
|
|
2725
|
+
setHeadlessRootRenderableClass(RootRenderable2);
|
|
2726
|
+
const renderer = new HeadlessRenderer({ cols: fallbackCols, rows: fallbackRows });
|
|
2727
|
+
const root = createHeadlessRoot(renderer);
|
|
2728
|
+
text = root.renderToText(children);
|
|
2729
|
+
root.unmount();
|
|
2730
|
+
}
|
|
2731
|
+
return /* @__PURE__ */ jsx3("div", { style, className, children: /* @__PURE__ */ jsx3(
|
|
2732
|
+
"pre",
|
|
2733
|
+
{
|
|
2734
|
+
suppressHydrationWarning: true,
|
|
2735
|
+
"aria-hidden": true,
|
|
2736
|
+
style: {
|
|
2737
|
+
fontFamily,
|
|
2738
|
+
fontSize,
|
|
2739
|
+
margin: 0,
|
|
2740
|
+
position: "absolute",
|
|
2741
|
+
width: "1px",
|
|
2742
|
+
height: "1px",
|
|
2743
|
+
overflow: "hidden",
|
|
2744
|
+
clip: "rect(0, 0, 0, 0)",
|
|
2745
|
+
whiteSpace: "pre"
|
|
2746
|
+
},
|
|
2747
|
+
children: text
|
|
2748
|
+
}
|
|
2749
|
+
) });
|
|
2578
2750
|
}
|
|
2579
|
-
return /* @__PURE__ */
|
|
2751
|
+
return /* @__PURE__ */ jsx3(
|
|
2580
2752
|
"div",
|
|
2581
2753
|
{
|
|
2582
2754
|
ref: containerRef,
|
|
@@ -2586,7 +2758,7 @@ function TUI({
|
|
|
2586
2758
|
...style
|
|
2587
2759
|
},
|
|
2588
2760
|
className,
|
|
2589
|
-
children: /* @__PURE__ */
|
|
2761
|
+
children: /* @__PURE__ */ jsx3(
|
|
2590
2762
|
"canvas",
|
|
2591
2763
|
{
|
|
2592
2764
|
ref: canvasRef,
|
|
@@ -2723,13 +2895,17 @@ export {
|
|
|
2723
2895
|
BrowserTextBuffer,
|
|
2724
2896
|
BrowserTextBufferView,
|
|
2725
2897
|
CanvasPainter,
|
|
2898
|
+
HeadlessRenderer,
|
|
2726
2899
|
SelectionManager,
|
|
2727
2900
|
TUI,
|
|
2901
|
+
bufferToText,
|
|
2728
2902
|
calculateGridSize,
|
|
2729
2903
|
createBrowserRoot,
|
|
2904
|
+
createHeadlessRoot,
|
|
2730
2905
|
isBrowser,
|
|
2731
2906
|
isCanvasSupported,
|
|
2732
2907
|
mountGridland,
|
|
2908
|
+
setHeadlessRootRenderableClass,
|
|
2733
2909
|
useBrowserContext,
|
|
2734
2910
|
useFileDrop,
|
|
2735
2911
|
usePaste
|