@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,415 @@
1
+ import { HandlerAction } from "../core/Action";
2
+ import { AnimationTiming } from "../core/Animation";
3
+ import { Disposable, disposeAll } from "../core/Disposable";
4
+ import { HandleValue, Orientation, Unit } from "../core/ffi";
5
+ import { Node } from "../core/Node";
6
+ import { throwNullArgument } from "../core/Errors";
7
+ import {
8
+ canRestorePersistedScrollOffset,
9
+ clampPersistedScrollOffset,
10
+ storePersistedScrollOffset,
11
+ tryLoadPersistedScrollOffset,
12
+ } from "../core/PersistedUiState";
13
+ import { FlexBox } from "./FlexBox";
14
+ import { Row } from "./helpers";
15
+ import { ScrollBar, ScrollBarVisibility } from "./ScrollBar";
16
+ import { ScrollState } from "./ScrollState";
17
+ import { ScrollView } from "./ScrollView";
18
+ import { NodeTransitions } from "../core/Transitions";
19
+
20
+ const DEFAULT_SCROLLBAR_GUTTER: f32 = 6.0;
21
+ const OVERFLOW_TOLERANCE: f32 = 0.5;
22
+
23
+ function noopPointerCallback(_x: f32, _y: f32): void {}
24
+
25
+ export class ScrollBox extends FlexBox {
26
+ private readonly scrollStateValue: ScrollState;
27
+ private readonly viewportValue: ScrollView;
28
+ private readonly topRowValue: FlexBox;
29
+ private readonly bottomRowValue: FlexBox;
30
+ private readonly verticalGutterValue: FlexBox;
31
+ private readonly cornerValue: FlexBox;
32
+ private readonly verticalScrollBarValue: ScrollBar;
33
+ private readonly horizontalScrollBarValue: ScrollBar;
34
+ private readonly disposables: Array<Disposable> = new Array<Disposable>();
35
+ private verticalVisibilityValue: ScrollBarVisibility = ScrollBarVisibility.Auto;
36
+ private horizontalVisibilityValue: ScrollBarVisibility = ScrollBarVisibility.Auto;
37
+ private verticalScrollEnabledValue: bool = true;
38
+ private horizontalScrollEnabledValue: bool = true;
39
+ private scrollbarGutterValue: f32 = DEFAULT_SCROLLBAR_GUTTER;
40
+ private verticalChromeVisibleValue: bool = false;
41
+ private horizontalChromeVisibleValue: bool = false;
42
+ private persistScrollValue: bool = false;
43
+ private persistedScrollRestorePending: bool = false;
44
+
45
+ constructor(scrollState: ScrollState = new ScrollState(), viewportOverride: ScrollView | null = null) {
46
+ super();
47
+ this.scrollStateValue = scrollState;
48
+
49
+ const viewportValue = (viewportOverride === null ? new ScrollView() : viewportOverride)
50
+ .bindScrollState(scrollState)
51
+ .showScrollbars(false)
52
+ .width(0.0, Unit.Pixel)
53
+ .height(100.0, Unit.Percent)
54
+ .flexGrow(1.0);
55
+ const verticalGutterValue = new FlexBox()
56
+ .width(DEFAULT_SCROLLBAR_GUTTER, Unit.Pixel)
57
+ .height(100.0, Unit.Percent)
58
+ .onPointerDown(noopPointerCallback) as FlexBox;
59
+ const verticalScrollBarValue = new ScrollBar(scrollState, Orientation.Vertical);
60
+ const cornerValue = new FlexBox()
61
+ .width(0.0, Unit.Pixel)
62
+ .height(0.0, Unit.Pixel)
63
+ .onPointerDown(noopPointerCallback) as FlexBox;
64
+ const horizontalScrollBarValue = new ScrollBar(scrollState, Orientation.Horizontal);
65
+ const topRowValue = Row(
66
+ viewportValue,
67
+ verticalGutterValue,
68
+ verticalScrollBarValue.render(),
69
+ );
70
+ topRowValue.onPointerDown(noopPointerCallback);
71
+ topRowValue.width(100.0, Unit.Percent).height(0.0, Unit.Pixel).flexGrow(1.0);
72
+ const bottomRowValue = Row(
73
+ horizontalScrollBarValue.render(),
74
+ cornerValue,
75
+ );
76
+ bottomRowValue.onPointerDown(noopPointerCallback);
77
+ bottomRowValue.width(100.0, Unit.Percent).height(0.0, Unit.Pixel);
78
+
79
+ this.viewportValue = viewportValue;
80
+ this.topRowValue = topRowValue;
81
+ this.bottomRowValue = bottomRowValue;
82
+ this.verticalGutterValue = verticalGutterValue;
83
+ this.cornerValue = cornerValue;
84
+ this.verticalScrollBarValue = verticalScrollBarValue;
85
+ this.horizontalScrollBarValue = horizontalScrollBarValue;
86
+
87
+ super.child(topRowValue);
88
+ super.child(bottomRowValue);
89
+ this.attachListeners();
90
+ this.refreshChrome();
91
+ }
92
+
93
+ get scrollState(): ScrollState {
94
+ return this.scrollStateValue;
95
+ }
96
+
97
+ get viewport(): ScrollView {
98
+ return this.viewportValue;
99
+ }
100
+
101
+ get verticalScrollBar(): ScrollBar {
102
+ return this.verticalScrollBarValue;
103
+ }
104
+
105
+ get horizontalScrollBar(): ScrollBar {
106
+ return this.horizontalScrollBarValue;
107
+ }
108
+
109
+ nodeId(id: string): this {
110
+ super.nodeId(id);
111
+ return this;
112
+ }
113
+
114
+ child(node: Node): this {
115
+ if (node == null) {
116
+ throwNullArgument("ScrollBox.child", "node");
117
+ }
118
+ this.clearContentScrollProxyTargets();
119
+ this.viewportValue.child(node);
120
+ this.bindContentScrollProxyTargets();
121
+ return this;
122
+ }
123
+
124
+ children(nodes: Array<Node>): this {
125
+ this.clearContentScrollProxyTargets();
126
+ this.viewportValue.children(nodes);
127
+ this.bindContentScrollProxyTargets();
128
+ return this;
129
+ }
130
+
131
+ scrollEnabledX(flag: bool): this {
132
+ this.horizontalScrollEnabledValue = flag;
133
+ this.viewportValue.scrollEnabledX(flag);
134
+ this.refreshChrome();
135
+ return this;
136
+ }
137
+
138
+ scrollEnabledY(flag: bool): this {
139
+ this.verticalScrollEnabledValue = flag;
140
+ this.viewportValue.scrollEnabledY(flag);
141
+ this.refreshChrome();
142
+ return this;
143
+ }
144
+
145
+ persistScroll(flag: bool = true): this {
146
+ this.persistScrollValue = flag;
147
+ if (!flag) {
148
+ this.persistedScrollRestorePending = false;
149
+ }
150
+ return this;
151
+ }
152
+
153
+ scrollOffset(x: f32, y: f32): this {
154
+ this.viewportValue.scrollOffset(x, y);
155
+ return this;
156
+ }
157
+
158
+ scrollContentSize(contentWidth: f32 = -1.0, contentHeight: f32 = -1.0): this {
159
+ this.viewportValue.scrollContentSize(contentWidth, contentHeight);
160
+ return this;
161
+ }
162
+
163
+ scrollTo(x: f32, y: f32): this {
164
+ this.viewportValue.scrollTo(x, y);
165
+ return this;
166
+ }
167
+
168
+ scrollToAnimated(x: f32, y: f32, timing: AnimationTiming): this {
169
+ this.viewportValue.scrollToAnimated(x, y, timing);
170
+ return this;
171
+ }
172
+
173
+ transitions(transitions: NodeTransitions | null): this {
174
+ this.viewportValue.transitions(transitions);
175
+ return this;
176
+ }
177
+
178
+ setRuntimeScrollOffset(x: f32, y: f32): void {
179
+ this.viewportValue.setRuntimeScrollOffset(x, y);
180
+ }
181
+
182
+ verticalScrollbarVisibility(mode: ScrollBarVisibility): this {
183
+ this.verticalVisibilityValue = mode;
184
+ this.refreshChrome();
185
+ return this;
186
+ }
187
+
188
+ horizontalScrollbarVisibility(mode: ScrollBarVisibility): this {
189
+ this.horizontalVisibilityValue = mode;
190
+ this.refreshChrome();
191
+ return this;
192
+ }
193
+
194
+ scrollbarGutter(value: f32): this {
195
+ this.scrollbarGutterValue = value > 0.0 ? value : 0.0;
196
+ this.refreshChrome();
197
+ return this;
198
+ }
199
+
200
+ build(): u64 {
201
+ const handle = super.build();
202
+ this.bindScrollChrome();
203
+ this.refreshChrome();
204
+ return handle;
205
+ }
206
+
207
+ private disposeControl(): void {
208
+ this.verticalScrollBarValue.dispose();
209
+ this.horizontalScrollBarValue.dispose();
210
+ disposeAll(this.disposables);
211
+ }
212
+
213
+ dispose(): void {
214
+ const viewportHandle = this.viewportValue.builtHandle;
215
+ this.verticalScrollBarValue.clearScrollHandle(viewportHandle);
216
+ this.horizontalScrollBarValue.clearScrollHandle(viewportHandle);
217
+ this._bindScrollProxyTarget(0);
218
+ this.topRowValue._bindScrollProxyTarget(0);
219
+ this.bottomRowValue._bindScrollProxyTarget(0);
220
+ this.verticalGutterValue._bindScrollProxyTarget(0);
221
+ this.cornerValue._bindScrollProxyTarget(0);
222
+ this.clearContentScrollProxyTargets();
223
+ this.disposeControl();
224
+ super.dispose();
225
+ }
226
+
227
+ private attachListeners(): void {
228
+ this.track(this.scrollStateValue.contentWidth.addAction(new HandlerAction<ScrollBox, f32>(this, (scrollBox: ScrollBox, _value: f32): void => {
229
+ scrollBox.refreshChrome();
230
+ scrollBox.tryRestorePersistedScrollOffset();
231
+ })));
232
+ this.track(this.scrollStateValue.contentHeight.addAction(new HandlerAction<ScrollBox, f32>(this, (scrollBox: ScrollBox, _value: f32): void => {
233
+ scrollBox.refreshChrome();
234
+ scrollBox.tryRestorePersistedScrollOffset();
235
+ })));
236
+ this.track(this.scrollStateValue.viewportWidth.addAction(new HandlerAction<ScrollBox, f32>(this, (scrollBox: ScrollBox, _value: f32): void => {
237
+ scrollBox.refreshChrome();
238
+ scrollBox.tryRestorePersistedScrollOffset();
239
+ })));
240
+ this.track(this.scrollStateValue.viewportHeight.addAction(new HandlerAction<ScrollBox, f32>(this, (scrollBox: ScrollBox, _value: f32): void => {
241
+ scrollBox.refreshChrome();
242
+ scrollBox.tryRestorePersistedScrollOffset();
243
+ })));
244
+ this.track(this.verticalScrollBarValue.chromeMetricVersion.addAction(new HandlerAction<ScrollBox, i32>(this, (scrollBox: ScrollBox, _value: i32): void => {
245
+ scrollBox.refreshChrome();
246
+ })));
247
+ this.track(this.horizontalScrollBarValue.chromeMetricVersion.addAction(new HandlerAction<ScrollBox, i32>(this, (scrollBox: ScrollBox, _value: i32): void => {
248
+ scrollBox.refreshChrome();
249
+ })));
250
+ this.track(this.scrollStateValue.offsetX.addAction(new HandlerAction<ScrollBox, f32>(this, (scrollBox: ScrollBox, _value: f32): void => {
251
+ scrollBox.tryRestorePersistedScrollOffset();
252
+ })));
253
+ this.track(this.scrollStateValue.offsetY.addAction(new HandlerAction<ScrollBox, f32>(this, (scrollBox: ScrollBox, _value: f32): void => {
254
+ scrollBox.tryRestorePersistedScrollOffset();
255
+ })));
256
+ }
257
+
258
+ private track(disposable: Disposable): void {
259
+ this.disposables.push(disposable);
260
+ }
261
+
262
+ private bindScrollChrome(): void {
263
+ const viewportHandle = this.viewportValue.builtHandle;
264
+ this.verticalScrollBarValue.bindScrollHandle(viewportHandle);
265
+ this.horizontalScrollBarValue.bindScrollHandle(viewportHandle);
266
+ this._bindScrollProxyTarget(viewportHandle);
267
+ this.topRowValue._bindScrollProxyTarget(viewportHandle);
268
+ this.bottomRowValue._bindScrollProxyTarget(viewportHandle);
269
+ this.verticalGutterValue._bindScrollProxyTarget(viewportHandle);
270
+ this.cornerValue._bindScrollProxyTarget(viewportHandle);
271
+ this.bindContentScrollProxyTargets();
272
+ }
273
+
274
+ private bindContentScrollProxyTargets(): void {
275
+ const viewportHandle = this.viewportValue.builtHandle;
276
+ if (viewportHandle == <u64>HandleValue.Invalid) {
277
+ return;
278
+ }
279
+ for (let index = 0; index < this.viewportValue.childCount; index += 1) {
280
+ const child = this.viewportValue.getChildAt(index);
281
+ if (child !== null) {
282
+ child._bindScrollProxyTarget(viewportHandle);
283
+ }
284
+ }
285
+ }
286
+
287
+ private clearContentScrollProxyTargets(): void {
288
+ for (let index = 0; index < this.viewportValue.childCount; index += 1) {
289
+ const child = this.viewportValue.getChildAt(index);
290
+ if (child !== null) {
291
+ child._bindScrollProxyTarget(<u64>HandleValue.Invalid);
292
+ }
293
+ }
294
+ }
295
+
296
+ private refreshChrome(): void {
297
+ const verticalRailThickness = this.scrollbarGutterValue + this.verticalScrollBarValue.thickness;
298
+ const horizontalRailThickness = this.horizontalScrollBarValue.thickness;
299
+ const outerViewportWidth = this.scrollStateValue.viewportWidth.value + (this.verticalChromeVisibleValue ? verticalRailThickness : 0.0);
300
+ const outerViewportHeight = this.scrollStateValue.viewportHeight.value + (this.horizontalChromeVisibleValue ? horizontalRailThickness : 0.0);
301
+ let showVertical = this.verticalChromeVisibleValue;
302
+ let showHorizontal = this.horizontalChromeVisibleValue;
303
+ for (let pass = 0; pass < 3; pass += 1) {
304
+ const availableWidth = outerViewportWidth - (showVertical ? verticalRailThickness : 0.0);
305
+ const availableHeight = outerViewportHeight - (showHorizontal ? horizontalRailThickness : 0.0);
306
+ const nextVertical = this.shouldShow(
307
+ this.verticalVisibilityValue,
308
+ this.verticalScrollEnabledValue,
309
+ this.scrollStateValue.contentHeight.value,
310
+ availableHeight,
311
+ );
312
+ const nextHorizontal = this.shouldShow(
313
+ this.horizontalVisibilityValue,
314
+ this.horizontalScrollEnabledValue,
315
+ this.scrollStateValue.contentWidth.value,
316
+ availableWidth,
317
+ );
318
+ if (nextVertical == showVertical && nextHorizontal == showHorizontal) {
319
+ break;
320
+ }
321
+ showVertical = nextVertical;
322
+ showHorizontal = nextHorizontal;
323
+ }
324
+ this.verticalChromeVisibleValue = showVertical;
325
+ this.horizontalChromeVisibleValue = showHorizontal;
326
+ this.verticalScrollBarValue.chromeVisible(showVertical);
327
+ this.horizontalScrollBarValue.chromeVisible(showHorizontal);
328
+ const verticalRailWidth = showVertical ? verticalRailThickness : 0.0;
329
+ const horizontalRailHeight = showHorizontal ? horizontalRailThickness : 0.0;
330
+
331
+ this.verticalGutterValue.width(showVertical ? this.scrollbarGutterValue : 0.0, Unit.Pixel);
332
+ this.verticalScrollBarValue.render().width(
333
+ showVertical ? this.verticalScrollBarValue.thickness : 0.0,
334
+ Unit.Pixel,
335
+ );
336
+ this.bottomRowValue.height(horizontalRailHeight, Unit.Pixel);
337
+ this.horizontalScrollBarValue.render().height(showHorizontal ? this.horizontalScrollBarValue.thickness : 0.0, Unit.Pixel);
338
+ this.cornerValue.width(showVertical ? verticalRailWidth : 0.0, Unit.Pixel);
339
+ this.cornerValue.height(showHorizontal ? horizontalRailHeight : 0.0, Unit.Pixel);
340
+ }
341
+
342
+ private shouldShow(mode: ScrollBarVisibility, enabled: bool, contentSize: f32, viewportSize: f32): bool {
343
+ if (!enabled || mode == ScrollBarVisibility.Never) {
344
+ return false;
345
+ }
346
+ if (mode == ScrollBarVisibility.Always) {
347
+ return true;
348
+ }
349
+ if (viewportSize <= 0.0 || contentSize <= 0.0) {
350
+ return false;
351
+ }
352
+ return contentSize > viewportSize + OVERFLOW_TOLERANCE;
353
+ }
354
+
355
+ protected capturePersistedState(): void {
356
+ super.capturePersistedState();
357
+ if (!this.persistScrollValue) {
358
+ return;
359
+ }
360
+ this.storePersistedScrollOffset(this.scrollStateValue.offsetX.value, this.scrollStateValue.offsetY.value);
361
+ }
362
+
363
+ protected restorePersistedState(): void {
364
+ super.restorePersistedState();
365
+ if (!this.persistScrollValue) {
366
+ return;
367
+ }
368
+ this.persistedScrollRestorePending = true;
369
+ this.tryRestorePersistedScrollOffset();
370
+ }
371
+
372
+ private tryRestorePersistedScrollOffset(): bool {
373
+ if (!this.persistedScrollRestorePending || !this.persistScrollValue) {
374
+ return false;
375
+ }
376
+ const nodeId = this.getNodeId();
377
+ if (nodeId === null || nodeId.length == 0) {
378
+ this.persistedScrollRestorePending = false;
379
+ return false;
380
+ }
381
+ const restored = tryLoadPersistedScrollOffset(nodeId);
382
+ if (restored === null) {
383
+ this.persistedScrollRestorePending = false;
384
+ return false;
385
+ }
386
+ if (!canRestorePersistedScrollOffset(
387
+ this.scrollStateValue,
388
+ restored,
389
+ this.horizontalScrollEnabledValue,
390
+ this.verticalScrollEnabledValue,
391
+ )) {
392
+ return false;
393
+ }
394
+ this.persistedScrollRestorePending = false;
395
+ const clamped = clampPersistedScrollOffset(
396
+ this.scrollStateValue,
397
+ restored,
398
+ this.horizontalScrollEnabledValue,
399
+ this.verticalScrollEnabledValue,
400
+ );
401
+ this.setRuntimeScrollOffset(clamped.x, clamped.y);
402
+ return true;
403
+ }
404
+
405
+ private storePersistedScrollOffset(x: f32, y: f32): void {
406
+ if (!this.persistScrollValue) {
407
+ return;
408
+ }
409
+ const nodeId = this.getNodeId();
410
+ if (nodeId === null || nodeId.length == 0) {
411
+ return;
412
+ }
413
+ storePersistedScrollOffset(nodeId, x, y);
414
+ }
415
+ }
@@ -0,0 +1,10 @@
1
+ import { Signal } from "../core/Signal";
2
+
3
+ export class ScrollState {
4
+ readonly offsetX: Signal<f32> = new Signal<f32>(0.0);
5
+ readonly offsetY: Signal<f32> = new Signal<f32>(0.0);
6
+ readonly contentWidth: Signal<f32> = new Signal<f32>(0.0);
7
+ readonly contentHeight: Signal<f32> = new Signal<f32>(0.0);
8
+ readonly viewportWidth: Signal<f32> = new Signal<f32>(0.0);
9
+ readonly viewportHeight: Signal<f32> = new Signal<f32>(0.0);
10
+ }