@effindomv2/fui-as 0.1.9 → 0.1.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effindomv2/fui-as",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "private": false,
5
5
  "license": "AGPL-3.0-only OR LicenseRef-EffinDom-Commercial",
6
6
  "description": "EffinDom v2 AssemblyScript frontend framework SDK and browser harness",
@@ -78,7 +78,7 @@
78
78
  },
79
79
  "dependencies": {
80
80
  "@assemblyscript/loader": "^0.28.17",
81
- "@effindomv2/runtime": "0.1.2"
81
+ "@effindomv2/runtime": "0.1.4"
82
82
  },
83
83
  "devDependencies": {
84
84
  "@as-pect/assembly": "8.1.0",
@@ -19,7 +19,8 @@ import { Theme, activeTheme } from "../core/Theme";
19
19
  import { warn } from "../core/Logger";
20
20
  import { Node } from "../core/Node";
21
21
  import { PersistedInt32Codec, PersistedValueState } from "../core/PersistedState";
22
- import { FlexBox, Portal, ScrollBarVisibility, ScrollBox } from "../nodes";
22
+ import { registerScrollHook } from "../core/ScrollHooks";
23
+ import { FlexBox, Portal, ScrollBarVisibility, ScrollBox, ScrollView } from "../nodes";
23
24
  import { bind2 } from "../core/bind";
24
25
  import { getControlTemplates } from "./ControlTemplateSet";
25
26
  import {
@@ -179,6 +180,7 @@ class DropdownOptionNode extends FlexBox {
179
180
 
180
181
  export class Dropdown extends FlexBox implements GlobalKeyHandler {
181
182
  private static activeInstance: Dropdown | null = null;
183
+ private static scrollHookRegistered: bool = false;
182
184
 
183
185
  private fieldTemplateValue: DropdownFieldTemplate | null = null;
184
186
  private chevronTemplateValue: DropdownChevronTemplate | null = null;
@@ -212,6 +214,7 @@ export class Dropdown extends FlexBox implements GlobalKeyHandler {
212
214
 
213
215
  constructor() {
214
216
  super();
217
+ Dropdown.ensureScrollHook();
215
218
  const fieldPresenter = createFieldPresenter(null);
216
219
  const chevronPresenter = createChevronPresenter(null);
217
220
  const popupRoot = new Portal()
@@ -394,6 +397,24 @@ export class Dropdown extends FlexBox implements GlobalKeyHandler {
394
397
  }
395
398
  }
396
399
 
400
+ static dismissActiveDropdownIfTriggerOutOfViewport(): void {
401
+ const dropdown = Dropdown.activeInstance;
402
+ if (dropdown === null) {
403
+ return;
404
+ }
405
+ if (!dropdown.isTriggerVisibleInViewport()) {
406
+ dropdown.close();
407
+ }
408
+ }
409
+
410
+ private static ensureScrollHook(): void {
411
+ if (Dropdown.scrollHookRegistered) {
412
+ return;
413
+ }
414
+ registerScrollHook((): void => Dropdown.dismissActiveDropdownIfTriggerOutOfViewport());
415
+ Dropdown.scrollHookRegistered = true;
416
+ }
417
+
397
418
  highlightIndex(index: i32): void {
398
419
  if (index < 0 || index >= this.itemsValue.length || this.highlightedIndexValue == index) {
399
420
  if (index < 0 || index >= this.itemsValue.length) {
@@ -603,6 +624,56 @@ export class Dropdown extends FlexBox implements GlobalKeyHandler {
603
624
  return ui.tryGetBounds(this.builtHandle);
604
625
  }
605
626
 
627
+ private findContainingScrollView(): ScrollView | null {
628
+ let current: Node | null = this.parentNode;
629
+ while (current !== null) {
630
+ if (current instanceof ScrollView) {
631
+ return current as ScrollView;
632
+ }
633
+ current = current.parentNode;
634
+ }
635
+ return null;
636
+ }
637
+
638
+ private isTriggerVisibleInViewport(): bool {
639
+ const bounds = this.tryGetViewportBounds();
640
+ if (bounds === null) {
641
+ return true;
642
+ }
643
+ const x = unchecked(bounds[0]);
644
+ const y = unchecked(bounds[1]);
645
+ const width = unchecked(bounds[2]);
646
+ const height = unchecked(bounds[3]);
647
+ if (width <= 0.0 || height <= 0.0) {
648
+ return true;
649
+ }
650
+ const right = x + width;
651
+ const bottom = y + height;
652
+
653
+ const scrollView = this.findContainingScrollView();
654
+ if (scrollView === null) {
655
+ const viewportWidth = ui.getViewportWidth();
656
+ const viewportHeight = ui.getViewportHeight();
657
+ return right > 0.0 && bottom > 0.0 && x < viewportWidth && y < viewportHeight;
658
+ }
659
+
660
+ const scrollViewBounds = ui.tryGetBounds(scrollView.builtHandle);
661
+ if (scrollViewBounds === null) {
662
+ const viewportWidth = ui.getViewportWidth();
663
+ const viewportHeight = ui.getViewportHeight();
664
+ return right > 0.0 && bottom > 0.0 && x < viewportWidth && y < viewportHeight;
665
+ }
666
+
667
+ const svX = unchecked(scrollViewBounds[0]);
668
+ const svY = unchecked(scrollViewBounds[1]);
669
+ const svWidth = unchecked(scrollViewBounds[2]);
670
+ const svHeight = unchecked(scrollViewBounds[3]);
671
+ const svRight = svX + svWidth;
672
+ const svBottom = svY + svHeight;
673
+
674
+ return right > svX && bottom > svY && x < svRight && y < svBottom;
675
+ }
676
+
606
677
  private positionPanel(triggerX: f32, triggerY: f32, triggerWidth: f32, triggerHeight: f32): void {
607
678
  const popupWidth = this.resolvePopupWidth(triggerWidth);
608
679
  const panelHeight = this.resolveViewportClampedPanelOuterHeight();
@@ -15,6 +15,7 @@ import { DragDropEffects, DragSession, ExternalDropItemInfo, Node } from "./Node
15
15
  import { DragDropManager } from "./DragDropManager";
16
16
  import { ExternalDragEventType, ExternalDropManager } from "./ExternalDropManager";
17
17
  import { isCoarsePointer } from "./Platform";
18
+ import { runScrollHooks } from "./ScrollHooks";
18
19
 
19
20
  export interface GlobalKeyHandler {
20
21
  handleGlobalKeyEvent(eventType: KeyEventType, key: string, modifiers: u32): bool;
@@ -161,6 +162,7 @@ export class EventRouter {
161
162
  viewportHeight: f32,
162
163
  ): void {
163
164
  ToolTipManager.handleScroll();
165
+ runScrollHooks();
164
166
  const node = this.resolveNode(handle);
165
167
  if (node === null) {
166
168
  return;
@@ -2,7 +2,7 @@ import * as ui from "../bindings/ui";
2
2
  import { BorderStyle, Unit } from "./ffi";
3
3
  import { Node } from "./Node";
4
4
  import { activeTheme } from "./Theme";
5
- import { Portal, ScrollView, FlexBox } from "../nodes";
5
+ import { Portal, FlexBox } from "../nodes";
6
6
 
7
7
  const STANDARD_FOCUS_RING_WIDTH: f32 = 2.0;
8
8
  const STANDARD_FOCUS_RING_OUTSET: f32 = 2.0;
@@ -59,7 +59,7 @@ export class FocusAdornerManager {
59
59
  .position(0.0, 0.0)
60
60
  .width(0.0, Unit.Pixel)
61
61
  .height(0.0, Unit.Pixel)
62
- .clipToBounds(true) as Portal;
62
+ .clipToBounds(false) as Portal;
63
63
  this.hostRoot = hostRoot;
64
64
  this.ringNode = ringNode;
65
65
  return hostRoot;
@@ -239,20 +239,6 @@ export class FocusAdornerManager {
239
239
  maxX = <f32>Math.min(maxX, ui.getViewportWidth());
240
240
  maxY = <f32>Math.min(maxY, ui.getViewportHeight());
241
241
 
242
- let ancestor = owner.parentNode;
243
- while (ancestor !== null) {
244
- if (ancestor instanceof ScrollView && ancestor.builtHandle != 0) {
245
- const viewportBounds = ui.tryGetBounds(ancestor.builtHandle);
246
- if (viewportBounds !== null) {
247
- minX = <f32>Math.max(minX, unchecked(viewportBounds[0]));
248
- minY = <f32>Math.max(minY, unchecked(viewportBounds[1]));
249
- maxX = <f32>Math.min(maxX, unchecked(viewportBounds[0]) + unchecked(viewportBounds[2]));
250
- maxY = <f32>Math.min(maxY, unchecked(viewportBounds[1]) + unchecked(viewportBounds[3]));
251
- }
252
- }
253
- ancestor = ancestor.parentNode;
254
- }
255
-
256
242
  const width = maxX - minX;
257
243
  const height = maxY - minY;
258
244
  if (width <= 0.0 || height <= 0.0) {
@@ -0,0 +1,13 @@
1
+ type ScrollHook = () => void;
2
+
3
+ const hooks: Array<ScrollHook> = new Array<ScrollHook>();
4
+
5
+ export function registerScrollHook(hook: ScrollHook): void {
6
+ hooks.push(hook);
7
+ }
8
+
9
+ export function runScrollHooks(): void {
10
+ for (let index = 0; index < hooks.length; ++index) {
11
+ unchecked(hooks[index])();
12
+ }
13
+ }