@effindomv2/fui-as 0.1.0
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.md +7 -0
- package/browser/src/common-harness/host-imports.ts +430 -0
- package/browser/src/common-harness/interop.ts +39 -0
- package/browser/src/common-harness/managed-harness-bitmap-host.ts +92 -0
- package/browser/src/common-harness/managed-harness-fetch-host.ts +201 -0
- package/browser/src/common-harness/managed-harness-file-host.ts +1101 -0
- package/browser/src/common-harness/managed-harness-file-payloads.ts +143 -0
- package/browser/src/common-harness/managed-harness-file-types.ts +106 -0
- package/browser/src/common-harness/managed-harness-session.ts +15 -0
- package/browser/src/common-harness/managed-harness.ts +1323 -0
- package/browser/src/common-harness/managed-history.ts +168 -0
- package/browser/src/common-harness/persisted-restore-policy.ts +50 -0
- package/browser/src/common-harness/persisted-ui-state-controller.ts +309 -0
- package/browser/src/common-harness/text-session-bridge.ts +452 -0
- package/browser/src/common-harness/types.ts +205 -0
- package/browser/src/common-harness/ui-chrome.ts +191 -0
- package/browser/src/common-harness/ui-imports.ts +529 -0
- package/browser/src/common-harness/wasm-module-cache.ts +47 -0
- package/browser/src/common-harness.ts +27 -0
- package/browser/src/file-processing-worker.ts +89 -0
- package/browser/src/host-events.ts +97 -0
- package/browser/src/host-services.ts +203 -0
- package/browser/src/index.ts +62 -0
- package/browser/src/persisted-ui-state.ts +206 -0
- package/browser/src/routed-harness.ts +198 -0
- package/browser/src/worker-bootstrap.ts +483 -0
- package/browser/src/worker-manager.ts +230 -0
- package/browser/src/worker-types.ts +50 -0
- package/package.json +89 -0
- package/scripts/build-demo-as.sh +91 -0
- package/scripts/build.sh +325 -0
- package/scripts/generate-host-events.ts +175 -0
- package/scripts/generate-host-services.ts +157 -0
- package/src/Fui.ts +205 -0
- package/src/FuiExports.ts +55 -0
- package/src/FuiPrimitives.ts +15 -0
- package/src/FuiWorker.ts +3 -0
- package/src/FuiWorkerExports.ts +6 -0
- package/src/bindings/ui.ts +531 -0
- package/src/color.ts +86 -0
- package/src/controls/AntiSelectionArea.ts +23 -0
- package/src/controls/Button.ts +750 -0
- package/src/controls/Checkbox.ts +181 -0
- package/src/controls/ContextMenu.ts +885 -0
- package/src/controls/ControlTemplateSet.ts +37 -0
- package/src/controls/Dialog.ts +355 -0
- package/src/controls/Dropdown.ts +856 -0
- package/src/controls/Form.ts +110 -0
- package/src/controls/NavLink.ts +211 -0
- package/src/controls/Popup.ts +129 -0
- package/src/controls/ProgressBar.ts +180 -0
- package/src/controls/RadioButton.ts +135 -0
- package/src/controls/RadioGroup.ts +244 -0
- package/src/controls/SelectionArea.ts +75 -0
- package/src/controls/Slider.ts +471 -0
- package/src/controls/Switch.ts +132 -0
- package/src/controls/TextArea.ts +20 -0
- package/src/controls/TextInput.ts +7 -0
- package/src/controls/index.ts +18 -0
- package/src/controls/internal/ButtonPresenter.ts +95 -0
- package/src/controls/internal/CheckboxIndicatorPresenter.ts +93 -0
- package/src/controls/internal/DropdownChevronPresenter.ts +67 -0
- package/src/controls/internal/DropdownFieldPresenter.ts +110 -0
- package/src/controls/internal/DropdownOptionRowPresenter.ts +82 -0
- package/src/controls/internal/PopupPresenter.ts +198 -0
- package/src/controls/internal/PressableIndicatorPresenter.ts +32 -0
- package/src/controls/internal/PressableLabeledControl.ts +221 -0
- package/src/controls/internal/RadioIndicatorPresenter.ts +73 -0
- package/src/controls/internal/SliderPresenter.ts +157 -0
- package/src/controls/internal/SwitchIndicatorPresenter.ts +72 -0
- package/src/controls/internal/TextInputCore.ts +695 -0
- package/src/controls/internal/TextInputPresenter.ts +72 -0
- package/src/controls/templating.ts +54 -0
- package/src/core/Action.ts +94 -0
- package/src/core/Actions.ts +37 -0
- package/src/core/Animation.ts +412 -0
- package/src/core/Application.ts +328 -0
- package/src/core/Assets.ts +264 -0
- package/src/core/AttachedProperties.ts +32 -0
- package/src/core/Bitmap.ts +70 -0
- package/src/core/BoundCallback.ts +104 -0
- package/src/core/Callbacks.ts +17 -0
- package/src/core/ContextMenuManager.ts +466 -0
- package/src/core/DebugApi.ts +30 -0
- package/src/core/Disposable.ts +10 -0
- package/src/core/DragDropManager.ts +179 -0
- package/src/core/DragGesture.ts +184 -0
- package/src/core/DynamicAssetIds.ts +24 -0
- package/src/core/Errors.ts +48 -0
- package/src/core/EventRouter.ts +408 -0
- package/src/core/ExternalDropManager.ts +122 -0
- package/src/core/Fetch.ts +264 -0
- package/src/core/FetchFfi.ts +15 -0
- package/src/core/File.ts +1002 -0
- package/src/core/FocusAdornerManager.ts +263 -0
- package/src/core/FocusVisibility.ts +36 -0
- package/src/core/FrameScheduler.ts +28 -0
- package/src/core/KeyboardScroll.ts +161 -0
- package/src/core/KeyboardScrollTracker.ts +386 -0
- package/src/core/Logger.ts +80 -0
- package/src/core/Navigation.ts +13 -0
- package/src/core/Node.ts +1708 -0
- package/src/core/PersistedState.ts +102 -0
- package/src/core/PersistedUiState.ts +142 -0
- package/src/core/Platform.ts +219 -0
- package/src/core/Signal.ts +89 -0
- package/src/core/Theme.ts +365 -0
- package/src/core/Timers.ts +129 -0
- package/src/core/ToolTip.ts +122 -0
- package/src/core/ToolTipManager.ts +459 -0
- package/src/core/Transitions.ts +34 -0
- package/src/core/Typography.ts +204 -0
- package/src/core/Worker.ts +196 -0
- package/src/core/bind.ts +37 -0
- package/src/core/event_exports.ts +596 -0
- package/src/core/ffi.ts +728 -0
- package/src/host-services/runtime.ts +25 -0
- package/src/nodes/FlexBox.ts +789 -0
- package/src/nodes/GradientStop.ts +9 -0
- package/src/nodes/Grid.ts +183 -0
- package/src/nodes/Image.ts +189 -0
- package/src/nodes/Portal.ts +14 -0
- package/src/nodes/RichText.ts +312 -0
- package/src/nodes/ScrollBar.ts +570 -0
- package/src/nodes/ScrollBox.ts +415 -0
- package/src/nodes/ScrollState.ts +10 -0
- package/src/nodes/ScrollView.ts +511 -0
- package/src/nodes/Svg.ts +142 -0
- package/src/nodes/Text.ts +145 -0
- package/src/nodes/TextCore.ts +558 -0
- package/src/nodes/VirtualList.ts +431 -0
- package/src/nodes/helpers.ts +25 -0
- package/src/nodes/index.ts +14 -0
- package/src/tsconfig.json +7 -0
- package/src/worker/Worker.ts +169 -0
- package/src/worker/WorkerJob.ts +65 -0
- package/src/worker/ffi.ts +23 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import type { HarnessAppSession } from './managed-harness-session';
|
|
2
|
+
|
|
3
|
+
interface ActiveFetchRequestRecord {
|
|
4
|
+
readonly requestId: number;
|
|
5
|
+
readonly session: HarnessAppSession;
|
|
6
|
+
readonly controller: AbortController;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface ManagedHarnessFetchHostDependencies {
|
|
10
|
+
getCurrentSession(): HarnessAppSession | null;
|
|
11
|
+
readAppUtf8(ptr: number, len: number): string;
|
|
12
|
+
readAppBytes(ptr: number, len: number): Uint8Array;
|
|
13
|
+
readAppTextParts(ptr: number, len: number): string[];
|
|
14
|
+
writeTextCallbackPayload(session: HarnessAppSession, text: string, context: string): number;
|
|
15
|
+
describeHarnessError(error: unknown): string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const encoder = new TextEncoder();
|
|
19
|
+
|
|
20
|
+
function encodeLengthPrefixedText(value: string): Uint8Array {
|
|
21
|
+
return encoder.encode(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function measureLengthPrefixedText(encoded: Uint8Array): number {
|
|
25
|
+
return 4 + encoded.length;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeLengthPrefixedText(
|
|
29
|
+
memory: WebAssembly.Memory,
|
|
30
|
+
basePtr: number,
|
|
31
|
+
byteOffset: number,
|
|
32
|
+
encoded: Uint8Array,
|
|
33
|
+
): number {
|
|
34
|
+
const view = new DataView(memory.buffer, basePtr, byteOffset + 4 + encoded.length);
|
|
35
|
+
view.setUint32(byteOffset, encoded.length >>> 0, true);
|
|
36
|
+
let nextOffset = byteOffset + 4;
|
|
37
|
+
if (encoded.length > 0) {
|
|
38
|
+
new Uint8Array(memory.buffer, basePtr + nextOffset, encoded.length).set(encoded);
|
|
39
|
+
nextOffset += encoded.length;
|
|
40
|
+
}
|
|
41
|
+
return nextOffset;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function writeTextPartsPayload(session: HarnessAppSession, values: readonly string[], context: string): number {
|
|
45
|
+
const encodedValues = new Array<Uint8Array>(values.length);
|
|
46
|
+
let totalBytes = 4;
|
|
47
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
48
|
+
const encoded = encodeLengthPrefixedText(values[index] ?? '');
|
|
49
|
+
encodedValues[index] = encoded;
|
|
50
|
+
totalBytes += measureLengthPrefixedText(encoded);
|
|
51
|
+
}
|
|
52
|
+
if (totalBytes > session.textBufferSize) {
|
|
53
|
+
throw new Error(`${context} exceeds the shared AssemblyScript text buffer.`);
|
|
54
|
+
}
|
|
55
|
+
const dataView = new DataView(session.memory.buffer, session.textBufferPtr, totalBytes);
|
|
56
|
+
let byteOffset = 0;
|
|
57
|
+
dataView.setUint32(byteOffset, values.length >>> 0, true);
|
|
58
|
+
byteOffset += 4;
|
|
59
|
+
for (let index = 0; index < encodedValues.length; index += 1) {
|
|
60
|
+
byteOffset = writeLengthPrefixedText(session.memory, session.textBufferPtr, byteOffset, encodedValues[index] ?? new Uint8Array());
|
|
61
|
+
}
|
|
62
|
+
return totalBytes;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function copyBytesToArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
66
|
+
const copied = new Uint8Array(bytes.byteLength);
|
|
67
|
+
copied.set(bytes);
|
|
68
|
+
return copied.buffer as ArrayBuffer;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function createManagedHarnessFetchHost(dependencies: ManagedHarnessFetchHostDependencies) {
|
|
72
|
+
const activeFetchRequests = new Map<number, ActiveFetchRequestRecord>();
|
|
73
|
+
|
|
74
|
+
function emitFetchComplete(
|
|
75
|
+
session: HarnessAppSession | null,
|
|
76
|
+
requestId: number,
|
|
77
|
+
ok: boolean,
|
|
78
|
+
status: number,
|
|
79
|
+
statusText: string,
|
|
80
|
+
url: string,
|
|
81
|
+
): void {
|
|
82
|
+
if (session === null) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const payloadLength = writeTextPartsPayload(
|
|
86
|
+
session,
|
|
87
|
+
[statusText, url],
|
|
88
|
+
'Fetch completion payload',
|
|
89
|
+
);
|
|
90
|
+
session.exports.__fui_on_fetch_complete(
|
|
91
|
+
requestId,
|
|
92
|
+
ok,
|
|
93
|
+
status,
|
|
94
|
+
payloadLength > 0 ? session.textBufferPtr : 0,
|
|
95
|
+
payloadLength,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function emitFetchError(session: HarnessAppSession | null, requestId: number, message: string): void {
|
|
100
|
+
if (session === null) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const payloadLength = dependencies.writeTextCallbackPayload(session, message, 'Fetch failure payload');
|
|
104
|
+
session.exports.__fui_on_fetch_error(
|
|
105
|
+
requestId,
|
|
106
|
+
payloadLength > 0 ? session.textBufferPtr : 0,
|
|
107
|
+
payloadLength,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function cancelAllForSession(session: HarnessAppSession | null): void {
|
|
112
|
+
for (const [requestId, record] of activeFetchRequests.entries()) {
|
|
113
|
+
if (session !== null && record.session !== session) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
activeFetchRequests.delete(requestId);
|
|
117
|
+
record.controller.abort();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
cancelAllForSession,
|
|
123
|
+
imports: {
|
|
124
|
+
fui_fetch_start(
|
|
125
|
+
requestId: number,
|
|
126
|
+
methodPtr: number,
|
|
127
|
+
methodLen: number,
|
|
128
|
+
urlPtr: number,
|
|
129
|
+
urlLen: number,
|
|
130
|
+
headersPtr: number,
|
|
131
|
+
headersLen: number,
|
|
132
|
+
bodyPtr: number,
|
|
133
|
+
bodyLen: number,
|
|
134
|
+
): void {
|
|
135
|
+
const session = dependencies.getCurrentSession();
|
|
136
|
+
if (session === null) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const method = dependencies.readAppUtf8(methodPtr, methodLen);
|
|
140
|
+
const url = dependencies.readAppUtf8(urlPtr, urlLen);
|
|
141
|
+
const headerParts = dependencies.readAppTextParts(headersPtr, headersLen);
|
|
142
|
+
if ((headerParts.length & 1) != 0) {
|
|
143
|
+
emitFetchError(session, requestId, 'Fetch request headers were malformed.');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const controller = new AbortController();
|
|
147
|
+
const headers = new Headers();
|
|
148
|
+
for (let index = 0; index < headerParts.length; index += 2) {
|
|
149
|
+
headers.append(headerParts[index] ?? '', headerParts[index + 1] ?? '');
|
|
150
|
+
}
|
|
151
|
+
const bodyBytes = dependencies.readAppBytes(bodyPtr, bodyLen);
|
|
152
|
+
activeFetchRequests.set(requestId, {
|
|
153
|
+
requestId,
|
|
154
|
+
session,
|
|
155
|
+
controller,
|
|
156
|
+
});
|
|
157
|
+
void fetch(url, {
|
|
158
|
+
method,
|
|
159
|
+
headers,
|
|
160
|
+
body: bodyBytes.length > 0 ? copyBytesToArrayBuffer(bodyBytes) : undefined,
|
|
161
|
+
signal: controller.signal,
|
|
162
|
+
}).then((response) => {
|
|
163
|
+
const active = activeFetchRequests.get(requestId);
|
|
164
|
+
if (active === undefined || active.session !== session) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
activeFetchRequests.delete(requestId);
|
|
168
|
+
if (dependencies.getCurrentSession() !== session) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
emitFetchComplete(
|
|
172
|
+
session,
|
|
173
|
+
requestId,
|
|
174
|
+
response.ok,
|
|
175
|
+
response.status,
|
|
176
|
+
response.statusText,
|
|
177
|
+
response.url,
|
|
178
|
+
);
|
|
179
|
+
}).catch((error: unknown) => {
|
|
180
|
+
const active = activeFetchRequests.get(requestId);
|
|
181
|
+
if (active === undefined) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
activeFetchRequests.delete(requestId);
|
|
185
|
+
if (controller.signal.aborted || dependencies.getCurrentSession() !== session) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
emitFetchError(session, requestId, dependencies.describeHarnessError(error));
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
fui_fetch_cancel(requestId: number): void {
|
|
192
|
+
const record = activeFetchRequests.get(requestId);
|
|
193
|
+
if (record === undefined) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
activeFetchRequests.delete(requestId);
|
|
197
|
+
record.controller.abort();
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|