@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.
Files changed (137) hide show
  1. package/LICENSE.md +7 -0
  2. package/browser/src/common-harness/host-imports.ts +430 -0
  3. package/browser/src/common-harness/interop.ts +39 -0
  4. package/browser/src/common-harness/managed-harness-bitmap-host.ts +92 -0
  5. package/browser/src/common-harness/managed-harness-fetch-host.ts +201 -0
  6. package/browser/src/common-harness/managed-harness-file-host.ts +1101 -0
  7. package/browser/src/common-harness/managed-harness-file-payloads.ts +143 -0
  8. package/browser/src/common-harness/managed-harness-file-types.ts +106 -0
  9. package/browser/src/common-harness/managed-harness-session.ts +15 -0
  10. package/browser/src/common-harness/managed-harness.ts +1323 -0
  11. package/browser/src/common-harness/managed-history.ts +168 -0
  12. package/browser/src/common-harness/persisted-restore-policy.ts +50 -0
  13. package/browser/src/common-harness/persisted-ui-state-controller.ts +309 -0
  14. package/browser/src/common-harness/text-session-bridge.ts +452 -0
  15. package/browser/src/common-harness/types.ts +205 -0
  16. package/browser/src/common-harness/ui-chrome.ts +191 -0
  17. package/browser/src/common-harness/ui-imports.ts +529 -0
  18. package/browser/src/common-harness/wasm-module-cache.ts +47 -0
  19. package/browser/src/common-harness.ts +27 -0
  20. package/browser/src/file-processing-worker.ts +89 -0
  21. package/browser/src/host-events.ts +97 -0
  22. package/browser/src/host-services.ts +203 -0
  23. package/browser/src/index.ts +62 -0
  24. package/browser/src/persisted-ui-state.ts +206 -0
  25. package/browser/src/routed-harness.ts +198 -0
  26. package/browser/src/worker-bootstrap.ts +483 -0
  27. package/browser/src/worker-manager.ts +230 -0
  28. package/browser/src/worker-types.ts +50 -0
  29. package/package.json +89 -0
  30. package/scripts/build-demo-as.sh +91 -0
  31. package/scripts/build.sh +325 -0
  32. package/scripts/generate-host-events.ts +175 -0
  33. package/scripts/generate-host-services.ts +157 -0
  34. package/src/Fui.ts +205 -0
  35. package/src/FuiExports.ts +55 -0
  36. package/src/FuiPrimitives.ts +15 -0
  37. package/src/FuiWorker.ts +3 -0
  38. package/src/FuiWorkerExports.ts +6 -0
  39. package/src/bindings/ui.ts +531 -0
  40. package/src/color.ts +86 -0
  41. package/src/controls/AntiSelectionArea.ts +23 -0
  42. package/src/controls/Button.ts +750 -0
  43. package/src/controls/Checkbox.ts +181 -0
  44. package/src/controls/ContextMenu.ts +885 -0
  45. package/src/controls/ControlTemplateSet.ts +37 -0
  46. package/src/controls/Dialog.ts +355 -0
  47. package/src/controls/Dropdown.ts +856 -0
  48. package/src/controls/Form.ts +110 -0
  49. package/src/controls/NavLink.ts +211 -0
  50. package/src/controls/Popup.ts +129 -0
  51. package/src/controls/ProgressBar.ts +180 -0
  52. package/src/controls/RadioButton.ts +135 -0
  53. package/src/controls/RadioGroup.ts +244 -0
  54. package/src/controls/SelectionArea.ts +75 -0
  55. package/src/controls/Slider.ts +471 -0
  56. package/src/controls/Switch.ts +132 -0
  57. package/src/controls/TextArea.ts +20 -0
  58. package/src/controls/TextInput.ts +7 -0
  59. package/src/controls/index.ts +18 -0
  60. package/src/controls/internal/ButtonPresenter.ts +95 -0
  61. package/src/controls/internal/CheckboxIndicatorPresenter.ts +93 -0
  62. package/src/controls/internal/DropdownChevronPresenter.ts +67 -0
  63. package/src/controls/internal/DropdownFieldPresenter.ts +110 -0
  64. package/src/controls/internal/DropdownOptionRowPresenter.ts +82 -0
  65. package/src/controls/internal/PopupPresenter.ts +198 -0
  66. package/src/controls/internal/PressableIndicatorPresenter.ts +32 -0
  67. package/src/controls/internal/PressableLabeledControl.ts +221 -0
  68. package/src/controls/internal/RadioIndicatorPresenter.ts +73 -0
  69. package/src/controls/internal/SliderPresenter.ts +157 -0
  70. package/src/controls/internal/SwitchIndicatorPresenter.ts +72 -0
  71. package/src/controls/internal/TextInputCore.ts +695 -0
  72. package/src/controls/internal/TextInputPresenter.ts +72 -0
  73. package/src/controls/templating.ts +54 -0
  74. package/src/core/Action.ts +94 -0
  75. package/src/core/Actions.ts +37 -0
  76. package/src/core/Animation.ts +412 -0
  77. package/src/core/Application.ts +328 -0
  78. package/src/core/Assets.ts +264 -0
  79. package/src/core/AttachedProperties.ts +32 -0
  80. package/src/core/Bitmap.ts +70 -0
  81. package/src/core/BoundCallback.ts +104 -0
  82. package/src/core/Callbacks.ts +17 -0
  83. package/src/core/ContextMenuManager.ts +466 -0
  84. package/src/core/DebugApi.ts +30 -0
  85. package/src/core/Disposable.ts +10 -0
  86. package/src/core/DragDropManager.ts +179 -0
  87. package/src/core/DragGesture.ts +184 -0
  88. package/src/core/DynamicAssetIds.ts +24 -0
  89. package/src/core/Errors.ts +48 -0
  90. package/src/core/EventRouter.ts +408 -0
  91. package/src/core/ExternalDropManager.ts +122 -0
  92. package/src/core/Fetch.ts +264 -0
  93. package/src/core/FetchFfi.ts +15 -0
  94. package/src/core/File.ts +1002 -0
  95. package/src/core/FocusAdornerManager.ts +263 -0
  96. package/src/core/FocusVisibility.ts +36 -0
  97. package/src/core/FrameScheduler.ts +28 -0
  98. package/src/core/KeyboardScroll.ts +161 -0
  99. package/src/core/KeyboardScrollTracker.ts +386 -0
  100. package/src/core/Logger.ts +80 -0
  101. package/src/core/Navigation.ts +13 -0
  102. package/src/core/Node.ts +1708 -0
  103. package/src/core/PersistedState.ts +102 -0
  104. package/src/core/PersistedUiState.ts +142 -0
  105. package/src/core/Platform.ts +219 -0
  106. package/src/core/Signal.ts +89 -0
  107. package/src/core/Theme.ts +365 -0
  108. package/src/core/Timers.ts +129 -0
  109. package/src/core/ToolTip.ts +122 -0
  110. package/src/core/ToolTipManager.ts +459 -0
  111. package/src/core/Transitions.ts +34 -0
  112. package/src/core/Typography.ts +204 -0
  113. package/src/core/Worker.ts +196 -0
  114. package/src/core/bind.ts +37 -0
  115. package/src/core/event_exports.ts +596 -0
  116. package/src/core/ffi.ts +728 -0
  117. package/src/host-services/runtime.ts +25 -0
  118. package/src/nodes/FlexBox.ts +789 -0
  119. package/src/nodes/GradientStop.ts +9 -0
  120. package/src/nodes/Grid.ts +183 -0
  121. package/src/nodes/Image.ts +189 -0
  122. package/src/nodes/Portal.ts +14 -0
  123. package/src/nodes/RichText.ts +312 -0
  124. package/src/nodes/ScrollBar.ts +570 -0
  125. package/src/nodes/ScrollBox.ts +415 -0
  126. package/src/nodes/ScrollState.ts +10 -0
  127. package/src/nodes/ScrollView.ts +511 -0
  128. package/src/nodes/Svg.ts +142 -0
  129. package/src/nodes/Text.ts +145 -0
  130. package/src/nodes/TextCore.ts +558 -0
  131. package/src/nodes/VirtualList.ts +431 -0
  132. package/src/nodes/helpers.ts +25 -0
  133. package/src/nodes/index.ts +14 -0
  134. package/src/tsconfig.json +7 -0
  135. package/src/worker/Worker.ts +169 -0
  136. package/src/worker/WorkerJob.ts +65 -0
  137. package/src/worker/ffi.ts +23 -0
@@ -0,0 +1,143 @@
1
+ import type { HarnessAppSession } from './managed-harness-session';
2
+ import type { ExternalHarnessDropItem, StoredFileRecord } from './managed-harness-file-types';
3
+ import { EXTERNAL_DROP_ITEM_KIND_FILE } from './managed-harness-file-types';
4
+
5
+ const encoder = new TextEncoder();
6
+
7
+ export function encodeLengthPrefixedText(value: string): Uint8Array {
8
+ return encoder.encode(value);
9
+ }
10
+
11
+ export function measureLengthPrefixedText(encoded: Uint8Array): number {
12
+ return 4 + encoded.length;
13
+ }
14
+
15
+ export function writeLengthPrefixedText(
16
+ memory: WebAssembly.Memory,
17
+ basePtr: number,
18
+ byteOffset: number,
19
+ encoded: Uint8Array,
20
+ ): number {
21
+ const view = new DataView(memory.buffer, basePtr, byteOffset + 4 + encoded.length);
22
+ view.setUint32(byteOffset, encoded.length >>> 0, true);
23
+ let nextOffset = byteOffset + 4;
24
+ if (encoded.length > 0) {
25
+ new Uint8Array(memory.buffer, basePtr + nextOffset, encoded.length).set(encoded);
26
+ nextOffset += encoded.length;
27
+ }
28
+ return nextOffset;
29
+ }
30
+
31
+ export function writeFileListPayload(session: HarnessAppSession, files: readonly StoredFileRecord[]): number {
32
+ let totalBytes = 4;
33
+ const encodedIds = new Array<Uint8Array>(files.length);
34
+ const encodedNames = new Array<Uint8Array>(files.length);
35
+ const encodedMimeTypes = new Array<Uint8Array>(files.length);
36
+ for (let index = 0; index < files.length; index += 1) {
37
+ const entry = files[index];
38
+ const encodedId = encodeLengthPrefixedText(entry?.id ?? '');
39
+ const encodedName = encodeLengthPrefixedText(entry?.file.name ?? '');
40
+ const encodedMimeType = encodeLengthPrefixedText(entry?.file.type ?? '');
41
+ encodedIds[index] = encodedId;
42
+ encodedNames[index] = encodedName;
43
+ encodedMimeTypes[index] = encodedMimeType;
44
+ totalBytes += measureLengthPrefixedText(encodedId) + 8 + 8 + measureLengthPrefixedText(encodedName) + measureLengthPrefixedText(encodedMimeType);
45
+ }
46
+ if (totalBytes > session.textBufferSize) {
47
+ throw new Error('File picker payload exceeds the shared AssemblyScript text buffer.');
48
+ }
49
+ const dataView = new DataView(session.memory.buffer, session.textBufferPtr, totalBytes);
50
+ let byteOffset = 0;
51
+ dataView.setUint32(byteOffset, files.length >>> 0, true);
52
+ byteOffset += 4;
53
+ for (let index = 0; index < files.length; index += 1) {
54
+ const entry = files[index];
55
+ const encodedId = encodedIds[index] ?? new Uint8Array();
56
+ const encodedName = encodedNames[index] ?? new Uint8Array();
57
+ const encodedMimeType = encodedMimeTypes[index] ?? new Uint8Array();
58
+ byteOffset = writeLengthPrefixedText(session.memory, session.textBufferPtr, byteOffset, encodedId);
59
+ dataView.setBigUint64(byteOffset, BigInt(entry?.file.size ?? 0), true);
60
+ byteOffset += 8;
61
+ dataView.setBigUint64(byteOffset, BigInt(Math.max(0, Math.trunc(entry?.file.lastModified ?? 0))), true);
62
+ byteOffset += 8;
63
+ byteOffset = writeLengthPrefixedText(session.memory, session.textBufferPtr, byteOffset, encodedName);
64
+ byteOffset = writeLengthPrefixedText(session.memory, session.textBufferPtr, byteOffset, encodedMimeType);
65
+ }
66
+ return totalBytes;
67
+ }
68
+
69
+ export function writeWriterPayload(
70
+ session: HarnessAppSession,
71
+ mode: number,
72
+ first: string,
73
+ second: string | null = null,
74
+ ): number {
75
+ const encodedFirst = encodeLengthPrefixedText(first);
76
+ const encodedSecond = second === null ? null : encodeLengthPrefixedText(second);
77
+ const totalBytes = 4 + measureLengthPrefixedText(encodedFirst) + (encodedSecond === null ? 0 : measureLengthPrefixedText(encodedSecond));
78
+ if (totalBytes > session.textBufferSize) {
79
+ throw new Error('File bridge metadata exceeds the shared AssemblyScript text buffer.');
80
+ }
81
+ const dataView = new DataView(session.memory.buffer, session.textBufferPtr, totalBytes);
82
+ let byteOffset = 0;
83
+ dataView.setUint32(byteOffset, mode >>> 0, true);
84
+ byteOffset += 4;
85
+ byteOffset = writeLengthPrefixedText(session.memory, session.textBufferPtr, byteOffset, encodedFirst);
86
+ if (encodedSecond !== null) {
87
+ byteOffset = writeLengthPrefixedText(session.memory, session.textBufferPtr, byteOffset, encodedSecond);
88
+ }
89
+ return totalBytes;
90
+ }
91
+
92
+ export function writeExternalDropPayload(session: HarnessAppSession, items: readonly ExternalHarnessDropItem[]): number {
93
+ let totalBytes = 4;
94
+ const encodedIds = new Array<Uint8Array>(items.length);
95
+ const encodedNames = new Array<Uint8Array>(items.length);
96
+ const encodedMimeTypes = new Array<Uint8Array>(items.length);
97
+ for (let index = 0; index < items.length; index += 1) {
98
+ const item = items[index];
99
+ const encodedId = encoder.encode(item?.id ?? '');
100
+ const encodedName = encoder.encode(item?.name ?? '');
101
+ const encodedMimeType = encoder.encode(item?.mimeType ?? '');
102
+ encodedIds[index] = encodedId;
103
+ encodedNames[index] = encodedName;
104
+ encodedMimeTypes[index] = encodedMimeType;
105
+ totalBytes += 4 + 8 + 4 + encodedId.length + 4 + encodedName.length + 4 + encodedMimeType.length;
106
+ }
107
+ if (totalBytes > session.textBufferSize) {
108
+ throw new Error('External drop payload exceeds the shared AssemblyScript text buffer.');
109
+ }
110
+ const dataView = new DataView(session.memory.buffer, session.textBufferPtr, totalBytes);
111
+ let byteOffset = 0;
112
+ dataView.setUint32(byteOffset, items.length >>> 0, true);
113
+ byteOffset += 4;
114
+ for (let index = 0; index < items.length; index += 1) {
115
+ const item = items[index];
116
+ const encodedId = encodedIds[index] ?? new Uint8Array();
117
+ const encodedName = encodedNames[index] ?? new Uint8Array();
118
+ const encodedMimeType = encodedMimeTypes[index] ?? new Uint8Array();
119
+ dataView.setUint32(byteOffset, (item?.kind ?? EXTERNAL_DROP_ITEM_KIND_FILE) >>> 0, true);
120
+ byteOffset += 4;
121
+ dataView.setFloat64(byteOffset, item?.sizeBytes ?? 0, true);
122
+ byteOffset += 8;
123
+ dataView.setUint32(byteOffset, encodedId.length >>> 0, true);
124
+ byteOffset += 4;
125
+ if (encodedId.length > 0) {
126
+ new Uint8Array(session.memory.buffer, session.textBufferPtr + byteOffset, encodedId.length).set(encodedId);
127
+ byteOffset += encodedId.length;
128
+ }
129
+ dataView.setUint32(byteOffset, encodedName.length >>> 0, true);
130
+ byteOffset += 4;
131
+ if (encodedName.length > 0) {
132
+ new Uint8Array(session.memory.buffer, session.textBufferPtr + byteOffset, encodedName.length).set(encodedName);
133
+ byteOffset += encodedName.length;
134
+ }
135
+ dataView.setUint32(byteOffset, encodedMimeType.length >>> 0, true);
136
+ byteOffset += 4;
137
+ if (encodedMimeType.length > 0) {
138
+ new Uint8Array(session.memory.buffer, session.textBufferPtr + byteOffset, encodedMimeType.length).set(encodedMimeType);
139
+ byteOffset += encodedMimeType.length;
140
+ }
141
+ }
142
+ return totalBytes;
143
+ }
@@ -0,0 +1,106 @@
1
+ import type { HarnessAppSession } from './managed-harness-session';
2
+
3
+ export const EXTERNAL_DRAG_EVENT_ENTER = 1;
4
+ export const EXTERNAL_DRAG_EVENT_OVER = 2;
5
+ export const EXTERNAL_DRAG_EVENT_LEAVE = 3;
6
+ export const EXTERNAL_DRAG_EVENT_DROP = 4;
7
+ export const EXTERNAL_DROP_ITEM_KIND_FILE = 1;
8
+ export const FILE_STATUS_SUCCESS = 1;
9
+ export const FILE_STATUS_CANCELLED = 2;
10
+ export const FILE_STATUS_ERROR = 3;
11
+ export const FILE_SAVE_MODE_DOWNLOAD = 1;
12
+ export const FILE_SAVE_MODE_NATIVE_PICKER = 2;
13
+ export const FILE_CAPABILITY_OPEN = 1 << 0;
14
+ export const FILE_CAPABILITY_READ = 1 << 1;
15
+ export const FILE_CAPABILITY_SAVE = 1 << 2;
16
+ export const FILE_CAPABILITY_CHUNKED_READ = 1 << 3;
17
+ export const FILE_CAPABILITY_CHUNKED_WRITE = 1 << 4;
18
+ export const FILE_CAPABILITY_NATIVE_SAVE_PICKER = 1 << 5;
19
+ export const FILE_CAPABILITY_PROCESS_WORKER_SAVE = 1 << 6;
20
+
21
+ export interface ExternalHarnessDropItem {
22
+ readonly id: string;
23
+ readonly kind: number;
24
+ readonly name: string;
25
+ readonly mimeType: string | null;
26
+ readonly sizeBytes: number;
27
+ }
28
+
29
+ export interface WritableFileStreamLike {
30
+ write(data: BufferSource | Blob | string): Promise<void>;
31
+ close(): Promise<void>;
32
+ abort?(reason?: unknown): Promise<void>;
33
+ }
34
+
35
+ export interface SaveFileHandleLike {
36
+ readonly name?: string;
37
+ createWritable(): Promise<WritableFileStreamLike>;
38
+ }
39
+
40
+ export interface SavePickerWindow extends Window {
41
+ showSaveFilePicker?: (options?: {
42
+ suggestedName?: string;
43
+ }) => Promise<SaveFileHandleLike>;
44
+ }
45
+
46
+ export interface StoredFileRecord {
47
+ readonly id: string;
48
+ readonly file: File;
49
+ }
50
+
51
+ export interface ActiveFileWriterRecord {
52
+ readonly id: string;
53
+ readonly session: HarnessAppSession;
54
+ readonly fileName: string;
55
+ readonly mode: number;
56
+ readonly stream: WritableFileStreamLike;
57
+ writtenBytes: number;
58
+ }
59
+
60
+ export interface FileProcessingWorkerStartMessage {
61
+ readonly type: 'start';
62
+ readonly file: File;
63
+ readonly chunkSize: number;
64
+ }
65
+
66
+ export interface FileProcessingWorkerNextMessage {
67
+ readonly type: 'next';
68
+ }
69
+
70
+ export interface FileProcessingWorkerCancelMessage {
71
+ readonly type: 'cancel';
72
+ }
73
+
74
+ export type FileProcessingWorkerInboundMessage =
75
+ | FileProcessingWorkerStartMessage
76
+ | FileProcessingWorkerNextMessage
77
+ | FileProcessingWorkerCancelMessage;
78
+
79
+ export interface FileProcessingWorkerChunkMessage {
80
+ readonly type: 'chunk';
81
+ readonly offsetBytes: number;
82
+ readonly bytes: ArrayBuffer;
83
+ readonly copiedBytes: number;
84
+ readonly totalBytes: number;
85
+ }
86
+
87
+ export interface FileProcessingWorkerErrorMessage {
88
+ readonly type: 'error';
89
+ readonly message: string;
90
+ }
91
+
92
+ export type FileProcessingWorkerOutboundMessage =
93
+ | FileProcessingWorkerChunkMessage
94
+ | FileProcessingWorkerErrorMessage;
95
+
96
+ export interface ActiveFileProcessingRecord {
97
+ readonly requestId: number;
98
+ readonly session: HarnessAppSession;
99
+ readonly sourceFileName: string;
100
+ readonly targetFileName: string | null;
101
+ readonly totalBytes: number;
102
+ readonly worker: Worker;
103
+ readonly stream: WritableFileStreamLike | null;
104
+ readonly saveToPickedFile: boolean;
105
+ cancelled: boolean;
106
+ }
@@ -0,0 +1,15 @@
1
+ import type { WorkerHostServicesBundleConfig } from '../worker-types';
2
+
3
+ import type { HarnessExports, HarnessState } from './types';
4
+
5
+ export interface HarnessAppSession {
6
+ readonly exports: HarnessExports;
7
+ readonly memory: WebAssembly.Memory;
8
+ readonly keyBufferPtr: number;
9
+ readonly textBufferPtr: number;
10
+ readonly textBufferSize: number;
11
+ readonly hostEventDisposers: Array<() => void>;
12
+ readonly workerHostServices?: WorkerHostServicesBundleConfig;
13
+ readonly onStateUpdated?: (state: HarnessState) => void;
14
+ readonly onDispose?: (exports: HarnessExports) => void;
15
+ }