|
@@ -6,6 +6,28 @@ import { Mesh } from 'three'
|
|
|
import { useEventListener } from '@vueuse/core'
|
|
|
import { TresEvent, TresObject } from '../types'
|
|
|
|
|
|
+const HTML_TAGS =
|
|
|
+ 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' +
|
|
|
+ 'header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,' +
|
|
|
+ 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' +
|
|
|
+ 'data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,' +
|
|
|
+ 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' +
|
|
|
+ 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' +
|
|
|
+ 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' +
|
|
|
+ 'option,output,progress,select,textarea,details,dialog,menu,' +
|
|
|
+ 'summary,template,blockquote,iframe,tfoot'
|
|
|
+
|
|
|
+export const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS)
|
|
|
+
|
|
|
+export function makeMap(str: string, expectsLowerCase?: boolean): (key: string) => boolean {
|
|
|
+ const map: Record<string, boolean> = Object.create(null)
|
|
|
+ const list: Array<string> = str.split(',')
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ map[list[i]] = true
|
|
|
+ }
|
|
|
+ return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]
|
|
|
+}
|
|
|
+
|
|
|
const { logWarning } = useLogger()
|
|
|
|
|
|
function hasEvents(obj: any) {
|
|
@@ -21,10 +43,26 @@ function noop(fn: string): any {
|
|
|
fn
|
|
|
}
|
|
|
|
|
|
-export const nodeOps: RendererOptions<TresObject, TresObject> = {
|
|
|
- createElement(type, _isSVG, _isCustomizedBuiltIn, props) {
|
|
|
- if (type === 'template') return null
|
|
|
- if (type === 'div') return null
|
|
|
+const doc = (typeof document !== 'undefined' ? document : null) as Document
|
|
|
+export const svgNS = 'http://www.w3.org/2000/svg'
|
|
|
+
|
|
|
+const templateContainer = doc && /*#__PURE__*/ doc.createElement('template')
|
|
|
+
|
|
|
+let scene = null
|
|
|
+
|
|
|
+export const nodeOps: RendererOptions<any, any> = {
|
|
|
+ createElement(tag, isSVG, anchor, props) {
|
|
|
+ // Vue core
|
|
|
+ /* const el = isSVG ? doc.createElementNS(svgNS, tag) : doc.createElement(tag, anchor ? { anchor } : undefined)
|
|
|
+
|
|
|
+ if (tag === 'select' && props && props.multiple != null) {
|
|
|
+ ;(el as HTMLSelectElement).setAttribute('multiple', props.multiple)
|
|
|
+ }
|
|
|
+
|
|
|
+ return el */
|
|
|
+ // Tres
|
|
|
+ if (tag === 'template') return null
|
|
|
+ if (isHTMLTag(tag)) return null
|
|
|
let instance
|
|
|
|
|
|
if (props === null) {
|
|
@@ -32,9 +70,9 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
|
|
|
}
|
|
|
|
|
|
if (props?.arg) {
|
|
|
- instance = new catalogue[type.replace('Tres', '')](...props.args)
|
|
|
+ instance = new catalogue[tag.replace('Tres', '')](...props.args)
|
|
|
} else {
|
|
|
- instance = new catalogue[type.replace('Tres', '')]()
|
|
|
+ instance = new catalogue[tag.replace('Tres', '')]()
|
|
|
}
|
|
|
|
|
|
if (instance.isCamera) {
|
|
@@ -55,22 +93,30 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
|
|
|
}
|
|
|
|
|
|
console.log({
|
|
|
- type,
|
|
|
+ tag,
|
|
|
+
|
|
|
instance,
|
|
|
- threeObj: catalogue[type.replace('Tres', '')],
|
|
|
+ threeObj: catalogue[tag.replace('Tres', '')],
|
|
|
})
|
|
|
|
|
|
return instance
|
|
|
},
|
|
|
- insert(child, parent, beforeChild) {
|
|
|
+ insert(child, parent, anchor) {
|
|
|
+ if (scene === null && parent.isScene) scene = parent
|
|
|
+ if (parent === null) parent = scene
|
|
|
+ //vue core
|
|
|
+ /* parent.insertBefore(child, anchor || null) */
|
|
|
if (parent?.isObject3D && child?.isObject3D) {
|
|
|
- const index = beforeChild ? parent.children.indexOf(beforeChild) : 0
|
|
|
+ console.log('insert', { child, parent, anchor })
|
|
|
+ const index = anchor ? parent.children.indexOf(anchor) : 0
|
|
|
child.parent = parent
|
|
|
parent.children.splice(index, 0, child)
|
|
|
child.dispatchEvent({ type: 'added' })
|
|
|
} else if (typeof child?.attach === 'string') {
|
|
|
- child.__previousAttach = child[parent.attach]
|
|
|
- parent[child.attach] = child
|
|
|
+ child.__previousAttach = child[parent?.attach]
|
|
|
+ if (parent) {
|
|
|
+ parent[child.attach] = child
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const { onLoop } = useRenderLoop()
|
|
@@ -82,7 +128,7 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
|
|
|
const { raycaster } = useRaycaster()
|
|
|
if (child && child instanceof Mesh && hasEvents(child)) {
|
|
|
onLoop(() => {
|
|
|
- if (parent.children && child && raycaster) {
|
|
|
+ if (parent?.children && child && raycaster) {
|
|
|
const intersects = raycaster.value.intersectObjects(parent.children)
|
|
|
|
|
|
if (intersects.length > 0 && intersects[0].object.uuid === child.uuid) {
|
|
@@ -111,7 +157,12 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
|
|
|
}
|
|
|
},
|
|
|
remove(node) {
|
|
|
- if (!node) return
|
|
|
+ // Vue Core
|
|
|
+ const parent = node.parentNode
|
|
|
+ if (parent) {
|
|
|
+ parent.removeChild(node)
|
|
|
+ }
|
|
|
+ /* if (!node) return
|
|
|
const parent = node.parent
|
|
|
if (parent) {
|
|
|
if (parent.isObject3D && node.isObject3D) {
|
|
@@ -126,46 +177,58 @@ export const nodeOps: RendererOptions<TresObject, TresObject> = {
|
|
|
node.dispose?.()
|
|
|
node.traverse?.(node => {
|
|
|
;(node as TresObject).dispose?.()
|
|
|
- })
|
|
|
+ }) */
|
|
|
},
|
|
|
patchProp(node, prop, prevValue, nextValue) {
|
|
|
- let root = node
|
|
|
- let key = prop
|
|
|
- let target = root[key]
|
|
|
-
|
|
|
- // Traverse pierced props (e.g. foo-bar=value => foo.bar = value)
|
|
|
- /* if (key.includes('-')) {
|
|
|
- const chain = key.split('-')
|
|
|
- target = chain.reduce((acc, key) => acc[key], root)
|
|
|
- key = chain.pop() as string
|
|
|
-
|
|
|
- if (!target?.set) root = chain.reduce((acc, key) => acc[key], root)
|
|
|
- } */
|
|
|
-
|
|
|
- const value = nextValue
|
|
|
- /* try {
|
|
|
- const num = parseFloat(value)
|
|
|
- value = isNaN(num) ? value : num
|
|
|
- } catch (_) {} */
|
|
|
-
|
|
|
- // Set prop, prefer atomic methods if applicable
|
|
|
- if (!target?.set) root[key] = value
|
|
|
- else if (target.constructor === value.constructor && target?.copy) target?.copy(value)
|
|
|
- else if (Array.isArray(value)) target.set(...value)
|
|
|
- else if (!target.isColor && target.setScalar) target.setScalar(value)
|
|
|
- else target.set(value)
|
|
|
+ if (node) {
|
|
|
+ let root = node
|
|
|
+ let key = prop
|
|
|
+ let target = root?.[key]
|
|
|
+ // Traverse pierced props (e.g. foo-bar=value => foo.bar = value)
|
|
|
+ /* if (key.includes('-')) {
|
|
|
+ const chain = key.split('-')
|
|
|
+ target = chain.reduce((acc, key) => acc[key], root)
|
|
|
+ key = chain.pop() as string
|
|
|
+
|
|
|
+ if (!target?.set) root = chain.reduce((acc, key) => acc[key], root)
|
|
|
+ } */
|
|
|
+ const value = nextValue
|
|
|
+ /* try {
|
|
|
+ const num = parseFloat(value)
|
|
|
+ value = isNaN(num) ? value : num
|
|
|
+ } catch (_) {} */
|
|
|
+ // Set prop, prefer atomic methods if applicable
|
|
|
+ if (!target?.set) root[key] = value
|
|
|
+ else if (target.constructor === value.constructor && target?.copy) target?.copy(value)
|
|
|
+ else if (Array.isArray(value)) target.set(...value)
|
|
|
+ else if (!target.isColor && target.setScalar) target.setScalar(value)
|
|
|
+ else target.set(value)
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
parentNode(node) {
|
|
|
- return node?.parent || null
|
|
|
+ // Vue core
|
|
|
+ return node.parentNode as Element | null
|
|
|
+ /* return node?.parent || null */
|
|
|
+ },
|
|
|
+ createText: text => doc.createTextNode(text),
|
|
|
+
|
|
|
+ createComment: text => doc.createComment(text),
|
|
|
+
|
|
|
+ setText: (node, text) => {
|
|
|
+ node.nodeValue = text
|
|
|
+ },
|
|
|
+
|
|
|
+ setElementText: (el, text) => {
|
|
|
+ el.textContent = text
|
|
|
+ },
|
|
|
+ nextSibling: node => node.nextSibling,
|
|
|
+
|
|
|
+ querySelector: selector => doc.querySelector(selector),
|
|
|
+
|
|
|
+ setScopeId(el, id) {
|
|
|
+ /* el.setAttribute(id, '') */
|
|
|
},
|
|
|
- createText: () => noop('createText'),
|
|
|
- createComment: () => noop('createComment'),
|
|
|
- setText: () => noop('setText'),
|
|
|
- setElementText: () => noop('setElementText'),
|
|
|
- nextSibling: () => noop('nextSibling'),
|
|
|
- querySelector: () => noop('querySelector'),
|
|
|
- setScopeId: () => noop('setScopeId'),
|
|
|
cloneNode: () => noop('cloneNode'),
|
|
|
insertStaticContent: () => noop('insertStaticContent'),
|
|
|
|