lunchboxjs 0.2.1001-beta.0 → 0.2.1001-beta.301
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 +438 -420
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +435 -408
- package/extras/OrbitControlsWrapper.vue +2 -12
- package/package.json +6 -2
- package/src/components/LunchboxEventHandlers.tsx +237 -0
- package/src/components/LunchboxWrapper/LunchboxWrapper.tsx +49 -7
- 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/index.ts +0 -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 +32 -44
- package/src/core/updateObjectProp.ts +21 -16
- package/src/index.ts +65 -34
- package/src/keys.ts +1 -0
- package/src/nodeOps/index.ts +70 -57
- package/src/types.ts +0 -8
- package/src/utils/index.ts +10 -0
- package/src/components/catalogue.ts +0 -3
- package/src/core/ensure.ts +0 -16
- 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
|
@@ -11,15 +11,8 @@
|
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
13
|
<script lang="ts" setup>
|
|
14
|
-
import { computed, ref
|
|
15
|
-
import {
|
|
16
|
-
onBeforeRender,
|
|
17
|
-
globals,
|
|
18
|
-
Lunch,
|
|
19
|
-
// camera,
|
|
20
|
-
useRenderer,
|
|
21
|
-
useCamera,
|
|
22
|
-
} from '../src'
|
|
14
|
+
import { computed, ref } from 'vue'
|
|
15
|
+
import { onBeforeRender, Lunch, useCamera, useRenderer } from '../src'
|
|
23
16
|
|
|
24
17
|
// props
|
|
25
18
|
const props = defineProps<{
|
|
@@ -33,9 +26,6 @@ const ready = computed(() => {
|
|
|
33
26
|
const camera = useCamera()
|
|
34
27
|
const renderer = useRenderer()
|
|
35
28
|
const orbitArgs = computed(() => [camera.value, renderer.value?.domElement])
|
|
36
|
-
// watch(() => orbitArgs.value, console.log, { immediate: true })
|
|
37
|
-
// console.log(renderer)
|
|
38
|
-
watch(camera, console.log)
|
|
39
29
|
|
|
40
30
|
// update
|
|
41
31
|
const controls = ref<Lunch.LunchboxComponent>()
|
package/package.json
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lunchboxjs",
|
|
3
|
-
"version": "0.2.1001-beta.
|
|
3
|
+
"version": "0.2.1001-beta.301",
|
|
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",
|
|
14
14
|
"docs:serve": "vitepress serve docs",
|
|
15
15
|
"demo:create": "node utils/createExample"
|
|
16
16
|
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=16.0.0"
|
|
19
|
+
},
|
|
17
20
|
"dependencies": {
|
|
18
21
|
"uuid": "8.3.2",
|
|
19
22
|
"vue": "^3.2.16"
|
|
@@ -36,6 +39,7 @@
|
|
|
36
39
|
"nice-color-palettes": "3.0.0",
|
|
37
40
|
"prompt": "1.3.0",
|
|
38
41
|
"prompts": "2.4.2",
|
|
42
|
+
"rimraf": "3.0.2",
|
|
39
43
|
"rollup-plugin-delete": "2.0.0",
|
|
40
44
|
"rollup-plugin-jsx": "1.0.3",
|
|
41
45
|
"rollup-plugin-terser": "7.0.2",
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { defineComponent, onBeforeUnmount, ref, watch } from 'vue'
|
|
2
|
+
import {
|
|
3
|
+
useCamera,
|
|
4
|
+
Lunch,
|
|
5
|
+
useGlobals,
|
|
6
|
+
useLunchboxInteractables,
|
|
7
|
+
onRendererReady,
|
|
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 globals = useGlobals()
|
|
17
|
+
const mousePos = ref({ x: Infinity, y: Infinity })
|
|
18
|
+
const inputActive = ref(false)
|
|
19
|
+
|
|
20
|
+
let currentIntersections: Array<{
|
|
21
|
+
element: Lunch.Node
|
|
22
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
23
|
+
}> = []
|
|
24
|
+
|
|
25
|
+
const raycaster = new THREE.Raycaster(
|
|
26
|
+
new THREE.Vector3(),
|
|
27
|
+
new THREE.Vector3(0, 0, -1)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
const fireEventsFromIntersections = ({
|
|
31
|
+
element,
|
|
32
|
+
eventKeys,
|
|
33
|
+
intersection,
|
|
34
|
+
}: {
|
|
35
|
+
element: Lunch.Node
|
|
36
|
+
eventKeys: Array<Lunch.EventKey>
|
|
37
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
38
|
+
}) => {
|
|
39
|
+
if (!element) return
|
|
40
|
+
eventKeys.forEach((eventKey) => {
|
|
41
|
+
if (element.eventListeners[eventKey]) {
|
|
42
|
+
element.eventListeners[eventKey].forEach((cb) => {
|
|
43
|
+
cb({ intersection })
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// add mouse listener to renderer DOM element when the element is ready
|
|
50
|
+
onRendererReady((v) => {
|
|
51
|
+
if (!v?.domElement) return
|
|
52
|
+
|
|
53
|
+
// we have a DOM element, so let's add mouse listeners
|
|
54
|
+
const { domElement } = v
|
|
55
|
+
|
|
56
|
+
const mouseMoveListener = (evt: PointerEvent) => {
|
|
57
|
+
const screenWidth = (domElement.width ?? 1) / globals.dpr
|
|
58
|
+
const screenHeight = (domElement.height ?? 1) / globals.dpr
|
|
59
|
+
mousePos.value.x = (evt.offsetX / screenWidth) * 2 - 1
|
|
60
|
+
mousePos.value.y = -(evt.offsetY / screenHeight) * 2 + 1
|
|
61
|
+
}
|
|
62
|
+
const mouseDownListener = () => (inputActive.value = true)
|
|
63
|
+
const mouseUpListener = () => (inputActive.value = false)
|
|
64
|
+
|
|
65
|
+
// add mouse events
|
|
66
|
+
domElement.addEventListener('pointermove', mouseMoveListener)
|
|
67
|
+
domElement.addEventListener('pointerdown', mouseDownListener)
|
|
68
|
+
domElement.addEventListener('pointerup', mouseUpListener)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const camera = useCamera()
|
|
72
|
+
const update = () => {
|
|
73
|
+
const c = camera.value
|
|
74
|
+
if (!c) return
|
|
75
|
+
|
|
76
|
+
// console.log(camera.value)
|
|
77
|
+
|
|
78
|
+
raycaster.setFromCamera(mousePos.value, c)
|
|
79
|
+
const intersections = raycaster.intersectObjects(
|
|
80
|
+
interactables?.value.map(
|
|
81
|
+
(v) => v.instance as any as THREE.Object3D
|
|
82
|
+
) ?? []
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
let enterValues: Array<THREE.Intersection<THREE.Object3D>> = [],
|
|
86
|
+
sameValues: Array<THREE.Intersection<THREE.Object3D>> = [],
|
|
87
|
+
leaveValues: Array<THREE.Intersection<THREE.Object3D>> = [],
|
|
88
|
+
entering: Array<{
|
|
89
|
+
element: Lunch.Node
|
|
90
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
91
|
+
}> = [],
|
|
92
|
+
staying: Array<{
|
|
93
|
+
element: Lunch.Node
|
|
94
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
95
|
+
}> = []
|
|
96
|
+
|
|
97
|
+
// intersection arrays
|
|
98
|
+
leaveValues = currentIntersections.map((v) => v.intersection)
|
|
99
|
+
|
|
100
|
+
// element arrays
|
|
101
|
+
intersections?.forEach((intersection) => {
|
|
102
|
+
const currentIdx = currentIntersections.findIndex(
|
|
103
|
+
(v) => v.intersection.object === intersection.object
|
|
104
|
+
)
|
|
105
|
+
if (currentIdx === -1) {
|
|
106
|
+
// new intersection
|
|
107
|
+
enterValues.push(intersection)
|
|
108
|
+
|
|
109
|
+
const found = interactables?.value.find(
|
|
110
|
+
(v) => v.instance?.uuid === intersection.object.uuid
|
|
111
|
+
)
|
|
112
|
+
if (found) {
|
|
113
|
+
entering.push({ element: found, intersection })
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
// existing intersection
|
|
117
|
+
sameValues.push(intersection)
|
|
118
|
+
|
|
119
|
+
const found = interactables?.value.find(
|
|
120
|
+
(v) => v.instance?.uuid === intersection.object.uuid
|
|
121
|
+
)
|
|
122
|
+
if (found) {
|
|
123
|
+
staying.push({ element: found, intersection })
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// this is a current intersection, so it won't be in our `leave` array
|
|
127
|
+
const leaveIdx = leaveValues.findIndex(
|
|
128
|
+
(v) => v.object.uuid === intersection.object.uuid
|
|
129
|
+
)
|
|
130
|
+
if (leaveIdx !== -1) {
|
|
131
|
+
leaveValues.splice(leaveIdx, 1)
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const leaving: Array<{
|
|
136
|
+
element: Lunch.Node
|
|
137
|
+
intersection: THREE.Intersection<THREE.Object3D>
|
|
138
|
+
}> = leaveValues.map((intersection) => {
|
|
139
|
+
return {
|
|
140
|
+
element: interactables?.value.find(
|
|
141
|
+
(interactable) =>
|
|
142
|
+
interactable.instance?.uuid ===
|
|
143
|
+
intersection.object.uuid
|
|
144
|
+
) as any as Lunch.Node,
|
|
145
|
+
intersection,
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
// new interactions
|
|
150
|
+
entering.forEach(({ element, intersection }) => {
|
|
151
|
+
fireEventsFromIntersections({
|
|
152
|
+
element,
|
|
153
|
+
eventKeys: ['onPointerEnter'],
|
|
154
|
+
intersection,
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// unchanged interactions
|
|
159
|
+
staying.forEach(({ element, intersection }) => {
|
|
160
|
+
const eventKeys: Array<Lunch.EventKey> = [
|
|
161
|
+
'onPointerOver',
|
|
162
|
+
'onPointerMove',
|
|
163
|
+
]
|
|
164
|
+
fireEventsFromIntersections({
|
|
165
|
+
element,
|
|
166
|
+
eventKeys,
|
|
167
|
+
intersection,
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// exited interactions
|
|
172
|
+
leaving.forEach(({ element, intersection }) => {
|
|
173
|
+
const eventKeys: Array<Lunch.EventKey> = [
|
|
174
|
+
'onPointerLeave',
|
|
175
|
+
'onPointerOut',
|
|
176
|
+
]
|
|
177
|
+
fireEventsFromIntersections({
|
|
178
|
+
element,
|
|
179
|
+
eventKeys,
|
|
180
|
+
intersection,
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
currentIntersections = ([] as any).concat(entering, staying)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// update function
|
|
188
|
+
onBeforeRender(update)
|
|
189
|
+
|
|
190
|
+
const teardown = () => offBeforeRender(update)
|
|
191
|
+
onBeforeUnmount(teardown)
|
|
192
|
+
|
|
193
|
+
const clickEventKeys: Lunch.EventKey[] = [
|
|
194
|
+
'onClick',
|
|
195
|
+
'onPointerDown',
|
|
196
|
+
'onPointerUp',
|
|
197
|
+
]
|
|
198
|
+
watch(inputActive, (isDown) => {
|
|
199
|
+
// run raycaster on click (necessary when `update` is not automatically called,
|
|
200
|
+
// for example in `updateSource` functions)
|
|
201
|
+
update()
|
|
202
|
+
|
|
203
|
+
// meshes with multiple intersections receive multiple callbacks by default -
|
|
204
|
+
// let's make it so they only receive one callback of each type per frame.
|
|
205
|
+
// (ie usually when you click on a mesh, you expect only one click event to fire, even
|
|
206
|
+
// if there are technically multiple intersections with that mesh)
|
|
207
|
+
const uuidsInteractedWithThisFrame: string[] = []
|
|
208
|
+
currentIntersections.forEach((v) => {
|
|
209
|
+
clickEventKeys.forEach((key) => {
|
|
210
|
+
const id = v.element.uuid + key
|
|
211
|
+
if (
|
|
212
|
+
isDown &&
|
|
213
|
+
(key === 'onClick' || key === 'onPointerDown')
|
|
214
|
+
) {
|
|
215
|
+
if (!uuidsInteractedWithThisFrame.includes(id)) {
|
|
216
|
+
v.element.eventListeners[key]?.forEach((cb) =>
|
|
217
|
+
cb({ intersection: v.intersection })
|
|
218
|
+
)
|
|
219
|
+
uuidsInteractedWithThisFrame.push(id)
|
|
220
|
+
}
|
|
221
|
+
} else if (!isDown && key === 'onPointerUp') {
|
|
222
|
+
if (!uuidsInteractedWithThisFrame.includes(id)) {
|
|
223
|
+
v.element.eventListeners[key]?.forEach((cb) =>
|
|
224
|
+
cb({ intersection: v.intersection })
|
|
225
|
+
)
|
|
226
|
+
uuidsInteractedWithThisFrame.push(id)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
// return arbitrary object to ensure instantiation
|
|
234
|
+
// TODO: why can't we return a <raycaster/> here?
|
|
235
|
+
return () => <object3D />
|
|
236
|
+
},
|
|
237
|
+
})
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
|
+
computed,
|
|
2
3
|
defineComponent,
|
|
3
4
|
onBeforeUnmount,
|
|
4
5
|
onMounted,
|
|
5
6
|
PropType,
|
|
6
7
|
reactive,
|
|
7
8
|
ref,
|
|
9
|
+
watch,
|
|
8
10
|
WatchSource,
|
|
9
11
|
} from 'vue'
|
|
10
12
|
import { cancelUpdate, cancelUpdateSource, MiniDom, update } from '../../core'
|
|
11
|
-
import { Lunch, useApp, useGlobals } from '../..'
|
|
13
|
+
import { Lunch, useApp, useGlobals, useLunchboxInteractables } from '../..'
|
|
12
14
|
import * as THREE from 'three'
|
|
13
15
|
import { prepCanvas } from './prepCanvas'
|
|
14
16
|
import { useUpdateGlobals, useStartCallbacks } from '../..'
|
|
15
17
|
import { LunchboxScene } from './LunchboxScene'
|
|
18
|
+
import { LunchboxEventHandlers } from '../LunchboxEventHandlers'
|
|
19
|
+
import * as Keys from '../../keys'
|
|
20
|
+
import { waitFor } from '../../utils'
|
|
16
21
|
|
|
17
22
|
/** fixed & fill styling for container */
|
|
18
23
|
const fillStyle = (position: string) => {
|
|
@@ -67,6 +72,8 @@ export const LunchboxWrapper = defineComponent({
|
|
|
67
72
|
;(THREE as any).ColorManagement.legacyMode = false
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
const interactables = useLunchboxInteractables()
|
|
76
|
+
|
|
70
77
|
// MOUNT
|
|
71
78
|
// ====================
|
|
72
79
|
onMounted(async () => {
|
|
@@ -104,26 +111,21 @@ export const LunchboxWrapper = defineComponent({
|
|
|
104
111
|
}
|
|
105
112
|
updateGlobals?.({ dpr })
|
|
106
113
|
|
|
107
|
-
console.log(1)
|
|
108
114
|
while (
|
|
109
115
|
!renderer.value?.$el?.instance &&
|
|
110
116
|
// TODO: remove `as any`
|
|
111
117
|
!(renderer.value as any)?.component?.ctx.$el?.instance
|
|
112
118
|
) {
|
|
113
|
-
console.log(2)
|
|
114
119
|
await new Promise((r) => requestAnimationFrame(r))
|
|
115
120
|
}
|
|
116
121
|
|
|
117
|
-
console.log(3)
|
|
118
122
|
while (
|
|
119
123
|
!scene.value?.$el?.instance &&
|
|
120
124
|
// TODO: remove `as any`
|
|
121
125
|
!(scene.value as any)?.component?.ctx.$el?.instance
|
|
122
126
|
) {
|
|
123
|
-
console.log(4)
|
|
124
127
|
await new Promise((r) => requestAnimationFrame(r))
|
|
125
128
|
}
|
|
126
|
-
console.log(5)
|
|
127
129
|
|
|
128
130
|
const normalizedRenderer = (renderer.value?.$el?.instance ??
|
|
129
131
|
(renderer.value as any)?.component?.ctx.$el
|
|
@@ -214,6 +216,43 @@ export const LunchboxWrapper = defineComponent({
|
|
|
214
216
|
const canvasFillStyle =
|
|
215
217
|
props.sizePolicy === 'container' ? 'static' : 'fixed'
|
|
216
218
|
|
|
219
|
+
// REACTIVE CUSTOM CAMERAS
|
|
220
|
+
// ====================
|
|
221
|
+
// find first camera with `type.name` property
|
|
222
|
+
// (which indicates a Lunch.Node)
|
|
223
|
+
const activeCamera = computed(() => {
|
|
224
|
+
const output = context.slots
|
|
225
|
+
?.camera?.()
|
|
226
|
+
.find((c) => (c.type as any)?.name)
|
|
227
|
+
if (output) {
|
|
228
|
+
return output
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return output
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
// TODO: make custom cameras reactive
|
|
235
|
+
watch(
|
|
236
|
+
activeCamera,
|
|
237
|
+
async (newVal, oldVal) => {
|
|
238
|
+
// console.log('got camera', newVal)
|
|
239
|
+
if (newVal && newVal?.props?.key !== oldVal?.props?.key) {
|
|
240
|
+
// TODO: remove cast
|
|
241
|
+
camera.value = newVal as any
|
|
242
|
+
|
|
243
|
+
// TODO: why isn't this updating app camera?
|
|
244
|
+
// const el = await waitFor(() => newVal.el)
|
|
245
|
+
// console.log(el)
|
|
246
|
+
// camera.value = el
|
|
247
|
+
// console.log(newVal.uuid)
|
|
248
|
+
// updateGlobals?.({ camera: el })
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{ immediate: true }
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
// RENDER FUNCTION
|
|
255
|
+
// ====================
|
|
217
256
|
return () => (
|
|
218
257
|
<>
|
|
219
258
|
{/* use renderer slot if provided... */}
|
|
@@ -272,7 +311,7 @@ export const LunchboxWrapper = defineComponent({
|
|
|
272
311
|
{/* use camera slot if provided... */}
|
|
273
312
|
{context.slots?.camera?.()?.length ? (
|
|
274
313
|
// TODO: remove `any` cast
|
|
275
|
-
|
|
314
|
+
camera.value
|
|
276
315
|
) : props.ortho || props.orthographic ? (
|
|
277
316
|
<orthographicCamera
|
|
278
317
|
ref={camera}
|
|
@@ -293,6 +332,9 @@ export const LunchboxWrapper = defineComponent({
|
|
|
293
332
|
{...consolidatedCameraProperties}
|
|
294
333
|
/>
|
|
295
334
|
)}
|
|
335
|
+
|
|
336
|
+
{/* Lunchbox interaction handlers */}
|
|
337
|
+
{interactables?.value.length && <LunchboxEventHandlers />}
|
|
296
338
|
</>
|
|
297
339
|
)
|
|
298
340
|
},
|
|
@@ -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
package/src/core/index.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