lunchboxjs 0.2.1020 → 2.0.0-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/dist/lunchboxjs.cjs +46 -0
- package/dist/lunchboxjs.d.ts +1 -0
- package/dist/lunchboxjs.js +1632 -1962
- package/dist/lunchboxjs.umd.cjs +46 -0
- package/package.json +36 -81
- package/LICENSE.md +0 -7
- package/README.md +0 -17
- package/dist/lunchboxjs.es.d.ts +0 -1
- package/dist/lunchboxjs.min.js +0 -1
- package/dist/lunchboxjs.module.js +0 -1924
- package/dist/lunchboxjs.umd.d.ts +0 -1
- package/src/components/LunchboxEventHandlers.tsx +0 -237
- package/src/components/LunchboxWrapper/LunchboxScene.tsx +0 -8
- package/src/components/LunchboxWrapper/LunchboxWrapper.tsx +0 -341
- package/src/components/LunchboxWrapper/prepCanvas.ts +0 -55
- package/src/components/LunchboxWrapper/resizeCanvas.ts +0 -41
- package/src/components/autoGeneratedComponents.ts +0 -175
- package/src/components/index.ts +0 -31
- package/src/core/createNode.ts +0 -71
- package/src/core/extend.ts +0 -25
- package/src/core/index.ts +0 -7
- package/src/core/instantiateThreeObject/index.ts +0 -37
- package/src/core/instantiateThreeObject/processProps.ts +0 -40
- package/src/core/interaction.ts +0 -55
- package/src/core/minidom.ts +0 -256
- package/src/core/update.ts +0 -149
- package/src/core/updateObjectProp.ts +0 -153
- package/src/index.ts +0 -400
- package/src/keys.ts +0 -31
- package/src/nodeOps/createElement.ts +0 -34
- package/src/nodeOps/index.ts +0 -83
- package/src/nodeOps/insert.ts +0 -165
- package/src/nodeOps/remove.ts +0 -32
- package/src/plugins/bridge/BridgeComponent.tsx +0 -60
- package/src/plugins/bridge/bridge.ts +0 -9
- package/src/types.ts +0 -186
- package/src/utils/find.ts +0 -24
- package/src/utils/get.ts +0 -18
- package/src/utils/index.ts +0 -60
- package/src/utils/isNumber.ts +0 -87
- package/src/utils/set.ts +0 -14
package/src/core/update.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import type { Lunch } from '..'
|
|
2
|
-
import { inject, toRaw, watch } from 'vue'
|
|
3
|
-
import * as Keys from '../keys'
|
|
4
|
-
|
|
5
|
-
const requestUpdate = (opts: Lunch.UpdateCallbackProperties) => {
|
|
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
|
-
})
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const update: Lunch.UpdateCallback = (opts) => {
|
|
22
|
-
if (opts.updateSource) {
|
|
23
|
-
if (!opts.app.config.globalProperties.lunchbox.watchStopHandle) {
|
|
24
|
-
// request next frame only when state changes
|
|
25
|
-
opts.app.config.globalProperties.lunchbox.watchStopHandle = watch(
|
|
26
|
-
opts.updateSource,
|
|
27
|
-
() => {
|
|
28
|
-
requestUpdate(opts)
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
deep: true,
|
|
32
|
-
}
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
// request next frame on a continuous loop
|
|
37
|
-
requestUpdate(opts)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// prep options
|
|
41
|
-
const { app, renderer, scene } = opts
|
|
42
|
-
|
|
43
|
-
// BEFORE RENDER
|
|
44
|
-
app.config.globalProperties.lunchbox.beforeRender.forEach((cb) => {
|
|
45
|
-
cb?.(opts)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
// RENDER
|
|
49
|
-
if (renderer && scene && opts.app.config.globalProperties.lunchbox.camera) {
|
|
50
|
-
if (app.customRender) {
|
|
51
|
-
app.customRender(opts)
|
|
52
|
-
} else {
|
|
53
|
-
renderer.render(
|
|
54
|
-
toRaw(scene),
|
|
55
|
-
opts.app.config.globalProperties.lunchbox.camera
|
|
56
|
-
// toRaw(camera)
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// AFTER RENDER
|
|
62
|
-
app.config.globalProperties.lunchbox.afterRender.forEach((cb) => {
|
|
63
|
-
cb?.(opts)
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
|
|
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
|
-
),
|
|
76
|
-
}
|
|
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
|
-
*/
|
|
91
|
-
export const offBeforeRender = (cb: Lunch.UpdateCallback | number) => {
|
|
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),
|
|
102
|
-
}
|
|
103
|
-
}
|
|
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
|
-
*/
|
|
110
|
-
export const onAfterRender = (cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
111
|
-
useBeforeRender().onBeforeRender?.(cb, index)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** Remove a function from the `afterRender` callback list. Useful for tearing down functions added
|
|
115
|
-
* by `onAfterRender`.
|
|
116
|
-
*/
|
|
117
|
-
export const offAfterRender = (cb: Lunch.UpdateCallback | number) => {
|
|
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)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Cancel the current update frame. Usually used internally by Lunchbox. */
|
|
132
|
-
export const cancelUpdate = () => {
|
|
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?.()
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** Cancel an update source. Usually used internally by Lunchbox. */
|
|
147
|
-
export const cancelUpdateSource = () => {
|
|
148
|
-
useCancelUpdateSource()?.()
|
|
149
|
-
}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
get,
|
|
3
|
-
isEventKey,
|
|
4
|
-
isLunchboxStandardNode,
|
|
5
|
-
isNumber,
|
|
6
|
-
set,
|
|
7
|
-
} from '../utils'
|
|
8
|
-
import { addEventListener } from './interaction'
|
|
9
|
-
import type { Lunch } from '..'
|
|
10
|
-
import type { Ref } from 'vue'
|
|
11
|
-
|
|
12
|
-
/** Update a single prop on a given node. */
|
|
13
|
-
export function updateObjectProp({
|
|
14
|
-
node,
|
|
15
|
-
key,
|
|
16
|
-
interactables,
|
|
17
|
-
value,
|
|
18
|
-
}: {
|
|
19
|
-
node: Lunch.Node
|
|
20
|
-
key: string
|
|
21
|
-
interactables: Ref<Lunch.Node[]>
|
|
22
|
-
value: any
|
|
23
|
-
}) {
|
|
24
|
-
// handle and return early if prop is an event
|
|
25
|
-
// (event list from react-three-fiber)
|
|
26
|
-
if (isEventKey(key)) {
|
|
27
|
-
return addEventListener({ node, key, interactables, value })
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// update THREE property
|
|
31
|
-
// get final key
|
|
32
|
-
const camelKey = key.replace(/-/g, '.')
|
|
33
|
-
const finalKey = propertyShortcuts[camelKey] || camelKey
|
|
34
|
-
|
|
35
|
-
// handle and return early if prop is specific to Vue/Lunchbox
|
|
36
|
-
if (
|
|
37
|
-
internalLunchboxVueKeys.includes(key) ||
|
|
38
|
-
internalLunchboxVueKeys.includes(finalKey)
|
|
39
|
-
)
|
|
40
|
-
return node
|
|
41
|
-
|
|
42
|
-
// everything else should be Three-specific, so let's cancel if this isn't a standard node
|
|
43
|
-
if (!isLunchboxStandardNode(node)) return node
|
|
44
|
-
|
|
45
|
-
// parse $attached values
|
|
46
|
-
if (typeof value === 'string' && value.startsWith('$attached')) {
|
|
47
|
-
const attachedName = value.replace('$attached.', '')
|
|
48
|
-
value = get(node.attached, attachedName, null)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// save instance
|
|
52
|
-
const target = node.instance
|
|
53
|
-
|
|
54
|
-
// cancel if no target
|
|
55
|
-
if (!target) return node
|
|
56
|
-
|
|
57
|
-
// burrow down until we get property to change
|
|
58
|
-
let liveProperty: any
|
|
59
|
-
for (let i = 0; i < nestedPropertiesToCheck.length && !liveProperty; i++) {
|
|
60
|
-
const nestedProperty = nestedPropertiesToCheck[i]
|
|
61
|
-
const fullPath = [nestedProperty, finalKey].filter(Boolean).join('.')
|
|
62
|
-
liveProperty = liveProperty = get(target, fullPath)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// change property
|
|
66
|
-
// first, save as array in case we need to spread it
|
|
67
|
-
if (liveProperty && isNumber(value) && liveProperty?.setScalar) {
|
|
68
|
-
// if value is a number and the property has a `setScalar` method, use that
|
|
69
|
-
liveProperty.setScalar(value)
|
|
70
|
-
} else if (liveProperty && liveProperty.set) {
|
|
71
|
-
// if property has `set` method, use that (https://github.com/pmndrs/react-three-fiber/blob/master/markdown/api.md#shortcuts)
|
|
72
|
-
const nextValueAsArray = Array.isArray(value) ? value : [value]
|
|
73
|
-
;(target as any)[finalKey].set(...nextValueAsArray)
|
|
74
|
-
} else if (typeof liveProperty === 'function') {
|
|
75
|
-
// some function properties are set rather than called, so let's handle them
|
|
76
|
-
if (
|
|
77
|
-
finalKey.toLowerCase() === 'onbeforerender' ||
|
|
78
|
-
finalKey.toLowerCase() === 'onafterrender'
|
|
79
|
-
) {
|
|
80
|
-
;(target as any)[finalKey] = value
|
|
81
|
-
} else {
|
|
82
|
-
if (!Array.isArray(value)) {
|
|
83
|
-
throw new Error(
|
|
84
|
-
'Arguments on a declarative method must be wrapped in an array.\nWorks:\n<example :methodCall="[256]" />\nDoesn\'t work:\n<example :methodCall="256" />'
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
// if property is a function, let's try calling it
|
|
88
|
-
liveProperty.bind(node.instance)(...value)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// pass the result to the parent
|
|
92
|
-
// const parent = node.parentNode
|
|
93
|
-
// if (parent) {
|
|
94
|
-
// const parentAsLunchboxNode = parent as Lunchbox.Node
|
|
95
|
-
// parentAsLunchboxNode.attached[finalKey] = result
|
|
96
|
-
// ; (parentAsLunchboxNode.instance as any)[finalKey] = result
|
|
97
|
-
// }
|
|
98
|
-
} else if (get(target, finalKey, undefined) !== undefined) {
|
|
99
|
-
// blank strings evaluate to `true`
|
|
100
|
-
// <mesh castShadow receiveShadow /> will work the same as
|
|
101
|
-
// <mesh :castShadow="true" :receiveShadow="true" />
|
|
102
|
-
set(target, finalKey, value === '' ? true : value)
|
|
103
|
-
} else {
|
|
104
|
-
// if you see this error in production, you might need to add `finalKey`
|
|
105
|
-
// to `internalLunchboxVueKeys` below
|
|
106
|
-
console.log(`No property ${finalKey} found on ${target}`)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// mark that we need to update if needed
|
|
110
|
-
const targetTypeRaw =
|
|
111
|
-
(target as any)?.texture?.type || (target as any)?.type
|
|
112
|
-
if (typeof targetTypeRaw === 'string') {
|
|
113
|
-
const targetType = targetTypeRaw.toLowerCase()
|
|
114
|
-
|
|
115
|
-
switch (true) {
|
|
116
|
-
case targetType.includes('material'):
|
|
117
|
-
;(target as unknown as THREE.Material).needsUpdate = true
|
|
118
|
-
break
|
|
119
|
-
case targetType.includes('camera') &&
|
|
120
|
-
(target as any).updateProjectionMatrix:
|
|
121
|
-
;(
|
|
122
|
-
target as unknown as
|
|
123
|
-
| THREE.PerspectiveCamera
|
|
124
|
-
| THREE.OrthographicCamera
|
|
125
|
-
).updateProjectionMatrix()
|
|
126
|
-
break
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return node
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const propertyShortcuts: { [key: string]: string } = {
|
|
134
|
-
x: 'position.x',
|
|
135
|
-
y: 'position.y',
|
|
136
|
-
z: 'position.z',
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export const nestedPropertiesToCheck = ['', 'parameters']
|
|
140
|
-
|
|
141
|
-
/** props that Lunchbox intercepts and prevents passing to created instances */
|
|
142
|
-
const internalLunchboxVueKeys = [
|
|
143
|
-
'args',
|
|
144
|
-
'attach',
|
|
145
|
-
'attachArray',
|
|
146
|
-
'is.default',
|
|
147
|
-
'isDefault',
|
|
148
|
-
'key',
|
|
149
|
-
'onAdded',
|
|
150
|
-
// 'onReady',
|
|
151
|
-
'ref',
|
|
152
|
-
'src',
|
|
153
|
-
]
|
package/src/index.ts
DELETED
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
computed,
|
|
3
|
-
createRenderer,
|
|
4
|
-
Component,
|
|
5
|
-
ComputedRef,
|
|
6
|
-
inject,
|
|
7
|
-
watch,
|
|
8
|
-
reactive,
|
|
9
|
-
Ref,
|
|
10
|
-
WatchStopHandle,
|
|
11
|
-
toRaw,
|
|
12
|
-
} from 'vue'
|
|
13
|
-
import { createNodeOps } from './nodeOps'
|
|
14
|
-
import { extend, MiniDom } from './core'
|
|
15
|
-
import { components } from './components'
|
|
16
|
-
import { Lunch } from './types'
|
|
17
|
-
|
|
18
|
-
export * from './core'
|
|
19
|
-
export * from './types'
|
|
20
|
-
|
|
21
|
-
import * as Keys from './keys'
|
|
22
|
-
export * from './keys'
|
|
23
|
-
|
|
24
|
-
// Utilities
|
|
25
|
-
export * from './utils/find'
|
|
26
|
-
|
|
27
|
-
/** The current camera as a computed value. */
|
|
28
|
-
export const useCamera = <T extends THREE.Camera = THREE.Camera>() =>
|
|
29
|
-
inject<ComputedRef<T>>(Keys.appCameraKey)!
|
|
30
|
-
/** Run a function using the current camera when it's present. */
|
|
31
|
-
export const onCameraReady = <T extends THREE.Camera = THREE.Camera>(
|
|
32
|
-
cb: (camera?: T) => void
|
|
33
|
-
) => {
|
|
34
|
-
const existing = useCamera<T>()
|
|
35
|
-
if (existing.value) {
|
|
36
|
-
cb(existing.value)
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let stopWatch: WatchStopHandle | null = null
|
|
41
|
-
stopWatch = watch(useCamera<T>(), (newVal) => {
|
|
42
|
-
if (newVal) {
|
|
43
|
-
cb(newVal)
|
|
44
|
-
stopWatch?.()
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** The current renderer as a computed value. */
|
|
50
|
-
export const useRenderer = <T extends THREE.Renderer = THREE.WebGLRenderer>() =>
|
|
51
|
-
inject<ComputedRef<T>>(Keys.appRenderersKey)!
|
|
52
|
-
/** Run a function using the current renderer when it's present. */
|
|
53
|
-
export const onRendererReady = <T extends THREE.Renderer = THREE.Renderer>(
|
|
54
|
-
cb: (renderer?: T) => void
|
|
55
|
-
) => {
|
|
56
|
-
const existing = useRenderer<T>()
|
|
57
|
-
if (existing.value) {
|
|
58
|
-
cb(existing.value)
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
let stopWatch: WatchStopHandle | null = null
|
|
63
|
-
stopWatch = watch(
|
|
64
|
-
useRenderer<T>(),
|
|
65
|
-
(newVal) => {
|
|
66
|
-
if (newVal) {
|
|
67
|
-
cb(newVal)
|
|
68
|
-
stopWatch?.()
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
{ immediate: true }
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** The current scene as a computed value. */
|
|
76
|
-
export const useScene = <T extends THREE.Scene = THREE.Scene>() =>
|
|
77
|
-
inject<ComputedRef<T>>(Keys.appSceneKey)!
|
|
78
|
-
/** Run a function using the current scene when it's present. */
|
|
79
|
-
export const onSceneReady = <T extends THREE.Scene = THREE.Scene>(
|
|
80
|
-
cb: (scene?: T) => void
|
|
81
|
-
) => {
|
|
82
|
-
const existing = useScene<T>()
|
|
83
|
-
if (existing.value) {
|
|
84
|
-
cb(existing.value)
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
let stopWatch: WatchStopHandle | null = null
|
|
89
|
-
stopWatch = watch(
|
|
90
|
-
useScene<T>(),
|
|
91
|
-
(newVal) => {
|
|
92
|
-
if (newVal) {
|
|
93
|
-
cb(newVal)
|
|
94
|
-
stopWatch?.()
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
{ immediate: true }
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// CUSTOM RENDER SUPPORT
|
|
102
|
-
// ====================
|
|
103
|
-
/** Set a custom render function, overriding the Lunchbox app's default render function.
|
|
104
|
-
* Changing this requires the user to manually render their scene.
|
|
105
|
-
*
|
|
106
|
-
* Invokes immediately - use `useCustomRender().setCustomRender`
|
|
107
|
-
* if you need to call somewhere outside of `setup`.
|
|
108
|
-
*/
|
|
109
|
-
export const setCustomRender = (
|
|
110
|
-
render: (opts: Lunch.UpdateCallbackProperties) => void
|
|
111
|
-
) => {
|
|
112
|
-
useCustomRender()?.setCustomRender?.(render)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Clear the active app's custom render function.
|
|
116
|
-
*
|
|
117
|
-
* Invokes immediately - use `useCustomRender().clearCustomRender`
|
|
118
|
-
* if you need to call somewhere outside of `setup`.
|
|
119
|
-
*/
|
|
120
|
-
export const clearCustomRender = () => {
|
|
121
|
-
useCustomRender()?.clearCustomRender?.()
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** Provides `setCustomRender` and `clearCustomRender` functions to be called in a non-`setup` context. */
|
|
125
|
-
export const useCustomRender = () => {
|
|
126
|
-
return {
|
|
127
|
-
/** Set a custom render function, overriding the Lunchbox app's default render function.
|
|
128
|
-
* Changing this requires the user to manually render their scene. */
|
|
129
|
-
setCustomRender: inject<Lunch.CustomRenderFunctionSetter>(
|
|
130
|
-
Keys.setCustomRenderKey
|
|
131
|
-
),
|
|
132
|
-
/** Clear the active app's custom render function. */
|
|
133
|
-
clearCustomRender: inject<() => void>(Keys.clearCustomRenderKey),
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** Use app-level globals. */
|
|
138
|
-
export const useGlobals = () =>
|
|
139
|
-
inject<Lunch.AppGlobals>(Keys.globalsInjectionKey)!
|
|
140
|
-
|
|
141
|
-
/** Construct a function to update your app-level globals.
|
|
142
|
-
*
|
|
143
|
-
* ```js
|
|
144
|
-
* // in setup():
|
|
145
|
-
* const updateGlobals = useUpdateGlobals()
|
|
146
|
-
*
|
|
147
|
-
* // ...later, to update the device pixel resolution...
|
|
148
|
-
* updateGlobals({ dpr: 2 })
|
|
149
|
-
* ```
|
|
150
|
-
*/
|
|
151
|
-
export const useUpdateGlobals = () =>
|
|
152
|
-
inject<Lunch.AppGlobalsUpdate>(Keys.updateGlobalsInjectionKey)
|
|
153
|
-
|
|
154
|
-
/** Update app-level globals.
|
|
155
|
-
*
|
|
156
|
-
* Invokes immediately - use `useUpdateGlobals`
|
|
157
|
-
* if you need to call somewhere outside of `setup`.
|
|
158
|
-
*/
|
|
159
|
-
export const updateGlobals = (newValue: Partial<Lunch.AppGlobals>) => {
|
|
160
|
-
useUpdateGlobals()?.(newValue)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** Use the current Lunchbox app. Usually used internally by Lunchbox. */
|
|
164
|
-
export const useApp = () => inject<Lunch.App>(Keys.appKey)
|
|
165
|
-
|
|
166
|
-
/** Obtain a list of the start callback functions. Usually used internally by Lunchbox. */
|
|
167
|
-
export const useStartCallbacks = () =>
|
|
168
|
-
inject<Lunch.UpdateCallback[]>(Keys.startCallbackKey)
|
|
169
|
-
|
|
170
|
-
/** Run a given callback once when the Lunchbox app starts. Include an index to
|
|
171
|
-
* splice the callback at that index in the callback queue. */
|
|
172
|
-
export const onStart = (cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
173
|
-
const callbacks = useStartCallbacks()
|
|
174
|
-
if (index === Infinity) {
|
|
175
|
-
callbacks?.push(cb)
|
|
176
|
-
} else {
|
|
177
|
-
callbacks?.splice(index, 0, cb)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/** Obtain a list of interactable objects (registered via onClick, onHover, etc events). Usually used internally by Lunchbox. */
|
|
182
|
-
export const useLunchboxInteractables = () =>
|
|
183
|
-
inject<Ref<Lunch.Node[]>>(Keys.lunchboxInteractables)
|
|
184
|
-
|
|
185
|
-
/** Build a computed instance-getter from a specified ref. Defaults to a `toRaw`'d result. */
|
|
186
|
-
export const getInstance = <T = unknown>(
|
|
187
|
-
target: Ref<Lunch.LunchboxComponent<T> | Lunch.Node<T> | null>,
|
|
188
|
-
raw = true
|
|
189
|
-
) =>
|
|
190
|
-
computed(() => {
|
|
191
|
-
const output =
|
|
192
|
-
(target.value as Lunch.LunchboxComponent<T>)?.$el?.instance ??
|
|
193
|
-
(target.value as Lunch.Node<T>)?.instance ??
|
|
194
|
-
null
|
|
195
|
-
if (output && raw) return toRaw(output)
|
|
196
|
-
return output
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
// CREATE APP
|
|
200
|
-
// ====================
|
|
201
|
-
export const createApp = (
|
|
202
|
-
root: Component,
|
|
203
|
-
rootProps: Record<string, any> = {}
|
|
204
|
-
) => {
|
|
205
|
-
const { nodeOps, interactables } = createNodeOps()
|
|
206
|
-
const app = createRenderer(nodeOps).createApp(root, rootProps) as Lunch.App
|
|
207
|
-
|
|
208
|
-
// provide Lunchbox interaction handlers flag (modified when user references events via
|
|
209
|
-
// @click, etc)
|
|
210
|
-
app.provide(Keys.lunchboxInteractables, interactables)
|
|
211
|
-
|
|
212
|
-
// register all components
|
|
213
|
-
// ====================
|
|
214
|
-
Object.keys(components).forEach((key) => {
|
|
215
|
-
app?.component(key, (components as any)[key])
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
// provide custom renderer functions
|
|
219
|
-
// ====================
|
|
220
|
-
app.provide(
|
|
221
|
-
Keys.setCustomRenderKey,
|
|
222
|
-
(render: (opts: Lunch.UpdateCallbackProperties) => void) => {
|
|
223
|
-
app.setCustomRender(render)
|
|
224
|
-
}
|
|
225
|
-
)
|
|
226
|
-
app.provide(Keys.clearCustomRenderKey, () => {
|
|
227
|
-
app.clearCustomRender()
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
// before render
|
|
231
|
-
// ====================
|
|
232
|
-
const beforeRender = [] as Lunch.UpdateCallback[]
|
|
233
|
-
app.provide(Keys.beforeRenderKey, beforeRender)
|
|
234
|
-
app.provide(
|
|
235
|
-
Keys.onBeforeRenderKey,
|
|
236
|
-
(cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
237
|
-
if (index === Infinity) {
|
|
238
|
-
beforeRender.push(cb)
|
|
239
|
-
} else {
|
|
240
|
-
beforeRender.splice(index, 0, cb)
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
)
|
|
244
|
-
app.provide(
|
|
245
|
-
Keys.offBeforeRenderKey,
|
|
246
|
-
(cb: Lunch.UpdateCallback | number) => {
|
|
247
|
-
if (isFinite(cb as number)) {
|
|
248
|
-
beforeRender.splice(cb as number, 1)
|
|
249
|
-
} else {
|
|
250
|
-
const idx = beforeRender.findIndex((v) => v == cb)
|
|
251
|
-
if (idx !== -1) {
|
|
252
|
-
beforeRender.splice(idx, 1)
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
// after render
|
|
259
|
-
// ====================
|
|
260
|
-
const afterRender = [] as Lunch.UpdateCallback[]
|
|
261
|
-
app.provide(Keys.afterRenderKey, afterRender)
|
|
262
|
-
app.provide(
|
|
263
|
-
Keys.onAfterRenderKey,
|
|
264
|
-
(cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
265
|
-
if (index === Infinity) {
|
|
266
|
-
afterRender.push(cb)
|
|
267
|
-
} else {
|
|
268
|
-
afterRender.splice(index, 0, cb)
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
)
|
|
272
|
-
app.provide(Keys.offAfterRenderKey, (cb: Lunch.UpdateCallback | number) => {
|
|
273
|
-
if (isFinite(cb as number)) {
|
|
274
|
-
afterRender.splice(cb as number, 1)
|
|
275
|
-
} else {
|
|
276
|
-
const idx = afterRender.findIndex((v) => v == cb)
|
|
277
|
-
if (idx !== -1) {
|
|
278
|
-
afterRender.splice(idx, 1)
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
// save app-level components
|
|
284
|
-
// ====================
|
|
285
|
-
app.config.globalProperties.lunchbox = reactive({
|
|
286
|
-
afterRender,
|
|
287
|
-
beforeRender,
|
|
288
|
-
camera: null,
|
|
289
|
-
dpr: 1,
|
|
290
|
-
frameId: -1,
|
|
291
|
-
renderer: null,
|
|
292
|
-
scene: null,
|
|
293
|
-
watchStopHandle: null,
|
|
294
|
-
|
|
295
|
-
// TODO: inputActive, mousePos
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
// provide app-level globals & globals update method
|
|
299
|
-
// ====================
|
|
300
|
-
app.provide(Keys.globalsInjectionKey, app.config.globalProperties.lunchbox)
|
|
301
|
-
app.provide<Lunch.AppGlobalsUpdate>(
|
|
302
|
-
Keys.updateGlobalsInjectionKey,
|
|
303
|
-
(newGlobals: Partial<Lunch.AppGlobals>) => {
|
|
304
|
-
Object.keys(newGlobals).forEach((key) => {
|
|
305
|
-
const typedKey = key as keyof Lunch.AppGlobals
|
|
306
|
-
// TODO: fix
|
|
307
|
-
app.config.globalProperties.lunchbox[typedKey] = newGlobals[
|
|
308
|
-
typedKey
|
|
309
|
-
] as any
|
|
310
|
-
})
|
|
311
|
-
}
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
// frame ID (used for update functions)
|
|
315
|
-
// ====================
|
|
316
|
-
app.provide(Keys.frameIdKey, app.config.globalProperties.lunchbox.frameId)
|
|
317
|
-
|
|
318
|
-
// watch stop handler (used for conditional update loop)
|
|
319
|
-
// ====================
|
|
320
|
-
app.provide(
|
|
321
|
-
Keys.watchStopHandleKey,
|
|
322
|
-
app.config.globalProperties.lunchbox.watchStopHandle
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
// update mount function to match Lunchbox.Node
|
|
326
|
-
// ====================
|
|
327
|
-
const { mount } = app
|
|
328
|
-
app.mount = (root, ...args) => {
|
|
329
|
-
// find DOM element to use as app root
|
|
330
|
-
const domElement = (
|
|
331
|
-
typeof root === 'string' ? document.querySelector(root) : root
|
|
332
|
-
) as HTMLElement
|
|
333
|
-
// create or find root node
|
|
334
|
-
const rootNode = new MiniDom.RendererRootNode({
|
|
335
|
-
domElement,
|
|
336
|
-
isLunchboxRootNode: true,
|
|
337
|
-
name: 'root',
|
|
338
|
-
metaType: 'rootMeta',
|
|
339
|
-
type: 'root',
|
|
340
|
-
uuid: 'LUNCHBOX_ROOT',
|
|
341
|
-
})
|
|
342
|
-
app.rootNode = rootNode
|
|
343
|
-
app.provide(Keys.appRootNodeKey, rootNode)
|
|
344
|
-
const mounted = mount(rootNode, ...args)
|
|
345
|
-
return mounted
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// embed .extend function
|
|
349
|
-
// ====================
|
|
350
|
-
app.extend = (targets: Record<string, any>) => {
|
|
351
|
-
extend({ app: app!, ...targets })
|
|
352
|
-
return app!
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// start callback functions
|
|
356
|
-
// ====================
|
|
357
|
-
const startCallbacks: Lunch.UpdateCallback[] = []
|
|
358
|
-
app.provide(Keys.startCallbackKey, startCallbacks)
|
|
359
|
-
|
|
360
|
-
// prep for custom render support
|
|
361
|
-
// ====================
|
|
362
|
-
app.setCustomRender = (
|
|
363
|
-
newRender: (opts: Lunch.UpdateCallbackProperties) => void
|
|
364
|
-
) => {
|
|
365
|
-
if (app) {
|
|
366
|
-
app.customRender = newRender
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// add custom render removal
|
|
371
|
-
app.clearCustomRender = () => {
|
|
372
|
-
if (app) {
|
|
373
|
-
app.customRender = null
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// provide app
|
|
378
|
-
// ====================
|
|
379
|
-
app.provide(Keys.appKey, app)
|
|
380
|
-
app.provide(
|
|
381
|
-
Keys.appRenderersKey,
|
|
382
|
-
computed(() => app.config.globalProperties.lunchbox.renderer)
|
|
383
|
-
)
|
|
384
|
-
app.provide(
|
|
385
|
-
Keys.appSceneKey,
|
|
386
|
-
computed(() => app.config.globalProperties.lunchbox.scene)
|
|
387
|
-
)
|
|
388
|
-
app.provide(
|
|
389
|
-
Keys.appCameraKey,
|
|
390
|
-
computed(() => app.config.globalProperties.lunchbox.camera)
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
app._props
|
|
394
|
-
|
|
395
|
-
// done
|
|
396
|
-
return app
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/** Use this plugin to add a <lunchbox> component in your HTML app. */
|
|
400
|
-
export { bridge as lunchbox } from './plugins/bridge/bridge'
|