lunchboxjs 0.2.1001-beta.0 → 0.2.1001-beta.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 +0 -47
- package/dist/lunchboxjs.js +292 -347
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +292 -342
- package/package.json +3 -2
- package/src/components/LunchboxEventHandlers.tsx +239 -0
- package/src/components/LunchboxWrapper/LunchboxWrapper.tsx +7 -6
- package/src/components/autoGeneratedComponents.ts +1 -1
- package/src/components/index.ts +2 -2
- package/src/core/createNode.ts +1 -1
- package/src/core/extend.ts +1 -1
- package/src/core/instantiateThreeObject/index.ts +1 -1
- package/src/core/instantiateThreeObject/processProps.ts +1 -1
- package/src/core/interaction.ts +55 -0
- package/src/core/minidom.ts +1 -1
- package/src/core/update.ts +2 -30
- package/src/core/updateObjectProp.ts +5 -14
- package/src/index.ts +12 -3
- package/src/keys.ts +1 -0
- package/src/nodeOps/index.ts +70 -57
- package/src/types.ts +0 -8
- package/src/components/catalogue.ts +0 -3
- 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 -232
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lunchboxjs",
|
|
3
|
-
"version": "0.2.1001-beta.
|
|
3
|
+
"version": "0.2.1001-beta.1",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "vite -c utils/vite.config.ts",
|
|
6
6
|
"build": "vue-tsc --noEmit && vite build -c utils/vite.config.ts",
|
|
7
7
|
"build:tsc": "tsc --project ./utils/tsconfig.lib.json",
|
|
8
8
|
"build:rollup": "rollup -c ./utils/lib-rollup.ts",
|
|
9
9
|
"build:dts": "cp utils/lib-dts.d.ts dist/lunchboxjs.es.d.ts && cp utils/lib-dts.d.ts dist/lunchboxjs.umd.d.ts",
|
|
10
|
-
"build:lib": "
|
|
10
|
+
"build:lib": "rimraf js && npm run build:tsc && npm run build:rollup && npm run build:dts",
|
|
11
11
|
"prepare": "npm run build:lib",
|
|
12
12
|
"docs:dev": "vitepress dev docs",
|
|
13
13
|
"docs:build": "vitepress build docs",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"nice-color-palettes": "3.0.0",
|
|
37
37
|
"prompt": "1.3.0",
|
|
38
38
|
"prompts": "2.4.2",
|
|
39
|
+
"rimraf": "3.0.2",
|
|
39
40
|
"rollup-plugin-delete": "2.0.0",
|
|
40
41
|
"rollup-plugin-jsx": "1.0.3",
|
|
41
42
|
"rollup-plugin-terser": "7.0.2",
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { defineComponent, onBeforeUnmount, ref, watch } from 'vue'
|
|
2
|
+
import {
|
|
3
|
+
Lunch,
|
|
4
|
+
useCamera,
|
|
5
|
+
useGlobals,
|
|
6
|
+
useLunchboxInteractables,
|
|
7
|
+
useRenderer,
|
|
8
|
+
} from '..'
|
|
9
|
+
import * as THREE from 'three'
|
|
10
|
+
import { offBeforeRender, onBeforeRender } from '../core'
|
|
11
|
+
|
|
12
|
+
export const LunchboxEventHandlers = defineComponent({
|
|
13
|
+
name: 'LunchboxEventHandlers',
|
|
14
|
+
setup() {
|
|
15
|
+
const interactables = useLunchboxInteractables()
|
|
16
|
+
const camera = useCamera()
|
|
17
|
+
const renderer = useRenderer()
|
|
18
|
+
const globals = useGlobals()
|
|
19
|
+
const mousePos = ref({ x: Infinity, y: Infinity })
|
|
20
|
+
const inputActive = ref(false)
|
|
21
|
+
|
|
22
|
+
let currentIntersections: Array<{
|
|
23
|
+
element: Lunch.Node
|
|
24
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
25
|
+
}> = []
|
|
26
|
+
|
|
27
|
+
const raycaster = new THREE.Raycaster(
|
|
28
|
+
new THREE.Vector3(),
|
|
29
|
+
new THREE.Vector3(0, 0, -1)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const fireEventsFromIntersections = ({
|
|
33
|
+
element,
|
|
34
|
+
eventKeys,
|
|
35
|
+
intersection,
|
|
36
|
+
}: {
|
|
37
|
+
element: Lunch.Node
|
|
38
|
+
eventKeys: Array<Lunch.EventKey>
|
|
39
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
40
|
+
}) => {
|
|
41
|
+
if (!element) return
|
|
42
|
+
eventKeys.forEach((eventKey) => {
|
|
43
|
+
if (element.eventListeners[eventKey]) {
|
|
44
|
+
element.eventListeners[eventKey].forEach((cb) => {
|
|
45
|
+
cb({ intersection })
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// add mouse listener to renderer DOM element when the element is ready
|
|
52
|
+
const stopWatch = watch(
|
|
53
|
+
renderer,
|
|
54
|
+
(v) => {
|
|
55
|
+
if (!v?.domElement) return
|
|
56
|
+
|
|
57
|
+
// we have a DOM element, so let's add mouse listeners
|
|
58
|
+
const { domElement } = v
|
|
59
|
+
|
|
60
|
+
const mouseMoveListener = (evt: PointerEvent) => {
|
|
61
|
+
const screenWidth = (domElement.width ?? 1) / globals.dpr
|
|
62
|
+
const screenHeight = (domElement.height ?? 1) / globals.dpr
|
|
63
|
+
mousePos.value.x = (evt.offsetX / screenWidth) * 2 - 1
|
|
64
|
+
mousePos.value.y = -(evt.offsetY / screenHeight) * 2 + 1
|
|
65
|
+
}
|
|
66
|
+
const mouseDownListener = () => (inputActive.value = true)
|
|
67
|
+
const mouseUpListener = () => (inputActive.value = false)
|
|
68
|
+
|
|
69
|
+
// add mouse events
|
|
70
|
+
domElement.addEventListener('pointermove', mouseMoveListener)
|
|
71
|
+
domElement.addEventListener('pointerdown', mouseDownListener)
|
|
72
|
+
domElement.addEventListener('pointerup', mouseUpListener)
|
|
73
|
+
|
|
74
|
+
// stop the watcher
|
|
75
|
+
stopWatch()
|
|
76
|
+
},
|
|
77
|
+
{ immediate: true }
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
const update = () => {
|
|
81
|
+
const c = camera.value
|
|
82
|
+
if (!c) return
|
|
83
|
+
|
|
84
|
+
raycaster.setFromCamera(mousePos.value, c)
|
|
85
|
+
const intersections = raycaster.intersectObjects(
|
|
86
|
+
interactables?.value.map(
|
|
87
|
+
(v) => v.instance as any as THREE.Object3D
|
|
88
|
+
) ?? []
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
let enterValues: Array<THREE.Intersection<THREE.Object3D>> = [],
|
|
92
|
+
sameValues: Array<THREE.Intersection<THREE.Object3D>> = [],
|
|
93
|
+
leaveValues: Array<THREE.Intersection<THREE.Object3D>> = [],
|
|
94
|
+
entering: Array<{
|
|
95
|
+
element: Lunch.Node
|
|
96
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
97
|
+
}> = [],
|
|
98
|
+
staying: Array<{
|
|
99
|
+
element: Lunch.Node
|
|
100
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
101
|
+
}> = []
|
|
102
|
+
|
|
103
|
+
// intersection arrays
|
|
104
|
+
leaveValues = currentIntersections.map((v) => v.intersection)
|
|
105
|
+
|
|
106
|
+
// element arrays
|
|
107
|
+
intersections?.forEach((intersection) => {
|
|
108
|
+
const currentIdx = currentIntersections.findIndex(
|
|
109
|
+
(v) => v.intersection.object === intersection.object
|
|
110
|
+
)
|
|
111
|
+
if (currentIdx === -1) {
|
|
112
|
+
// new intersection
|
|
113
|
+
enterValues.push(intersection)
|
|
114
|
+
|
|
115
|
+
const found = interactables?.value.find(
|
|
116
|
+
(v) => v.instance?.uuid === intersection.object.uuid
|
|
117
|
+
)
|
|
118
|
+
if (found) {
|
|
119
|
+
entering.push({ element: found, intersection })
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
// existing intersection
|
|
123
|
+
sameValues.push(intersection)
|
|
124
|
+
|
|
125
|
+
const found = interactables?.value.find(
|
|
126
|
+
(v) => v.instance?.uuid === intersection.object.uuid
|
|
127
|
+
)
|
|
128
|
+
if (found) {
|
|
129
|
+
staying.push({ element: found, intersection })
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// this is a current intersection, so it won't be in our `leave` array
|
|
133
|
+
const leaveIdx = leaveValues.findIndex(
|
|
134
|
+
(v) => v.object.uuid === intersection.object.uuid
|
|
135
|
+
)
|
|
136
|
+
if (leaveIdx !== -1) {
|
|
137
|
+
leaveValues.splice(leaveIdx, 1)
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
const leaving: Array<{
|
|
142
|
+
element: Lunch.Node
|
|
143
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
144
|
+
}> = leaveValues.map((intersection) => {
|
|
145
|
+
return {
|
|
146
|
+
element: interactables?.value.find(
|
|
147
|
+
(interactable) =>
|
|
148
|
+
interactable.instance?.uuid ===
|
|
149
|
+
intersection.object.uuid
|
|
150
|
+
) as any as Lunch.Node,
|
|
151
|
+
intersection,
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// new interactions
|
|
156
|
+
entering.forEach(({ element, intersection }) => {
|
|
157
|
+
fireEventsFromIntersections({
|
|
158
|
+
element,
|
|
159
|
+
eventKeys: ['onPointerEnter'],
|
|
160
|
+
intersection,
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
// unchanged interactions
|
|
165
|
+
staying.forEach(({ element, intersection }) => {
|
|
166
|
+
const eventKeys: Array<Lunch.EventKey> = [
|
|
167
|
+
'onPointerOver',
|
|
168
|
+
'onPointerMove',
|
|
169
|
+
]
|
|
170
|
+
fireEventsFromIntersections({
|
|
171
|
+
element,
|
|
172
|
+
eventKeys,
|
|
173
|
+
intersection,
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// exited interactions
|
|
178
|
+
leaving.forEach(({ element, intersection }) => {
|
|
179
|
+
const eventKeys: Array<Lunch.EventKey> = [
|
|
180
|
+
'onPointerLeave',
|
|
181
|
+
'onPointerOut',
|
|
182
|
+
]
|
|
183
|
+
fireEventsFromIntersections({
|
|
184
|
+
element,
|
|
185
|
+
eventKeys,
|
|
186
|
+
intersection,
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
currentIntersections = ([] as any).concat(entering, staying)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// update function
|
|
194
|
+
onBeforeRender(update)
|
|
195
|
+
|
|
196
|
+
const teardown = () => offBeforeRender(update)
|
|
197
|
+
onBeforeUnmount(teardown)
|
|
198
|
+
|
|
199
|
+
const clickEventKeys: Lunch.EventKey[] = [
|
|
200
|
+
'onClick',
|
|
201
|
+
'onPointerDown',
|
|
202
|
+
'onPointerUp',
|
|
203
|
+
]
|
|
204
|
+
watch(inputActive, (isDown) => {
|
|
205
|
+
// meshes with multiple intersections receive multiple callbacks by default -
|
|
206
|
+
// let's make it so they only receive one callback of each type per frame.
|
|
207
|
+
// (ie usually when you click on a mesh, you expect only one click event to fire, even
|
|
208
|
+
// if there are technically multiple intersections with that mesh)
|
|
209
|
+
const uuidsInteractedWithThisFrame: string[] = []
|
|
210
|
+
currentIntersections.forEach((v) => {
|
|
211
|
+
clickEventKeys.forEach((key) => {
|
|
212
|
+
const id = v.element.uuid + key
|
|
213
|
+
if (
|
|
214
|
+
isDown &&
|
|
215
|
+
(key === 'onClick' || key === 'onPointerDown')
|
|
216
|
+
) {
|
|
217
|
+
if (!uuidsInteractedWithThisFrame.includes(id)) {
|
|
218
|
+
v.element.eventListeners[key]?.forEach((cb) =>
|
|
219
|
+
cb({ intersection: v.intersection })
|
|
220
|
+
)
|
|
221
|
+
uuidsInteractedWithThisFrame.push(id)
|
|
222
|
+
}
|
|
223
|
+
} else if (!isDown && key === 'onPointerUp') {
|
|
224
|
+
if (!uuidsInteractedWithThisFrame.includes(id)) {
|
|
225
|
+
v.element.eventListeners[key]?.forEach((cb) =>
|
|
226
|
+
cb({ intersection: v.intersection })
|
|
227
|
+
)
|
|
228
|
+
uuidsInteractedWithThisFrame.push(id)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
// return arbitrary object to ensure instantiation
|
|
236
|
+
// TODO: why can't we return a <raycaster/> here?
|
|
237
|
+
return () => <object3D />
|
|
238
|
+
},
|
|
239
|
+
})
|
|
@@ -8,11 +8,12 @@ import {
|
|
|
8
8
|
WatchSource,
|
|
9
9
|
} from 'vue'
|
|
10
10
|
import { cancelUpdate, cancelUpdateSource, MiniDom, update } from '../../core'
|
|
11
|
-
import { Lunch, useApp, useGlobals } from '../..'
|
|
11
|
+
import { Lunch, useApp, useGlobals, useLunchboxInteractables } from '../..'
|
|
12
12
|
import * as THREE from 'three'
|
|
13
13
|
import { prepCanvas } from './prepCanvas'
|
|
14
14
|
import { useUpdateGlobals, useStartCallbacks } from '../..'
|
|
15
15
|
import { LunchboxScene } from './LunchboxScene'
|
|
16
|
+
import { LunchboxEventHandlers } from '../LunchboxEventHandlers'
|
|
16
17
|
|
|
17
18
|
/** fixed & fill styling for container */
|
|
18
19
|
const fillStyle = (position: string) => {
|
|
@@ -67,6 +68,8 @@ export const LunchboxWrapper = defineComponent({
|
|
|
67
68
|
;(THREE as any).ColorManagement.legacyMode = false
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
const interactables = useLunchboxInteractables()
|
|
72
|
+
|
|
70
73
|
// MOUNT
|
|
71
74
|
// ====================
|
|
72
75
|
onMounted(async () => {
|
|
@@ -104,26 +107,21 @@ export const LunchboxWrapper = defineComponent({
|
|
|
104
107
|
}
|
|
105
108
|
updateGlobals?.({ dpr })
|
|
106
109
|
|
|
107
|
-
console.log(1)
|
|
108
110
|
while (
|
|
109
111
|
!renderer.value?.$el?.instance &&
|
|
110
112
|
// TODO: remove `as any`
|
|
111
113
|
!(renderer.value as any)?.component?.ctx.$el?.instance
|
|
112
114
|
) {
|
|
113
|
-
console.log(2)
|
|
114
115
|
await new Promise((r) => requestAnimationFrame(r))
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
console.log(3)
|
|
118
118
|
while (
|
|
119
119
|
!scene.value?.$el?.instance &&
|
|
120
120
|
// TODO: remove `as any`
|
|
121
121
|
!(scene.value as any)?.component?.ctx.$el?.instance
|
|
122
122
|
) {
|
|
123
|
-
console.log(4)
|
|
124
123
|
await new Promise((r) => requestAnimationFrame(r))
|
|
125
124
|
}
|
|
126
|
-
console.log(5)
|
|
127
125
|
|
|
128
126
|
const normalizedRenderer = (renderer.value?.$el?.instance ??
|
|
129
127
|
(renderer.value as any)?.component?.ctx.$el
|
|
@@ -293,6 +291,9 @@ export const LunchboxWrapper = defineComponent({
|
|
|
293
291
|
{...consolidatedCameraProperties}
|
|
294
292
|
/>
|
|
295
293
|
)}
|
|
294
|
+
|
|
295
|
+
{/* Lunchbox interaction handlers */}
|
|
296
|
+
{interactables?.value.length && <LunchboxEventHandlers />}
|
|
296
297
|
</>
|
|
297
298
|
)
|
|
298
299
|
},
|
|
@@ -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,9 +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 }
|
|
6
|
+
export const catalogue: Lunch.Catalogue = {}
|
|
7
7
|
|
|
8
8
|
// component creation utility
|
|
9
9
|
const createComponent = (tag: string) =>
|
package/src/core/createNode.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isLunchboxRootNode } from '../utils'
|
|
2
2
|
import { instantiateThreeObject, MiniDom } from '.'
|
|
3
|
-
import { Lunch } from '..'
|
|
3
|
+
import type { Lunch } from '..'
|
|
4
4
|
|
|
5
5
|
/** Create a new Lunchbox comment node. */
|
|
6
6
|
export function createCommentNode(options: Partial<Lunch.CommentMeta> = {}) {
|
package/src/core/extend.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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
|
|
@@ -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
package/src/core/update.ts
CHANGED
|
@@ -1,18 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// ensuredScene,
|
|
4
|
-
// ensuredCamera,
|
|
5
|
-
// } from '.'
|
|
6
|
-
import { Lunch } from '..'
|
|
7
|
-
import { inject, toRaw, watch, WatchStopHandle } from 'vue'
|
|
1
|
+
import type { Lunch } from '..'
|
|
2
|
+
import { inject, toRaw, watch } from 'vue'
|
|
8
3
|
import * as Keys from '../keys'
|
|
9
4
|
|
|
10
|
-
// let frameID: number
|
|
11
|
-
// let watchStopHandle: WatchStopHandle
|
|
12
|
-
|
|
13
|
-
// export const beforeRender = [] as Lunch.UpdateCallback[]
|
|
14
|
-
// export const afterRender = [] as Lunch.UpdateCallback[]
|
|
15
|
-
|
|
16
5
|
const requestUpdate = (opts: Lunch.UpdateCallbackProperties) => {
|
|
17
6
|
if (typeof opts.app.config.globalProperties.lunchbox.frameId === 'number') {
|
|
18
7
|
cancelAnimationFrame(opts.app.config.globalProperties.lunchbox.frameId)
|
|
@@ -117,23 +106,6 @@ export const offAfterRender = (cb: Lunch.UpdateCallback | number) => {
|
|
|
117
106
|
useBeforeRender().offBeforeRender?.(cb)
|
|
118
107
|
}
|
|
119
108
|
|
|
120
|
-
// export const onAfterRender = (cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
121
|
-
// if (index === Infinity) {
|
|
122
|
-
// afterRender.push(cb)
|
|
123
|
-
// } else {
|
|
124
|
-
// afterRender.splice(index, 0, cb)
|
|
125
|
-
// }
|
|
126
|
-
// }
|
|
127
|
-
|
|
128
|
-
// export const offAfterRender = (cb: Lunch.UpdateCallback | number) => {
|
|
129
|
-
// if (isFinite(cb as number)) {
|
|
130
|
-
// afterRender.splice(cb as number, 1)
|
|
131
|
-
// } else {
|
|
132
|
-
// const idx = afterRender.findIndex((v) => v == cb)
|
|
133
|
-
// afterRender.splice(idx, 1)
|
|
134
|
-
// }
|
|
135
|
-
// }
|
|
136
|
-
|
|
137
109
|
// TODO: document
|
|
138
110
|
export const useCancelUpdate = () => {
|
|
139
111
|
const frameId = inject<number>(Keys.frameIdKey)
|
|
@@ -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
|
package/src/index.ts
CHANGED
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
inject,
|
|
6
6
|
watch,
|
|
7
7
|
reactive,
|
|
8
|
+
Ref,
|
|
8
9
|
} from 'vue'
|
|
9
|
-
import {
|
|
10
|
+
import { createNodeOps } from './nodeOps'
|
|
10
11
|
import {
|
|
11
12
|
ensuredCamera,
|
|
12
13
|
ensureRenderer,
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
import { components } from './components'
|
|
18
19
|
import { Lunch } from './types'
|
|
19
20
|
|
|
20
|
-
// export { lunchboxRootNode as lunchboxTree } from './core'
|
|
21
21
|
export * from './core'
|
|
22
22
|
export * from './types'
|
|
23
23
|
|
|
@@ -48,7 +48,7 @@ export function useScene(callback: (newScene: THREE.Scene) => void) {
|
|
|
48
48
|
scene,
|
|
49
49
|
(newVal) => {
|
|
50
50
|
if (!newVal) return
|
|
51
|
-
callback(newVal.value)
|
|
51
|
+
callback(newVal.value as THREE.Scene)
|
|
52
52
|
},
|
|
53
53
|
{ immediate: true }
|
|
54
54
|
)
|
|
@@ -137,11 +137,20 @@ export const onStart = (cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
// TODO: document
|
|
141
|
+
export const useLunchboxInteractables = () =>
|
|
142
|
+
inject<Ref<Lunch.Node[]>>(Keys.lunchboxInteractables)
|
|
143
|
+
|
|
140
144
|
// CREATE APP
|
|
141
145
|
// ====================
|
|
142
146
|
export const createApp = (root: Component) => {
|
|
147
|
+
const { nodeOps, interactables } = createNodeOps()
|
|
143
148
|
const app = createRenderer(nodeOps).createApp(root) as Lunch.App
|
|
144
149
|
|
|
150
|
+
// provide Lunchbox interaction handlers flag (modified when user references events via
|
|
151
|
+
// @click, etc)
|
|
152
|
+
app.provide(Keys.lunchboxInteractables, interactables)
|
|
153
|
+
|
|
145
154
|
// register all components
|
|
146
155
|
// ====================
|
|
147
156
|
Object.keys(components).forEach((key) => {
|
package/src/keys.ts
CHANGED