@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.
- package/LICENSE +73 -0
- package/README.md +412 -0
- package/dist/hotty-xterm.js +3804 -0
- package/dist/hotty-xterm.js.map +7 -0
- package/dist/types/addon.d.ts +183 -0
- package/dist/types/delta.d.ts +19 -0
- package/dist/types/hostcss.d.ts +48 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/keys.d.ts +122 -0
- package/dist/types/network.d.ts +18 -0
- package/dist/types/resolver.d.ts +46 -0
- package/dist/types/resources.d.ts +32 -0
- package/dist/types/surface.d.ts +486 -0
- package/dist/types/touch.d.ts +37 -0
- package/dist/types/version.d.ts +12 -0
- package/dist/types/wire.d.ts +59 -0
- package/package.json +54 -0
|
@@ -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
|
+
}
|