@neuroplastio/xterm-addon-hotty 0.1.0-next.1

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,486 @@
1
+ import { Deltas } from "./delta.ts";
2
+ import { Resolver } from "./resolver.ts";
3
+ import { type Policy } from "./network.ts";
4
+ import { type Store } from "./resources.ts";
5
+ /** A surface's CSP: nothing from the network but what the host grants. The
6
+ * `<base>` is the addon's own (a document's is read, then dropped), so any
7
+ * http(s) base is allowed. */
8
+ export declare function csp(host: Policy): string;
9
+ /** What a surface needs from the addon. */
10
+ /** A window of a surface, in cells from its top-left corner (SPEC §5.2). */
11
+ export interface Window {
12
+ x: number;
13
+ y: number;
14
+ w: number;
15
+ h: number;
16
+ }
17
+ export interface SurfaceHost {
18
+ layer: HTMLElement;
19
+ store: Store;
20
+ /** Sends a HOTTY message (an event) to the program. */
21
+ event(surface: string, kind: string, target: string, detail?: unknown): void;
22
+ /** A key the surface does not use (a keydown or its keyup), for the
23
+ * terminal to send to the program as if typed there (SPEC §10.2). */
24
+ key(e: KeyboardEvent): void;
25
+ /** What the terminal would send the program for a key, sent nowhere
26
+ * (SPEC §10.4: a text field names the key from it); null when the
27
+ * terminal cannot tell. */
28
+ encodeKey(e: KeyboardEvent): string | null;
29
+ /** Sends the program what `encodeKey` gave, as typed. */
30
+ sendKey(data: string): void;
31
+ /** A key the browser keeps (the `browserKeys` option): the surface
32
+ * leaves it to the browser rather than hand it to the terminal. */
33
+ browserKey(e: KeyboardEvent): boolean;
34
+ /** Gives the keyboard back to the terminal. */
35
+ focusTerminal(): void;
36
+ /** The host's half of the network policy (SPEC §7.2). */
37
+ policy: Policy;
38
+ /** The page scrolls, not the terminal (the `scroll` option): wheels and
39
+ * touch drags over the surface are left to the browser. */
40
+ pageScrolls: boolean;
41
+ /** The wheel gesture a wheel over a document that scrolls belongs to:
42
+ * where it began decides where the rest of it goes (`decide`, called for
43
+ * a gesture's first wheel), as a browser latches scrolling to what it
44
+ * began on. A gesture begun over the cells stays the terminal's. */
45
+ wheelGesture(surface: string, decide: () => Route): Route;
46
+ /** Scrolls the page by dx, dy pixels, where the page scrolls: for a
47
+ * gesture the browser would give an element of the document instead. */
48
+ scrollPage(dx: number, dy: number): void;
49
+ /** A hyperlink (SPEC §9: a link with target="_blank") was hovered, left
50
+ * or clicked: the terminal's, as an OSC 8 hyperlink is. `box` is the
51
+ * link's box in the page. */
52
+ hyperlink(kind: "activate" | "hover" | "leave", e: MouseEvent, url: string, box: DOMRect): void;
53
+ /** A wheel event over the surface, or a touch drag made one: the
54
+ * terminal's (SPEC §9), at a point in the page. */
55
+ wheel(e: WheelEvent, pageX: number, pageY: number): void;
56
+ /** A press with Alt held, a move of the gesture it began, or its release
57
+ * (SPEC §9.2): the program's, as on the cells beneath, at a point in the
58
+ * page. */
59
+ cells(kind: "down" | "move" | "up", e: MouseEvent, pageX: number, pageY: number): void;
60
+ }
61
+ /** The theme's colour scheme, as the host stylesheet declares it. */
62
+ export type Scheme = "dark" | "light";
63
+ /** Where a gesture or a key that scrolls goes in a document that scrolls
64
+ * (SPEC §5.3): the document (an element of it that can still move that
65
+ * way), the terminal, or nowhere (`overscroll-behavior` stopped it). */
66
+ export type Route = "doc" | "terminal" | "stop";
67
+ /** An element's cells, as the user sees it (SPEC §9: `area`). */
68
+ export interface Area {
69
+ c: number;
70
+ r: number;
71
+ w: number;
72
+ h: number;
73
+ }
74
+ export declare class Surface {
75
+ readonly name: string;
76
+ readonly box: HTMLDivElement;
77
+ readonly frame: HTMLIFrameElement;
78
+ readonly doc: Document;
79
+ readonly resolver: Resolver;
80
+ readonly deltas: Deltas;
81
+ cols: number;
82
+ rows: number;
83
+ /** The part of the surface on screen, in cells (SPEC §5.2). */
84
+ win: Window;
85
+ autoRows: boolean;
86
+ private readonly host;
87
+ private readonly hostStyle;
88
+ /** Set while the program moves focus, so no `focus` event echoes back. */
89
+ private programFocus;
90
+ /** The document's base URL (SPEC §7.3). */
91
+ private base;
92
+ private keyboard;
93
+ /** Detached (SPEC §5.5): nothing in the surface reaches the program. */
94
+ private detachedState;
95
+ /** A press is on something that takes no focus (SPEC §10.1): the focus
96
+ * the browser gives the frame for it is not the surface's. */
97
+ private pressNothing;
98
+ /** The element a press focuses, until the browser is done with it. */
99
+ private pressed;
100
+ /** A press of another button than the primary one, until the browser is
101
+ * done with it: it neither takes nor gives back the keyboard. */
102
+ private auxPress;
103
+ private settling;
104
+ /** A drag under way (SPEC §9.1). */
105
+ private drag;
106
+ /** A drag just ended at a release: it reported its own click, so the
107
+ * browser's, which follows in the same task, is not reported. */
108
+ private dragReleased;
109
+ /** The placement asked for presses (`p=1`, SPEC §5.2). */
110
+ presses: boolean;
111
+ /** A mouse's or a pen's pointerdown came first: the mousedown that
112
+ * follows is the same press, not a tap's. */
113
+ private pointerPress;
114
+ /** The pointer of a press with Alt held (SPEC §9.2), until its release:
115
+ * the gesture is the program's. */
116
+ private altPointer;
117
+ /** Such a gesture just ended at a release: the browser's click that
118
+ * follows in the same task is not the surface's. */
119
+ private altReleased;
120
+ /** One cell, in CSS pixels: a drag's detail counts cells (SPEC §9.1). */
121
+ private cellW;
122
+ private cellH;
123
+ private css;
124
+ /** Keys whose keydown went to the program, so their keyup follows. */
125
+ private forwarded;
126
+ /** A run of row moves in a field (SPEC §10.2): the caret it left, and the
127
+ * place along the row it keeps. Anything else that moves the caret ends
128
+ * it. */
129
+ private goal;
130
+ /** The field shown as `text` while focused (`NO_CARET`). */
131
+ private masked;
132
+ /** Tab is moving focus: the field it reaches selects its text. */
133
+ private tabbing;
134
+ /** The rows the program heard last, while the placement asked for `fit`
135
+ * (`f=1`, SPEC §5.2); null when it did not. */
136
+ private fitRows;
137
+ /** The height may have changed since the last check. */
138
+ private fitDirty;
139
+ /** The frame a check waits for. */
140
+ private fitFrame;
141
+ private fitObserver;
142
+ /** The axes the document asked to scroll along (`scroll`, SPEC §5.1): 1
143
+ * vertically, 2 horizontally, 3 both; 0, nothing scrolls. */
144
+ private axes;
145
+ /** Where the touch drag under way goes, once it has a direction. */
146
+ private touchRoute;
147
+ /** The box the wheel gesture under way scrolls, if it went to the
148
+ * document: the gesture moves no other (`scrollWheel`). */
149
+ private wheelBox;
150
+ /** Some element may carry `CLIP`. */
151
+ private clipping;
152
+ constructor(name: string, host: SurfaceHost, hostCss: string, scheme: Scheme);
153
+ setHostCss(css: string, scheme: Scheme): void;
154
+ private restyle;
155
+ /** Replaces the whole document (`a=doc`): its head's styles and its body.
156
+ * `detached` (`d=1`) detaches the surface first; without it, the surface
157
+ * is the program's again (SPEC §5.1, §5.5). `axes` (`scroll`) are the
158
+ * axes it scrolls along, 0 for none (§5.3). */
159
+ setDocument(html: string, detached?: boolean, axes?: number): void;
160
+ /** A delta (SPEC §6). On a detached surface, the controls it adds are
161
+ * disabled too, and so is one whose `disabled` it removes. */
162
+ delta(op: string, target: string | undefined, key: string | undefined, payload: string): void;
163
+ get detached(): boolean;
164
+ /** `a=detach`: nothing in the surface reaches the program any more. A
165
+ * surface that has the keyboard gives it back silently, with no `change`
166
+ * and no `blur`, and its form controls act disabled. */
167
+ detach(): void;
168
+ /** Disables the form controls of a detached surface, as if each had the
169
+ * `disabled` attribute, or enables those it disabled, and marks its
170
+ * hyperlinks for the host's stylesheet. The attributes are the host's
171
+ * own: the document reports the program's (SPEC §16). */
172
+ private sync;
173
+ private copyAttributes;
174
+ /** Rows the content needs at `cols` columns (`r=auto`). */
175
+ contentRows(cols: number, cellW: number, cellH: number): number;
176
+ /**
177
+ * Rows the document needs at `cols` columns: `r=auto`'s, and `fit`'s
178
+ * (SPEC §5.2). The frame is laid out at the width a placement gives it
179
+ * and a height of 1px, so the viewport adds nothing, then restored in the
180
+ * same task: nothing is drawn in between.
181
+ */
182
+ private neededRows;
183
+ /**
184
+ * In a document that scrolls along one axis only, the elements whose
185
+ * `overflow` along the other is `auto` or `scroll` are marked (`CLIP`), so
186
+ * that the host stylesheet clips that axis as `overflow: hidden` does
187
+ * (SPEC §5.3): no scrollbar, and nothing the user does scrolls it. CSS
188
+ * cannot select by a computed value, so the addon reads it, with its own
189
+ * rule off (`UNCLIPPED`), each time the document or its style may have
190
+ * changed: a document, a delta, the host stylesheet. Style only, no
191
+ * layout, and only for a document with `scroll` of 1 or 2.
192
+ */
193
+ private clip;
194
+ /**
195
+ * `f=1` on the placement: from `rows`, the placement's own, the program
196
+ * hears `fit` whenever the rows the document needs differ from those it
197
+ * heard last. `null`: the placement did not ask (or is gone).
198
+ *
199
+ * What can change the height asks for a check in the next frame drawn:
200
+ * a document, a delta, a resource (`refresh`), the host stylesheet (cell
201
+ * size, font), an image, stylesheet or font loading, and, for whatever
202
+ * else does (the user opening a `<details>`, say), the root's and the
203
+ * body's boxes changing size. One check per frame, so one `fit` at most.
204
+ */
205
+ setFit(rows: number | null): void;
206
+ /** The document's height may have changed: a check in the next frame
207
+ * drawn. A surface out of view draws none; it checks once shown. */
208
+ private refit;
209
+ private checkFit;
210
+ /** A resource changed (`a=res`, `a=del`): what names it resolves again. */
211
+ refresh(names: Set<string>): void;
212
+ /** The surface is `cols`×`rows` cells, and the box shows `win` of it:
213
+ * the document keeps the whole size, offset by the window's corner. */
214
+ setSize(cols: number, rows: number, cellW: number, cellH: number, win?: Window): void;
215
+ /** The placement's z (SPEC §5.2): CSS z-index on the box, so overlapping
216
+ * boxes stack by it, and by their order in the layer at the same z. */
217
+ setZ(z: number): void;
218
+ /** Shows the surface with its top-left corner at (x, y) in the screen's pixels. */
219
+ show(x: number, y: number): void;
220
+ /** Out of view (its line left the screen): a drag under way ends
221
+ * (SPEC §9.1). */
222
+ hide(): void;
223
+ /** No placement (hidden, or not placed yet): the document stays, and the
224
+ * browser skips its style, layout and paint until it is placed again. */
225
+ park(): void;
226
+ destroy(): void;
227
+ hasKeyboard(): boolean;
228
+ /** `a=focus`: the surface takes the keyboard, at `target` if given. */
229
+ focus(target?: string): void;
230
+ /** `a=blur`, or the keyboard leaving: the edited control commits first. */
231
+ blur(): void;
232
+ /** The browser's focus goes from the frame to the terminal. The frame lets
233
+ * go of it first: Firefox can leave the frame focused otherwise. */
234
+ private giveBack;
235
+ private commit;
236
+ private focusedControl;
237
+ /** Whether the browser's focus is in this surface's frame. */
238
+ private frameFocused;
239
+ /**
240
+ * A press (SPEC §10.1). On an element that takes focus, the focus that
241
+ * follows gives the surface the keyboard (`onFocusIn`). On anything else,
242
+ * or anywhere in a detached surface, it takes nothing: a surface that had
243
+ * the keyboard gives it back (its control commits, then `blur`), and the
244
+ * focus the browser gives the frame anyway goes back to the terminal.
245
+ */
246
+ private onPress;
247
+ /**
248
+ * Once the browser is done with a press (its default action focuses the
249
+ * frame): an element that takes focus has it, even where the browser does
250
+ * not focus one on a click (a button on a Mac, say); and focus the
251
+ * surface does not hold goes back to the terminal. The frame keeps it
252
+ * until then, so text selection starts as usual.
253
+ */
254
+ private settle;
255
+ /** An element got focus: the surface takes the keyboard if the element is
256
+ * one that takes focus, and the focus is neither the program's (no echo)
257
+ * nor a detached surface's. */
258
+ private onFocusIn;
259
+ private tabbable;
260
+ private controlKind;
261
+ /** Whether the focused element uses the key; if not, the program gets it. */
262
+ private consumes;
263
+ private onKey;
264
+ /**
265
+ * A key the focused element's keymap gives the program (SPEC §10.2, *Keys
266
+ * for the program*), outside a text field: it reaches the program before
267
+ * the element uses it (a select's arrows) and before the document
268
+ * scrolls with it. The keymap is each `data-keys` from the root down to
269
+ * the element, with no default, and only its `program` bindings count.
270
+ * The key is named as in a text field (`fieldKey`).
271
+ */
272
+ private programKey;
273
+ /**
274
+ * A key the focused element's keymap binds to a scroll action (SPEC
275
+ * §10.2, *Scrolling keys*), outside a text field, and that the element
276
+ * does not use. Along an axis the document scrolls, it scrolls the
277
+ * nearest box from the element outward that can still move that way, as
278
+ * a gesture goes (§5.3), and never the terminal: where nothing can move,
279
+ * the key is used and does nothing. Along an axis the document does not
280
+ * scroll, it goes on as if its keymap did not bind it. The key is named
281
+ * as in a text field (`fieldKey`).
282
+ */
283
+ private scrollActionKey;
284
+ /** Scrolls `to` as a key does (`KeyScroll`), by Chromium's amounts. */
285
+ private scrollBox;
286
+ /** A key the program has, as xterm.js encoded it (`data`; null when it
287
+ * cannot say, and the key goes through it). Its release follows. */
288
+ private toProgram;
289
+ /** An input's type, as the browser has it; the program's for a field
290
+ * that is `text` while focused (`NO_CARET`). */
291
+ private inputType;
292
+ /**
293
+ * A key in a text field. It is named as the program would read it: from
294
+ * what xterm.js would send the program for it, in the encoding the
295
+ * program enabled, read as SPEC §10.4 says. The field's keymap (the
296
+ * default, then each `data-keys` from the root to the field) says what
297
+ * the field does with each key; what it does not use is the program's,
298
+ * sent as xterm.js encoded it.
299
+ */
300
+ private fieldKey;
301
+ /** A field's keymap (SPEC §10.2): the default, then the `data-keys` of
302
+ * each element from the root down to the field. */
303
+ private keymapOf;
304
+ /** Does an action in a field, or types text in it. */
305
+ private edit;
306
+ /** An input's or a textarea's value: the action's plan, applied with
307
+ * the editing commands, so that the browser sends `input` (and `change`
308
+ * when focus leaves) as for typing. */
309
+ private editValue;
310
+ /** Replaces code units `from` to `to` of a field's value with `text`, the
311
+ * caret after it, as typing does. */
312
+ private replace;
313
+ /**
314
+ * A textarea's rows as it lays them out (SPEC §10.2: a line that wraps is
315
+ * several rows): a hidden copy of its text, wrapped as it wraps, with
316
+ * every character in an element of its own, measured where each
317
+ * position is. The place along a row is a position's x.
318
+ */
319
+ private textareaRows;
320
+ /**
321
+ * An editing host (`contenteditable`): the actions with the selection's
322
+ * own moves, a character at a time where they need to see the text, so
323
+ * that words and lines are SPEC §10.2's, then the editing commands.
324
+ */
325
+ private editHost;
326
+ /** A field that hides its caret (`NO_CARET`) is `text` while focused:
327
+ * from the press that focuses it, so that the caret lands where the
328
+ * press does, or from the focus. */
329
+ private maskField;
330
+ private unmaskField;
331
+ /**
332
+ * A key a browser scrolls with, in a document that scrolls (SPEC §5.3):
333
+ * it scrolls the innermost box, from the focused element outward (from
334
+ * the root when none is), that can still move that way. Where none can,
335
+ * the key goes on to the program, as every key the surface does not use
336
+ * does (§10.2), unless `overscroll-behavior` stops it. The addon scrolls
337
+ * the box itself: the browser's own action could be the focused
338
+ * element's instead (a radio button's arrows, a number field's).
339
+ */
340
+ private scrollKey;
341
+ private forward;
342
+ /** The release of a key the program had: the program hears it too, if it
343
+ * asked the terminal for releases (SPEC §10.3). */
344
+ private onKeyUp;
345
+ /**
346
+ * A press of a mouse's or a pen's primary button on an element with
347
+ * `drag` in its `data-on` (the nearest, from the pressed one outward, and
348
+ * only if it has an id) starts a drag. The surface then holds the pointer
349
+ * until the release: captured by its root element, which no delta
350
+ * replaces, so every move comes here wherever it is (over the cells,
351
+ * another surface, or outside the page), and nothing else hears it.
352
+ */
353
+ private onDragDown;
354
+ /** A move during a drag: an event each time its target changes, and
355
+ * while it has none, each time its cell does. */
356
+ private onDragMove;
357
+ /** The release ends the drag, wherever it is. Where it began, it is the
358
+ * click it would have been without the drag; anywhere else, no click. */
359
+ private onDragUp;
360
+ /** The browser took the pointer away before the release. */
361
+ private lostPointer;
362
+ /**
363
+ * Ends a drag under way without a release (SPEC §9.1: its placement went
364
+ * away, a new document came, or the pointer was lost): `dragend` with no
365
+ * target, at the last cell the program heard of.
366
+ */
367
+ cancelDrag(): void;
368
+ /** Ends a drag under way, silently (a detached or deleted surface). */
369
+ private dropDrag;
370
+ /** The surface's cell under the pointer, from its top left (the frame's
371
+ * origin), counting on past its edges. */
372
+ private cellOf;
373
+ /** The element under the pointer, if it is in the window (SPEC §5.2). */
374
+ private elementAt;
375
+ /** A drag's target: the nearest element with an id and `drag` in its
376
+ * `data-on`, from `el` outward; "" where there is none. */
377
+ private dragTarget;
378
+ /**
379
+ * A press of a mouse's or a pen's primary button with Alt held is the
380
+ * program's: the addon replays it on the cells beneath, and the surface
381
+ * hears nothing of it (no press, drag, click, focus or selection; its
382
+ * mousedown is cancelled). It holds the pointer until the release, as a
383
+ * drag does, so every move and the release go to the cells, wherever the
384
+ * pointer is. Whether it is the program's is decided here, at the press:
385
+ * Alt let go later changes nothing.
386
+ */
387
+ private onAltDown;
388
+ private onAltMove;
389
+ private onAltUp;
390
+ /** Ends such a gesture without a release: the frame goes away. */
391
+ private dropAlt;
392
+ /** A point of the frame's document in the page. */
393
+ private toPage;
394
+ /** `press` (SPEC §9), if the placement asked for it: `t` is the nearest
395
+ * element with an id. A press on a hyperlink is the terminal's. */
396
+ private reportPress;
397
+ /**
398
+ * The cells an element's border box covers as the user sees it, scrolled
399
+ * included (SPEC §9: `area`), counted from the surface's top left cell:
400
+ * whole, where it is clipped or scrolled away. An edge within half a
401
+ * device pixel of a cell's is on it: layout rounds positions to fractions
402
+ * of a pixel, and the user sees no less than a device pixel.
403
+ */
404
+ private areaOf;
405
+ private listen;
406
+ /**
407
+ * Nothing in a surface scrolls, and a wheel over it is the terminal's
408
+ * (SPEC §5.3, §9). Wheel events never leave an iframe, so without this
409
+ * the terminal's scrollback (or, on the alternate screen, the program's
410
+ * wheel input) would stall under the pointer. Ctrl and the wheel stay the
411
+ * browser's: its zoom. Where the page scrolls (the `scroll` option), the
412
+ * wheel is the browser's too: nothing in the frame scrolls, so it scrolls
413
+ * the page, as over the cells; but over an element it would scroll
414
+ * instead, the surface scrolls the page itself.
415
+ */
416
+ private onWheel;
417
+ /** Whether a wheel or a touch at target would scroll an element of the
418
+ * document, overflowing with `overflow: auto` or `scroll`: the browser
419
+ * gives the gesture to it before the page, and nothing in a surface
420
+ * scrolls (SPEC §5.3), so the gesture would go nowhere. */
421
+ private inScroller;
422
+ /**
423
+ * A wheel over a document that scrolls (SPEC §5.3). A gesture's first
424
+ * wheel decides where all of it goes, as a browser latches scrolling to
425
+ * what it began on: while an element under the pointer can still move
426
+ * that way, the browser scrolls it; where none can, the gesture goes on
427
+ * to the terminal, as over the cells beneath (§9), unless
428
+ * `overscroll-behavior` stops it. A gesture the document took goes no
429
+ * further when it reaches the end there, as in a browser. Where the page
430
+ * scrolls (the `scroll` option), the page is the terminal, and the
431
+ * browser chains to it from the document natively. A wheel the browser
432
+ * does not let the page cancel is the browser's already.
433
+ */
434
+ private scrollWheel;
435
+ /** Where a gesture that scrolls by dx, dy pixels at `target` goes, by its
436
+ * main axis (SPEC §5.3). */
437
+ private gestureRoute;
438
+ private gestureTarget;
439
+ /** Whether a box that scrolls can still move along `axis`, `d`'s way. */
440
+ private canMove;
441
+ /**
442
+ * What a scroll along `axis`, `d`'s way, from `from` (an element, or the
443
+ * root for none) moves in a document that scrolls (SPEC §5.3): the
444
+ * innermost box, from `from` outward, that the user scrolls along it
445
+ * (`overflow` `auto` or `scroll`; the root's, unless `hidden` or `clip`),
446
+ * that overflows there, and that can still move that way. At a box that
447
+ * cannot, the scroll stops if its `overscroll-behavior` is `contain` or
448
+ * `none`, and goes on outward otherwise. Past the root, and along an axis
449
+ * the document did not ask for, it is the terminal's.
450
+ */
451
+ private scroller;
452
+ /** Whatever the browser scrolled along an axis the document did not ask
453
+ * for (a focused element into view, say) goes back to zero. A text
454
+ * field's own text follows its caret (SPEC §5.3). */
455
+ private onScroll;
456
+ /** An event for the program (SPEC §9); a detached surface sends none (§5.5). */
457
+ private emit;
458
+ private linkIn;
459
+ /** A link's `url` (SPEC §9): its href resolved against the document's
460
+ * base, or "" under hotty.invalid or when it is no URL. */
461
+ private urlOf;
462
+ /** The link's box in the page (the iframe may be offset for a window). */
463
+ private pageBox;
464
+ /** A hyperlink (SPEC §9): a link with target="_blank" and a `url`. One
465
+ * without a url is the program's, as any other link. */
466
+ private isHyperlink;
467
+ private readonly hyper;
468
+ /** A link's click (SPEC §9). A hyperlink is the terminal's, as an OSC 8
469
+ * one is, and not reported; any other link is the program's: an event,
470
+ * with or without an id. The host opens nothing itself. */
471
+ private onLink;
472
+ /** Other buttons on a link do nothing: no navigation, no new tab. */
473
+ private onAuxClick;
474
+ private hovered;
475
+ /** The pointer onto a hyperlink: the terminal hears it, as it does over
476
+ * an OSC 8 one. */
477
+ private onOver;
478
+ private onOut;
479
+ private onLeave;
480
+ private onClick;
481
+ /** The click of the nearest element on `path` that reports one (SPEC §9). */
482
+ private reportClick;
483
+ private onSubmit;
484
+ private onChange;
485
+ private onInput;
486
+ }
@@ -0,0 +1,37 @@
1
+ export interface TouchHost {
2
+ /** Scroll by dx, dy pixels, at a point in the page (a wheel event for the
3
+ * terminal). */
4
+ scroll(dx: number, dy: number, pageX: number, pageY: number): void;
5
+ /** A tap at a point in the page, for a Touch that owns taps too. */
6
+ tap?(pageX: number, pageY: number): void;
7
+ /** The listened-to document's point in the page (an iframe's offset). */
8
+ toPage(x: number, y: number): [number, number];
9
+ /** Whether a drag that has just begun, scrolling by dx, dy pixels so far,
10
+ * is this Touch's. One it declines is the browser's to its end. Absent:
11
+ * every drag is. */
12
+ claim?(dx: number, dy: number, e: TouchEvent): boolean;
13
+ }
14
+ export declare class Touch {
15
+ private readonly win;
16
+ private readonly host;
17
+ private readonly exclusive;
18
+ private readonly engage?;
19
+ private touch;
20
+ private fling;
21
+ private readonly off;
22
+ /**
23
+ * `exclusive`: every touch here is this Touch's (the cells: xterm.js's own
24
+ * touch handling, which listens on the document, never sees it). Otherwise
25
+ * (a surface) a touch is left alone until it moves. `engage`, if given,
26
+ * says on a touch's start whether it is this Touch's at all: one it
27
+ * declines is the browser's, from start to end.
28
+ */
29
+ constructor(target: EventTarget, win: Window, host: TouchHost, exclusive?: boolean, engage?: ((e: TouchEvent) => boolean) | undefined);
30
+ dispose(): void;
31
+ private keep;
32
+ private start;
33
+ private move;
34
+ private end;
35
+ private startFling;
36
+ private stopFling;
37
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The addon's version, as its capabilities report it (SPEC §4): package.json's
3
+ * without its prerelease part (0.1.0 for 0.1.0-next.1), since SPEC §4's
4
+ * version is dot-separated numbers only. A unit test keeps the two equal so.
5
+ * A program tells hosts apart by name
6
+ * and version: under HOST every version takes `a=delta`. Before the scope, as
7
+ * `xterm-addon-hotty`, 0.1.0 named no version and took `a=patch`, and 0.2.0
8
+ * took `a=delta`.
9
+ */
10
+ export declare const VERSION = "0.1.0";
11
+ /** The host's name in its capabilities (SPEC §4): the package's. */
12
+ export declare const HOST = "@neuroplastio/xterm-addon-hotty";
@@ -0,0 +1,59 @@
1
+ export declare const OSC = 7279;
2
+ /** Largest base64 chunk a host sends (VTE ignores longer strings). */
3
+ export declare const CHUNK = 4096;
4
+ /** Largest reassembled command, in base64 bytes. */
5
+ export declare const MAX_COMMAND: number;
6
+ /** `key=value` pairs separated by `:`, in order. */
7
+ export declare class Control {
8
+ readonly pairs: [string, string][];
9
+ constructor(pairs?: [string, string][]);
10
+ static parse(text: string): Control;
11
+ get(key: string): string | undefined;
12
+ set(key: string, value: string): this;
13
+ delete(key: string): this;
14
+ /** A continuation chunk carries nothing but `m` and `q`. */
15
+ onlyChunkKeys(): boolean;
16
+ encode(): string;
17
+ }
18
+ /**
19
+ * A control value is printable ASCII (SPEC §3.2): each character it may not
20
+ * hold (`:`, `;`, `=`, a control character, anything outside ASCII) becomes
21
+ * one `_`, one per code point.
22
+ */
23
+ export declare function clean(value: string): string;
24
+ export interface Command {
25
+ control: Control;
26
+ payload: Uint8Array;
27
+ }
28
+ export type Decoded = {
29
+ kind: "command";
30
+ command: Command;
31
+ } | {
32
+ kind: "invalid";
33
+ reason: string;
34
+ } | {
35
+ kind: "partial";
36
+ };
37
+ /**
38
+ * Reassembles chunked commands. Decoding is synchronous unless the payload is
39
+ * zlib (`o=z`), which the browser only inflates asynchronously; the caller
40
+ * then gets a Promise, and xterm's parser waits for it.
41
+ */
42
+ export declare class Assembler {
43
+ private partial;
44
+ /** Feeds the data of one OSC 7279 sequence. */
45
+ feed(data: string): Decoded[] | Promise<Decoded[]>;
46
+ }
47
+ export declare function fromBase64(b64: string): Uint8Array;
48
+ export declare function toBase64(bytes: Uint8Array): string;
49
+ /** zlib (RFC 1950), which `DecompressionStream` calls "deflate". */
50
+ export declare function inflate(bytes: Uint8Array): Promise<Uint8Array>;
51
+ export declare function text(bytes: Uint8Array): string;
52
+ /**
53
+ * Encodes one message for the program: base64, chunked at `CHUNK`, each chunk
54
+ * a complete OSC terminated by ST. Replies are small, so they are never
55
+ * compressed (`o=z` is optional in both directions).
56
+ */
57
+ export declare function encode(control: Control, payload?: Uint8Array | string): string;
58
+ /** Decodes messages the host sent (for tests and for programs written in JS). */
59
+ export declare function decodeAll(stream: string): Promise<Command[]>;
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@neuroplastio/xterm-addon-hotty",
3
+ "version": "0.1.0-next.1",
4
+ "description": "HOTTY (HTML Over The TTY) for xterm.js: surfaces rendered by the browser, each in a sandboxed iframe",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/types/index.d.ts",
10
+ "default": "./dist/hotty-xterm.js"
11
+ }
12
+ },
13
+ "types": "./dist/types/index.d.ts",
14
+ "files": [
15
+ "dist/hotty-xterm.js",
16
+ "dist/hotty-xterm.js.map",
17
+ "dist/types"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "build": "node build.mjs",
22
+ "types": "tsc -p tsconfig.types.json",
23
+ "typecheck": "tsc --noEmit -p .",
24
+ "test:unit": "node --test tests/unit/*.test.ts",
25
+ "test:e2e": "playwright test",
26
+ "check": "npm run typecheck && npm run build && npm run types && npm run test:unit && npm run test:e2e",
27
+ "prepare": "npm run build && npm run types"
28
+ },
29
+ "peerDependencies": {
30
+ "@xterm/xterm": "^6.0.0 || ^6.1.0-0"
31
+ },
32
+ "devDependencies": {
33
+ "@playwright/test": "1.63.0",
34
+ "@types/node": "^26.6.3",
35
+ "@xterm/addon-fit": "0.12.0-beta.301",
36
+ "@xterm/xterm": "6.1.0-beta.304",
37
+ "esbuild": "0.28.2",
38
+ "typescript": "7.0.2"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/neuroplastio/xterm-addon-hotty.git"
43
+ },
44
+ "homepage": "https://github.com/neuroplastio/xterm-addon-hotty#readme",
45
+ "bugs": "https://github.com/neuroplastio/xterm-addon-hotty/issues",
46
+ "keywords": [
47
+ "xterm.js",
48
+ "xterm",
49
+ "addon",
50
+ "hotty",
51
+ "terminal",
52
+ "html"
53
+ ]
54
+ }