@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.
@@ -0,0 +1,22 @@
1
+ type WebpackConfig = any;
2
+ type WebpackInstance = any;
3
+ interface NextConfig {
4
+ webpack?: (config: WebpackConfig, context: {
5
+ isServer: boolean;
6
+ webpack: WebpackInstance;
7
+ }) => WebpackConfig;
8
+ [key: string]: any;
9
+ }
10
+ /**
11
+ * Next.js plugin that configures webpack for Gridland.
12
+ * Equivalent to `gridlandWebPlugin()` for Vite — handles module aliases,
13
+ * FFI shims, tree-sitter stubs, Node.js built-in stubs, and circular
14
+ * dependency fixes.
15
+ *
16
+ * Requires @opentui/core, @opentui/react, and @opentui/ui as peer dependencies.
17
+ *
18
+ * @param nextConfig - Optional additional Next.js config to merge
19
+ */
20
+ declare function withGridland(nextConfig?: NextConfig): NextConfig;
21
+
22
+ export { withGridland };
@@ -0,0 +1,22 @@
1
+ type WebpackConfig = any;
2
+ type WebpackInstance = any;
3
+ interface NextConfig {
4
+ webpack?: (config: WebpackConfig, context: {
5
+ isServer: boolean;
6
+ webpack: WebpackInstance;
7
+ }) => WebpackConfig;
8
+ [key: string]: any;
9
+ }
10
+ /**
11
+ * Next.js plugin that configures webpack for Gridland.
12
+ * Equivalent to `gridlandWebPlugin()` for Vite — handles module aliases,
13
+ * FFI shims, tree-sitter stubs, Node.js built-in stubs, and circular
14
+ * dependency fixes.
15
+ *
16
+ * Requires @opentui/core, @opentui/react, and @opentui/ui as peer dependencies.
17
+ *
18
+ * @param nextConfig - Optional additional Next.js config to merge
19
+ */
20
+ declare function withGridland(nextConfig?: NextConfig): NextConfig;
21
+
22
+ export { withGridland };
@@ -0,0 +1,112 @@
1
+ // src/next-plugin.ts
2
+ import path from "path";
3
+ function withGridland(nextConfig = {}) {
4
+ const pkgRoot = path.resolve(__dirname, "..");
5
+ const opentuiRoot = path.resolve(pkgRoot, "../../opentui");
6
+ const coreRoot = path.resolve(opentuiRoot, "packages/core");
7
+ const reactRoot = path.resolve(opentuiRoot, "packages/react");
8
+ const uiRoot = path.resolve(opentuiRoot, "packages/ui");
9
+ function shimPath(p) {
10
+ return path.resolve(pkgRoot, p);
11
+ }
12
+ const coreFileShims = {
13
+ zig: "src/shims/zig-stub.ts",
14
+ buffer: "src/browser-buffer.ts",
15
+ "text-buffer": "src/shims/text-buffer-shim.ts",
16
+ "text-buffer-view": "src/shims/text-buffer-view-shim.ts",
17
+ "syntax-style": "src/shims/syntax-style-shim.ts",
18
+ renderer: "src/shims/renderer-stub.ts",
19
+ console: "src/shims/console-stub.ts",
20
+ "edit-buffer": "src/shims/edit-buffer-stub.ts",
21
+ "editor-view": "src/shims/editor-view-stub.ts",
22
+ NativeSpanFeed: "src/shims/native-span-feed-stub.ts",
23
+ "post/filters": "src/shims/filters-stub.ts",
24
+ "animation/Timeline": "src/shims/timeline-stub.ts"
25
+ };
26
+ const userWebpack = nextConfig.webpack;
27
+ return {
28
+ ...nextConfig,
29
+ webpack: (config, context) => {
30
+ const { isServer, webpack } = context;
31
+ if (userWebpack) {
32
+ config = userWebpack(config, context);
33
+ }
34
+ const sharedAliases = {
35
+ // @opentui packages — core-shims includes all exports @opentui/react needs
36
+ "@opentui/core": shimPath("src/core-shims/index.ts"),
37
+ "@opentui/react": path.resolve(reactRoot, "src/index.ts"),
38
+ "@opentui/ui": path.resolve(uiRoot, "src/index.ts"),
39
+ // FFI shims (no Zig/Bun on server or client in browser context)
40
+ "bun:ffi": shimPath("src/shims/bun-ffi.ts"),
41
+ "bun-ffi-structs": shimPath("src/shims/bun-ffi-structs.ts"),
42
+ bun: shimPath("src/shims/bun-ffi.ts"),
43
+ // Tree-sitter stubs — IMPORTANT: longer prefix must come first to avoid
44
+ // "tree-sitter" matching "tree-sitter-styled-text" (webpack prefix match)
45
+ "tree-sitter-styled-text": shimPath("src/shims/tree-sitter-styled-text-stub.ts"),
46
+ "web-tree-sitter": shimPath("src/shims/tree-sitter-stub.ts"),
47
+ "hast-styled-text": shimPath("src/shims/hast-stub.ts"),
48
+ // Internal tree-sitter source directories (pulled in via renderable imports)
49
+ [path.resolve(coreRoot, "src/lib/tree-sitter-styled-text")]: shimPath("src/shims/tree-sitter-styled-text-stub.ts"),
50
+ [path.resolve(coreRoot, "src/lib/tree-sitter")]: shimPath("src/shims/tree-sitter-stub.ts"),
51
+ [path.resolve(coreRoot, "src/lib/hast-styled-text")]: shimPath("src/shims/hast-stub.ts"),
52
+ // Devtools polyfill stub (original uses top-level await for ws import)
53
+ [path.resolve(reactRoot, "src/reconciler/devtools-polyfill")]: shimPath("src/shims/devtools-polyfill-stub.ts")
54
+ };
55
+ for (const [key, shimFile] of Object.entries(coreFileShims)) {
56
+ sharedAliases[path.resolve(coreRoot, "src", key)] = shimPath(shimFile);
57
+ }
58
+ config.resolve = config.resolve || {};
59
+ config.resolve.alias = {
60
+ ...config.resolve.alias,
61
+ ...sharedAliases
62
+ };
63
+ const renderablesDir = path.resolve(coreRoot, "src/renderables");
64
+ config.plugins.push(
65
+ new webpack.NormalModuleReplacementPlugin(/^\.\.\/index$/, (resource) => {
66
+ if (resource.context === renderablesDir) {
67
+ resource.request = shimPath("src/shims/slider-deps.ts");
68
+ }
69
+ })
70
+ );
71
+ if (!isServer) {
72
+ const clientAliases = {
73
+ "node:console": shimPath("src/shims/console.ts"),
74
+ "events$": shimPath("src/shims/events-shim.ts"),
75
+ "fs/promises": shimPath("src/shims/node-fs.ts"),
76
+ "fs$": shimPath("src/shims/node-fs.ts"),
77
+ "path$": shimPath("src/shims/node-path.ts"),
78
+ "util$": shimPath("src/shims/node-util.ts"),
79
+ "os$": shimPath("src/shims/node-os.ts"),
80
+ "stream$": shimPath("src/shims/node-stream.ts"),
81
+ "url$": shimPath("src/shims/node-url.ts")
82
+ };
83
+ config.resolve.alias = {
84
+ ...config.resolve.alias,
85
+ ...clientAliases
86
+ };
87
+ config.resolve.modules = [
88
+ ...config.resolve.modules || [],
89
+ path.resolve(pkgRoot, "node_modules"),
90
+ path.resolve(pkgRoot, "../../node_modules")
91
+ ];
92
+ config.plugins.push(
93
+ new webpack.NormalModuleReplacementPlugin(/^node:/, (resource) => {
94
+ resource.request = resource.request.replace(/^node:/, "");
95
+ }),
96
+ new webpack.NormalModuleReplacementPlugin(/^bun:/, (resource) => {
97
+ resource.request = resource.request.replace(/^bun:/, "");
98
+ })
99
+ );
100
+ }
101
+ config.experiments = {
102
+ ...config.experiments,
103
+ topLevelAwait: true
104
+ };
105
+ return config;
106
+ }
107
+ };
108
+ }
109
+ export {
110
+ withGridland
111
+ };
112
+ //# sourceMappingURL=next-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/next-plugin.ts"],"sourcesContent":["import path from \"path\"\n\ntype WebpackConfig = any\ntype WebpackInstance = any\n\ninterface NextConfig {\n webpack?: (config: WebpackConfig, context: { isServer: boolean; webpack: WebpackInstance }) => WebpackConfig\n [key: string]: any\n}\n\n/**\n * Next.js plugin that configures webpack for Gridland.\n * Equivalent to `gridlandWebPlugin()` for Vite — handles module aliases,\n * FFI shims, tree-sitter stubs, Node.js built-in stubs, and circular\n * dependency fixes.\n *\n * Requires @opentui/core, @opentui/react, and @opentui/ui as peer dependencies.\n *\n * @param nextConfig - Optional additional Next.js config to merge\n */\nexport function withGridland(nextConfig: NextConfig = {}): NextConfig {\n // __dirname works natively in CJS; tsup shims it for ESM via import.meta.url\n const pkgRoot = path.resolve(__dirname, \"..\")\n\n // Resolve opentui package roots from the git submodule\n const opentuiRoot = path.resolve(pkgRoot, \"../../opentui\")\n const coreRoot = path.resolve(opentuiRoot, \"packages/core\")\n const reactRoot = path.resolve(opentuiRoot, \"packages/react\")\n const uiRoot = path.resolve(opentuiRoot, \"packages/ui\")\n\n function shimPath(p: string) {\n return path.resolve(pkgRoot, p)\n }\n\n // Core shims — same mappings as the Vite plugin\n const coreFileShims: Record<string, string> = {\n zig: \"src/shims/zig-stub.ts\",\n buffer: \"src/browser-buffer.ts\",\n \"text-buffer\": \"src/shims/text-buffer-shim.ts\",\n \"text-buffer-view\": \"src/shims/text-buffer-view-shim.ts\",\n \"syntax-style\": \"src/shims/syntax-style-shim.ts\",\n renderer: \"src/shims/renderer-stub.ts\",\n console: \"src/shims/console-stub.ts\",\n \"edit-buffer\": \"src/shims/edit-buffer-stub.ts\",\n \"editor-view\": \"src/shims/editor-view-stub.ts\",\n NativeSpanFeed: \"src/shims/native-span-feed-stub.ts\",\n \"post/filters\": \"src/shims/filters-stub.ts\",\n \"animation/Timeline\": \"src/shims/timeline-stub.ts\",\n }\n\n const userWebpack = nextConfig.webpack\n\n return {\n ...nextConfig,\n webpack: (config: WebpackConfig, context: { isServer: boolean; webpack: WebpackInstance }) => {\n const { isServer, webpack } = context\n\n // Chain user's webpack config first if provided\n if (userWebpack) {\n config = userWebpack(config, context)\n }\n\n // Aliases needed on BOTH server and client (opentui packages, FFI stubs,\n // tree-sitter stubs, core file shims). The server doesn't actually render\n // the TUI but still walks the module graph for \"use client\" components.\n const sharedAliases: Record<string, string> = {\n // @opentui packages — core-shims includes all exports @opentui/react needs\n \"@opentui/core\": shimPath(\"src/core-shims/index.ts\"),\n \"@opentui/react\": path.resolve(reactRoot, \"src/index.ts\"),\n \"@opentui/ui\": path.resolve(uiRoot, \"src/index.ts\"),\n\n // FFI shims (no Zig/Bun on server or client in browser context)\n \"bun:ffi\": shimPath(\"src/shims/bun-ffi.ts\"),\n \"bun-ffi-structs\": shimPath(\"src/shims/bun-ffi-structs.ts\"),\n bun: shimPath(\"src/shims/bun-ffi.ts\"),\n\n // Tree-sitter stubs — IMPORTANT: longer prefix must come first to avoid\n // \"tree-sitter\" matching \"tree-sitter-styled-text\" (webpack prefix match)\n \"tree-sitter-styled-text\": shimPath(\"src/shims/tree-sitter-styled-text-stub.ts\"),\n \"web-tree-sitter\": shimPath(\"src/shims/tree-sitter-stub.ts\"),\n \"hast-styled-text\": shimPath(\"src/shims/hast-stub.ts\"),\n // Internal tree-sitter source directories (pulled in via renderable imports)\n [path.resolve(coreRoot, \"src/lib/tree-sitter-styled-text\")]:\n shimPath(\"src/shims/tree-sitter-styled-text-stub.ts\"),\n [path.resolve(coreRoot, \"src/lib/tree-sitter\")]:\n shimPath(\"src/shims/tree-sitter-stub.ts\"),\n [path.resolve(coreRoot, \"src/lib/hast-styled-text\")]:\n shimPath(\"src/shims/hast-stub.ts\"),\n\n // Devtools polyfill stub (original uses top-level await for ws import)\n [path.resolve(reactRoot, \"src/reconciler/devtools-polyfill\")]:\n shimPath(\"src/shims/devtools-polyfill-stub.ts\"),\n }\n\n // Core file shims (opentui source → browser shim)\n for (const [key, shimFile] of Object.entries(coreFileShims)) {\n sharedAliases[path.resolve(coreRoot, \"src\", key)] = shimPath(shimFile)\n }\n\n config.resolve = config.resolve || {}\n config.resolve.alias = {\n ...config.resolve.alias,\n ...sharedAliases,\n }\n\n // Slider circular dependency fix: Slider.ts imports from \"../index\" which\n // creates barrel → renderables → Slider → barrel cycle. Redirect to a\n // minimal deps file that provides only what Slider needs.\n const renderablesDir = path.resolve(coreRoot, \"src/renderables\")\n config.plugins.push(\n new webpack.NormalModuleReplacementPlugin(/^\\.\\.\\/index$/, (resource: any) => {\n if (resource.context === renderablesDir) {\n resource.request = shimPath(\"src/shims/slider-deps.ts\")\n }\n }),\n )\n\n if (!isServer) {\n // Client-only: Node.js built-in stubs, events shim, console shim.\n // Use \"$\" suffix for exact match to prevent \"fs\" from matching \"fs/promises\".\n const clientAliases: Record<string, string> = {\n \"node:console\": shimPath(\"src/shims/console.ts\"),\n \"events$\": shimPath(\"src/shims/events-shim.ts\"),\n \"fs/promises\": shimPath(\"src/shims/node-fs.ts\"),\n \"fs$\": shimPath(\"src/shims/node-fs.ts\"),\n \"path$\": shimPath(\"src/shims/node-path.ts\"),\n \"util$\": shimPath(\"src/shims/node-util.ts\"),\n \"os$\": shimPath(\"src/shims/node-os.ts\"),\n \"stream$\": shimPath(\"src/shims/node-stream.ts\"),\n \"url$\": shimPath(\"src/shims/node-url.ts\"),\n }\n\n config.resolve.alias = {\n ...config.resolve.alias,\n ...clientAliases,\n }\n\n // Allow webpack to resolve modules from our workspace node_modules\n config.resolve.modules = [\n ...(config.resolve.modules || []),\n path.resolve(pkgRoot, \"node_modules\"),\n path.resolve(pkgRoot, \"../../node_modules\"),\n ]\n\n // Strip `node:` and `bun:` prefixes from imports so they resolve\n // through aliases. Webpack 5 treats these as unhandled URL schemes.\n config.plugins.push(\n new webpack.NormalModuleReplacementPlugin(/^node:/, (resource: any) => {\n resource.request = resource.request.replace(/^node:/, \"\")\n }),\n new webpack.NormalModuleReplacementPlugin(/^bun:/, (resource: any) => {\n resource.request = resource.request.replace(/^bun:/, \"\")\n }),\n )\n }\n\n // Enable top-level await (used by opentui source code)\n config.experiments = {\n ...config.experiments,\n topLevelAwait: true,\n }\n\n return config\n },\n }\n}\n"],"mappings":"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","names":[]}
package/dist/next.d.ts ADDED
@@ -0,0 +1,337 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode, CSSProperties } from 'react';
3
+ import { EventEmitter } from 'events';
4
+
5
+ declare class RGBA {
6
+ buffer: Float32Array;
7
+ constructor(buffer: Float32Array);
8
+ static fromArray(array: Float32Array): RGBA;
9
+ static fromValues(r: number, g: number, b: number, a?: number): RGBA;
10
+ static fromInts(r: number, g: number, b: number, a?: number): RGBA;
11
+ static fromHex(hex: string): RGBA;
12
+ get r(): number;
13
+ set r(v: number);
14
+ get g(): number;
15
+ set g(v: number);
16
+ get b(): number;
17
+ set b(v: number);
18
+ get a(): number;
19
+ set a(v: number);
20
+ toInts(): [number, number, number, number];
21
+ map<R>(fn: (value: number) => R): R[];
22
+ toString(): string;
23
+ equals(other?: RGBA): boolean;
24
+ }
25
+
26
+ type CursorStyle = "block" | "line" | "underline";
27
+ type MousePointerStyle = "default" | "pointer" | "text" | "crosshair" | "move" | "not-allowed";
28
+ type WidthMethod$1 = "wcwidth" | "unicode";
29
+ interface CursorStyleOptions {
30
+ style?: CursorStyle;
31
+ blinking?: boolean;
32
+ color?: RGBA;
33
+ cursor?: MousePointerStyle;
34
+ }
35
+ interface RenderContext {
36
+ addToHitGrid: (x: number, y: number, width: number, height: number, id: number) => void;
37
+ pushHitGridScissorRect: (x: number, y: number, width: number, height: number) => void;
38
+ popHitGridScissorRect: () => void;
39
+ clearHitGridScissorRects: () => void;
40
+ width: number;
41
+ height: number;
42
+ requestRender: () => void;
43
+ setCursorPosition: (x: number, y: number, visible: boolean) => void;
44
+ setCursorStyle: (options: CursorStyleOptions) => void;
45
+ setCursorColor: (color: RGBA) => void;
46
+ setMousePointer: (shape: MousePointerStyle) => void;
47
+ widthMethod: WidthMethod$1;
48
+ capabilities: any | null;
49
+ requestLive: () => void;
50
+ dropLive: () => void;
51
+ hasSelection: boolean;
52
+ getSelection: () => any | null;
53
+ requestSelectionUpdate: () => void;
54
+ currentFocusedRenderable: any | null;
55
+ focusRenderable: (renderable: any) => void;
56
+ registerLifecyclePass: (renderable: any) => void;
57
+ unregisterLifecyclePass: (renderable: any) => void;
58
+ getLifecyclePasses: () => Set<any>;
59
+ keyInput: any;
60
+ _internalKeyInput: any;
61
+ clearSelection: () => void;
62
+ startSelection: (renderable: any, x: number, y: number) => void;
63
+ updateSelection: (currentRenderable: any | undefined, x: number, y: number, options?: {
64
+ finishDragging?: boolean;
65
+ }) => void;
66
+ on: (event: string, listener: (...args: any[]) => void) => any;
67
+ off: (event: string, listener: (...args: any[]) => void) => any;
68
+ emit: (event: string, ...args: any[]) => boolean;
69
+ removeAllListeners: (event?: string) => any;
70
+ }
71
+ interface CapturedSpan {
72
+ text: string;
73
+ fg: RGBA;
74
+ bg: RGBA;
75
+ attributes: number;
76
+ width: number;
77
+ }
78
+ interface CapturedLine {
79
+ spans: CapturedSpan[];
80
+ }
81
+
82
+ type WidthMethod = "wcwidth" | "unicode";
83
+ interface BorderDrawOptions {
84
+ x: number;
85
+ y: number;
86
+ width: number;
87
+ height: number;
88
+ borderStyle?: string;
89
+ customBorderChars?: Uint32Array;
90
+ border: boolean | string[];
91
+ borderColor: RGBA;
92
+ backgroundColor: RGBA;
93
+ shouldFill?: boolean;
94
+ title?: string;
95
+ titleAlignment?: "left" | "center" | "right";
96
+ }
97
+ declare class BrowserBuffer {
98
+ id: string;
99
+ respectAlpha: boolean;
100
+ private _width;
101
+ private _height;
102
+ private _widthMethod;
103
+ char: Uint32Array;
104
+ fg: Float32Array;
105
+ bg: Float32Array;
106
+ attributes: Uint32Array;
107
+ private scissorStack;
108
+ private opacityStack;
109
+ linkRegistry: Map<number, string>;
110
+ private nextLinkId;
111
+ constructor(width: number, height: number, options?: {
112
+ respectAlpha?: boolean;
113
+ id?: string;
114
+ widthMethod?: WidthMethod;
115
+ });
116
+ static create(width: number, height: number, widthMethod: WidthMethod, options?: {
117
+ respectAlpha?: boolean;
118
+ id?: string;
119
+ }): BrowserBuffer;
120
+ get width(): number;
121
+ get height(): number;
122
+ get widthMethod(): WidthMethod;
123
+ get ptr(): number;
124
+ get buffers(): {
125
+ char: Uint32Array<ArrayBufferLike>;
126
+ fg: Float32Array<ArrayBufferLike>;
127
+ bg: Float32Array<ArrayBufferLike>;
128
+ attributes: Uint32Array<ArrayBufferLike>;
129
+ };
130
+ setRespectAlpha(respectAlpha: boolean): void;
131
+ getNativeId(): string;
132
+ registerLink(url: string): number;
133
+ getLinkUrl(linkId: number): string | undefined;
134
+ private isInScissor;
135
+ private getCurrentOpacityMultiplier;
136
+ private applyOpacity;
137
+ clear(bg?: RGBA): void;
138
+ setCell(x: number, y: number, char: string, fgColor: RGBA, bgColor: RGBA, attr?: number): void;
139
+ setCellWithAlphaBlending(x: number, y: number, char: string, fgColor: RGBA, bgColor: RGBA, attr?: number): void;
140
+ drawChar(charCode: number, x: number, y: number, fgColor: RGBA, bgColor: RGBA, attr?: number): void;
141
+ drawText(text: string, x: number, y: number, fgColor: RGBA, bgColor?: RGBA, attr?: number, _selection?: {
142
+ start: number;
143
+ end: number;
144
+ bgColor?: RGBA;
145
+ fgColor?: RGBA;
146
+ } | null): void;
147
+ fillRect(x: number, y: number, width: number, height: number, bgColor: RGBA): void;
148
+ drawBox(options: BorderDrawOptions): void;
149
+ private getDefaultBorderChars;
150
+ pushScissorRect(x: number, y: number, width: number, height: number): void;
151
+ popScissorRect(): void;
152
+ clearScissorRects(): void;
153
+ pushOpacity(opacity: number): void;
154
+ popOpacity(): void;
155
+ getCurrentOpacity(): number;
156
+ clearOpacity(): void;
157
+ resize(width: number, height: number): void;
158
+ getSpanLines(): CapturedLine[];
159
+ drawTextBufferView(view: any, x: number, y: number): void;
160
+ drawTextBuffer(textBufferView: any, x: number, y: number): void;
161
+ drawFrameBuffer(destX: number, destY: number, frameBuffer: BrowserBuffer, sourceX?: number, sourceY?: number, sourceWidth?: number, sourceHeight?: number): void;
162
+ drawEditorView(editorView: any, x: number, y: number): void;
163
+ drawSuperSampleBuffer(): void;
164
+ drawPackedBuffer(): void;
165
+ drawGrayscaleBuffer(): void;
166
+ drawGrayscaleBufferSupersampled(): void;
167
+ drawGrid(): void;
168
+ encodeUnicode(_text: string): null;
169
+ freeUnicode(): void;
170
+ getRealCharBytes(): Uint8Array;
171
+ destroy(): void;
172
+ }
173
+
174
+ declare class BrowserKeyHandler extends EventEmitter {
175
+ constructor();
176
+ processInput(_data: string): boolean;
177
+ }
178
+ declare class BrowserInternalKeyHandler extends BrowserKeyHandler {
179
+ private renderableHandlers;
180
+ onInternal(event: string, handler: Function): void;
181
+ offInternal(event: string, handler: Function): void;
182
+ emit(event: string, ...args: any[]): boolean;
183
+ }
184
+ declare class BrowserRenderContext extends EventEmitter implements RenderContext {
185
+ private _width;
186
+ private _height;
187
+ private _widthMethod;
188
+ private _renderRequested;
189
+ private _onRenderRequest;
190
+ private _lifecyclePasses;
191
+ private _focusedRenderable;
192
+ keyInput: BrowserKeyHandler;
193
+ _internalKeyInput: BrowserInternalKeyHandler;
194
+ constructor(width: number, height: number, widthMethod?: WidthMethod$1);
195
+ get width(): number;
196
+ get height(): number;
197
+ get widthMethod(): WidthMethod$1;
198
+ get capabilities(): any;
199
+ get hasSelection(): boolean;
200
+ get currentFocusedRenderable(): any | null;
201
+ setOnRenderRequest(callback: () => void): void;
202
+ resize(width: number, height: number): void;
203
+ addToHitGrid(_x: number, _y: number, _width: number, _height: number, _id: number): void;
204
+ pushHitGridScissorRect(_x: number, _y: number, _width: number, _height: number): void;
205
+ popHitGridScissorRect(): void;
206
+ clearHitGridScissorRects(): void;
207
+ requestRender(): void;
208
+ setCursorPosition(_x: number, _y: number, _visible: boolean): void;
209
+ setCursorStyle(_options: CursorStyleOptions): void;
210
+ setCursorColor(_color: RGBA): void;
211
+ setMousePointer(_shape: MousePointerStyle): void;
212
+ requestLive(): void;
213
+ dropLive(): void;
214
+ getSelection(): any | null;
215
+ requestSelectionUpdate(): void;
216
+ focusRenderable(renderable: any): void;
217
+ registerLifecyclePass(renderable: any): void;
218
+ unregisterLifecyclePass(renderable: any): void;
219
+ getLifecyclePasses(): Set<any>;
220
+ clearSelection(): void;
221
+ startSelection(_renderable: any, _x: number, _y: number): void;
222
+ updateSelection(_currentRenderable: any | undefined, _x: number, _y: number, _options?: {
223
+ finishDragging?: boolean;
224
+ }): void;
225
+ }
226
+
227
+ interface SelectionRange {
228
+ startCol: number;
229
+ startRow: number;
230
+ endCol: number;
231
+ endRow: number;
232
+ }
233
+ declare class SelectionManager {
234
+ private _startCol;
235
+ private _startRow;
236
+ private _endCol;
237
+ private _endRow;
238
+ private _active;
239
+ private _selecting;
240
+ startSelection(col: number, row: number): void;
241
+ updateSelection(col: number, row: number): void;
242
+ endSelection(): void;
243
+ clearSelection(): void;
244
+ get active(): boolean;
245
+ get selecting(): boolean;
246
+ /** Returns the selection range normalized to reading order (top-left to bottom-right) */
247
+ getSelectedRange(): SelectionRange | null;
248
+ isSelected(col: number, row: number): boolean;
249
+ getSelectedText(buffer: BrowserBuffer): string;
250
+ }
251
+
252
+ interface CanvasPainterOptions {
253
+ fontFamily?: string;
254
+ fontSize?: number;
255
+ }
256
+ declare class CanvasPainter {
257
+ private cellWidth;
258
+ private cellHeight;
259
+ private fontFamily;
260
+ private fontSize;
261
+ private baselineOffset;
262
+ constructor(options?: CanvasPainterOptions);
263
+ measureCell(ctx: CanvasRenderingContext2D): {
264
+ width: number;
265
+ height: number;
266
+ };
267
+ getCellSize(): {
268
+ width: number;
269
+ height: number;
270
+ };
271
+ paint(ctx: CanvasRenderingContext2D, buffer: BrowserBuffer, selection?: SelectionManager): void;
272
+ }
273
+
274
+ declare class BrowserRenderer {
275
+ canvas: HTMLCanvasElement;
276
+ ctx2d: CanvasRenderingContext2D;
277
+ buffer: BrowserBuffer;
278
+ renderContext: BrowserRenderContext;
279
+ root: any;
280
+ painter: CanvasPainter;
281
+ selection: SelectionManager;
282
+ private cols;
283
+ private rows;
284
+ private cellWidth;
285
+ private cellHeight;
286
+ private rafId;
287
+ private lastTime;
288
+ private needsRender;
289
+ private isDragOver;
290
+ private cleanupListeners;
291
+ private mouseDownCell;
292
+ constructor(canvas: HTMLCanvasElement, cols: number, rows: number);
293
+ private pixelToCell;
294
+ private setupDomListeners;
295
+ start(): void;
296
+ stop(): void;
297
+ private loop;
298
+ resize(cols: number, rows: number): void;
299
+ private static PREVENT_DEFAULT_KEYS;
300
+ private static MODIFIER_KEYS;
301
+ private static KEY_MAP;
302
+ handleKeyDown(event: KeyboardEvent): void;
303
+ }
304
+
305
+ interface TUIProps {
306
+ children: ReactNode;
307
+ /** CSS styles for the outer container div */
308
+ style?: CSSProperties;
309
+ /** CSS class for the outer container div */
310
+ className?: string;
311
+ /** Font size in pixels (default: 14) */
312
+ fontSize?: number;
313
+ /** Font family (default: monospace stack) */
314
+ fontFamily?: string;
315
+ /** Auto-focus the canvas for keyboard input (default: true) */
316
+ autoFocus?: boolean;
317
+ /** Called when the renderer is ready */
318
+ onReady?: (renderer: BrowserRenderer) => void;
319
+ }
320
+ /**
321
+ * A single React component that renders TUI content to an HTML5 Canvas.
322
+ * Gridland is built on the opentui engine.
323
+ *
324
+ * Usage:
325
+ * ```tsx
326
+ * <TUI style={{ width: "100%", height: 400 }}>
327
+ * <box border borderStyle="rounded">
328
+ * <text>Hello from Gridland!</text>
329
+ * </box>
330
+ * </TUI>
331
+ * ```
332
+ *
333
+ * No dynamic imports, no wrapper chains. Just a component.
334
+ */
335
+ declare function TUI({ children, style, className, fontSize, fontFamily, autoFocus, onReady, }: TUIProps): react_jsx_runtime.JSX.Element;
336
+
337
+ export { TUI, type TUIProps };