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.
@@ -1,70 +1,83 @@
1
- import { RendererOptions } from 'vue'
1
+ import { RendererOptions, ref } from 'vue'
2
2
  import { createElement } from './createElement'
3
3
  import { insert } from './insert'
4
4
  import { remove } from './remove'
5
5
  import { isLunchboxDomComponent, isLunchboxRootNode } from '../utils'
6
- import {
7
- createCommentNode,
8
- createTextNode,
9
- MiniDom,
10
- updateObjectProp,
11
- } from '../core'
12
- import { Lunch } from '..'
6
+ import { createCommentNode, createTextNode, updateObjectProp } from '../core'
7
+ import type { MiniDom } from '../core'
8
+ import type { Lunch } from '..'
13
9
 
14
10
  /*
15
11
  Elements are `create`d from the outside in, then `insert`ed from the inside out.
16
12
  */
17
13
 
18
- export const nodeOps: RendererOptions<
19
- MiniDom.RendererBaseNode,
20
- MiniDom.RendererBaseNode
21
- > = {
22
- createElement,
23
- createText(text) {
24
- return createTextNode({ text })
25
- },
26
- createComment(text) {
27
- return createCommentNode({ text })
28
- },
29
- insert,
30
- nextSibling(node) {
31
- const result = node.nextSibling
32
- // console.log('found', result)
33
- if (!result) return null
34
- return result as MiniDom.RendererBaseNode
35
- },
36
- parentNode(node) {
37
- const result = node.parentNode
38
- if (!result) return null
39
- return result as MiniDom.RendererBaseNode
40
- },
41
- patchProp(node, key, prevValue, nextValue) {
42
- if (isLunchboxDomComponent(node)) {
43
- // handle DOM node
44
- if (key === 'style') {
45
- // special handling for style
46
- Object.keys(nextValue).forEach((k) => {
47
- ;(node.domElement.style as any)[k] = nextValue[k]
48
- })
49
- } else {
50
- node.domElement.setAttribute(key, nextValue)
14
+ export const createNodeOps = () => {
15
+ // APP-LEVEL GLOBALS
16
+ // ====================
17
+ // These need to exist at the app level in a place where the node ops can access them.
18
+ // It'd be better to set these via `app.provide` at app creation, but the node ops need access
19
+ // to these values before the app is instantiated, so this is the next-best place for them to exist.
20
+ const interactables = ref([] as Lunch.Node[])
21
+
22
+ // NODE OPS
23
+ // ====================
24
+ const nodeOps: RendererOptions<
25
+ MiniDom.RendererBaseNode,
26
+ MiniDom.RendererBaseNode
27
+ > = {
28
+ createElement,
29
+ createText(text) {
30
+ return createTextNode({ text })
31
+ },
32
+ createComment(text) {
33
+ return createCommentNode({ text })
34
+ },
35
+ insert,
36
+ nextSibling(node) {
37
+ const result = node.nextSibling
38
+ if (!result) return null
39
+ return result as MiniDom.RendererBaseNode
40
+ },
41
+ parentNode(node) {
42
+ const result = node.parentNode
43
+ if (!result) return null
44
+ return result as MiniDom.RendererBaseNode
45
+ },
46
+ patchProp(node, key, prevValue, nextValue) {
47
+ if (isLunchboxDomComponent(node)) {
48
+ // handle DOM node
49
+ if (key === 'style') {
50
+ // special handling for style
51
+ Object.keys(nextValue).forEach((k) => {
52
+ ;(node.domElement.style as any)[k] = nextValue[k]
53
+ })
54
+ } else {
55
+ node.domElement.setAttribute(key, nextValue)
56
+ }
57
+ return
58
+ }
59
+
60
+ // ignore if root node, or Lunchbox internal prop
61
+ if (isLunchboxRootNode(node) || key.startsWith('$')) {
62
+ return
51
63
  }
52
- return
53
- }
54
64
 
55
- // ignore if root node, or Lunchbox internal prop
56
- if (isLunchboxRootNode(node) || key.startsWith('$')) {
57
- return
58
- }
65
+ // otherwise, update prop
66
+ updateObjectProp({
67
+ node: node as Lunch.Node,
68
+ key,
69
+ interactables,
70
+ value: nextValue,
71
+ })
72
+ },
73
+ remove,
74
+ setElementText() {
75
+ // noop
76
+ },
77
+ setText() {
78
+ // noop
79
+ },
80
+ }
59
81
 
60
- // otherwise, update prop
61
- updateObjectProp({ node: node as Lunch.Node, key, value: nextValue })
62
- },
63
- remove,
64
- setElementText() {
65
- // noop
66
- },
67
- setText() {
68
- // noop
69
- },
82
+ return { nodeOps, interactables }
70
83
  }
package/src/types.ts CHANGED
@@ -36,10 +36,6 @@ export declare namespace Lunch {
36
36
  update: UpdateCallback
37
37
  }
38
38
 
39
- // type AppGlobals = {
40
- // /** Device pixel resolution */
41
- // dpr: number
42
- // }
43
39
  type AppGlobals = App['config']['globalProperties']['lunchbox']
44
40
 
45
41
  type AppGlobalsUpdate = (newValue: Partial<AppGlobals>) => void
@@ -159,10 +155,6 @@ export declare namespace Lunch {
159
155
  renderer?: THREE.Renderer | null
160
156
  camera?: THREE.Camera | null
161
157
  updateSource?: WatchSource | null
162
-
163
- // sceneNode: Node<THREE.Scene> | null
164
- // rendererNode: Node<THREE.Renderer> | null
165
- // cameraNode: Node<THREE.Camera> | null
166
158
  }
167
159
 
168
160
  /** Universally unique identifier. */
@@ -1,3 +0,0 @@
1
- import { Lunch } from '..'
2
-
3
- export const catalogue: Lunch.Catalogue = {}
@@ -1,102 +0,0 @@
1
- import { watch } from 'vue'
2
- import {
3
- addInteractable,
4
- interactables,
5
- removeInteractable,
6
- } from './interactables'
7
- // import { ensuredRaycaster } from '..'
8
- import { inputActive } from './input'
9
- import { currentIntersections } from '.'
10
- import { Lunch } from '../..'
11
-
12
- export * from './input'
13
- export * from './interactables'
14
- export * from './setupAutoRaycaster'
15
-
16
- /** Add an event listener to the given node. Also creates the event teardown function and any necessary raycaster/interaction dictionary updates. */
17
- export function addEventListener({
18
- node,
19
- key,
20
- value,
21
- }: {
22
- node: Lunch.Node
23
- key: Lunch.EventKey
24
- value: Lunch.EventCallback
25
- }) {
26
- // create new records for this key if needed
27
- if (!node.eventListeners[key]) {
28
- node.eventListeners[key] = []
29
- }
30
- if (!node.eventListenerRemoveFunctions[key]) {
31
- node.eventListenerRemoveFunctions[key] = []
32
- }
33
-
34
- // add event listener
35
- node.eventListeners[key].push(value)
36
-
37
- // if we need it, let's get/create the main raycaster
38
- if (interactionsRequiringRaycaster.includes(key)) {
39
- // we're not using `v` here, we're just making sure the raycaster has been created
40
- // TODO: is this necessary?
41
- // const v = ensuredRaycaster.value
42
-
43
- if (node.instance && !interactables.includes(node)) {
44
- addInteractable(node)
45
- node.eventListenerRemoveFunctions[key].push(() =>
46
- removeInteractable(node)
47
- )
48
- }
49
- }
50
-
51
- // register click, pointerdown, pointerup
52
- if (key === 'onClick' || key === 'onPointerDown' || key === 'onPointerUp') {
53
- const stop = watch(
54
- () => inputActive.value,
55
- (isDown) => {
56
- const idx = currentIntersections
57
- .map((v) => v.element)
58
- .findIndex(
59
- (v) =>
60
- v.instance &&
61
- v.instance.uuid === node.instance?.uuid
62
- )
63
- if (idx !== -1) {
64
- if (
65
- isDown &&
66
- (key === 'onClick' || key === 'onPointerDown')
67
- ) {
68
- node.eventListeners[key].forEach((func) => {
69
- func({
70
- intersection:
71
- currentIntersections[idx].intersection,
72
- })
73
- })
74
- } else if (!isDown && key === 'onPointerUp') {
75
- node.eventListeners[key].forEach((func) => {
76
- func({
77
- intersection:
78
- currentIntersections[idx].intersection,
79
- })
80
- })
81
- }
82
- }
83
- }
84
- )
85
-
86
- node.eventListenerRemoveFunctions[key].push(stop)
87
- }
88
-
89
- return node
90
- }
91
-
92
- const interactionsRequiringRaycaster = [
93
- 'onClick',
94
- 'onPointerUp',
95
- 'onPointerDown',
96
- 'onPointerOver',
97
- 'onPointerOut',
98
- 'onPointerEnter',
99
- 'onPointerLeave',
100
- 'onPointerMove',
101
- // 'onPointerMissed',
102
- ]
@@ -1,4 +0,0 @@
1
- import { ref } from 'vue'
2
-
3
- /** Mouse is down, touch is pressed, etc */
4
- export const inputActive = ref(false)
@@ -1,14 +0,0 @@
1
- import { Lunch } from '../..'
2
-
3
- export const interactables: Array<Lunch.Node> = []
4
-
5
- export const addInteractable = (target: Lunch.Node) => {
6
- interactables.push(target)
7
- }
8
-
9
- export const removeInteractable = (target: Lunch.Node) => {
10
- const idx = interactables.indexOf(target)
11
- if (idx !== -1) {
12
- interactables.splice(idx, 1)
13
- }
14
- }
@@ -1,232 +0,0 @@
1
- // import { interactables } from '.'
2
- // import {
3
- // ensuredCamera,
4
- // // ensuredRaycaster,
5
- // ensureRenderer,
6
- // onBeforeRender,
7
- // } from '..'
8
- import {
9
- // globals,
10
- Lunch,
11
- useGlobals,
12
- } from '../../'
13
- import { ref, watch, WatchStopHandle } from 'vue'
14
- import { inputActive } from './input'
15
- import { Intersection } from 'three'
16
-
17
- // let mouseMoveListener: (event: MouseEvent) => void
18
- // let mouseDownListener: (event: MouseEvent) => void
19
- // let mouseUpListener: (event: MouseEvent) => void
20
-
21
- export const mousePos = ref({ x: Infinity, y: Infinity })
22
- // let autoRaycasterEventsInitialized = false
23
-
24
- // let frameID: number
25
-
26
- // export const setupAutoRaycaster = (node: Lunch.Node<THREE.Raycaster>) => {
27
- // const instance = node.instance
28
-
29
- // if (!instance) return
30
-
31
- // // TODO: inject doesn't work here. replace this raycaster with a component so we can
32
- // // `inject` in `setup`?
33
- // const appLevelGlobals = { dpr: window.devicePixelRatio } //useGlobals()
34
-
35
- // // add mouse events once renderer is ready
36
- // let stopWatcher: WatchStopHandle | null = null
37
- // stopWatcher = watch(
38
- // () => ensureRenderer.value,
39
- // (renderer) => {
40
- // // make sure renderer exists
41
- // if (!renderer?.instance) return
42
-
43
- // // cancel early if autoraycaster exists
44
- // if (autoRaycasterEventsInitialized) {
45
- // if (stopWatcher) stopWatcher()
46
- // return
47
- // }
48
-
49
- // // create mouse events
50
- // mouseMoveListener = (evt) => {
51
- // const screenWidth =
52
- // (renderer.instance!.domElement.width ?? 1) /
53
- // appLevelGlobals.dpr
54
- // const screenHeight =
55
- // (renderer.instance!.domElement.height ?? 1) /
56
- // appLevelGlobals.dpr
57
-
58
- // mousePos.value.x = (evt.offsetX / screenWidth) * 2 - 1
59
- // mousePos.value.y = -(evt.offsetY / screenHeight) * 2 + 1
60
- // }
61
- // mouseDownListener = () => (inputActive.value = true)
62
- // mouseUpListener = () => (inputActive.value = false)
63
-
64
- // // add mouse events
65
- // renderer.instance.domElement.addEventListener(
66
- // 'mousemove',
67
- // mouseMoveListener
68
- // )
69
- // renderer.instance.domElement.addEventListener(
70
- // 'mousedown',
71
- // mouseDownListener
72
- // )
73
- // renderer.instance.domElement.addEventListener(
74
- // 'mouseup',
75
- // mouseUpListener
76
- // )
77
-
78
- // // TODO: add touch events
79
-
80
- // // process mouse events asynchronously, whenever the mouse state changes
81
- // watch(
82
- // () => [inputActive.value, mousePos.value.x, mousePos.value.y],
83
- // () => {
84
- // if (frameID) cancelAnimationFrame(frameID)
85
- // frameID = requestAnimationFrame(() => {
86
- // autoRaycasterBeforeRender()
87
- // })
88
- // }
89
- // )
90
-
91
- // // mark complete
92
- // autoRaycasterEventsInitialized = true
93
-
94
- // // cancel setup watcher
95
- // if (stopWatcher) {
96
- // stopWatcher()
97
- // }
98
- // },
99
- // { immediate: true }
100
- // )
101
- // }
102
-
103
- // AUTO-RAYCASTER CALLBACK
104
- // ====================
105
- export let currentIntersections: Array<{
106
- element: Lunch.Node
107
- intersection: Intersection<THREE.Object3D>
108
- }> = []
109
-
110
- // const autoRaycasterBeforeRender = () => {
111
- // // setup
112
- // const raycaster = ensuredRaycaster.value?.instance
113
- // const camera = ensuredCamera.value?.instance
114
- // if (!raycaster || !camera) return
115
-
116
- // raycaster.setFromCamera(globals.mousePos.value, camera)
117
- // const intersections = raycaster.intersectObjects(
118
- // interactables.map((v) => v.instance as any as THREE.Object3D)
119
- // )
120
-
121
- // let enterValues: Array<Intersection<THREE.Object3D>> = [],
122
- // sameValues: Array<Intersection<THREE.Object3D>> = [],
123
- // leaveValues: Array<Intersection<THREE.Object3D>> = [],
124
- // entering: Array<{
125
- // element: Lunch.Node
126
- // intersection: Intersection<THREE.Object3D>
127
- // }> = [],
128
- // staying: Array<{
129
- // element: Lunch.Node
130
- // intersection: Intersection<THREE.Object3D>
131
- // }> = []
132
-
133
- // // intersection arrays
134
- // leaveValues = currentIntersections.map((v) => v.intersection)
135
-
136
- // // element arrays
137
- // intersections?.forEach((intersection) => {
138
- // const currentIdx = currentIntersections.findIndex(
139
- // (v) => v.intersection.object === intersection.object
140
- // )
141
- // if (currentIdx === -1) {
142
- // // new intersection
143
- // enterValues.push(intersection)
144
-
145
- // const found = interactables.find(
146
- // (v) => v.instance?.uuid === intersection.object.uuid
147
- // )
148
- // if (found) {
149
- // entering.push({ element: found, intersection })
150
- // }
151
- // } else {
152
- // // existing intersection
153
- // sameValues.push(intersection)
154
-
155
- // const found = interactables.find(
156
- // (v) => v.instance?.uuid === intersection.object.uuid
157
- // )
158
- // if (found) {
159
- // staying.push({ element: found, intersection })
160
- // }
161
- // }
162
- // // this is a current intersection, so it won't be in our `leave` array
163
- // const leaveIdx = leaveValues.findIndex(
164
- // (v) => v.object.uuid === intersection.object.uuid
165
- // )
166
- // if (leaveIdx !== -1) {
167
- // leaveValues.splice(leaveIdx, 1)
168
- // }
169
- // })
170
-
171
- // const leaving: Array<{
172
- // element: Lunch.Node
173
- // intersection: Intersection<THREE.Object3D>
174
- // }> = leaveValues.map((intersection) => {
175
- // return {
176
- // element: interactables.find(
177
- // (interactable) =>
178
- // interactable.instance?.uuid === intersection.object.uuid
179
- // ) as any as Lunch.Node,
180
- // intersection,
181
- // }
182
- // })
183
-
184
- // // new interactions
185
- // entering.forEach(({ element, intersection }) => {
186
- // fireEventsFromIntersections({
187
- // element,
188
- // eventKeys: ['onPointerEnter'],
189
- // intersection,
190
- // })
191
- // })
192
-
193
- // // unchanged interactions
194
- // staying.forEach(({ element, intersection }) => {
195
- // const eventKeys: Array<Lunch.EventKey> = [
196
- // 'onPointerOver',
197
- // 'onPointerMove',
198
- // ]
199
- // fireEventsFromIntersections({ element, eventKeys, intersection })
200
- // })
201
-
202
- // // exited interactions
203
- // leaving.forEach(({ element, intersection }) => {
204
- // const eventKeys: Array<Lunch.EventKey> = [
205
- // 'onPointerLeave',
206
- // 'onPointerOut',
207
- // ]
208
- // fireEventsFromIntersections({ element, eventKeys, intersection })
209
- // })
210
-
211
- // currentIntersections = ([] as any).concat(entering, staying)
212
- // }
213
-
214
- // utility function for firing multiple callbacks and multiple events on a Lunchbox.Element
215
- // const fireEventsFromIntersections = ({
216
- // element,
217
- // eventKeys,
218
- // intersection,
219
- // }: {
220
- // element: Lunch.Node
221
- // eventKeys: Array<Lunch.EventKey>
222
- // intersection: Intersection<THREE.Object3D>
223
- // }) => {
224
- // if (!element) return
225
- // eventKeys.forEach((eventKey) => {
226
- // if (element.eventListeners[eventKey]) {
227
- // element.eventListeners[eventKey].forEach((cb) => {
228
- // cb({ intersection })
229
- // })
230
- // }
231
- // })
232
- // }