@effindomv2/fui-as 0.1.37 → 0.1.39

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 (118) hide show
  1. package/browser/routed-app-conventions.ts +1 -1
  2. package/browser/src/common-harness.ts +1 -27
  3. package/browser/src/index.ts +19 -26
  4. package/browser/src/routed-harness.ts +1 -194
  5. package/browser/src/shared-browser.ts +6 -0
  6. package/package.json +23 -13
  7. package/scripts/build.sh +47 -46
  8. package/scripts/framework-host-services.ts +1 -1
  9. package/scripts/generate-host-events.ts +15 -241
  10. package/scripts/generate-host-services.ts +13 -261
  11. package/scripts/hostgen/assemblyscript-host-events.ts +165 -0
  12. package/scripts/hostgen/assemblyscript-host-services.ts +207 -0
  13. package/scripts/hostgen/common.ts +73 -0
  14. package/scripts/hostgen/registry.ts +159 -0
  15. package/src/Fui.ts +65 -5
  16. package/src/FuiExports.ts +12 -1
  17. package/src/bindings/ui.ts +157 -8
  18. package/src/controls/Button.ts +98 -71
  19. package/src/controls/Checkbox.ts +23 -21
  20. package/src/controls/ComboBox.ts +1201 -0
  21. package/src/controls/ContextMenu.ts +279 -165
  22. package/src/controls/Dialog.ts +91 -17
  23. package/src/controls/Dropdown.ts +101 -333
  24. package/src/controls/NavLink.ts +29 -6
  25. package/src/controls/Popup.ts +10 -5
  26. package/src/controls/ProgressBar.ts +1 -2
  27. package/src/controls/RadioButton.ts +34 -13
  28. package/src/controls/RadioGroup.ts +32 -19
  29. package/src/controls/Slider.ts +21 -23
  30. package/src/controls/Switch.ts +34 -17
  31. package/src/controls/index.ts +2 -1
  32. package/src/controls/internal/ButtonPresenter.ts +5 -2
  33. package/src/controls/internal/CheckboxIndicatorPresenter.ts +10 -10
  34. package/src/controls/internal/DropdownChevronPresenter.ts +3 -3
  35. package/src/controls/internal/DropdownFieldPresenter.ts +6 -6
  36. package/src/controls/internal/DropdownOptionRowPresenter.ts +5 -4
  37. package/src/controls/internal/PressableLabeledControl.ts +4 -7
  38. package/src/controls/internal/RadioIndicatorPresenter.ts +7 -7
  39. package/src/controls/internal/SelectablePopupList.ts +463 -0
  40. package/src/controls/internal/SliderPresenter.ts +5 -5
  41. package/src/controls/internal/SwitchIndicatorPresenter.ts +63 -17
  42. package/src/controls/internal/TextInputCore.ts +307 -41
  43. package/src/controls/internal/TextInputPresenter.ts +2 -2
  44. package/src/controls/templating.ts +10 -0
  45. package/src/core/Application.ts +17 -8
  46. package/src/core/Bitmap.ts +192 -3
  47. package/src/core/ContextMenuManager.ts +128 -44
  48. package/src/core/DebugApi.ts +17 -2
  49. package/src/core/DragGesture.ts +8 -7
  50. package/src/core/EventRouter.ts +332 -12
  51. package/src/core/Fetch.ts +15 -7
  52. package/src/core/FetchFfi.ts +1 -15
  53. package/src/core/File.ts +75 -34
  54. package/src/core/FocusAdornerManager.ts +3 -3
  55. package/src/core/FocusVisibility.ts +7 -0
  56. package/src/core/FrameScheduler.ts +104 -5
  57. package/src/core/ImageSampling.ts +43 -0
  58. package/src/core/Logger.ts +2 -0
  59. package/src/core/MobileTextSelectionToolbarManager.ts +901 -0
  60. package/src/core/Node.ts +1039 -97
  61. package/src/core/Platform.ts +16 -16
  62. package/src/core/SelectionHandleAdornerManager.ts +697 -0
  63. package/src/core/Theme.ts +34 -20
  64. package/src/core/ToolTipManager.ts +3 -3
  65. package/src/core/Typography.ts +411 -19
  66. package/src/core/Worker.ts +69 -33
  67. package/src/core/event_exports.ts +123 -5
  68. package/src/core/ffi.ts +5 -865
  69. package/src/core/generated/FetchHostAbi.ts +10 -0
  70. package/src/core/generated/FrameworkHostServices.ts +1 -1
  71. package/src/core/generated/HostAbi.ts +220 -0
  72. package/src/core/generated/UiAbi.ts +356 -0
  73. package/src/core/generated/UiEnums.ts +186 -0
  74. package/src/drawing/DrawCallback.ts +17 -1
  75. package/src/drawing/DrawContext.ts +140 -32
  76. package/src/nodes/CustomDrawable.ts +8 -1
  77. package/src/nodes/FlexBox.ts +40 -11
  78. package/src/nodes/Grid.ts +5 -5
  79. package/src/nodes/Image.ts +20 -1
  80. package/src/nodes/RichText.ts +36 -25
  81. package/src/nodes/ScrollBar.ts +2 -1
  82. package/src/nodes/ScrollBox.ts +7 -2
  83. package/src/nodes/ScrollView.ts +17 -6
  84. package/src/nodes/Svg.ts +18 -1
  85. package/src/nodes/Text.ts +1 -1
  86. package/src/nodes/TextCore.ts +115 -20
  87. package/src/nodes/index.ts +1 -1
  88. package/src/text/DynamicTextLayout.ts +275 -0
  89. package/src/text/TextLayout.ts +308 -0
  90. package/src/worker/Worker.ts +3 -36
  91. package/src/worker/WorkerJob.ts +5 -9
  92. package/src/worker/ffi.ts +0 -6
  93. package/browser/src/common-harness/host-imports.ts +0 -447
  94. package/browser/src/common-harness/interop.ts +0 -39
  95. package/browser/src/common-harness/managed-harness-bitmap-host.ts +0 -92
  96. package/browser/src/common-harness/managed-harness-canvas-host.ts +0 -72
  97. package/browser/src/common-harness/managed-harness-fetch-host.ts +0 -201
  98. package/browser/src/common-harness/managed-harness-file-host.ts +0 -1066
  99. package/browser/src/common-harness/managed-harness-file-payloads.ts +0 -143
  100. package/browser/src/common-harness/managed-harness-file-types.ts +0 -71
  101. package/browser/src/common-harness/managed-harness-session.ts +0 -15
  102. package/browser/src/common-harness/managed-harness.ts +0 -1472
  103. package/browser/src/common-harness/managed-history.ts +0 -168
  104. package/browser/src/common-harness/persisted-restore-policy.ts +0 -50
  105. package/browser/src/common-harness/persisted-ui-state-controller.ts +0 -309
  106. package/browser/src/common-harness/text-session-bridge.ts +0 -452
  107. package/browser/src/common-harness/types.ts +0 -206
  108. package/browser/src/common-harness/ui-chrome.ts +0 -206
  109. package/browser/src/common-harness/ui-imports.ts +0 -559
  110. package/browser/src/common-harness/wasm-module-cache.ts +0 -47
  111. package/browser/src/file-processing-worker.ts +0 -89
  112. package/browser/src/host-events.ts +0 -118
  113. package/browser/src/host-services.ts +0 -483
  114. package/browser/src/persisted-ui-state.ts +0 -206
  115. package/browser/src/routed-app-conventions.ts +0 -292
  116. package/browser/src/worker-bootstrap.ts +0 -916
  117. package/browser/src/worker-manager.ts +0 -234
  118. package/browser/src/worker-types.ts +0 -68
@@ -11,11 +11,19 @@ import {
11
11
  trackKeyboardScrollPointerUp,
12
12
  unregisterKeyboardScrollNode,
13
13
  } from "./KeyboardScrollTracker";
14
- import { DragDropEffects, DragSession, ExternalDropItemInfo, Node } from "./Node";
14
+ import { DEFAULT_LONG_PRESS_MINIMUM_DURATION_MS, DEFAULT_LONG_PRESS_MOVEMENT_TOLERANCE, DragDropEffects, DragSession, ExternalDropItemInfo, GestureEventArgs, GestureEventKind, GestureEventPhase, GestureIntent, LongPressEventArgs, Node, PointerEventArgs, PointerType, WheelDeltaMode, WheelEventArgs } from "./Node";
15
15
  import { DragDropManager } from "./DragDropManager";
16
16
  import { ExternalDragEventType, ExternalDropManager } from "./ExternalDropManager";
17
17
  import { isCoarsePointer } from "./Platform";
18
+ import { ContextMenuManager } from "./ContextMenuManager";
19
+ import { MobileTextSelectionToolbarManager } from "./MobileTextSelectionToolbarManager";
20
+ import { SelectionHandleAdornerManager } from "./SelectionHandleAdornerManager";
18
21
  import { runScrollHooks } from "./ScrollHooks";
22
+ import * as ui from "../bindings/ui";
23
+ import { NavLink } from "../controls/NavLink";
24
+ import { TextInputCore } from "../controls/internal/TextInputCore";
25
+ import { Image } from "../nodes/Image";
26
+ import { Svg } from "../nodes/Svg";
19
27
 
20
28
  export interface GlobalKeyHandler {
21
29
  handleGlobalKeyEvent(eventType: KeyEventType, key: string, modifiers: u32): bool;
@@ -68,36 +76,97 @@ export class EventRouter {
68
76
  this.applyCurrentCursor();
69
77
  }
70
78
 
71
- static dispatchPointerEvent(handle: u64, eventType: PointerEventType, x: f32, y: f32, modifiers: u32 = 0): void {
79
+ static dispatchPointerEvent(
80
+ handle: u64,
81
+ eventType: PointerEventType,
82
+ x: f32,
83
+ y: f32,
84
+ modifiers: u32 = 0,
85
+ pointerId: i32 = -1,
86
+ pointerType: PointerType = PointerType.Unknown,
87
+ button: i32 = 0,
88
+ buttons: u32 = 0,
89
+ pressure: f32 = 0.0,
90
+ width: f32 = 0.0,
91
+ height: f32 = 0.0,
92
+ clickCount: i32 = 0,
93
+ ): bool {
72
94
  showKeyboardFocusForPointerEvent(eventType);
95
+ SelectionHandleAdornerManager.recordPointerEvent(eventType, pointerType);
73
96
  const pointedNode = this.resolveNode(handle);
97
+ if (
98
+ eventType == PointerEventType.Down &&
99
+ !this.preservesSelectionOnPointerDownForRouting(pointedNode) &&
100
+ MobileTextSelectionToolbarManager.dismissForOutsidePointerDown(x, y)
101
+ ) {
102
+ DragDropManager.handlePointerEvent(null, eventType, x, y, modifiers);
103
+ this.applyCurrentCursor();
104
+ return true;
105
+ }
74
106
  if (eventType == PointerEventType.Up) {
75
107
  trackKeyboardScrollPointerUp(pointedNode, x, y);
76
108
  }
77
- if (eventType == PointerEventType.Move || eventType == PointerEventType.Up) {
109
+ if (eventType == PointerEventType.Move || eventType == PointerEventType.Up || eventType == PointerEventType.Cancel) {
78
110
  const capturedNode = this.resolveNode(this.capturedPointerHandle);
79
111
  if (capturedNode !== null) {
80
112
  const capturedHandle = this.capturedPointerHandle;
81
- capturedNode._handlePointerEvent(eventType, x, y, modifiers);
113
+ const event = new PointerEventArgs(
114
+ eventType,
115
+ x,
116
+ y,
117
+ modifiers,
118
+ pointerId,
119
+ pointerType,
120
+ button,
121
+ buttons,
122
+ pressure,
123
+ width,
124
+ height,
125
+ clickCount,
126
+ );
127
+ Node._dispatchPointerEventWithArgs(capturedNode, event);
128
+ this.bubblePointerEvent(changetype<Node>(capturedNode).parentNode, event);
82
129
  DragDropManager.handlePointerEvent(pointedNode, eventType, x, y, modifiers);
83
- if (eventType == PointerEventType.Up && this.capturedPointerHandle == capturedHandle) {
130
+ if ((eventType == PointerEventType.Up || eventType == PointerEventType.Cancel) && this.capturedPointerHandle == capturedHandle) {
84
131
  this.capturedPointerHandle = <u64>HandleValue.Invalid;
85
132
  }
86
133
  this.applyCurrentCursor();
87
- return;
134
+ return event.handled;
88
135
  }
89
136
  if (this.capturedPointerHandle != <u64>HandleValue.Invalid) {
90
137
  this.capturedPointerHandle = <u64>HandleValue.Invalid;
91
138
  }
92
139
  }
93
140
 
141
+ if (eventType == PointerEventType.Move || eventType == PointerEventType.Up || eventType == PointerEventType.Cancel) {
142
+ const handleDragEvent = new PointerEventArgs(
143
+ eventType,
144
+ x,
145
+ y,
146
+ modifiers,
147
+ pointerId,
148
+ pointerType,
149
+ button,
150
+ buttons,
151
+ pressure,
152
+ width,
153
+ height,
154
+ clickCount,
155
+ );
156
+ if (SelectionHandleAdornerManager.routeActiveHandleDragEvent(handleDragEvent)) {
157
+ DragDropManager.handlePointerEvent(pointedNode, eventType, x, y, modifiers);
158
+ this.applyCurrentCursor();
159
+ return handleDragEvent.handled;
160
+ }
161
+ }
162
+
94
163
  if (handle == <u64>HandleValue.Invalid) {
95
164
  if (eventType == PointerEventType.Leave) {
96
165
  this.clearHoverStack();
97
166
  }
98
167
  DragDropManager.handlePointerEvent(null, eventType, x, y, modifiers);
99
168
  this.applyCurrentCursor();
100
- return;
169
+ return false;
101
170
  }
102
171
 
103
172
  const node = pointedNode;
@@ -107,16 +176,220 @@ export class EventRouter {
107
176
  }
108
177
  DragDropManager.handlePointerEvent(null, eventType, x, y, modifiers);
109
178
  this.applyCurrentCursor();
110
- return;
179
+ return false;
111
180
  }
112
181
  if (eventType == PointerEventType.Enter) {
113
182
  this.pushHover(changetype<Node>(node));
114
183
  } else if (eventType == PointerEventType.Leave) {
115
184
  this.popHover(changetype<Node>(node));
116
185
  }
117
- node._handlePointerEvent(eventType, x, y, modifiers);
186
+ const event = new PointerEventArgs(
187
+ eventType,
188
+ x,
189
+ y,
190
+ modifiers,
191
+ pointerId,
192
+ pointerType,
193
+ button,
194
+ buttons,
195
+ pressure,
196
+ width,
197
+ height,
198
+ clickCount,
199
+ );
200
+ Node._dispatchPointerEventWithArgs(node, event);
201
+ this.bubblePointerEvent(changetype<Node>(node).parentNode, event);
118
202
  DragDropManager.handlePointerEvent(node, eventType, x, y, modifiers);
119
203
  this.applyCurrentCursor();
204
+ return event.handled;
205
+ }
206
+
207
+ private static bubblePointerEvent(parent: Node | null, event: PointerEventArgs): void {
208
+ let node = parent;
209
+ while (node !== null && !event.handled) {
210
+ const current = changetype<Node>(node);
211
+ current._handleBubbledPointerEvent(event);
212
+ node = current.parentNode;
213
+ }
214
+ }
215
+
216
+ static dispatchWheelEvent(
217
+ handle: u64,
218
+ x: f32,
219
+ y: f32,
220
+ deltaX: f32,
221
+ deltaY: f32,
222
+ deltaMode: WheelDeltaMode,
223
+ modifiers: u32,
224
+ ): bool {
225
+ let node = this.resolveNode(handle);
226
+ if (node === null) {
227
+ return false;
228
+ }
229
+ const event = new WheelEventArgs(x, y, deltaX, deltaY, deltaMode, modifiers);
230
+ while (node !== null) {
231
+ const current = changetype<Node>(node);
232
+ if (current.isEnabled && current.isVisible && current._handleWheelEvent(event)) {
233
+ return true;
234
+ }
235
+ node = current.parentNode;
236
+ }
237
+ return false;
238
+ }
239
+
240
+ static resolveGestureOwner(handle: u64): u64 {
241
+ let node = this.resolveNode(handle);
242
+ while (node !== null) {
243
+ const current = changetype<Node>(node);
244
+ if (current.isEnabled && current.isVisible && current.gestureIntentValueForRouting != GestureIntent.None) {
245
+ return current.builtHandle;
246
+ }
247
+ node = current.parentNode;
248
+ }
249
+ return <u64>HandleValue.Invalid;
250
+ }
251
+
252
+ static getGestureIntent(handle: u64): GestureIntent {
253
+ const node = this.resolveNode(handle);
254
+ return node === null ? GestureIntent.None : node.gestureIntentValueForRouting;
255
+ }
256
+
257
+ static resolveLongPressOwner(handle: u64): u64 {
258
+ let node = this.resolveNode(handle);
259
+ while (node !== null) {
260
+ const current = changetype<Node>(node);
261
+ if (current.isEnabled && current.isVisible && current.hasLongPressGestureForRouting) {
262
+ return current.builtHandle;
263
+ }
264
+ node = current.parentNode;
265
+ }
266
+ node = this.resolveNode(handle);
267
+ while (node !== null) {
268
+ const current = changetype<Node>(node);
269
+ if (
270
+ current.isEnabled &&
271
+ current.isVisible &&
272
+ (current instanceof NavLink || current instanceof Image || current instanceof Svg)
273
+ ) {
274
+ return current.builtHandle;
275
+ }
276
+ if (current.isEnabled && current.isVisible && this.hasImageContextMenuTargetDescendant(current)) {
277
+ return current.builtHandle;
278
+ }
279
+ if (current.isEnabled && current.isVisible && current instanceof TextInputCore) {
280
+ const editor = changetype<TextInputCore>(current).editorNode;
281
+ if (editor.isEnabled && editor.isVisible && (editor.isSelectableText || editor.isEditableText)) {
282
+ return editor.builtHandle;
283
+ }
284
+ }
285
+ if (current.isEnabled && current.isVisible && (current.isSelectableText || current.isEditableText)) {
286
+ return current.builtHandle;
287
+ }
288
+ node = current.parentNode;
289
+ }
290
+ return <u64>HandleValue.Invalid;
291
+ }
292
+
293
+ private static hasImageContextMenuTargetDescendant(node: Node): bool {
294
+ for (let index = 0; index < node.childCount; ++index) {
295
+ const child = node.getChildAt(index);
296
+ if (child === null) {
297
+ continue;
298
+ }
299
+ const childNode = changetype<Node>(child);
300
+ if (!childNode.isEnabled || !childNode.isVisible) {
301
+ continue;
302
+ }
303
+ if (childNode instanceof Image || childNode instanceof Svg) {
304
+ return true;
305
+ }
306
+ if (this.hasImageContextMenuTargetDescendant(childNode)) {
307
+ return true;
308
+ }
309
+ }
310
+ return false;
311
+ }
312
+
313
+ static getLongPressMinimumDurationMs(handle: u64): i32 {
314
+ const node = this.resolveNode(handle);
315
+ return node === null ? DEFAULT_LONG_PRESS_MINIMUM_DURATION_MS : node.longPressMinimumDurationMsForRouting;
316
+ }
317
+
318
+ static getLongPressMovementTolerance(handle: u64): f32 {
319
+ const node = this.resolveNode(handle);
320
+ return node === null ? DEFAULT_LONG_PRESS_MOVEMENT_TOLERANCE : node.longPressMovementToleranceForRouting;
321
+ }
322
+
323
+ static dispatchLongPressEvent(
324
+ handle: u64,
325
+ x: f32,
326
+ y: f32,
327
+ pointerId: i32,
328
+ pointerType: PointerType,
329
+ modifiers: u32,
330
+ durationMs: i32,
331
+ ): bool {
332
+ const node = this.resolveNode(handle);
333
+ if (node === null) {
334
+ return false;
335
+ }
336
+ const event = new LongPressEventArgs(x, y, pointerId, pointerType, modifiers, durationMs);
337
+ Node._dispatchLongPressEventWithArgs(node, event);
338
+ this.bubbleLongPressEvent(changetype<Node>(node).parentNode, event);
339
+ if (
340
+ !event.handled &&
341
+ (pointerType == PointerType.Touch || pointerType == PointerType.Pen) &&
342
+ (node.isSelectableText || node.isEditableText)
343
+ ) {
344
+ MobileTextSelectionToolbarManager.setPendingCrossSelectionTextHandle(handle);
345
+ event.handled = ui.selectWordAt(handle, x, y);
346
+ if (!event.handled) {
347
+ MobileTextSelectionToolbarManager.setPendingCrossSelectionTextHandle(0);
348
+ }
349
+ }
350
+ if (!event.handled) {
351
+ event.handled = ContextMenuManager.showForLongPress(handle, x, y);
352
+ }
353
+ return event.handled;
354
+ }
355
+
356
+ private static bubbleLongPressEvent(parent: Node | null, event: LongPressEventArgs): void {
357
+ let node = parent;
358
+ while (node !== null && !event.handled) {
359
+ const current = changetype<Node>(node);
360
+ current._handleBubbledLongPressEvent(event);
361
+ node = current.parentNode;
362
+ }
363
+ }
364
+
365
+ static dispatchGestureEvent(
366
+ handle: u64,
367
+ phase: GestureEventPhase,
368
+ kind: GestureEventKind,
369
+ x: f32,
370
+ y: f32,
371
+ deltaX: f32,
372
+ deltaY: f32,
373
+ scale: f32,
374
+ pointerCount: i32,
375
+ ): bool {
376
+ const node = this.resolveNode(handle);
377
+ if (node === null) {
378
+ return false;
379
+ }
380
+ const event = new GestureEventArgs(phase, kind, x, y, deltaX, deltaY, scale, pointerCount);
381
+ Node._dispatchGestureEventWithArgs(node, event);
382
+ this.bubbleGestureEvent(changetype<Node>(node).parentNode, event);
383
+ return event.handled;
384
+ }
385
+
386
+ private static bubbleGestureEvent(parent: Node | null, event: GestureEventArgs): void {
387
+ let node = parent;
388
+ while (node !== null && !event.handled) {
389
+ const current = changetype<Node>(node);
390
+ current._handleBubbledGestureEvent(event);
391
+ node = current.parentNode;
392
+ }
120
393
  }
121
394
 
122
395
  static dispatchFocusChanged(handle: u64, focused: bool): void {
@@ -133,22 +406,29 @@ export class EventRouter {
133
406
  }
134
407
 
135
408
  static dispatchKeyEvent(handle: u64, eventType: KeyEventType, key: string, modifiers: u32): bool {
136
- showKeyboardFocusForKeyEvent(eventType, key, modifiers);
137
409
  const node = this.resolveNode(handle);
138
410
  if (node === null) {
411
+ showKeyboardFocusForKeyEvent(eventType, key, modifiers);
139
412
  return false;
140
413
  }
141
- return node._handleKeyEvent(eventType, key, modifiers);
414
+ const handled = node._handleKeyEvent(eventType, key, modifiers);
415
+ if (!handled || key != "Tab" || modifiers != 0) {
416
+ showKeyboardFocusForKeyEvent(eventType, key, modifiers);
417
+ }
418
+ return handled;
142
419
  }
143
420
 
144
421
  static dispatchGlobalKeyEvent(eventType: KeyEventType, key: string, modifiers: u32): bool {
145
- showKeyboardFocusForKeyEvent(eventType, key, modifiers);
146
422
  for (let index = this.keyFilterHandlers.length - 1; index >= 0; --index) {
147
423
  const handler = unchecked(this.keyFilterHandlers[index]);
148
424
  if (handler.handleGlobalKeyEvent(eventType, key, modifiers)) {
425
+ if (key != "Tab" || modifiers != 0) {
426
+ showKeyboardFocusForKeyEvent(eventType, key, modifiers);
427
+ }
149
428
  return true;
150
429
  }
151
430
  }
431
+ showKeyboardFocusForKeyEvent(eventType, key, modifiers);
152
432
  return false;
153
433
  }
154
434
 
@@ -162,6 +442,8 @@ export class EventRouter {
162
442
  viewportHeight: f32,
163
443
  ): void {
164
444
  ToolTipManager.handleScroll();
445
+ SelectionHandleAdornerManager.refreshActiveGeometry();
446
+ MobileTextSelectionToolbarManager.refreshActiveGeometry(SelectionHandleAdornerManager.isVisible());
165
447
  runScrollHooks();
166
448
  const node = this.resolveNode(handle);
167
449
  if (node === null) {
@@ -189,16 +471,42 @@ export class EventRouter {
189
471
  static dispatchSelectionChanged(handle: u64, start: u32, end: u32): void {
190
472
  const node = this.resolveNode(handle);
191
473
  if (node === null) {
474
+ SelectionHandleAdornerManager.clear();
475
+ MobileTextSelectionToolbarManager.clear();
192
476
  return;
193
477
  }
478
+ let chromeHandle = handle;
479
+ let chromeNode = node;
480
+ if (node instanceof TextInputCore) {
481
+ const editor = changetype<TextInputCore>(node).editorNode;
482
+ chromeHandle = editor.builtHandle;
483
+ chromeNode = editor;
484
+ }
485
+ SelectionHandleAdornerManager.handleSelectionChanged(chromeHandle, start, end);
486
+ MobileTextSelectionToolbarManager.handleSelectionChanged(
487
+ chromeHandle,
488
+ changetype<Node>(chromeNode),
489
+ start,
490
+ end,
491
+ SelectionHandleAdornerManager.isVisible(),
492
+ );
194
493
  node._handleSelectionChanged(start, end);
195
494
  }
196
495
 
197
496
  static dispatchCrossSelectionChanged(handle: u64, text: string): void {
198
497
  const node = this.resolveNode(handle);
199
498
  if (node === null) {
499
+ SelectionHandleAdornerManager.clear();
500
+ MobileTextSelectionToolbarManager.clear();
200
501
  return;
201
502
  }
503
+ SelectionHandleAdornerManager.handleCrossSelectionChanged(handle, text);
504
+ MobileTextSelectionToolbarManager.handleCrossSelectionChanged(
505
+ handle,
506
+ changetype<Node>(node),
507
+ text,
508
+ SelectionHandleAdornerManager.isVisible(),
509
+ );
202
510
  node._handleCrossSelectionChanged(text);
203
511
  }
204
512
 
@@ -331,6 +639,18 @@ export class EventRouter {
331
639
  return this.nodes.get(index);
332
640
  }
333
641
 
642
+ private static preservesSelectionOnPointerDownForRouting(node: Node | null): bool {
643
+ let current = node;
644
+ while (current !== null) {
645
+ const value = changetype<Node>(current);
646
+ if (value.preservesSelectionOnPointerDownForRouting) {
647
+ return true;
648
+ }
649
+ current = value.parentNode;
650
+ }
651
+ return false;
652
+ }
653
+
334
654
  private static pushHover(node: Node): void {
335
655
  const existingIndex = this.indexOfHoveredNode(node);
336
656
  if (existingIndex >= 0) {
package/src/core/Fetch.ts CHANGED
@@ -65,13 +65,21 @@ export class FetchResponse {
65
65
  }
66
66
  }
67
67
 
68
+ export class FetchErrorEventArgs {
69
+ readonly message: string;
70
+
71
+ constructor(message: string) {
72
+ this.message = message;
73
+ }
74
+ }
75
+
68
76
  export class FetchRequest implements Disposable {
69
77
  private urlValue: string;
70
78
  private methodValue: string = "GET";
71
79
  private headerParts: Array<string> = new Array<string>();
72
80
  private bodyBytesValue: Uint8Array | null = null;
73
81
  private completeBinding: Callback1<FetchResponse> | null = null;
74
- private errorBinding: Callback1<string> | null = null;
82
+ private errorBinding: Callback1<FetchErrorEventArgs> | null = null;
75
83
  private requestId: u32 = 0;
76
84
  private started: bool = false;
77
85
  private finished: bool = false;
@@ -128,15 +136,15 @@ export class FetchRequest implements Disposable {
128
136
  return this.onComplete<Owner>(owner, handler);
129
137
  }
130
138
 
131
- onError<Owner>(owner: Owner, handler: Handler1<Owner, string>): this {
139
+ onError<Owner>(owner: Owner, handler: Handler1<Owner, FetchErrorEventArgs>): this {
132
140
  if (changetype<usize>(handler) == 0) {
133
141
  throwNullArgument("FetchRequest.onError", "handler");
134
142
  }
135
- this.errorBinding = bind1<Owner, string>(owner, handler);
143
+ this.errorBinding = bind1<Owner, FetchErrorEventArgs>(owner, handler);
136
144
  return this;
137
145
  }
138
146
 
139
- onErrorWith<Owner>(owner: Owner, handler: Handler1<Owner, string>): this {
147
+ onErrorWith<Owner>(owner: Owner, handler: Handler1<Owner, FetchErrorEventArgs>): this {
140
148
  return this.onError<Owner>(owner, handler);
141
149
  }
142
150
 
@@ -147,7 +155,7 @@ export class FetchRequest implements Disposable {
147
155
  if (this.urlValue.length == 0) {
148
156
  const binding = this.errorBinding;
149
157
  if (binding !== null) {
150
- binding.invoke("FetchRequest.start: url must not be empty.");
158
+ binding.invoke(new FetchErrorEventArgs("FetchRequest.start: url must not be empty."));
151
159
  }
152
160
  return this;
153
161
  }
@@ -215,7 +223,7 @@ export class FetchRequest implements Disposable {
215
223
  const binding = this.errorBinding;
216
224
  this.finish();
217
225
  if (binding !== null) {
218
- binding.invoke(message);
226
+ binding.invoke(new FetchErrorEventArgs(message));
219
227
  }
220
228
  }
221
229
  }
@@ -258,7 +266,7 @@ export function disposeAllFetchRequests(): void {
258
266
  }
259
267
  }
260
268
 
261
- export function __resetFetchForTests(): void {
269
+ export function resetFetchRuntime(): void {
262
270
  disposeAllFetchRequests();
263
271
  nextFetchRequestId = 1;
264
272
  }
@@ -1,15 +1 @@
1
- @external("fui_fetch_host", "fui_fetch_start")
2
- export declare function fui_fetch_start(
3
- requestId: u32,
4
- methodPtr: usize,
5
- methodLen: u32,
6
- urlPtr: usize,
7
- urlLen: u32,
8
- headersPtr: usize,
9
- headersLen: u32,
10
- bodyPtr: usize,
11
- bodyLen: u32,
12
- ): void;
13
-
14
- @external("fui_fetch_host", "fui_fetch_cancel")
15
- export declare function fui_fetch_cancel(requestId: u32): void;
1
+ export { fui_fetch_cancel, fui_fetch_start } from "./generated/FetchHostAbi";