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.
Files changed (41) hide show
  1. package/dist/lunchboxjs.js +1739 -1670
  2. package/dist/lunchboxjs.min.js +1 -1
  3. package/dist/lunchboxjs.module.js +1694 -1667
  4. package/extras/OrbitControlsWrapper.vue +5 -7
  5. package/package.json +15 -4
  6. package/src/components/LunchboxEventHandlers.tsx +237 -0
  7. package/src/components/LunchboxWrapper/LunchboxScene.tsx +8 -0
  8. package/src/components/LunchboxWrapper/LunchboxWrapper.tsx +341 -0
  9. package/src/components/LunchboxWrapper/prepCanvas.ts +27 -21
  10. package/src/components/LunchboxWrapper/resizeCanvas.ts +13 -12
  11. package/src/components/autoGeneratedComponents.ts +1 -1
  12. package/src/components/index.ts +2 -4
  13. package/src/core/createNode.ts +2 -18
  14. package/src/core/extend.ts +1 -1
  15. package/src/core/index.ts +0 -3
  16. package/src/core/instantiateThreeObject/index.ts +7 -2
  17. package/src/core/instantiateThreeObject/processProps.ts +1 -1
  18. package/src/core/interaction.ts +55 -0
  19. package/src/core/minidom.ts +5 -9
  20. package/src/core/update.ts +92 -53
  21. package/src/core/updateObjectProp.ts +5 -14
  22. package/src/index.ts +270 -76
  23. package/src/keys.ts +25 -0
  24. package/src/nodeOps/createElement.ts +2 -5
  25. package/src/nodeOps/index.ts +70 -57
  26. package/src/nodeOps/insert.ts +11 -32
  27. package/src/nodeOps/remove.ts +1 -17
  28. package/src/types.ts +34 -10
  29. package/src/utils/index.ts +11 -4
  30. package/dist/.DS_Store +0 -0
  31. package/src/.DS_Store +0 -0
  32. package/src/components/LunchboxWrapper/LunchboxWrapper.ts +0 -312
  33. package/src/components/catalogue.ts +0 -3
  34. package/src/core/.DS_Store +0 -0
  35. package/src/core/allNodes.ts +0 -4
  36. package/src/core/ensure.ts +0 -203
  37. package/src/core/interaction/index.ts +0 -102
  38. package/src/core/interaction/input.ts +0 -4
  39. package/src/core/interaction/interactables.ts +0 -14
  40. package/src/core/interaction/setupAutoRaycaster.ts +0 -224
  41. 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 = node.clientWidth - parseFloat(computedStyle.paddingLeft) - parseFloat(computedStyle.paddingRight)
9
- const height = node.clientHeight - parseFloat(computedStyle.paddingTop) - parseFloat(computedStyle.paddingBottom)
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
- canvasElement: HTMLCanvasElement,
16
- onBeforeUnmount: Function,
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 === "container") {
26
- const dims = getInnerDimensions(containerElement);
27
- resizeCanvas(dims.width, dims.height);
28
- }
29
- else
30
- resizeCanvas()
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
- const observer = new ResizeObserver(([canvas]) => {
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
- onBeforeUnmount(() => {
45
- if (canvasElement) {
46
- observer.unobserve(canvasElement)
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 = (width?: number, height?: number) => {
5
- const renderer = ensureRenderer.value?.instance
6
- const scene = ensuredScene.value.instance
7
- const camera = ensuredCamera.value
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.instance as THREE.PerspectiveCamera
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
- // console.log('TODO: ortho camera update')
23
- const orthoCamera = camera.instance as THREE.OrthographicCamera
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
- console.log('TODO: non-ortho or perspective camera')
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.instance) {
38
- renderer.render(toRaw(scene), toRaw(camera.instance))
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
@@ -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
- import { catalogue } from './catalogue'
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) =>
@@ -1,7 +1,6 @@
1
1
  import { isLunchboxRootNode } from '../utils'
2
- import { instantiateThreeObject, MiniDom, ensuredScene } from '.'
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
  }
@@ -1,6 +1,6 @@
1
1
  import { h, defineComponent } from 'vue'
2
2
  import { catalogue } from '../components'
3
- import { Lunch } from '..'
3
+ import type { Lunch } from '..'
4
4
 
5
5
  const createComponent = (tag: string) =>
6
6
  defineComponent({
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 targetClass = catalogue[node.type] || (THREE as any)[uppercaseType]
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
 
@@ -1,4 +1,4 @@
1
- import { Lunch } from '../..'
1
+ import type { Lunch } from '../..'
2
2
 
3
3
  /** Process props into either themselves or the $attached value */
4
4
  export function processProp<T, U = THREE.Object3D>({
@@ -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
+ ]
@@ -1,6 +1,5 @@
1
1
  import { v4 as createUuid } from 'uuid'
2
- import { allNodes } from '.'
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
- allNodes.forEach((node) => node.removeChild(this))
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'
@@ -1,31 +1,28 @@
1
- import { ensureRenderer, ensuredScene, ensuredCamera } from '.'
2
- import { Lunch } from '..'
3
- import { toRaw, watch, WatchStopHandle } from 'vue'
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
- cancelUpdate()
13
- frameID = requestAnimationFrame(() =>
14
- update({
15
- app: opts.app,
16
- renderer: ensureRenderer.value?.instance,
17
- scene: ensuredScene.value.instance,
18
- camera: ensuredCamera.value?.instance,
19
- updateSource: opts.updateSource,
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, camera } = opts
41
+ const { app, renderer, scene } = opts
45
42
 
46
43
  // BEFORE RENDER
47
- beforeRender.forEach((cb: Lunch.UpdateCallback | undefined) => {
48
- if (cb) {
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(toRaw(scene), toRaw(camera))
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: Lunch.UpdateCallback | undefined) => {
64
- if (cb) {
65
- cb(opts)
66
- }
62
+ app.config.globalProperties.lunchbox.afterRender.forEach((cb) => {
63
+ cb?.(opts)
67
64
  })
68
65
  }
69
66
 
70
- export const onBeforeRender = (cb: Lunch.UpdateCallback, index = Infinity) => {
71
- if (index === Infinity) {
72
- beforeRender.push(cb)
73
- } else {
74
- beforeRender.splice(index, 0, cb)
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
- if (isFinite(cb as number)) {
80
- beforeRender.splice(cb as number, 1)
81
- } else {
82
- const idx = beforeRender.findIndex((v) => v == cb)
83
- beforeRender.splice(idx, 1)
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
- if (index === Infinity) {
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
- if (isFinite(cb as number)) {
97
- afterRender.splice(cb as number, 1)
98
- } else {
99
- const idx = afterRender.findIndex((v) => v == cb)
100
- afterRender.splice(idx, 1)
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
- if (frameID) cancelAnimationFrame(frameID)
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
- if (watchStopHandle) watchStopHandle()
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