@fusion.dev/helix-headless 0.211.1 → 0.212.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.
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { customElement, formatWords, HelixBeforeToggleEvent, HelixElement, HelixToggleEvent, inlineStep, requestChange, requestValue, words, } from '@fusion.dev/helix-core';
2
+ import { customElement, formatWords, HelixBeforeToggleEvent, HelixElement, HelixToggleEvent, inlineStep, requestChange, requestValue, stopPress, words, } from '@fusion.dev/helix-core';
3
3
  import { nothing } from 'lit';
4
4
  import { property, state } from 'lit/decorators.js';
5
5
  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
@@ -29,7 +29,6 @@ export const registerHighlighter = (highlighter, sheet) => {
29
29
  }
30
30
  }
31
31
  };
32
- const stopPress = (event) => event.stopPropagation();
33
32
  const isBlock = (element) => element?.localName.endsWith('code-block') === true;
34
33
  const blocksIn = (host) => [...host.children].filter((child) => child.slot === '' && isBlock(child));
35
34
  const nameOf = (block) => {
@@ -0,0 +1,13 @@
1
+ /**
2
+ * How far a touch may travel and still be a tap, in CSS pixels: the drift
3
+ * Speed Dial's long press allows a press that stays one press.
4
+ */
5
+ export declare const TAP_SLOP = 10;
6
+ /** What one finger did between landing and lifting. */
7
+ export type Gesture = 'swipe' | 'tap';
8
+ /**
9
+ * A tap where the finger never strayed further than `TAP_SLOP` from where it
10
+ * landed, and a swipe otherwise. The furthest it strayed, and not where it
11
+ * lifted: a finger that went out and came back moved something on the way.
12
+ */
13
+ export declare const gestureOf: (furthest: number) => Gesture;
@@ -0,0 +1,3 @@
1
+ import { LONG_PRESS_SLOP } from '../speed-dial/long-press.js';
2
+ export const TAP_SLOP = LONG_PRESS_SLOP;
3
+ export const gestureOf = (furthest) => (furthest > TAP_SLOP ? 'swipe' : 'tap');
@@ -0,0 +1 @@
1
+ export { HelixHeadlessDeviceScreen } from './root/device-screen-root.js';
@@ -0,0 +1 @@
1
+ export { HelixHeadlessDeviceScreen } from './root/device-screen-root.js';
@@ -0,0 +1,531 @@
1
+ import { ChildrenController, type DeviceButton, HelixElement, ToolbarController } from '@fusion.dev/helix-core';
2
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
+ import '../../icon-button/index.js';
4
+ /**
5
+ * @summary A device's screen, drawn from a stream you supply, that sends taps, swipes, keys, and button presses back to the device.
6
+ *
7
+ * @description
8
+ * Shows the screen of a phone, a tablet, or a watch, such as the iOS Simulator
9
+ * or the Android Emulator, and turns what you do on it into events. Helix does
10
+ * not connect to the device. Put the element that draws the stream inside: a
11
+ * `<video>` fed by WebRTC or Media Source, an `<img>` showing an MJPEG stream,
12
+ * or a `<canvas>` you draw decoded frames on. The frame gives the screen the
13
+ * device's shape and stretches the element to fill it.
14
+ *
15
+ * Set `screen-width` and `screen-height` to the screen's size in the units
16
+ * your device takes input in: points for the iOS Simulator, and pixels for an
17
+ * Android device. Every point an event carries is in those units, beside the
18
+ * `width` and `height` it is measured against. Without them, the frame reads
19
+ * the stream's own size in pixels.
20
+ *
21
+ * **Touches.** Listen in one of two ways, and not both, or the device moves
22
+ * twice:
23
+ * - `helix-device-touch` for each finger as it lands, moves, and lifts, for a
24
+ * source that takes live touches. A drag and a pinch need it.
25
+ * - `helix-device-tap` and `helix-device-swipe` once the finger lifts, for a
26
+ * source that takes whole gestures. A long press is a tap with a long
27
+ * `duration`.
28
+ *
29
+ * Alt, or Option on a Mac, with a drag sends two touches mirrored about the
30
+ * middle of the screen, for a pinch or a turn, as the iOS Simulator does. A
31
+ * wheel or a trackpad over the screen sends `helix-device-scroll`.
32
+ *
33
+ * **Keyboard.** Press Tab to reach the screen, or press the screen. While it
34
+ * has focus:
35
+ *
36
+ * | Key | What it does |
37
+ * |---|---|
38
+ * | Any key | Sends `helix-device-key` as it goes down, and again as it comes up. |
39
+ * | Tab, Shift with Tab | Moves focus on from the screen. Never sent. |
40
+ * | Control, Command, or Alt with a key | Left to the browser, unless `forward-shortcuts` is set. |
41
+ * | Command or Control with V | Sends the clipboard's text as `helix-device-text`. |
42
+ *
43
+ * A key still held when focus leaves is sent as released. The screen has the
44
+ * `application` role, so a screen reader passes every key to it, and its
45
+ * description says how to leave.
46
+ *
47
+ * **Buttons.** `controls` names the hardware buttons to draw: `back`, `home`,
48
+ * `recents`, `power`, `volume`, `rotate`, `screenshot`, and `fullscreen`,
49
+ * `home screenshot` by default. Each sends `helix-device-button` with how long
50
+ * it was held, and the screenshot button sends `helix-device-screenshot`.
51
+ * `press()` and `screenshot()` do the same from a script. Put buttons of your
52
+ * own in the `controls` slot, and they join the row. The row is one tab stop,
53
+ * and the arrow keys move along it, or Up and Down in a column.
54
+ *
55
+ * Set `rotation` where your source sends frames in the device's natural
56
+ * orientation while the device is turned: the frame turns the picture, and
57
+ * turns every point back. Set `readonly` to show the screen and send nothing,
58
+ * such as while an agent drives the device. The screen is then a picture, and
59
+ * `showTap()` and `showSwipe()` mark where the agent touched it.
60
+ *
61
+ * @since 0.211.0
62
+ * @status experimental
63
+ * @category media
64
+ * @aliases Simulator, Emulator, Device mirror, Remote screen
65
+ * @documentation https://fusion.dev/helix/components/device-screen
66
+ *
67
+ * @slot - The element that draws the stream: a `<video>`, an `<img>`, or a `<canvas>`.
68
+ * @slot back-icon - Replaces the glyph inside the Back button.
69
+ * @slot bezel - A picture of the device drawn over the screen, such as a photograph of a phone with a clear screen. It takes no touches.
70
+ * @slot controls - Buttons of your own, such as Shake or Record, in the row after the hardware buttons and before the fullscreen button.
71
+ * @slot empty - Content shown over the screen while no element that draws the stream is inside and `loading` is not set, such as "No simulator is running" and a button to start one.
72
+ * @slot footer - Content below the device.
73
+ * @slot fullscreen-icon - Replaces the glyph inside the fullscreen button.
74
+ * @slot header - Content above the device, such as its name and state.
75
+ * @slot home-icon - Replaces the glyph inside the Home button.
76
+ * @slot loading - Content shown over the screen while `loading` is set, such as a spinner. `loading-label` by default, which screen readers hear either way.
77
+ * @slot power-icon - Replaces the glyph inside the Power button.
78
+ * @slot recents-icon - Replaces the glyph inside the Recent apps button.
79
+ * @slot rotate-left-icon - Replaces the glyph inside the Rotate left button.
80
+ * @slot rotate-right-icon - Replaces the glyph inside the Rotate right button.
81
+ * @slot screenshot-icon - Replaces the glyph inside the screenshot button.
82
+ * @slot volume-down-icon - Replaces the glyph inside the Volume down button.
83
+ * @slot volume-up-icon - Replaces the glyph inside the Volume up button.
84
+ *
85
+ * @event {HelixDeviceButtonEvent} helix-device-button - A hardware button was pressed, with how long it was held. Press it on the device in response.
86
+ * @event {HelixDeviceKeyEvent} helix-device-key - A key went down or came up while the screen had focus. Press or release it on the device in response.
87
+ * @event {HelixDeviceScreenshotEvent} helix-device-screenshot - A screenshot was asked for. Take one in response.
88
+ * @event {HelixDeviceScrollEvent} helix-device-scroll - A wheel or a trackpad scrolled over the screen. Scroll the device in response.
89
+ * @event {HelixDeviceSwipeEvent} helix-device-swipe - One finger moved across the screen and lifted. Swipe the device in response.
90
+ * @event {HelixDeviceTapEvent} helix-device-tap - One finger touched the screen and lifted near where it landed. Tap the device in response.
91
+ * @event {HelixDeviceTextEvent} helix-device-text - Text was pasted into the screen. Type it on the device in response.
92
+ * @event {HelixDeviceTouchEvent} helix-device-touch - A finger landed, moved, lifted, or was taken away. Touch the device in response.
93
+ *
94
+ * @csspart back - The Back button.
95
+ * @csspart back-button - The Back button's inner button.
96
+ * @csspart back-live - The Back button's live region, which speaks while the button is pending.
97
+ * @csspart back-spinner - The ring the Back button turns while it is pending.
98
+ * @csspart back-text - The box the Back button's icon sits in.
99
+ * @csspart bezel - The body of the device around the screen.
100
+ * @csspart controls - The row of buttons: the hardware buttons and any of yours in the `controls` slot.
101
+ * @csspart device - The box the device is fitted into, which keeps its shape inside it.
102
+ * @csspart empty - The box over the screen that holds the `empty` slot while no stream is inside and `loading` is not set. It stands beside the screen, so what you put in it takes presses and keys of its own, and a read-only screen does not hide it from screen readers.
103
+ * @csspart footer - The strip below the device.
104
+ * @csspart fullscreen - The button that makes the device fill the screen.
105
+ * @csspart fullscreen-button - The fullscreen button's inner button.
106
+ * @csspart fullscreen-live - The fullscreen button's live region, which speaks while the button is pending.
107
+ * @csspart fullscreen-spinner - The ring the fullscreen button turns while it is pending.
108
+ * @csspart fullscreen-text - The box the fullscreen button's icon sits in.
109
+ * @csspart header - The strip above the device.
110
+ * @csspart home - The Home button.
111
+ * @csspart home-button - The Home button's inner button.
112
+ * @csspart home-live - The Home button's live region, which speaks while the button is pending.
113
+ * @csspart home-spinner - The ring the Home button turns while it is pending.
114
+ * @csspart home-text - The box the Home button's icon sits in.
115
+ * @csspart keys-hint - What a screen reader says about the keys when it reaches the screen, as its description. Read by screen readers only.
116
+ * @csspart live - What screen readers hear while `loading` is set: `loading-label`. Read by screen readers only.
117
+ * @csspart loading - The box over the screen that holds the `loading` slot while `loading` is set. Screen readers hear `live` in its place.
118
+ * @csspart picture - The box the stream is drawn in, turned by `rotation`.
119
+ * @csspart power - The Power button.
120
+ * @csspart power-button - The Power button's inner button.
121
+ * @csspart power-live - The Power button's live region, which speaks while the button is pending.
122
+ * @csspart power-spinner - The ring the Power button turns while it is pending.
123
+ * @csspart power-text - The box the Power button's icon sits in.
124
+ * @csspart recents - The Recent apps button.
125
+ * @csspart recents-button - The Recent apps button's inner button.
126
+ * @csspart recents-live - The Recent apps button's live region, which speaks while the button is pending.
127
+ * @csspart recents-spinner - The ring the Recent apps button turns while it is pending.
128
+ * @csspart recents-text - The box the Recent apps button's icon sits in.
129
+ * @csspart region - The box that holds the device, its buttons, the header, and the footer.
130
+ * @csspart rotate-left - The Rotate left button.
131
+ * @csspart rotate-left-button - The Rotate left button's inner button.
132
+ * @csspart rotate-left-live - The Rotate left button's live region, which speaks while the button is pending.
133
+ * @csspart rotate-left-spinner - The ring the Rotate left button turns while it is pending.
134
+ * @csspart rotate-left-text - The box the Rotate left button's icon sits in.
135
+ * @csspart rotate-right - The Rotate right button.
136
+ * @csspart rotate-right-button - The Rotate right button's inner button.
137
+ * @csspart rotate-right-live - The Rotate right button's live region, which speaks while the button is pending.
138
+ * @csspart rotate-right-spinner - The ring the Rotate right button turns while it is pending.
139
+ * @csspart rotate-right-text - The box the Rotate right button's icon sits in.
140
+ * @csspart screen - The device's screen, which takes the touches and the keys.
141
+ * @csspart screenshot - The button that asks for a screenshot.
142
+ * @csspart screenshot-button - The screenshot button's inner button.
143
+ * @csspart screenshot-live - The screenshot button's live region, which speaks while the button is pending.
144
+ * @csspart screenshot-spinner - The ring the screenshot button turns while it is pending.
145
+ * @csspart screenshot-text - The box the screenshot button's icon sits in.
146
+ * @csspart touch - A ring where a touch is or was.
147
+ * @csspart touch-held - A ring under a finger that is down, beside `touch`, with `show-touches`.
148
+ * @csspart volume-down - The Volume down button.
149
+ * @csspart volume-down-button - The Volume down button's inner button.
150
+ * @csspart volume-down-live - The Volume down button's live region, which speaks while the button is pending.
151
+ * @csspart volume-down-spinner - The ring the Volume down button turns while it is pending.
152
+ * @csspart volume-down-text - The box the Volume down button's icon sits in.
153
+ * @csspart volume-up - The Volume up button.
154
+ * @csspart volume-up-button - The Volume up button's inner button.
155
+ * @csspart volume-up-live - The Volume up button's live region, which speaks while the button is pending.
156
+ * @csspart volume-up-spinner - The ring the Volume up button turns while it is pending.
157
+ * @csspart volume-up-text - The box the Volume up button's icon sits in.
158
+ *
159
+ * @cssproperty --device-screen-ratio - The drawn screen's width divided by its height, turned by `rotation`, as a number. Written by the frame once the screen's size is known.
160
+ * @cssproperty --device-screen-rotation - How far the picture is turned, as an angle. The frame writes it from `rotation`.
161
+ * @cssproperty --device-screen-touch-duration - How long a swipe's ring takes to travel, as a time. Written on each ring from `showSwipe()`.
162
+ * @cssproperty --device-screen-touch-to-x - Where a swipe's ring travels to, across the screen, as a percentage. Written on each ring from `showSwipe()`.
163
+ * @cssproperty --device-screen-touch-to-y - Where a swipe's ring travels to, down the screen, as a percentage. Written on each ring from `showSwipe()`.
164
+ * @cssproperty --device-screen-touch-x - Where a ring is, across the screen, as a percentage. Written on each ring.
165
+ * @cssproperty --device-screen-touch-y - Where a ring is, down the screen, as a percentage. Written on each ring.
166
+ *
167
+ * @cssstate empty - No element that draws the stream is inside, which the frame knows once it runs in the browser.
168
+ * @cssstate fullscreen - The device fills the screen.
169
+ * @cssstate loading - `loading` is set.
170
+ * @cssstate readonly - `readonly` is set, and the screen sends nothing.
171
+ * @cssstate sideways - `rotation` turns the picture a quarter, so the drawn screen is the device's height wide.
172
+ * @cssstate touching - A finger is on the screen.
173
+ */
174
+ export declare class HelixHeadlessDeviceScreen extends HelixElement {
175
+ /**
176
+ * The key this family's words are registered under, its styled tag:
177
+ * `registerWords('de', { 'helix-device-screen': { homeLabel: 'Home' } })`.
178
+ */
179
+ static words: string;
180
+ protected static markRules: string[];
181
+ /** The Back button's label. */
182
+ backLabel: string;
183
+ /**
184
+ * Which hardware buttons to draw, as a list: `back`, `home`, `recents`,
185
+ * `power`, `volume`, `rotate`, `screenshot`, and `fullscreen`, or `none`.
186
+ * They are drawn in that order whatever order the list is in. Absent is
187
+ * `home screenshot`. `volume` draws Volume up and Volume down, and `rotate`
188
+ * draws Rotate left and Rotate right.
189
+ */
190
+ controls?: string;
191
+ /** The name of the toolbar of hardware buttons, read by screen readers. */
192
+ controlsLabel: string;
193
+ /**
194
+ * Which side of the device the hardware buttons sit on. Absent and `top`
195
+ * are a row above it, `bottom` is a row below it, and `start` and `end` are
196
+ * a column beside it, as the Android Emulator draws its toolbar. The words
197
+ * are sides, as Carousel's are, and not the corners a map's controls take.
198
+ */
199
+ controlsPlacement?: 'bottom' | 'end' | 'start' | 'top';
200
+ /** The screen's name where `label` is empty and the host has no `aria-label`. */
201
+ fallbackLabel: string;
202
+ /**
203
+ * Also sends key presses with Control, Command, or Alt held, which are left
204
+ * to the browser otherwise. For an app that owns its window. Command or
205
+ * Control with V pastes either way.
206
+ */
207
+ forwardShortcuts: boolean;
208
+ /** The fullscreen button's label. */
209
+ fullscreenLabel: string;
210
+ /** The Home button's label. */
211
+ homeLabel: string;
212
+ /**
213
+ * What a screen reader says about the keys when it reaches the screen,
214
+ * after its name.
215
+ */
216
+ keysHintLabel: string;
217
+ /**
218
+ * The device's name, read by screen readers as the screen's name, such as
219
+ * "iPhone 17 Pro". Name each device on a page with several. Required.
220
+ */
221
+ label: string;
222
+ /**
223
+ * Shows the `loading` slot over the screen, for a stream that is starting
224
+ * or has stopped. Screen readers hear `loading-label`.
225
+ */
226
+ loading: boolean;
227
+ /** What the screen shows and screen readers hear while `loading` is set and nothing is in the `loading` slot. */
228
+ loadingLabel: string;
229
+ /** The Power button's label. */
230
+ powerLabel: string;
231
+ /**
232
+ * Shows the screen and sends nothing: no touches, scrolls, keys, or button
233
+ * presses. The screen is then a picture, out of the tab order, and the
234
+ * hardware buttons are off but for screenshot and fullscreen. Buttons of
235
+ * your own in the `controls` slot are yours to turn off.
236
+ */
237
+ readonly: boolean;
238
+ /** The Recent apps button's label. */
239
+ recentsLabel: string;
240
+ /**
241
+ * What a screen reader calls the screen in place of its role, after its
242
+ * name: "iPhone 17 Pro, screen". Empty leaves the role.
243
+ */
244
+ roleLabel: string;
245
+ /** The Rotate left button's label. */
246
+ rotateLeftLabel: string;
247
+ /** The Rotate right button's label. */
248
+ rotateRightLabel: string;
249
+ /**
250
+ * How far to turn the picture clockwise, in degrees: `90`, `180`, or `270`.
251
+ * For a source that sends frames in the device's natural orientation while
252
+ * the device is turned. Every point is turned back, so events stay in the
253
+ * device's own orientation. A source whose frames turn with the device
254
+ * needs none.
255
+ */
256
+ rotation: number;
257
+ /**
258
+ * The screen's height in the units your device takes input in: points for
259
+ * the iOS Simulator, pixels for an Android device. Set with `screen-width`.
260
+ * Set alone, the width follows the stream's shape, and with neither, both
261
+ * are the stream's own size in pixels.
262
+ */
263
+ screenHeight?: number | undefined;
264
+ /** The screenshot button's label. */
265
+ screenshotLabel: string;
266
+ /**
267
+ * The screen's width in the units your device takes input in, as
268
+ * `screen-height` is. Set alone, the height follows the stream's shape.
269
+ */
270
+ screenWidth?: number | undefined;
271
+ /**
272
+ * The screen's outline. Absent is a rectangle with rounded corners;
273
+ * `square` has square corners, as on a phone with a Home button or a
274
+ * television, and `circle` is round, as on a round watch, and takes
275
+ * touches inside the circle only.
276
+ */
277
+ shape?: 'circle' | 'square';
278
+ /**
279
+ * Draws a ring under each finger on the screen, as the iOS Simulator's
280
+ * Show single touches does. Rings from `showTap()` and `showSwipe()` are
281
+ * drawn either way.
282
+ */
283
+ showTouches: boolean;
284
+ /** The Volume down button's label. */
285
+ volumeDownLabel: string;
286
+ /** The Volume up button's label. */
287
+ volumeUpLabel: string;
288
+ /** Whether the device fills the screen. */
289
+ private filled;
290
+ /** The stream's own size in pixels, once the element drawing it says. */
291
+ private intrinsic;
292
+ /** The rings on the screen now. */
293
+ private marks;
294
+ /** The fingers on the screen now, by the pointer each one is. */
295
+ private readonly fingers;
296
+ /** The most fingers that were down at once since the screen was last bare. */
297
+ private crowd;
298
+ /**
299
+ * The keys sent down and not yet up, by their `code`, or by their `key`
300
+ * where a soft keyboard or an input method reports no code.
301
+ */
302
+ private readonly held;
303
+ /** When a hardware button was pressed, so its release can say how long it was held. */
304
+ private heldSince;
305
+ /** The next ring's key. */
306
+ private nextMark;
307
+ /** The waits that take rings away. */
308
+ private readonly timers;
309
+ /** The element drawing the stream, while one is listened to. */
310
+ private watched;
311
+ /** A canvas's own size, which changes with no event. */
312
+ private resized;
313
+ /**
314
+ * Draws again as children arrive or leave. A button of the page's for the
315
+ * `controls` slot can arrive while no row is drawn, and then no slot exists
316
+ * to report it.
317
+ */
318
+ protected readonly childWatch: ChildrenController;
319
+ /**
320
+ * The buttons as one tab stop, the arrow keys moving along the row, or up
321
+ * and down a column beside the device. The page's own buttons in the
322
+ * `controls` slot are among them.
323
+ */
324
+ protected readonly controlKeys: ToolbarController;
325
+ private readonly fullscreen;
326
+ /**
327
+ * Whether the buttons are drawn raised, which the styled tier says and the
328
+ * headless tier leaves unset, having nothing to paint.
329
+ */
330
+ protected get controlsRaised(): boolean;
331
+ /** Whether the buttons are a column beside the device rather than a row. */
332
+ private get column();
333
+ /** How many quarter turns `rotation` is. */
334
+ private get turns();
335
+ /**
336
+ * The screen's size in the device's own way up, where the page or the stream
337
+ * has said it.
338
+ *
339
+ * **One side from the page is never mixed with the other from the stream**,
340
+ * which counts in pixels where the page may count in points: the missing
341
+ * side is the given one turned by the stream's shape.
342
+ */
343
+ private get size();
344
+ /**
345
+ * The element drawing the stream: the first child in no named slot, which is
346
+ * what the default slot holds. Read off the children, so it is known before
347
+ * the render, and none on a server.
348
+ */
349
+ private get stream();
350
+ /** The screen, where it has been drawn. */
351
+ private get screen();
352
+ /** Whether `controls`, or the resting controls, names a button. */
353
+ private draws;
354
+ /**
355
+ * An element's own size in pixels, read by its tag: a server has no
356
+ * `HTMLVideoElement` to compare with.
357
+ */
358
+ private sizeOf;
359
+ /** Reads the stream's own size off the element drawing it. */
360
+ private measure;
361
+ private readonly handleMeasure;
362
+ /** Stops listening to the element that drew the stream. */
363
+ private unwatch;
364
+ /**
365
+ * Listens to the element drawing the stream for its size: a video says it
366
+ * on `loadedmetadata` and `resize`, an image on `load`, and a canvas changes
367
+ * its `width` and `height` with no event at all.
368
+ */
369
+ private watch;
370
+ /** A stream put in or taken out, which is read again on the next render. */
371
+ private readonly handleSlotChange;
372
+ /**
373
+ * Where a pointer is on the drawn screen, as a fraction of it, or nothing
374
+ * where it is off the screen's shape. `clamp` holds a finger that has left
375
+ * the screen at its edge, as a finger on glass stops at the glass.
376
+ */
377
+ private fractionAt;
378
+ /**
379
+ * The screen's size for an event: the one the page or the stream gave, or
380
+ * the drawn screen's own in CSS pixels where neither has, so the points an
381
+ * event carries agree with the size beside them.
382
+ */
383
+ private sizeFor;
384
+ /** Sends a touch for a finger, and for its mirror where it has one. */
385
+ private sendTouch;
386
+ /** The lowest number free for a finger, with the one after it free too for a mirror. */
387
+ private freeId;
388
+ /** How many touches are down, a mirror counting as one of its own. */
389
+ private get touches();
390
+ /** The rings under the fingers, with `show-touches`, kept beside the rings that were shown. */
391
+ private holdMarks;
392
+ /**
393
+ * A finger landing on the screen. The screen takes focus, so keys follow,
394
+ * and keeps the pointer, so a finger that slides off the screen still lifts
395
+ * on it.
396
+ *
397
+ * **The primary button only.** A right click or a middle click is the
398
+ * page's, for a menu or a new tab, and a device has no second finger
399
+ * button to send it to.
400
+ */
401
+ private readonly handlePointerDown;
402
+ private readonly handlePointerMove;
403
+ /**
404
+ * A finger lifting, or the browser taking it away. Once the screen is bare,
405
+ * one finger that lifted is a tap or a swipe; a touch that had more fingers
406
+ * on it, or that the browser took away, is neither.
407
+ */
408
+ private readonly handlePointerUp;
409
+ /** Sends what one finger did, as a tap or a swipe. */
410
+ private sendGesture;
411
+ /**
412
+ * A wheel or a trackpad over the screen, which scrolls the device and not
413
+ * the page. Control or Command with the wheel is the page's zoom, and a
414
+ * trackpad's pinch arrives as it, so it stays the page's unless
415
+ * `forward-shortcuts` is set.
416
+ */
417
+ private readonly handleWheel;
418
+ /** Sends a key, and keeps the page from acting on it. */
419
+ private sendKey;
420
+ /**
421
+ * A key going down on the screen.
422
+ *
423
+ * **Tab is never sent**, so focus can always leave: a screen that kept
424
+ * every key would hold a keyboard reader inside it. **A shortcut is the
425
+ * browser's** unless `forward-shortcuts` is set, so page zoom, find, and
426
+ * the window's own keys keep working. AltGr types a character, and is not
427
+ * a shortcut, although it reports Control and Alt on Windows. The paste
428
+ * shortcut always reaches the browser, which pastes into the screen.
429
+ */
430
+ private readonly handleKeydown;
431
+ /** A key coming up, sent only where its press was: a Tab into the screen lifts on it. */
432
+ private readonly handleKeyup;
433
+ /**
434
+ * Focus leaving with keys still down, which would otherwise stay down on
435
+ * the device: each is sent as released.
436
+ */
437
+ private readonly handleBlur;
438
+ /**
439
+ * Text pasted while the screen has focus, sent as text.
440
+ *
441
+ * **Heard on the document, wherever the paste lands.** A browser sends a
442
+ * paste to the text selected on the page where there is any, and WebKit
443
+ * sends one with nothing selected to the host. A press on the screen keeps
444
+ * the selection it found, so copying from another pane, pressing the screen,
445
+ * and pasting would otherwise send the device nothing.
446
+ */
447
+ private readonly handlePaste;
448
+ /** A hardware button going down, so its release can say how long it was held. */
449
+ private readonly handleHoldStart;
450
+ /**
451
+ * A hardware button pressed, with how long a pointer held it. A press from
452
+ * a key has no length, and says `0`.
453
+ */
454
+ private pressed;
455
+ /**
456
+ * Presses a hardware button, as its control does: sends
457
+ * `helix-device-button`. `duration` is how long it is held, in
458
+ * milliseconds.
459
+ */
460
+ press(button: DeviceButton, duration?: number): void;
461
+ /** Asks for a screenshot, as the screenshot button does: sends `helix-device-screenshot`. */
462
+ screenshot(): void;
463
+ /**
464
+ * The picture on the screen now, as an image, at the stream's own size and
465
+ * turned by `rotation`. For a page with no sharper screenshot from its
466
+ * source.
467
+ *
468
+ * Fails where there is no stream, where it has not drawn a frame, and where
469
+ * the browser will not let a page read it, such as an image from another
470
+ * origin served without CORS.
471
+ */
472
+ capture(type?: string, quality?: number): Promise<Blob>;
473
+ /**
474
+ * Draws a ring at a point on the screen for a moment, in the device's
475
+ * units, for a touch made elsewhere, such as by an agent. Drawn whether or
476
+ * not `show-touches` is set, and nothing is sent.
477
+ */
478
+ showTap(x: number, y: number): void;
479
+ /**
480
+ * Draws a ring that travels from one point to another over `duration`
481
+ * milliseconds, in the device's units, for a swipe made elsewhere, as
482
+ * `showTap()` does for a tap.
483
+ */
484
+ showSwipe(fromX: number, fromY: number, toX: number, toY: number, duration?: number): void;
485
+ /**
486
+ * Where a point in the device's units is drawn, as a fraction of the drawn
487
+ * screen, measured against the size the events carry, so a point an event
488
+ * sent is drawn where it came from.
489
+ */
490
+ private drawnAt;
491
+ /** Adds a ring, and takes it away once it has been seen. */
492
+ private addMark;
493
+ /** A screen put back on the page listens to its stream and for pastes again. */
494
+ connectedCallback(): void;
495
+ /**
496
+ * Taken off the page mid-touch or with a key down, as a pane closing is:
497
+ * each finger is sent as canceled and each key as released, or the device
498
+ * would hold them down.
499
+ */
500
+ disconnectedCallback(): void;
501
+ protected firstUpdated(changed: PropertyValues): void;
502
+ protected willUpdate(changed: PropertyValues): void;
503
+ /**
504
+ * The hardware buttons `controls` names, in one fixed order, and the page's
505
+ * own in the `controls` slot before the fullscreen button. Each is an Icon
506
+ * Button written out, because a part name behind an interpolation is a part
507
+ * the manifest cannot see.
508
+ *
509
+ * **Drawn while there is a button to hold**, a hardware one or one of the
510
+ * page's, which the frame knows only once its children are known: a server
511
+ * draws the hardware buttons alone.
512
+ */
513
+ protected renderControls(): TemplateResult | typeof nothing;
514
+ /** The rings on the screen, each placed by the custom properties it carries. */
515
+ private renderMarks;
516
+ /**
517
+ * The device, its buttons, and the strips around it.
518
+ *
519
+ * **The buttons come before the device in the markup where they are drawn
520
+ * before it**, above it or at its start, and after it otherwise, so the
521
+ * order Tab takes is the order the eye takes. A column at a side is drawn
522
+ * inside the device's box, so it stands beside the device however wide the
523
+ * box is.
524
+ */
525
+ protected render(): TemplateResult;
526
+ }
527
+ declare global {
528
+ interface HTMLElementTagNameMap {
529
+ 'helix-headless-device-screen': HelixHeadlessDeviceScreen;
530
+ }
531
+ }