@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,431 @@
1
+ import { HandlerAction } from "../core/Action";
2
+ import { Disposable, disposeAll } from "../core/Disposable";
3
+ import { markNeedsCommit } from "../core/FrameScheduler";
4
+ import { FlexDirection, HandleValue, Unit } from "../core/ffi";
5
+ import { Node } from "../core/Node";
6
+ import { FlexBox } from "./FlexBox";
7
+ import { ScrollBar } from "./ScrollBar";
8
+ import { ScrollBox } from "./ScrollBox";
9
+ import { ScrollState } from "./ScrollState";
10
+ import { Text } from "./Text";
11
+ import * as ui from "../bindings/ui";
12
+ import { SelectionArea } from "../controls/SelectionArea";
13
+
14
+ const FULL_SIZE: f32 = 100.0;
15
+ const DEFAULT_MAX_VISIBLE_ITEMS: i32 = 20;
16
+ const POOL_OVERSCAN_ITEMS: i32 = 2;
17
+
18
+ export type VirtualListBinder = (container: FlexBox, index: i32) => void;
19
+
20
+ export class VirtualList extends FlexBox {
21
+ private totalItemsValue: i32;
22
+ private readonly itemHeightValue: f32;
23
+ private readonly bindItemValue: VirtualListBinder;
24
+ private readonly scrollStateValue: ScrollState;
25
+ private readonly scrollBoxValue: ScrollBox;
26
+ private readonly contentValue: FlexBox;
27
+ private readonly topSpacerValue: FlexBox;
28
+ private readonly bottomSpacerValue: FlexBox;
29
+ private readonly poolSizeValue: i32;
30
+ private readonly poolValue: Array<SelectionArea>;
31
+ private readonly poolItemIndexByRow: Array<i32>;
32
+ private readonly disposables: Array<Disposable>;
33
+ private currentFirstVisibleIndex: i32 = -1;
34
+ private currentLastVisibleIndex: i32 = -1;
35
+
36
+ constructor(totalItems: i32, itemHeight: f32, bindItem: VirtualListBinder, maxVisible: i32 = DEFAULT_MAX_VISIBLE_ITEMS) {
37
+ super();
38
+ const scrollStateValue = new ScrollState();
39
+ const poolValue = new Array<SelectionArea>();
40
+ const poolItemIndexByRow = new Array<i32>();
41
+ const disposables = new Array<Disposable>();
42
+ const totalItemsValue = totalItems > 0 ? totalItems : 0;
43
+ const itemHeightValue = itemHeight > 0.0 ? itemHeight : 1.0;
44
+ const poolSizeValue = maxVisible > 0 ? maxVisible + POOL_OVERSCAN_ITEMS : POOL_OVERSCAN_ITEMS;
45
+ this.totalItemsValue = totalItemsValue;
46
+ this.itemHeightValue = itemHeightValue;
47
+ this.bindItemValue = bindItem;
48
+ this.scrollStateValue = scrollStateValue;
49
+ this.poolSizeValue = poolSizeValue;
50
+
51
+ const topSpacerValue = new FlexBox()
52
+ .width(FULL_SIZE, Unit.Percent)
53
+ .height(0.0, Unit.Pixel);
54
+ const bottomSpacerValue = new FlexBox()
55
+ .width(FULL_SIZE, Unit.Percent)
56
+ .height(0.0, Unit.Pixel);
57
+ const contentValue = new FlexBox()
58
+ .width(FULL_SIZE, Unit.Percent)
59
+ .flexDirection(FlexDirection.Column)
60
+ .child(topSpacerValue);
61
+
62
+ for (let index = 0; index < poolSizeValue; ++index) {
63
+ const container = new FlexBox()
64
+ .width(FULL_SIZE, Unit.Percent)
65
+ .height(FULL_SIZE, Unit.Percent);
66
+ const rowArea = new SelectionArea()
67
+ .width(FULL_SIZE, Unit.Percent)
68
+ .height(0.0, Unit.Pixel)
69
+ .child(container) as SelectionArea;
70
+ contentValue.child(rowArea);
71
+ poolValue.push(rowArea);
72
+ poolItemIndexByRow.push(-1);
73
+ }
74
+
75
+ contentValue.child(bottomSpacerValue);
76
+ const scrollBoxValue = new ScrollBox(scrollStateValue)
77
+ .scrollEnabledX(false)
78
+ .scrollEnabledY(true)
79
+ .scrollOffset(scrollStateValue.offsetX.value, scrollStateValue.offsetY.value)
80
+ .scrollContentSize(-1.0, <f32>totalItemsValue * itemHeightValue)
81
+ .width(FULL_SIZE, Unit.Percent)
82
+ .height(FULL_SIZE, Unit.Percent)
83
+ .child(contentValue) as ScrollBox;
84
+ scrollStateValue.contentHeight.value = <f32>totalItemsValue * itemHeightValue;
85
+
86
+ this.topSpacerValue = topSpacerValue;
87
+ this.bottomSpacerValue = bottomSpacerValue;
88
+ this.contentValue = contentValue;
89
+ this.scrollBoxValue = scrollBoxValue;
90
+ this.poolValue = poolValue;
91
+ this.poolItemIndexByRow = poolItemIndexByRow;
92
+ this.disposables = disposables;
93
+
94
+ this.flexDirection(FlexDirection.Column)
95
+ .child(this.scrollBoxValue)
96
+ .width(FULL_SIZE, Unit.Percent)
97
+ .height(FULL_SIZE, Unit.Percent);
98
+
99
+ this.attachListeners();
100
+ this.rebuildVisibleRange(false);
101
+ }
102
+
103
+ get scrollState(): ScrollState {
104
+ return this.scrollStateValue;
105
+ }
106
+
107
+ get totalItems(): i32 {
108
+ return this.totalItemsValue;
109
+ }
110
+
111
+ get scrollBar(): ScrollBar {
112
+ return this.scrollBoxValue.verticalScrollBar;
113
+ }
114
+
115
+ get itemHeight(): f32 {
116
+ return this.itemHeightValue;
117
+ }
118
+
119
+ get totalContentHeight(): f32 {
120
+ return <f32>this.totalItemsValue * this.itemHeightValue;
121
+ }
122
+
123
+ get firstVisibleIndex(): i32 {
124
+ return this.currentFirstVisibleIndex >= 0 ? this.currentFirstVisibleIndex : 0;
125
+ }
126
+
127
+ get renderedItemCount(): i32 {
128
+ if (this.currentFirstVisibleIndex < 0 || this.currentLastVisibleIndex < this.currentFirstVisibleIndex) {
129
+ return 0;
130
+ }
131
+ return this.currentLastVisibleIndex - this.currentFirstVisibleIndex;
132
+ }
133
+
134
+ get isSelectionBarrier(): bool {
135
+ return true;
136
+ }
137
+
138
+ nodeId(id: string): this {
139
+ this.scrollBoxValue.nodeId(id);
140
+ return this;
141
+ }
142
+
143
+ persistScroll(flag: bool = true): this {
144
+ this.scrollBoxValue.persistScroll(flag);
145
+ return this;
146
+ }
147
+
148
+ build(): u64 {
149
+ if (this.builtHandle != <u64>HandleValue.Invalid) {
150
+ return this.builtHandle;
151
+ }
152
+ const handle = super.build();
153
+ ui.setSelectionAreaBarrier(handle, true);
154
+ return handle;
155
+ }
156
+
157
+ width(value: f32, unit: Unit = Unit.Pixel): this {
158
+ super.width(value, unit);
159
+ if (unit == Unit.Pixel) {
160
+ this.scrollStateValue.viewportWidth.value = value;
161
+ }
162
+ return this;
163
+ }
164
+
165
+ height(value: f32, unit: Unit = Unit.Pixel): this {
166
+ super.height(value, unit);
167
+ if (unit == Unit.Pixel) {
168
+ this.scrollStateValue.viewportHeight.value = value;
169
+ }
170
+ return this;
171
+ }
172
+
173
+ render(): this {
174
+ return this;
175
+ }
176
+
177
+ updateItemCount(next: i32): void {
178
+ this.totalItemsValue = next > 0 ? next : 0;
179
+ this.scrollStateValue.contentHeight.value = this.totalContentHeight;
180
+ this.scrollBoxValue.scrollContentSize(-1.0, this.totalContentHeight);
181
+ this.currentFirstVisibleIndex = -1;
182
+ this.currentLastVisibleIndex = -1;
183
+
184
+ const clampedOffset = this.maxOffsetForCurrentViewport();
185
+ if (this.scrollStateValue.offsetY.value > clampedOffset) {
186
+ this.scrollBoxValue.scrollOffset(this.scrollStateValue.offsetX.value, clampedOffset);
187
+ return;
188
+ }
189
+ this.rebuildVisibleRange(true);
190
+ }
191
+
192
+ private disposeControl(): void {
193
+ disposeAll(this.disposables);
194
+ this.scrollBoxValue.dispose();
195
+ }
196
+
197
+ dispose(): void {
198
+ this.disposeControl();
199
+ super.dispose();
200
+ }
201
+
202
+ private attachListeners(): void {
203
+ this.disposables.push(
204
+ this.scrollStateValue.offsetY.addAction(
205
+ new HandlerAction<VirtualList, f32>(this, (list, _value): void => list.handleScrollOffsetChanged()),
206
+ ),
207
+ );
208
+ this.disposables.push(
209
+ this.scrollStateValue.viewportHeight.addAction(
210
+ new HandlerAction<VirtualList, f32>(this, (list, _value): void => list.handleMetricsChanged()),
211
+ ),
212
+ );
213
+ this.disposables.push(
214
+ this.scrollStateValue.contentHeight.addAction(
215
+ new HandlerAction<VirtualList, f32>(this, (list, _value): void => list.handleMetricsChanged()),
216
+ ),
217
+ );
218
+ }
219
+
220
+ private handleMetricsChanged(): void {
221
+ this.rebuildVisibleRange(true);
222
+ }
223
+
224
+ private handleScrollOffsetChanged(): void {
225
+ this.rebuildVisibleRange(true);
226
+ }
227
+
228
+ private rebuildVisibleRange(commit: bool = true): void {
229
+ const totalItems = this.totalItemsValue;
230
+ if (totalItems <= 0) {
231
+ if (this.currentFirstVisibleIndex == 0 && this.currentLastVisibleIndex == 0) {
232
+ return;
233
+ }
234
+ this.currentFirstVisibleIndex = 0;
235
+ this.currentLastVisibleIndex = 0;
236
+ this.topSpacerValue.height(0.0, Unit.Pixel);
237
+ this.bottomSpacerValue.height(0.0, Unit.Pixel);
238
+ for (let index = 0; index < this.poolSizeValue; ++index) {
239
+ this.hidePoolItem(unchecked(this.poolValue[index]), index);
240
+ }
241
+ this.commitIfBuilt(commit);
242
+ return;
243
+ }
244
+
245
+ let firstVisibleIndex = <i32>Math.floor(this.scrollStateValue.offsetY.value / this.itemHeightValue);
246
+ if (firstVisibleIndex < 0) {
247
+ firstVisibleIndex = 0;
248
+ }
249
+ if (firstVisibleIndex > totalItems) {
250
+ firstVisibleIndex = totalItems;
251
+ }
252
+
253
+ const viewportHeight = this.scrollStateValue.viewportHeight.value > 0.0
254
+ ? this.scrollStateValue.viewportHeight.value
255
+ : this.itemHeightValue;
256
+ let visibleCount = <i32>Math.ceil(viewportHeight / this.itemHeightValue) + 1;
257
+ if (visibleCount < 1) {
258
+ visibleCount = 1;
259
+ }
260
+ if (visibleCount > this.poolSizeValue) {
261
+ visibleCount = this.poolSizeValue;
262
+ }
263
+
264
+ let lastVisibleIndex = firstVisibleIndex + visibleCount;
265
+ if (lastVisibleIndex > totalItems) {
266
+ lastVisibleIndex = totalItems;
267
+ }
268
+
269
+ if (firstVisibleIndex == this.currentFirstVisibleIndex && lastVisibleIndex == this.currentLastVisibleIndex) {
270
+ return;
271
+ }
272
+
273
+ this.currentFirstVisibleIndex = firstVisibleIndex;
274
+ this.currentLastVisibleIndex = lastVisibleIndex;
275
+
276
+ const topSpacerHeight = <f32>firstVisibleIndex * this.itemHeightValue;
277
+ let bottomSpacerHeight = this.totalContentHeight - (<f32>lastVisibleIndex * this.itemHeightValue);
278
+ if (bottomSpacerHeight < 0.0) {
279
+ bottomSpacerHeight = 0.0;
280
+ }
281
+
282
+ this.topSpacerValue.height(topSpacerHeight, Unit.Pixel);
283
+ this.bottomSpacerValue.height(bottomSpacerHeight, Unit.Pixel);
284
+
285
+ const previousItemIndexByRow = new Array<i32>(this.poolSizeValue);
286
+ for (let poolIndex = 0; poolIndex < this.poolSizeValue; ++poolIndex) {
287
+ unchecked(previousItemIndexByRow[poolIndex] = this.poolItemIndexByRow[poolIndex]);
288
+ }
289
+
290
+ const visibleItems = lastVisibleIndex - firstVisibleIndex;
291
+ for (let poolIndex = 0; poolIndex < this.poolSizeValue; ++poolIndex) {
292
+ const previousItemIndex = unchecked(previousItemIndexByRow[poolIndex]);
293
+ if (previousItemIndex != -1 && (previousItemIndex < firstVisibleIndex || previousItemIndex >= lastVisibleIndex)) {
294
+ this.clearRowSelection(unchecked(this.poolValue[poolIndex]));
295
+ }
296
+ }
297
+
298
+ for (let poolIndex = 0; poolIndex < this.poolSizeValue; ++poolIndex) {
299
+ const rowArea = unchecked(this.poolValue[poolIndex]);
300
+ if (poolIndex < visibleItems) {
301
+ const nextItemIndex = firstVisibleIndex + poolIndex;
302
+ rowArea.height(this.itemHeightValue, Unit.Pixel);
303
+ const container = changetype<FlexBox>(rowArea.getChildAt(0));
304
+ this.bindItemValue(container, nextItemIndex);
305
+ unchecked(this.poolItemIndexByRow[poolIndex] = nextItemIndex);
306
+ } else {
307
+ this.hidePoolItem(rowArea, poolIndex);
308
+ }
309
+ }
310
+
311
+ for (let poolIndex = 0; poolIndex < visibleItems; ++poolIndex) {
312
+ const nextItemIndex = firstVisibleIndex + poolIndex;
313
+ const previousPoolIndex = this.findPoolIndexForItem(previousItemIndexByRow, nextItemIndex);
314
+ if (previousPoolIndex != -1 && previousPoolIndex != poolIndex) {
315
+ this.retargetRowSelection(
316
+ unchecked(this.poolValue[previousPoolIndex]),
317
+ unchecked(this.poolValue[poolIndex]),
318
+ );
319
+ }
320
+ }
321
+
322
+ this.commitIfBuilt(commit);
323
+ }
324
+
325
+ private hidePoolItem(rowArea: SelectionArea, poolIndex: i32): void {
326
+ if (unchecked(this.poolItemIndexByRow[poolIndex]) != -1) {
327
+ this.clearRowSelection(rowArea);
328
+ unchecked(this.poolItemIndexByRow[poolIndex] = -1);
329
+ }
330
+ rowArea.height(0.0, Unit.Pixel);
331
+ const container = rowArea.getChildAt(0);
332
+ if (container !== null) {
333
+ this.clearItemNode(container);
334
+ }
335
+ }
336
+
337
+ private clearRowSelection(rowArea: SelectionArea): void {
338
+ if (this.builtHandle == <u64>HandleValue.Invalid) {
339
+ return;
340
+ }
341
+ this.clearSelectionNode(rowArea);
342
+ }
343
+
344
+ private retargetRowSelection(fromRowArea: SelectionArea, toRowArea: SelectionArea): void {
345
+ if (this.builtHandle == <u64>HandleValue.Invalid) {
346
+ return;
347
+ }
348
+ const fromTexts = new Array<Text>();
349
+ const toTexts = new Array<Text>();
350
+ this.collectTextNodes(fromRowArea, fromTexts);
351
+ this.collectTextNodes(toRowArea, toTexts);
352
+ const pairCount = fromTexts.length < toTexts.length ? fromTexts.length : toTexts.length;
353
+ for (let index = 0; index < pairCount; ++index) {
354
+ const fromText = unchecked(fromTexts[index]);
355
+ const toText = unchecked(toTexts[index]);
356
+ if (
357
+ fromText.builtHandle != <u64>HandleValue.Invalid &&
358
+ toText.builtHandle != <u64>HandleValue.Invalid &&
359
+ fromText.builtHandle != toText.builtHandle
360
+ ) {
361
+ ui.retargetSelection(fromText.builtHandle, toText.builtHandle);
362
+ }
363
+ }
364
+ }
365
+
366
+ private collectTextNodes(node: Node, out: Array<Text>): void {
367
+ if (node instanceof Text) {
368
+ out.push(changetype<Text>(node));
369
+ return;
370
+ }
371
+ for (let index = 0; index < node.childCount; ++index) {
372
+ const child = node.getChildAt(index);
373
+ if (child !== null) {
374
+ this.collectTextNodes(changetype<Node>(child), out);
375
+ }
376
+ }
377
+ }
378
+
379
+ private findPoolIndexForItem(previousItemIndexByRow: Array<i32>, itemIndex: i32): i32 {
380
+ for (let poolIndex = 0; poolIndex < this.poolSizeValue; ++poolIndex) {
381
+ if (unchecked(previousItemIndexByRow[poolIndex]) == itemIndex) {
382
+ return poolIndex;
383
+ }
384
+ }
385
+ return -1;
386
+ }
387
+
388
+ private clearSelectionNode(node: Node): void {
389
+ if (node instanceof Text) {
390
+ const textNode = changetype<Text>(node);
391
+ if (textNode.builtHandle != <u64>HandleValue.Invalid) {
392
+ ui.clearSelection(textNode.builtHandle);
393
+ }
394
+ return;
395
+ }
396
+ for (let index = 0; index < node.childCount; ++index) {
397
+ const child = node.getChildAt(index);
398
+ if (child !== null) {
399
+ this.clearSelectionNode(changetype<Node>(child));
400
+ }
401
+ }
402
+ }
403
+
404
+ private clearItemNode(node: Node): void {
405
+ node.semanticLabel("");
406
+ if (node instanceof Text) {
407
+ changetype<Text>(node).text("");
408
+ }
409
+ for (let index = 0; index < node.childCount; ++index) {
410
+ const child = node.getChildAt(index);
411
+ if (child !== null) {
412
+ this.clearItemNode(changetype<Node>(child));
413
+ }
414
+ }
415
+ }
416
+
417
+ private commitIfBuilt(commit: bool): void {
418
+ if (!commit || this.builtHandle == <u64>HandleValue.Invalid) {
419
+ return;
420
+ }
421
+ markNeedsCommit();
422
+ }
423
+
424
+ private maxOffsetForCurrentViewport(): f32 {
425
+ const viewportHeight = this.scrollStateValue.viewportHeight.value > 0.0
426
+ ? this.scrollStateValue.viewportHeight.value
427
+ : 0.0;
428
+ const maxOffset = this.totalContentHeight - viewportHeight;
429
+ return maxOffset > 0.0 ? maxOffset : 0.0;
430
+ }
431
+ }
@@ -0,0 +1,25 @@
1
+ import { FlexDirection, Unit } from "../core/ffi";
2
+ import { Node } from "../core/Node";
3
+ import { FlexBox } from "./FlexBox";
4
+
5
+ export function px(value: f32): StaticArray<f32> {
6
+ const pair = new StaticArray<f32>(2);
7
+ unchecked(pair[0] = value);
8
+ unchecked(pair[1] = <f32>Unit.Pixel);
9
+ return pair;
10
+ }
11
+
12
+ export function pct(value: f32): StaticArray<f32> {
13
+ const pair = new StaticArray<f32>(2);
14
+ unchecked(pair[0] = value);
15
+ unchecked(pair[1] = <f32>Unit.Percent);
16
+ return pair;
17
+ }
18
+
19
+ export function Row(...children: Node[]): FlexBox {
20
+ return new FlexBox().flexDirection(FlexDirection.Row).children(children);
21
+ }
22
+
23
+ export function Column(...children: Node[]): FlexBox {
24
+ return new FlexBox().flexDirection(FlexDirection.Column).children(children);
25
+ }
@@ -0,0 +1,14 @@
1
+ export { FlexBox, FlexBoxProps } from "./FlexBox";
2
+ export { GradientStop } from "./GradientStop";
3
+ export { Grid } from "./Grid";
4
+ export { Image } from "./Image";
5
+ export { Portal } from "./Portal";
6
+ export { RichText, RichTextSpan, Span, span } from "./RichText";
7
+ export { ScrollBox } from "./ScrollBox";
8
+ export { ScrollBar, ScrollBarVisibility } from "./ScrollBar";
9
+ export { ScrollState } from "./ScrollState";
10
+ export { ScrollView } from "./ScrollView";
11
+ export { Svg } from "./Svg";
12
+ export { Text } from "./Text";
13
+ export { TextCore, TextProps } from "./TextCore";
14
+ export { VirtualList } from "./VirtualList";
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "assemblyscript/std/assembly.json",
3
+ "compilerOptions": {
4
+ "noEmit": true
5
+ },
6
+ "include": ["**/*.ts"]
7
+ }
@@ -0,0 +1,169 @@
1
+ import {
2
+ fui_worker_complete_string,
3
+ fui_worker_copy_input,
4
+ fui_worker_fail,
5
+ fui_worker_input_length,
6
+ fui_worker_is_cancelled,
7
+ fui_worker_request_yield,
8
+ fui_worker_request_yield_delay,
9
+ fui_worker_report_progress,
10
+ } from "./ffi";
11
+ import { handleFetchComplete, handleFetchError } from "../core/Fetch";
12
+
13
+ let inputRead = false;
14
+ let inputCache = "";
15
+ let terminalSent = false;
16
+ let testInputOverride: string | null = null;
17
+ const WORKER_CALLBACK_BUFFER = new Uint8Array(1024 * 1024);
18
+
19
+ function encodeUtf8(text: string): Uint8Array {
20
+ return Uint8Array.wrap(String.UTF8.encode(text, false));
21
+ }
22
+
23
+ function readInputMessage(): string {
24
+ if (testInputOverride !== null) {
25
+ return changetype<string>(testInputOverride);
26
+ }
27
+ const byteLength = fui_worker_input_length();
28
+ if (byteLength == 0) {
29
+ return "";
30
+ }
31
+ const bytes = new Uint8Array(byteLength);
32
+ const copied = fui_worker_copy_input(bytes.dataStart, <u32>bytes.length);
33
+ if (copied == 0) {
34
+ return "";
35
+ }
36
+ return String.UTF8.decodeUnsafe(bytes.dataStart, <usize>copied, false);
37
+ }
38
+
39
+ function sendText(text: string, callback: (ptr: usize, len: u32) => void): void {
40
+ const bytes = encodeUtf8(text);
41
+ callback(bytes.length > 0 ? bytes.dataStart : 0, <u32>bytes.length);
42
+ }
43
+
44
+ export class Worker {
45
+ static receiveMessage(): string {
46
+ if (inputRead) {
47
+ return inputCache;
48
+ }
49
+ inputCache = readInputMessage();
50
+ inputRead = true;
51
+ return inputCache;
52
+ }
53
+
54
+ static reportProgress(progress: string): void {
55
+ if (terminalSent) {
56
+ return;
57
+ }
58
+ sendText(progress, (ptr, len) => {
59
+ fui_worker_report_progress(ptr, len);
60
+ });
61
+ }
62
+
63
+ static complete(result: string): void {
64
+ if (terminalSent) {
65
+ return;
66
+ }
67
+ terminalSent = true;
68
+ sendText(result, (ptr, len) => {
69
+ fui_worker_complete_string(ptr, len);
70
+ });
71
+ }
72
+
73
+ static fail(message: string): void {
74
+ if (terminalSent) {
75
+ return;
76
+ }
77
+ terminalSent = true;
78
+ sendText(message, (ptr, len) => {
79
+ fui_worker_fail(ptr, len);
80
+ });
81
+ }
82
+
83
+ static isCancelled(): bool {
84
+ return fui_worker_is_cancelled();
85
+ }
86
+
87
+ static yield(delayMs: i32 = 0): bool {
88
+ if (terminalSent) {
89
+ return false;
90
+ }
91
+ if (delayMs > 0) {
92
+ fui_worker_request_yield_delay(delayMs);
93
+ return true;
94
+ }
95
+ fui_worker_request_yield();
96
+ return true;
97
+ }
98
+
99
+ static yieldNow(delayMs: i32 = 0): bool {
100
+ return Worker.yield(delayMs);
101
+ }
102
+ }
103
+
104
+ function readWorkerTextParts(payloadPtr: usize, payloadLen: u32): Array<string> {
105
+ const values = new Array<string>();
106
+ if (payloadPtr == 0 || payloadLen < sizeof<u32>()) {
107
+ return values;
108
+ }
109
+ const end = payloadPtr + <usize>payloadLen;
110
+ let cursor = payloadPtr;
111
+ const count = load<u32>(cursor);
112
+ cursor += sizeof<u32>();
113
+ for (let index: u32 = 0; index < count; index += 1) {
114
+ if (cursor + sizeof<u32>() > end) {
115
+ return values;
116
+ }
117
+ const partLen = load<u32>(cursor);
118
+ cursor += sizeof<u32>();
119
+ if (cursor + <usize>partLen > end) {
120
+ return values;
121
+ }
122
+ values.push(partLen > 0 ? String.UTF8.decodeUnsafe(cursor, <usize>partLen, false) : "");
123
+ cursor += <usize>partLen;
124
+ }
125
+ return values;
126
+ }
127
+
128
+ export function __fui_worker_text_buffer(): usize {
129
+ return WORKER_CALLBACK_BUFFER.dataStart;
130
+ }
131
+
132
+ export function __fui_worker_text_buffer_size(): u32 {
133
+ return <u32>WORKER_CALLBACK_BUFFER.length;
134
+ }
135
+
136
+ export function __fui_on_fetch_complete(
137
+ requestId: u32,
138
+ ok: bool,
139
+ status: i32,
140
+ payloadPtr: usize,
141
+ payloadLen: u32,
142
+ ): void {
143
+ const payload = readWorkerTextParts(payloadPtr, payloadLen);
144
+ handleFetchComplete(
145
+ requestId,
146
+ ok,
147
+ status,
148
+ payload.length > 0 ? unchecked(payload[0]) : "",
149
+ payload.length > 1 ? unchecked(payload[1]) : "",
150
+ );
151
+ }
152
+
153
+ export function __fui_on_fetch_error(requestId: u32, payloadPtr: usize, payloadLen: u32): void {
154
+ handleFetchError(
155
+ requestId,
156
+ payloadPtr == 0 || payloadLen == 0 ? null : String.UTF8.decodeUnsafe(payloadPtr, <usize>payloadLen, false),
157
+ );
158
+ }
159
+
160
+ export function __resetWorkerRuntimeForTests(): void {
161
+ inputRead = false;
162
+ inputCache = "";
163
+ terminalSent = false;
164
+ testInputOverride = null;
165
+ }
166
+
167
+ export function __setWorkerInputForTests(value: string): void {
168
+ testInputOverride = value;
169
+ }
@@ -0,0 +1,65 @@
1
+ import { Worker } from "./Worker";
2
+
3
+ export abstract class WorkerJob {
4
+ private started: bool = false;
5
+ private finished: bool = false;
6
+
7
+ static resume<T extends WorkerJob>(job: T): T | null {
8
+ job.ensureStarted();
9
+ if (job.finished) {
10
+ return null;
11
+ }
12
+ job.run();
13
+ return job.finished ? null : job;
14
+ }
15
+
16
+ protected onStart(): void {}
17
+
18
+ abstract run(): void;
19
+
20
+ protected receiveMessage(): string {
21
+ return Worker.receiveMessage();
22
+ }
23
+
24
+ protected reportProgress(progress: string): void {
25
+ if (this.finished) {
26
+ return;
27
+ }
28
+ Worker.reportProgress(progress);
29
+ }
30
+
31
+ protected complete(result: string): void {
32
+ if (this.finished) {
33
+ return;
34
+ }
35
+ this.finished = true;
36
+ Worker.complete(result);
37
+ }
38
+
39
+ protected fail(message: string): void {
40
+ if (this.finished) {
41
+ return;
42
+ }
43
+ this.finished = true;
44
+ Worker.fail(message);
45
+ }
46
+
47
+ protected isCancelled(): bool {
48
+ return Worker.isCancelled();
49
+ }
50
+
51
+ protected yield(delayMs: i32 = 0): bool {
52
+ if (this.finished) {
53
+ return false;
54
+ }
55
+ return Worker.yield(delayMs);
56
+ }
57
+
58
+ private ensureStarted(): void {
59
+ if (this.started) {
60
+ return;
61
+ }
62
+ this.started = true;
63
+ this.onStart();
64
+ }
65
+ }