drawnui-react 0.1.0-preview.7 → 0.1.0-preview.9
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/SKIPPED.md +2 -1
- package/dist/core/Canvas.d.ts +15 -2
- package/dist/core/Canvas.js +26 -1
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.js +10 -4
- package/package.json +1 -1
package/SKIPPED.md
CHANGED
|
@@ -47,10 +47,11 @@ DrawnUi name and semantics; nothing here is a redesign, only an omission.
|
|
|
47
47
|
| Area | Status | Notes |
|
|
48
48
|
|---|---|---|
|
|
49
49
|
| `RenderingMode` | partial | `Accelerated` (WebGL) with automatic fallback to software; read once at first surface creation. |
|
|
50
|
-
| `Gestures` param | ported | Touch: `Lock` applies `touch-action:none`; `Enabled` behaves like MAUI's Enabled inside a native scroll view: `touch-action` is the axes the page (or a scrolling ancestor) can scroll (`pan-y` / `pan-x` / both, `none` when it cannot; inside an iframe the vertical axis always counts, because the embedding page cannot be inspected cross-origin), recomputed on attach, on window / html / body resize and after every touch, so a finger pan along a page axis scrolls the page and the canvas pointer is cancelled (a cancelled pointer never flings a `SkiaScroll`), taps and the other axis stay on the canvas, and a full-page app keeps every touch. `user-select:none` in both. Mouse wheel: `Enabled` shares it with the page like Blazor's `TouchHandlingStyle.Manual` (the wheel is processed in the DOM handler and the browser default is prevented only when a control used it: a scroll that moved, a `ConsumeGestures` handler that consumed, or any other consumer that is not a `BlockGesturesBelow` layer merely blocking the controls below, so an embedded canvas lets the page scroll over anything that does not scroll, including a shell page, and a scroll at its edge hands the wheel to the page; `TouchActionEventArgs.Handled` is the AppoMobi marker for that use); `Lock` prevents every wheel and also blocks `touchmove` default. Not ported: Blazor's pointer capture policy for `Enabled` (capture only while locked, release when a pan is not consumed); React captures every press. |
|
|
50
|
+
| `Gestures` param | ported | Touch: `Lock` applies `touch-action:none`; `Enabled` behaves like MAUI's Enabled inside a native scroll view: `touch-action` is the axes the page (or a scrolling ancestor) can scroll (`pan-y` / `pan-x` / both, `none` when it cannot; inside an iframe the vertical axis always counts, because the embedding page cannot be inspected cross-origin), recomputed on attach, on window / html / body resize and after every touch, so a finger pan along a page axis scrolls the page and the canvas pointer is cancelled (a cancelled pointer never flings a `SkiaScroll`), taps and the other axis stay on the canvas, and a full-page app keeps every touch. `user-select:none` in both. Claimed touches: in `Enabled` a touch or pen Down is processed immediately (queued gestures first) and, when a control used it (same rule as the wheel: marked `Handled`, or a consumer that is not a `BlockGesturesBelow` layer), the touch is claimed and its `touchmove` events are default-prevented until it ends, so the page cannot take that drag mid-gesture (iOS Safari ignores `touch-action` for off-axis drags, w3c/pointerevents#303); unclaimed touches share the page as before. Controls that use a Down: `ConsumeGestures` handlers that set `Consumed`, `SkiaCarousel` (always), `SkiaSlider`, `SkiaEditor`, `SkiaButton` when `OnDown` accepts; `SkiaScroll` and plain `Tapped` controls do not. Mouse wheel: `Enabled` shares it with the page like Blazor's `TouchHandlingStyle.Manual` (the wheel is processed in the DOM handler and the browser default is prevented only when a control used it: a scroll that moved, a `ConsumeGestures` handler that consumed, or any other consumer that is not a `BlockGesturesBelow` layer merely blocking the controls below, so an embedded canvas lets the page scroll over anything that does not scroll, including a shell page, and a scroll at its edge hands the wheel to the page; `TouchActionEventArgs.Handled` is the AppoMobi marker for that use); `Lock` prevents every wheel and also blocks `touchmove` default. Not ported: Blazor's pointer capture policy for `Enabled` (capture only while locked, release when a pan is not consumed); React captures every press. |
|
|
51
51
|
| Mouse cursor over interactive controls (Blazor `Canvas.razor` `.xaml-a11y-interactive { cursor: pointer }`) | ported (differently) | The overlay here is `pointer-events: none`, so `Canvas.UpdateCursor` hit-tests mouse moves with no active pointer against the accessibility snapshot rects (`CanInteract` = has `Tapped`, buttons, links) and asks each hit control `WantsPointerCursor(x, y)` (default `AccessibilityCanInteract`; `SkiaLabel` also answers for its tappable `TextSpan`s), setting the canvas element's `cursor` only when the answer changes. Touch pointers do nothing. Engine hover (`IsHovered` / `OnHover`, `TouchActionResult.Pointer`) stays skipped, see Gestures. |
|
|
52
52
|
| `ContextMenu` (right click / long press / Menu key, React extension) | ported (web-only) | `SkiaControl.ContextMenu` / `Canvas.ContextMenu` handlers with `ContextMenuEventArgs` (`Location` points, `Pixels`, `Local` px in the control, `Source`, `Native`); the DOM `contextmenu` event is routed like a tap (`ProcessContextMenu`: visible non-transparent children top-most first through `TransformPointToLocalSpace`, then the control, then the canvas). `true` = handled, browser menu suppressed; nothing handled = browser menu. Not in DrawnUi.Net. |
|
|
53
53
|
| Keyboard, focus (`FocusedChild`) | skipped | |
|
|
54
|
+
| Canvas draw events | ported | `WillFirstTimeDraw` (once, right before the first frame drawn on a ready surface, with that frame's `{ Canvas, Surface }`), `WasDrawn` (after every frame, no context, like the C# `null`), `WasRendered` (set after the first frame completes, so the first `WasDrawn` still sees `false`, C# order), `CanRender` (surface ready). JSX: `<Canvas WillFirstTimeDraw WasDrawn>`; the engine draws frame 1 in its constructor, so the component hands both callbacks to the constructor's `init`. Not ported: `WillDraw`. |
|
|
54
55
|
| Rendering stats | partial | `Canvas.FPS` (frames drawn over the last second) and `Canvas.FrameTime` (ms of the last measure + arrange + render, GPU flush excluded) are computed every frame and reachable from React through the `<Canvas>` ref. Not ported: the `SkiaLabelFps` control, `Super.EnableRenderingStats`. |
|
|
55
56
|
| Insets / safe areas | ported | `Super.Insets` measures `env(safe-area-inset-*)` off a probe element (once, and again on resize / orientation), `Super.OnInsetsChanged` notifies; `SkiaShell` pads its nav and tab bars with them. Not ported: the C# per-page `IgnoreSafeArea` / MAUI inset plumbing. |
|
|
56
57
|
|
package/dist/core/Canvas.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
5
|
import { type Color, type RenderingModeType } from "./Types";
|
|
@@ -23,6 +23,18 @@ export declare class Canvas {
|
|
|
23
23
|
/** Frames per second over the last second of drawn frames. */
|
|
24
24
|
FPS: number;
|
|
25
25
|
private frameTimes;
|
|
26
|
+
/** DrawnView.WasRendered: a frame has been drawn on a ready surface (set after the first one completes). */
|
|
27
|
+
WasRendered: boolean;
|
|
28
|
+
/** DrawnView.CanRender: the surface (and its GPU context when accelerated) is ready to draw. */
|
|
29
|
+
get CanRender(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* DrawnView.WillFirstTimeDraw: raised once, right before the first frame drawn on a ready surface, with that
|
|
32
|
+
* frame's drawing context. The engine draws its first frame while it is being constructed (so the page never shows
|
|
33
|
+
* an unpainted canvas): pass it through the constructor's `init` to receive that frame.
|
|
34
|
+
*/
|
|
35
|
+
WillFirstTimeDraw?: (sender: Canvas, context: DrawingContext["Context"]) => void;
|
|
36
|
+
/** DrawnView.WasDrawn: raised after every frame has been drawn (the C# event passes no context). */
|
|
37
|
+
WasDrawn?: (sender: Canvas) => void;
|
|
26
38
|
/** Registry + rate-limited snapshot of accessible controls, rendered by the DOM overlay (DrawnUi AccessibilityManager). */
|
|
27
39
|
readonly AccessibilityManager: SkiaAccessibilityManager;
|
|
28
40
|
private content?;
|
|
@@ -35,7 +47,8 @@ export declare class Canvas {
|
|
|
35
47
|
private frameId;
|
|
36
48
|
private disposed;
|
|
37
49
|
private readonly observer;
|
|
38
|
-
|
|
50
|
+
/** `init` runs before the first frame is drawn: the place to attach `WillFirstTimeDraw` / `WasDrawn` for that frame. */
|
|
51
|
+
constructor(Element: HTMLCanvasElement, init?: (canvas: Canvas) => void);
|
|
39
52
|
/** Request a redraw (full measure + arrange + render) on the next animation frame. */
|
|
40
53
|
Update(): void;
|
|
41
54
|
/** Deletes the current surface; a pending frame on it is cancelled first (drawing on a deleted surface faults). */
|
package/dist/core/Canvas.js
CHANGED
|
@@ -21,6 +21,18 @@ export class Canvas {
|
|
|
21
21
|
/** Frames per second over the last second of drawn frames. */
|
|
22
22
|
FPS = 0;
|
|
23
23
|
frameTimes = [];
|
|
24
|
+
/** DrawnView.WasRendered: a frame has been drawn on a ready surface (set after the first one completes). */
|
|
25
|
+
WasRendered = false;
|
|
26
|
+
/** DrawnView.CanRender: the surface (and its GPU context when accelerated) is ready to draw. */
|
|
27
|
+
get CanRender() { return !!this.surface && !this.disposed; }
|
|
28
|
+
/**
|
|
29
|
+
* DrawnView.WillFirstTimeDraw: raised once, right before the first frame drawn on a ready surface, with that
|
|
30
|
+
* frame's drawing context. The engine draws its first frame while it is being constructed (so the page never shows
|
|
31
|
+
* an unpainted canvas): pass it through the constructor's `init` to receive that frame.
|
|
32
|
+
*/
|
|
33
|
+
WillFirstTimeDraw;
|
|
34
|
+
/** DrawnView.WasDrawn: raised after every frame has been drawn (the C# event passes no context). */
|
|
35
|
+
WasDrawn;
|
|
24
36
|
/** Registry + rate-limited snapshot of accessible controls, rendered by the DOM overlay (DrawnUi AccessibilityManager). */
|
|
25
37
|
AccessibilityManager = new SkiaAccessibilityManager();
|
|
26
38
|
content;
|
|
@@ -42,10 +54,12 @@ export class Canvas {
|
|
|
42
54
|
frameId = 0;
|
|
43
55
|
disposed = false;
|
|
44
56
|
observer;
|
|
45
|
-
|
|
57
|
+
/** `init` runs before the first frame is drawn: the place to attach `WillFirstTimeDraw` / `WasDrawn` for that frame. */
|
|
58
|
+
constructor(Element, init) {
|
|
46
59
|
this.Element = Element;
|
|
47
60
|
if (!Super.CK)
|
|
48
61
|
throw new Error("DrawnUi: call Super.UseDrawnUi()...BuildAsync() before creating a Canvas");
|
|
62
|
+
init?.(this);
|
|
49
63
|
this.observer = new ResizeObserver(() => this.OnResized());
|
|
50
64
|
this.observer.observe(Element);
|
|
51
65
|
this.OnResized();
|
|
@@ -122,6 +136,9 @@ export class Canvas {
|
|
|
122
136
|
const started = performance.now();
|
|
123
137
|
this.ProcessPendingGestures();
|
|
124
138
|
const executed = this.ExecuteAnimators(Math.round(started * 1_000_000));
|
|
139
|
+
const canRender = this.CanRender;
|
|
140
|
+
if (canRender && !this.WasRendered)
|
|
141
|
+
this.WillFirstTimeDraw?.(this, { Canvas: canvas, Surface: this.surface });
|
|
125
142
|
canvas.clear(Super.ParseColor(this.BackgroundColor));
|
|
126
143
|
const root = this.content;
|
|
127
144
|
if (root) {
|
|
@@ -141,6 +158,10 @@ export class Canvas {
|
|
|
141
158
|
this.FPS = this.frameTimes.length;
|
|
142
159
|
if (executed > 0)
|
|
143
160
|
this.Update(); // animators running: keep frames coming
|
|
161
|
+
// C# order: WasDrawn at the end of the frame, then the frame counts as rendered
|
|
162
|
+
this.WasDrawn?.(this);
|
|
163
|
+
if (!this.WasRendered && canRender)
|
|
164
|
+
this.WasRendered = true;
|
|
144
165
|
}
|
|
145
166
|
// ---- deferred disposal (DrawnUi DisposeObject: never delete Skia objects mid-frame) ----
|
|
146
167
|
disposeQueue = [];
|
|
@@ -395,6 +416,10 @@ export class Canvas {
|
|
|
395
416
|
y = true;
|
|
396
417
|
if (!x && !clips(hs.overflowX) && !clips(bs.overflowX) && root.scrollWidth > root.clientWidth + 1)
|
|
397
418
|
x = true;
|
|
419
|
+
// a canvas filling a framed document (a widget in an iframe): the page that scrolls is the parent, which a
|
|
420
|
+
// cross-origin frame cannot inspect, so assume it scrolls vertically; horizontal pans and taps stay on the canvas
|
|
421
|
+
if (!y && window.self !== window.top)
|
|
422
|
+
y = true;
|
|
398
423
|
return x && y ? "pan-x pan-y" : y ? "pan-y" : x ? "pan-x" : "none";
|
|
399
424
|
}
|
|
400
425
|
/**
|
package/dist/react/index.d.ts
CHANGED
|
@@ -113,12 +113,16 @@ export interface CanvasProps {
|
|
|
113
113
|
ref?: Ref<CanvasView>;
|
|
114
114
|
/** Context-menu request (right click / long press / Menu key) no control handled; return true to suppress the browser menu. */
|
|
115
115
|
ContextMenu?: CanvasView["ContextMenu"];
|
|
116
|
+
/** DrawnView.WillFirstTimeDraw: once, right before the first frame is drawn, with its drawing context. */
|
|
117
|
+
WillFirstTimeDraw?: CanvasView["WillFirstTimeDraw"];
|
|
118
|
+
/** DrawnView.WasDrawn: after every drawn frame. */
|
|
119
|
+
WasDrawn?: CanvasView["WasDrawn"];
|
|
116
120
|
}
|
|
117
121
|
/**
|
|
118
122
|
* Mirrors DrawnUi Canvas: the bridge between the DOM (react-dom) and the drawn tree (DrawnUi reconciler).
|
|
119
123
|
* Requires Super.UseDrawnUi()...BuildAsync() to have completed.
|
|
120
124
|
*/
|
|
121
|
-
export declare function Canvas({ BackgroundColor, RenderingMode, Gestures, children, style, className, ref: viewRef, ContextMenu }: CanvasProps): import("react").JSX.Element;
|
|
125
|
+
export declare function Canvas({ BackgroundColor, RenderingMode, Gestures, children, style, className, ref: viewRef, ContextMenu, WillFirstTimeDraw, WasDrawn }: CanvasProps): import("react").JSX.Element;
|
|
122
126
|
export type { SkiaControl };
|
|
123
127
|
export * from "../index";
|
|
124
128
|
export * from "./SkiaShell";
|
package/dist/react/index.js
CHANGED
|
@@ -66,15 +66,19 @@ function removeStaticContent() {
|
|
|
66
66
|
* Mirrors DrawnUi Canvas: the bridge between the DOM (react-dom) and the drawn tree (DrawnUi reconciler).
|
|
67
67
|
* Requires Super.UseDrawnUi()...BuildAsync() to have completed.
|
|
68
68
|
*/
|
|
69
|
-
export function Canvas({ BackgroundColor, RenderingMode, Gestures, children, style, className, ref: viewRef, ContextMenu }) {
|
|
69
|
+
export function Canvas({ BackgroundColor, RenderingMode, Gestures, children, style, className, ref: viewRef, ContextMenu, WillFirstTimeDraw, WasDrawn }) {
|
|
70
70
|
const ref = useRef(null);
|
|
71
71
|
const view = useRef(null);
|
|
72
72
|
const root = useRef(null);
|
|
73
73
|
const [engine, setEngine] = useState(null);
|
|
74
74
|
useLayoutEffect(() => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
// the engine draws frame 1 inside its constructor: the draw events and the rendering mode must be on it before that
|
|
76
|
+
const v = new CanvasView(ref.current, (c) => {
|
|
77
|
+
if (RenderingMode)
|
|
78
|
+
c.RenderingMode = RenderingMode;
|
|
79
|
+
c.WillFirstTimeDraw = WillFirstTimeDraw;
|
|
80
|
+
c.WasDrawn = WasDrawn;
|
|
81
|
+
});
|
|
78
82
|
view.current = v;
|
|
79
83
|
root.current = createDrawnRoot(v);
|
|
80
84
|
setEngine(v);
|
|
@@ -93,6 +97,8 @@ export function Canvas({ BackgroundColor, RenderingMode, Gestures, children, sty
|
|
|
93
97
|
}
|
|
94
98
|
v.Gestures = Gestures ?? "Disabled";
|
|
95
99
|
v.ContextMenu = ContextMenu;
|
|
100
|
+
v.WillFirstTimeDraw = WillFirstTimeDraw;
|
|
101
|
+
v.WasDrawn = WasDrawn;
|
|
96
102
|
root.current.render(children);
|
|
97
103
|
});
|
|
98
104
|
// The drawn surface is aria-hidden; the overlay is the accessibility tree (DrawnUi.Blazor pattern).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drawnui-react",
|
|
3
|
-
"version": "0.1.0-preview.
|
|
3
|
+
"version": "0.1.0-preview.9",
|
|
4
4
|
"description": "DrawnUi for React: the DrawnUi (.NET) drawn-UI engine in TypeScript on CanvasKit (Skia WASM). Same controls, same PascalCase API as DrawnUi.Net.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Nick Kovalsky (AppoMobi)",
|