lecodes-sdk 1.2.0 → 2.0.1
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 +5 -2
- package/dist/editor.d.ts +12 -0
- package/dist/global.d.ts +4 -8
- package/dist/host.d.ts +2 -3
- package/dist/types/animate/tween/Animation.d.ts +0 -3
- package/dist/types/animate/tween/animateValue.d.ts +4 -2
- package/dist/types/animate/tween/easing.d.ts +8 -0
- package/dist/types/animate/tween/spec.d.ts +15 -7
- package/dist/types/audio/audio.d.ts +2 -1
- package/dist/types/canvas/Canvas.d.ts +40 -108
- package/dist/types/canvas/gen/cssColor.d.ts +17 -0
- package/dist/types/canvas/gen/recorder.d.ts +118 -0
- package/dist/types/canvas/gen/spec.d.ts +144 -0
- package/dist/types/core/color.d.ts +3 -1
- package/dist/types/core/pins.d.ts +18 -0
- package/dist/types/g2/Node2D.d.ts +5 -8
- package/dist/types/g2/Scene2D.d.ts +6 -2
- package/dist/types/gl/Foliage.d.ts +30 -7
- package/dist/types/gl/Light.d.ts +8 -0
- package/dist/types/gl/Lightmap.d.ts +13 -2
- package/dist/types/gl/Material.d.ts +17 -3
- package/dist/types/gl/Model.d.ts +6 -2
- package/dist/types/gl/Node.d.ts +3 -6
- package/dist/types/gl/Scene.d.ts +41 -13
- package/dist/types/gl/Texture.d.ts +1 -1
- package/dist/types/gl/animation/Locomotion.d.ts +8 -1
- package/dist/types/inject.d.ts +11 -11
- package/dist/types/inject.editor.d.ts +1 -0
- package/dist/types/net/core.d.ts +7 -0
- package/dist/types/plugin.d.ts +76 -0
- package/dist/types/plugins/gen/camera/sdk/camera.d.ts +24 -0
- package/dist/types/plugins/gen/camera/sdk/camera.gen.d.ts +25 -0
- package/dist/types/plugins/{geolocation.d.ts → gen/geolocation/sdk/geolocation.d.ts} +2 -20
- package/dist/types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts +31 -0
- package/dist/types/plugins/{map.d.ts → gen/map/sdk/map.d.ts} +9 -50
- package/dist/types/plugins/gen/map/sdk/map.gen.d.ts +53 -0
- package/dist/types/plugins/gen/push/sdk/push.d.ts +23 -0
- package/dist/types/plugins/gen/push/sdk/push.gen.d.ts +35 -0
- package/dist/types/plugins/{qr.d.ts → gen/qr-scanner/sdk/qr-scanner.d.ts} +2 -3
- package/dist/types/plugins/gen/qr-scanner/sdk/qr-scanner.gen.d.ts +15 -0
- package/dist/types/runtime/app.d.ts +9 -2
- package/dist/types/runtime/fetch.d.ts +2 -0
- package/dist/types/runtime/input.d.ts +1 -1
- package/dist/types/runtime/media.d.ts +6 -10
- package/dist/types/runtime/misc.d.ts +4 -1
- package/dist/types/runtime/net.d.ts +3 -2
- package/dist/types/runtime/touch.d.ts +32 -0
- package/dist/types/scene/defineScene.d.ts +43 -2
- package/dist/types/scene/editor.d.ts +52 -0
- package/dist/types/scene/gizmos.d.ts +7 -4
- package/dist/types/ui/NativeView.d.ts +6 -4
- package/dist/types/ui/UI.d.ts +1 -1
- package/dist/types/ui/UIBottomSheet.d.ts +6 -12
- package/dist/types/ui/UIButton.d.ts +12 -14
- package/dist/types/ui/UIContainer.d.ts +0 -6
- package/dist/types/ui/UIImage.d.ts +1 -4
- package/dist/types/ui/UIInput.d.ts +8 -24
- package/dist/types/ui/UIModal.d.ts +0 -2
- package/dist/types/ui/UINode.d.ts +70 -56
- package/dist/types/ui/UIPager.d.ts +28 -27
- package/dist/types/ui/UIPopover.d.ts +0 -2
- package/dist/types/ui/UIScreen.d.ts +12 -17
- package/dist/types/ui/UIScrollable.d.ts +1 -4
- package/dist/types/ui/UIText.d.ts +0 -2
- package/dist/types/ui/UIVideo.d.ts +3 -5
- package/dist/types/ui/UIVirtualizedList.d.ts +14 -16
- package/dist/types/ui/UIWidget.d.ts +10 -9
- package/dist/types/ui/colorKeys.gen.d.ts +9 -0
- package/dist/types/ui/presentable.d.ts +46 -32
- package/dist/types/ui/router.d.ts +18 -7
- package/dist/types/ui/styleColor.d.ts +1 -0
- package/dist/types/ui/transitions.d.ts +18 -0
- package/dist/types/ui/tree.d.ts +75 -0
- package/dist/types/version.d.ts +10 -0
- package/dist/types.json +1 -1
- package/package.json +12 -3
- package/prompts/2d.md +2 -6
- package/prompts/3d.md +1 -5
- package/prompts/README.md +1 -1
- package/prompts/canvas.md +9 -8
- package/prompts/compose.ts +1 -1
- package/prompts/core.md +3 -3
- package/prompts/design.md +1 -1
- package/prompts/dist/2d-game.md +473 -239
- package/prompts/dist/3d-app.md +553 -205
- package/prompts/dist/ar-app.md +435 -202
- package/prompts/dist/design.md +113 -95
- package/prompts/dist/ui-app.md +386 -170
- package/prompts/ui-design.md +2 -3
- package/prompts/ui.md +45 -37
- package/src/animate/tween/Animation.ts +34 -150
- package/src/animate/tween/Timeline.ts +175 -175
- package/src/animate/tween/animateValue.ts +6 -3
- package/src/animate/tween/easing.ts +10 -3
- package/src/animate/tween/spec.ts +41 -15
- package/src/audio/Sound.ts +3 -3
- package/src/audio/audio.ts +2 -1
- package/src/bridges/2d.d.ts +317 -0
- package/src/bridges/app.d.ts +91 -0
- package/src/bridges/audio.d.ts +97 -0
- package/src/bridges/canvas.d.ts +79 -0
- package/src/bridges/device.d.ts +72 -0
- package/src/bridges/fetch.d.ts +80 -0
- package/src/bridges/files.d.ts +70 -0
- package/src/bridges/gl.d.ts +1133 -0
- package/src/bridges/input.d.ts +72 -0
- package/src/bridges/media.d.ts +55 -0
- package/src/bridges/nav.d.ts +71 -0
- package/src/bridges/net.d.ts +52 -0
- package/src/bridges/service.d.ts +52 -0
- package/src/bridges/socket.d.ts +31 -0
- package/src/bridges/storage.d.ts +33 -0
- package/src/bridges/tree.d.ts +301 -0
- package/src/bridges/types.d.ts +49 -0
- package/src/canvas/Canvas.ts +114 -159
- package/src/canvas/gen/cssColor.ts +224 -0
- package/src/canvas/gen/recorder.ts +212 -0
- package/src/canvas/gen/spec.ts +201 -0
- package/src/chisel.ts +193 -0
- package/src/compile/assetMacro.ts +1 -1
- package/src/compile/bundler.ts +11 -2
- package/src/compile/compileProject.ts +43 -4
- package/src/compile/fontMacro.ts +3 -4
- package/src/compile/header.ts +26 -5
- package/src/compile/index.ts +3 -1
- package/src/compile/liteMaterial.ts +1 -1
- package/src/compile/sceneEditor.ts +11 -26
- package/src/core/color.ts +73 -30
- package/src/core/pins.ts +51 -0
- package/src/core/signals.ts +8 -1
- package/src/g2/CharacterController2D.ts +3 -3
- package/src/g2/Node2D.ts +57 -39
- package/src/g2/Physics2D.ts +2 -2
- package/src/g2/Scene2D.ts +35 -23
- package/src/g2/Texture2D.ts +1 -1
- package/src/g2/loop.ts +4 -4
- package/src/gl/CameraPlace.ts +52 -52
- package/src/gl/Foliage.ts +72 -17
- package/src/gl/Geometry.ts +1 -2
- package/src/gl/Light.ts +10 -0
- package/src/gl/Lightmap.ts +45 -29
- package/src/gl/Material.ts +95 -51
- package/src/gl/Mesh.ts +120 -120
- package/src/gl/Model.ts +21 -16
- package/src/gl/Node.ts +91 -24
- package/src/gl/Particles.ts +1 -1
- package/src/gl/Scene.ts +100 -44
- package/src/gl/Texture.ts +8 -7
- package/src/gl/animation/AnimationClip.ts +1 -1
- package/src/gl/animation/DynamicBone.ts +482 -482
- package/src/gl/animation/Locomotion.ts +8 -3
- package/src/gl/nav/NavMesh.ts +3 -4
- package/src/gl/physics/Physics.ts +2 -2
- package/src/gl/physics/physicsEvents.ts +3 -3
- package/src/gl/scenarios.ts +291 -291
- package/src/gl/terrain/Terrain.ts +4 -5
- package/src/gl/touch.ts +14 -15
- package/src/host.d.ts +2 -3
- package/src/inject.editor.ts +7 -0
- package/src/inject.ts +13 -16
- package/src/net/core.ts +6 -5
- package/src/net/index.ts +1 -1
- package/src/net/replication.ts +1 -1
- package/src/plugin.ts +191 -0
- package/src/plugins/gen/camera/contract.d.ts +27 -0
- package/src/plugins/gen/camera/sdk/camera.gen.ts +46 -0
- package/src/plugins/gen/camera/sdk/camera.ts +57 -0
- package/src/plugins/gen/geolocation/contract.d.ts +50 -0
- package/src/plugins/gen/geolocation/sdk/geolocation.gen.ts +54 -0
- package/src/plugins/{geolocation.ts → gen/geolocation/sdk/geolocation.ts} +22 -43
- package/src/plugins/gen/map/contract.d.ts +144 -0
- package/src/plugins/gen/map/sdk/map.gen.ts +88 -0
- package/src/plugins/{map.ts → gen/map/sdk/map.ts} +68 -102
- package/src/plugins/gen/push/contract.d.ts +61 -0
- package/src/plugins/gen/push/sdk/push.gen.ts +60 -0
- package/src/plugins/gen/push/sdk/push.ts +105 -0
- package/src/plugins/gen/qr-scanner/contract.d.ts +16 -0
- package/src/plugins/gen/qr-scanner/sdk/qr-scanner.gen.ts +29 -0
- package/src/plugins/gen/qr-scanner/sdk/qr-scanner.ts +52 -0
- package/src/plugins/permission.ts +5 -4
- package/src/runtime/app.ts +20 -9
- package/src/runtime/appEvents.ts +5 -4
- package/src/runtime/channel.ts +18 -15
- package/src/runtime/clipboard.ts +4 -3
- package/src/runtime/datetime.ts +2 -1
- package/src/runtime/device.ts +17 -15
- package/src/runtime/fetch.ts +30 -20
- package/src/runtime/files.ts +16 -15
- package/src/runtime/input.ts +12 -10
- package/src/runtime/media.ts +50 -46
- package/src/runtime/misc.ts +7 -3
- package/src/runtime/net.ts +8 -7
- package/src/runtime/rpc.ts +1 -3
- package/src/runtime/service.ts +19 -14
- package/src/runtime/share.ts +4 -3
- package/src/runtime/storage.ts +6 -4
- package/src/runtime/touch.ts +32 -0
- package/src/scene/defineScene.ts +61 -365
- package/src/scene/editor.ts +408 -0
- package/src/scene/editorPlugins.ts +3 -3
- package/src/scene/gizmos.ts +15 -9
- package/src/server/db/marci/query.ts +1 -1
- package/src/server/host.ts +1 -1
- package/src/server/runtime.ts +1 -1
- package/src/ui/NativeView.ts +72 -25
- package/src/ui/UI.ts +3 -3
- package/src/ui/UIBottomSheet.ts +16 -17
- package/src/ui/UIButton.ts +54 -16
- package/src/ui/UIContainer.ts +0 -6
- package/src/ui/UIImage.ts +34 -30
- package/src/ui/UIInput.ts +29 -37
- package/src/ui/UIModal.ts +1 -3
- package/src/ui/UINode.ts +347 -297
- package/src/ui/UIPager.ts +93 -78
- package/src/ui/UIPopover.ts +0 -2
- package/src/ui/UIScreen.ts +41 -36
- package/src/ui/UIScrollable.ts +19 -13
- package/src/ui/UISpacer.ts +1 -1
- package/src/ui/UITabs.ts +8 -6
- package/src/ui/UIText.ts +7 -17
- package/src/ui/UIVideo.ts +30 -27
- package/src/ui/UIVirtualizedList.ts +58 -59
- package/src/ui/UIWidget.ts +38 -18
- package/src/ui/colorKeys.gen.ts +37 -0
- package/src/ui/fonts.ts +2 -2
- package/src/ui/presentable.ts +59 -42
- package/src/ui/router.ts +52 -35
- package/src/ui/styleColor.ts +56 -0
- package/src/ui/theme.ts +7 -6
- package/src/ui/transitions.ts +249 -0
- package/src/ui/tree.ts +346 -0
- package/src/version.ts +24 -0
- package/tests/helpers/engineWorld.ts +11 -0
- package/tests/helpers/fakeTree.ts +353 -0
- package/tests/helpers/hostStubs.ts +31 -0
- package/tests/helpers/index.ts +14 -0
- package/tests/helpers/memoryMarci.ts +124 -0
- package/tests/helpers/phases.ts +23 -0
- package/tests/helpers/preload.ts +18 -0
- package/tests/helpers/stubApp.ts +2 -0
- package/tests/helpers/stubDevice.ts +2 -0
- package/tests/helpers/stubFetch.ts +2 -0
- package/tests/helpers/stubInput.ts +2 -0
- package/dist/inject.js +0 -4629
- package/dist/types/core/registry.d.ts +0 -7
- package/dist/types/plugins/camera.d.ts +0 -25
- package/dist/types/plugins/push.d.ts +0 -46
- package/src/bridges.d.ts +0 -1769
- package/src/compile/__tests__/assetIconMacro.test.ts +0 -219
- package/src/compile/__tests__/assetMacro.test.ts +0 -100
- package/src/compile/__tests__/assetName.test.ts +0 -55
- package/src/compile/__tests__/compile.test.ts +0 -310
- package/src/compile/__tests__/detectEntry.test.ts +0 -151
- package/src/compile/__tests__/fontMacro.test.ts +0 -199
- package/src/compile/__tests__/serverSplit.test.ts +0 -27
- package/src/core/__tests__/stateMachine.test.ts +0 -132
- package/src/core/registry.ts +0 -23
- package/src/plugins/camera.ts +0 -81
- package/src/plugins/push.ts +0 -132
- package/src/plugins/qr.ts +0 -73
package/src/runtime/media.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
// Audio / video playback over the host
|
|
2
|
-
//
|
|
3
|
-
// when the Texture type exists — see gl/.
|
|
1
|
+
// Audio / video playback over the host's `_creatorMedia` bridge (absent on hosts without media
|
|
2
|
+
// players — the players are inert there). The listener boilerplate is folded into the shared Emitter.
|
|
4
3
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// Ownership (owned handles, docs/plans/hosts-unification-plan.md phase 10): a player is an owned resource
|
|
5
|
+
// — `_h` is the handle the runtime returned; the runtime counts a PLAYING player as natively owned.
|
|
6
|
+
// So `new AudioPlayer(src).play()` in a handler, reference dropped, plays to its end and is released
|
|
7
|
+
// then; a paused player you stop referencing is released at once. There is nothing to dispose. The
|
|
8
|
+
// end-of-playback report comes by id through ONE emitter per world; a playing player is pinned so
|
|
9
|
+
// the report finds it.
|
|
9
10
|
|
|
10
11
|
import { Emitter } from "../core/events"
|
|
12
|
+
import { Pins } from "../core/pins"
|
|
11
13
|
import { Texture } from "../gl/Texture"
|
|
12
14
|
|
|
13
15
|
type MediaEvents = {
|
|
@@ -17,83 +19,84 @@ type MediaEvents = {
|
|
|
17
19
|
completed: () => void
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
/** The players native owns right now (playing), by id — what an end-of-playback report resolves to. */
|
|
23
|
+
const players = new Pins<MediaPlayer>()
|
|
24
|
+
/** The host's media table, or undefined on a host without one (`@optional`: the global is absent). */
|
|
25
|
+
const media = (): typeof _creatorMedia | undefined => (typeof _creatorMedia !== "undefined" ? _creatorMedia : undefined)
|
|
26
|
+
let emitterInstalled = false
|
|
27
|
+
const ensureEmitter = (): void => {
|
|
28
|
+
const m = media()
|
|
29
|
+
if (emitterInstalled || !m || typeof m.setEmitter !== "function") return
|
|
30
|
+
emitterInstalled = true
|
|
31
|
+
m.setEmitter((id) => { players.get(id)?._finished() })
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
abstract class MediaPlayer extends Emitter<MediaEvents> {
|
|
21
|
-
|
|
35
|
+
/** @internal The player's owned handle (`_h.id` = the host player id; -1 = no host player). */
|
|
36
|
+
_h: Handle = { id: -1 }
|
|
22
37
|
protected _src = ""
|
|
23
38
|
private _playing = false
|
|
24
39
|
private _loop = false
|
|
25
40
|
private _volume = 1
|
|
26
|
-
private _disposed = false
|
|
27
|
-
|
|
28
|
-
// Every host-touching operation runs through this so a disposed player can never address a freed
|
|
29
|
-
// (and possibly reused) host slot.
|
|
30
|
-
private _assertAlive(): void {
|
|
31
|
-
if (this._disposed) throw new Error("MediaPlayer has been disposed")
|
|
32
|
-
}
|
|
33
41
|
|
|
34
42
|
play(): void { this.playing = true }
|
|
35
43
|
pause(): void { this.playing = false }
|
|
44
|
+
/** Pause and rewind to the start. */
|
|
45
|
+
stop(): void {
|
|
46
|
+
this.playing = false
|
|
47
|
+
media()?.setTime?.(this._h.id, 0)
|
|
48
|
+
}
|
|
36
49
|
|
|
37
50
|
get playing(): boolean { return this._playing }
|
|
38
51
|
set playing(value: boolean) {
|
|
39
|
-
this._assertAlive()
|
|
40
52
|
this._playing = value
|
|
41
|
-
|
|
53
|
+
media()?.setPlaying(this._h.id, value)
|
|
54
|
+
if (value) players.pin(this) // playing: native owns it, the end report must find it
|
|
55
|
+
else players.unpin(this._h.id)
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
get volume(): number { return this._volume }
|
|
45
59
|
set volume(value: number) {
|
|
46
|
-
this._assertAlive()
|
|
47
60
|
this._volume = value
|
|
48
|
-
|
|
61
|
+
media()?.setVolume(this._h.id, value)
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
get loop(): boolean { return this._loop }
|
|
52
65
|
set loop(value: boolean) {
|
|
53
|
-
this._assertAlive()
|
|
54
66
|
this._loop = value
|
|
55
|
-
|
|
67
|
+
media()?.setLoop(this._h.id, value)
|
|
56
68
|
}
|
|
57
69
|
|
|
58
70
|
/** Current playback position, in seconds. Settable to seek. */
|
|
59
|
-
get time(): number {
|
|
60
|
-
set time(value: number) {
|
|
71
|
+
get time(): number { return media()?.time?.(this._h.id) ?? 0 }
|
|
72
|
+
set time(value: number) { media()?.setTime?.(this._h.id, value) }
|
|
61
73
|
|
|
62
74
|
/** Total media length in seconds (0 until metadata has loaded). */
|
|
63
|
-
get duration(): number {
|
|
75
|
+
get duration(): number { return media()?.duration?.(this._h.id) ?? 0 }
|
|
64
76
|
|
|
65
|
-
/**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Release the underlying host media resource (decoder, network, buffers) immediately and detach
|
|
70
|
-
* all listeners. Idempotent. Any further use of the player throws.
|
|
71
|
-
*/
|
|
72
|
-
dispose(): void {
|
|
73
|
-
if (this._disposed) return
|
|
74
|
-
this._disposed = true
|
|
75
|
-
this._playing = false
|
|
76
|
-
this.clearListeners()
|
|
77
|
-
_creatorUtils.removeMediaPlayer(this._id)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** @internal — the host calls this when a play-through finishes. */
|
|
81
|
-
protected _finished(): void {
|
|
82
|
-
if (this._disposed) return
|
|
77
|
+
/** @internal — the runtime reports a play-through end. */
|
|
78
|
+
_finished(): void {
|
|
83
79
|
if (this._loop) {
|
|
84
80
|
this.dispatch("loopReached")
|
|
85
81
|
} else {
|
|
86
82
|
this._playing = false
|
|
83
|
+
players.unpin(this._h.id)
|
|
87
84
|
this.dispatch("completed")
|
|
88
85
|
}
|
|
89
86
|
}
|
|
87
|
+
|
|
88
|
+
/** @deprecated There is nothing to dispose — a player the app stops referencing is released by
|
|
89
|
+
* the runtime (a playing one at its end). Kept as `stop()` so old code still silences the player;
|
|
90
|
+
* call `stop()` / `pause()` instead. */
|
|
91
|
+
dispose(): void { this.stop() }
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
export class AudioPlayer extends MediaPlayer {
|
|
93
95
|
constructor(src?: string) {
|
|
94
96
|
super()
|
|
95
97
|
this._src = src ?? ""
|
|
96
|
-
|
|
98
|
+
ensureEmitter()
|
|
99
|
+
this._h = media()?.createAudio(this._src) ?? { id: -1 }
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
|
|
@@ -101,11 +104,12 @@ export class VideoPlayer extends MediaPlayer {
|
|
|
101
104
|
constructor(src?: string) {
|
|
102
105
|
super()
|
|
103
106
|
this._src = src ?? ""
|
|
104
|
-
|
|
107
|
+
ensureEmitter()
|
|
108
|
+
this._h = media()?.createVideo(this._src) ?? { id: -1 }
|
|
105
109
|
}
|
|
106
110
|
|
|
107
|
-
/** A 3D Texture that samples this video (e.g. for a Material.video()). */
|
|
111
|
+
/** A 3D Texture that samples this video (e.g. for a Material.video()). Owned by the player. */
|
|
108
112
|
get texture(): Texture {
|
|
109
|
-
return new Texture(0, 0, _creator.createMediaPlayerTexture(this.
|
|
113
|
+
return new Texture(0, 0, _creator.createMediaPlayerTexture(this._h.id))
|
|
110
114
|
}
|
|
111
115
|
}
|
package/src/runtime/misc.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
// Small platform globals that are real (not engine-specific). Grown in Phase 1.
|
|
2
2
|
|
|
3
|
+
import type { ColorInput } from "../core/color"
|
|
4
|
+
|
|
3
5
|
/** Show a transient toast notification. */
|
|
4
|
-
export const toast = (msg: string): void =>
|
|
6
|
+
export const toast = (msg: string): void => _creatorTree.toast(msg, 2000)
|
|
5
7
|
|
|
6
8
|
/** Open `url` in the system browser / external handler (fire-and-forget, like `share`). Silent
|
|
7
9
|
* no-op on hosts without one (headless). */
|
|
8
|
-
export const openURL = (url: string): void =>
|
|
10
|
+
export const openURL = (url: string): void => _creatorApp.openUrl?.(url)
|
|
9
11
|
|
|
10
12
|
export type SvgSourceValue = {
|
|
11
13
|
readonly svg: string
|
|
12
|
-
tintColor:
|
|
14
|
+
/** The source-level tint (a mask recolor under the `tintColor` style, which wins): any color, or
|
|
15
|
+
* a theme `var(--…)`. */
|
|
16
|
+
tintColor: ColorInput | null
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
/** Wrap raw SVG XML so it can be used as an image source. */
|
package/src/runtime/net.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// WebSocket over the host bridge. Same event surface as the browser's
|
|
2
|
-
// via the shared Emitter.
|
|
1
|
+
// WebSocket over the host's `_creatorSocket` bridge. Same event surface as the browser's
|
|
2
|
+
// (open/message/close/error) via the shared Emitter.
|
|
3
3
|
|
|
4
4
|
import { Emitter } from "../core/events"
|
|
5
5
|
|
|
@@ -13,18 +13,19 @@ type SocketEvents = {
|
|
|
13
13
|
export class WebSocket extends Emitter<SocketEvents> {
|
|
14
14
|
private _id: number | null = null
|
|
15
15
|
|
|
16
|
-
constructor(url: string
|
|
16
|
+
constructor(url: string) {
|
|
17
17
|
super()
|
|
18
|
-
this._id =
|
|
18
|
+
this._id = _creatorSocket.open(url, (channel, data) => this._onMessage(channel, data))
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
/** Send a text frame. */
|
|
22
|
+
send(message: string): void {
|
|
23
|
+
if (this._id !== null) _creatorSocket.send(this._id, message)
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
close(): void {
|
|
26
27
|
if (this._id !== null) {
|
|
27
|
-
|
|
28
|
+
_creatorSocket.close(this._id)
|
|
28
29
|
this._id = null
|
|
29
30
|
}
|
|
30
31
|
}
|
package/src/runtime/rpc.ts
CHANGED
|
@@ -68,7 +68,6 @@ export const __rpc = (serverUrl: string, id: string) => {
|
|
|
68
68
|
}
|
|
69
69
|
let body: any
|
|
70
70
|
try { body = res.json() } catch { body = null }
|
|
71
|
-
res.dispose()
|
|
72
71
|
if (body && typeof body === "object" && "session" in body) setSession(serverUrl, body.session ?? null)
|
|
73
72
|
if (body && body.ok === true) return body.result
|
|
74
73
|
if (body && body.ok === false) throw new RpcError(body.status ?? res.status, body.message ?? "")
|
|
@@ -132,8 +131,7 @@ class ChannelSocket {
|
|
|
132
131
|
if (this.ws || this.timer !== null) return
|
|
133
132
|
this.closedByUs = false
|
|
134
133
|
const url = this.serverUrl.replace(/^http/, "ws") + "/ws"
|
|
135
|
-
const
|
|
136
|
-
const ws = new WebSocket(url, session ? { authorization: `Bearer ${session}` } : undefined)
|
|
134
|
+
const ws = new WebSocket(url)
|
|
137
135
|
this.ws = ws
|
|
138
136
|
ws.addEventListener("open", () => {
|
|
139
137
|
this.open = true
|
package/src/runtime/service.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// A host-registered headless service (geolocation, bluetooth, contacts, …) — the UI-less sibling
|
|
2
2
|
// of NativeView (docs/service-channel-plan.md). The host registers a *capability*
|
|
3
3
|
// (`registerService("geolocation") { params, channel -> ... }`); the SDK talks to it over the
|
|
4
|
-
// shared
|
|
4
|
+
// shared call / event protocol (runtime/channel.ts) via `_creatorService`.
|
|
5
5
|
//
|
|
6
6
|
// Not a public global itself: apps meet services through typed plugin wrappers (Geolocation —
|
|
7
7
|
// src/plugins/) or the raw `Service(name)` global (src/plugins/service.ts), both thin layers
|
|
@@ -26,18 +26,22 @@ export class ServiceClient {
|
|
|
26
26
|
|
|
27
27
|
/** Whether this host registered a `registerService` factory under `name`. */
|
|
28
28
|
static isSupported(name: string): boolean {
|
|
29
|
-
return typeof
|
|
30
|
-
|
|
29
|
+
return typeof _creatorService !== "undefined" && _creatorService.supported(name)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The contract version of the host's service `name`: 0 when it has none, 1 for one written by hand. */
|
|
33
|
+
static version(name: string): number {
|
|
34
|
+
return typeof _creatorService !== "undefined" ? _creatorService.version(name) : 0
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
/** @internal open (or reuse) the host session; throws when the host has no channel/factory. */
|
|
34
38
|
private _ensureOpen(): number {
|
|
35
39
|
if (this._serviceId !== null) return this._serviceId
|
|
36
|
-
if (typeof
|
|
37
|
-
throw new Error(`Service("${this.serviceName}") is not supported on this host (
|
|
40
|
+
if (typeof _creatorService === "undefined") {
|
|
41
|
+
throw new Error(`Service("${this.serviceName}") is not supported on this host (no service channel)`)
|
|
38
42
|
}
|
|
39
|
-
const id =
|
|
40
|
-
(event: string,
|
|
43
|
+
const id = _creatorService.open(this.serviceName, JSON.stringify(this.params ?? {}),
|
|
44
|
+
(event: string, data?: unknown) => _channelEmit(this._listeners, event, data))
|
|
41
45
|
if (id < 0) {
|
|
42
46
|
throw new Error(`Service("${this.serviceName}") is not registered on this host`)
|
|
43
47
|
}
|
|
@@ -46,8 +50,11 @@ export class ServiceClient {
|
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
/** Invoke a method on the service (`geo.call("getCurrent", options)`). Args and the result are
|
|
49
|
-
*
|
|
50
|
-
call(method: string, ...args: any[]): Promise<any> {
|
|
53
|
+
* plain data (and Uint8Array). Rejects if the host has no such service/method. */
|
|
54
|
+
call(method: string, ...args: any[]): Promise<any> { return this._channelSend(method, args) }
|
|
55
|
+
|
|
56
|
+
/** @internal One call over the channel (runtime/channel.ts). */
|
|
57
|
+
_channelSend(method: string, args: any[]): Promise<any> {
|
|
51
58
|
let id: number
|
|
52
59
|
try {
|
|
53
60
|
id = this._ensureOpen()
|
|
@@ -55,8 +62,8 @@ export class ServiceClient {
|
|
|
55
62
|
return Promise.reject(e)
|
|
56
63
|
}
|
|
57
64
|
return _channelCall(
|
|
58
|
-
typeof
|
|
59
|
-
`Service("${this.serviceName}") is not supported on this host (
|
|
65
|
+
typeof _creatorService !== "undefined" ? _creatorService : undefined, "call",
|
|
66
|
+
`Service("${this.serviceName}") is not supported on this host (no service channel)`,
|
|
60
67
|
id, method, args)
|
|
61
68
|
}
|
|
62
69
|
|
|
@@ -76,8 +83,6 @@ export class ServiceClient {
|
|
|
76
83
|
if (this._serviceId === null) return
|
|
77
84
|
const id = this._serviceId
|
|
78
85
|
this._serviceId = null
|
|
79
|
-
if (typeof
|
|
80
|
-
_creatorUtils.serviceClose(id)
|
|
81
|
-
}
|
|
86
|
+
if (typeof _creatorService !== "undefined") _creatorService.close(id)
|
|
82
87
|
}
|
|
83
88
|
}
|
package/src/runtime/share.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
// Share a media File (image/video) via the OS share sheet. Wraps `
|
|
1
|
+
// Share a media File (image/video) via the OS share sheet. Wraps `_creatorDevice.share`, which
|
|
2
2
|
// takes the host buffer id behind the File. On iOS the sheet also lets the user save to Files/Photos;
|
|
3
|
-
// on web it saves (downloads) the file. `text` is an optional caption/message.
|
|
3
|
+
// on web it saves (downloads) the file. `text` is an optional caption/message. A silent no-op on
|
|
4
|
+
// hosts without a share slot (headless).
|
|
4
5
|
|
|
5
6
|
import type { File, FetchResponse } from "./fetch"
|
|
6
7
|
|
|
7
8
|
export function share(media: File | FetchResponse, text?: string): void {
|
|
8
|
-
|
|
9
|
+
_creatorDevice.share?.((media as any)._h.id, text)
|
|
9
10
|
}
|
package/src/runtime/storage.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
// Key/value persistence backed by the host. Same shape as the web localStorage
|
|
1
|
+
// Key/value persistence backed by the host (`_creatorStorage`). Same shape as the web localStorage
|
|
2
|
+
// subset projects use.
|
|
3
|
+
|
|
2
4
|
|
|
3
5
|
export const localStorage = {
|
|
4
6
|
getItem(key: string): string | null {
|
|
5
|
-
return
|
|
7
|
+
return _creatorStorage.get(key)
|
|
6
8
|
},
|
|
7
9
|
setItem(key: string, value: string): void {
|
|
8
|
-
|
|
10
|
+
_creatorStorage.set(key, value)
|
|
9
11
|
},
|
|
10
12
|
removeItem(key: string): void {
|
|
11
|
-
|
|
13
|
+
_creatorStorage.remove(key)
|
|
12
14
|
},
|
|
13
15
|
}
|
package/src/runtime/touch.ts
CHANGED
|
@@ -74,3 +74,35 @@ export class LongPressEvent<T = any> {
|
|
|
74
74
|
this._trackHandler = handler
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
/** What a hover `track()` takes: the cursor's moves inside the element (only delivered when
|
|
79
|
+
* `onMove` is present — otherwise the host never crosses into JS for them), `onEnd` when it
|
|
80
|
+
* leaves (with the last position), `onCancel` when the element went away underneath it. No
|
|
81
|
+
* `claim`: a hover competes with nothing. */
|
|
82
|
+
export interface HoverTrackHandler {
|
|
83
|
+
onMove?(pos: { clientX: number, clientY: number, deltaX: number, deltaY: number }): void
|
|
84
|
+
onEnd?(pos: { clientX: number, clientY: number, deltaX: number, deltaY: number }): void
|
|
85
|
+
onCancel?(): void
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Delivered to a `UIButton` `onMouseEnter` handler when a mouse cursor (no button) enters the
|
|
89
|
+
* button. There is no separate leave event: `ev.track({ onEnd })` follows this hover to its end,
|
|
90
|
+
* `onMove` follows the cursor inside — the visual state itself is the reserved `$hovered` class.
|
|
91
|
+
* Touch never produces one. */
|
|
92
|
+
export class MouseEnterEvent<T = any> {
|
|
93
|
+
readonly type = "mouseenter"
|
|
94
|
+
readonly clientX: number
|
|
95
|
+
readonly clientY: number
|
|
96
|
+
target!: T
|
|
97
|
+
/** @internal — read by the dispatch system after the handler runs. */
|
|
98
|
+
_trackHandler?: HoverTrackHandler
|
|
99
|
+
constructor(clientX: number, clientY: number) {
|
|
100
|
+
this.clientX = clientX
|
|
101
|
+
this.clientY = clientY
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Follow this hover: moves inside the element, its end (the cursor left), its cancel. */
|
|
105
|
+
track(handler: HoverTrackHandler): void {
|
|
106
|
+
this._trackHandler = handler
|
|
107
|
+
}
|
|
108
|
+
}
|