@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.
|
|
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.
|
|
81
|
+
"@effindomv2/runtime": "0.1.4"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@as-pect/assembly": "8.1.0",
|
package/src/controls/Dropdown.ts
CHANGED
|
@@ -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 {
|
|
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();
|
package/src/core/EventRouter.ts
CHANGED
|
@@ -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,
|
|
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(
|
|
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
|
+
}
|