@octane-xplat/canvas 0.14.0 → 0.15.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.
- package/README.md +45 -1
- package/package.json +16 -9
- package/src/Canvas.macos.tsrx +23 -0
- package/src/Canvas.web.tsrx +25 -9
- package/src/gpu.macos.ts +4 -0
- package/src/index.macos.ts +3 -0
- package/src/props.ts +7 -4
- package/types/index.d.ts +2 -1
- package/types/props.d.ts +7 -4
- package/dist/native/Canvas.tsrx.js +0 -35
- package/dist/native/gpu.js +0 -10
- package/dist/native/index.js +0 -3
- package/dist/native/octane-client-build.json +0 -8
- package/dist/web/Canvas.web.tsrx.js +0 -48
- package/dist/web/gpu.web.js +0 -10
- package/dist/web/index.js +0 -3
- package/dist/web/octane-client-build.json +0 -8
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ export function Drawing() {
|
|
|
30
30
|
Pass `context` to have the leaf resolve it before `onReady`, or omit it and
|
|
31
31
|
call `getContext` yourself — one kind per canvas, decided on first call.
|
|
32
32
|
`onReady` fires after mount on web and on the plugin's `ready` event on
|
|
33
|
-
|
|
33
|
+
iOS/Android (earlier `getContext` calls can return null). For WebGPU,
|
|
34
34
|
`getGPU()` normalizes adapter/device acquisition across targets.
|
|
35
35
|
|
|
36
36
|
```tsx
|
|
@@ -51,6 +51,50 @@ const adapter = await gpu?.requestAdapter()
|
|
|
51
51
|
const device = await adapter?.requestDevice()
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
## Keep a fallback when drawing is unavailable
|
|
55
|
+
|
|
56
|
+
Native macOS/AppKit imports and mounts safely, but drawing is unsupported.
|
|
57
|
+
`onReady` reports `context: null` after a neutral frame mounts; it does not
|
|
58
|
+
announce a drawing surface. Its unavailable `canvas` handle returns `null`
|
|
59
|
+
from `getContext()` for every kind, including `2d`, `webgl`, `webgl2`,
|
|
60
|
+
`webgpu`, and `bitmaprenderer`. `getGPU()` also returns `null`, so no adapter
|
|
61
|
+
or device can be acquired. Check these results before drawing and keep your
|
|
62
|
+
own static fallback. For example, put this component in your app:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { Canvas, getGPU } from '@octane-xplat/canvas'
|
|
66
|
+
import { Text, View } from '@octane-xplat/ui'
|
|
67
|
+
import { useState } from 'octane'
|
|
68
|
+
|
|
69
|
+
export function DrawingWithFallback() {
|
|
70
|
+
const [drawn, setDrawn] = useState(false)
|
|
71
|
+
return (
|
|
72
|
+
<View>
|
|
73
|
+
{!drawn && <Text>Blue square illustration</Text>}
|
|
74
|
+
<Canvas
|
|
75
|
+
context="2d"
|
|
76
|
+
width={80}
|
|
77
|
+
height={80}
|
|
78
|
+
onReady={({ canvas, context }) => {
|
|
79
|
+
const drawing = context ?? canvas.getContext('2d')
|
|
80
|
+
if (!drawing) return
|
|
81
|
+
drawing.fillStyle = '#2563eb'
|
|
82
|
+
drawing.fillRect(0, 0, 80, 80)
|
|
83
|
+
setDrawn(true)
|
|
84
|
+
}}
|
|
85
|
+
/>
|
|
86
|
+
</View>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// AppKit returns null here, before adapter/device acquisition.
|
|
91
|
+
const gpu = getGPU()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The AppKit backend for 2D, WebGL, and WebGPU remains deferred until a concrete
|
|
95
|
+
consumer needs one and the implementation is approved. Native desktop shader
|
|
96
|
+
effects remain unsupported. A DOM webview uses the separate web implementation.
|
|
97
|
+
|
|
54
98
|
Per-target limits are recorded in
|
|
55
99
|
[known limits](../../docs/verify/known-limits.md). Exercised by
|
|
56
100
|
[`CanvasDemo`](../demos/src/CanvasDemo.tsrx) (including a WGSL path).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octane-xplat/canvas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Canvas/GPU surface for Octane xplat — web <canvas> + @nativescript/canvas (2D, WebGL/WebGL2, WebGPU/WGSL)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"canvas",
|
|
@@ -23,17 +23,19 @@
|
|
|
23
23
|
"directory": "packages/canvas"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
|
-
"dist",
|
|
27
26
|
"types",
|
|
28
|
-
"src"
|
|
27
|
+
"src",
|
|
28
|
+
"!src/**/*.test.*",
|
|
29
|
+
"!src/**/*.spec.*"
|
|
29
30
|
],
|
|
30
31
|
"type": "module",
|
|
31
32
|
"exports": {
|
|
32
33
|
".": {
|
|
33
34
|
"types": "./types/index.d.ts",
|
|
34
|
-
"web": "./
|
|
35
|
-
"
|
|
36
|
-
"
|
|
35
|
+
"web": "./src/index.web.ts",
|
|
36
|
+
"macos": "./src/index.macos.ts",
|
|
37
|
+
"native": "./src/index.ts",
|
|
38
|
+
"default": "./src/index.ts"
|
|
37
39
|
}
|
|
38
40
|
},
|
|
39
41
|
"publishConfig": {
|
|
@@ -43,17 +45,19 @@
|
|
|
43
45
|
"@nativescript/canvas": "3.0.0-alpha.15"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
|
-
"@nativescript-community/octane": "0.2.
|
|
48
|
+
"@nativescript-community/octane": "0.2.5",
|
|
47
49
|
"@nativescript/core": "9.1.3",
|
|
50
|
+
"@octane-xplat/macos-renderer": "0.15.0",
|
|
48
51
|
"@octanejs/vite-plugin": "0.1.61",
|
|
49
52
|
"octane": "0.11.0",
|
|
50
|
-
"tsrx-typegen": "0.
|
|
53
|
+
"tsrx-typegen": "0.3.0",
|
|
51
54
|
"typescript": "5.9.3",
|
|
52
55
|
"vite": "8.3.0"
|
|
53
56
|
},
|
|
54
57
|
"peerDependencies": {
|
|
55
58
|
"@nativescript-community/octane": ">=0.2.1 <1",
|
|
56
59
|
"@nativescript/core": ">=9.1.0 <10",
|
|
60
|
+
"@octane-xplat/macos-renderer": "0.15.0",
|
|
57
61
|
"octane": ">=0.6.3 <1"
|
|
58
62
|
},
|
|
59
63
|
"peerDependenciesMeta": {
|
|
@@ -62,12 +66,15 @@
|
|
|
62
66
|
},
|
|
63
67
|
"@nativescript/core": {
|
|
64
68
|
"optional": true
|
|
69
|
+
},
|
|
70
|
+
"@octane-xplat/macos-renderer": {
|
|
71
|
+
"optional": true
|
|
65
72
|
}
|
|
66
73
|
},
|
|
67
74
|
"scripts": {
|
|
68
|
-
"build": "vite build && vite build --mode native && pnpm typegen && node ../../scripts/check-native-dist.mjs",
|
|
69
75
|
"typegen": "tsc -p tsconfig.types.json",
|
|
70
76
|
"test:packed": "node tests/packed-consumer.mjs",
|
|
77
|
+
"test:macos-runtime": "node ../../scripts/probe.mjs run tests/unsupported.macos.tsrx --target macos --deps @octane-xplat/canvas",
|
|
71
78
|
"pack:check": "tsrx-typegen --pack-check"
|
|
72
79
|
}
|
|
73
80
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @jsxImportSource @octane-xplat/macos-renderer */
|
|
2
|
+
import { useEffect } from 'octane';
|
|
3
|
+
import type { CanvasContextKind, CanvasProps } from './props';
|
|
4
|
+
|
|
5
|
+
/** AppKit mounts a neutral frame. No drawing surface or GPU is created. */
|
|
6
|
+
export function Canvas(props: CanvasProps) @{
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
// Preserve deferred acquisition without pretending this is a native view.
|
|
9
|
+
const canvas = Object.freeze({
|
|
10
|
+
getContext: (_kind: CanvasContextKind, _options?: any): null => null,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
props.onReady?.({ canvas, context: null });
|
|
14
|
+
}, []);
|
|
15
|
+
|
|
16
|
+
<gridlayout
|
|
17
|
+
id={props.id}
|
|
18
|
+
className={props.className}
|
|
19
|
+
style={props.style}
|
|
20
|
+
width={props.width}
|
|
21
|
+
height={props.height}
|
|
22
|
+
/>;
|
|
23
|
+
}
|
package/src/Canvas.web.tsrx
CHANGED
|
@@ -1,23 +1,39 @@
|
|
|
1
|
+
import { useMemo, useRef } from 'octane';
|
|
1
2
|
import type { CanvasProps } from './props';
|
|
2
3
|
|
|
3
4
|
/** Canvas — a plain <canvas>. `onReady` fires at mount with the element
|
|
4
5
|
* and the resolved context. */
|
|
5
6
|
export function Canvas(props: CanvasProps) @{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
ref={(el: HTMLCanvasElement | null) => {
|
|
7
|
+
// Keep the element callback referentially stable — a fresh closure each
|
|
8
|
+
// render makes the web renderer detach/reattach it, refiring onReady.
|
|
9
|
+
const propsRef = useRef(props);
|
|
10
|
+
propsRef.current = props;
|
|
11
|
+
const canvasRef = useMemo(
|
|
12
|
+
() => (el: HTMLCanvasElement | null) => {
|
|
13
13
|
if (!el) {
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
propsRef.current.onReady?.({
|
|
18
18
|
canvas: el,
|
|
19
|
-
context:
|
|
19
|
+
context: propsRef.current.context
|
|
20
|
+
? el.getContext(propsRef.current.context)
|
|
21
|
+
: null,
|
|
20
22
|
});
|
|
23
|
+
},
|
|
24
|
+
[],
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
<canvas
|
|
28
|
+
id={props.id}
|
|
29
|
+
className={props.className}
|
|
30
|
+
style={{
|
|
31
|
+
width: typeof props.width === 'string' ? props.width : undefined,
|
|
32
|
+
height: typeof props.height === 'string' ? props.height : undefined,
|
|
33
|
+
...props.style,
|
|
21
34
|
}}
|
|
35
|
+
width={typeof props.width === 'number' ? props.width : undefined}
|
|
36
|
+
height={typeof props.height === 'number' ? props.height : undefined}
|
|
37
|
+
ref={canvasRef}
|
|
22
38
|
/>
|
|
23
39
|
}
|
package/src/gpu.macos.ts
ADDED
package/src/props.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export type CanvasContextKind = '2d' | 'webgl' | 'webgl2' | 'webgpu' | 'bitmaprenderer'
|
|
2
2
|
|
|
3
3
|
export interface CanvasReady {
|
|
4
|
-
/** HTMLCanvasElement on web, the plugin's Canvas view on
|
|
5
|
-
*
|
|
4
|
+
/** HTMLCanvasElement on web, the plugin's Canvas view on iOS/Android.
|
|
5
|
+
* AppKit supplies an unavailable handle whose `getContext()` always
|
|
6
|
+
* returns null; it is not a native drawing surface. */
|
|
6
7
|
canvas: any
|
|
7
8
|
/** The resolved context for the `context` prop, or null when that
|
|
8
9
|
* kind is unsupported/unavailable. WebGPU still needs a device —
|
|
@@ -17,8 +18,10 @@ export interface CanvasProps {
|
|
|
17
18
|
/** Context kind resolved before `onReady` fires. Omit to defer
|
|
18
19
|
* `getContext` to user code (only one kind per canvas — call once). */
|
|
19
20
|
context?: CanvasContextKind
|
|
20
|
-
/** Web: after mount.
|
|
21
|
-
*
|
|
21
|
+
/** Web: after mount. iOS/Android: the plugin's `ready` event (earlier
|
|
22
|
+
* `getContext` calls can return null). AppKit: after the neutral frame
|
|
23
|
+
* mounts, with context null. This callback does not guarantee drawing
|
|
24
|
+
* or GPU readiness; check context or call canvas.getContext first. */
|
|
22
25
|
onReady?: (ready: CanvasReady) => void
|
|
23
26
|
/** Numeric values map to the element's width/height — on web that is
|
|
24
27
|
* the canvas *drawing buffer* size (pair with style for display
|
package/types/index.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ import type { CanvasProps } from './props.js'
|
|
|
7
7
|
export declare const Canvas: UniversalComponent<CanvasProps>
|
|
8
8
|
|
|
9
9
|
/** Returns the WebGPU entry point — `navigator.gpu` on web, the plugin's
|
|
10
|
-
* GPU shim on
|
|
10
|
+
* GPU shim on iOS/Android — or null where WebGPU is unavailable.
|
|
11
|
+
* Native AppKit always returns null. */
|
|
11
12
|
export declare function getGPU(): any
|
|
12
13
|
|
|
13
14
|
export type { CanvasProps, CanvasContextKind, CanvasReady } from './props.js'
|
package/types/props.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export type CanvasContextKind = '2d' | 'webgl' | 'webgl2' | 'webgpu' | 'bitmaprenderer';
|
|
2
2
|
export interface CanvasReady {
|
|
3
|
-
/** HTMLCanvasElement on web, the plugin's Canvas view on
|
|
4
|
-
*
|
|
3
|
+
/** HTMLCanvasElement on web, the plugin's Canvas view on iOS/Android.
|
|
4
|
+
* AppKit supplies an unavailable handle whose `getContext()` always
|
|
5
|
+
* returns null; it is not a native drawing surface. */
|
|
5
6
|
canvas: any;
|
|
6
7
|
/** The resolved context for the `context` prop, or null when that
|
|
7
8
|
* kind is unsupported/unavailable. WebGPU still needs a device —
|
|
@@ -15,8 +16,10 @@ export interface CanvasProps {
|
|
|
15
16
|
/** Context kind resolved before `onReady` fires. Omit to defer
|
|
16
17
|
* `getContext` to user code (only one kind per canvas — call once). */
|
|
17
18
|
context?: CanvasContextKind;
|
|
18
|
-
/** Web: after mount.
|
|
19
|
-
*
|
|
19
|
+
/** Web: after mount. iOS/Android: the plugin's `ready` event (earlier
|
|
20
|
+
* `getContext` calls can return null). AppKit: after the neutral frame
|
|
21
|
+
* mounts, with context null. This callback does not guarantee drawing
|
|
22
|
+
* or GPU readiness; check context or call canvas.getContext first. */
|
|
20
23
|
onReady?: (ready: CanvasReady) => void;
|
|
21
24
|
/** Numeric values map to the element's width/height — on web that is
|
|
22
25
|
* the canvas *drawing buffer* size (pair with style for display
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { defineUniversalComponent, registerElement, universalPlan, universalValue } from "@nativescript-community/octane";
|
|
2
|
-
import { Canvas } from "@nativescript/canvas";
|
|
3
|
-
//#region src/Canvas.tsrx
|
|
4
|
-
var __octaneUniversalPlan0 = universalPlan("nativescript", {
|
|
5
|
-
"kind": "host",
|
|
6
|
-
"type": "nscanvas",
|
|
7
|
-
"bindings": [
|
|
8
|
-
["id", 0],
|
|
9
|
-
["className", 1],
|
|
10
|
-
["style", 2],
|
|
11
|
-
["width", 3],
|
|
12
|
-
["height", 4],
|
|
13
|
-
["onReady", 5]
|
|
14
|
-
]
|
|
15
|
-
});
|
|
16
|
-
registerElement("nscanvas", Canvas);
|
|
17
|
-
var Canvas$1 = defineUniversalComponent("nativescript", function Canvas(props) {
|
|
18
|
-
const ready = (event) => {
|
|
19
|
-
const canvas = event.object;
|
|
20
|
-
props.onReady?.({
|
|
21
|
-
canvas,
|
|
22
|
-
context: props.context ? canvas.getContext(props.context) : null
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
|
-
return universalValue(__octaneUniversalPlan0, [
|
|
26
|
-
props.id,
|
|
27
|
-
props.className,
|
|
28
|
-
props.style,
|
|
29
|
-
props.width,
|
|
30
|
-
props.height,
|
|
31
|
-
ready
|
|
32
|
-
]);
|
|
33
|
-
}, { "module": "@nativescript-community/octane" });
|
|
34
|
-
//#endregion
|
|
35
|
-
export { Canvas$1 as Canvas };
|
package/dist/native/gpu.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { GPU } from "@nativescript/canvas";
|
|
2
|
-
//#region src/gpu.ts
|
|
3
|
-
/** getGPU — returns the plugin's GPU shim (wgpu over Metal/Vulkan). Same
|
|
4
|
-
* spec-shaped surface as web's `navigator.gpu`: `requestAdapter()` +
|
|
5
|
-
* `getPreferredCanvasFormat()`. */
|
|
6
|
-
function getGPU() {
|
|
7
|
-
return new GPU();
|
|
8
|
-
}
|
|
9
|
-
//#endregion
|
|
10
|
-
export { getGPU };
|
package/dist/native/index.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { __s, bag7, clone, queueRefAttach, queueRefDetach, setStyle, template } from "octane";
|
|
2
|
-
import { replaceRef, setClassNameIfChanged, setPlainAttributeIfChanged } from "octane/internal/client";
|
|
3
|
-
//#region src/Canvas.web.tsrx
|
|
4
|
-
var _t$0 = /* @__PURE__ */ template("<canvas></canvas>");
|
|
5
|
-
var _rm$0 = [
|
|
6
|
-
"r",
|
|
7
|
-
"g",
|
|
8
|
-
"b"
|
|
9
|
-
];
|
|
10
|
-
var Canvas = /* @__PURE__ */ __s(function Canvas(props, __s, __extra) {
|
|
11
|
-
let _b = __s.slots[0];
|
|
12
|
-
if (_b === void 0) {
|
|
13
|
-
let _m6;
|
|
14
|
-
const _root = clone(_t$0);
|
|
15
|
-
queueRefAttach(__s, _m6 = (el) => {
|
|
16
|
-
if (!el) return;
|
|
17
|
-
props.onReady?.({
|
|
18
|
-
canvas: el,
|
|
19
|
-
context: props.context ? el.getContext(props.context) : null
|
|
20
|
-
});
|
|
21
|
-
}, _root);
|
|
22
|
-
(__s.cleanups ??= []).push(() => _b && queueRefDetach(_b.g, _b.b));
|
|
23
|
-
_b = bag7(__s, _root, void 0, _root, void 0, void 0, void 0, void 0, _m6);
|
|
24
|
-
__s.refFields = _rm$0;
|
|
25
|
-
} else {
|
|
26
|
-
const _r = (el) => {
|
|
27
|
-
if (!el) return;
|
|
28
|
-
props.onReady?.({
|
|
29
|
-
canvas: el,
|
|
30
|
-
context: props.context ? el.getContext(props.context) : null
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
if (_r !== _b.g) _b.g = replaceRef(__s, _b.g, _r, _b.b);
|
|
34
|
-
}
|
|
35
|
-
_b.a = setPlainAttributeIfChanged(props.id, _b.a, _b.b, "id");
|
|
36
|
-
_b.c = setClassNameIfChanged(props.className, _b.c, _b.b);
|
|
37
|
-
{
|
|
38
|
-
const _v = props.style;
|
|
39
|
-
if (_b.d !== _v) {
|
|
40
|
-
setStyle(_b.b, _v, _b.d);
|
|
41
|
-
_b.d = _v;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
_b.e = setPlainAttributeIfChanged(typeof props.width === "number" ? props.width : void 0, _b.e, _b.b, "width");
|
|
45
|
-
_b.f = setPlainAttributeIfChanged(typeof props.height === "number" ? props.height : void 0, _b.f, _b.b, "height");
|
|
46
|
-
});
|
|
47
|
-
//#endregion
|
|
48
|
-
export { Canvas };
|
package/dist/web/gpu.web.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
//#region src/gpu.web.ts
|
|
2
|
-
/** getGPU — returns the WebGPU entry point (`navigator.gpu`) or null when
|
|
3
|
-
* WebGPU is unavailable (insecure context, unsupported browser). The
|
|
4
|
-
* returned object is spec-shaped: `requestAdapter()` +
|
|
5
|
-
* `getPreferredCanvasFormat()`. */
|
|
6
|
-
function getGPU() {
|
|
7
|
-
return globalThis.navigator?.gpu ?? null;
|
|
8
|
-
}
|
|
9
|
-
//#endregion
|
|
10
|
-
export { getGPU };
|
package/dist/web/index.js
DELETED