@effindomv2/fui-as 0.2.5-alpha1 → 0.2.6-alpha1

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.2.5-alpha1",
3
+ "version": "0.2.6-alpha1",
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",
@@ -106,7 +106,7 @@
106
106
  "typecheck": "npm run guard:runtime-dependency && npm run check:abi && tsc -p tsconfig.json --noEmit"
107
107
  },
108
108
  "dependencies": {
109
- "@effindomv2/runtime": "0.2.13"
109
+ "@effindomv2/runtime": "0.2.14"
110
110
  },
111
111
  "devDependencies": {
112
112
  "@as-pect/assembly": "9.0.0",
package/src/Fui.ts CHANGED
@@ -113,7 +113,7 @@ export {
113
113
  } from "./core/Node";
114
114
  export { DragCompletedEvent, DragDeltaEvent, DragGesture, DragGestureHost, DragStartedEvent } from "./core/DragGesture";
115
115
  export { ContextMenuManager } from "./core/ContextMenuManager";
116
- export { NavigateEventArgs } from "./controls/NavLink";
116
+ export { NavigateEventArgs, NavLinkInteractionState } from "./controls/NavLink";
117
117
  export {
118
118
  AlignSelf,
119
119
  AlignItems,
@@ -8,14 +8,16 @@ import {
8
8
  fui_show_url_preview,
9
9
  } from "../core/ffi";
10
10
  import { HandlerAction } from "../core/Action";
11
+ import { Callback2, Handler2 } from "../core/Callbacks";
11
12
  import { Disposable, disposeAll } from "../core/Disposable";
12
13
  import { FocusAdornerManager } from "../core/FocusAdornerManager";
13
14
  import { keyboardFocusVisible } from "../core/FocusVisibility";
15
+ import { bind2 } from "../core/bind";
14
16
  import { navigateTo } from "../core/Navigation";
15
17
  import { PointerButton, PointerEventArgs, PointerType } from "../core/Node";
16
18
  import { hasPrimaryShortcutModifier } from "../core/Platform";
17
19
  import { Theme, activeTheme } from "../core/Theme";
18
- import { FlexBox, Text } from "../nodes";
20
+ import { FlexBox } from "../nodes";
19
21
 
20
22
  export class NavigateEventArgs {
21
23
  readonly path: string;
@@ -25,6 +27,15 @@ export class NavigateEventArgs {
25
27
  }
26
28
  }
27
29
 
30
+ export class NavLinkInteractionState {
31
+ constructor(
32
+ readonly hovered: bool,
33
+ readonly pressed: bool,
34
+ readonly focused: bool,
35
+ readonly enabled: bool,
36
+ ) {}
37
+ }
38
+
28
39
  export class NavLink extends FlexBox {
29
40
  private static activePreviewOwner: NavLink | null = null;
30
41
  private hrefValue: string;
@@ -40,29 +51,19 @@ export class NavLink extends FlexBox {
40
51
  private previewVisible: bool = false;
41
52
  private previewPinnedForContextMenu: bool = false;
42
53
  private disposed: bool = false;
43
- private textColorValue: u32;
44
- readonly labelNode: Text;
54
+ private interactionStateCallback: ((state: NavLinkInteractionState, theme: Theme) => void) | null = null;
55
+ private interactionStateBinding: Callback2<NavLinkInteractionState, Theme> | null = null;
45
56
 
46
- constructor(href: string, label: string = href, openInNewTab: bool = false) {
57
+ constructor(href: string, openInNewTab: bool = false) {
47
58
  super();
48
- const theme = activeTheme.value;
49
59
  this.hrefValue = href;
50
60
  this.openInNewTabValue = openInNewTab;
51
- this.textColorValue = theme.colors.accent;
52
- this.labelNode = new Text(label)
53
- .fontFamily(theme.fonts.bodyFamily)
54
- .fontSize(15.0)
55
- .textColor(theme.colors.accent)
56
- .selectable(false)
57
- .cursor(CursorStyle.Pointer) as Text;
58
61
  this.semanticRole(SemanticRole.Link);
59
- this.semanticLabel(label);
60
62
  this.cursor(CursorStyle.Pointer);
61
63
  this.focusable(true);
62
- this.child(this.labelNode);
63
64
  this.track(activeTheme.addAction(new HandlerAction<NavLink, Theme>(this, (link: NavLink, _theme: Theme): void => {
64
- link.syncVisualState();
65
65
  link.syncFocusChrome();
66
+ link.notifyInteractionState();
66
67
  })));
67
68
  this.track(keyboardFocusVisible.addAction(new HandlerAction<NavLink, bool>(this, (link: NavLink, _visible: bool): void => {
68
69
  link.syncFocusChrome();
@@ -87,15 +88,35 @@ export class NavLink extends FlexBox {
87
88
  return this;
88
89
  }
89
90
 
90
- text(value: string): this {
91
- this.semanticLabel(value);
92
- this.labelNode.text(value);
91
+ onInteractionStateChanged(cb: (state: NavLinkInteractionState, theme: Theme) => void): this {
92
+ this.interactionStateCallback = cb;
93
+ this.interactionStateBinding = null;
94
+ this.notifyInteractionState();
93
95
  return this;
94
96
  }
95
97
 
96
- textColor(color: u32): this {
97
- this.textColorValue = color;
98
- this.syncVisualState();
98
+ bindInteractionState<Owner>(
99
+ owner: Owner,
100
+ handler: Handler2<Owner, NavLinkInteractionState, Theme>,
101
+ ): this {
102
+ this.interactionStateCallback = null;
103
+ this.interactionStateBinding = bind2<Owner, NavLinkInteractionState, Theme>(owner, handler);
104
+ this.notifyInteractionState();
105
+ return this;
106
+ }
107
+
108
+ enabled(flag: bool): this {
109
+ super.enabled(flag);
110
+ if (!flag) {
111
+ this.hovered = false;
112
+ this.focused = false;
113
+ this.pointerPressed = false;
114
+ this.pointerPressedOpenInNewTab = false;
115
+ this.enterPressed = false;
116
+ this.enterPressedOpenInNewTab = false;
117
+ }
118
+ this.syncFocusChrome();
119
+ this.notifyInteractionState();
99
120
  return this;
100
121
  }
101
122
 
@@ -103,6 +124,8 @@ export class NavLink extends FlexBox {
103
124
  this.hidePreview();
104
125
  if (!this.disposed) {
105
126
  this.disposed = true;
127
+ this.interactionStateCallback = null;
128
+ this.interactionStateBinding = null;
106
129
  disposeAll(this.disposables);
107
130
  }
108
131
  super.dispose();
@@ -119,7 +142,7 @@ export class NavLink extends FlexBox {
119
142
  super._handlePointerEvent(eventType, x, y, modifiers);
120
143
  if (eventType == PointerEventType.Enter) {
121
144
  this.hovered = true;
122
- this.syncVisualState();
145
+ this.notifyInteractionState();
123
146
  this.showPreview();
124
147
  return;
125
148
  }
@@ -127,7 +150,7 @@ export class NavLink extends FlexBox {
127
150
  this.hovered = false;
128
151
  this.pointerPressed = false;
129
152
  this.pointerPressedOpenInNewTab = false;
130
- this.syncVisualState();
153
+ this.notifyInteractionState();
131
154
  if (!this.previewPinnedForContextMenu && !this.focused) {
132
155
  this.hidePreview();
133
156
  }
@@ -137,16 +160,19 @@ export class NavLink extends FlexBox {
137
160
  if (!isActivation) {
138
161
  this.pointerPressed = false;
139
162
  this.pointerPressedOpenInNewTab = false;
163
+ this.notifyInteractionState();
140
164
  return;
141
165
  }
142
166
  this.pointerPressed = true;
143
167
  this.pointerPressedOpenInNewTab = isMiddleClick || this.shouldOpenInNewTab(modifiers);
168
+ this.notifyInteractionState();
144
169
  return;
145
170
  }
146
171
  if (eventType == PointerEventType.Up && this.pointerPressed && isActivation) {
147
172
  this.pointerPressed = false;
148
173
  this.activate(isMiddleClick || this.pointerPressedOpenInNewTab || this.shouldOpenInNewTab(modifiers));
149
174
  this.pointerPressedOpenInNewTab = false;
175
+ this.notifyInteractionState();
150
176
  }
151
177
  }
152
178
 
@@ -164,6 +190,7 @@ export class NavLink extends FlexBox {
164
190
  this.hidePreview();
165
191
  }
166
192
  }
193
+ this.notifyInteractionState();
167
194
  }
168
195
 
169
196
  _handleKeyEvent(eventType: KeyEventType, key: string, modifiers: u32): bool {
@@ -177,12 +204,14 @@ export class NavLink extends FlexBox {
177
204
  if (eventType == KeyEventType.Down) {
178
205
  this.enterPressed = true;
179
206
  this.enterPressedOpenInNewTab = this.shouldOpenInNewTab(modifiers);
207
+ this.notifyInteractionState();
180
208
  return true;
181
209
  }
182
210
  if (eventType == KeyEventType.Up && this.enterPressed) {
183
211
  this.enterPressed = false;
184
212
  this.activate(this.enterPressedOpenInNewTab || this.shouldOpenInNewTab(modifiers));
185
213
  this.enterPressedOpenInNewTab = false;
214
+ this.notifyInteractionState();
186
215
  return true;
187
216
  }
188
217
  return callbackHandled;
@@ -261,8 +290,23 @@ export class NavLink extends FlexBox {
261
290
  FocusAdornerManager.hideOwner(this);
262
291
  }
263
292
 
264
- private syncVisualState(): void {
265
- this.labelNode.textColor(this.hovered ? activeTheme.value.colors.accentHovered : this.textColorValue);
293
+ private notifyInteractionState(): void {
294
+ const state = new NavLinkInteractionState(
295
+ this.hovered,
296
+ this.pointerPressed || this.enterPressed,
297
+ this.focused,
298
+ this.isEnabled,
299
+ );
300
+ const theme = activeTheme.value;
301
+ const callback = this.interactionStateCallback;
302
+ if (callback !== null) {
303
+ callback(state, theme);
304
+ return;
305
+ }
306
+ const binding = this.interactionStateBinding;
307
+ if (binding !== null) {
308
+ binding.invoke(state, theme);
309
+ }
266
310
  }
267
311
 
268
312
  private track(disposable: Disposable): void {
@@ -11,7 +11,7 @@ export { ContextMenu, MenuItem } from "./ContextMenu";
11
11
  export { Dialog, DialogShownEventArgs } from "./Dialog";
12
12
  export { Dropdown, DropdownItem } from "./Dropdown";
13
13
  export { Form } from "./Form";
14
- export { NavLink } from "./NavLink";
14
+ export { NavLink, NavLinkInteractionState } from "./NavLink";
15
15
  export { Popup, PopupPlacement } from "./Popup";
16
16
  export { ProgressBar } from "./ProgressBar";
17
17
  export { RadioButton } from "./RadioButton";