@swifttui/web 0.0.13 → 0.0.15

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.
Files changed (92) hide show
  1. package/README.md +24 -10
  2. package/dist/index.d.ts +9 -0
  3. package/dist/index.js +9 -0
  4. package/dist/manifest.d.ts +2 -0
  5. package/dist/manifest.js +2 -0
  6. package/dist/src/AccessibilityTree.js +156 -0
  7. package/dist/src/AccessibilityTree.js.map +1 -0
  8. package/dist/src/BoxDrawingRenderer.js +1106 -0
  9. package/dist/src/BoxDrawingRenderer.js.map +1 -0
  10. package/dist/src/WebHostApp.d.ts +41 -0
  11. package/dist/src/WebHostApp.js +135 -0
  12. package/dist/src/WebHostApp.js.map +1 -0
  13. package/dist/src/WebHostSceneManifest.d.ts +18 -0
  14. package/dist/src/WebHostSceneManifest.js +70 -0
  15. package/dist/src/WebHostSceneManifest.js.map +1 -0
  16. package/dist/src/WebHostSceneRuntime.d.ts +112 -0
  17. package/dist/src/WebHostSceneRuntime.js +651 -0
  18. package/dist/src/WebHostSceneRuntime.js.map +1 -0
  19. package/dist/src/WebHostSurfaceTransport.d.ts +166 -0
  20. package/dist/src/WebHostSurfaceTransport.js +252 -0
  21. package/dist/src/WebHostSurfaceTransport.js.map +1 -0
  22. package/dist/src/WebHostTerminalStyle.d.ts +92 -0
  23. package/dist/src/WebHostTerminalStyle.js +277 -0
  24. package/dist/src/WebHostTerminalStyle.js.map +1 -0
  25. package/dist/src/WebHostTestFixtures.d.ts +5 -0
  26. package/dist/src/WebHostTestFixtures.js +9 -0
  27. package/dist/src/WebHostTestFixtures.js.map +1 -0
  28. package/dist/src/WebSocketSceneBridge.d.ts +53 -0
  29. package/dist/src/WebSocketSceneBridge.js +124 -0
  30. package/dist/src/WebSocketSceneBridge.js.map +1 -0
  31. package/dist/src/wasi/BrowserWASIBridge.d.ts +33 -0
  32. package/dist/src/wasi/BrowserWASIBridge.js +97 -0
  33. package/dist/src/wasi/BrowserWASIBridge.js.map +1 -0
  34. package/dist/src/wasi/SharedInputQueue.d.ts +31 -0
  35. package/dist/src/wasi/SharedInputQueue.js +102 -0
  36. package/dist/src/wasi/SharedInputQueue.js.map +1 -0
  37. package/dist/src/wasi/StdIOPipe.d.ts +15 -0
  38. package/dist/src/wasi/StdIOPipe.js +56 -0
  39. package/dist/src/wasi/StdIOPipe.js.map +1 -0
  40. package/dist/src/wasi/WasiPollScheduler.js +114 -0
  41. package/dist/src/wasi/WasiPollScheduler.js.map +1 -0
  42. package/dist/src/wasi/WasmSceneRuntime.d.ts +23 -0
  43. package/dist/src/wasi/WasmSceneRuntime.js +119 -0
  44. package/dist/src/wasi/WasmSceneRuntime.js.map +1 -0
  45. package/dist/src/wasi/WasmSceneWorker.d.ts +27 -0
  46. package/dist/src/wasi/WasmSceneWorker.js +109 -0
  47. package/dist/src/wasi/WasmSceneWorker.js.map +1 -0
  48. package/dist/testing.d.ts +2 -0
  49. package/dist/testing.js +2 -0
  50. package/dist/wasi-worker.d.ts +2 -0
  51. package/dist/wasi-worker.js +2 -0
  52. package/dist/wasi.d.ts +6 -0
  53. package/dist/wasi.js +6 -0
  54. package/dist/websocket.d.ts +2 -0
  55. package/dist/websocket.js +2 -0
  56. package/package.json +49 -18
  57. package/AGENTS.md +0 -52
  58. package/cli.ts +0 -168
  59. package/index.html +0 -50
  60. package/index.ts +0 -8
  61. package/manifest.ts +0 -1
  62. package/src/AccessibilityTree.ts +0 -262
  63. package/src/BoxDrawingRenderer.ts +0 -585
  64. package/src/PublicEntrypointBoundary.test.ts +0 -20
  65. package/src/WebHostApp.test.ts +0 -222
  66. package/src/WebHostApp.ts +0 -269
  67. package/src/WebHostSceneManifest.test.ts +0 -38
  68. package/src/WebHostSceneManifest.ts +0 -156
  69. package/src/WebHostSceneRuntime.test.ts +0 -1982
  70. package/src/WebHostSceneRuntime.ts +0 -1142
  71. package/src/WebHostSurfaceTransport.test.ts +0 -362
  72. package/src/WebHostSurfaceTransport.ts +0 -691
  73. package/src/WebHostTerminalStyle.test.ts +0 -123
  74. package/src/WebHostTerminalStyle.ts +0 -471
  75. package/src/WebHostTestFixtures.ts +0 -10
  76. package/src/WebSocketSceneBridge.test.ts +0 -198
  77. package/src/WebSocketSceneBridge.ts +0 -233
  78. package/src/browser.ts +0 -59
  79. package/src/wasi/BrowserWASIBridge.test.ts +0 -168
  80. package/src/wasi/BrowserWASIBridge.ts +0 -167
  81. package/src/wasi/SharedInputQueue.test.ts +0 -146
  82. package/src/wasi/SharedInputQueue.ts +0 -199
  83. package/src/wasi/StdIOPipe.ts +0 -72
  84. package/src/wasi/WasiPollScheduler.test.ts +0 -176
  85. package/src/wasi/WasiPollScheduler.ts +0 -305
  86. package/src/wasi/WasmSceneRuntime.ts +0 -205
  87. package/src/wasi/WasmSceneWorker.ts +0 -182
  88. package/testing.ts +0 -1
  89. package/tsconfig.json +0 -29
  90. package/wasi-worker.ts +0 -1
  91. package/wasi.ts +0 -4
  92. package/websocket.ts +0 -1
package/index.html DELETED
@@ -1,50 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>WebHost</title>
7
- <style>
8
- :root {
9
- color-scheme: dark;
10
- }
11
-
12
- html,
13
- body {
14
- margin: 0;
15
- height: 100%;
16
- background: #000;
17
- }
18
-
19
- #webhost-root,
20
- .webhost-scene-root,
21
- .webhost-scene {
22
- width: 100%;
23
- height: 100%;
24
- }
25
-
26
- .webhost-scene__header {
27
- display: none;
28
- }
29
-
30
- .webhost-scene__terminal {
31
- width: 100%;
32
- height: 100%;
33
- min-height: 100%;
34
- touch-action: none;
35
- -webkit-user-select: none;
36
- user-select: none;
37
- cursor: default;
38
- }
39
-
40
- .webhost-scene__terminal canvas {
41
- touch-action: none;
42
- cursor: default;
43
- }
44
- </style>
45
- <script type="module" src="./src/browser.ts"></script>
46
- </head>
47
- <body>
48
- <main id="webhost-root"></main>
49
- </body>
50
- </html>
package/index.ts DELETED
@@ -1,8 +0,0 @@
1
- export * from "./src/WebHostApp.ts";
2
- export * from "./src/WebHostSceneManifest.ts";
3
- export * from "./src/WebHostTerminalStyle.ts";
4
- export * from "./src/WebHostSurfaceTransport.ts";
5
- export * from "./src/WebHostSceneRuntime.ts";
6
- export * from "./src/WebSocketSceneBridge.ts";
7
- export * from "./src/wasi/BrowserWASIBridge.ts";
8
- export * from "./src/wasi/StdIOPipe.ts";
package/manifest.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./src/WebHostSceneManifest.ts";
@@ -1,262 +0,0 @@
1
- import type {
2
- WebHostAccessibilityAnnouncement,
3
- WebHostAccessibilityNode,
4
- } from "./WebHostSurfaceTransport.ts";
5
-
6
- interface AccessibilityTreeMetrics {
7
- cellWidth: number;
8
- cellHeight: number;
9
- }
10
-
11
- interface AccessibilityTreePresentationOptions {
12
- synchronizeFocus?: boolean;
13
- }
14
-
15
- interface RoleMapping {
16
- role?: string;
17
- level?: number;
18
- }
19
-
20
- export class AccessibilityTreeMounter {
21
- readonly element: HTMLElement;
22
- readonly announcerElement: HTMLElement;
23
-
24
- private readonly nodesById = new Map<string, HTMLElement>();
25
- private previousLabelsById = new Map<string, string>();
26
- private hasLiveRegionBaseline = false;
27
-
28
- constructor() {
29
- this.element = document.createElement("div");
30
- this.element.className = "webhost-scene__accessibility-tree";
31
- applyScreenReaderOnlyStyle(this.element);
32
-
33
- this.announcerElement = document.createElement("div");
34
- this.announcerElement.className = "webhost-scene__accessibility-announcer";
35
- this.announcerElement.setAttribute("aria-atomic", "true");
36
- applyScreenReaderOnlyStyle(this.announcerElement);
37
- }
38
-
39
- present(
40
- nodes: WebHostAccessibilityNode[],
41
- metrics: AccessibilityTreeMetrics,
42
- announcements: WebHostAccessibilityAnnouncement[] = [],
43
- options: AccessibilityTreePresentationOptions = {}
44
- ): void {
45
- this.element.replaceChildren();
46
- this.nodesById.clear();
47
-
48
- for (const node of nodes) {
49
- const element = this.elementForNode(node, metrics);
50
- this.nodesById.set(node.id, element);
51
- }
52
-
53
- for (const node of nodes) {
54
- const element = this.nodesById.get(node.id);
55
- if (!element) {
56
- continue;
57
- }
58
-
59
- const parent = node.parentId ? this.nodesById.get(node.parentId) : undefined;
60
- (parent ?? this.element).appendChild(element);
61
- }
62
-
63
- this.announceLiveRegionChanges(nodes, announcements);
64
-
65
- const focused = nodes.find((node) => node.isFocused);
66
- if ((options.synchronizeFocus ?? true) && focused) {
67
- this.nodesById.get(focused.id)?.focus?.({ preventScroll: true });
68
- }
69
- }
70
-
71
- private elementForNode(
72
- node: WebHostAccessibilityNode,
73
- metrics: AccessibilityTreeMetrics
74
- ): HTMLElement {
75
- const element = document.createElement("div");
76
- element.id = `swifttui-a11y-${stableDOMId(node.id)}`;
77
- element.dataset.accessibilityId = node.id;
78
- element.tabIndex = node.isFocused ? 0 : -1;
79
-
80
- const role = roleMapping(node.role);
81
- if (role.role) {
82
- element.setAttribute("role", role.role);
83
- }
84
- if (role.level !== undefined) {
85
- element.setAttribute("aria-level", String(role.level));
86
- }
87
- if (node.label) {
88
- element.setAttribute("aria-label", node.label);
89
- }
90
- if (node.hint) {
91
- element.setAttribute("aria-description", node.hint);
92
- }
93
- if (node.liveRegion) {
94
- element.setAttribute("aria-live", node.liveRegion);
95
- }
96
- if (node.isFocused) {
97
- element.dataset.focused = "true";
98
- }
99
-
100
- const [x, y, width, height] = node.rect;
101
- element.style.position = "absolute";
102
- element.style.left = `${x * metrics.cellWidth}px`;
103
- element.style.top = `${y * metrics.cellHeight}px`;
104
- element.style.width = `${Math.max(1, width) * metrics.cellWidth}px`;
105
- element.style.height = `${Math.max(1, height) * metrics.cellHeight}px`;
106
-
107
- return element;
108
- }
109
-
110
- private announceLiveRegionChanges(
111
- nodes: WebHostAccessibilityNode[],
112
- announcements: WebHostAccessibilityAnnouncement[]
113
- ): void {
114
- const candidates = nodes.filter(
115
- (node) => node.liveRegion && node.liveRegion !== "off" && node.label
116
- );
117
- const currentLabelsById = new Map(candidates.map((node) => [node.id, node.label ?? ""]));
118
- const imperativeAssertive = announcements.filter(
119
- (announcement) => announcement.politeness === "assertive"
120
- );
121
- const imperativePolite = announcements.filter(
122
- (announcement) => announcement.politeness === "polite"
123
- );
124
-
125
- if (!this.hasLiveRegionBaseline) {
126
- this.previousLabelsById = currentLabelsById;
127
- this.hasLiveRegionBaseline = true;
128
- this.publishAnnouncements([], imperativeAssertive, [], imperativePolite);
129
- return;
130
- }
131
-
132
- const changed = candidates.filter((node) => {
133
- const previous = this.previousLabelsById.get(node.id);
134
- return previous !== undefined && previous !== node.label;
135
- });
136
- this.previousLabelsById = currentLabelsById;
137
-
138
- const assertive = changed.filter((node) => node.liveRegion === "assertive");
139
- const polite = changed.filter((node) => node.liveRegion === "polite");
140
- this.publishAnnouncements(assertive, imperativeAssertive, polite, imperativePolite);
141
- }
142
-
143
- private publishAnnouncements(
144
- assertive: WebHostAccessibilityNode[],
145
- imperativeAssertive: WebHostAccessibilityAnnouncement[],
146
- polite: WebHostAccessibilityNode[],
147
- imperativePolite: WebHostAccessibilityAnnouncement[]
148
- ): void {
149
- const ordered = [...assertive, ...imperativeAssertive, ...polite, ...imperativePolite];
150
- if (ordered.length === 0) {
151
- return;
152
- }
153
-
154
- const politeness = assertive.length > 0 || imperativeAssertive.length > 0
155
- ? "assertive"
156
- : "polite";
157
- this.announcerElement.setAttribute("aria-live", politeness);
158
- this.announcerElement.textContent = ordered.map((entry) => {
159
- if ("message" in entry) {
160
- return entry.message;
161
- }
162
- return entry.label ?? "";
163
- }).join("\n");
164
- }
165
- }
166
-
167
- function applyScreenReaderOnlyStyle(
168
- element: HTMLElement
169
- ): void {
170
- element.style.position = "absolute";
171
- element.style.left = "0";
172
- element.style.top = "0";
173
- element.style.width = "1px";
174
- element.style.height = "1px";
175
- element.style.overflow = "hidden";
176
- element.style.clipPath = "inset(50%)";
177
- element.style.whiteSpace = "nowrap";
178
- }
179
-
180
- function roleMapping(
181
- role: string
182
- ): RoleMapping {
183
- const heading = /^heading\(level: ([0-9]+)\)$/.exec(role);
184
- if (heading) {
185
- return {
186
- role: "heading",
187
- level: Math.max(1, Math.min(6, Number(heading[1]))),
188
- };
189
- }
190
-
191
- const custom = /^custom\((.+)\)$/.exec(role);
192
- if (custom) {
193
- return { role: custom[1] };
194
- }
195
-
196
- switch (role) {
197
- case "alert":
198
- case "button":
199
- case "cell":
200
- case "checkbox":
201
- case "grid":
202
- case "group":
203
- case "link":
204
- case "list":
205
- case "menu":
206
- case "region":
207
- case "separator":
208
- case "slider":
209
- case "status":
210
- case "tab":
211
- case "table":
212
- case "timer":
213
- return { role };
214
- case "columnHeader":
215
- return { role: "columnheader" };
216
- case "confirmationDialog":
217
- case "sheet":
218
- return { role: "dialog" };
219
- case "disclosureGroup":
220
- case "scrollView":
221
- case "scrollViewWithIndicators":
222
- case "section":
223
- return { role: "region" };
224
- case "image":
225
- return { role: "img" };
226
- case "menuItem":
227
- return { role: "menuitem" };
228
- case "picker":
229
- return { role: "combobox" };
230
- case "progressBar":
231
- return { role: "progressbar" };
232
- case "rowHeader":
233
- return { role: "rowheader" };
234
- case "secureField":
235
- case "textEditor":
236
- case "textField":
237
- return { role: "textbox" };
238
- case "stepper":
239
- return { role: "spinbutton" };
240
- case "tabPanel":
241
- return { role: "tabpanel" };
242
- case "tableRow":
243
- return { role: "row" };
244
- case "tabView":
245
- return { role: "tablist" };
246
- case "toggle":
247
- return { role: "checkbox" };
248
- default:
249
- return { role: "group" };
250
- }
251
- }
252
-
253
- function stableDOMId(
254
- id: string
255
- ): string {
256
- return Array.from(id).map((character) => {
257
- if (/^[a-zA-Z0-9_-]$/.test(character)) {
258
- return character;
259
- }
260
- return `-${character.codePointAt(0)?.toString(16) ?? "0"}-`;
261
- }).join("");
262
- }