lunchboxjs 0.1.4016 → 0.2.1001-beta.0

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.
@@ -3,7 +3,6 @@ import {
3
3
  isLunchboxRootNode,
4
4
  isLunchboxStandardNode,
5
5
  } from '../utils'
6
- import { ensureRootNode, ensuredScene } from '../core'
7
6
  import { MiniDom } from '../core/minidom'
8
7
  import { Lunch } from '..'
9
8
 
@@ -12,9 +11,12 @@ export const insert = (
12
11
  parent: MiniDom.RendererBaseNode | null,
13
12
  anchor?: MiniDom.RendererBaseNode | null
14
13
  ) => {
14
+ if (!parent) {
15
+ throw new Error('missing parent')
16
+ }
15
17
  // add to parent tree node if we have one
16
- let effectiveParent = parent ?? ensureRootNode()
17
- effectiveParent.insertBefore(child, anchor)
18
+ // let effectiveParent = parent ?? ensureRootNode()
19
+ parent.insertBefore(child, anchor)
18
20
 
19
21
  // handle comment & text nodes
20
22
  if (child.metaType === 'commentMeta' || child.metaType === 'textMeta') {
@@ -33,54 +35,31 @@ export const insert = (
33
35
  // handle standard nodes
34
36
  if (isLunchboxStandardNode(child)) {
35
37
  // let effectiveParent = parent
36
- let effectiveParentNodeType = effectiveParent.metaType
38
+ let effectiveParentNodeType = parent.metaType
37
39
 
38
40
  if (
39
41
  effectiveParentNodeType === 'textMeta' ||
40
42
  effectiveParentNodeType === 'commentMeta'
41
43
  ) {
42
- const path = effectiveParent.getPath() as MiniDom.RendererBaseNode[]
44
+ const path = parent.getPath() as MiniDom.RendererBaseNode[]
43
45
  for (let i = path.length - 1; i >= 0; i--) {
44
46
  if (
45
47
  path[i].metaType !== 'textMeta' &&
46
48
  path[i].metaType !== 'commentMeta'
47
49
  ) {
48
- effectiveParent = path[i]
50
+ parent = path[i]
49
51
  break
50
52
  }
51
53
  }
52
54
  }
53
55
 
54
- // add to scene if parent is the wrapper node
55
56
  if (
56
- child.metaType === 'standardMeta' &&
57
- child.type !== 'scene' &&
58
- isLunchboxRootNode(effectiveParent)
59
- ) {
60
- // ensure scene exists
61
- const sceneNode = ensuredScene.value
62
-
63
- if (sceneNode.instance && child) {
64
- sceneNode.addChild(child)
65
- }
66
- if (
67
- child.instance &&
68
- child.instance.isObject3D &&
69
- sceneNode.instance
70
- ) {
71
- if (sceneNode !== child) {
72
- sceneNode.instance.add(child.instance)
73
- }
74
- }
75
- }
76
- // add to hierarchy otherwise
77
- else if (
78
57
  isLunchboxStandardNode(child) &&
79
58
  child.instance?.isObject3D &&
80
- isLunchboxStandardNode(effectiveParent) &&
81
- effectiveParent.instance?.isObject3D
59
+ isLunchboxStandardNode(parent) &&
60
+ parent.instance?.isObject3D
82
61
  ) {
83
- effectiveParent.instance?.add?.(child.instance)
62
+ parent.instance?.add?.(child.instance)
84
63
  }
85
64
 
86
65
  // add attached props
@@ -1,10 +1,8 @@
1
- import { allNodes, MiniDom } from '../core'
1
+ import { MiniDom } from '../core'
2
2
  import { isLunchboxStandardNode } from '../utils'
3
- import { overrides } from '../core'
4
3
 
5
4
  export const remove = (node: MiniDom.RendererBaseNode) => {
6
5
  if (!node) return
7
- const overrideKeys = Object.keys(overrides)
8
6
  // prep subtree
9
7
  const subtree: MiniDom.BaseNode[] = []
10
8
  node.walk((descendant) => {
@@ -14,14 +12,6 @@ export const remove = (node: MiniDom.RendererBaseNode) => {
14
12
 
15
13
  // clean up subtree
16
14
  subtree.forEach((n) => {
17
- const overrideKey = overrideKeys.find(
18
- (key) => overrides[key]?.uuid === n.uuid
19
- )
20
- // if this node is an override, remove it from the overrides list
21
- if (overrideKey) {
22
- overrides[overrideKey] = null
23
- }
24
-
25
15
  if (isLunchboxStandardNode(n)) {
26
16
  // try to remove three object
27
17
  n.instance?.removeFromParent?.()
@@ -38,11 +28,5 @@ export const remove = (node: MiniDom.RendererBaseNode) => {
38
28
 
39
29
  // drop tree node
40
30
  n.drop()
41
-
42
- // remove Lunchbox node from main list
43
- const idx = allNodes.findIndex((v) => v.uuid === n.uuid)
44
- if (idx !== -1) {
45
- allNodes.splice(idx, 1)
46
- }
47
31
  })
48
32
  }
package/src/types.ts CHANGED
@@ -1,14 +1,32 @@
1
+ type RendererStandardNode<T = THREE.Object3D> =
2
+ import('./core').MiniDom.RendererStandardNode<T>
1
3
  type RootNode = import('./core/minidom').MiniDom.RendererRootNode
2
4
  type VNodeProps = import('vue').VNodeProps
3
5
  type VueApp<T> = import('vue').App<T>
4
6
  type WatchSource = import('vue').WatchSource
5
- type RendererStandardNode<T = THREE.Object3D> =
6
- import('./core').MiniDom.RendererStandardNode<T>
7
+ type WatchStopHandle = import('vue').WatchStopHandle
8
+ type ThreeCamera = import('three').Camera
9
+ type ThreeRenderer = import('three').Renderer
10
+ type ThreeScene = import('three').Scene
7
11
 
8
12
  export declare namespace Lunch {
9
13
  /** Lunchbox app. */
10
- type App = VueApp<any> & {
14
+ type App = Omit<VueApp<any>, 'config'> & {
11
15
  clearCustomRender: () => void
16
+ config: Omit<VueApp<any>['config'], 'globalProperties'> & {
17
+ globalProperties: {
18
+ lunchbox: {
19
+ afterRender: Lunch.UpdateCallback[]
20
+ beforeRender: Lunch.UpdateCallback[]
21
+ camera: ThreeCamera | null
22
+ dpr: number
23
+ frameId: number
24
+ renderer: ThreeRenderer | null
25
+ scene: ThreeScene | null
26
+ watchStopHandle: WatchStopHandle | null
27
+ }
28
+ } & Record<string, any>
29
+ }
12
30
  customRender: ((opts: UpdateCallbackProperties) => void) | null
13
31
  extend: (v: Record<string, any>) => App
14
32
  rootNode: RootNode
@@ -18,6 +36,14 @@ export declare namespace Lunch {
18
36
  update: UpdateCallback
19
37
  }
20
38
 
39
+ // type AppGlobals = {
40
+ // /** Device pixel resolution */
41
+ // dpr: number
42
+ // }
43
+ type AppGlobals = App['config']['globalProperties']['lunchbox']
44
+
45
+ type AppGlobalsUpdate = (newValue: Partial<AppGlobals>) => void
46
+
21
47
  interface CanvasProps {
22
48
  dpr?: number
23
49
  wrapperProps?: WrapperProps
@@ -34,6 +60,10 @@ export declare namespace Lunch {
34
60
  text: string
35
61
  }
36
62
 
63
+ type CustomRenderFunctionSetter = (
64
+ render: (opts: Lunch.UpdateCallbackProperties) => void
65
+ ) => void
66
+
37
67
  interface DomMeta extends MetaBase {
38
68
  domElement: HTMLElement
39
69
  }
@@ -138,12 +168,16 @@ export declare namespace Lunch {
138
168
  /** Universally unique identifier. */
139
169
  type Uuid = string
140
170
 
171
+ type SizePolicy = 'full' | 'container'
172
+
173
+ type Vector3AsArray = [number, number, number]
174
+
141
175
  interface WrapperProps {
142
176
  background?: string
143
177
  cameraArgs?: any[]
144
- cameraLook?: [number, number, number]
145
- cameraLookAt?: [number, number, number]
146
- cameraPosition?: [number, number, number]
178
+ cameraLook?: Vector3AsArray
179
+ cameraLookAt?: Vector3AsArray
180
+ cameraPosition?: Vector3AsArray
147
181
  dpr?: number
148
182
  ortho?: boolean
149
183
  orthographic?: boolean
@@ -151,6 +185,7 @@ export declare namespace Lunch {
151
185
  // TODO: Why doesn't ConstructorParameters<THREE.WebGLRenderer> work here?
152
186
  rendererArguments?: object
153
187
  rendererProperties?: Partial<THREE.WebGLRenderer>
188
+ sizePolicy?: SizePolicy
154
189
  shadow?: ShadowSugar
155
190
  transparent?: boolean
156
191
  zoom?: number
@@ -1,4 +1,3 @@
1
- import { lunchboxDomComponentNames } from '../components'
2
1
  import { Lunch } from '..'
3
2
 
4
3
  export * from './find'
@@ -32,9 +31,7 @@ export const isLunchboxComponent = (
32
31
  export const isLunchboxDomComponent = (node: any): node is Lunch.DomMeta => {
33
32
  if ((node as Lunch.MetaBase)?.metaType === 'domMeta') return true
34
33
 
35
- const typeToCheck = typeof node === 'string' ? node : node?.type
36
-
37
- return lunchboxDomComponentNames.includes(typeToCheck ?? '')
34
+ return node?.props?.['data-lunchbox']
38
35
  }
39
36
 
40
37
  export const isLunchboxStandardNode = (
package/dist/.DS_Store DELETED
Binary file
package/src/.DS_Store DELETED
Binary file
@@ -1,306 +0,0 @@
1
- import {
2
- h,
3
- ComponentOptions,
4
- getCurrentInstance,
5
- onBeforeUnmount,
6
- onMounted,
7
- ref,
8
- WatchSource,
9
- WritableComputedRef,
10
- } from 'vue'
11
- import {
12
- cameraReady,
13
- cancelUpdate,
14
- cancelUpdateSource,
15
- createNode,
16
- ensuredCamera,
17
- ensureRenderer,
18
- ensuredScene,
19
- fallbackCameraUuid,
20
- fallbackRendererUuid,
21
- MiniDom,
22
- rendererReady,
23
- startCallbacks,
24
- tryGetNodeWithInstanceType,
25
- update,
26
- } from '../../core'
27
- import { set } from 'lodash'
28
- import { globals, Lunch } from '../..'
29
- // import { Color, Vector2, sRGBEncoding, ACESFilmicToneMapping } from 'three'
30
- import * as THREE from 'three'
31
- import { prepCanvas } from './prepCanvas'
32
-
33
- // TODO:
34
- // Continue r3f prop - what else (besides camera fov) makes r3f look good?
35
-
36
- /** fixed & fill styling for container */
37
- const fillStyle = (position: string) => {
38
- return {
39
- position,
40
- top: 0,
41
- right: 0,
42
- bottom: 0,
43
- left: 0,
44
- width: '100%',
45
- height: '100%',
46
- }
47
- }
48
-
49
- export const LunchboxWrapper: ComponentOptions = {
50
- name: 'Lunchbox',
51
- props: {
52
- // These should match the Lunchbox.WrapperProps interface
53
- background: String,
54
- cameraArgs: Array,
55
- cameraLook: Array,
56
- cameraLookAt: Array,
57
- cameraPosition: Array,
58
- dpr: Number,
59
- ortho: Boolean,
60
- orthographic: Boolean,
61
- r3f: Boolean,
62
- rendererArguments: Object,
63
- rendererProperties: Object,
64
- shadow: [Boolean, Object],
65
- transparent: Boolean,
66
- zoom: Number,
67
- updateSource: Object,
68
- },
69
- setup(props: Lunch.WrapperProps, context) {
70
- const canvas = ref<MiniDom.RendererDomNode>()
71
- const useFallbackRenderer = ref(true)
72
- const dpr = ref(props.dpr ?? -1)
73
- const container = ref<MiniDom.RendererDomNode>()
74
- let renderer: Lunch.Node<THREE.WebGLRenderer> | null
75
- let camera: Lunch.Node<THREE.Camera> | null
76
- let scene: MiniDom.RendererStandardNode<THREE.Scene>
77
-
78
- // https://threejs.org/docs/index.html#manual/en/introduction/Color-management
79
- if (props.r3f && (THREE as any)?.ColorManagement) {
80
- ;(THREE as any).ColorManagement.legacyMode = false
81
- }
82
-
83
- // MOUNT
84
- // ====================
85
- onMounted(() => {
86
- // canvas needs to exist
87
- if (!canvas.value) throw new Error('missing canvas')
88
-
89
- // RENDERER
90
- // ====================
91
- // is there already a renderer?
92
- // TODO: allow other renderer types
93
- renderer = tryGetNodeWithInstanceType([
94
- 'WebGLRenderer',
95
- ]) as unknown as Lunch.Node<THREE.WebGLRenderer> | null
96
-
97
- // if renderer is missing, initialize with options
98
- if (!renderer) {
99
- // build renderer args
100
- const rendererArgs: THREE.WebGLRendererParameters = {
101
- alpha: props.transparent,
102
- antialias: true,
103
- canvas: canvas.value.domElement,
104
- powerPreference: !!props.r3f
105
- ? 'high-performance'
106
- : 'default',
107
- ...(props.rendererArguments ?? {}),
108
- }
109
-
110
- // create new renderer
111
- ensureRenderer.value = createNode<THREE.WebGLRenderer>({
112
- type: 'WebGLRenderer',
113
- uuid: fallbackRendererUuid,
114
- props: {
115
- args: [rendererArgs],
116
- },
117
- })
118
-
119
- // we've initialized the renderer, so anything depending on it can execute now
120
- rendererReady.value = true
121
-
122
- const rendererAsWebGlRenderer =
123
- ensureRenderer as WritableComputedRef<
124
- Lunch.Node<THREE.WebGLRenderer>
125
- >
126
-
127
- // apply r3f settings if desired
128
- if (props.r3f) {
129
- if (rendererAsWebGlRenderer.value.instance) {
130
- rendererAsWebGlRenderer.value.instance.outputEncoding =
131
- THREE.sRGBEncoding
132
- rendererAsWebGlRenderer.value.instance.toneMapping =
133
- THREE.ACESFilmicToneMapping
134
- }
135
- }
136
-
137
- // update render sugar
138
- const sugar = {
139
- shadow: props.shadow,
140
- }
141
- if (rendererAsWebGlRenderer.value.instance && sugar?.shadow) {
142
- rendererAsWebGlRenderer.value.instance.shadowMap.enabled =
143
- true
144
- if (typeof sugar.shadow === 'object') {
145
- rendererAsWebGlRenderer.value.instance.shadowMap.type =
146
- sugar.shadow.type
147
- }
148
- }
149
-
150
- // set renderer props if needed
151
- if (props.rendererProperties) {
152
- Object.keys(props.rendererProperties).forEach((key) => {
153
- set(
154
- rendererAsWebGlRenderer.value,
155
- key,
156
- (props.rendererProperties as any)[key]
157
- )
158
- })
159
- }
160
-
161
- // update using created renderer
162
- renderer = rendererAsWebGlRenderer.value
163
- } else {
164
- useFallbackRenderer.value = false
165
- // the user has initialized the renderer, so anything depending
166
- // on the renderer can execute
167
- rendererReady.value = true
168
- }
169
-
170
- // CAMERA
171
- // ====================
172
- // is there already a camera?
173
- camera = tryGetNodeWithInstanceType([
174
- 'PerspectiveCamera',
175
- 'OrthographicCamera',
176
- ])
177
- // if not, let's create one
178
- if (!camera) {
179
- // create ortho camera
180
- if (props.ortho || props.orthographic) {
181
- ensuredCamera.value = createNode<THREE.OrthographicCamera>({
182
- props: { args: props.cameraArgs ?? [] },
183
- type: 'OrthographicCamera',
184
- uuid: fallbackCameraUuid,
185
- })
186
- } else {
187
- ensuredCamera.value = createNode<THREE.PerspectiveCamera>({
188
- props: {
189
- args: props.cameraArgs ?? [
190
- props.r3f ? 75 : 45,
191
- 0.5625,
192
- 1,
193
- 1000,
194
- ],
195
- },
196
- type: 'PerspectiveCamera',
197
- uuid: fallbackCameraUuid,
198
- })
199
- }
200
-
201
- cameraReady.value = true
202
-
203
- camera = ensuredCamera.value
204
- } else {
205
- cameraReady.value = true
206
- }
207
- if (!camera.instance) {
208
- throw new Error('Error creating camera.')
209
- }
210
- // move camera if needed
211
- if (camera && props.cameraPosition) {
212
- camera.instance.position.set(...props.cameraPosition)
213
- }
214
- // angle camera if needed
215
- if (camera && (props.cameraLookAt || props.cameraLook)) {
216
- const source = (props.cameraLookAt || props.cameraLook)!
217
- camera.instance.lookAt(...source)
218
- }
219
- // zoom camera if needed
220
- if (camera && props.zoom !== undefined) {
221
- ;(camera.instance as THREE.OrthographicCamera).zoom = props.zoom
222
- }
223
-
224
- // SCENE
225
- // ====================
226
- scene = ensuredScene.value
227
- // set background color
228
- if (scene && scene.instance && props.background) {
229
- scene.instance.background = new THREE.Color(props.background)
230
- }
231
-
232
- // MISC PROPERTIES
233
- // ====================
234
- if (dpr.value === -1) {
235
- dpr.value = window.devicePixelRatio
236
- }
237
-
238
- if (renderer?.instance) {
239
- renderer.instance.setPixelRatio(dpr.value)
240
- globals.dpr.value = dpr.value
241
- // prep canvas (sizing, observe, unmount, etc)
242
- prepCanvas(
243
- container,
244
- renderer.instance.domElement,
245
- onBeforeUnmount
246
- )
247
- } else {
248
- throw new Error('missing renderer')
249
- }
250
-
251
- // CALLBACK PREP
252
- // ====================
253
- const app = getCurrentInstance()!.appContext.app as Lunch.App
254
-
255
- // START
256
- // ====================
257
- for (let startCallback of startCallbacks) {
258
- startCallback({
259
- app,
260
- camera: camera.instance,
261
- renderer: renderer.instance,
262
- scene: scene.instance,
263
- })
264
- }
265
-
266
- // KICK UPDATE
267
- // ====================
268
- update({
269
- app,
270
- camera: camera.instance,
271
- renderer: renderer.instance,
272
- scene: scene.instance,
273
- updateSource: props.updateSource,
274
- })
275
- })
276
-
277
- // UNMOUNT
278
- // ====================
279
- onBeforeUnmount(() => {
280
- cancelUpdate()
281
- cancelUpdateSource()
282
- })
283
-
284
- // RENDER FUNCTION
285
- // ====================
286
- return () => [
287
- context.slots.default?.() ?? null,
288
- h(
289
- 'div',
290
- {
291
- style: fillStyle('absolute'),
292
- ref: container,
293
- },
294
- [
295
- useFallbackRenderer.value
296
- ? h('canvas', {
297
- style: fillStyle('fixed'),
298
- class: 'lunchbox-canvas',
299
- ref: canvas,
300
- })
301
- : null,
302
- ]
303
- ),
304
- ]
305
- },
306
- }
Binary file
@@ -1,4 +0,0 @@
1
- import { MiniDom } from '.'
2
-
3
- // this needs to be in a separate file to ensure it's created immediately
4
- export const allNodes = [] as Array<MiniDom.BaseNode>
package/src/core/start.ts DELETED
@@ -1,11 +0,0 @@
1
- import { Lunch } from '..'
2
-
3
- export const startCallbacks = [] as Lunch.UpdateCallback[]
4
-
5
- export const onStart = (cb: Lunch.UpdateCallback, index = Infinity) => {
6
- if (index === Infinity) {
7
- startCallbacks.push(cb)
8
- } else {
9
- startCallbacks.splice(index, 0, cb)
10
- }
11
- }