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
package/src/index.ts CHANGED
@@ -1,82 +1,79 @@
1
- import { computed, createRenderer, Component, ref, watch } from 'vue'
2
- import { nodeOps } from './nodeOps'
3
1
  import {
4
- // createdCamera,
5
- // createdRenderer,
6
- // autoScene,
7
- ensuredCamera,
8
- ensureRenderer,
9
- ensuredScene,
10
- ensureRootNode,
11
- extend,
12
- inputActive,
13
- mousePos,
14
- rootUuid,
15
- } from './core'
2
+ computed,
3
+ createRenderer,
4
+ Component,
5
+ ComputedRef,
6
+ inject,
7
+ watch,
8
+ reactive,
9
+ Ref,
10
+ } from 'vue'
11
+ import { createNodeOps } from './nodeOps'
12
+ import { extend, MiniDom } from './core'
16
13
  import { components } from './components'
17
14
  import { Lunch } from './types'
18
15
 
19
- export { lunchboxRootNode as lunchboxTree } from './core'
20
- export {
21
- offAfterRender,
22
- offBeforeRender,
23
- onAfterRender,
24
- onBeforeRender,
25
- onStart,
26
- } from './core'
16
+ export * from './core'
27
17
  export * from './types'
28
18
 
19
+ import * as Keys from './keys'
20
+ export * from './keys'
21
+
29
22
  // Utilities
30
23
  export * from './utils/find'
31
24
 
32
- /** Useful globals. */
33
- export const globals = {
34
- dpr: ref(1),
35
- inputActive,
36
- mousePos,
37
- }
38
-
39
- /** The current camera. Often easier to use `useCamera` instead of this. */
40
- export const camera = computed(() => ensuredCamera.value?.instance ?? null)
25
+ /** The current camera as a computed value. */
26
+ export const useCamera = <T extends THREE.Camera = THREE.Camera>() =>
27
+ inject<ComputedRef<T>>(Keys.appCameraKey)!
41
28
  /** Run a function using the current camera when it's present. */
42
- export function useCamera<T extends THREE.Camera = THREE.PerspectiveCamera>(
43
- callback: (cam: T) => void
44
- ) {
45
- return watch(
46
- camera,
29
+ export const onCameraReady = <T extends THREE.Camera = THREE.Camera>(
30
+ cb: (camera?: T) => void
31
+ ) => {
32
+ const stopWatch = watch(
33
+ useCamera<T>(),
47
34
  (newVal) => {
48
- if (!newVal) return
49
- callback(newVal as unknown as T)
35
+ if (newVal) {
36
+ cb(newVal)
37
+ stopWatch()
38
+ }
50
39
  },
51
40
  { immediate: true }
52
41
  )
53
42
  }
54
43
 
55
- /** The current renderer. Often easier to use `useRenderer` instead of this. */
56
- export const renderer = computed(() => ensureRenderer.value?.instance ?? null)
44
+ /** The current renderer as a computed value. */
45
+ export const useRenderer = <T extends THREE.Renderer = THREE.WebGLRenderer>() =>
46
+ inject<ComputedRef<T>>(Keys.appRenderersKey)!
57
47
  /** Run a function using the current renderer when it's present. */
58
- export function useRenderer<T extends THREE.Renderer = THREE.WebGLRenderer>(
59
- callback: (rend: T) => void
60
- ) {
61
- return watch(
62
- renderer,
48
+ export const onRendererReady = <T extends THREE.Renderer = THREE.Renderer>(
49
+ cb: (renderer?: T) => void
50
+ ) => {
51
+ const stopWatch = watch(
52
+ useRenderer<T>(),
63
53
  (newVal) => {
64
- if (!newVal) return
65
- callback(newVal as unknown as T)
54
+ if (newVal) {
55
+ cb(newVal)
56
+ stopWatch()
57
+ }
66
58
  },
67
59
  { immediate: true }
68
60
  )
69
61
  }
70
62
 
71
- /** The current scene. Often easier to use `useScene` instead of this. */
72
- export const scene = computed(() => ensuredScene.value.instance)
63
+ /** The current scene as a computed value. */
64
+ export const useScene = <T extends THREE.Scene = THREE.Scene>() =>
65
+ inject<ComputedRef<T>>(Keys.appSceneKey)!
73
66
  /** Run a function using the current scene when it's present. */
74
- export function useScene(callback: (newScene: THREE.Scene) => void) {
75
- return watch(
76
- scene,
67
+ export const onSceneReady = <T extends THREE.Scene = THREE.Scene>(
68
+ cb: (scene?: T) => void
69
+ ) => {
70
+ const stopWatch = watch(
71
+ useScene<T>(),
77
72
  (newVal) => {
78
- if (!newVal) return
79
- callback(newVal as any)
73
+ if (newVal) {
74
+ cb(newVal)
75
+ stopWatch()
76
+ }
80
77
  },
81
78
  { immediate: true }
82
79
  )
@@ -84,38 +81,213 @@ export function useScene(callback: (newScene: THREE.Scene) => void) {
84
81
 
85
82
  // CUSTOM RENDER SUPPORT
86
83
  // ====================
87
- let app: Lunch.App | null = null
88
- let queuedCustomRenderFunction:
89
- | ((opts: Lunch.UpdateCallbackProperties) => void)
90
- | null = null
91
-
92
84
  /** Set a custom render function, overriding the Lunchbox app's default render function.
93
85
  * Changing this requires the user to manually render their scene.
86
+ *
87
+ * Invokes immediately - use `useCustomRender().setCustomRender`
88
+ * if you need to call somewhere outside of `setup`.
94
89
  */
95
90
  export const setCustomRender = (
96
91
  render: (opts: Lunch.UpdateCallbackProperties) => void
97
92
  ) => {
98
- if (app) app.setCustomRender(render)
99
- else queuedCustomRenderFunction = render
93
+ useCustomRender()?.setCustomRender?.(render)
100
94
  }
101
95
 
102
- /** Clear the active app's custom render function. */
96
+ /** Clear the active app's custom render function.
97
+ *
98
+ * Invokes immediately - use `useCustomRender().clearCustomRender`
99
+ * if you need to call somewhere outside of `setup`.
100
+ */
103
101
  export const clearCustomRender = () => {
104
- if (app) app.clearCustomRender()
105
- else queuedCustomRenderFunction = null
102
+ useCustomRender()?.clearCustomRender?.()
103
+ }
104
+
105
+ /** Provides `setCustomRender` and `clearCustomRender` functions to be called in a non-`setup` context. */
106
+ export const useCustomRender = () => {
107
+ return {
108
+ /** Set a custom render function, overriding the Lunchbox app's default render function.
109
+ * Changing this requires the user to manually render their scene. */
110
+ setCustomRender: inject<Lunch.CustomRenderFunctionSetter>(
111
+ Keys.setCustomRenderKey
112
+ ),
113
+ /** Clear the active app's custom render function. */
114
+ clearCustomRender: inject<() => void>(Keys.clearCustomRenderKey),
115
+ }
116
+ }
117
+
118
+ /** Use app-level globals. */
119
+ export const useGlobals = () =>
120
+ inject<Lunch.AppGlobals>(Keys.globalsInjectionKey)!
121
+
122
+ /** Construct a function to update your app-level globals.
123
+ *
124
+ * ```js
125
+ * // in setup():
126
+ * const updateGlobals = useUpdateGlobals()
127
+ *
128
+ * // ...later, to update the device pixel resolution...
129
+ * updateGlobals({ dpr: 2 })
130
+ * ```
131
+ */
132
+ export const useUpdateGlobals = () =>
133
+ inject<Lunch.AppGlobalsUpdate>(Keys.updateGlobalsInjectionKey)
134
+
135
+ /** Update app-level globals.
136
+ *
137
+ * Invokes immediately - use `useUpdateGlobals`
138
+ * if you need to call somewhere outside of `setup`.
139
+ */
140
+ export const updateGlobals = (newValue: Partial<Lunch.AppGlobals>) => {
141
+ useUpdateGlobals()?.(newValue)
142
+ }
143
+
144
+ /** Use the current Lunchbox app. Usually used internally by Lunchbox. */
145
+ export const useApp = () => inject<Lunch.App>(Keys.appKey)
146
+
147
+ /** Obtain a list of the start callback functions. Usually used internally by Lunchbox. */
148
+ export const useStartCallbacks = () =>
149
+ inject<Lunch.UpdateCallback[]>(Keys.startCallbackKey)
150
+
151
+ /** Run a given callback once when the Lunchbox app starts. Include an index to
152
+ * splice the callback at that index in the callback queue. */
153
+ export const onStart = (cb: Lunch.UpdateCallback, index = Infinity) => {
154
+ const callbacks = useStartCallbacks()
155
+ if (index === Infinity) {
156
+ callbacks?.push(cb)
157
+ } else {
158
+ callbacks?.splice(index, 0, cb)
159
+ }
106
160
  }
107
161
 
162
+ /** Obtain a list of interactable objects (registered via onClick, onHover, etc events). Usually used internally by Lunchbox. */
163
+ export const useLunchboxInteractables = () =>
164
+ inject<Ref<Lunch.Node[]>>(Keys.lunchboxInteractables)
165
+
108
166
  // CREATE APP
109
167
  // ====================
110
168
  export const createApp = (root: Component) => {
111
- app = createRenderer(nodeOps).createApp(root) as Lunch.App
169
+ const { nodeOps, interactables } = createNodeOps()
170
+ const app = createRenderer(nodeOps).createApp(root) as Lunch.App
171
+
172
+ // provide Lunchbox interaction handlers flag (modified when user references events via
173
+ // @click, etc)
174
+ app.provide(Keys.lunchboxInteractables, interactables)
112
175
 
113
176
  // register all components
177
+ // ====================
114
178
  Object.keys(components).forEach((key) => {
115
179
  app?.component(key, (components as any)[key])
116
180
  })
117
181
 
182
+ // provide custom renderer functions
183
+ // ====================
184
+ app.provide(
185
+ Keys.setCustomRenderKey,
186
+ (render: (opts: Lunch.UpdateCallbackProperties) => void) => {
187
+ app.setCustomRender(render)
188
+ }
189
+ )
190
+ app.provide(Keys.clearCustomRenderKey, () => {
191
+ app.clearCustomRender()
192
+ })
193
+
194
+ // before render
195
+ // ====================
196
+ const beforeRender = [] as Lunch.UpdateCallback[]
197
+ app.provide(Keys.beforeRenderKey, beforeRender)
198
+ app.provide(
199
+ Keys.onBeforeRenderKey,
200
+ (cb: Lunch.UpdateCallback, index = Infinity) => {
201
+ if (index === Infinity) {
202
+ beforeRender.push(cb)
203
+ } else {
204
+ beforeRender.splice(index, 0, cb)
205
+ }
206
+ }
207
+ )
208
+ app.provide(
209
+ Keys.offBeforeRenderKey,
210
+ (cb: Lunch.UpdateCallback | number) => {
211
+ if (isFinite(cb as number)) {
212
+ beforeRender.splice(cb as number, 1)
213
+ } else {
214
+ const idx = beforeRender.findIndex((v) => v == cb)
215
+ if (idx !== -1) {
216
+ beforeRender.splice(idx, 1)
217
+ }
218
+ }
219
+ }
220
+ )
221
+
222
+ // after render
223
+ // ====================
224
+ const afterRender = [] as Lunch.UpdateCallback[]
225
+ app.provide(Keys.afterRenderKey, afterRender)
226
+ app.provide(
227
+ Keys.onAfterRenderKey,
228
+ (cb: Lunch.UpdateCallback, index = Infinity) => {
229
+ if (index === Infinity) {
230
+ afterRender.push(cb)
231
+ } else {
232
+ afterRender.splice(index, 0, cb)
233
+ }
234
+ }
235
+ )
236
+ app.provide(Keys.offAfterRenderKey, (cb: Lunch.UpdateCallback | number) => {
237
+ if (isFinite(cb as number)) {
238
+ afterRender.splice(cb as number, 1)
239
+ } else {
240
+ const idx = afterRender.findIndex((v) => v == cb)
241
+ if (idx !== -1) {
242
+ afterRender.splice(idx, 1)
243
+ }
244
+ }
245
+ })
246
+
247
+ // save app-level components
248
+ // ====================
249
+ app.config.globalProperties.lunchbox = reactive({
250
+ afterRender,
251
+ beforeRender,
252
+ camera: null,
253
+ dpr: 1,
254
+ frameId: -1,
255
+ renderer: null,
256
+ scene: null,
257
+ watchStopHandle: null,
258
+
259
+ // TODO: inputActive, mousePos
260
+ })
261
+
262
+ // provide app-level globals & globals update method
263
+ // ====================
264
+ app.provide(Keys.globalsInjectionKey, app.config.globalProperties.lunchbox)
265
+ app.provide<Lunch.AppGlobalsUpdate>(
266
+ Keys.updateGlobalsInjectionKey,
267
+ (newGlobals: Partial<Lunch.AppGlobals>) => {
268
+ Object.keys(newGlobals).forEach((key) => {
269
+ const typedKey = key as keyof Lunch.AppGlobals
270
+ // TODO: fix
271
+ app.config.globalProperties.lunchbox[typedKey] = newGlobals[
272
+ typedKey
273
+ ] as any
274
+ })
275
+ }
276
+ )
277
+
278
+ // frame ID (used for update functions)
279
+ // ====================
280
+ app.provide(Keys.frameIdKey, app.config.globalProperties.lunchbox.frameId)
281
+
282
+ // watch stop handler (used for conditional update loop)
283
+ // ====================
284
+ app.provide(
285
+ Keys.watchStopHandleKey,
286
+ app.config.globalProperties.lunchbox.watchStopHandle
287
+ )
288
+
118
289
  // update mount function to match Lunchbox.Node
290
+ // ====================
119
291
  const { mount } = app
120
292
  app.mount = (root, ...args) => {
121
293
  // find DOM element to use as app root
@@ -123,43 +295,65 @@ export const createApp = (root: Component) => {
123
295
  typeof root === 'string' ? document.querySelector(root) : root
124
296
  ) as HTMLElement
125
297
  // create or find root node
126
- const rootNode = ensureRootNode({
298
+ const rootNode = new MiniDom.RendererRootNode({
127
299
  domElement,
128
300
  isLunchboxRootNode: true,
129
301
  name: 'root',
130
302
  metaType: 'rootMeta',
131
303
  type: 'root',
132
- uuid: rootUuid,
304
+ uuid: 'LUNCHBOX_ROOT',
133
305
  })
134
- app!.rootNode = rootNode
306
+ app.rootNode = rootNode
307
+ app.provide(Keys.appRootNodeKey, rootNode)
135
308
  const mounted = mount(rootNode, ...args)
136
309
  return mounted
137
310
  }
138
311
 
139
312
  // embed .extend function
313
+ // ====================
140
314
  app.extend = (targets: Record<string, any>) => {
141
315
  extend({ app: app!, ...targets })
142
316
  return app!
143
317
  }
144
318
 
319
+ // start callback functions
320
+ // ====================
321
+ const startCallbacks: Lunch.UpdateCallback[] = []
322
+ app.provide(Keys.startCallbackKey, startCallbacks)
323
+
145
324
  // prep for custom render support
325
+ // ====================
146
326
  app.setCustomRender = (
147
327
  newRender: (opts: Lunch.UpdateCallbackProperties) => void
148
328
  ) => {
149
- app!.customRender = newRender
150
- }
151
-
152
- // add queued custom render if we have one
153
- if (queuedCustomRenderFunction) {
154
- app.setCustomRender(queuedCustomRenderFunction)
155
- queuedCustomRenderFunction = null
329
+ if (app) {
330
+ app.customRender = newRender
331
+ }
156
332
  }
157
333
 
158
334
  // add custom render removal
159
335
  app.clearCustomRender = () => {
160
- app!.customRender = null
336
+ if (app) {
337
+ app.customRender = null
338
+ }
161
339
  }
162
340
 
341
+ // provide app
342
+ // ====================
343
+ app.provide(Keys.appKey, app)
344
+ app.provide(
345
+ Keys.appRenderersKey,
346
+ computed(() => app.config.globalProperties.lunchbox.renderer)
347
+ )
348
+ app.provide(
349
+ Keys.appSceneKey,
350
+ computed(() => app.config.globalProperties.lunchbox.scene)
351
+ )
352
+ app.provide(
353
+ Keys.appCameraKey,
354
+ computed(() => app.config.globalProperties.lunchbox.camera)
355
+ )
356
+
163
357
  // done
164
358
  return app
165
359
  }
package/src/keys.ts ADDED
@@ -0,0 +1,25 @@
1
+ export const globalsInjectionKey = Symbol()
2
+ export const updateGlobalsInjectionKey = Symbol()
3
+
4
+ export const setCustomRenderKey = Symbol()
5
+ export const clearCustomRenderKey = Symbol()
6
+
7
+ export const beforeRenderKey = Symbol()
8
+ export const onBeforeRenderKey = Symbol()
9
+ export const offBeforeRenderKey = Symbol()
10
+
11
+ export const afterRenderKey = Symbol()
12
+ export const onAfterRenderKey = Symbol()
13
+ export const offAfterRenderKey = Symbol()
14
+
15
+ export const frameIdKey = Symbol()
16
+ export const watchStopHandleKey = Symbol()
17
+
18
+ export const appRootNodeKey = Symbol()
19
+ export const appKey = Symbol()
20
+ export const appRenderersKey = Symbol()
21
+ export const appSceneKey = Symbol()
22
+ export const appCameraKey = Symbol()
23
+ export const lunchboxInteractables = Symbol()
24
+
25
+ export const startCallbackKey = Symbol()
@@ -10,13 +10,10 @@ export const createElement = (
10
10
  isCustomizedBuiltin?: string,
11
11
  vnodeProps?: Lunch.LunchboxMetaProps
12
12
  ) => {
13
- const options = { type } as Partial<Lunch.MetaBase>
14
- if (vnodeProps) {
15
- options.props = vnodeProps
16
- }
13
+ const options: Partial<Lunch.MetaBase> = { type, props: vnodeProps }
17
14
 
18
15
  // handle dom node
19
- const isDomNode = isLunchboxDomComponent(type)
16
+ const isDomNode = isLunchboxDomComponent(options)
20
17
  if (isDomNode) {
21
18
  const node = createDomNode(options)
22
19
  return node
@@ -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
  }