-
-
Notifications
You must be signed in to change notification settings - Fork 115
/
Sync.svelte
145 lines (114 loc) · 4.27 KB
/
Sync.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<script lang="ts">
import type { ISheetObject, UnknownShorthandCompoundProps } from '@theatre/core'
import { resolvePropertyPath, useParent, watch, type CurrentWritable } from '@threlte/core'
import { onDestroy } from 'svelte'
import type { Transformer } from '../transfomers/types'
import type { AnyProp } from './Sync.svelte'
import { getInitialValue } from './utils/getInitialValue'
import { isComplexProp } from './utils/isComplexProp'
import { makeAlphanumeric } from './utils/makeAlphanumeric'
import { parsePropLabel } from './utils/parsePropLabel'
import { isStringProp } from './utils/isStringProp'
import { useStudio } from '../../studio/useStudio'
// used for type hinting auto props
export let type: any = undefined
/** @package */
export let sheetObject: CurrentWritable<ISheetObject>
/** @package */
export let addProps: (props: UnknownShorthandCompoundProps) => void
/** @package */
export let removeProps: (propNames: string[]) => void
const parent = useParent()
// serves as a map to map (custom) prop names to object target properties
let propMappings = {} as Record<
string,
{
propertyPath: string
transformer: Transformer
}
>
const initProps = () => {
const props = {} as Record<string, any>
// propertyPath is for example "position.x" or "intensity", so a property path on the parent object
Object.entries(<Record<string, AnyProp>>$$restProps).forEach(
([propertyPath, propertyValue]) => {
// The prop might have a custom name, for example "intensity" might be mapped to "light-intensity"
const customKey = isComplexProp(propertyValue)
? propertyValue.key
: isStringProp(propertyValue)
? propertyValue
: undefined
const key = customKey ?? makeAlphanumeric(propertyPath)
// get the initial value as well as the correct transformer for the property
const { value, transformer } = getInitialValue(propertyPath, propertyValue, $parent)
const label = parsePropLabel(key, propertyValue)
// apply the label to the value
value.label = label
// add the prop to the propMappings map
propMappings[key] = {
propertyPath,
transformer
}
// add the prop to the props object
props[key] = value
}
)
// add the props to the parent IsheetObject
addProps(props)
}
const updateProjectionMatrixKeys = [
'fov',
'near',
'far',
'zoom',
'left',
'right',
'top',
'bottom',
'aspect'
]
watch([parent, sheetObject], ([parent, sheetObject]) => {
if (!parent) return
return sheetObject?.onValuesChange((values) => {
// Ensure that the parent is still mounted
Object.keys(values).forEach((key) => {
// first, check if the prop is mapped in this component
const propMapping = propMappings[key]
if (!propMapping) return
// we're using the addedProps map to infer the target property name from the property name on values
const { target, key: targetKey } = resolvePropertyPath(
parent as any,
propMapping.propertyPath
)
// use a transformer to apply value
const transformer = propMapping.transformer
transformer.apply(target, targetKey, values[key])
if (updateProjectionMatrixKeys.includes(targetKey)) {
target.updateProjectionMatrix?.()
}
})
})
})
initProps()
const studio = useStudio()
export const capture = () => {
if (!$studio) return
const scrub = $studio.scrub()
Object.keys(sheetObject.current.value).forEach((key) => {
// first, check if the prop is mapped in this component
const propMapping = propMappings[key]
if (!propMapping) return
// we're using the addedProps map to infer the target property name from the property name on values
const { target, key: targetKey } = resolvePropertyPath($parent, propMapping.propertyPath)
const value = propMapping.transformer.transform(target[targetKey]).default
scrub.capture(({ set }) => {
set(sheetObject.current.props[key], value)
})
})
scrub.commit()
}
onDestroy(() => {
removeProps(Object.keys(propMappings))
})
</script>
<slot {capture} />