lunchboxjs 0.1.4018 → 0.2.1001-beta.2
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/dist/lunchboxjs.js +1739 -1670
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +1694 -1667
- package/extras/OrbitControlsWrapper.vue +5 -7
- package/package.json +15 -4
- package/src/components/LunchboxEventHandlers.tsx +237 -0
- package/src/components/LunchboxWrapper/LunchboxScene.tsx +8 -0
- package/src/components/LunchboxWrapper/LunchboxWrapper.tsx +341 -0
- package/src/components/LunchboxWrapper/prepCanvas.ts +27 -21
- package/src/components/LunchboxWrapper/resizeCanvas.ts +13 -12
- package/src/components/autoGeneratedComponents.ts +1 -1
- package/src/components/index.ts +2 -4
- package/src/core/createNode.ts +2 -18
- package/src/core/extend.ts +1 -1
- package/src/core/index.ts +0 -3
- package/src/core/instantiateThreeObject/index.ts +7 -2
- package/src/core/instantiateThreeObject/processProps.ts +1 -1
- package/src/core/interaction.ts +55 -0
- package/src/core/minidom.ts +5 -9
- package/src/core/update.ts +92 -53
- package/src/core/updateObjectProp.ts +5 -14
- package/src/index.ts +270 -76
- package/src/keys.ts +25 -0
- package/src/nodeOps/createElement.ts +2 -5
- package/src/nodeOps/index.ts +70 -57
- package/src/nodeOps/insert.ts +11 -32
- package/src/nodeOps/remove.ts +1 -17
- package/src/types.ts +34 -10
- package/src/utils/index.ts +11 -4
- package/dist/.DS_Store +0 -0
- package/src/.DS_Store +0 -0
- package/src/components/LunchboxWrapper/LunchboxWrapper.ts +0 -312
- package/src/components/catalogue.ts +0 -3
- package/src/core/.DS_Store +0 -0
- package/src/core/allNodes.ts +0 -4
- package/src/core/ensure.ts +0 -203
- package/src/core/interaction/index.ts +0 -102
- package/src/core/interaction/input.ts +0 -4
- package/src/core/interaction/interactables.ts +0 -14
- package/src/core/interaction/setupAutoRaycaster.ts +0 -224
- package/src/core/start.ts +0 -11
|
@@ -5,35 +5,39 @@ import { resizeCanvas } from './resizeCanvas'
|
|
|
5
5
|
|
|
6
6
|
const getInnerDimensions = (node: Element) => {
|
|
7
7
|
const computedStyle = getComputedStyle(node)
|
|
8
|
-
const width =
|
|
9
|
-
|
|
8
|
+
const width =
|
|
9
|
+
node.clientWidth -
|
|
10
|
+
parseFloat(computedStyle.paddingLeft) -
|
|
11
|
+
parseFloat(computedStyle.paddingRight)
|
|
12
|
+
const height =
|
|
13
|
+
node.clientHeight -
|
|
14
|
+
parseFloat(computedStyle.paddingTop) -
|
|
15
|
+
parseFloat(computedStyle.paddingBottom)
|
|
10
16
|
return { width, height }
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
export const prepCanvas = (
|
|
14
20
|
container: Ref<MiniDom.RendererDomNode | undefined>,
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
camera: THREE.Camera,
|
|
22
|
+
renderer: THREE.Renderer,
|
|
23
|
+
scene: THREE.Scene,
|
|
17
24
|
sizePolicy?: Lunch.SizePolicy
|
|
18
25
|
) => {
|
|
19
26
|
const containerElement = container.value?.domElement
|
|
20
27
|
if (!containerElement) throw new Error('missing container')
|
|
21
28
|
|
|
22
|
-
// save
|
|
23
|
-
// ...and size element
|
|
29
|
+
// save and size element
|
|
24
30
|
const resizeCanvasByPolicy = () => {
|
|
25
|
-
if (sizePolicy ===
|
|
26
|
-
const dims = getInnerDimensions(containerElement)
|
|
27
|
-
resizeCanvas(dims.width, dims.height)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
};
|
|
32
|
-
resizeCanvasByPolicy();
|
|
31
|
+
if (sizePolicy === 'container') {
|
|
32
|
+
const dims = getInnerDimensions(containerElement)
|
|
33
|
+
resizeCanvas(camera, renderer, scene, dims.width, dims.height)
|
|
34
|
+
} else resizeCanvas(camera, renderer, scene)
|
|
35
|
+
}
|
|
36
|
+
resizeCanvasByPolicy()
|
|
33
37
|
|
|
34
38
|
// attach listeners
|
|
35
|
-
|
|
36
|
-
resizeCanvasByPolicy()
|
|
39
|
+
let observer = new ResizeObserver(() => {
|
|
40
|
+
resizeCanvasByPolicy()
|
|
37
41
|
})
|
|
38
42
|
// window.addEventListener('resize', resizeCanvas)
|
|
39
43
|
if (containerElement) {
|
|
@@ -41,9 +45,11 @@ export const prepCanvas = (
|
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
// cleanup
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
return {
|
|
49
|
+
dispose() {
|
|
50
|
+
if (containerElement) {
|
|
51
|
+
observer.unobserve(containerElement)
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
}
|
|
49
55
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { ensuredCamera, ensureRenderer, ensuredScene } from '../../core'
|
|
2
1
|
import { toRaw } from 'vue'
|
|
3
2
|
|
|
4
|
-
export const resizeCanvas = (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
export const resizeCanvas = (
|
|
4
|
+
camera: THREE.Camera,
|
|
5
|
+
renderer: THREE.Renderer,
|
|
6
|
+
scene: THREE.Scene,
|
|
7
|
+
width?: number,
|
|
8
|
+
height?: number
|
|
9
|
+
) => {
|
|
9
10
|
// ignore if no element
|
|
10
11
|
if (!renderer?.domElement || !scene || !camera) return
|
|
11
12
|
|
|
@@ -15,12 +16,12 @@ export const resizeCanvas = (width?: number, height?: number) => {
|
|
|
15
16
|
// update camera
|
|
16
17
|
const aspect = width / height
|
|
17
18
|
if (camera.type?.toLowerCase() === 'perspectivecamera') {
|
|
18
|
-
const perspectiveCamera = camera
|
|
19
|
+
const perspectiveCamera = camera as THREE.PerspectiveCamera
|
|
19
20
|
perspectiveCamera.aspect = aspect
|
|
20
21
|
perspectiveCamera.updateProjectionMatrix()
|
|
21
22
|
} else if (camera.type?.toLowerCase() === 'orthographiccamera') {
|
|
22
|
-
//
|
|
23
|
-
const orthoCamera = camera
|
|
23
|
+
// TODO: ortho camera update
|
|
24
|
+
const orthoCamera = camera as THREE.OrthographicCamera
|
|
24
25
|
const heightInTermsOfWidth = height / width
|
|
25
26
|
orthoCamera.top = heightInTermsOfWidth * 10
|
|
26
27
|
orthoCamera.bottom = -heightInTermsOfWidth * 10
|
|
@@ -28,13 +29,13 @@ export const resizeCanvas = (width?: number, height?: number) => {
|
|
|
28
29
|
orthoCamera.left = -10
|
|
29
30
|
orthoCamera.updateProjectionMatrix()
|
|
30
31
|
} else {
|
|
31
|
-
|
|
32
|
+
// TODO: non-ortho or perspective camera
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
// update canvas
|
|
35
36
|
renderer.setSize(width, height)
|
|
36
37
|
// render immediately so there's no flicker
|
|
37
|
-
if (scene && camera
|
|
38
|
-
renderer.render(toRaw(scene), toRaw(camera
|
|
38
|
+
if (scene && camera) {
|
|
39
|
+
renderer.render(toRaw(scene), toRaw(camera))
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -106,6 +106,7 @@ export const autoGeneratedComponents = [
|
|
|
106
106
|
'group',
|
|
107
107
|
'catmullRomCurve3',
|
|
108
108
|
'points',
|
|
109
|
+
'raycaster',
|
|
109
110
|
|
|
110
111
|
// helpers
|
|
111
112
|
'cameraHelper',
|
|
@@ -157,7 +158,6 @@ export const autoGeneratedComponents = [
|
|
|
157
158
|
|
|
158
159
|
|
|
159
160
|
// misc
|
|
160
|
-
raycaster: RaycasterProps
|
|
161
161
|
vector2: Vector2Props
|
|
162
162
|
vector3: Vector3Props
|
|
163
163
|
vector4: Vector4Props
|
package/src/components/index.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { h, defineComponent } from 'vue'
|
|
2
2
|
import { LunchboxWrapper } from './LunchboxWrapper/LunchboxWrapper'
|
|
3
3
|
import { autoGeneratedComponents } from './autoGeneratedComponents'
|
|
4
|
+
import type { Lunch } from '../types'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
export { catalogue }
|
|
7
|
-
|
|
8
|
-
export const lunchboxDomComponentNames = ['canvas', 'div', 'LunchboxWrapper']
|
|
6
|
+
export const catalogue: Lunch.Catalogue = {}
|
|
9
7
|
|
|
10
8
|
// component creation utility
|
|
11
9
|
const createComponent = (tag: string) =>
|
package/src/core/createNode.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { isLunchboxRootNode } from '../utils'
|
|
2
|
-
import { instantiateThreeObject, MiniDom
|
|
3
|
-
import { Lunch } from '..'
|
|
4
|
-
import { ensuredCamera } from './ensure'
|
|
2
|
+
import { instantiateThreeObject, MiniDom } from '.'
|
|
3
|
+
import type { Lunch } from '..'
|
|
5
4
|
|
|
6
5
|
/** Create a new Lunchbox comment node. */
|
|
7
6
|
export function createCommentNode(options: Partial<Lunch.CommentMeta> = {}) {
|
|
@@ -59,13 +58,6 @@ export function createNode<T extends object = THREE.Object3D>(
|
|
|
59
58
|
})
|
|
60
59
|
|
|
61
60
|
if (node.type && !isLunchboxRootNode(node) && !node.instance) {
|
|
62
|
-
// if (node.type.includes('Camera')) {
|
|
63
|
-
// console.log(node.type, {
|
|
64
|
-
// ...node.props,
|
|
65
|
-
// ...props,
|
|
66
|
-
// })
|
|
67
|
-
// console.trace()
|
|
68
|
-
// }
|
|
69
61
|
node.instance = instantiateThreeObject({
|
|
70
62
|
...node,
|
|
71
63
|
props: {
|
|
@@ -75,13 +67,5 @@ export function createNode<T extends object = THREE.Object3D>(
|
|
|
75
67
|
})
|
|
76
68
|
}
|
|
77
69
|
|
|
78
|
-
// TODO: these manual overrides are a bit brittle - replace?
|
|
79
|
-
if (node.type?.toLowerCase() === 'scene') {
|
|
80
|
-
// manually set scene override
|
|
81
|
-
ensuredScene.value = node as Lunch.Node<THREE.Scene>
|
|
82
|
-
} else if (node.type?.toLowerCase().endsWith('camera')) {
|
|
83
|
-
ensuredCamera.value = node as Lunch.Node<THREE.Camera>
|
|
84
|
-
}
|
|
85
|
-
|
|
86
70
|
return node
|
|
87
71
|
}
|
package/src/core/extend.ts
CHANGED
package/src/core/index.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
export * from './allNodes'
|
|
2
1
|
export * from './createNode'
|
|
3
|
-
export * from './ensure'
|
|
4
2
|
export * from './interaction'
|
|
5
3
|
export * from './extend'
|
|
6
4
|
export * from './instantiateThreeObject'
|
|
7
5
|
export * from './minidom'
|
|
8
|
-
export * from './start'
|
|
9
6
|
export * from './update'
|
|
10
7
|
export * from './updateObjectProp'
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { catalogue } from '../../components'
|
|
2
2
|
import * as THREE from 'three'
|
|
3
3
|
import { processPropAsArray } from './processProps'
|
|
4
|
-
import { Lunch } from '../..'
|
|
4
|
+
import type { Lunch } from '../..'
|
|
5
5
|
|
|
6
6
|
export function instantiateThreeObject<T>(node: Lunch.StandardMeta<T>) {
|
|
7
7
|
if (!node.type) return null
|
|
8
8
|
|
|
9
9
|
// what class will we be instantiating?
|
|
10
10
|
const uppercaseType = node.type[0].toUpperCase() + node.type.slice(1)
|
|
11
|
-
const
|
|
11
|
+
const translatedType = uppercaseType.replace(/Lunchbox$/, '')
|
|
12
|
+
const targetClass =
|
|
13
|
+
catalogue[node.type] ||
|
|
14
|
+
(THREE as any)[uppercaseType] ||
|
|
15
|
+
catalogue[translatedType] ||
|
|
16
|
+
(THREE as any)[translatedType]
|
|
12
17
|
if (!targetClass)
|
|
13
18
|
throw `${uppercaseType} is not part of the THREE namespace! Did you forget to extend? import {extend} from 'lunchbox'; extend({app, YourComponent, ...})`
|
|
14
19
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
import type { Lunch } from '..'
|
|
3
|
+
|
|
4
|
+
/** Add an event listener to the given node. Also creates the event teardown function and any necessary raycaster/interaction dictionary updates. */
|
|
5
|
+
export function addEventListener({
|
|
6
|
+
node,
|
|
7
|
+
key,
|
|
8
|
+
interactables,
|
|
9
|
+
value,
|
|
10
|
+
}: {
|
|
11
|
+
node: Lunch.Node
|
|
12
|
+
key: Lunch.EventKey
|
|
13
|
+
interactables: Ref<Lunch.Node[]>
|
|
14
|
+
value: Lunch.EventCallback
|
|
15
|
+
}) {
|
|
16
|
+
// create new records for this key if needed
|
|
17
|
+
if (!node.eventListeners[key]) {
|
|
18
|
+
node.eventListeners[key] = []
|
|
19
|
+
}
|
|
20
|
+
if (!node.eventListenerRemoveFunctions[key]) {
|
|
21
|
+
node.eventListenerRemoveFunctions[key] = []
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// add event listener
|
|
25
|
+
node.eventListeners[key].push(value)
|
|
26
|
+
|
|
27
|
+
// if we need it, let's get/create the main raycaster
|
|
28
|
+
if (interactionsRequiringRaycaster.includes(key)) {
|
|
29
|
+
if (node.instance && !interactables.value.includes(node)) {
|
|
30
|
+
// add to interactables
|
|
31
|
+
interactables.value.push(node)
|
|
32
|
+
node.eventListenerRemoveFunctions[key].push(() => {
|
|
33
|
+
// remove from interactables
|
|
34
|
+
const idx = interactables.value.indexOf(node)
|
|
35
|
+
if (idx !== -1) {
|
|
36
|
+
interactables.value.splice(idx, 1)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return node
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const interactionsRequiringRaycaster = [
|
|
46
|
+
'onClick',
|
|
47
|
+
'onPointerUp',
|
|
48
|
+
'onPointerDown',
|
|
49
|
+
'onPointerOver',
|
|
50
|
+
'onPointerOut',
|
|
51
|
+
'onPointerEnter',
|
|
52
|
+
'onPointerLeave',
|
|
53
|
+
'onPointerMove',
|
|
54
|
+
// 'onPointerMissed',
|
|
55
|
+
]
|
package/src/core/minidom.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { v4 as createUuid } from 'uuid'
|
|
2
|
-
import {
|
|
3
|
-
import { Lunch } from '..'
|
|
2
|
+
import type { Lunch } from '..'
|
|
4
3
|
|
|
5
4
|
// MiniDom recreates DOM node properties and methods.
|
|
6
5
|
// Since Vue 3 is a DOM-first framework, many of its nodeOps depend on
|
|
@@ -17,7 +16,7 @@ export namespace MiniDom {
|
|
|
17
16
|
this.minidomType = 'MinidomBaseNode'
|
|
18
17
|
this.uuid = options?.uuid ?? createUuid()
|
|
19
18
|
|
|
20
|
-
allNodes.push(this)
|
|
19
|
+
// allNodes.push(this)
|
|
21
20
|
}
|
|
22
21
|
uuid: Lunch.Uuid
|
|
23
22
|
|
|
@@ -89,10 +88,10 @@ export namespace MiniDom {
|
|
|
89
88
|
/** Drop this node. Removes parent's knowledge of this node
|
|
90
89
|
* and resets this node's internal parent. */
|
|
91
90
|
drop() {
|
|
92
|
-
// remove parent
|
|
93
|
-
this.parentNode = null
|
|
94
91
|
// remove as child
|
|
95
92
|
this.removeAsChildFromAnyParents()
|
|
93
|
+
// remove parent
|
|
94
|
+
this.parentNode = null
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
/** Walk over the entire subtree. Return falsey value in callback to end early. */
|
|
@@ -124,7 +123,7 @@ export namespace MiniDom {
|
|
|
124
123
|
minidomType: MiniDom.NodeType
|
|
125
124
|
|
|
126
125
|
removeAsChildFromAnyParents() {
|
|
127
|
-
|
|
126
|
+
this.parentNode?.removeChild(this)
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
129
|
|
|
@@ -255,6 +254,3 @@ export namespace MiniDom {
|
|
|
255
254
|
export function isMinidomNode(item: any): item is MiniDom.RendererBaseNode {
|
|
256
255
|
return (item as MiniDom.BaseNode)?.minidomType === 'RendererNode'
|
|
257
256
|
}
|
|
258
|
-
|
|
259
|
-
export const rootNode = new MiniDom.RendererRootNode()
|
|
260
|
-
rootNode.minidomType = 'RootNode'
|
package/src/core/update.ts
CHANGED
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
let frameID: number
|
|
6
|
-
let watchStopHandle: WatchStopHandle
|
|
7
|
-
|
|
8
|
-
export const beforeRender = [] as Lunch.UpdateCallback[]
|
|
9
|
-
export const afterRender = [] as Lunch.UpdateCallback[]
|
|
1
|
+
import type { Lunch } from '..'
|
|
2
|
+
import { inject, toRaw, watch } from 'vue'
|
|
3
|
+
import * as Keys from '../keys'
|
|
10
4
|
|
|
11
5
|
const requestUpdate = (opts: Lunch.UpdateCallbackProperties) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
if (typeof opts.app.config.globalProperties.lunchbox.frameId === 'number') {
|
|
7
|
+
cancelAnimationFrame(opts.app.config.globalProperties.lunchbox.frameId)
|
|
8
|
+
}
|
|
9
|
+
opts.app.config.globalProperties.lunchbox.frameId = requestAnimationFrame(
|
|
10
|
+
() =>
|
|
11
|
+
update({
|
|
12
|
+
app: opts.app,
|
|
13
|
+
renderer: opts.renderer,
|
|
14
|
+
scene: opts.scene,
|
|
15
|
+
camera: opts.camera,
|
|
16
|
+
updateSource: opts.updateSource,
|
|
17
|
+
})
|
|
21
18
|
)
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
export const update: Lunch.UpdateCallback = (opts) => {
|
|
25
22
|
if (opts.updateSource) {
|
|
26
|
-
if (!watchStopHandle) {
|
|
23
|
+
if (!opts.app.config.globalProperties.lunchbox.watchStopHandle) {
|
|
27
24
|
// request next frame only when state changes
|
|
28
|
-
watchStopHandle = watch(
|
|
25
|
+
opts.app.config.globalProperties.lunchbox.watchStopHandle = watch(
|
|
29
26
|
opts.updateSource,
|
|
30
27
|
() => {
|
|
31
28
|
requestUpdate(opts)
|
|
@@ -41,70 +38,112 @@ export const update: Lunch.UpdateCallback = (opts) => {
|
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
// prep options
|
|
44
|
-
const { app, renderer, scene
|
|
41
|
+
const { app, renderer, scene } = opts
|
|
45
42
|
|
|
46
43
|
// BEFORE RENDER
|
|
47
|
-
beforeRender.forEach((cb
|
|
48
|
-
|
|
49
|
-
cb(opts)
|
|
50
|
-
}
|
|
44
|
+
app.config.globalProperties.lunchbox.beforeRender.forEach((cb) => {
|
|
45
|
+
cb?.(opts)
|
|
51
46
|
})
|
|
52
47
|
|
|
53
48
|
// RENDER
|
|
54
|
-
if (renderer && scene && camera) {
|
|
49
|
+
if (renderer && scene && opts.app.config.globalProperties.lunchbox.camera) {
|
|
55
50
|
if (app.customRender) {
|
|
56
51
|
app.customRender(opts)
|
|
57
52
|
} else {
|
|
58
|
-
renderer.render(
|
|
53
|
+
renderer.render(
|
|
54
|
+
toRaw(scene),
|
|
55
|
+
opts.app.config.globalProperties.lunchbox.camera
|
|
56
|
+
// toRaw(camera)
|
|
57
|
+
)
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
// AFTER RENDER
|
|
63
|
-
afterRender.forEach((cb
|
|
64
|
-
|
|
65
|
-
cb(opts)
|
|
66
|
-
}
|
|
62
|
+
app.config.globalProperties.lunchbox.afterRender.forEach((cb) => {
|
|
63
|
+
cb?.(opts)
|
|
67
64
|
})
|
|
68
65
|
}
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
// before render
|
|
68
|
+
// ====================
|
|
69
|
+
/** Obtain callback methods for `onBeforeRender` and `offBeforeRender`. Usually used internally by Lunchbox. */
|
|
70
|
+
export const useBeforeRender = () => {
|
|
71
|
+
return {
|
|
72
|
+
onBeforeRender: inject<typeof onBeforeRender>(Keys.onBeforeRenderKey),
|
|
73
|
+
offBeforeRender: inject<typeof offBeforeRender>(
|
|
74
|
+
Keys.offBeforeRenderKey
|
|
75
|
+
),
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
/** Run a function before every render.
|
|
80
|
+
*
|
|
81
|
+
* Note that if `updateSource` is set in the Lunchbox wrapper component, this will **only** run
|
|
82
|
+
* before a render triggered by that `updateSource`. Normally, the function should run every frame.
|
|
83
|
+
*/
|
|
84
|
+
export const onBeforeRender = (cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
85
|
+
useBeforeRender().onBeforeRender?.(cb, index)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Remove a function from the `beforeRender` callback list. Useful for tearing down functions added
|
|
89
|
+
* by `onBeforeRender`.
|
|
90
|
+
*/
|
|
78
91
|
export const offBeforeRender = (cb: Lunch.UpdateCallback | number) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
92
|
+
useBeforeRender().offBeforeRender?.(cb)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// after render
|
|
96
|
+
// ====================
|
|
97
|
+
/** Obtain callback methods for `onAfterRender` and `offAfterRender`. Usually used internally by Lunchbox. */
|
|
98
|
+
export const useAfterRender = () => {
|
|
99
|
+
return {
|
|
100
|
+
onAfterRender: inject<typeof onAfterRender>(Keys.onBeforeRenderKey),
|
|
101
|
+
offAfterRender: inject<typeof offAfterRender>(Keys.offBeforeRenderKey),
|
|
84
102
|
}
|
|
85
103
|
}
|
|
86
104
|
|
|
105
|
+
/** Run a function after every render.
|
|
106
|
+
*
|
|
107
|
+
* Note that if `updateSource` is set in the Lunchbox wrapper component, this will **only** run
|
|
108
|
+
* after a render triggered by that `updateSource`. Normally, the function should run every frame.
|
|
109
|
+
*/
|
|
87
110
|
export const onAfterRender = (cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
88
|
-
|
|
89
|
-
afterRender.push(cb)
|
|
90
|
-
} else {
|
|
91
|
-
afterRender.splice(index, 0, cb)
|
|
92
|
-
}
|
|
111
|
+
useBeforeRender().onBeforeRender?.(cb, index)
|
|
93
112
|
}
|
|
94
113
|
|
|
114
|
+
/** Remove a function from the `afterRender` callback list. Useful for tearing down functions added
|
|
115
|
+
* by `onAfterRender`.
|
|
116
|
+
*/
|
|
95
117
|
export const offAfterRender = (cb: Lunch.UpdateCallback | number) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
118
|
+
useBeforeRender().offBeforeRender?.(cb)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Obtain a function used to cancel the current update frame. Use `cancelUpdate` if you wish
|
|
122
|
+
* to immediately invoke the cancellation function. Usually used internally by Lunchbox.
|
|
123
|
+
*/
|
|
124
|
+
export const useCancelUpdate = () => {
|
|
125
|
+
const frameId = inject<number>(Keys.frameIdKey)
|
|
126
|
+
return () => {
|
|
127
|
+
if (frameId !== undefined) cancelAnimationFrame(frameId)
|
|
101
128
|
}
|
|
102
129
|
}
|
|
103
130
|
|
|
131
|
+
/** Cancel the current update frame. Usually used internally by Lunchbox. */
|
|
104
132
|
export const cancelUpdate = () => {
|
|
105
|
-
|
|
133
|
+
useCancelUpdate()?.()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Obtain a function used to cancel an update source. Use `cancelUpdateSource` if you wish to
|
|
137
|
+
* immediately invoke the cancellation function. Usually used internally by Lunchbox.
|
|
138
|
+
*/
|
|
139
|
+
export const useCancelUpdateSource = () => {
|
|
140
|
+
const cancel = inject<
|
|
141
|
+
Lunch.App['config']['globalProperties']['watchStopHandle']
|
|
142
|
+
>(Keys.watchStopHandleKey)
|
|
143
|
+
return () => cancel?.()
|
|
106
144
|
}
|
|
107
145
|
|
|
146
|
+
/** Cancel an update source. Usually used internally by Lunchbox. */
|
|
108
147
|
export const cancelUpdateSource = () => {
|
|
109
|
-
|
|
148
|
+
useCancelUpdateSource()?.()
|
|
110
149
|
}
|
|
@@ -1,34 +1,25 @@
|
|
|
1
1
|
import { isEventKey, isLunchboxStandardNode } from '../utils'
|
|
2
2
|
import { addEventListener } from './interaction'
|
|
3
3
|
import { get, isNumber, set } from 'lodash'
|
|
4
|
-
import { Lunch } from '..'
|
|
5
|
-
|
|
6
|
-
/** Update the given node so all of its props are current. */
|
|
7
|
-
export function updateAllObjectProps({ node }: { node: Lunch.Node }) {
|
|
8
|
-
// set props
|
|
9
|
-
const props = node.props || {}
|
|
10
|
-
let output = node
|
|
11
|
-
Object.keys(props).forEach((key) => {
|
|
12
|
-
output = updateObjectProp({ node, key, value: props[key] })
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
return output
|
|
16
|
-
}
|
|
4
|
+
import type { Lunch } from '..'
|
|
5
|
+
import type { Ref } from 'vue'
|
|
17
6
|
|
|
18
7
|
/** Update a single prop on a given node. */
|
|
19
8
|
export function updateObjectProp({
|
|
20
9
|
node,
|
|
21
10
|
key,
|
|
11
|
+
interactables,
|
|
22
12
|
value,
|
|
23
13
|
}: {
|
|
24
14
|
node: Lunch.Node
|
|
25
15
|
key: string
|
|
16
|
+
interactables: Ref<Lunch.Node[]>
|
|
26
17
|
value: any
|
|
27
18
|
}) {
|
|
28
19
|
// handle and return early if prop is an event
|
|
29
20
|
// (event list from react-three-fiber)
|
|
30
21
|
if (isEventKey(key)) {
|
|
31
|
-
return addEventListener({ node, key, value })
|
|
22
|
+
return addEventListener({ node, key, interactables, value })
|
|
32
23
|
}
|
|
33
24
|
|
|
34
25
|
// update THREE property
|