1
- import { computed , DestroyRef , Directive , effect , ElementRef , inject , input , signal } from '@angular/core' ;
1
+ import { computed , DestroyRef , Directive , effect , ElementRef , inject , input } from '@angular/core' ;
2
2
import { NgtAnyRecord , resolveInstanceKey , resolveRef } from 'angular-three' ;
3
3
import { THEATRE_STUDIO } from '../studio/studio-token' ;
4
4
import { getDefaultTransformer } from '../transformers/default-transformer' ;
@@ -7,7 +7,7 @@ import { TheatreSheetObject } from './sheet-object';
7
7
8
8
const updateProjectionMatrixKeys = [ 'fov' , 'near' , 'far' , 'zoom' , 'left' , 'right' , 'top' , 'bottom' , 'aspect' ] ;
9
9
10
- @Directive ( { selector : '[sync]' } )
10
+ @Directive ( { selector : '[sync]' , exportAs : 'sync' } )
11
11
export class TheatreSheetObjectSync < TObject extends object > {
12
12
parent = input . required < TObject | ElementRef < TObject > | ( ( ) => TObject | ElementRef < TObject > | undefined | null ) > ( {
13
13
alias : 'sync' ,
@@ -16,7 +16,8 @@ export class TheatreSheetObjectSync<TObject extends object> {
16
16
Array < string | [ string , string | { label ?: string ; key ?: string ; transformer ?: TheatreTransformer } ] >
17
17
> ( [ ] , { alias : 'syncProps' } ) ;
18
18
19
- private sheetObject = inject ( TheatreSheetObject ) ;
19
+ private theatreSheetObject = inject ( TheatreSheetObject ) ;
20
+ sheetObject = computed ( ( ) => this . theatreSheetObject . sheetObject ( ) ) ;
20
21
private studio = inject ( THEATRE_STUDIO , { optional : true } ) ;
21
22
22
23
private parentRef = computed ( ( ) => {
@@ -46,48 +47,52 @@ export class TheatreSheetObjectSync<TObject extends object> {
46
47
) ;
47
48
} ) ;
48
49
49
- private init = signal ( false ) ;
50
- private propsMapping : Record < string , { path : string ; transformer : TheatreTransformer } > = { } ;
50
+ private propsToAdd = computed ( ( ) => {
51
+ const parent = this . parentRef ( ) ;
52
+ if ( ! parent ) return null ;
51
53
52
- constructor ( ) {
53
- effect ( ( ) => {
54
- const parent = this . parentRef ( ) ;
55
- if ( ! parent ) return ;
54
+ const propsToAdd : NgtAnyRecord = { } ;
55
+ const resolvedProps = this . resolvedProps ( ) ;
56
+ resolvedProps . forEach ( ( [ propName , { key, label, transformer } ] ) => {
57
+ const { root, targetKey } = resolveInstanceKey ( parent , propName ) ;
58
+ const rawValue = root [ targetKey ] ;
59
+ const valueTransformer = transformer ?? getDefaultTransformer ( root , targetKey , propName ) ;
60
+ const value = valueTransformer . transform ( rawValue ) ;
61
+
62
+ value . label = label ?? key ;
56
63
57
- const propsToAdd : NgtAnyRecord = { } ;
58
- const resolvedProps = this . resolvedProps ( ) ;
59
- resolvedProps . forEach ( ( [ propName , { key, label, transformer } ] ) => {
60
- const { root, targetKey, targetProp } = resolveInstanceKey ( parent , propName ) ;
61
- const rawValue = root [ targetKey ] ;
62
- const valueTransformer = transformer ?? getDefaultTransformer ( root , targetKey , propName ) ;
63
- const value = valueTransformer . transform ( rawValue ) ;
64
+ this . propsMapping [ key ] = { path : propName , transformer : valueTransformer } ;
65
+ propsToAdd [ key ] = value ;
66
+ } ) ;
64
67
65
- value . label = label ?? key ;
68
+ return propsToAdd ;
69
+ } ) ;
66
70
67
- this . propsMapping [ key ] = { path : propName , transformer : valueTransformer } ;
68
- propsToAdd [ key ] = value ;
69
- } ) ;
71
+ private propsMapping : Record < string , { path : string ; transformer : TheatreTransformer } > = { } ;
70
72
71
- this . sheetObject . addProps ( propsToAdd ) ;
72
- this . init . set ( true ) ;
73
+ constructor ( ) {
74
+ effect ( ( ) => {
75
+ const propsToAdd = this . propsToAdd ( ) ;
76
+ if ( ! propsToAdd ) return ;
77
+ this . theatreSheetObject . addProps ( propsToAdd ) ;
73
78
} ) ;
74
79
75
80
effect ( ( onCleanup ) => {
76
81
const parent = this . parentRef ( ) ;
77
82
if ( ! parent ) return ;
78
83
79
- const init = this . init ( ) ;
80
- if ( ! init ) return ;
84
+ const propsToAdd = this . propsToAdd ( ) ;
85
+ if ( ! propsToAdd ) return ;
81
86
82
- const sheetObject = this . sheetObject . sheetObject ( ) ;
87
+ const sheetObject = this . sheetObject ( ) ;
83
88
const cleanup = sheetObject . onValuesChange ( ( newValues ) => {
84
89
Object . keys ( newValues ) . forEach ( ( key ) => {
85
90
// first, check if the prop is mapped in this component
86
91
const propMapping = this . propsMapping [ key ] ;
87
92
if ( ! propMapping ) return ;
88
93
89
94
// we're using the addedProps map to infer the target property name from the property name on values
90
- const { root, targetProp , targetKey } = resolveInstanceKey ( parent , propMapping . path ) ;
95
+ const { root, targetKey } = resolveInstanceKey ( parent , propMapping . path ) ;
91
96
92
97
// use a transformer to apply value
93
98
const transformer = propMapping . transformer ;
@@ -103,10 +108,39 @@ export class TheatreSheetObjectSync<TObject extends object> {
103
108
} ) ;
104
109
105
110
inject ( DestroyRef ) . onDestroy ( ( ) => {
106
- this . sheetObject . removeProps ( Object . keys ( this . propsMapping ) ) ;
111
+ this . theatreSheetObject . removeProps ( Object . keys ( this . propsMapping ) ) ;
107
112
} ) ;
108
113
}
109
114
115
+ capture ( ) {
116
+ const studio = this . studio ?.( ) ;
117
+ if ( ! studio ) return ;
118
+
119
+ const parent = this . parentRef ( ) ;
120
+ if ( ! parent ) return ;
121
+
122
+ const sheetObject = this . sheetObject ( ) ;
123
+ if ( ! sheetObject ) return ;
124
+
125
+ const scrub = studio . scrub ( ) ;
126
+
127
+ Object . keys ( sheetObject . value ) . forEach ( ( key ) => {
128
+ // first, check if the prop is mapped in this component
129
+ const propMapping = this . propsMapping [ key ] ;
130
+ if ( ! propMapping ) return ;
131
+
132
+ // we're using the addedProps map to infer the target property name from the property name on values
133
+ const { targetProp } = resolveInstanceKey ( parent , propMapping . path ) ;
134
+ const value = propMapping . transformer . transform ( targetProp ) . default ;
135
+
136
+ scrub . capture ( ( { set } ) => {
137
+ set ( sheetObject . props [ key ] , value ) ;
138
+ } ) ;
139
+ } ) ;
140
+
141
+ scrub . commit ( ) ;
142
+ }
143
+
110
144
private resolvePropertyPath ( propPath : string ) {
111
145
return (
112
146
propPath
0 commit comments