@gridland/web 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/dist/next.js ADDED
@@ -0,0 +1,2596 @@
1
+ "use client";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+
21
+ // src/TUI.tsx
22
+ import {
23
+ useRef,
24
+ useEffect,
25
+ useState
26
+ } from "react";
27
+
28
+ // src/core-shims/index.ts
29
+ var core_shims_exports = {};
30
+ __export(core_shims_exports, {
31
+ ATTRIBUTE_BASE_BITS: () => ATTRIBUTE_BASE_BITS,
32
+ ATTRIBUTE_BASE_MASK: () => ATTRIBUTE_BASE_MASK,
33
+ BaseRenderable: () => BaseRenderable,
34
+ BorderCharArrays: () => BorderCharArrays,
35
+ BorderChars: () => BorderChars,
36
+ CliRenderEvents: () => CliRenderEvents,
37
+ CliRenderer: () => CliRenderer,
38
+ DebugOverlayCorner: () => DebugOverlayCorner,
39
+ InternalKeyHandler: () => BrowserInternalKeyHandler,
40
+ KeyHandler: () => BrowserKeyHandler,
41
+ LayoutEvents: () => LayoutEvents,
42
+ OptimizedBuffer: () => BrowserBuffer,
43
+ RGBA: () => RGBA,
44
+ Renderable: () => Renderable,
45
+ RenderableEvents: () => RenderableEvents,
46
+ RootRenderable: () => RootRenderable,
47
+ Selection: () => Selection,
48
+ StyledText: () => StyledText,
49
+ SyntaxStyle: () => BrowserSyntaxStyle,
50
+ TextAttributes: () => TextAttributes,
51
+ TextBuffer: () => BrowserTextBuffer,
52
+ TextBufferView: () => BrowserTextBufferView,
53
+ Timeline: () => Timeline,
54
+ Yoga: () => Yoga,
55
+ attributesWithLink: () => attributesWithLink,
56
+ bg: () => bg,
57
+ black: () => black,
58
+ blink: () => blink,
59
+ blue: () => blue,
60
+ bold: () => bold,
61
+ borderCharsToArray: () => borderCharsToArray,
62
+ convertGlobalToLocalSelection: () => convertGlobalToLocalSelection,
63
+ createCliRenderer: () => createCliRenderer,
64
+ createTextAttributes: () => createTextAttributes,
65
+ createTimeline: () => createTimeline,
66
+ cyan: () => cyan,
67
+ dim: () => dim,
68
+ engine: () => engine,
69
+ fg: () => fg,
70
+ getBaseAttributes: () => getBaseAttributes,
71
+ getBorderFromSides: () => getBorderFromSides,
72
+ getBorderSides: () => getBorderSides,
73
+ getLinkId: () => getLinkId,
74
+ green: () => green,
75
+ hexToRgb: () => hexToRgb,
76
+ hsvToRgb: () => hsvToRgb,
77
+ isDimensionType: () => isDimensionType,
78
+ isFlexBasisType: () => isFlexBasisType,
79
+ isMarginType: () => isMarginType,
80
+ isOverflowType: () => isOverflowType,
81
+ isPaddingType: () => isPaddingType,
82
+ isPositionType: () => isPositionType,
83
+ isPositionTypeType: () => isPositionTypeType,
84
+ isRenderable: () => isRenderable,
85
+ isSizeType: () => isSizeType,
86
+ isStyledText: () => isStyledText,
87
+ isValidBorderStyle: () => isValidBorderStyle,
88
+ italic: () => italic,
89
+ magenta: () => magenta,
90
+ maybeMakeRenderable: () => maybeMakeRenderable,
91
+ parseAlign: () => parseAlign,
92
+ parseAlignItems: () => parseAlignItems,
93
+ parseBorderStyle: () => parseBorderStyle,
94
+ parseColor: () => parseColor,
95
+ parseFlexDirection: () => parseFlexDirection,
96
+ parseJustify: () => parseJustify,
97
+ parseOverflow: () => parseOverflow,
98
+ parsePositionType: () => parsePositionType,
99
+ parseWrap: () => parseWrap,
100
+ red: () => red,
101
+ resolveRenderLib: () => resolveRenderLib,
102
+ reverse: () => reverse,
103
+ rgbToHex: () => rgbToHex,
104
+ strikethrough: () => strikethrough,
105
+ stringToStyledText: () => stringToStyledText,
106
+ t: () => t,
107
+ underline: () => underline,
108
+ validateOptions: () => validateOptions,
109
+ visualizeRenderableTree: () => visualizeRenderableTree,
110
+ white: () => white,
111
+ yellow: () => yellow
112
+ });
113
+
114
+ // src/core-shims/rgba.ts
115
+ var RGBA = class _RGBA {
116
+ buffer;
117
+ constructor(buffer) {
118
+ this.buffer = buffer;
119
+ }
120
+ static fromArray(array) {
121
+ return new _RGBA(array);
122
+ }
123
+ static fromValues(r, g, b, a = 1) {
124
+ return new _RGBA(new Float32Array([r, g, b, a]));
125
+ }
126
+ static fromInts(r, g, b, a = 255) {
127
+ return new _RGBA(new Float32Array([r / 255, g / 255, b / 255, a / 255]));
128
+ }
129
+ static fromHex(hex) {
130
+ return hexToRgb(hex);
131
+ }
132
+ get r() {
133
+ return this.buffer[0];
134
+ }
135
+ set r(v) {
136
+ this.buffer[0] = v;
137
+ }
138
+ get g() {
139
+ return this.buffer[1];
140
+ }
141
+ set g(v) {
142
+ this.buffer[1] = v;
143
+ }
144
+ get b() {
145
+ return this.buffer[2];
146
+ }
147
+ set b(v) {
148
+ this.buffer[2] = v;
149
+ }
150
+ get a() {
151
+ return this.buffer[3];
152
+ }
153
+ set a(v) {
154
+ this.buffer[3] = v;
155
+ }
156
+ toInts() {
157
+ return [
158
+ Math.round(this.buffer[0] * 255),
159
+ Math.round(this.buffer[1] * 255),
160
+ Math.round(this.buffer[2] * 255),
161
+ Math.round(this.buffer[3] * 255)
162
+ ];
163
+ }
164
+ map(fn) {
165
+ return [fn(this.buffer[0]), fn(this.buffer[1]), fn(this.buffer[2]), fn(this.buffer[3])];
166
+ }
167
+ toString() {
168
+ const [r, g, b, a] = this.toInts();
169
+ return `rgba(${r}, ${g}, ${b}, ${a / 255})`;
170
+ }
171
+ equals(other) {
172
+ if (!other) return false;
173
+ return this.buffer[0] === other.buffer[0] && this.buffer[1] === other.buffer[1] && this.buffer[2] === other.buffer[2] && this.buffer[3] === other.buffer[3];
174
+ }
175
+ };
176
+ var CSS_COLOR_NAMES = {
177
+ black: "#000000",
178
+ white: "#ffffff",
179
+ red: "#ff0000",
180
+ green: "#008000",
181
+ blue: "#0000ff",
182
+ yellow: "#ffff00",
183
+ cyan: "#00ffff",
184
+ magenta: "#ff00ff",
185
+ silver: "#c0c0c0",
186
+ gray: "#808080",
187
+ grey: "#808080",
188
+ maroon: "#800000",
189
+ olive: "#808000",
190
+ lime: "#00ff00",
191
+ aqua: "#00ffff",
192
+ teal: "#008080",
193
+ navy: "#000080",
194
+ fuchsia: "#ff00ff",
195
+ purple: "#800080",
196
+ orange: "#ffa500",
197
+ transparent: "#00000000",
198
+ brightblack: "#808080",
199
+ brightred: "#ff5555",
200
+ brightgreen: "#55ff55",
201
+ brightyellow: "#ffff55",
202
+ brightblue: "#5555ff",
203
+ brightmagenta: "#ff55ff",
204
+ brightcyan: "#55ffff",
205
+ brightwhite: "#ffffff"
206
+ };
207
+ function hexToRgb(hex) {
208
+ hex = hex.replace(/^#/, "");
209
+ if (hex.length === 3) {
210
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
211
+ }
212
+ if (hex.length === 6) {
213
+ hex = hex + "ff";
214
+ }
215
+ const r = parseInt(hex.substring(0, 2), 16) / 255;
216
+ const g = parseInt(hex.substring(2, 4), 16) / 255;
217
+ const b = parseInt(hex.substring(4, 6), 16) / 255;
218
+ const a = parseInt(hex.substring(6, 8), 16) / 255;
219
+ return RGBA.fromValues(r, g, b, a);
220
+ }
221
+ function rgbToHex(rgb) {
222
+ const [r, g, b] = rgb.toInts();
223
+ return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
224
+ }
225
+ function hsvToRgb(h, s, v) {
226
+ const c = v * s;
227
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
228
+ const m = v - c;
229
+ let r = 0, g = 0, b = 0;
230
+ if (h < 60) {
231
+ r = c;
232
+ g = x;
233
+ b = 0;
234
+ } else if (h < 120) {
235
+ r = x;
236
+ g = c;
237
+ b = 0;
238
+ } else if (h < 180) {
239
+ r = 0;
240
+ g = c;
241
+ b = x;
242
+ } else if (h < 240) {
243
+ r = 0;
244
+ g = x;
245
+ b = c;
246
+ } else if (h < 300) {
247
+ r = x;
248
+ g = 0;
249
+ b = c;
250
+ } else {
251
+ r = c;
252
+ g = 0;
253
+ b = x;
254
+ }
255
+ return RGBA.fromValues(r + m, g + m, b + m, 1);
256
+ }
257
+ function parseColor(color) {
258
+ if (color instanceof RGBA) return color;
259
+ if (typeof color !== "string") return RGBA.fromValues(1, 1, 1, 1);
260
+ const lower = color.toLowerCase().trim();
261
+ if (CSS_COLOR_NAMES[lower]) {
262
+ return hexToRgb(CSS_COLOR_NAMES[lower]);
263
+ }
264
+ if (lower.startsWith("#")) {
265
+ return hexToRgb(lower);
266
+ }
267
+ const rgbaMatch = lower.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/);
268
+ if (rgbaMatch) {
269
+ return RGBA.fromInts(
270
+ parseInt(rgbaMatch[1]),
271
+ parseInt(rgbaMatch[2]),
272
+ parseInt(rgbaMatch[3]),
273
+ rgbaMatch[4] ? Math.round(parseFloat(rgbaMatch[4]) * 255) : 255
274
+ );
275
+ }
276
+ return RGBA.fromValues(1, 1, 1, 1);
277
+ }
278
+
279
+ // src/core-shims/types.ts
280
+ var TextAttributes = {
281
+ NONE: 0,
282
+ BOLD: 1 << 0,
283
+ DIM: 1 << 1,
284
+ ITALIC: 1 << 2,
285
+ UNDERLINE: 1 << 3,
286
+ BLINK: 1 << 4,
287
+ INVERSE: 1 << 5,
288
+ HIDDEN: 1 << 6,
289
+ STRIKETHROUGH: 1 << 7
290
+ };
291
+ var ATTRIBUTE_BASE_BITS = 8;
292
+ var ATTRIBUTE_BASE_MASK = 255;
293
+ function getBaseAttributes(attr) {
294
+ return attr & 255;
295
+ }
296
+ var DebugOverlayCorner = /* @__PURE__ */ ((DebugOverlayCorner2) => {
297
+ DebugOverlayCorner2[DebugOverlayCorner2["topLeft"] = 0] = "topLeft";
298
+ DebugOverlayCorner2[DebugOverlayCorner2["topRight"] = 1] = "topRight";
299
+ DebugOverlayCorner2[DebugOverlayCorner2["bottomLeft"] = 2] = "bottomLeft";
300
+ DebugOverlayCorner2[DebugOverlayCorner2["bottomRight"] = 3] = "bottomRight";
301
+ return DebugOverlayCorner2;
302
+ })(DebugOverlayCorner || {});
303
+
304
+ // src/core-shims/index.ts
305
+ __reExport(core_shims_exports, Box_star);
306
+ __reExport(core_shims_exports, Text_star);
307
+ __reExport(core_shims_exports, TextNode_star);
308
+ __reExport(core_shims_exports, Code_star);
309
+ __reExport(core_shims_exports, Diff_star);
310
+ __reExport(core_shims_exports, Input_star);
311
+ __reExport(core_shims_exports, Select_star);
312
+ __reExport(core_shims_exports, TabSelect_star);
313
+ __reExport(core_shims_exports, Textarea_star);
314
+ __reExport(core_shims_exports, ScrollBox_star);
315
+ __reExport(core_shims_exports, ScrollBar_star);
316
+ __reExport(core_shims_exports, Slider_star);
317
+ __reExport(core_shims_exports, ASCIIFont_star);
318
+ __reExport(core_shims_exports, LineNumberRenderable_star);
319
+ __reExport(core_shims_exports, Markdown_star);
320
+ __reExport(core_shims_exports, FrameBuffer_star);
321
+ __reExport(core_shims_exports, TextBufferRenderable_star);
322
+ import {
323
+ Renderable,
324
+ BaseRenderable,
325
+ RootRenderable,
326
+ LayoutEvents,
327
+ RenderableEvents,
328
+ isRenderable
329
+ } from "../../../../opentui/packages/core/src/Renderable";
330
+ import {
331
+ BorderChars,
332
+ BorderCharArrays,
333
+ isValidBorderStyle,
334
+ parseBorderStyle,
335
+ getBorderFromSides,
336
+ getBorderSides,
337
+ borderCharsToArray
338
+ } from "../../../../opentui/packages/core/src/lib/border";
339
+ import {
340
+ StyledText,
341
+ isStyledText,
342
+ stringToStyledText,
343
+ t,
344
+ bold,
345
+ italic,
346
+ underline,
347
+ strikethrough,
348
+ dim,
349
+ reverse,
350
+ blink,
351
+ fg,
352
+ bg,
353
+ black,
354
+ red,
355
+ green,
356
+ yellow,
357
+ blue,
358
+ magenta,
359
+ cyan,
360
+ white
361
+ } from "../../../../opentui/packages/core/src/lib/styled-text";
362
+ import {
363
+ parseAlign,
364
+ parseAlignItems,
365
+ parseFlexDirection,
366
+ parseJustify,
367
+ parseOverflow,
368
+ parsePositionType,
369
+ parseWrap
370
+ } from "../../../../opentui/packages/core/src/lib/yoga.options";
371
+ import {
372
+ validateOptions,
373
+ isPositionType,
374
+ isDimensionType,
375
+ isFlexBasisType,
376
+ isSizeType,
377
+ isMarginType,
378
+ isPaddingType,
379
+ isPositionTypeType,
380
+ isOverflowType
381
+ } from "../../../../opentui/packages/core/src/lib/renderable.validations";
382
+ import {
383
+ Selection,
384
+ convertGlobalToLocalSelection
385
+ } from "../../../../opentui/packages/core/src/lib/selection";
386
+ import { maybeMakeRenderable } from "../../../../opentui/packages/core/src/renderables/composition/vnode";
387
+ import * as Box_star from "../../../../opentui/packages/core/src/renderables/Box";
388
+ import * as Text_star from "../../../../opentui/packages/core/src/renderables/Text";
389
+ import * as TextNode_star from "../../../../opentui/packages/core/src/renderables/TextNode";
390
+ import * as Code_star from "../../../../opentui/packages/core/src/renderables/Code";
391
+ import * as Diff_star from "../../../../opentui/packages/core/src/renderables/Diff";
392
+ import * as Input_star from "../../../../opentui/packages/core/src/renderables/Input";
393
+ import * as Select_star from "../../../../opentui/packages/core/src/renderables/Select";
394
+ import * as TabSelect_star from "../../../../opentui/packages/core/src/renderables/TabSelect";
395
+ import * as Textarea_star from "../../../../opentui/packages/core/src/renderables/Textarea";
396
+ import * as ScrollBox_star from "../../../../opentui/packages/core/src/renderables/ScrollBox";
397
+ import * as ScrollBar_star from "../../../../opentui/packages/core/src/renderables/ScrollBar";
398
+ import * as Slider_star from "../../../../opentui/packages/core/src/renderables/Slider";
399
+ import * as ASCIIFont_star from "../../../../opentui/packages/core/src/renderables/ASCIIFont";
400
+ import * as LineNumberRenderable_star from "../../../../opentui/packages/core/src/renderables/LineNumberRenderable";
401
+ import * as Markdown_star from "../../../../opentui/packages/core/src/renderables/Markdown";
402
+ import * as FrameBuffer_star from "../../../../opentui/packages/core/src/renderables/FrameBuffer";
403
+ import * as TextBufferRenderable_star from "../../../../opentui/packages/core/src/renderables/TextBufferRenderable";
404
+
405
+ // src/browser-text-buffer.ts
406
+ var BrowserTextBuffer = class _BrowserTextBuffer {
407
+ _text = "";
408
+ _chunks = [];
409
+ _defaultFg = null;
410
+ _defaultBg = null;
411
+ _defaultAttributes = 0;
412
+ _syntaxStyle = null;
413
+ _tabWidth = 4;
414
+ _widthMethod;
415
+ constructor(widthMethod) {
416
+ this._widthMethod = widthMethod;
417
+ }
418
+ static create(widthMethod) {
419
+ return new _BrowserTextBuffer(widthMethod);
420
+ }
421
+ // Compat property
422
+ get ptr() {
423
+ return 1;
424
+ }
425
+ get length() {
426
+ return this._text.length;
427
+ }
428
+ get byteSize() {
429
+ return new TextEncoder().encode(this._text).length;
430
+ }
431
+ setText(text) {
432
+ this._text = text;
433
+ this._chunks = [
434
+ {
435
+ __isChunk: true,
436
+ text,
437
+ fg: this._defaultFg ?? void 0,
438
+ bg: this._defaultBg ?? void 0,
439
+ attributes: this._defaultAttributes
440
+ }
441
+ ];
442
+ }
443
+ append(text) {
444
+ this._text += text;
445
+ this._chunks.push({
446
+ __isChunk: true,
447
+ text,
448
+ fg: this._defaultFg ?? void 0,
449
+ bg: this._defaultBg ?? void 0,
450
+ attributes: this._defaultAttributes
451
+ });
452
+ }
453
+ setStyledText(styledText) {
454
+ this._chunks = styledText.chunks.map((chunk) => ({
455
+ __isChunk: true,
456
+ text: chunk.text,
457
+ fg: chunk.fg ?? this._defaultFg ?? void 0,
458
+ bg: chunk.bg ?? this._defaultBg ?? void 0,
459
+ attributes: chunk.attributes ?? this._defaultAttributes,
460
+ link: chunk.link
461
+ }));
462
+ this._text = this._chunks.map((c) => c.text).join("");
463
+ }
464
+ getPlainText() {
465
+ return this._text;
466
+ }
467
+ getTextRange(startOffset, endOffset) {
468
+ return this._text.slice(startOffset, endOffset);
469
+ }
470
+ getLineCount() {
471
+ if (this._text.length === 0) return 0;
472
+ return this._text.split("\n").length;
473
+ }
474
+ getChunks() {
475
+ return this._chunks;
476
+ }
477
+ setDefaultFg(fg2) {
478
+ this._defaultFg = fg2;
479
+ }
480
+ setDefaultBg(bg2) {
481
+ this._defaultBg = bg2;
482
+ }
483
+ setDefaultAttributes(attributes) {
484
+ this._defaultAttributes = attributes ?? 0;
485
+ }
486
+ resetDefaults() {
487
+ this._defaultFg = null;
488
+ this._defaultBg = null;
489
+ this._defaultAttributes = 0;
490
+ }
491
+ get defaultFg() {
492
+ return this._defaultFg;
493
+ }
494
+ get defaultBg() {
495
+ return this._defaultBg;
496
+ }
497
+ get defaultAttributes() {
498
+ return this._defaultAttributes;
499
+ }
500
+ setSyntaxStyle(style) {
501
+ this._syntaxStyle = style;
502
+ }
503
+ getSyntaxStyle() {
504
+ return this._syntaxStyle;
505
+ }
506
+ setTabWidth(width) {
507
+ this._tabWidth = width;
508
+ }
509
+ getTabWidth() {
510
+ return this._tabWidth;
511
+ }
512
+ addHighlightByCharRange(_highlight) {
513
+ }
514
+ addHighlight(_lineIdx, _highlight) {
515
+ }
516
+ removeHighlightsByRef(_hlRef) {
517
+ }
518
+ clearLineHighlights(_lineIdx) {
519
+ }
520
+ clearAllHighlights() {
521
+ }
522
+ getLineHighlights(_lineIdx) {
523
+ return [];
524
+ }
525
+ getHighlightCount() {
526
+ return 0;
527
+ }
528
+ loadFile(_path) {
529
+ }
530
+ clear() {
531
+ this._text = "";
532
+ this._chunks = [];
533
+ }
534
+ reset() {
535
+ this.clear();
536
+ this.resetDefaults();
537
+ }
538
+ destroy() {
539
+ this._text = "";
540
+ this._chunks = [];
541
+ }
542
+ };
543
+
544
+ // src/browser-text-buffer-view.ts
545
+ var defaultFg = {
546
+ r: 1,
547
+ g: 1,
548
+ b: 1,
549
+ a: 1,
550
+ buffer: new Float32Array([1, 1, 1, 1])
551
+ };
552
+ var defaultBg = {
553
+ r: 0,
554
+ g: 0,
555
+ b: 0,
556
+ a: 0,
557
+ buffer: new Float32Array([0, 0, 0, 0])
558
+ };
559
+ var BrowserTextBufferView = class _BrowserTextBufferView {
560
+ textBuffer;
561
+ _wrapWidth = null;
562
+ _wrapMode = "word";
563
+ _viewportX = 0;
564
+ _viewportY = 0;
565
+ _viewportWidth = 0;
566
+ _viewportHeight = 0;
567
+ _truncate = false;
568
+ _selection = null;
569
+ _selectionBg;
570
+ _selectionFg;
571
+ constructor(textBuffer) {
572
+ this.textBuffer = textBuffer;
573
+ }
574
+ static create(textBuffer) {
575
+ return new _BrowserTextBufferView(textBuffer);
576
+ }
577
+ // Compat
578
+ get ptr() {
579
+ return 1;
580
+ }
581
+ get lineInfo() {
582
+ const lines = this.getAllWrappedLines();
583
+ const lineStarts = [];
584
+ const lineWidths = [];
585
+ const lineSources = [];
586
+ const lineWraps = [];
587
+ let maxWidth = 0;
588
+ let offset = 0;
589
+ for (let i = 0; i < lines.length; i++) {
590
+ lineStarts.push(offset);
591
+ const lineText = lines[i].map((c) => c.text).join("");
592
+ const w = lineText.length;
593
+ lineWidths.push(w);
594
+ lineSources.push(0);
595
+ lineWraps.push(0);
596
+ if (w > maxWidth) maxWidth = w;
597
+ offset += lineText.length + 1;
598
+ }
599
+ return { lineStarts, lineWidths, maxLineWidth: maxWidth, lineSources, lineWraps };
600
+ }
601
+ get logicalLineInfo() {
602
+ return this.lineInfo;
603
+ }
604
+ setSelection(start, end, bgColor, fgColor) {
605
+ this._selection = { start, end };
606
+ this._selectionBg = bgColor;
607
+ this._selectionFg = fgColor;
608
+ }
609
+ updateSelection(end, bgColor, fgColor) {
610
+ if (this._selection) {
611
+ this._selection.end = end;
612
+ }
613
+ if (bgColor) this._selectionBg = bgColor;
614
+ if (fgColor) this._selectionFg = fgColor;
615
+ }
616
+ resetSelection() {
617
+ this._selection = null;
618
+ }
619
+ getSelection() {
620
+ return this._selection;
621
+ }
622
+ hasSelection() {
623
+ return this._selection !== null;
624
+ }
625
+ setLocalSelection(_anchorX, _anchorY, _focusX, _focusY, _bgColor, _fgColor) {
626
+ return false;
627
+ }
628
+ updateLocalSelection(_anchorX, _anchorY, _focusX, _focusY, _bgColor, _fgColor) {
629
+ return false;
630
+ }
631
+ resetLocalSelection() {
632
+ }
633
+ getSelectedText() {
634
+ if (!this._selection) return "";
635
+ const text = this.textBuffer.getPlainText();
636
+ const start = Math.min(this._selection.start, this._selection.end);
637
+ const end = Math.max(this._selection.start, this._selection.end);
638
+ return text.slice(start, end);
639
+ }
640
+ getPlainText() {
641
+ return this.textBuffer.getPlainText();
642
+ }
643
+ setWrapWidth(width) {
644
+ this._wrapWidth = width;
645
+ }
646
+ setWrapMode(mode) {
647
+ this._wrapMode = mode;
648
+ }
649
+ setViewportSize(width, height) {
650
+ this._viewportWidth = width;
651
+ this._viewportHeight = height;
652
+ }
653
+ setViewport(x, y, width, height) {
654
+ this._viewportX = x;
655
+ this._viewportY = y;
656
+ this._viewportWidth = width;
657
+ this._viewportHeight = height;
658
+ }
659
+ setTabIndicator(_indicator) {
660
+ }
661
+ setTabIndicatorColor(_color) {
662
+ }
663
+ setTruncate(truncate) {
664
+ this._truncate = truncate;
665
+ }
666
+ getAllWrappedLines() {
667
+ const chunks = this.textBuffer.getChunks();
668
+ if (chunks.length === 0) return [];
669
+ const dfg = this.textBuffer.defaultFg ?? defaultFg;
670
+ const dbg = this.textBuffer.defaultBg ?? defaultBg;
671
+ const logicalLines = [[]];
672
+ for (const chunk of chunks) {
673
+ const parts = chunk.text.split("\n");
674
+ for (let i = 0; i < parts.length; i++) {
675
+ if (i > 0) {
676
+ logicalLines.push([]);
677
+ }
678
+ if (parts[i].length > 0) {
679
+ const vlc = {
680
+ text: parts[i],
681
+ fg: chunk.fg ?? dfg,
682
+ bg: chunk.bg ?? dbg,
683
+ attributes: chunk.attributes ?? 0
684
+ };
685
+ if (chunk.link) vlc.link = chunk.link;
686
+ logicalLines[logicalLines.length - 1].push(vlc);
687
+ }
688
+ }
689
+ }
690
+ if (this._wrapMode === "none" || !this._wrapWidth || this._wrapWidth <= 0) {
691
+ return logicalLines;
692
+ }
693
+ const wrappedLines = [];
694
+ const wrapWidth = this._wrapWidth;
695
+ for (const logicalLine of logicalLines) {
696
+ const lineText = logicalLine.map((c) => c.text).join("");
697
+ if (lineText.length <= wrapWidth) {
698
+ wrappedLines.push(logicalLine);
699
+ continue;
700
+ }
701
+ if (this._wrapMode === "char") {
702
+ let pos = 0;
703
+ while (pos < lineText.length) {
704
+ const end = Math.min(pos + wrapWidth, lineText.length);
705
+ const sliceChunks = this.sliceChunks(logicalLine, pos, end);
706
+ wrappedLines.push(sliceChunks);
707
+ pos = end;
708
+ }
709
+ } else {
710
+ let pos = 0;
711
+ while (pos < lineText.length) {
712
+ let end = Math.min(pos + wrapWidth, lineText.length);
713
+ if (end < lineText.length) {
714
+ let breakPos = end;
715
+ while (breakPos > pos && lineText[breakPos] !== " ") {
716
+ breakPos--;
717
+ }
718
+ if (breakPos > pos) {
719
+ end = breakPos + 1;
720
+ }
721
+ }
722
+ const sliceChunks = this.sliceChunks(logicalLine, pos, end);
723
+ wrappedLines.push(sliceChunks);
724
+ pos = end;
725
+ }
726
+ }
727
+ }
728
+ return wrappedLines;
729
+ }
730
+ sliceChunks(chunks, start, end) {
731
+ const result = [];
732
+ let offset = 0;
733
+ for (const chunk of chunks) {
734
+ const chunkStart = offset;
735
+ const chunkEnd = offset + chunk.text.length;
736
+ if (chunkEnd <= start || chunkStart >= end) {
737
+ offset = chunkEnd;
738
+ continue;
739
+ }
740
+ const sliceStart = Math.max(0, start - chunkStart);
741
+ const sliceEnd = Math.min(chunk.text.length, end - chunkStart);
742
+ const slicedText = chunk.text.slice(sliceStart, sliceEnd);
743
+ if (slicedText.length > 0) {
744
+ const sliced = {
745
+ text: slicedText,
746
+ fg: chunk.fg,
747
+ bg: chunk.bg,
748
+ attributes: chunk.attributes
749
+ };
750
+ if (chunk.link) sliced.link = chunk.link;
751
+ result.push(sliced);
752
+ }
753
+ offset = chunkEnd;
754
+ }
755
+ return result;
756
+ }
757
+ measureForDimensions(width, height) {
758
+ const oldWrapWidth = this._wrapWidth;
759
+ if (width > 0 && this._wrapMode !== "none") {
760
+ this._wrapWidth = width;
761
+ } else if (width === 0) {
762
+ this._wrapWidth = null;
763
+ }
764
+ const lines = this.getAllWrappedLines();
765
+ this._wrapWidth = oldWrapWidth;
766
+ let maxWidth = 0;
767
+ for (const line of lines) {
768
+ const lineWidth = line.reduce((sum, c) => sum + c.text.length, 0);
769
+ if (lineWidth > maxWidth) maxWidth = lineWidth;
770
+ }
771
+ return {
772
+ lineCount: lines.length,
773
+ maxWidth
774
+ };
775
+ }
776
+ getVirtualLineCount() {
777
+ return this.getAllWrappedLines().length;
778
+ }
779
+ getVisibleLines() {
780
+ const allLines = this.getAllWrappedLines();
781
+ if (allLines.length === 0) return null;
782
+ const startLine = this._viewportY;
783
+ const endLine = this._viewportHeight > 0 ? Math.min(startLine + this._viewportHeight, allLines.length) : allLines.length;
784
+ const visibleLines = [];
785
+ for (let i = startLine; i < endLine; i++) {
786
+ if (i >= 0 && i < allLines.length) {
787
+ visibleLines.push({ chunks: allLines[i] });
788
+ }
789
+ }
790
+ return visibleLines;
791
+ }
792
+ destroy() {
793
+ }
794
+ };
795
+
796
+ // src/browser-syntax-style.ts
797
+ var BrowserSyntaxStyle = class _BrowserSyntaxStyle {
798
+ _destroyed = false;
799
+ static create() {
800
+ return new _BrowserSyntaxStyle();
801
+ }
802
+ static fromTheme(_theme) {
803
+ return new _BrowserSyntaxStyle();
804
+ }
805
+ static fromStyles(_styles) {
806
+ return new _BrowserSyntaxStyle();
807
+ }
808
+ get ptr() {
809
+ return 0;
810
+ }
811
+ registerStyle(_name, _style) {
812
+ return 0;
813
+ }
814
+ resolveStyleId(_name) {
815
+ return null;
816
+ }
817
+ getStyleId(_name) {
818
+ return null;
819
+ }
820
+ getStyleCount() {
821
+ return 0;
822
+ }
823
+ clearNameCache() {
824
+ }
825
+ getStyle(_name) {
826
+ return void 0;
827
+ }
828
+ mergeStyles(..._styleNames) {
829
+ return { attributes: 0 };
830
+ }
831
+ clearCache() {
832
+ }
833
+ getCacheSize() {
834
+ return 0;
835
+ }
836
+ getAllStyles() {
837
+ return /* @__PURE__ */ new Map();
838
+ }
839
+ getRegisteredNames() {
840
+ return [];
841
+ }
842
+ destroy() {
843
+ this._destroyed = true;
844
+ }
845
+ };
846
+
847
+ // src/browser-render-context.ts
848
+ import { EventEmitter } from "events";
849
+ var BrowserKeyHandler = class extends EventEmitter {
850
+ constructor() {
851
+ super();
852
+ }
853
+ processInput(_data) {
854
+ return false;
855
+ }
856
+ };
857
+ var BrowserInternalKeyHandler = class extends BrowserKeyHandler {
858
+ renderableHandlers = /* @__PURE__ */ new Map();
859
+ onInternal(event, handler) {
860
+ if (!this.renderableHandlers.has(event)) {
861
+ this.renderableHandlers.set(event, /* @__PURE__ */ new Set());
862
+ }
863
+ this.renderableHandlers.get(event).add(handler);
864
+ }
865
+ offInternal(event, handler) {
866
+ const handlers = this.renderableHandlers.get(event);
867
+ if (handlers) {
868
+ handlers.delete(handler);
869
+ }
870
+ }
871
+ emit(event, ...args) {
872
+ const hasGlobal = super.emit(event, ...args);
873
+ const renderableSet = this.renderableHandlers.get(event);
874
+ if (renderableSet && renderableSet.size > 0) {
875
+ for (const handler of [...renderableSet]) {
876
+ try {
877
+ handler(...args);
878
+ } catch (e) {
879
+ console.error(`[BrowserInternalKeyHandler] Error in ${event} handler:`, e);
880
+ }
881
+ if (args[0] && args[0].propagationStopped) break;
882
+ }
883
+ return true;
884
+ }
885
+ return hasGlobal;
886
+ }
887
+ };
888
+ var BrowserRenderContext = class extends EventEmitter {
889
+ _width;
890
+ _height;
891
+ _widthMethod;
892
+ _renderRequested = false;
893
+ _onRenderRequest = null;
894
+ _lifecyclePasses = /* @__PURE__ */ new Set();
895
+ _focusedRenderable = null;
896
+ keyInput;
897
+ _internalKeyInput;
898
+ constructor(width, height, widthMethod = "wcwidth") {
899
+ super();
900
+ this._width = width;
901
+ this._height = height;
902
+ this._widthMethod = widthMethod;
903
+ this.keyInput = new BrowserKeyHandler();
904
+ this._internalKeyInput = new BrowserInternalKeyHandler();
905
+ }
906
+ get width() {
907
+ return this._width;
908
+ }
909
+ get height() {
910
+ return this._height;
911
+ }
912
+ get widthMethod() {
913
+ return this._widthMethod;
914
+ }
915
+ get capabilities() {
916
+ return null;
917
+ }
918
+ get hasSelection() {
919
+ return false;
920
+ }
921
+ get currentFocusedRenderable() {
922
+ return this._focusedRenderable;
923
+ }
924
+ setOnRenderRequest(callback) {
925
+ this._onRenderRequest = callback;
926
+ }
927
+ resize(width, height) {
928
+ this._width = width;
929
+ this._height = height;
930
+ this.emit("resize", width, height);
931
+ }
932
+ // RenderContext interface methods
933
+ addToHitGrid(_x, _y, _width, _height, _id) {
934
+ }
935
+ pushHitGridScissorRect(_x, _y, _width, _height) {
936
+ }
937
+ popHitGridScissorRect() {
938
+ }
939
+ clearHitGridScissorRects() {
940
+ }
941
+ requestRender() {
942
+ if (this._renderRequested) return;
943
+ this._renderRequested = true;
944
+ this._onRenderRequest?.();
945
+ this._renderRequested = false;
946
+ }
947
+ setCursorPosition(_x, _y, _visible) {
948
+ }
949
+ setCursorStyle(_options) {
950
+ }
951
+ setCursorColor(_color) {
952
+ }
953
+ setMousePointer(_shape) {
954
+ }
955
+ requestLive() {
956
+ }
957
+ dropLive() {
958
+ }
959
+ getSelection() {
960
+ return null;
961
+ }
962
+ requestSelectionUpdate() {
963
+ }
964
+ focusRenderable(renderable) {
965
+ if (this._focusedRenderable && this._focusedRenderable !== renderable) {
966
+ this._focusedRenderable.blur?.();
967
+ }
968
+ this._focusedRenderable = renderable;
969
+ }
970
+ registerLifecyclePass(renderable) {
971
+ this._lifecyclePasses.add(renderable);
972
+ }
973
+ unregisterLifecyclePass(renderable) {
974
+ this._lifecyclePasses.delete(renderable);
975
+ }
976
+ getLifecyclePasses() {
977
+ return this._lifecyclePasses;
978
+ }
979
+ clearSelection() {
980
+ }
981
+ startSelection(_renderable, _x, _y) {
982
+ }
983
+ updateSelection(_currentRenderable, _x, _y, _options) {
984
+ }
985
+ };
986
+
987
+ // src/core-shims/index.ts
988
+ import {
989
+ CliRenderer,
990
+ CliRenderEvents,
991
+ createCliRenderer
992
+ } from "../../../../opentui/packages/core/src/renderer";
993
+ import {
994
+ Timeline,
995
+ engine,
996
+ createTimeline
997
+ } from "../../../../opentui/packages/core/src/animation/Timeline";
998
+ import * as Yoga from "yoga-layout";
999
+ function resolveRenderLib() {
1000
+ return null;
1001
+ }
1002
+ function createTextAttributes(opts = {}) {
1003
+ const TA = {
1004
+ NONE: 0,
1005
+ BOLD: 1,
1006
+ DIM: 2,
1007
+ ITALIC: 4,
1008
+ UNDERLINE: 8,
1009
+ BLINK: 16,
1010
+ INVERSE: 32,
1011
+ HIDDEN: 64,
1012
+ STRIKETHROUGH: 128
1013
+ };
1014
+ let attr = TA.NONE;
1015
+ if (opts.bold) attr |= TA.BOLD;
1016
+ if (opts.italic) attr |= TA.ITALIC;
1017
+ if (opts.underline) attr |= TA.UNDERLINE;
1018
+ if (opts.dim) attr |= TA.DIM;
1019
+ if (opts.blink) attr |= TA.BLINK;
1020
+ if (opts.inverse) attr |= TA.INVERSE;
1021
+ if (opts.hidden) attr |= TA.HIDDEN;
1022
+ if (opts.strikethrough) attr |= TA.STRIKETHROUGH;
1023
+ return attr;
1024
+ }
1025
+ function attributesWithLink(baseAttributes, linkId) {
1026
+ return baseAttributes & 255 | (linkId & 16777215) << 8;
1027
+ }
1028
+ function getLinkId(attributes) {
1029
+ return attributes >>> 8 & 16777215;
1030
+ }
1031
+ function visualizeRenderableTree(..._args) {
1032
+ }
1033
+
1034
+ // src/browser-buffer.ts
1035
+ var CONTINUATION = 3221225472;
1036
+ var BrowserBuffer = class _BrowserBuffer {
1037
+ id;
1038
+ respectAlpha;
1039
+ _width;
1040
+ _height;
1041
+ _widthMethod;
1042
+ // Cell data - same layout as native OptimizedBuffer
1043
+ char;
1044
+ fg;
1045
+ bg;
1046
+ attributes;
1047
+ scissorStack = [];
1048
+ opacityStack = [];
1049
+ // Link registry for clickable links
1050
+ linkRegistry = /* @__PURE__ */ new Map();
1051
+ nextLinkId = 1;
1052
+ constructor(width, height, options = {}) {
1053
+ this._width = width;
1054
+ this._height = height;
1055
+ this._widthMethod = options.widthMethod ?? "wcwidth";
1056
+ this.respectAlpha = options.respectAlpha ?? false;
1057
+ this.id = options.id ?? `browser-buffer-${Math.random().toString(36).slice(2, 8)}`;
1058
+ const size = width * height;
1059
+ this.char = new Uint32Array(size);
1060
+ this.fg = new Float32Array(size * 4);
1061
+ this.bg = new Float32Array(size * 4);
1062
+ this.attributes = new Uint32Array(size);
1063
+ this.char.fill(32);
1064
+ }
1065
+ static create(width, height, widthMethod, options) {
1066
+ return new _BrowserBuffer(width, height, { ...options, widthMethod });
1067
+ }
1068
+ get width() {
1069
+ return this._width;
1070
+ }
1071
+ get height() {
1072
+ return this._height;
1073
+ }
1074
+ get widthMethod() {
1075
+ return this._widthMethod;
1076
+ }
1077
+ get ptr() {
1078
+ return 0;
1079
+ }
1080
+ get buffers() {
1081
+ return {
1082
+ char: this.char,
1083
+ fg: this.fg,
1084
+ bg: this.bg,
1085
+ attributes: this.attributes
1086
+ };
1087
+ }
1088
+ setRespectAlpha(respectAlpha) {
1089
+ this.respectAlpha = respectAlpha;
1090
+ }
1091
+ getNativeId() {
1092
+ return this.id;
1093
+ }
1094
+ registerLink(url) {
1095
+ const id = this.nextLinkId++;
1096
+ this.linkRegistry.set(id, url);
1097
+ return id;
1098
+ }
1099
+ getLinkUrl(linkId) {
1100
+ return this.linkRegistry.get(linkId);
1101
+ }
1102
+ isInScissor(x, y) {
1103
+ if (this.scissorStack.length === 0) return true;
1104
+ const rect = this.scissorStack[this.scissorStack.length - 1];
1105
+ return x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height;
1106
+ }
1107
+ getCurrentOpacityMultiplier() {
1108
+ if (this.opacityStack.length === 0) return 1;
1109
+ return this.opacityStack[this.opacityStack.length - 1];
1110
+ }
1111
+ applyOpacity(color) {
1112
+ const multiplier = this.getCurrentOpacityMultiplier();
1113
+ if (multiplier >= 1) return color;
1114
+ return {
1115
+ r: color.r,
1116
+ g: color.g,
1117
+ b: color.b,
1118
+ a: color.a * multiplier,
1119
+ buffer: new Float32Array([color.r, color.g, color.b, color.a * multiplier]),
1120
+ toInts: color.toInts,
1121
+ equals: color.equals,
1122
+ map: color.map,
1123
+ toString: color.toString
1124
+ };
1125
+ }
1126
+ clear(bg2) {
1127
+ const size = this._width * this._height;
1128
+ this.char.fill(32);
1129
+ this.attributes.fill(0);
1130
+ this.linkRegistry.clear();
1131
+ this.nextLinkId = 1;
1132
+ if (bg2) {
1133
+ for (let i = 0; i < size; i++) {
1134
+ const offset = i * 4;
1135
+ this.bg[offset] = bg2.r;
1136
+ this.bg[offset + 1] = bg2.g;
1137
+ this.bg[offset + 2] = bg2.b;
1138
+ this.bg[offset + 3] = bg2.a;
1139
+ this.fg[offset] = 0;
1140
+ this.fg[offset + 1] = 0;
1141
+ this.fg[offset + 2] = 0;
1142
+ this.fg[offset + 3] = 0;
1143
+ }
1144
+ } else {
1145
+ this.fg.fill(0);
1146
+ this.bg.fill(0);
1147
+ }
1148
+ }
1149
+ setCell(x, y, char, fgColor, bgColor, attr = 0) {
1150
+ if (x < 0 || x >= this._width || y < 0 || y >= this._height) return;
1151
+ if (!this.isInScissor(x, y)) return;
1152
+ const idx = y * this._width + x;
1153
+ const offset = idx * 4;
1154
+ const effectiveBg = this.applyOpacity(bgColor);
1155
+ const effectiveFg = this.applyOpacity(fgColor);
1156
+ this.char[idx] = char.codePointAt(0) ?? 32;
1157
+ this.attributes[idx] = attr;
1158
+ this.fg[offset] = effectiveFg.r;
1159
+ this.fg[offset + 1] = effectiveFg.g;
1160
+ this.fg[offset + 2] = effectiveFg.b;
1161
+ this.fg[offset + 3] = effectiveFg.a;
1162
+ this.bg[offset] = effectiveBg.r;
1163
+ this.bg[offset + 1] = effectiveBg.g;
1164
+ this.bg[offset + 2] = effectiveBg.b;
1165
+ this.bg[offset + 3] = effectiveBg.a;
1166
+ }
1167
+ setCellWithAlphaBlending(x, y, char, fgColor, bgColor, attr = 0) {
1168
+ this.setCell(x, y, char, fgColor, bgColor, attr);
1169
+ }
1170
+ drawChar(charCode, x, y, fgColor, bgColor, attr = 0) {
1171
+ if (x < 0 || x >= this._width || y < 0 || y >= this._height) return;
1172
+ if (!this.isInScissor(x, y)) return;
1173
+ const idx = y * this._width + x;
1174
+ const offset = idx * 4;
1175
+ const effectiveBg = this.applyOpacity(bgColor);
1176
+ const effectiveFg = this.applyOpacity(fgColor);
1177
+ this.char[idx] = charCode;
1178
+ this.attributes[idx] = attr;
1179
+ this.fg[offset] = effectiveFg.r;
1180
+ this.fg[offset + 1] = effectiveFg.g;
1181
+ this.fg[offset + 2] = effectiveFg.b;
1182
+ this.fg[offset + 3] = effectiveFg.a;
1183
+ this.bg[offset] = effectiveBg.r;
1184
+ this.bg[offset + 1] = effectiveBg.g;
1185
+ this.bg[offset + 2] = effectiveBg.b;
1186
+ this.bg[offset + 3] = effectiveBg.a;
1187
+ }
1188
+ drawText(text, x, y, fgColor, bgColor, attr = 0, _selection) {
1189
+ const transparentBg = {
1190
+ r: 0,
1191
+ g: 0,
1192
+ b: 0,
1193
+ a: 0,
1194
+ buffer: new Float32Array([0, 0, 0, 0])
1195
+ };
1196
+ const bg2 = bgColor ?? transparentBg;
1197
+ let curX = x;
1198
+ for (const ch of text) {
1199
+ if (curX >= this._width) break;
1200
+ if (curX >= 0) {
1201
+ this.setCell(curX, y, ch, fgColor, bg2, attr);
1202
+ }
1203
+ curX++;
1204
+ }
1205
+ }
1206
+ fillRect(x, y, width, height, bgColor) {
1207
+ for (let row = y; row < y + height && row < this._height; row++) {
1208
+ for (let col = x; col < x + width && col < this._width; col++) {
1209
+ if (col < 0 || row < 0) continue;
1210
+ if (!this.isInScissor(col, row)) continue;
1211
+ const idx = row * this._width + col;
1212
+ const offset = idx * 4;
1213
+ const effectiveBg = this.applyOpacity(bgColor);
1214
+ this.char[idx] = 32;
1215
+ this.bg[offset] = effectiveBg.r;
1216
+ this.bg[offset + 1] = effectiveBg.g;
1217
+ this.bg[offset + 2] = effectiveBg.b;
1218
+ this.bg[offset + 3] = effectiveBg.a;
1219
+ }
1220
+ }
1221
+ }
1222
+ drawBox(options) {
1223
+ const {
1224
+ x,
1225
+ y,
1226
+ width,
1227
+ height,
1228
+ border,
1229
+ borderColor,
1230
+ backgroundColor,
1231
+ shouldFill = true,
1232
+ title,
1233
+ titleAlignment = "left"
1234
+ } = options;
1235
+ if (width <= 0 || height <= 0) return;
1236
+ const sides = {
1237
+ top: border === true || Array.isArray(border) && border.includes("top"),
1238
+ right: border === true || Array.isArray(border) && border.includes("right"),
1239
+ bottom: border === true || Array.isArray(border) && border.includes("bottom"),
1240
+ left: border === true || Array.isArray(border) && border.includes("left")
1241
+ };
1242
+ const borderChars = options.customBorderChars ?? this.getDefaultBorderChars(options.borderStyle);
1243
+ if (shouldFill) {
1244
+ const fillStartX = x + (sides.left ? 1 : 0);
1245
+ const fillStartY = y + (sides.top ? 1 : 0);
1246
+ const fillWidth = width - (sides.left ? 1 : 0) - (sides.right ? 1 : 0);
1247
+ const fillHeight = height - (sides.top ? 1 : 0) - (sides.bottom ? 1 : 0);
1248
+ if (fillWidth > 0 && fillHeight > 0) {
1249
+ this.fillRect(fillStartX, fillStartY, fillWidth, fillHeight, backgroundColor);
1250
+ }
1251
+ }
1252
+ if (!border) return;
1253
+ const transparent = { r: 0, g: 0, b: 0, a: 0, buffer: new Float32Array([0, 0, 0, 0]) };
1254
+ const topLeft = borderChars[0];
1255
+ const topRight = borderChars[1];
1256
+ const bottomLeft = borderChars[2];
1257
+ const bottomRight = borderChars[3];
1258
+ const horizontal = borderChars[4];
1259
+ const vertical = borderChars[5];
1260
+ if (sides.top) {
1261
+ if (sides.left) this.drawChar(topLeft, x, y, borderColor, transparent);
1262
+ for (let col = 1; col < width - 1; col++) {
1263
+ this.drawChar(horizontal, x + col, y, borderColor, transparent);
1264
+ }
1265
+ if (sides.right && width > 1) this.drawChar(topRight, x + width - 1, y, borderColor, transparent);
1266
+ }
1267
+ if (sides.bottom && height > 1) {
1268
+ if (sides.left) this.drawChar(bottomLeft, x, y + height - 1, borderColor, transparent);
1269
+ for (let col = 1; col < width - 1; col++) {
1270
+ this.drawChar(horizontal, x + col, y + height - 1, borderColor, transparent);
1271
+ }
1272
+ if (sides.right && width > 1)
1273
+ this.drawChar(bottomRight, x + width - 1, y + height - 1, borderColor, transparent);
1274
+ }
1275
+ if (sides.left) {
1276
+ for (let row = 1; row < height - 1; row++) {
1277
+ this.drawChar(vertical, x, y + row, borderColor, transparent);
1278
+ }
1279
+ }
1280
+ if (sides.right && width > 1) {
1281
+ for (let row = 1; row < height - 1; row++) {
1282
+ this.drawChar(vertical, x + width - 1, y + row, borderColor, transparent);
1283
+ }
1284
+ }
1285
+ if (title && sides.top && width > 4) {
1286
+ const maxTitleLen = width - 4;
1287
+ const truncatedTitle = title.length > maxTitleLen ? title.slice(0, maxTitleLen) : title;
1288
+ let titleX;
1289
+ if (titleAlignment === "center") {
1290
+ titleX = x + Math.floor((width - truncatedTitle.length) / 2);
1291
+ } else if (titleAlignment === "right") {
1292
+ titleX = x + width - truncatedTitle.length - 2;
1293
+ } else {
1294
+ titleX = x + 2;
1295
+ }
1296
+ this.drawText(truncatedTitle, titleX, y, borderColor, transparent);
1297
+ }
1298
+ }
1299
+ getDefaultBorderChars(borderStyle) {
1300
+ const styles = {
1301
+ rounded: [9581, 9582, 9584, 9583, 9472, 9474, 9516, 9524, 9500, 9508, 9532],
1302
+ single: [9484, 9488, 9492, 9496, 9472, 9474, 9516, 9524, 9500, 9508, 9532],
1303
+ double: [9556, 9559, 9562, 9565, 9552, 9553, 9574, 9577, 9568, 9571, 9580],
1304
+ heavy: [9487, 9491, 9495, 9499, 9473, 9475, 9523, 9531, 9507, 9515, 9547]
1305
+ };
1306
+ const chars = styles[borderStyle ?? "rounded"] ?? styles.rounded;
1307
+ return new Uint32Array(chars);
1308
+ }
1309
+ pushScissorRect(x, y, width, height) {
1310
+ if (this.scissorStack.length > 0) {
1311
+ const current = this.scissorStack[this.scissorStack.length - 1];
1312
+ const nx = Math.max(x, current.x);
1313
+ const ny = Math.max(y, current.y);
1314
+ const nw = Math.min(x + width, current.x + current.width) - nx;
1315
+ const nh = Math.min(y + height, current.y + current.height) - ny;
1316
+ this.scissorStack.push({ x: nx, y: ny, width: Math.max(0, nw), height: Math.max(0, nh) });
1317
+ } else {
1318
+ this.scissorStack.push({ x, y, width, height });
1319
+ }
1320
+ }
1321
+ popScissorRect() {
1322
+ this.scissorStack.pop();
1323
+ }
1324
+ clearScissorRects() {
1325
+ this.scissorStack = [];
1326
+ }
1327
+ pushOpacity(opacity) {
1328
+ const current = this.getCurrentOpacityMultiplier();
1329
+ this.opacityStack.push(current * opacity);
1330
+ }
1331
+ popOpacity() {
1332
+ this.opacityStack.pop();
1333
+ }
1334
+ getCurrentOpacity() {
1335
+ return this.getCurrentOpacityMultiplier();
1336
+ }
1337
+ clearOpacity() {
1338
+ this.opacityStack = [];
1339
+ }
1340
+ resize(width, height) {
1341
+ this._width = width;
1342
+ this._height = height;
1343
+ const size = width * height;
1344
+ this.char = new Uint32Array(size);
1345
+ this.fg = new Float32Array(size * 4);
1346
+ this.bg = new Float32Array(size * 4);
1347
+ this.attributes = new Uint32Array(size);
1348
+ this.char.fill(32);
1349
+ }
1350
+ // Read buffer into CapturedLine[] for testing
1351
+ getSpanLines() {
1352
+ const lines = [];
1353
+ for (let row = 0; row < this._height; row++) {
1354
+ const spans = [];
1355
+ let currentSpan = null;
1356
+ for (let col = 0; col < this._width; col++) {
1357
+ const idx = row * this._width + col;
1358
+ const offset = idx * 4;
1359
+ if (this.attributes[idx] & CONTINUATION) continue;
1360
+ const charCode = this.char[idx];
1361
+ const ch = charCode === 0 ? " " : String.fromCodePoint(charCode);
1362
+ const fgR = this.fg[offset];
1363
+ const fgG = this.fg[offset + 1];
1364
+ const fgB = this.fg[offset + 2];
1365
+ const fgA = this.fg[offset + 3];
1366
+ const bgR = this.bg[offset];
1367
+ const bgG = this.bg[offset + 1];
1368
+ const bgB = this.bg[offset + 2];
1369
+ const bgA = this.bg[offset + 3];
1370
+ const attr = this.attributes[idx] & 255;
1371
+ const fg2 = {
1372
+ r: fgR,
1373
+ g: fgG,
1374
+ b: fgB,
1375
+ a: fgA,
1376
+ buffer: new Float32Array([fgR, fgG, fgB, fgA])
1377
+ };
1378
+ const bg2 = {
1379
+ r: bgR,
1380
+ g: bgG,
1381
+ b: bgB,
1382
+ a: bgA,
1383
+ buffer: new Float32Array([bgR, bgG, bgB, bgA])
1384
+ };
1385
+ if (currentSpan && currentSpan.fg.r === fgR && currentSpan.fg.g === fgG && currentSpan.fg.b === fgB && currentSpan.fg.a === fgA && currentSpan.bg.r === bgR && currentSpan.bg.g === bgG && currentSpan.bg.b === bgB && currentSpan.bg.a === bgA && currentSpan.attributes === attr) {
1386
+ currentSpan.text += ch;
1387
+ currentSpan.width += 1;
1388
+ } else {
1389
+ if (currentSpan) spans.push(currentSpan);
1390
+ currentSpan = { text: ch, fg: fg2, bg: bg2, attributes: attr, width: 1 };
1391
+ }
1392
+ }
1393
+ if (currentSpan) spans.push(currentSpan);
1394
+ lines.push({ spans });
1395
+ }
1396
+ return lines;
1397
+ }
1398
+ // Draw a text buffer view into the buffer
1399
+ drawTextBufferView(view, x, y) {
1400
+ if (!view || !view.getVisibleLines) return;
1401
+ const lines = view.getVisibleLines();
1402
+ if (!lines) return;
1403
+ for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
1404
+ const line = lines[lineIdx];
1405
+ if (!line) continue;
1406
+ let curX = x;
1407
+ for (const chunk of line.chunks) {
1408
+ const text = chunk.text;
1409
+ const fgColor = chunk.fg;
1410
+ const bgColor = chunk.bg;
1411
+ let attr = chunk.attributes ?? 0;
1412
+ if (chunk.link && chunk.link.url) {
1413
+ const linkId = this.registerLink(chunk.link.url);
1414
+ attr = attributesWithLink(attr, linkId);
1415
+ }
1416
+ for (const ch of text) {
1417
+ if (curX >= this._width) break;
1418
+ if (curX >= 0 && y + lineIdx >= 0 && y + lineIdx < this._height) {
1419
+ this.setCell(curX, y + lineIdx, ch, fgColor, bgColor, attr);
1420
+ }
1421
+ curX++;
1422
+ }
1423
+ }
1424
+ }
1425
+ }
1426
+ drawTextBuffer(textBufferView, x, y) {
1427
+ this.drawTextBufferView(textBufferView, x, y);
1428
+ }
1429
+ drawFrameBuffer(destX, destY, frameBuffer, sourceX = 0, sourceY = 0, sourceWidth, sourceHeight) {
1430
+ const sw = sourceWidth ?? frameBuffer.width;
1431
+ const sh = sourceHeight ?? frameBuffer.height;
1432
+ const srcChar = frameBuffer.char;
1433
+ const srcFg = frameBuffer.fg;
1434
+ const srcBg = frameBuffer.bg;
1435
+ const srcAttr = frameBuffer.attributes;
1436
+ const srcCols = frameBuffer.width;
1437
+ for (let row = 0; row < sh; row++) {
1438
+ const srcRow = sourceY + row;
1439
+ const dstRow = destY + row;
1440
+ if (srcRow < 0 || srcRow >= frameBuffer.height) continue;
1441
+ if (dstRow < 0 || dstRow >= this._height) continue;
1442
+ for (let col = 0; col < sw; col++) {
1443
+ const srcCol = sourceX + col;
1444
+ const dstCol = destX + col;
1445
+ if (srcCol < 0 || srcCol >= frameBuffer.width) continue;
1446
+ if (dstCol < 0 || dstCol >= this._width) continue;
1447
+ if (!this.isInScissor(dstCol, dstRow)) continue;
1448
+ const srcIdx = srcRow * srcCols + srcCol;
1449
+ const dstIdx = dstRow * this._width + dstCol;
1450
+ const srcOffset = srcIdx * 4;
1451
+ const dstOffset = dstIdx * 4;
1452
+ this.char[dstIdx] = srcChar[srcIdx];
1453
+ this.attributes[dstIdx] = srcAttr[srcIdx];
1454
+ const fgA = srcFg[srcOffset + 3];
1455
+ const opacityMul = this.getCurrentOpacityMultiplier();
1456
+ this.fg[dstOffset] = srcFg[srcOffset];
1457
+ this.fg[dstOffset + 1] = srcFg[srcOffset + 1];
1458
+ this.fg[dstOffset + 2] = srcFg[srcOffset + 2];
1459
+ this.fg[dstOffset + 3] = fgA * opacityMul;
1460
+ const bgA = srcBg[srcOffset + 3];
1461
+ this.bg[dstOffset] = srcBg[srcOffset];
1462
+ this.bg[dstOffset + 1] = srcBg[srcOffset + 1];
1463
+ this.bg[dstOffset + 2] = srcBg[srcOffset + 2];
1464
+ this.bg[dstOffset + 3] = bgA * opacityMul;
1465
+ }
1466
+ }
1467
+ }
1468
+ drawEditorView(editorView, x, y) {
1469
+ if (!editorView) return;
1470
+ const viewport = editorView.getViewport();
1471
+ const text = editorView.getText();
1472
+ const lines = text.split("\n");
1473
+ const dfg = editorView.editBuffer?._defaultFg ?? {
1474
+ r: 1,
1475
+ g: 1,
1476
+ b: 1,
1477
+ a: 1,
1478
+ buffer: new Float32Array([1, 1, 1, 1])
1479
+ };
1480
+ const dbg = editorView.editBuffer?._defaultBg ?? {
1481
+ r: 0,
1482
+ g: 0,
1483
+ b: 0,
1484
+ a: 0,
1485
+ buffer: new Float32Array([0, 0, 0, 0])
1486
+ };
1487
+ const visibleRows = viewport.height > 0 ? viewport.height : this._height - y;
1488
+ if (text === "" && editorView._placeholderChunks && editorView._placeholderChunks.length > 0) {
1489
+ let curX = x;
1490
+ for (const chunk of editorView._placeholderChunks) {
1491
+ const chunkFg = chunk.fg ?? dfg;
1492
+ const chunkBg = chunk.bg ?? dbg;
1493
+ const attr = (chunk.attributes ?? 0) | 2;
1494
+ for (const ch of chunk.text) {
1495
+ if (curX >= this._width) break;
1496
+ if (curX >= 0 && y >= 0 && y < this._height) {
1497
+ this.setCell(curX, y, ch, chunkFg, chunkBg, attr);
1498
+ }
1499
+ curX++;
1500
+ }
1501
+ }
1502
+ } else {
1503
+ for (let row = 0; row < visibleRows; row++) {
1504
+ const lineIdx = viewport.offsetY + row;
1505
+ if (lineIdx < 0 || lineIdx >= lines.length) continue;
1506
+ const dstRow = y + row;
1507
+ if (dstRow < 0 || dstRow >= this._height) continue;
1508
+ const line = lines[lineIdx];
1509
+ for (let col = 0; col < line.length; col++) {
1510
+ const srcCol = viewport.offsetX + col;
1511
+ if (srcCol < 0 || srcCol >= line.length) continue;
1512
+ const dstCol = x + col;
1513
+ if (dstCol < 0 || dstCol >= this._width) break;
1514
+ this.setCell(dstCol, dstRow, line[srcCol], dfg, dbg, 0);
1515
+ }
1516
+ }
1517
+ }
1518
+ const cursor = editorView.getVisualCursor();
1519
+ if (cursor) {
1520
+ const cursorX = x + cursor.visualCol;
1521
+ const cursorY = y + cursor.visualRow;
1522
+ if (cursorX >= 0 && cursorX < this._width && cursorY >= 0 && cursorY < this._height) {
1523
+ const idx = cursorY * this._width + cursorX;
1524
+ const charCode = this.char[idx];
1525
+ const ch = charCode === 0 || charCode === 32 ? " " : String.fromCodePoint(charCode);
1526
+ this.setCell(cursorX, cursorY, ch, dfg, dbg, 32);
1527
+ }
1528
+ }
1529
+ }
1530
+ drawSuperSampleBuffer() {
1531
+ }
1532
+ drawPackedBuffer() {
1533
+ }
1534
+ drawGrayscaleBuffer() {
1535
+ }
1536
+ drawGrayscaleBufferSupersampled() {
1537
+ }
1538
+ drawGrid() {
1539
+ }
1540
+ encodeUnicode(_text) {
1541
+ return null;
1542
+ }
1543
+ freeUnicode() {
1544
+ }
1545
+ getRealCharBytes() {
1546
+ return new Uint8Array(0);
1547
+ }
1548
+ destroy() {
1549
+ }
1550
+ };
1551
+
1552
+ // src/canvas-painter.ts
1553
+ var TextAttributes2 = {
1554
+ BOLD: 1 << 0,
1555
+ DIM: 1 << 1,
1556
+ ITALIC: 1 << 2,
1557
+ UNDERLINE: 1 << 3,
1558
+ UNDERLINE_DASHED: 1 << 4,
1559
+ INVERSE: 1 << 5,
1560
+ UNDERLINE_DOTTED: 1 << 6
1561
+ };
1562
+ var CONTINUATION2 = 3221225472;
1563
+ var BOX_DRAWING_MAP = {
1564
+ // Light lines
1565
+ 9472: { left: true, right: true, type: "light" },
1566
+ // ─
1567
+ 9474: { up: true, down: true, type: "light" },
1568
+ // │
1569
+ 9484: { right: true, down: true, type: "light" },
1570
+ // ┌
1571
+ 9488: { left: true, down: true, type: "light" },
1572
+ // ┐
1573
+ 9492: { right: true, up: true, type: "light" },
1574
+ // └
1575
+ 9496: { left: true, up: true, type: "light" },
1576
+ // ┘
1577
+ 9500: { up: true, down: true, right: true, type: "light" },
1578
+ // ├
1579
+ 9508: { up: true, down: true, left: true, type: "light" },
1580
+ // ┤
1581
+ 9516: { left: true, right: true, down: true, type: "light" },
1582
+ // ┬
1583
+ 9524: { left: true, right: true, up: true, type: "light" },
1584
+ // ┴
1585
+ 9532: { left: true, right: true, up: true, down: true, type: "light" },
1586
+ // ┼
1587
+ // Heavy lines
1588
+ 9473: { left: true, right: true, type: "heavy" },
1589
+ // ━
1590
+ 9475: { up: true, down: true, type: "heavy" },
1591
+ // ┃
1592
+ 9487: { right: true, down: true, type: "heavy" },
1593
+ // ┏
1594
+ 9491: { left: true, down: true, type: "heavy" },
1595
+ // ┓
1596
+ 9495: { right: true, up: true, type: "heavy" },
1597
+ // ┗
1598
+ 9499: { left: true, up: true, type: "heavy" },
1599
+ // ┛
1600
+ 9507: { up: true, down: true, right: true, type: "heavy" },
1601
+ // ┣
1602
+ 9515: { up: true, down: true, left: true, type: "heavy" },
1603
+ // ┫
1604
+ 9523: { left: true, right: true, down: true, type: "heavy" },
1605
+ // ┳
1606
+ 9531: { left: true, right: true, up: true, type: "heavy" },
1607
+ // ┻
1608
+ 9547: { left: true, right: true, up: true, down: true, type: "heavy" },
1609
+ // ╋
1610
+ // Light/heavy mixed (treat as light for simplicity of joins)
1611
+ 9485: { right: true, down: true, type: "heavy" },
1612
+ // ┍
1613
+ 9486: { right: true, down: true, type: "heavy" },
1614
+ // ┎
1615
+ 9489: { left: true, down: true, type: "heavy" },
1616
+ // ┑
1617
+ 9490: { left: true, down: true, type: "heavy" },
1618
+ // ┒
1619
+ 9493: { right: true, up: true, type: "heavy" },
1620
+ // ┕
1621
+ 9494: { right: true, up: true, type: "heavy" },
1622
+ // ┖
1623
+ 9497: { left: true, up: true, type: "heavy" },
1624
+ // ┙
1625
+ 9498: { left: true, up: true, type: "heavy" },
1626
+ // ┚
1627
+ 9501: { up: true, down: true, right: true, type: "heavy" },
1628
+ // ┝
1629
+ 9502: { up: true, down: true, right: true, type: "light" },
1630
+ // ┞
1631
+ 9503: { up: true, down: true, right: true, type: "light" },
1632
+ // ┟
1633
+ 9504: { up: true, down: true, right: true, type: "heavy" },
1634
+ // ┠
1635
+ 9505: { up: true, down: true, right: true, type: "heavy" },
1636
+ // ┡
1637
+ 9506: { up: true, down: true, right: true, type: "heavy" },
1638
+ // ┢
1639
+ 9509: { up: true, down: true, left: true, type: "heavy" },
1640
+ // ┥
1641
+ 9510: { up: true, down: true, left: true, type: "light" },
1642
+ // ┦
1643
+ 9511: { up: true, down: true, left: true, type: "light" },
1644
+ // ┧
1645
+ 9512: { up: true, down: true, left: true, type: "heavy" },
1646
+ // ┨
1647
+ 9513: { up: true, down: true, left: true, type: "heavy" },
1648
+ // ┩
1649
+ 9514: { up: true, down: true, left: true, type: "heavy" },
1650
+ // ┪
1651
+ 9517: { left: true, right: true, down: true, type: "heavy" },
1652
+ // ┭
1653
+ 9518: { left: true, right: true, down: true, type: "heavy" },
1654
+ // ┮
1655
+ 9519: { left: true, right: true, down: true, type: "heavy" },
1656
+ // ┯
1657
+ 9520: { left: true, right: true, down: true, type: "heavy" },
1658
+ // ┰
1659
+ 9521: { left: true, right: true, down: true, type: "heavy" },
1660
+ // ┱
1661
+ 9522: { left: true, right: true, down: true, type: "heavy" },
1662
+ // ┲
1663
+ 9525: { left: true, right: true, up: true, type: "heavy" },
1664
+ // ┵
1665
+ 9526: { left: true, right: true, up: true, type: "heavy" },
1666
+ // ┶
1667
+ 9527: { left: true, right: true, up: true, type: "heavy" },
1668
+ // ┷
1669
+ 9528: { left: true, right: true, up: true, type: "heavy" },
1670
+ // ┸
1671
+ 9529: { left: true, right: true, up: true, type: "heavy" },
1672
+ // ┹
1673
+ 9530: { left: true, right: true, up: true, type: "heavy" },
1674
+ // ┺
1675
+ 9533: { left: true, right: true, up: true, down: true, type: "heavy" },
1676
+ // ┽
1677
+ 9534: { left: true, right: true, up: true, down: true, type: "heavy" },
1678
+ // ┾
1679
+ 9535: { left: true, right: true, up: true, down: true, type: "heavy" },
1680
+ // ┿
1681
+ 9536: { left: true, right: true, up: true, down: true, type: "heavy" },
1682
+ // ╀
1683
+ 9537: { left: true, right: true, up: true, down: true, type: "heavy" },
1684
+ // ╁
1685
+ 9538: { left: true, right: true, up: true, down: true, type: "heavy" },
1686
+ // ╂
1687
+ 9539: { left: true, right: true, up: true, down: true, type: "heavy" },
1688
+ // ╃
1689
+ 9540: { left: true, right: true, up: true, down: true, type: "heavy" },
1690
+ // ╄
1691
+ 9541: { left: true, right: true, up: true, down: true, type: "heavy" },
1692
+ // ╅
1693
+ 9542: { left: true, right: true, up: true, down: true, type: "heavy" },
1694
+ // ╆
1695
+ 9543: { left: true, right: true, up: true, down: true, type: "heavy" },
1696
+ // ╇
1697
+ 9544: { left: true, right: true, up: true, down: true, type: "heavy" },
1698
+ // ╈
1699
+ 9545: { left: true, right: true, up: true, down: true, type: "heavy" },
1700
+ // ╉
1701
+ 9546: { left: true, right: true, up: true, down: true, type: "heavy" },
1702
+ // ╊
1703
+ // Dashed lines (render as solid light/heavy)
1704
+ 9476: { left: true, right: true, type: "light" },
1705
+ // ┄
1706
+ 9477: { left: true, right: true, type: "heavy" },
1707
+ // ┅
1708
+ 9478: { up: true, down: true, type: "light" },
1709
+ // ┆
1710
+ 9479: { up: true, down: true, type: "heavy" },
1711
+ // ┇
1712
+ 9480: { left: true, right: true, type: "light" },
1713
+ // ┈
1714
+ 9481: { left: true, right: true, type: "heavy" },
1715
+ // ┉
1716
+ 9482: { up: true, down: true, type: "light" },
1717
+ // ┊
1718
+ 9483: { up: true, down: true, type: "heavy" },
1719
+ // ┋
1720
+ // Double lines
1721
+ 9552: { left: true, right: true, type: "double" },
1722
+ // ═
1723
+ 9553: { up: true, down: true, type: "double" },
1724
+ // ║
1725
+ 9554: { right: true, down: true, type: "double" },
1726
+ // ╒
1727
+ 9555: { right: true, down: true, type: "double" },
1728
+ // ╓
1729
+ 9556: { right: true, down: true, type: "double" },
1730
+ // ╔
1731
+ 9557: { left: true, down: true, type: "double" },
1732
+ // ╕
1733
+ 9558: { left: true, down: true, type: "double" },
1734
+ // ╖
1735
+ 9559: { left: true, down: true, type: "double" },
1736
+ // ╗
1737
+ 9560: { right: true, up: true, type: "double" },
1738
+ // ╘
1739
+ 9561: { right: true, up: true, type: "double" },
1740
+ // ╙
1741
+ 9562: { right: true, up: true, type: "double" },
1742
+ // ╚
1743
+ 9563: { left: true, up: true, type: "double" },
1744
+ // ╛
1745
+ 9564: { left: true, up: true, type: "double" },
1746
+ // ╜
1747
+ 9565: { left: true, up: true, type: "double" },
1748
+ // ╝
1749
+ 9566: { up: true, down: true, right: true, type: "double" },
1750
+ // ╞
1751
+ 9567: { up: true, down: true, right: true, type: "double" },
1752
+ // ╟
1753
+ 9568: { up: true, down: true, right: true, type: "double" },
1754
+ // ╠
1755
+ 9569: { up: true, down: true, left: true, type: "double" },
1756
+ // ╡
1757
+ 9570: { up: true, down: true, left: true, type: "double" },
1758
+ // ╢
1759
+ 9571: { up: true, down: true, left: true, type: "double" },
1760
+ // ╣
1761
+ 9572: { left: true, right: true, down: true, type: "double" },
1762
+ // ╤
1763
+ 9573: { left: true, right: true, down: true, type: "double" },
1764
+ // ╥
1765
+ 9574: { left: true, right: true, down: true, type: "double" },
1766
+ // ╦
1767
+ 9575: { left: true, right: true, up: true, type: "double" },
1768
+ // ╧
1769
+ 9576: { left: true, right: true, up: true, type: "double" },
1770
+ // ╨
1771
+ 9577: { left: true, right: true, up: true, type: "double" },
1772
+ // ╩
1773
+ 9578: { left: true, right: true, up: true, down: true, type: "double" },
1774
+ // ╪
1775
+ 9579: { left: true, right: true, up: true, down: true, type: "double" },
1776
+ // ╫
1777
+ 9580: { left: true, right: true, up: true, down: true, type: "double" },
1778
+ // ╬
1779
+ // Rounded corners
1780
+ 9581: { right: true, down: true, type: "light", arc: "tl" },
1781
+ // ╭
1782
+ 9582: { left: true, down: true, type: "light", arc: "tr" },
1783
+ // ╮
1784
+ 9583: { left: true, up: true, type: "light", arc: "br" },
1785
+ // ╯
1786
+ 9584: { right: true, up: true, type: "light", arc: "bl" },
1787
+ // ╰
1788
+ // Diagonal lines (render as simple connecting lines)
1789
+ 9585: { type: "light" },
1790
+ // ╱ (forward slash)
1791
+ 9586: { type: "light" },
1792
+ // ╲ (backslash)
1793
+ 9587: { type: "light" },
1794
+ // ╳ (cross)
1795
+ // Half lines
1796
+ 9588: { left: true, type: "light" },
1797
+ // ╴
1798
+ 9589: { up: true, type: "light" },
1799
+ // ╵
1800
+ 9590: { right: true, type: "light" },
1801
+ // ╶
1802
+ 9591: { down: true, type: "light" },
1803
+ // ╷
1804
+ 9592: { left: true, type: "heavy" },
1805
+ // ╸
1806
+ 9593: { up: true, type: "heavy" },
1807
+ // ╹
1808
+ 9594: { right: true, type: "heavy" },
1809
+ // ╺
1810
+ 9595: { down: true, type: "heavy" },
1811
+ // ╻
1812
+ 9596: { left: true, right: true, type: "light" },
1813
+ // ╼ (light left, heavy right)
1814
+ 9597: { up: true, down: true, type: "light" },
1815
+ // ╽ (light up, heavy down)
1816
+ 9598: { left: true, right: true, type: "heavy" },
1817
+ // ╾ (heavy left, light right)
1818
+ 9599: { up: true, down: true, type: "heavy" }
1819
+ // ╿ (heavy up, light down)
1820
+ };
1821
+ var CanvasPainter = class {
1822
+ cellWidth = 0;
1823
+ cellHeight = 0;
1824
+ fontFamily;
1825
+ fontSize;
1826
+ baselineOffset = 0;
1827
+ constructor(options = {}) {
1828
+ this.fontFamily = options.fontFamily ?? "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace";
1829
+ this.fontSize = options.fontSize ?? 14;
1830
+ }
1831
+ measureCell(ctx) {
1832
+ ctx.font = `${this.fontSize}px ${this.fontFamily}`;
1833
+ const metrics = ctx.measureText("M");
1834
+ this.cellWidth = metrics.width;
1835
+ this.cellHeight = Math.ceil(this.fontSize * 1.4);
1836
+ this.baselineOffset = Math.ceil(this.fontSize * 1.1);
1837
+ return { width: this.cellWidth, height: this.cellHeight };
1838
+ }
1839
+ getCellSize() {
1840
+ return { width: this.cellWidth, height: this.cellHeight };
1841
+ }
1842
+ paint(ctx, buffer, selection) {
1843
+ const { char, fg: fg2, bg: bg2, attributes } = buffer;
1844
+ const cols = buffer.width;
1845
+ const rows = buffer.height;
1846
+ const cw = this.cellWidth;
1847
+ const ch = this.cellHeight;
1848
+ for (let row = 0; row < rows; row++) {
1849
+ let runStartCol = 0;
1850
+ let runR = -1, runG = -1, runB = -1, runA = -1;
1851
+ for (let col = 0; col <= cols; col++) {
1852
+ let r = 0, g = 0, b = 0, a = 0;
1853
+ if (col < cols) {
1854
+ const idx = row * cols + col;
1855
+ const offset = idx * 4;
1856
+ const attr = attributes[idx] & 255;
1857
+ const isInverse = !!(attr & TextAttributes2.INVERSE);
1858
+ if (isInverse) {
1859
+ r = fg2[offset];
1860
+ g = fg2[offset + 1];
1861
+ b = fg2[offset + 2];
1862
+ a = fg2[offset + 3];
1863
+ } else {
1864
+ r = bg2[offset];
1865
+ g = bg2[offset + 1];
1866
+ b = bg2[offset + 2];
1867
+ a = bg2[offset + 3];
1868
+ }
1869
+ }
1870
+ if (col < cols && r === runR && g === runG && b === runB && a === runA) {
1871
+ continue;
1872
+ }
1873
+ if (runA > 0 && col > runStartCol) {
1874
+ ctx.fillStyle = rgbaToCSS(runR, runG, runB, runA);
1875
+ ctx.fillRect(runStartCol * cw, row * ch, (col - runStartCol) * cw, ch);
1876
+ }
1877
+ runStartCol = col;
1878
+ runR = r;
1879
+ runG = g;
1880
+ runB = b;
1881
+ runA = a;
1882
+ }
1883
+ }
1884
+ for (let row = 0; row < rows; row++) {
1885
+ for (let col = 0; col < cols; col++) {
1886
+ const idx = row * cols + col;
1887
+ if (attributes[idx] & CONTINUATION2) continue;
1888
+ const charCode = char[idx];
1889
+ if (charCode === 0 || charCode === 32) continue;
1890
+ const offset = idx * 4;
1891
+ const attr = attributes[idx] & 255;
1892
+ const isInverse = !!(attr & TextAttributes2.INVERSE);
1893
+ let fgR, fgG, fgB, fgA;
1894
+ if (isInverse) {
1895
+ fgR = bg2[offset];
1896
+ fgG = bg2[offset + 1];
1897
+ fgB = bg2[offset + 2];
1898
+ fgA = bg2[offset + 3];
1899
+ if (fgA === 0) {
1900
+ fgR = 0;
1901
+ fgG = 0;
1902
+ fgB = 0;
1903
+ fgA = 1;
1904
+ }
1905
+ } else {
1906
+ fgR = fg2[offset];
1907
+ fgG = fg2[offset + 1];
1908
+ fgB = fg2[offset + 2];
1909
+ fgA = fg2[offset + 3];
1910
+ }
1911
+ if (fgA === 0) continue;
1912
+ const isBold = !!(attr & TextAttributes2.BOLD);
1913
+ const isItalic = !!(attr & TextAttributes2.ITALIC);
1914
+ const isDim = !!(attr & TextAttributes2.DIM);
1915
+ const isUnderline = !!(attr & TextAttributes2.UNDERLINE);
1916
+ const effectiveA = isDim ? fgA * 0.5 : fgA;
1917
+ if (charCode >= 9472 && charCode <= 9599) {
1918
+ const def = BOX_DRAWING_MAP[charCode];
1919
+ if (def) {
1920
+ const cellX = col * cw;
1921
+ const cellY = row * ch;
1922
+ const cx = cellX + cw / 2;
1923
+ const cy = cellY + ch / 2;
1924
+ ctx.strokeStyle = rgbaToCSS(fgR, fgG, fgB, effectiveA);
1925
+ ctx.lineCap = "square";
1926
+ if (def.type === "double") {
1927
+ const gap = Math.max(2, Math.round(cw / 5));
1928
+ ctx.lineWidth = 1;
1929
+ ctx.beginPath();
1930
+ if (def.left) {
1931
+ ctx.moveTo(cellX, cy - gap / 2);
1932
+ ctx.lineTo(cx, cy - gap / 2);
1933
+ ctx.moveTo(cellX, cy + gap / 2);
1934
+ ctx.lineTo(cx, cy + gap / 2);
1935
+ }
1936
+ if (def.right) {
1937
+ ctx.moveTo(cx, cy - gap / 2);
1938
+ ctx.lineTo(cellX + cw, cy - gap / 2);
1939
+ ctx.moveTo(cx, cy + gap / 2);
1940
+ ctx.lineTo(cellX + cw, cy + gap / 2);
1941
+ }
1942
+ if (def.up) {
1943
+ ctx.moveTo(cx - gap / 2, cellY);
1944
+ ctx.lineTo(cx - gap / 2, cy);
1945
+ ctx.moveTo(cx + gap / 2, cellY);
1946
+ ctx.lineTo(cx + gap / 2, cy);
1947
+ }
1948
+ if (def.down) {
1949
+ ctx.moveTo(cx - gap / 2, cy);
1950
+ ctx.lineTo(cx - gap / 2, cellY + ch);
1951
+ ctx.moveTo(cx + gap / 2, cy);
1952
+ ctx.lineTo(cx + gap / 2, cellY + ch);
1953
+ }
1954
+ ctx.stroke();
1955
+ } else if (def.arc) {
1956
+ const rx = cw / 2;
1957
+ const ry = ch / 2;
1958
+ ctx.lineWidth = 1;
1959
+ ctx.beginPath();
1960
+ if (def.arc === "tl") {
1961
+ ctx.ellipse(cellX + cw, cellY + ch, rx, ry, 0, Math.PI, Math.PI * 1.5);
1962
+ } else if (def.arc === "tr") {
1963
+ ctx.ellipse(cellX, cellY + ch, rx, ry, 0, Math.PI * 1.5, Math.PI * 2);
1964
+ } else if (def.arc === "bl") {
1965
+ ctx.ellipse(cellX + cw, cellY, rx, ry, 0, Math.PI * 0.5, Math.PI);
1966
+ } else if (def.arc === "br") {
1967
+ ctx.ellipse(cellX, cellY, rx, ry, 0, 0, Math.PI * 0.5);
1968
+ }
1969
+ ctx.stroke();
1970
+ } else if (charCode === 9585 || charCode === 9586 || charCode === 9587) {
1971
+ ctx.lineWidth = 1;
1972
+ ctx.beginPath();
1973
+ if (charCode === 9585 || charCode === 9587) {
1974
+ ctx.moveTo(cellX + cw, cellY);
1975
+ ctx.lineTo(cellX, cellY + ch);
1976
+ }
1977
+ if (charCode === 9586 || charCode === 9587) {
1978
+ ctx.moveTo(cellX, cellY);
1979
+ ctx.lineTo(cellX + cw, cellY + ch);
1980
+ }
1981
+ ctx.stroke();
1982
+ } else {
1983
+ ctx.lineWidth = def.type === "heavy" ? 2 : 1;
1984
+ ctx.beginPath();
1985
+ if (def.left) {
1986
+ ctx.moveTo(cellX, cy);
1987
+ ctx.lineTo(cx, cy);
1988
+ }
1989
+ if (def.right) {
1990
+ ctx.moveTo(cx, cy);
1991
+ ctx.lineTo(cellX + cw, cy);
1992
+ }
1993
+ if (def.up) {
1994
+ ctx.moveTo(cx, cellY);
1995
+ ctx.lineTo(cx, cy);
1996
+ }
1997
+ if (def.down) {
1998
+ ctx.moveTo(cx, cy);
1999
+ ctx.lineTo(cx, cellY + ch);
2000
+ }
2001
+ ctx.stroke();
2002
+ }
2003
+ continue;
2004
+ }
2005
+ }
2006
+ ctx.fillStyle = rgbaToCSS(fgR, fgG, fgB, effectiveA);
2007
+ let fontStyle = "";
2008
+ if (isItalic) fontStyle += "italic ";
2009
+ if (isBold) fontStyle += "bold ";
2010
+ fontStyle += `${this.fontSize}px ${this.fontFamily}`;
2011
+ ctx.font = fontStyle;
2012
+ const character = String.fromCodePoint(charCode);
2013
+ const x = col * cw;
2014
+ const y = row * this.cellHeight + this.baselineOffset;
2015
+ ctx.fillText(character, x, y);
2016
+ if (isUnderline) {
2017
+ const isDashed = !!(attr & TextAttributes2.UNDERLINE_DASHED);
2018
+ const isDotted = !!(attr & TextAttributes2.UNDERLINE_DOTTED);
2019
+ ctx.strokeStyle = ctx.fillStyle;
2020
+ ctx.lineWidth = 1;
2021
+ const underlineY = row * this.cellHeight + this.baselineOffset + 2;
2022
+ if (isDotted) {
2023
+ ctx.lineCap = "round";
2024
+ ctx.setLineDash([0.5, 2.5]);
2025
+ } else if (isDashed) {
2026
+ ctx.setLineDash([2, 2]);
2027
+ }
2028
+ ctx.beginPath();
2029
+ ctx.moveTo(x, underlineY);
2030
+ ctx.lineTo(x + cw, underlineY);
2031
+ ctx.stroke();
2032
+ if (isDotted || isDashed) {
2033
+ ctx.setLineDash([]);
2034
+ ctx.lineCap = "butt";
2035
+ }
2036
+ }
2037
+ }
2038
+ }
2039
+ if (selection?.active) {
2040
+ ctx.fillStyle = "rgba(51, 153, 255, 0.3)";
2041
+ for (let row = 0; row < rows; row++) {
2042
+ let runStart = -1;
2043
+ for (let col = 0; col <= cols; col++) {
2044
+ const selected = col < cols && selection.isSelected(col, row);
2045
+ if (selected && runStart === -1) {
2046
+ runStart = col;
2047
+ } else if (!selected && runStart !== -1) {
2048
+ ctx.fillRect(runStart * cw, row * ch, (col - runStart) * cw, ch);
2049
+ runStart = -1;
2050
+ }
2051
+ }
2052
+ }
2053
+ }
2054
+ }
2055
+ };
2056
+ function rgbaToCSS(r, g, b, a) {
2057
+ const ri = Math.round(r * 255);
2058
+ const gi = Math.round(g * 255);
2059
+ const bi = Math.round(b * 255);
2060
+ return `rgba(${ri},${gi},${bi},${a})`;
2061
+ }
2062
+
2063
+ // src/selection-manager.ts
2064
+ var SelectionManager = class {
2065
+ _startCol = 0;
2066
+ _startRow = 0;
2067
+ _endCol = 0;
2068
+ _endRow = 0;
2069
+ _active = false;
2070
+ _selecting = false;
2071
+ startSelection(col, row) {
2072
+ this._startCol = col;
2073
+ this._startRow = row;
2074
+ this._endCol = col;
2075
+ this._endRow = row;
2076
+ this._selecting = true;
2077
+ this._active = true;
2078
+ }
2079
+ updateSelection(col, row) {
2080
+ if (!this._selecting) return;
2081
+ this._endCol = col;
2082
+ this._endRow = row;
2083
+ }
2084
+ endSelection() {
2085
+ this._selecting = false;
2086
+ if (this._startCol === this._endCol && this._startRow === this._endRow) {
2087
+ this._active = false;
2088
+ }
2089
+ }
2090
+ clearSelection() {
2091
+ this._active = false;
2092
+ this._selecting = false;
2093
+ }
2094
+ get active() {
2095
+ return this._active;
2096
+ }
2097
+ get selecting() {
2098
+ return this._selecting;
2099
+ }
2100
+ /** Returns the selection range normalized to reading order (top-left to bottom-right) */
2101
+ getSelectedRange() {
2102
+ if (!this._active) return null;
2103
+ let startCol = this._startCol;
2104
+ let startRow = this._startRow;
2105
+ let endCol = this._endCol;
2106
+ let endRow = this._endRow;
2107
+ if (startRow > endRow || startRow === endRow && startCol > endCol) {
2108
+ const tmpCol = startCol;
2109
+ const tmpRow = startRow;
2110
+ startCol = endCol;
2111
+ startRow = endRow;
2112
+ endCol = tmpCol;
2113
+ endRow = tmpRow;
2114
+ }
2115
+ return { startCol, startRow, endCol, endRow };
2116
+ }
2117
+ isSelected(col, row) {
2118
+ const range = this.getSelectedRange();
2119
+ if (!range) return false;
2120
+ const { startCol, startRow, endCol, endRow } = range;
2121
+ if (row < startRow || row > endRow) return false;
2122
+ if (startRow === endRow) {
2123
+ return col >= startCol && col < endCol;
2124
+ }
2125
+ if (row === startRow) return col >= startCol;
2126
+ if (row === endRow) return col < endCol;
2127
+ return true;
2128
+ }
2129
+ getSelectedText(buffer) {
2130
+ const range = this.getSelectedRange();
2131
+ if (!range) return "";
2132
+ const { startCol, startRow, endCol, endRow } = range;
2133
+ const lines = [];
2134
+ for (let row = startRow; row <= endRow; row++) {
2135
+ let lineStart = row === startRow ? startCol : 0;
2136
+ let lineEnd = row === endRow ? endCol : buffer.width;
2137
+ let line = "";
2138
+ for (let col = lineStart; col < lineEnd && col < buffer.width; col++) {
2139
+ const idx = row * buffer.width + col;
2140
+ const charCode = buffer.char[idx];
2141
+ line += charCode === 0 ? " " : String.fromCodePoint(charCode);
2142
+ }
2143
+ lines.push(line.trimEnd());
2144
+ }
2145
+ return lines.join("\n");
2146
+ }
2147
+ };
2148
+
2149
+ // src/browser-renderer.ts
2150
+ var RootRenderableClass = null;
2151
+ function setRootRenderableClass(cls) {
2152
+ RootRenderableClass = cls;
2153
+ }
2154
+ var BrowserRenderer = class _BrowserRenderer {
2155
+ canvas;
2156
+ ctx2d;
2157
+ buffer;
2158
+ renderContext;
2159
+ root;
2160
+ // RootRenderable
2161
+ painter;
2162
+ selection;
2163
+ cols;
2164
+ rows;
2165
+ cellWidth = 0;
2166
+ cellHeight = 0;
2167
+ rafId = null;
2168
+ lastTime = 0;
2169
+ needsRender = true;
2170
+ isDragOver = false;
2171
+ cleanupListeners = [];
2172
+ mouseDownCell = null;
2173
+ constructor(canvas, cols, rows) {
2174
+ this.canvas = canvas;
2175
+ this.cols = cols;
2176
+ this.rows = rows;
2177
+ const ctx2d = canvas.getContext("2d");
2178
+ if (!ctx2d) throw new Error("Could not get 2d context");
2179
+ this.ctx2d = ctx2d;
2180
+ this.painter = new CanvasPainter();
2181
+ const cellSize = this.painter.measureCell(this.ctx2d);
2182
+ this.cellWidth = cellSize.width;
2183
+ this.cellHeight = cellSize.height;
2184
+ const dpr = window.devicePixelRatio || 1;
2185
+ canvas.width = Math.ceil(cols * this.cellWidth * dpr);
2186
+ canvas.height = Math.ceil(rows * this.cellHeight * dpr);
2187
+ canvas.style.width = `${cols * this.cellWidth}px`;
2188
+ canvas.style.height = `${rows * this.cellHeight}px`;
2189
+ this.ctx2d.scale(dpr, dpr);
2190
+ canvas.style.cursor = "text";
2191
+ this.buffer = BrowserBuffer.create(cols, rows, "wcwidth");
2192
+ this.renderContext = new BrowserRenderContext(cols, rows);
2193
+ this.renderContext.setOnRenderRequest(() => {
2194
+ this.needsRender = true;
2195
+ });
2196
+ this.selection = new SelectionManager();
2197
+ if (!RootRenderableClass) {
2198
+ throw new Error("RootRenderableClass not set. Call setRootRenderableClass before creating BrowserRenderer.");
2199
+ }
2200
+ this.root = new RootRenderableClass(this.renderContext);
2201
+ this.setupDomListeners();
2202
+ }
2203
+ pixelToCell(clientX, clientY) {
2204
+ const rect = this.canvas.getBoundingClientRect();
2205
+ const x = clientX - rect.left;
2206
+ const y = clientY - rect.top;
2207
+ const col = Math.floor(x / this.cellWidth);
2208
+ const row = Math.floor(y / this.cellHeight);
2209
+ return {
2210
+ col: Math.max(0, Math.min(col, this.cols - 1)),
2211
+ row: Math.max(0, Math.min(row, this.rows - 1))
2212
+ };
2213
+ }
2214
+ setupDomListeners() {
2215
+ const onDragOver = (e) => {
2216
+ e.preventDefault();
2217
+ };
2218
+ this.canvas.addEventListener("dragover", onDragOver);
2219
+ this.cleanupListeners.push(() => this.canvas.removeEventListener("dragover", onDragOver));
2220
+ const onDrop = (e) => {
2221
+ e.preventDefault();
2222
+ const files = e.dataTransfer?.files;
2223
+ if (!files || files.length === 0) return;
2224
+ const file = files[0];
2225
+ this.isDragOver = false;
2226
+ this.renderContext.emit("drag-leave", void 0);
2227
+ file.text().then((content) => {
2228
+ this.renderContext.emit("file-drop", {
2229
+ name: file.name,
2230
+ content,
2231
+ type: file.type,
2232
+ size: file.size
2233
+ });
2234
+ });
2235
+ };
2236
+ this.canvas.addEventListener("drop", onDrop);
2237
+ this.cleanupListeners.push(() => this.canvas.removeEventListener("drop", onDrop));
2238
+ const onMouseDown = (e) => {
2239
+ if (e.button !== 0) return;
2240
+ this.canvas.focus();
2241
+ const { col, row } = this.pixelToCell(e.clientX, e.clientY);
2242
+ this.mouseDownCell = { col, row };
2243
+ this.selection.startSelection(col, row);
2244
+ this.needsRender = true;
2245
+ };
2246
+ this.canvas.addEventListener("mousedown", onMouseDown);
2247
+ this.cleanupListeners.push(() => this.canvas.removeEventListener("mousedown", onMouseDown));
2248
+ const onMouseMove = (e) => {
2249
+ const { col, row } = this.pixelToCell(e.clientX, e.clientY);
2250
+ const idx = row * this.buffer.width + col;
2251
+ if (idx >= 0 && idx < this.buffer.attributes.length) {
2252
+ const linkId = getLinkId(this.buffer.attributes[idx]);
2253
+ this.canvas.style.cursor = linkId > 0 ? "pointer" : "text";
2254
+ }
2255
+ if (!this.selection.selecting) return;
2256
+ this.selection.updateSelection(col, row);
2257
+ this.needsRender = true;
2258
+ };
2259
+ this.canvas.addEventListener("mousemove", onMouseMove);
2260
+ this.cleanupListeners.push(() => this.canvas.removeEventListener("mousemove", onMouseMove));
2261
+ const onMouseUp = (e) => {
2262
+ const wasSelecting = this.selection.selecting;
2263
+ if (wasSelecting) {
2264
+ this.selection.endSelection();
2265
+ this.needsRender = true;
2266
+ }
2267
+ if (e.button === 0 && this.mouseDownCell) {
2268
+ const { col, row } = this.pixelToCell(e.clientX, e.clientY);
2269
+ if (col === this.mouseDownCell.col && row === this.mouseDownCell.row) {
2270
+ const idx = row * this.buffer.width + col;
2271
+ if (idx >= 0 && idx < this.buffer.attributes.length) {
2272
+ const attr = this.buffer.attributes[idx];
2273
+ const linkId = getLinkId(attr);
2274
+ if (linkId > 0) {
2275
+ const url = this.buffer.getLinkUrl(linkId);
2276
+ if (url) {
2277
+ window.open(url, "_blank");
2278
+ }
2279
+ }
2280
+ }
2281
+ }
2282
+ this.mouseDownCell = null;
2283
+ }
2284
+ };
2285
+ window.addEventListener("mouseup", onMouseUp);
2286
+ this.cleanupListeners.push(() => window.removeEventListener("mouseup", onMouseUp));
2287
+ const onDragEnter = (e) => {
2288
+ e.preventDefault();
2289
+ if (this.isDragOver) return;
2290
+ this.isDragOver = true;
2291
+ this.renderContext.emit("drag-enter", void 0);
2292
+ this.needsRender = true;
2293
+ };
2294
+ this.canvas.addEventListener("dragenter", onDragEnter);
2295
+ this.cleanupListeners.push(() => this.canvas.removeEventListener("dragenter", onDragEnter));
2296
+ const onDragLeave = (e) => {
2297
+ if (e.relatedTarget && this.canvas.contains(e.relatedTarget)) return;
2298
+ this.isDragOver = false;
2299
+ this.renderContext.emit("drag-leave", void 0);
2300
+ this.needsRender = true;
2301
+ };
2302
+ this.canvas.addEventListener("dragleave", onDragLeave);
2303
+ this.cleanupListeners.push(() => this.canvas.removeEventListener("dragleave", onDragLeave));
2304
+ const onPaste = (e) => {
2305
+ if (document.activeElement !== this.canvas) return;
2306
+ const text = e.clipboardData?.getData("text/plain");
2307
+ if (text) {
2308
+ e.preventDefault();
2309
+ this.renderContext.emit("paste", text);
2310
+ }
2311
+ };
2312
+ document.addEventListener("paste", onPaste);
2313
+ this.cleanupListeners.push(() => document.removeEventListener("paste", onPaste));
2314
+ }
2315
+ start() {
2316
+ this.lastTime = performance.now();
2317
+ this.loop();
2318
+ }
2319
+ stop() {
2320
+ if (this.rafId !== null) {
2321
+ cancelAnimationFrame(this.rafId);
2322
+ this.rafId = null;
2323
+ }
2324
+ for (const cleanup of this.cleanupListeners) {
2325
+ cleanup();
2326
+ }
2327
+ this.cleanupListeners = [];
2328
+ }
2329
+ loop = () => {
2330
+ this.rafId = requestAnimationFrame(this.loop);
2331
+ const now = performance.now();
2332
+ const deltaTime = now - this.lastTime;
2333
+ this.lastTime = now;
2334
+ if (!this.needsRender) return;
2335
+ this.needsRender = false;
2336
+ this.buffer.clear();
2337
+ const lifecyclePasses = this.renderContext.getLifecyclePasses();
2338
+ for (const renderable of lifecyclePasses) {
2339
+ if (renderable.onLifecyclePass) {
2340
+ renderable.onLifecyclePass();
2341
+ }
2342
+ }
2343
+ this.root.calculateLayout();
2344
+ const renderList = [];
2345
+ this.root.updateLayout(deltaTime, renderList);
2346
+ for (const cmd of renderList) {
2347
+ switch (cmd.action) {
2348
+ case "pushScissorRect":
2349
+ this.buffer.pushScissorRect(cmd.x, cmd.y, cmd.width, cmd.height);
2350
+ break;
2351
+ case "popScissorRect":
2352
+ this.buffer.popScissorRect();
2353
+ break;
2354
+ case "pushOpacity":
2355
+ this.buffer.pushOpacity(cmd.opacity);
2356
+ break;
2357
+ case "popOpacity":
2358
+ this.buffer.popOpacity();
2359
+ break;
2360
+ case "render":
2361
+ cmd.renderable.render(this.buffer, deltaTime);
2362
+ break;
2363
+ }
2364
+ }
2365
+ this.buffer.clearScissorRects();
2366
+ this.buffer.clearOpacity();
2367
+ const dpr = window.devicePixelRatio || 1;
2368
+ this.ctx2d.setTransform(dpr, 0, 0, dpr, 0, 0);
2369
+ this.ctx2d.clearRect(0, 0, this.canvas.width, this.canvas.height);
2370
+ this.painter.paint(this.ctx2d, this.buffer, this.selection);
2371
+ };
2372
+ resize(cols, rows) {
2373
+ this.cols = cols;
2374
+ this.rows = rows;
2375
+ const dpr = window.devicePixelRatio || 1;
2376
+ this.canvas.width = Math.ceil(cols * this.cellWidth * dpr);
2377
+ this.canvas.height = Math.ceil(rows * this.cellHeight * dpr);
2378
+ this.canvas.style.width = `${cols * this.cellWidth}px`;
2379
+ this.canvas.style.height = `${rows * this.cellHeight}px`;
2380
+ this.ctx2d.scale(dpr, dpr);
2381
+ this.buffer.resize(cols, rows);
2382
+ this.renderContext.resize(cols, rows);
2383
+ this.root.resize(cols, rows);
2384
+ this.needsRender = true;
2385
+ }
2386
+ static PREVENT_DEFAULT_KEYS = /* @__PURE__ */ new Set([
2387
+ "ArrowUp",
2388
+ "ArrowDown",
2389
+ "ArrowLeft",
2390
+ "ArrowRight",
2391
+ " ",
2392
+ "PageUp",
2393
+ "PageDown",
2394
+ "Tab",
2395
+ "Home",
2396
+ "End"
2397
+ ]);
2398
+ static MODIFIER_KEYS = /* @__PURE__ */ new Set(["Alt", "Control", "Meta", "Shift"]);
2399
+ static KEY_MAP = {
2400
+ ArrowUp: "up",
2401
+ ArrowDown: "down",
2402
+ ArrowLeft: "left",
2403
+ ArrowRight: "right",
2404
+ Enter: "return",
2405
+ Backspace: "backspace",
2406
+ Delete: "delete",
2407
+ Tab: "tab",
2408
+ Escape: "escape",
2409
+ Home: "home",
2410
+ End: "end",
2411
+ " ": "space",
2412
+ PageUp: "pageup",
2413
+ PageDown: "pagedown"
2414
+ };
2415
+ handleKeyDown(event) {
2416
+ if (_BrowserRenderer.PREVENT_DEFAULT_KEYS.has(event.key)) {
2417
+ event.preventDefault();
2418
+ }
2419
+ if (this.selection.active && (event.key === "c" || event.key === "\xE7") && (event.metaKey || event.ctrlKey || event.altKey)) {
2420
+ const text = this.selection.getSelectedText(this.buffer);
2421
+ if (text) {
2422
+ navigator.clipboard.writeText(text).catch(() => {
2423
+ const ta = document.createElement("textarea");
2424
+ ta.value = text;
2425
+ ta.style.position = "fixed";
2426
+ ta.style.left = "-9999px";
2427
+ document.body.appendChild(ta);
2428
+ ta.select();
2429
+ document.execCommand("copy");
2430
+ document.body.removeChild(ta);
2431
+ });
2432
+ }
2433
+ event.preventDefault();
2434
+ return;
2435
+ }
2436
+ const modifierOnly = _BrowserRenderer.MODIFIER_KEYS.has(event.key);
2437
+ if (this.selection.active && !modifierOnly) {
2438
+ this.selection.clearSelection();
2439
+ this.needsRender = true;
2440
+ }
2441
+ const keyEvent = {
2442
+ name: _BrowserRenderer.KEY_MAP[event.key] ?? (event.key.length === 1 ? event.key : event.key.toLowerCase()),
2443
+ ctrl: event.ctrlKey,
2444
+ meta: event.metaKey,
2445
+ shift: event.shiftKey,
2446
+ option: event.altKey,
2447
+ sequence: event.key,
2448
+ number: false,
2449
+ raw: event.key,
2450
+ eventType: "press",
2451
+ source: "raw",
2452
+ _defaultPrevented: false,
2453
+ _propagationStopped: false,
2454
+ get defaultPrevented() {
2455
+ return this._defaultPrevented;
2456
+ },
2457
+ get propagationStopped() {
2458
+ return this._propagationStopped;
2459
+ },
2460
+ preventDefault() {
2461
+ this._defaultPrevented = true;
2462
+ },
2463
+ stopPropagation() {
2464
+ this._propagationStopped = true;
2465
+ }
2466
+ };
2467
+ this.renderContext._internalKeyInput.emit("keypress", keyEvent);
2468
+ this.renderContext.keyInput.emit("keypress", keyEvent);
2469
+ }
2470
+ };
2471
+
2472
+ // src/browser-context.ts
2473
+ import { createContext, useContext } from "react";
2474
+ var BrowserContext = createContext(null);
2475
+
2476
+ // src/create-browser-root.tsx
2477
+ import { _render } from "../../../opentui/packages/react/src/reconciler/reconciler";
2478
+ import { AppContext } from "../../../opentui/packages/react/src/components/app";
2479
+ import { ErrorBoundary } from "../../../opentui/packages/react/src/components/error-boundary";
2480
+ import { jsx } from "react/jsx-runtime";
2481
+ function createBrowserRoot(renderer) {
2482
+ let unmountFn = null;
2483
+ return {
2484
+ render(node) {
2485
+ const element = /* @__PURE__ */ jsx(BrowserContext.Provider, { value: { renderContext: renderer.renderContext }, children: /* @__PURE__ */ jsx(AppContext.Provider, { value: { keyHandler: renderer.renderContext.keyInput, renderer: null }, children: /* @__PURE__ */ jsx(ErrorBoundary, { children: node }) }) });
2486
+ unmountFn = _render(element, renderer.root);
2487
+ },
2488
+ unmount() {
2489
+ if (unmountFn) {
2490
+ }
2491
+ }
2492
+ };
2493
+ }
2494
+
2495
+ // src/TUI.tsx
2496
+ import { RootRenderable as RootRenderable2 } from "@opentui/core";
2497
+ import { jsx as jsx2 } from "react/jsx-runtime";
2498
+ function TUI({
2499
+ children,
2500
+ style,
2501
+ className,
2502
+ fontSize = 14,
2503
+ fontFamily = "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace",
2504
+ autoFocus = true,
2505
+ onReady
2506
+ }) {
2507
+ const containerRef = useRef(null);
2508
+ const canvasRef = useRef(null);
2509
+ const rendererRef = useRef(null);
2510
+ const rootRef = useRef(null);
2511
+ const [isClient, setIsClient] = useState(false);
2512
+ useEffect(() => {
2513
+ setIsClient(true);
2514
+ }, []);
2515
+ useEffect(() => {
2516
+ if (!isClient) return;
2517
+ const canvas = canvasRef.current;
2518
+ const container = containerRef.current;
2519
+ if (!canvas || !container) return;
2520
+ setRootRenderableClass(RootRenderable2);
2521
+ const painter = new CanvasPainter({ fontSize, fontFamily });
2522
+ const tempCtx = canvas.getContext("2d");
2523
+ const cellSize = painter.measureCell(tempCtx);
2524
+ const containerRect = container.getBoundingClientRect();
2525
+ const cols = Math.max(1, Math.floor(containerRect.width / cellSize.width));
2526
+ const rows = Math.max(1, Math.floor(containerRect.height / cellSize.height));
2527
+ const renderer = new BrowserRenderer(canvas, cols, rows);
2528
+ rendererRef.current = renderer;
2529
+ const root = createBrowserRoot(renderer);
2530
+ rootRef.current = root;
2531
+ root.render(children);
2532
+ renderer.start();
2533
+ canvas.tabIndex = 0;
2534
+ if (autoFocus) {
2535
+ canvas.focus();
2536
+ }
2537
+ onReady?.(renderer);
2538
+ const onKeyDown = (e) => {
2539
+ renderer.handleKeyDown(e);
2540
+ };
2541
+ canvas.addEventListener("keydown", onKeyDown);
2542
+ const resizeObserver = new ResizeObserver((entries) => {
2543
+ for (const entry of entries) {
2544
+ const { width, height } = entry.contentRect;
2545
+ const newCols = Math.max(1, Math.floor(width / cellSize.width));
2546
+ const newRows = Math.max(1, Math.floor(height / cellSize.height));
2547
+ renderer.resize(newCols, newRows);
2548
+ }
2549
+ });
2550
+ resizeObserver.observe(container);
2551
+ return () => {
2552
+ canvas.removeEventListener("keydown", onKeyDown);
2553
+ resizeObserver.disconnect();
2554
+ renderer.stop();
2555
+ root.unmount();
2556
+ rendererRef.current = null;
2557
+ rootRef.current = null;
2558
+ };
2559
+ }, [isClient, fontSize, fontFamily]);
2560
+ useEffect(() => {
2561
+ if (rootRef.current) {
2562
+ rootRef.current.render(children);
2563
+ }
2564
+ }, [children]);
2565
+ if (!isClient) {
2566
+ return /* @__PURE__ */ jsx2("div", { style, className, children: /* @__PURE__ */ jsx2("div", { style: { width: "100%", height: "100%" } }) });
2567
+ }
2568
+ return /* @__PURE__ */ jsx2(
2569
+ "div",
2570
+ {
2571
+ ref: containerRef,
2572
+ style: {
2573
+ position: "relative",
2574
+ overflow: "hidden",
2575
+ ...style
2576
+ },
2577
+ className,
2578
+ children: /* @__PURE__ */ jsx2(
2579
+ "canvas",
2580
+ {
2581
+ ref: canvasRef,
2582
+ style: {
2583
+ display: "block",
2584
+ width: "100%",
2585
+ height: "100%",
2586
+ outline: "none"
2587
+ }
2588
+ }
2589
+ )
2590
+ }
2591
+ );
2592
+ }
2593
+ export {
2594
+ TUI
2595
+ };
2596
+ //# sourceMappingURL=next.js.map