drawnui-react 0.1.0-preview.2 → 0.1.0-preview.21

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 (87) hide show
  1. package/README.md +17 -4
  2. package/SKIPPED.md +33 -27
  3. package/dist/controls/AnimatedFramesRenderer.d.ts +7 -0
  4. package/dist/controls/AnimatedFramesRenderer.js +16 -1
  5. package/dist/controls/DrawnGame.d.ts +40 -0
  6. package/dist/controls/DrawnGame.js +64 -0
  7. package/dist/controls/GridStructure.d.ts +16 -2
  8. package/dist/controls/GridStructure.js +40 -4
  9. package/dist/controls/SkiaBackdrop.d.ts +8 -2
  10. package/dist/controls/SkiaBackdrop.js +48 -8
  11. package/dist/controls/SkiaButton.d.ts +19 -2
  12. package/dist/controls/SkiaButton.js +41 -11
  13. package/dist/controls/SkiaCarousel.d.ts +9 -1
  14. package/dist/controls/SkiaCarousel.js +16 -3
  15. package/dist/controls/SkiaCheckbox.d.ts +0 -1
  16. package/dist/controls/SkiaCheckbox.js +0 -6
  17. package/dist/controls/SkiaDrawer.d.ts +2 -0
  18. package/dist/controls/SkiaDrawer.js +2 -0
  19. package/dist/controls/SkiaEditor.d.ts +12 -1
  20. package/dist/controls/SkiaEditor.js +46 -19
  21. package/dist/controls/SkiaGif.d.ts +3 -0
  22. package/dist/controls/SkiaGif.js +12 -2
  23. package/dist/controls/SkiaImage.js +15 -10
  24. package/dist/controls/SkiaLabel.d.ts +54 -3
  25. package/dist/controls/SkiaLabel.js +235 -52
  26. package/dist/controls/SkiaLabelFps.d.ts +16 -0
  27. package/dist/controls/SkiaLabelFps.js +41 -0
  28. package/dist/controls/SkiaLayout.d.ts +64 -7
  29. package/dist/controls/SkiaLayout.js +316 -19
  30. package/dist/controls/SkiaLottie.js +4 -2
  31. package/dist/controls/SkiaProgress.d.ts +2 -1
  32. package/dist/controls/SkiaProgress.js +6 -3
  33. package/dist/controls/SkiaRadioButton.js +4 -3
  34. package/dist/controls/SkiaScroll.d.ts +35 -5
  35. package/dist/controls/SkiaScroll.js +233 -23
  36. package/dist/controls/SkiaScrollBar.d.ts +27 -0
  37. package/dist/controls/SkiaScrollBar.js +51 -2
  38. package/dist/controls/SkiaShaderCarousel.d.ts +5 -0
  39. package/dist/controls/SkiaShaderCarousel.js +5 -0
  40. package/dist/controls/SkiaShape.d.ts +13 -2
  41. package/dist/controls/SkiaShape.js +50 -10
  42. package/dist/controls/SkiaSlider.d.ts +20 -2
  43. package/dist/controls/SkiaSlider.js +59 -5
  44. package/dist/controls/SkiaSprite.d.ts +1 -0
  45. package/dist/controls/SkiaSprite.js +4 -0
  46. package/dist/controls/SkiaSvg.js +1 -1
  47. package/dist/controls/SkiaSwitch.d.ts +0 -1
  48. package/dist/controls/SkiaSwitch.js +0 -6
  49. package/dist/controls/SkiaToggle.d.ts +25 -5
  50. package/dist/controls/SkiaToggle.js +58 -5
  51. package/dist/controls/SnappingLayout.d.ts +12 -1
  52. package/dist/controls/SnappingLayout.js +19 -1
  53. package/dist/core/Accessibility.d.ts +80 -0
  54. package/dist/core/Accessibility.js +365 -8
  55. package/dist/core/Animators.d.ts +37 -1
  56. package/dist/core/Animators.js +102 -9
  57. package/dist/core/Canvas.d.ts +108 -7
  58. package/dist/core/Canvas.js +363 -35
  59. package/dist/core/Easing.d.ts +12 -1
  60. package/dist/core/Easing.js +25 -1
  61. package/dist/core/Gestures.d.ts +48 -2
  62. package/dist/core/Gestures.js +95 -3
  63. package/dist/core/Hover.d.ts +47 -0
  64. package/dist/core/Hover.js +134 -0
  65. package/dist/core/KeyboardManager.d.ts +13 -0
  66. package/dist/core/KeyboardManager.js +18 -0
  67. package/dist/core/ScrollAnimators.js +9 -0
  68. package/dist/core/SkiaControl.d.ts +216 -7
  69. package/dist/core/SkiaControl.js +516 -59
  70. package/dist/core/SkiaEffect.d.ts +17 -0
  71. package/dist/core/SkiaEffect.js +43 -8
  72. package/dist/core/SkiaImageManager.js +1 -1
  73. package/dist/core/Styles.d.ts +51 -0
  74. package/dist/core/Styles.js +92 -0
  75. package/dist/core/Super.d.ts +17 -1
  76. package/dist/core/Super.js +35 -4
  77. package/dist/core/ViewsAdapter.d.ts +7 -2
  78. package/dist/core/ViewsAdapter.js +10 -3
  79. package/dist/index.d.ts +4 -0
  80. package/dist/index.js +4 -0
  81. package/dist/react/SkiaShell.js +33 -14
  82. package/dist/react/index.d.ts +15 -4
  83. package/dist/react/index.js +102 -15
  84. package/dist/react/reconciler.js +34 -12
  85. package/dist/vite/index.d.ts +9 -0
  86. package/dist/vite/index.js +36 -3
  87. package/package.json +33 -3
@@ -16,7 +16,20 @@ export class AnimatorBase {
16
16
  StartFrameTimeNanos = 0;
17
17
  OnStart;
18
18
  OnStop;
19
+ /** Paused: the canvas does not tick it and it wakes no frames; Resume goes on from where it was (C# Pause / Resume). */
20
+ IsPaused = false;
21
+ /** Paused by the canvas because its control is hidden; resumed when it shows again. */
22
+ PausedWhileHidden = false;
23
+ /**
24
+ * Frame time (ns) before which nothing it shows changes: the canvas does not tick it and it keeps no frames coming
25
+ * until then, a timer wakes the frame loop at that time (a GIF or a sprite between two frames; DrawnUi.Rust frame
26
+ * animators sleep between changes). 0 = tick every frame.
27
+ */
28
+ SleepUntilNanos = 0;
19
29
  delayHandle = 0;
30
+ delayEnd = 0;
31
+ delayLeft = 0;
32
+ pausedAt = 0;
20
33
  constructor(parent) { this.Parent = parent; }
21
34
  Register() {
22
35
  const parent = this.Parent;
@@ -29,7 +42,14 @@ export class AnimatorBase {
29
42
  if (!parent.PostAnimators.includes(effect))
30
43
  parent.PostAnimators.push(effect);
31
44
  }
32
- const ok = parent.Superview?.RegisterAnimator(this) ?? false;
45
+ const superview = parent.Superview;
46
+ const ok = superview?.RegisterAnimator(this) ?? false;
47
+ // C# SkiaControl.RegisterAnimator: not attached yet, queue it; the parent starts it on its first arrange
48
+ if (!superview && !parent.IsDisposed) {
49
+ const pending = parent.PendingUnattachedAnimators ??= [];
50
+ if (!pending.includes(this))
51
+ pending.push(this);
52
+ }
33
53
  parent.Repaint();
34
54
  return ok;
35
55
  }
@@ -42,6 +62,9 @@ export class AnimatorBase {
42
62
  if (i >= 0)
43
63
  parent.PostAnimators.splice(i, 1);
44
64
  }
65
+ const pending = parent.PendingUnattachedAnimators?.indexOf(this) ?? -1;
66
+ if (pending >= 0)
67
+ parent.PendingUnattachedAnimators.splice(pending, 1);
45
68
  parent.Superview?.UnregisterAnimator(this.Uid);
46
69
  }
47
70
  Start(delayMs = 0) {
@@ -50,6 +73,8 @@ export class AnimatorBase {
50
73
  this.delayHandle = 0;
51
74
  }
52
75
  if (delayMs > 0) {
76
+ // the delay waits without frames
77
+ this.delayEnd = performance.now() + delayMs;
53
78
  this.delayHandle = window.setTimeout(() => { this.delayHandle = 0; this.Start(); }, delayMs);
54
79
  return;
55
80
  }
@@ -62,7 +87,43 @@ export class AnimatorBase {
62
87
  }
63
88
  }
64
89
  }
90
+ /** Freezes the run (and what is left of a start delay); Resume goes on from there. */
91
+ Pause() {
92
+ if (this.IsPaused)
93
+ return;
94
+ this.IsPaused = true;
95
+ this.pausedAt = performance.now();
96
+ if (this.delayHandle) {
97
+ clearTimeout(this.delayHandle);
98
+ this.delayHandle = 0;
99
+ this.delayLeft = Math.max(0, this.delayEnd - this.pausedAt);
100
+ }
101
+ }
102
+ /** Goes on from where Pause froze it: the paused time is not counted. */
103
+ Resume() {
104
+ if (!this.IsPaused)
105
+ return;
106
+ this.IsPaused = false;
107
+ const paused = (performance.now() - this.pausedAt) * 1_000_000;
108
+ if (this.StartFrameTimeNanos !== 0) {
109
+ this.StartFrameTimeNanos += paused;
110
+ this.LastFrameTimeNanos += paused;
111
+ }
112
+ if (this.SleepUntilNanos !== 0)
113
+ this.SleepUntilNanos += paused;
114
+ if (this.delayLeft > 0) {
115
+ const left = this.delayLeft;
116
+ this.delayLeft = 0;
117
+ this.Start(left);
118
+ return;
119
+ }
120
+ this.Parent?.Repaint(); // frames again
121
+ }
65
122
  Stop() {
123
+ this.IsPaused = false;
124
+ this.PausedWhileHidden = false;
125
+ this.SleepUntilNanos = 0;
126
+ this.delayLeft = 0;
66
127
  if (this.delayHandle) {
67
128
  clearTimeout(this.delayHandle);
68
129
  this.delayHandle = 0;
@@ -96,6 +157,21 @@ export class AnimatorBase {
96
157
  this.OnStop?.();
97
158
  }
98
159
  }
160
+ /**
161
+ * DrawnUi ActionOnTickAnimator: runs `action(frameTimeNanos)` on every frame until stopped, a game loop for
162
+ * DrawnGame or any per-frame work.
163
+ */
164
+ export class ActionOnTickAnimator extends AnimatorBase {
165
+ action;
166
+ constructor(parent, action) {
167
+ super(parent);
168
+ this.action = action;
169
+ }
170
+ TickFrame(frameTimeNanos) {
171
+ this.action(frameTimeNanos);
172
+ return super.TickFrame(frameTimeNanos);
173
+ }
174
+ }
99
175
  /** DrawnUi SkiaValueAnimator: drives mValue from mMinValue to mMaxValue over Speed ms with Easing. */
100
176
  export class SkiaValueAnimator extends AnimatorBase {
101
177
  mValue = 0;
@@ -130,23 +206,21 @@ export class SkiaValueAnimator extends AnimatorBase {
130
206
  }
131
207
  /** Passed over mValue; subclasses derive their own reported value here. */
132
208
  TransformReportedValue(_deltaT) { return this.mValue; }
133
- /** Updates mValue from elapsed time; true when the target was reached. */
209
+ /**
210
+ * Updates mValue from elapsed time; true when the run is over. The eased value is not clamped to the range: a spring
211
+ * easing goes past its ends, and a run whose mMinValue is above mMaxValue (a ping-pong's way back) goes down.
212
+ */
134
213
  UpdateValue(_deltaT, deltaFromStart) {
135
214
  const elapsedMs = deltaFromStart / 1_000_000;
136
215
  const progress = this.Speed > 0 ? elapsedMs / this.Speed : 1;
137
216
  const deltaValue = this.mMaxValue - this.mMinValue;
138
217
  const eased = this.Easing.Ease(Math.min(progress, 1));
139
218
  this.Progress = eased;
140
- const value = deltaValue * eased + this.mMinValue;
141
- if (value < this.mMinValue) {
142
- this.mValue = this.mMinValue;
143
- return false;
144
- }
145
- if (value >= this.mMaxValue || progress >= 1) {
219
+ if (progress >= 1) {
146
220
  this.mValue = this.mMaxValue;
147
221
  return true;
148
222
  }
149
- this.mValue = value;
223
+ this.mValue = deltaValue * eased + this.mMinValue;
150
224
  return false;
151
225
  }
152
226
  FinishedRunning() {
@@ -163,6 +237,25 @@ export class SkiaValueAnimator extends AnimatorBase {
163
237
  return true;
164
238
  }
165
239
  }
240
+ /** DrawnUi PingPongAnimator: every repeat runs the other way (Repeat -1 = forever by default). */
241
+ export class PingPongAnimator extends SkiaValueAnimator {
242
+ /** One way done, the next starts (C# CycleFInished). */
243
+ CycleFinished;
244
+ constructor(parent) { super(parent); this.Repeat = -1; }
245
+ FinishedRunning() {
246
+ if (this.Repeat !== 0) {
247
+ this.CycleFinished?.();
248
+ if (this.Repeat > 0)
249
+ this.Repeat--;
250
+ [this.mMinValue, this.mMaxValue] = [this.mMaxValue, this.mMinValue];
251
+ this.mValue = this.mMinValue;
252
+ this.LastFrameTimeNanos = 0;
253
+ this.StartFrameTimeNanos = 0;
254
+ return false;
255
+ }
256
+ return super.FinishedRunning();
257
+ }
258
+ }
166
259
  /** DrawnUi RenderingAnimator: a value animator that paints itself above its Parent (IOverlayEffect). */
167
260
  export class RenderingAnimator extends SkiaValueAnimator {
168
261
  constructor(parent) { super(parent); }
@@ -1,7 +1,8 @@
1
1
  import type { Surface } from "canvaskit-wasm";
2
- import type { SkiaControl } from "./SkiaControl";
2
+ import type { DrawingContext, SkiaControl } from "./SkiaControl";
3
3
  import type { AnimatorBase } from "./Animators";
4
4
  import { SkiaAccessibilityManager } from "./Accessibility";
5
+ import { HoverManager } from "./Hover";
5
6
  import { type Color, type RenderingModeType } from "./Types";
6
7
  import { ContextMenuEventArgs, type GesturesMode, SkiaGesturesParameters, TouchActionEventArgs } from "./Gestures";
7
8
  /**
@@ -14,6 +15,11 @@ export declare class Canvas {
14
15
  readonly Element: HTMLCanvasElement;
15
16
  /** Points a pointer may travel between Down and Up and still count as a tap (AppoMobi TouchEffect default). */
16
17
  static TappedCancelMoveThresholdPoints: number;
18
+ /**
19
+ * A press held this long without moving past TappedCancelMoveThresholdPoints is a LongPressing, at the press point
20
+ * (AppoMobi TouchEffect, DrawnUi.Rust LONG_PRESS_MS); its release sends no Tapped. A timer, no frames while waiting.
21
+ */
22
+ static LongPressTimeMs: number;
17
23
  BackgroundColor: Color;
18
24
  /** Accelerated = WebGL surface, Default = software. Read once at first frame. */
19
25
  RenderingMode: RenderingModeType;
@@ -23,8 +29,22 @@ export declare class Canvas {
23
29
  /** Frames per second over the last second of drawn frames. */
24
30
  FPS: number;
25
31
  private frameTimes;
32
+ /** DrawnView.WasRendered: a frame has been drawn on a ready surface (set after the first one completes). */
33
+ WasRendered: boolean;
34
+ /** DrawnView.CanRender: the surface (and its GPU context when accelerated) is ready to draw. */
35
+ get CanRender(): boolean;
36
+ /**
37
+ * DrawnView.WillFirstTimeDraw: raised once, right before the first frame drawn on a ready surface, with that
38
+ * frame's drawing context. The engine draws its first frame while it is being constructed (so the page never shows
39
+ * an unpainted canvas): pass it through the constructor's `init` to receive that frame.
40
+ */
41
+ WillFirstTimeDraw?: (sender: Canvas, context: DrawingContext["Context"]) => void;
42
+ /** DrawnView.WasDrawn: raised after every frame has been drawn (the C# event passes no context). */
43
+ WasDrawn?: (sender: Canvas) => void;
26
44
  /** Registry + rate-limited snapshot of accessible controls, rendered by the DOM overlay (DrawnUi AccessibilityManager). */
27
45
  readonly AccessibilityManager: SkiaAccessibilityManager;
46
+ /** Mouse hover of the controls (drawnui-cross 6m): ReceivesHover / IsHovered / HoverChanged. */
47
+ readonly Hover: HoverManager;
28
48
  private content?;
29
49
  get Content(): SkiaControl | undefined;
30
50
  set Content(value: SkiaControl | undefined);
@@ -35,7 +55,15 @@ export declare class Canvas {
35
55
  private frameId;
36
56
  private disposed;
37
57
  private readonly observer;
38
- constructor(Element: HTMLCanvasElement);
58
+ /** The WebGL context is lost: no frames until the browser restores it. */
59
+ private contextLost;
60
+ /**
61
+ * Bumped when the WebGL context was restored: every GPU object made before (Image caches, picture caches that may
62
+ * replay them, kept composite surfaces, effect textures) is remade at its next draw (DrawnUi.Rust Gpu::epoch).
63
+ */
64
+ GpuEpoch: number;
65
+ /** `init` runs before the first frame is drawn: the place to attach `WillFirstTimeDraw` / `WasDrawn` for that frame. */
66
+ constructor(Element: HTMLCanvasElement, init?: (canvas: Canvas) => void);
39
67
  /** Request a redraw (full measure + arrange + render) on the next animation frame. */
40
68
  Update(): void;
41
69
  /** Deletes the current surface; a pending frame on it is cancelled first (drawing on a deleted surface faults). */
@@ -48,6 +76,17 @@ export declare class Canvas {
48
76
  * redrawn content lands in the same paint and no blank frame is ever shown while dragging.
49
77
  */
50
78
  private OnResized;
79
+ /** WebGL context lost: keep the browser restoring it (preventDefault) and stop the frames. */
80
+ private readonly onContextLost;
81
+ /**
82
+ * WebGL context restored (as DrawnUi.Rust and the C# Wasm / Blazor heads): every GL object of the lost generation is
83
+ * gone. The old Skia context is abandoned first, while its own GL handle is current and before the new context makes
84
+ * any object, so its GL calls reach only lost-generation objects. CanvasKit exposes no `abandonContext`;
85
+ * `releaseResourcesAndAbandonContext` is its only way to abandon, and after it freeing an old image or surface makes no
86
+ * GL call. Then the same WebGL object is registered again (the old handle deleted first, which clears the canvas'
87
+ * context object) with a new GrContext and surface; GpuEpoch makes the old generation's GPU objects remake themselves.
88
+ */
89
+ private readonly onContextRestored;
51
90
  /** Draws one frame immediately (outside the rAF loop) and presents it. */
52
91
  private DrawNow;
53
92
  private Draw;
@@ -62,8 +101,20 @@ export declare class Canvas {
62
101
  UnregisterAnimator(uid: number): void;
63
102
  /** Ticks every registered animator once; returns how many ran. */
64
103
  protected ExecuteAnimators(frameTimeNanos: number): number;
104
+ private wakeTimer;
105
+ private wakeAtNanos;
106
+ /** One timer for the earliest sleeping animator: the frame loop wakes then, no frames run in between. */
107
+ private WakeAt;
65
108
  /** Frames drawn so far (SkiaBackdrop uses it to refresh once after a cached record). */
66
109
  FrameIndex: number;
110
+ /**
111
+ * DrawnView.WheelDeltaPerNotch: the Wheel.Delta one mouse-wheel notch produces, 100 CSS pixels in Chrome and Edge. A
112
+ * scroll moves by the event's share of a notch, so a touchpad, which sends many small events, scrolls as far as the
113
+ * fingers moved. 0 = units unknown: every event scrolls one line.
114
+ */
115
+ WheelDeltaPerNotch: number;
116
+ /** Vsync time of the last frame the animators ran on (nanoseconds, the performance.now() timeline). */
117
+ FrameTimeNanos: number;
67
118
  /** On-screen surface (SkiaBackdrop snapshots it). */
68
119
  get Surface(): Surface | undefined;
69
120
  /**
@@ -87,7 +138,13 @@ export declare class Canvas {
87
138
  private readonly previousTouchArgs;
88
139
  private readonly pendingGestures;
89
140
  private readonly onPointer;
141
+ /** The mouse left the canvas: hover ends at once, also while content moves. */
142
+ private readonly onPointerLeave;
90
143
  private readonly preventTouch;
144
+ /** Gestures="Enabled": touch / pen pointers whose Down a control used (see OnTouchAction). */
145
+ private readonly claimedTouches;
146
+ /** Gestures="Enabled": while a claimed touch is down the page may not take its drag. */
147
+ private readonly preventClaimedTouch;
91
148
  /** Called when no control handled a context-menu request; return true to suppress the browser's canvas menu. */
92
149
  ContextMenu?: (sender: Canvas, e: ContextMenuEventArgs) => boolean | void;
93
150
  /** DOM contextmenu (right click / long press / Menu key) -> ContextMenuEventArgs routed through the tree like a tap. */
@@ -95,20 +152,64 @@ export declare class Canvas {
95
152
  private cursorPointer;
96
153
  /**
97
154
  * DrawnUi.Blazor shows `cursor: pointer` over interactive controls through its overlay elements; here the overlay
98
- * is pointer-events:none, so the mouse position is tested against the accessibility snapshot (the accessible
99
- * controls' rects in points, already sorted and rate-limited), each hit control answering WantsPointerCursor
100
- * (itself tappable, or a tappable span of a label), and the canvas element's cursor is switched only when the
101
- * answer changes. Mouse moves only, no work without a mouse and none in the frame loop.
155
+ * is pointer-events:none, so the canvas decides from the hover hit path (Hover.Path: the controls under the mouse by
156
+ * the routing rules of ProcessGestures, so nothing below a popup that blocks gestures below): a control in the
157
+ * accessibility tree (it has a role) that answers WantsPointerCursor (itself tappable, or a tappable span of a label)
158
+ * shows the hand. A popup's close-on-background-tap wrapper has no role, so its backdrop shows none. The canvas
159
+ * element's cursor is switched only when the answer changes. Mouse moves only, none in the frame loop.
102
160
  */
103
161
  private UpdateCursor;
104
- /** Mouse wheel -> TouchActionResult.Wheel (page scroll suppressed while gestures are enabled). */
162
+ /**
163
+ * Mouse wheel -> TouchActionResult.Wheel.
164
+ * Lock keeps every wheel on the canvas. Enabled shares it with the page, like DrawnUi.Blazor's
165
+ * TouchHandlingStyle.Manual: the page scrolls unless a control consumed this wheel. The browser needs that answer
166
+ * inside this handler, so the wheel is processed now instead of at the next frame (Blazor does the same, for the
167
+ * same reason); pending gestures are flushed first so the event order is kept.
168
+ */
105
169
  private readonly onWheel;
170
+ /**
171
+ * Processes one gesture immediately (after whatever is queued) and reports whether a control USED it: a consumer
172
+ * that marked the event Handled, or any consumer that is not a `BlockGesturesBelow` layer. A blocker returns itself
173
+ * for every gesture it keeps from the controls below (a shell page, a popup backdrop), which is not a use: counting
174
+ * it would block the page wheel over every shell app.
175
+ */
176
+ private ProcessGestureNow;
177
+ /**
178
+ * The page axes a touch pan over the canvas hands to the browser: "pan-y" when the page (or a scrolling ancestor) can
179
+ * scroll vertically, "pan-x" horizontally, both, or "none". Mirrors MAUI's Gestures="Enabled" inside a native scroll
180
+ * view, where the parent takes the pans it scrolls in.
181
+ */
182
+ private static PageScrollAxes;
183
+ /**
184
+ * Gestures="Enabled" shares touch pans with the page like MAUI's Enabled inside a native scroll view: along an axis
185
+ * the page can scroll, the browser takes the pan (and sends pointercancel), taps and the other axis stay on the
186
+ * canvas. A page that cannot scroll, and Lock, keep every touch. The browser reads touch-action when a touch starts,
187
+ * so it is kept current ahead of time: on attach, when the window / html / body resize, and after every touch.
188
+ */
189
+ private readonly UpdateTouchAction;
190
+ private pageObserver?;
106
191
  private AttachInput;
192
+ /** The page's own overscroll-behavior before Lock set it to none (html, body), put back on detach. */
193
+ private pageOverscroll?;
107
194
  private DetachInput;
108
195
  /** Port of DrawnUi.Blazor Canvas.OnTouchAction: per-pointer state machine producing Down / Panning / Tapped / Up. */
109
196
  OnTouchAction(args: TouchActionEventArgs): void;
197
+ private readonly longPressTimers;
198
+ private readonly longPressed;
199
+ /** The long press of a new press: due LongPressTimeMs later unless the pointer moves away or lets go. */
200
+ private ArmLongPress;
201
+ private DisarmLongPress;
110
202
  private OnGestureEvent;
111
203
  private ProcessPendingGestures;
204
+ /**
205
+ * The control that consumed the current gesture keeps it until it lets go (DrawnUi Canvas.HadInput). Without this a
206
+ * gesture is re-routed by the pointer position on every event, so anything the finger drags away from — a drag
207
+ * handle, a slider thumb, a button being held — stops receiving Panning the moment the pointer leaves its box.
208
+ * Single pointer, which is what the web gives us here; C# keeps a set for multi-touch.
209
+ */
210
+ private gestureOwner;
211
+ /** DrawnUi IsSavedGesture: the types replayed to the owner instead of being routed again. */
212
+ private static IsSavedGesture;
112
213
  /** Entry into the control tree, same shape as DrawnUi Canvas.ProcessGestures. */
113
214
  protected ProcessGestures(root: SkiaControl, args: SkiaGesturesParameters): SkiaControl | null;
114
215
  }