@peekling/runtime 0.1.0 → 0.1.2
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/README.md +59 -8
- package/dist/canvas-renderer.d.ts +17 -0
- package/dist/canvas-renderer.d.ts.map +1 -0
- package/dist/canvas-renderer.js +192 -0
- package/dist/canvas.d.ts +5 -0
- package/dist/canvas.d.ts.map +1 -0
- package/dist/canvas.js +6 -0
- package/dist/configuration-validation.d.ts.map +1 -1
- package/dist/configuration-validation.js +176 -1
- package/dist/content.d.ts +3 -0
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +33 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/input.d.ts.map +1 -1
- package/dist/input.js +4 -1
- package/dist/interaction.d.ts +37 -0
- package/dist/interaction.d.ts.map +1 -0
- package/dist/interaction.js +204 -0
- package/dist/overrides.d.ts +8 -0
- package/dist/overrides.d.ts.map +1 -1
- package/dist/overrides.js +18 -16
- package/dist/path-sampler.d.ts +9 -0
- package/dist/path-sampler.d.ts.map +1 -0
- package/dist/path-sampler.js +47 -0
- package/dist/peekling.css +1 -1
- package/dist/peekling.css.sri +1 -1
- package/dist/peekling.js +1365 -86
- package/dist/peekling.js.sri +1 -1
- package/dist/peekling.min.js +1 -1
- package/dist/peekling.min.js.sri +1 -1
- package/dist/plan-compiler.d.ts +2 -0
- package/dist/plan-compiler.d.ts.map +1 -1
- package/dist/plan-compiler.js +71 -14
- package/dist/plan.d.ts +27 -1
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +281 -22
- package/dist/registry.js +2 -2
- package/dist/renderer.d.ts +18 -1
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +1 -0
- package/dist/runtime-validation.d.ts.map +1 -1
- package/dist/runtime-validation.js +35 -0
- package/dist/runtime.d.ts +49 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +365 -14
- package/dist/targets.d.ts +11 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +106 -0
- package/dist/types.d.ts +61 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ data cannot contain code, callbacks, DOM nodes, or raw HTML.
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
npm install @peekling/runtime@0.1.
|
|
13
|
+
npm install @peekling/runtime@0.1.2
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
The runtime supports modern ESM applications and the complete browser bundle.
|
|
@@ -48,6 +48,11 @@ After `ready` resolves, the Pack, stylesheet, initial State, and owned DOM are
|
|
|
48
48
|
ready. `character: "peek"` is a networked selection. It resolves an exact pinned
|
|
49
49
|
manifest and verifies the manifest and selected atlas before browser decoding.
|
|
50
50
|
|
|
51
|
+
The default `companion` behavior follows the pointer when the Pack provides
|
|
52
|
+
locomotion. The character can also be dragged and thrown. Clicking the character
|
|
53
|
+
shows or hides its owned content bubble. Set `interaction: false` only when the
|
|
54
|
+
host needs a pointer-transparent character with no direct control.
|
|
55
|
+
|
|
51
56
|
Other bundlers can copy `@peekling/runtime/peekling.css` to a public asset and
|
|
52
57
|
pass its final URL through `styles.url`. An HTTP or HTTPS ESM module can omit
|
|
53
58
|
`styles` when a usable `peekling.css` sits beside the module. A module location
|
|
@@ -85,6 +90,8 @@ mirrored asset.
|
|
|
85
90
|
| `override(input)` | Request temporary ownership of declared presentation channels. |
|
|
86
91
|
| `pause()` | Add the host pause reason and park runtime work. |
|
|
87
92
|
| `resume()` | Remove the host pause reason. Work resumes after every suspension reason clears. |
|
|
93
|
+
| `refreshTargets()` | Refresh host-approved target geometry after an application-specific layout change. |
|
|
94
|
+
| `setIndicator(value)` | Replace the accessible dot or count notification, including its optional color. Pass `null` to clear it. |
|
|
88
95
|
| `destroy()` | Abort pending work and release the instance's listeners, observers, frames, timers, roots, and object URLs. |
|
|
89
96
|
|
|
90
97
|
Configuration failures that can be decided without Pack bytes throw before
|
|
@@ -138,6 +145,46 @@ The selected State must exist in the Pack. An Override never edits the Plan.
|
|
|
138
145
|
When its lifetime ends, the runtime reevaluates the unchanged Plan from current
|
|
139
146
|
world state.
|
|
140
147
|
|
|
148
|
+
## Drag, throw, click, and custom routes
|
|
149
|
+
|
|
150
|
+
Direct manipulation is enabled without adding Plan rules:
|
|
151
|
+
|
|
152
|
+
```js
|
|
153
|
+
const companion = hatch({
|
|
154
|
+
character: "peek",
|
|
155
|
+
interaction: {
|
|
156
|
+
gravity: 1800,
|
|
157
|
+
maxThrowSpeed: 1800,
|
|
158
|
+
bounce: 0.35,
|
|
159
|
+
label: "Open controls or drag Peek",
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Press actions can toggle, show, or hide content. They can also emit one bounded
|
|
165
|
+
application Event. A drag suppresses its trailing click. Throw integration is
|
|
166
|
+
time based, bounded to the viewport, and releases ownership back to the Plan
|
|
167
|
+
after landing.
|
|
168
|
+
|
|
169
|
+
Targets connect motion or catching to host-approved geometry. Custom SVG paths
|
|
170
|
+
remain data and are sampled with detached browser geometry. See
|
|
171
|
+
[Character interaction and motion](../../docs/interaction-and-motion.md) for a
|
|
172
|
+
complete sunlit nook, viewport traversal, target catching, notification badge,
|
|
173
|
+
and custom path examples.
|
|
174
|
+
|
|
175
|
+
## Optional Canvas renderer
|
|
176
|
+
|
|
177
|
+
Use the Canvas entry point when character frame presentation should use Canvas
|
|
178
|
+
2D:
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
import { hatchCanvas as hatch } from "@peekling/runtime/canvas";
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Canvas uses the same Configuration, Pack, Plan, Event queue, interaction,
|
|
185
|
+
physics, targets, and lifecycle as the default DOM renderer. Content bubbles
|
|
186
|
+
remain DOM surfaces so native controls and accessibility keep working.
|
|
187
|
+
|
|
141
188
|
See the repository [configuration guide](../../docs/configuration.md) for Plan
|
|
142
189
|
syntax and recipes. The [execution model](../../docs/execution-model.md) defines
|
|
143
190
|
Event ordering, channel ownership, Override conflicts, and cleanup.
|
|
@@ -150,14 +197,14 @@ free. The element is a lifecycle facade over hatch, not a second engine.
|
|
|
150
197
|
```html
|
|
151
198
|
<script
|
|
152
199
|
defer
|
|
153
|
-
src="https://cdn.jsdelivr.net/npm/@peekling/runtime@0.1.
|
|
200
|
+
src="https://cdn.jsdelivr.net/npm/@peekling/runtime@0.1.2/dist/peekling.min.js"
|
|
154
201
|
integrity="sha384-<runtime-release-hash>"
|
|
155
202
|
crossorigin="anonymous"
|
|
156
203
|
></script>
|
|
157
204
|
|
|
158
205
|
<peekling-character
|
|
159
206
|
character="peek"
|
|
160
|
-
styles-url="https://cdn.jsdelivr.net/npm/@peekling/runtime@0.1.
|
|
207
|
+
styles-url="https://cdn.jsdelivr.net/npm/@peekling/runtime@0.1.2/dist/peekling.css"
|
|
161
208
|
styles-integrity="sha256-<stylesheet-release-hash>"
|
|
162
209
|
></peekling-character>
|
|
163
210
|
```
|
|
@@ -255,6 +302,7 @@ admission, use the repository
|
|
|
255
302
|
| Import | Contents |
|
|
256
303
|
| -------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
257
304
|
| `@peekling/runtime` | Side-effect-free ESM hatch API, public types, visibility helpers, and explicit Web Component registration. |
|
|
305
|
+
| `@peekling/runtime/canvas` | Optional Canvas 2D character renderer using the same runtime contract. |
|
|
258
306
|
| `@peekling/runtime/browser` | Complete browser-global artifact. |
|
|
259
307
|
| `@peekling/runtime/peekling.css` | Required runtime stylesheet asset. |
|
|
260
308
|
| `@peekling/runtime/pack` | Supported Pack parsing and validation surface for authoring tools. |
|
|
@@ -272,17 +320,20 @@ host surfaces, blocked stylesheets, suspension, dismissal recovery, remount
|
|
|
272
320
|
cleanup, hostile host layout, root repair, and contained failures in Chromium,
|
|
273
321
|
Firefox, and WebKit.
|
|
274
322
|
|
|
323
|
+
The 0.1.2 record below measures the interaction and renderer release with the
|
|
324
|
+
exact release toolchain and required reserve.
|
|
325
|
+
|
|
275
326
|
<!-- peekling-size-evidence:start -->
|
|
276
327
|
|
|
277
|
-
The recorded canonical delivery measurement is
|
|
278
|
-
bytes Brotli. Against the
|
|
279
|
-
build leaves
|
|
280
|
-
After the required 256-byte reserve,
|
|
328
|
+
The recorded canonical delivery measurement is 38,139 bytes gzip and 33,418
|
|
329
|
+
bytes Brotli. Against the 40 KiB gzip and 40 KiB Brotli caps, that recorded
|
|
330
|
+
build leaves 2,821 bytes of gzip headroom and 7,542 bytes of Brotli headroom.
|
|
331
|
+
After the required 256-byte reserve, 2,565 gzip bytes and 7,286 Brotli bytes
|
|
281
332
|
remain for that build.
|
|
282
333
|
<!-- peekling-size-evidence:end -->
|
|
283
334
|
|
|
284
335
|
The record is bound to artifact hashes. Node 22.14.0, npm 11.16.0, and Node's
|
|
285
|
-
default zlib compression certify
|
|
336
|
+
default zlib compression certify those recorded values. Other supported Node
|
|
286
337
|
versions still enforce their local size cap and reserve.
|
|
287
338
|
|
|
288
339
|
The [browser performance guide](../../docs/browser-performance.md) explains the
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CharacterRenderer, type CharacterRendererFactory } from "./renderer.js";
|
|
2
|
+
import { type RuntimeStyleAsset } from "./styles.js";
|
|
3
|
+
import type { NormalizedPack, Point } from "./types.js";
|
|
4
|
+
/** Optional Canvas 2D presentation for the same runtime and Plan evaluator. */
|
|
5
|
+
export declare class CanvasRenderer implements CharacterRenderer {
|
|
6
|
+
#private;
|
|
7
|
+
readonly host: HTMLElement;
|
|
8
|
+
readonly ready: Promise<void>;
|
|
9
|
+
constructor(document: Document, pack: NormalizedPack, atlasUrl: string, scale: number, styles: RuntimeStyleAsset);
|
|
10
|
+
swapAtlas(pack: NormalizedPack, atlasUrl: string): Promise<void>;
|
|
11
|
+
setHidden(hidden: boolean): void;
|
|
12
|
+
nextFrameIn(now: number): number | undefined;
|
|
13
|
+
render(stateName: string, now: number, position: Point, devicePixelRatio?: number, lift?: number): void;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare const createCanvasRenderer: CharacterRendererFactory;
|
|
17
|
+
//# sourceMappingURL=canvas-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas-renderer.d.ts","sourceRoot":"","sources":["../src/canvas-renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC9B,MAAM,eAAe,CAAC;AAEvB,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExD,+EAA+E;AAC/E,qBAAa,cAAe,YAAW,iBAAiB;;IACtD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAkB9B,YACE,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,cAAc,EACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,iBAAiB,EAkC1B;IAEK,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE;IAED,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAE/B;IAED,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmB3C;IAED,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,KAAK,EACf,gBAAgB,SAAI,EACpB,IAAI,SAAI,GACP,IAAI,CA8DN;IAED,OAAO,IAAI,IAAI,CAOd;CA4DF;AAED,eAAO,MAAM,oBAAoB,EAAE,wBAOhC,CAAC"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { animationCycleMs } from "./locomotion.js";
|
|
2
|
+
import { frameAt, snapToDevicePixel, } from "./renderer.js";
|
|
3
|
+
import { runtimeMessage } from "./runtime-diagnostics.js";
|
|
4
|
+
import { connectRuntimeHost, ShadowStyleSheet, } from "./styles.js";
|
|
5
|
+
/** Optional Canvas 2D presentation for the same runtime and Plan evaluator. */
|
|
6
|
+
export class CanvasRenderer {
|
|
7
|
+
host;
|
|
8
|
+
ready;
|
|
9
|
+
#document;
|
|
10
|
+
#root;
|
|
11
|
+
#canvas;
|
|
12
|
+
#context;
|
|
13
|
+
#styles;
|
|
14
|
+
#canvasRule;
|
|
15
|
+
#pack;
|
|
16
|
+
#image;
|
|
17
|
+
#scale;
|
|
18
|
+
#logicalWidth = 0;
|
|
19
|
+
#logicalHeight = 0;
|
|
20
|
+
#state = "";
|
|
21
|
+
#stateStartedAt = 0;
|
|
22
|
+
#frame = -1;
|
|
23
|
+
#destroyed = false;
|
|
24
|
+
#loadGeneration = 0;
|
|
25
|
+
constructor(document, pack, atlasUrl, scale, styles) {
|
|
26
|
+
this.#document = document;
|
|
27
|
+
this.#pack = pack;
|
|
28
|
+
this.#scale = scale;
|
|
29
|
+
this.host = document.createElement("div");
|
|
30
|
+
this.host.setAttribute("aria-hidden", "true");
|
|
31
|
+
this.host.setAttribute("data-peekling-host", "");
|
|
32
|
+
this.host.setAttribute("data-peekling-renderer", "canvas");
|
|
33
|
+
this.#root = this.host.attachShadow({ mode: "closed" });
|
|
34
|
+
this.#styles = new ShadowStyleSheet(document, this.#root, styles);
|
|
35
|
+
this.#canvas = document.createElement("canvas");
|
|
36
|
+
this.#canvas.className = "sprite";
|
|
37
|
+
const context = this.#canvas.getContext("2d", { alpha: true });
|
|
38
|
+
if (!context) {
|
|
39
|
+
throw new Error(runtimeMessage("renderer.canvas", "Canvas 2D is unavailable"));
|
|
40
|
+
}
|
|
41
|
+
this.#context = context;
|
|
42
|
+
this.#image = document.createElement("img");
|
|
43
|
+
this.#root.append(this.#canvas);
|
|
44
|
+
this.ready = Promise.all([
|
|
45
|
+
this.#styles.ready.then(() => {
|
|
46
|
+
if (this.#destroyed)
|
|
47
|
+
return;
|
|
48
|
+
this.#canvasRule = this.#styles.addRule(".sprite");
|
|
49
|
+
}),
|
|
50
|
+
this.#loadAtlas(pack, atlasUrl),
|
|
51
|
+
]).then(() => {
|
|
52
|
+
if (this.#destroyed)
|
|
53
|
+
return;
|
|
54
|
+
this.#applyGeometry(pack);
|
|
55
|
+
});
|
|
56
|
+
void this.ready.catch(() => { });
|
|
57
|
+
this.#repair();
|
|
58
|
+
}
|
|
59
|
+
async swapAtlas(pack, atlasUrl) {
|
|
60
|
+
if (this.#destroyed)
|
|
61
|
+
return;
|
|
62
|
+
await this.#loadAtlas(pack, atlasUrl);
|
|
63
|
+
if (this.#destroyed || this.#pack !== pack)
|
|
64
|
+
return;
|
|
65
|
+
this.#applyGeometry(pack);
|
|
66
|
+
this.#frame = -1;
|
|
67
|
+
}
|
|
68
|
+
setHidden(hidden) {
|
|
69
|
+
if (!this.#destroyed)
|
|
70
|
+
this.host.toggleAttribute("hidden", hidden);
|
|
71
|
+
}
|
|
72
|
+
nextFrameIn(now) {
|
|
73
|
+
if (this.#destroyed)
|
|
74
|
+
return;
|
|
75
|
+
const state = this.#pack.states[this.#state];
|
|
76
|
+
if (!state || state.frames.length < 2)
|
|
77
|
+
return;
|
|
78
|
+
const elapsed = Math.max(0, now - this.#stateStartedAt);
|
|
79
|
+
if (state.durations?.length === state.frames.length) {
|
|
80
|
+
const total = animationCycleMs(state);
|
|
81
|
+
if (!state.loop && elapsed >= total - state.durations.at(-1))
|
|
82
|
+
return;
|
|
83
|
+
const active = state.loop ? elapsed % total : elapsed;
|
|
84
|
+
let boundary = 0;
|
|
85
|
+
for (const duration of state.durations) {
|
|
86
|
+
boundary += duration;
|
|
87
|
+
if (boundary > active)
|
|
88
|
+
return boundary - active;
|
|
89
|
+
}
|
|
90
|
+
return state.loop ? state.durations[0] : undefined;
|
|
91
|
+
}
|
|
92
|
+
const interval = 1000 / (state.fps ?? 1);
|
|
93
|
+
if (!state.loop && elapsed >= interval * (state.frames.length - 1))
|
|
94
|
+
return;
|
|
95
|
+
return interval - (elapsed % interval || 0);
|
|
96
|
+
}
|
|
97
|
+
render(stateName, now, position, devicePixelRatio = 1, lift = 0) {
|
|
98
|
+
if (this.#destroyed)
|
|
99
|
+
return;
|
|
100
|
+
this.#repair();
|
|
101
|
+
const state = this.#pack.states[stateName];
|
|
102
|
+
if (!state) {
|
|
103
|
+
throw new Error(runtimeMessage("renderer.state", `Renderer received unknown state ${stateName}`));
|
|
104
|
+
}
|
|
105
|
+
if (stateName !== this.#state) {
|
|
106
|
+
this.#state = stateName;
|
|
107
|
+
this.#stateStartedAt = now;
|
|
108
|
+
this.#frame = -1;
|
|
109
|
+
this.host.setAttribute("data-peekling-state", stateName);
|
|
110
|
+
}
|
|
111
|
+
const frame = frameAt(state, now - this.#stateStartedAt);
|
|
112
|
+
if (frame !== this.#frame && this.#image.complete) {
|
|
113
|
+
const column = frame % this.#pack.atlas.columns;
|
|
114
|
+
const row = Math.floor(frame / this.#pack.atlas.columns);
|
|
115
|
+
const sourceWidth = this.#pack.atlas.cellWidth;
|
|
116
|
+
const sourceHeight = this.#pack.atlas.cellHeight;
|
|
117
|
+
this.#context.clearRect(0, 0, sourceWidth, sourceHeight);
|
|
118
|
+
this.#context.drawImage(this.#image, column * sourceWidth, row * sourceHeight, sourceWidth, sourceHeight, 0, 0, sourceWidth, sourceHeight);
|
|
119
|
+
this.#frame = frame;
|
|
120
|
+
this.host.setAttribute("data-peekling-frame", String(frame));
|
|
121
|
+
}
|
|
122
|
+
const width = this.#logicalWidth * this.#scale;
|
|
123
|
+
const height = this.#logicalHeight * this.#scale;
|
|
124
|
+
const x = snapToDevicePixel(position.x - width / 2, devicePixelRatio);
|
|
125
|
+
const y = snapToDevicePixel(position.y - height / 2 - lift, devicePixelRatio);
|
|
126
|
+
const rule = this.#canvasRule;
|
|
127
|
+
if (!rule) {
|
|
128
|
+
throw new Error(runtimeMessage("renderer.styles", "Peekling stylesheet is not ready"));
|
|
129
|
+
}
|
|
130
|
+
const transform = `translate3d(${x}px,${y}px,0) scale(${this.#scale})`;
|
|
131
|
+
if (rule.transform !== transform)
|
|
132
|
+
rule.transform = transform;
|
|
133
|
+
const xValue = String(x);
|
|
134
|
+
const yValue = String(y);
|
|
135
|
+
if (this.host.getAttribute("data-peekling-x") !== xValue) {
|
|
136
|
+
this.host.setAttribute("data-peekling-x", xValue);
|
|
137
|
+
}
|
|
138
|
+
if (this.host.getAttribute("data-peekling-y") !== yValue) {
|
|
139
|
+
this.host.setAttribute("data-peekling-y", yValue);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
destroy() {
|
|
143
|
+
if (this.#destroyed)
|
|
144
|
+
return;
|
|
145
|
+
this.#destroyed = true;
|
|
146
|
+
this.#loadGeneration += 1;
|
|
147
|
+
this.#image.src = "";
|
|
148
|
+
this.#styles.destroy();
|
|
149
|
+
this.host.remove();
|
|
150
|
+
}
|
|
151
|
+
async #loadAtlas(pack, atlasUrl) {
|
|
152
|
+
const generation = ++this.#loadGeneration;
|
|
153
|
+
const image = this.#document.createElement("img");
|
|
154
|
+
image.decoding = "async";
|
|
155
|
+
await new Promise((resolve, reject) => {
|
|
156
|
+
image.addEventListener("load", () => resolve(), { once: true });
|
|
157
|
+
image.addEventListener("error", () => reject(new Error(runtimeMessage("renderer.canvas-atlas", "Canvas atlas failed"))), { once: true });
|
|
158
|
+
image.src = atlasUrl;
|
|
159
|
+
});
|
|
160
|
+
if (this.#destroyed || generation !== this.#loadGeneration)
|
|
161
|
+
return;
|
|
162
|
+
this.#pack = pack;
|
|
163
|
+
this.#image = image;
|
|
164
|
+
}
|
|
165
|
+
#applyGeometry(pack) {
|
|
166
|
+
const rule = this.#canvasRule;
|
|
167
|
+
if (!rule) {
|
|
168
|
+
throw new Error(runtimeMessage("renderer.styles", "Peekling stylesheet is not ready"));
|
|
169
|
+
}
|
|
170
|
+
this.#logicalWidth = pack.atlas.logicalWidth ?? pack.atlas.cellWidth;
|
|
171
|
+
this.#logicalHeight = pack.atlas.logicalHeight ?? pack.atlas.cellHeight;
|
|
172
|
+
this.#canvas.width = pack.atlas.cellWidth;
|
|
173
|
+
this.#canvas.height = pack.atlas.cellHeight;
|
|
174
|
+
rule.width = `${this.#logicalWidth}px`;
|
|
175
|
+
rule.height = `${this.#logicalHeight}px`;
|
|
176
|
+
rule.imageRendering =
|
|
177
|
+
(pack.atlas.density ?? 1) === 1 ? "pixelated" : "auto";
|
|
178
|
+
}
|
|
179
|
+
#repair() {
|
|
180
|
+
if (this.#destroyed)
|
|
181
|
+
return;
|
|
182
|
+
connectRuntimeHost(this.host, this.#document, "data-peekling-host");
|
|
183
|
+
if (this.#root.host !== this.host ||
|
|
184
|
+
this.#canvas.getRootNode() !== this.#root) {
|
|
185
|
+
throw new Error(runtimeMessage("renderer.root", "Peekling character root structure was changed"));
|
|
186
|
+
}
|
|
187
|
+
if (this.host.getAttribute("aria-hidden") !== "true") {
|
|
188
|
+
this.host.setAttribute("aria-hidden", "true");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
export const createCanvasRenderer = (options) => new CanvasRenderer(options.document, options.pack, options.atlasUrl, options.scale, options.styles);
|
package/dist/canvas.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type PeeklingHatchInput, type PeeklingInstance, type PeeklingOptions } from "./runtime.js";
|
|
2
|
+
/** Hatch with Canvas 2D character pixels and accessible DOM content surfaces. */
|
|
3
|
+
export declare function hatchCanvas(input: PeeklingHatchInput | PeeklingOptions): PeeklingInstance;
|
|
4
|
+
export type { PeeklingHatchInput, PeeklingInstance, PeeklingOptions, } from "./runtime.js";
|
|
5
|
+
//# sourceMappingURL=canvas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../src/canvas.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAEtB,iFAAiF;AACjF,wBAAgB,WAAW,CACzB,KAAK,EAAE,kBAAkB,GAAG,eAAe,GAC1C,gBAAgB,CAElB;AAED,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,GAChB,MAAM,cAAc,CAAC"}
|
package/dist/canvas.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createCanvasRenderer } from "./canvas-renderer.js";
|
|
2
|
+
import { PeeklingRuntime, } from "./runtime.js";
|
|
3
|
+
/** Hatch with Canvas 2D character pixels and accessible DOM content surfaces. */
|
|
4
|
+
export function hatchCanvas(input) {
|
|
5
|
+
return PeeklingRuntime.hatch(input, createCanvasRenderer);
|
|
6
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configuration-validation.d.ts","sourceRoot":"","sources":["../src/configuration-validation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"configuration-validation.d.ts","sourceRoot":"","sources":["../src/configuration-validation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAgC/D,MAAM,MAAM,sBAAsB,GAAG,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,KACZ,IAAI,CAAC;AAEV,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,sBAAuB,SAAQ,SAAS;IACnD,QAAQ,CAAC,MAAM,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAEtD,YAAY,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAItD;CACF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,sBAAsB,GAC5B,WAAW,CA6Jb;AAkQD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,GAAG,OAAO,CAExE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validateHostContent } from "./content.js";
|
|
2
|
-
import { isHttpPath, isSurfaceColor, NAME_PATTERN } from "./contracts.js";
|
|
2
|
+
import { EVENT_NAME_PATTERN, isHttpPath, isSurfaceColor, NAME_PATTERN, STATE_NAME_PATTERN, } from "./contracts.js";
|
|
3
3
|
import { isRegisteredCharacter } from "./registry.js";
|
|
4
4
|
import { compactRuntimeDiagnostics } from "./runtime-diagnostics.js";
|
|
5
5
|
import { validStyleIntegrity } from "./styles.js";
|
|
@@ -13,6 +13,10 @@ const CONFIGURATION_FIELDS = [
|
|
|
13
13
|
"atlasUrl",
|
|
14
14
|
"styles",
|
|
15
15
|
"plan",
|
|
16
|
+
"preset",
|
|
17
|
+
"targets",
|
|
18
|
+
"interaction",
|
|
19
|
+
"indicator",
|
|
16
20
|
"content",
|
|
17
21
|
"bindings",
|
|
18
22
|
"theme",
|
|
@@ -50,6 +54,13 @@ export function validateConfiguration(options, baseUrl, fault) {
|
|
|
50
54
|
if (options.format !== undefined && options.format !== 1) {
|
|
51
55
|
reportConfigurationFault("unsupported-format", "$.format", fault);
|
|
52
56
|
}
|
|
57
|
+
if (options.plan !== undefined && options.preset !== undefined) {
|
|
58
|
+
reportConfigurationFault("incompatible-behavior", "$.preset", fault);
|
|
59
|
+
}
|
|
60
|
+
if (options.preset !== undefined &&
|
|
61
|
+
!["companion", "still", "bottom-patrol", "viewport-roam"].includes(options.preset)) {
|
|
62
|
+
reportConfigurationFault("invalid-preset", "$.preset", fault);
|
|
63
|
+
}
|
|
53
64
|
if (options.character !== undefined) {
|
|
54
65
|
if (typeof options.character !== "string" ||
|
|
55
66
|
!NAME_PATTERN.test(options.character)) {
|
|
@@ -127,6 +138,12 @@ export function validateConfiguration(options, baseUrl, fault) {
|
|
|
127
138
|
content = {};
|
|
128
139
|
}
|
|
129
140
|
validateBindings(options.bindings, content, fault);
|
|
141
|
+
validateTargets(options.targets, fault);
|
|
142
|
+
validateInteraction(options.interaction, options.targets, fault);
|
|
143
|
+
validateIndicator(options.indicator, fault);
|
|
144
|
+
if (options.interaction === false && options.indicator !== undefined) {
|
|
145
|
+
reportConfigurationFault("incompatible-indicator", "$.indicator", fault);
|
|
146
|
+
}
|
|
130
147
|
validateTheme(options.theme, fault);
|
|
131
148
|
validateDiagnostics(options.diagnostics, fault);
|
|
132
149
|
validateAccessibility(options.accessibility, fault);
|
|
@@ -137,6 +154,164 @@ export function validateConfiguration(options, baseUrl, fault) {
|
|
|
137
154
|
}
|
|
138
155
|
return content;
|
|
139
156
|
}
|
|
157
|
+
function validateInteraction(interaction, targets, fault) {
|
|
158
|
+
if (interaction === undefined || interaction === false)
|
|
159
|
+
return;
|
|
160
|
+
const checked = shape(interaction, "invalid-interaction", "$.interaction", [
|
|
161
|
+
"press",
|
|
162
|
+
"pressEvent",
|
|
163
|
+
"drag",
|
|
164
|
+
"throw",
|
|
165
|
+
"dragState",
|
|
166
|
+
"riseState",
|
|
167
|
+
"fallState",
|
|
168
|
+
"landState",
|
|
169
|
+
"gravity",
|
|
170
|
+
"maxThrowSpeed",
|
|
171
|
+
"bounce",
|
|
172
|
+
"floorInset",
|
|
173
|
+
"label",
|
|
174
|
+
"contentInitiallyHidden",
|
|
175
|
+
"clearIndicatorOnPress",
|
|
176
|
+
"catchTarget",
|
|
177
|
+
"catchAnchor",
|
|
178
|
+
"catchMargin",
|
|
179
|
+
"catchEvent",
|
|
180
|
+
], fault);
|
|
181
|
+
if (collectConfigurationFaults && !checked)
|
|
182
|
+
return;
|
|
183
|
+
const value = checked;
|
|
184
|
+
if (value.press !== undefined &&
|
|
185
|
+
![
|
|
186
|
+
"toggle-content",
|
|
187
|
+
"show-content",
|
|
188
|
+
"hide-content",
|
|
189
|
+
"emit",
|
|
190
|
+
"none",
|
|
191
|
+
].includes(value.press)) {
|
|
192
|
+
reportConfigurationFault("invalid-interaction", "$.interaction.press", fault);
|
|
193
|
+
}
|
|
194
|
+
if (value.pressEvent !== undefined &&
|
|
195
|
+
(typeof value.pressEvent !== "string" ||
|
|
196
|
+
!EVENT_NAME_PATTERN.test(value.pressEvent))) {
|
|
197
|
+
reportConfigurationFault("invalid-interaction-event", "$.interaction.pressEvent", fault);
|
|
198
|
+
}
|
|
199
|
+
if (value.press === "emit" && value.pressEvent === undefined) {
|
|
200
|
+
reportConfigurationFault("missing-interaction-event", "$.interaction.pressEvent", fault);
|
|
201
|
+
}
|
|
202
|
+
if (value.pressEvent !== undefined &&
|
|
203
|
+
value.press !== undefined &&
|
|
204
|
+
value.press !== "emit") {
|
|
205
|
+
reportConfigurationFault("incompatible-interaction-event", "$.interaction.pressEvent", fault);
|
|
206
|
+
}
|
|
207
|
+
for (const field of [
|
|
208
|
+
"drag",
|
|
209
|
+
"throw",
|
|
210
|
+
"contentInitiallyHidden",
|
|
211
|
+
"clearIndicatorOnPress",
|
|
212
|
+
]) {
|
|
213
|
+
if (value[field] !== undefined && typeof value[field] !== "boolean") {
|
|
214
|
+
reportConfigurationFault("invalid-interaction", `$.interaction.${field}`, fault);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
for (const field of [
|
|
218
|
+
"dragState",
|
|
219
|
+
"riseState",
|
|
220
|
+
"fallState",
|
|
221
|
+
"landState",
|
|
222
|
+
]) {
|
|
223
|
+
if (value[field] !== undefined &&
|
|
224
|
+
(typeof value[field] !== "string" ||
|
|
225
|
+
!STATE_NAME_PATTERN.test(value[field]))) {
|
|
226
|
+
reportConfigurationFault("invalid-interaction-state", `$.interaction.${field}`, fault);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
for (const [field, minimum, maximum] of [
|
|
230
|
+
["gravity", 0, 10_000],
|
|
231
|
+
["maxThrowSpeed", 0, 10_000],
|
|
232
|
+
["bounce", 0, 1],
|
|
233
|
+
["floorInset", 0, 1_000],
|
|
234
|
+
["catchMargin", 0, 1_000],
|
|
235
|
+
]) {
|
|
236
|
+
const item = value[field];
|
|
237
|
+
if (item !== undefined &&
|
|
238
|
+
(typeof item !== "number" ||
|
|
239
|
+
!Number.isFinite(item) ||
|
|
240
|
+
item < minimum ||
|
|
241
|
+
item > maximum)) {
|
|
242
|
+
reportConfigurationFault("invalid-interaction-range", `$.interaction.${field}`, fault);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (value.label !== undefined && !text(value.label, 120)) {
|
|
246
|
+
reportConfigurationFault("invalid-interaction-label", "$.interaction.label", fault);
|
|
247
|
+
}
|
|
248
|
+
if (value.catchTarget !== undefined &&
|
|
249
|
+
(typeof value.catchTarget !== "string" ||
|
|
250
|
+
!NAME_PATTERN.test(value.catchTarget) ||
|
|
251
|
+
!Object.hasOwn(targets ?? {}, value.catchTarget))) {
|
|
252
|
+
reportConfigurationFault("invalid-catch-target", "$.interaction.catchTarget", fault);
|
|
253
|
+
}
|
|
254
|
+
if (value.catchAnchor !== undefined &&
|
|
255
|
+
!["center", "top", "right", "bottom", "left"].includes(value.catchAnchor)) {
|
|
256
|
+
reportConfigurationFault("invalid-catch-anchor", "$.interaction.catchAnchor", fault);
|
|
257
|
+
}
|
|
258
|
+
if (value.catchEvent !== undefined &&
|
|
259
|
+
(typeof value.catchEvent !== "string" ||
|
|
260
|
+
!EVENT_NAME_PATTERN.test(value.catchEvent))) {
|
|
261
|
+
reportConfigurationFault("invalid-interaction-event", "$.interaction.catchEvent", fault);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function validateIndicator(indicator, fault) {
|
|
265
|
+
if (indicator === undefined)
|
|
266
|
+
return;
|
|
267
|
+
const checked = shape(indicator, "invalid-indicator", "$.indicator", ["kind", "count", "label", "color", "visible"], fault);
|
|
268
|
+
if (collectConfigurationFaults && !checked)
|
|
269
|
+
return;
|
|
270
|
+
const value = checked;
|
|
271
|
+
if (value.kind !== undefined &&
|
|
272
|
+
value.kind !== "dot" &&
|
|
273
|
+
value.kind !== "count") {
|
|
274
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.kind", fault);
|
|
275
|
+
}
|
|
276
|
+
if (!text(value.label, 120)) {
|
|
277
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.label", fault);
|
|
278
|
+
}
|
|
279
|
+
if (value.count !== undefined &&
|
|
280
|
+
(typeof value.count !== "number" ||
|
|
281
|
+
!Number.isInteger(value.count) ||
|
|
282
|
+
value.count < 0 ||
|
|
283
|
+
value.count > 999)) {
|
|
284
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.count", fault);
|
|
285
|
+
}
|
|
286
|
+
if (value.color !== undefined && !isSurfaceColor(value.color)) {
|
|
287
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.color", fault);
|
|
288
|
+
}
|
|
289
|
+
if (value.visible !== undefined && typeof value.visible !== "boolean") {
|
|
290
|
+
reportConfigurationFault("invalid-indicator", "$.indicator.visible", fault);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function validateTargets(targets, fault) {
|
|
294
|
+
if (targets === undefined)
|
|
295
|
+
return;
|
|
296
|
+
const checked = shape(targets, "invalid-targets", "$.targets", undefined, fault);
|
|
297
|
+
if (collectConfigurationFaults && !checked)
|
|
298
|
+
return;
|
|
299
|
+
const entries = Object.entries(checked);
|
|
300
|
+
if (entries.length > 16) {
|
|
301
|
+
reportConfigurationFault("target-limit", "$.targets", fault);
|
|
302
|
+
}
|
|
303
|
+
for (const [id, selector] of entries) {
|
|
304
|
+
if (!NAME_PATTERN.test(id)) {
|
|
305
|
+
reportConfigurationFault("invalid-target", `$.targets.${id}`, fault, id);
|
|
306
|
+
}
|
|
307
|
+
if (typeof selector !== "string" ||
|
|
308
|
+
selector.length < 1 ||
|
|
309
|
+
selector.length > 256 ||
|
|
310
|
+
/[\0\r\n]/.test(selector)) {
|
|
311
|
+
reportConfigurationFault("invalid-target-selector", `$.targets.${id}`, fault, id);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
140
315
|
export function validRuntimeName(value) {
|
|
141
316
|
return value === undefined || typeof value === "boolean" || text(value, 80);
|
|
142
317
|
}
|
package/dist/content.d.ts
CHANGED
|
@@ -39,6 +39,9 @@ export declare class ContentRenderer {
|
|
|
39
39
|
width: number;
|
|
40
40
|
height: number;
|
|
41
41
|
}, name?: string): void;
|
|
42
|
+
setUserHidden(hidden: boolean): boolean;
|
|
43
|
+
toggleUserHidden(): boolean;
|
|
44
|
+
get userHidden(): boolean;
|
|
42
45
|
destroy(): void;
|
|
43
46
|
}
|
|
44
47
|
//# sourceMappingURL=content.d.ts.map
|
package/dist/content.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,WAAW,EAGhB,KAAK,YAAY,EAGjB,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAErB,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,WAAW,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,GACd,WAAW,CA2Cb;AAyGD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,EACpC,OAAO,EAAE,WAAW,GACnB,IAAI,CAON;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,KAAK,EACf,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC3C,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC5C,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC,KAAK,CAwBP;AA8CD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,YAAY,EAAE,UAAU,CAAC;IAC5E,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,WAAW,EAGhB,KAAK,YAAY,EAGjB,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAIpB,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAErB,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,WAAW,GAAG,SAAS,EAC9B,OAAO,EAAE,MAAM,GACd,WAAW,CA2Cb;AAyGD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,EACpC,OAAO,EAAE,WAAW,GACnB,IAAI,CAON;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,KAAK,EACf,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC3C,SAAS,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC5C,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC,KAAK,CAwBP;AA8CD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,YAAY,EAAE,UAAU,CAAC;IAC5E,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IA6B9B,YAAY,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE,sBAA2B,EAmCnE;IAED,cAAc,CACZ,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,KAAK,EACf,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAC3C,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAC5C,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CA0IN;IAED,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAatC;IAED,gBAAgB,IAAI,OAAO,CAE1B;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAmXD,OAAO,IAAI,IAAI,CAQd;CA0DF"}
|
package/dist/content.js
CHANGED
|
@@ -150,6 +150,8 @@ export class ContentRenderer {
|
|
|
150
150
|
#name;
|
|
151
151
|
#nameSelection;
|
|
152
152
|
#nameItem;
|
|
153
|
+
#userHidden = false;
|
|
154
|
+
#hasVisibleSurface = false;
|
|
153
155
|
#destroyed = false;
|
|
154
156
|
constructor(document, options = {}) {
|
|
155
157
|
this.#document = document;
|
|
@@ -224,6 +226,17 @@ export class ContentRenderer {
|
|
|
224
226
|
if (this.#destroyed)
|
|
225
227
|
return;
|
|
226
228
|
}
|
|
229
|
+
let visible = false;
|
|
230
|
+
for (const surface of this.#surfaces.values()) {
|
|
231
|
+
if (!surface.host.hidden) {
|
|
232
|
+
visible = true;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
this.#hasVisibleSurface = visible;
|
|
237
|
+
const hidden = this.#userHidden || !visible;
|
|
238
|
+
if (this.#host.hidden !== hidden)
|
|
239
|
+
this.#host.hidden = hidden;
|
|
227
240
|
const viewportChanged = viewport.width !== this.#viewportWidth ||
|
|
228
241
|
viewport.height !== this.#viewportHeight;
|
|
229
242
|
const placementChanged = viewportChanged ||
|
|
@@ -305,15 +318,28 @@ export class ContentRenderer {
|
|
|
305
318
|
}
|
|
306
319
|
this.#placementDirty = false;
|
|
307
320
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
321
|
+
}
|
|
322
|
+
setUserHidden(hidden) {
|
|
323
|
+
if (this.#destroyed)
|
|
324
|
+
return false;
|
|
325
|
+
const wasHidden = this.#userHidden;
|
|
326
|
+
this.#userHidden = hidden;
|
|
327
|
+
this.#host.hidden = hidden || !this.#hasVisibleSurface;
|
|
328
|
+
if (wasHidden && !hidden && !this.#host.hidden) {
|
|
329
|
+
for (const surface of this.#surfaces.values()) {
|
|
330
|
+
if (!surface.host.hidden)
|
|
331
|
+
surface.measureDirty = true;
|
|
313
332
|
}
|
|
333
|
+
this.#placementDirty = true;
|
|
334
|
+
this.#wake();
|
|
314
335
|
}
|
|
315
|
-
|
|
316
|
-
|
|
336
|
+
return !this.#userHidden;
|
|
337
|
+
}
|
|
338
|
+
toggleUserHidden() {
|
|
339
|
+
return this.setUserHidden(!this.#userHidden);
|
|
340
|
+
}
|
|
341
|
+
get userHidden() {
|
|
342
|
+
return this.#userHidden;
|
|
317
343
|
}
|
|
318
344
|
#select(selection, item, generation) {
|
|
319
345
|
for (const region of CONTENT_REGIONS) {
|