@tanstack/angular-table 8.20.1 → 8.21.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.
- package/build/lib/esm2022/flex-render/context.mjs +6 -0
- package/build/lib/esm2022/flex-render/flags.mjs +42 -0
- package/build/lib/esm2022/flex-render/flex-render-component-ref.mjs +173 -0
- package/build/lib/esm2022/flex-render/flex-render-component.mjs +44 -0
- package/build/lib/esm2022/flex-render/view.mjs +102 -0
- package/build/lib/esm2022/flex-render.mjs +133 -73
- package/build/lib/esm2022/index.mjs +3 -2
- package/build/lib/esm2022/proxy.mjs +7 -3
- package/build/lib/fesm2022/tanstack-angular-table.mjs +494 -76
- package/build/lib/fesm2022/tanstack-angular-table.mjs.map +1 -1
- package/build/lib/flex-render/context.d.ts +3 -0
- package/build/lib/flex-render/flags.d.ts +40 -0
- package/build/lib/flex-render/flex-render-component-ref.d.ts +39 -0
- package/build/lib/flex-render/flex-render-component.d.ts +60 -0
- package/build/lib/flex-render/view.d.ts +49 -0
- package/build/lib/flex-render.d.ts +13 -17
- package/build/lib/index.d.ts +2 -1
- package/package.json +7 -4
- package/src/flex-render/context.ts +9 -0
- package/src/flex-render/flags.ts +40 -0
- package/src/flex-render/flex-render-component-ref.ts +236 -0
- package/src/flex-render/flex-render-component.ts +119 -0
- package/src/flex-render/view.ts +153 -0
- package/src/flex-render.ts +196 -94
- package/src/index.ts +7 -1
- package/src/proxy.ts +5 -2
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChangeDetectorRef,
|
|
3
|
+
ComponentRef,
|
|
4
|
+
inject,
|
|
5
|
+
Injectable,
|
|
6
|
+
Injector,
|
|
7
|
+
KeyValueDiffer,
|
|
8
|
+
KeyValueDiffers,
|
|
9
|
+
OutputEmitterRef,
|
|
10
|
+
OutputRefSubscription,
|
|
11
|
+
ViewContainerRef,
|
|
12
|
+
} from '@angular/core'
|
|
13
|
+
import { FlexRenderComponent } from './flex-render-component'
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class FlexRenderComponentFactory {
|
|
17
|
+
#viewContainerRef = inject(ViewContainerRef)
|
|
18
|
+
|
|
19
|
+
createComponent<T>(
|
|
20
|
+
flexRenderComponent: FlexRenderComponent<T>,
|
|
21
|
+
componentInjector: Injector
|
|
22
|
+
): FlexRenderComponentRef<T> {
|
|
23
|
+
const componentRef = this.#viewContainerRef.createComponent(
|
|
24
|
+
flexRenderComponent.component,
|
|
25
|
+
{
|
|
26
|
+
injector: componentInjector,
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
const view = new FlexRenderComponentRef(
|
|
30
|
+
componentRef,
|
|
31
|
+
flexRenderComponent,
|
|
32
|
+
componentInjector
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const { inputs, outputs } = flexRenderComponent
|
|
36
|
+
|
|
37
|
+
if (inputs) view.setInputs(inputs)
|
|
38
|
+
if (outputs) view.setOutputs(outputs)
|
|
39
|
+
|
|
40
|
+
return view
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class FlexRenderComponentRef<T> {
|
|
45
|
+
readonly #keyValueDiffersFactory: KeyValueDiffers
|
|
46
|
+
#componentData: FlexRenderComponent<T>
|
|
47
|
+
#inputValueDiffer: KeyValueDiffer<string, unknown>
|
|
48
|
+
|
|
49
|
+
readonly #outputRegistry: FlexRenderComponentOutputManager
|
|
50
|
+
|
|
51
|
+
constructor(
|
|
52
|
+
readonly componentRef: ComponentRef<T>,
|
|
53
|
+
componentData: FlexRenderComponent<T>,
|
|
54
|
+
readonly componentInjector: Injector
|
|
55
|
+
) {
|
|
56
|
+
this.#componentData = componentData
|
|
57
|
+
this.#keyValueDiffersFactory = componentInjector.get(KeyValueDiffers)
|
|
58
|
+
|
|
59
|
+
this.#outputRegistry = new FlexRenderComponentOutputManager(
|
|
60
|
+
this.#keyValueDiffersFactory,
|
|
61
|
+
this.outputs
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
this.#inputValueDiffer = this.#keyValueDiffersFactory
|
|
65
|
+
.find(this.inputs)
|
|
66
|
+
.create()
|
|
67
|
+
this.#inputValueDiffer.diff(this.inputs)
|
|
68
|
+
|
|
69
|
+
this.componentRef.onDestroy(() => this.#outputRegistry.unsubscribeAll())
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get component() {
|
|
73
|
+
return this.#componentData.component
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get inputs() {
|
|
77
|
+
return this.#componentData.inputs ?? {}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get outputs() {
|
|
81
|
+
return this.#componentData.outputs ?? {}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get component input and output diff by the given item
|
|
86
|
+
*/
|
|
87
|
+
diff(item: FlexRenderComponent<T>) {
|
|
88
|
+
return {
|
|
89
|
+
inputDiff: this.#inputValueDiffer.diff(item.inputs ?? {}),
|
|
90
|
+
outputDiff: this.#outputRegistry.diff(item.outputs ?? {}),
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
*
|
|
95
|
+
* @param compare Whether the current ref component instance is the same as the given one
|
|
96
|
+
*/
|
|
97
|
+
eqType(compare: FlexRenderComponent<T>): boolean {
|
|
98
|
+
return compare.component === this.component
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Tries to update current component refs input by the new given content component.
|
|
103
|
+
*/
|
|
104
|
+
update(content: FlexRenderComponent<T>) {
|
|
105
|
+
const eq = this.eqType(content)
|
|
106
|
+
if (!eq) return
|
|
107
|
+
const { inputDiff, outputDiff } = this.diff(content)
|
|
108
|
+
if (inputDiff) {
|
|
109
|
+
inputDiff.forEachAddedItem(item =>
|
|
110
|
+
this.setInput(item.key, item.currentValue)
|
|
111
|
+
)
|
|
112
|
+
inputDiff.forEachChangedItem(item =>
|
|
113
|
+
this.setInput(item.key, item.currentValue)
|
|
114
|
+
)
|
|
115
|
+
inputDiff.forEachRemovedItem(item => this.setInput(item.key, undefined))
|
|
116
|
+
}
|
|
117
|
+
if (outputDiff) {
|
|
118
|
+
outputDiff.forEachAddedItem(item => {
|
|
119
|
+
this.setOutput(item.key, item.currentValue)
|
|
120
|
+
})
|
|
121
|
+
outputDiff.forEachChangedItem(item => {
|
|
122
|
+
if (item.currentValue) {
|
|
123
|
+
this.#outputRegistry.setListener(item.key, item.currentValue)
|
|
124
|
+
} else {
|
|
125
|
+
this.#outputRegistry.unsubscribe(item.key)
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
outputDiff.forEachRemovedItem(item => {
|
|
129
|
+
this.#outputRegistry.unsubscribe(item.key)
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.#componentData = content
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
markAsDirty(): void {
|
|
137
|
+
this.componentRef.injector.get(ChangeDetectorRef).markForCheck()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
setInputs(inputs: Record<string, unknown>) {
|
|
141
|
+
for (const prop in inputs) {
|
|
142
|
+
this.setInput(prop, inputs[prop])
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
setInput(key: string, value: unknown) {
|
|
147
|
+
if (this.#componentData.allowedInputNames.includes(key)) {
|
|
148
|
+
this.componentRef.setInput(key, value)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
setOutputs(
|
|
153
|
+
outputs: Record<
|
|
154
|
+
string,
|
|
155
|
+
OutputEmitterRef<unknown>['emit'] | null | undefined
|
|
156
|
+
>
|
|
157
|
+
) {
|
|
158
|
+
this.#outputRegistry.unsubscribeAll()
|
|
159
|
+
for (const prop in outputs) {
|
|
160
|
+
this.setOutput(prop, outputs[prop])
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
setOutput(
|
|
165
|
+
outputName: string,
|
|
166
|
+
emit: OutputEmitterRef<unknown>['emit'] | undefined | null
|
|
167
|
+
): void {
|
|
168
|
+
if (!this.#componentData.allowedOutputNames.includes(outputName)) return
|
|
169
|
+
if (!emit) {
|
|
170
|
+
this.#outputRegistry.unsubscribe(outputName)
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const hasListener = this.#outputRegistry.hasListener(outputName)
|
|
175
|
+
this.#outputRegistry.setListener(outputName, emit)
|
|
176
|
+
|
|
177
|
+
if (hasListener) {
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const instance = this.componentRef.instance
|
|
182
|
+
const output = instance[outputName as keyof typeof instance]
|
|
183
|
+
if (output && output instanceof OutputEmitterRef) {
|
|
184
|
+
output.subscribe(value => {
|
|
185
|
+
this.#outputRegistry.getListener(outputName)?.(value)
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
class FlexRenderComponentOutputManager {
|
|
192
|
+
readonly #outputSubscribers: Record<string, OutputRefSubscription> = {}
|
|
193
|
+
readonly #outputListeners: Record<string, (...args: any[]) => void> = {}
|
|
194
|
+
|
|
195
|
+
readonly #valueDiffer: KeyValueDiffer<
|
|
196
|
+
string,
|
|
197
|
+
undefined | null | OutputEmitterRef<unknown>['emit']
|
|
198
|
+
>
|
|
199
|
+
|
|
200
|
+
constructor(keyValueDiffers: KeyValueDiffers, initialOutputs: any) {
|
|
201
|
+
this.#valueDiffer = keyValueDiffers.find(initialOutputs).create()
|
|
202
|
+
if (initialOutputs) {
|
|
203
|
+
this.#valueDiffer.diff(initialOutputs)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
hasListener(outputName: string) {
|
|
208
|
+
return outputName in this.#outputListeners
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
setListener(outputName: string, callback: (...args: any[]) => void) {
|
|
212
|
+
this.#outputListeners[outputName] = callback
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
getListener(outputName: string) {
|
|
216
|
+
return this.#outputListeners[outputName]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
unsubscribeAll(): void {
|
|
220
|
+
for (const prop in this.#outputSubscribers) {
|
|
221
|
+
this.unsubscribe(prop)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
unsubscribe(outputName: string) {
|
|
226
|
+
if (outputName in this.#outputSubscribers) {
|
|
227
|
+
this.#outputSubscribers[outputName]?.unsubscribe()
|
|
228
|
+
delete this.#outputSubscribers[outputName]
|
|
229
|
+
delete this.#outputListeners[outputName]
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
diff(outputs: Record<string, OutputEmitterRef<unknown>['emit'] | undefined>) {
|
|
234
|
+
return this.#valueDiffer.diff(outputs ?? {})
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ComponentMirror,
|
|
3
|
+
Injector,
|
|
4
|
+
InputSignal,
|
|
5
|
+
OutputEmitterRef,
|
|
6
|
+
reflectComponentType,
|
|
7
|
+
Type,
|
|
8
|
+
} from '@angular/core'
|
|
9
|
+
|
|
10
|
+
type Inputs<T> = {
|
|
11
|
+
[K in keyof T as T[K] extends InputSignal<infer R>
|
|
12
|
+
? K
|
|
13
|
+
: never]?: T[K] extends InputSignal<infer R> ? R : never
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type Outputs<T> = {
|
|
17
|
+
[K in keyof T as T[K] extends OutputEmitterRef<infer R>
|
|
18
|
+
? K
|
|
19
|
+
: never]?: T[K] extends OutputEmitterRef<infer R>
|
|
20
|
+
? OutputEmitterRef<R>['emit']
|
|
21
|
+
: never
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type OptionalKeys<T, K = keyof T> = K extends keyof T
|
|
25
|
+
? T[K] extends Required<T>[K]
|
|
26
|
+
? undefined extends T[K]
|
|
27
|
+
? K
|
|
28
|
+
: never
|
|
29
|
+
: K
|
|
30
|
+
: never
|
|
31
|
+
|
|
32
|
+
interface FlexRenderRequiredOptions<
|
|
33
|
+
TInputs extends Record<string, any>,
|
|
34
|
+
TOutputs extends Record<string, any>,
|
|
35
|
+
> {
|
|
36
|
+
/**
|
|
37
|
+
* Component instance inputs. They will be set via [componentRef.setInput API](https://angular.dev/api/core/ComponentRef#setInput)
|
|
38
|
+
*/
|
|
39
|
+
inputs: TInputs
|
|
40
|
+
/**
|
|
41
|
+
* Component instance outputs.
|
|
42
|
+
*/
|
|
43
|
+
outputs?: TOutputs
|
|
44
|
+
/**
|
|
45
|
+
* Optional {@link Injector} that will be used when rendering the component
|
|
46
|
+
*/
|
|
47
|
+
injector?: Injector
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface FlexRenderOptions<
|
|
51
|
+
TInputs extends Record<string, any>,
|
|
52
|
+
TOutputs extends Record<string, any>,
|
|
53
|
+
> {
|
|
54
|
+
/**
|
|
55
|
+
* Component instance inputs. They will be set via [componentRef.setInput API](https://angular.dev/api/core/ComponentRef#setInput)
|
|
56
|
+
*/
|
|
57
|
+
inputs?: TInputs
|
|
58
|
+
/**
|
|
59
|
+
* Component instance outputs.
|
|
60
|
+
*/
|
|
61
|
+
outputs?: TOutputs
|
|
62
|
+
/**
|
|
63
|
+
* Optional {@link Injector} that will be used when rendering the component
|
|
64
|
+
*/
|
|
65
|
+
injector?: Injector
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Helper function to create a [@link FlexRenderComponent] instance, with better type-safety.
|
|
70
|
+
*
|
|
71
|
+
* - options object must be passed when the given component instance contains at least one required signal input.
|
|
72
|
+
* - options/inputs is typed with the given component inputs
|
|
73
|
+
* - options/outputs is typed with the given component outputs
|
|
74
|
+
*/
|
|
75
|
+
export function flexRenderComponent<
|
|
76
|
+
TComponent = any,
|
|
77
|
+
TInputs extends Inputs<TComponent> = Inputs<TComponent>,
|
|
78
|
+
TOutputs extends Outputs<TComponent> = Outputs<TComponent>,
|
|
79
|
+
>(
|
|
80
|
+
component: Type<TComponent>,
|
|
81
|
+
...options: OptionalKeys<TInputs> extends never
|
|
82
|
+
? [FlexRenderOptions<TInputs, TOutputs>?]
|
|
83
|
+
: [FlexRenderRequiredOptions<TInputs, TOutputs>]
|
|
84
|
+
) {
|
|
85
|
+
const { inputs, injector, outputs } = options?.[0] ?? {}
|
|
86
|
+
return new FlexRenderComponent(component, inputs, injector, outputs)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Wrapper class for a component that will be used as content for {@link FlexRenderDirective}
|
|
91
|
+
*
|
|
92
|
+
* Prefer {@link flexRenderComponent} helper for better type-safety
|
|
93
|
+
*/
|
|
94
|
+
export class FlexRenderComponent<TComponent = any> {
|
|
95
|
+
readonly mirror: ComponentMirror<TComponent>
|
|
96
|
+
readonly allowedInputNames: string[] = []
|
|
97
|
+
readonly allowedOutputNames: string[] = []
|
|
98
|
+
|
|
99
|
+
constructor(
|
|
100
|
+
readonly component: Type<TComponent>,
|
|
101
|
+
readonly inputs?: Inputs<TComponent>,
|
|
102
|
+
readonly injector?: Injector,
|
|
103
|
+
readonly outputs?: Outputs<TComponent>
|
|
104
|
+
) {
|
|
105
|
+
const mirror = reflectComponentType(component)
|
|
106
|
+
if (!mirror) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`[@tanstack-table/angular] The provided symbol is not a component`
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
this.mirror = mirror
|
|
112
|
+
for (const input of this.mirror.inputs) {
|
|
113
|
+
this.allowedInputNames.push(input.propName)
|
|
114
|
+
}
|
|
115
|
+
for (const output of this.mirror.outputs) {
|
|
116
|
+
this.allowedOutputNames.push(output.propName)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { FlexRenderComponentRef } from './flex-render-component-ref'
|
|
2
|
+
import { EmbeddedViewRef, TemplateRef, Type } from '@angular/core'
|
|
3
|
+
import type { FlexRenderContent } from '../flex-render'
|
|
4
|
+
import { FlexRenderComponent } from './flex-render-component'
|
|
5
|
+
|
|
6
|
+
export type FlexRenderTypedContent =
|
|
7
|
+
| { kind: 'null' }
|
|
8
|
+
| {
|
|
9
|
+
kind: 'primitive'
|
|
10
|
+
content: string | number | Record<string, any>
|
|
11
|
+
}
|
|
12
|
+
| { kind: 'flexRenderComponent'; content: FlexRenderComponent<unknown> }
|
|
13
|
+
| { kind: 'templateRef'; content: TemplateRef<unknown> }
|
|
14
|
+
| { kind: 'component'; content: Type<unknown> }
|
|
15
|
+
|
|
16
|
+
export function mapToFlexRenderTypedContent(
|
|
17
|
+
content: FlexRenderContent<any>
|
|
18
|
+
): FlexRenderTypedContent {
|
|
19
|
+
if (content === null || content === undefined) {
|
|
20
|
+
return { kind: 'null' }
|
|
21
|
+
}
|
|
22
|
+
if (typeof content === 'string' || typeof content === 'number') {
|
|
23
|
+
return { kind: 'primitive', content }
|
|
24
|
+
}
|
|
25
|
+
if (content instanceof FlexRenderComponent) {
|
|
26
|
+
return { kind: 'flexRenderComponent', content }
|
|
27
|
+
} else if (content instanceof TemplateRef) {
|
|
28
|
+
return { kind: 'templateRef', content }
|
|
29
|
+
} else if (content instanceof Type) {
|
|
30
|
+
return { kind: 'component', content }
|
|
31
|
+
} else {
|
|
32
|
+
return { kind: 'primitive', content }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export abstract class FlexRenderView<
|
|
37
|
+
TView extends FlexRenderComponentRef<any> | EmbeddedViewRef<unknown> | null,
|
|
38
|
+
> {
|
|
39
|
+
readonly view: TView
|
|
40
|
+
#previousContent: FlexRenderTypedContent | undefined
|
|
41
|
+
#content: FlexRenderTypedContent
|
|
42
|
+
|
|
43
|
+
protected constructor(
|
|
44
|
+
initialContent: Exclude<FlexRenderTypedContent, { kind: 'null' }>,
|
|
45
|
+
view: TView
|
|
46
|
+
) {
|
|
47
|
+
this.#content = initialContent
|
|
48
|
+
this.view = view
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get previousContent(): FlexRenderTypedContent {
|
|
52
|
+
return this.#previousContent ?? { kind: 'null' }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get content() {
|
|
56
|
+
return this.#content
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set content(content: FlexRenderTypedContent) {
|
|
60
|
+
this.#previousContent = this.#content
|
|
61
|
+
this.#content = content
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
abstract updateProps(props: Record<string, any>): void
|
|
65
|
+
|
|
66
|
+
abstract dirtyCheck(): void
|
|
67
|
+
|
|
68
|
+
abstract onDestroy(callback: Function): void
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class FlexRenderTemplateView extends FlexRenderView<
|
|
72
|
+
EmbeddedViewRef<unknown>
|
|
73
|
+
> {
|
|
74
|
+
constructor(
|
|
75
|
+
initialContent: Extract<
|
|
76
|
+
FlexRenderTypedContent,
|
|
77
|
+
{ kind: 'primitive' | 'templateRef' }
|
|
78
|
+
>,
|
|
79
|
+
view: EmbeddedViewRef<unknown>
|
|
80
|
+
) {
|
|
81
|
+
super(initialContent, view)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override updateProps(props: Record<string, any>) {
|
|
85
|
+
this.view.markForCheck()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
override dirtyCheck() {
|
|
89
|
+
// Basically a no-op. When the view is created via EmbeddedViewRef, we don't need to do any manual update
|
|
90
|
+
// since this type of content has a proxy as a context, then every time the root component is checked for changes,
|
|
91
|
+
// the property getter will be re-evaluated.
|
|
92
|
+
//
|
|
93
|
+
// If in a future we need to manually mark the view as dirty, just uncomment next line
|
|
94
|
+
// this.view.markForCheck()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
override onDestroy(callback: Function) {
|
|
98
|
+
this.view.onDestroy(callback)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class FlexRenderComponentView extends FlexRenderView<
|
|
103
|
+
FlexRenderComponentRef<unknown>
|
|
104
|
+
> {
|
|
105
|
+
constructor(
|
|
106
|
+
initialContent: Extract<
|
|
107
|
+
FlexRenderTypedContent,
|
|
108
|
+
{ kind: 'component' | 'flexRenderComponent' }
|
|
109
|
+
>,
|
|
110
|
+
view: FlexRenderComponentRef<unknown>
|
|
111
|
+
) {
|
|
112
|
+
super(initialContent, view)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
override updateProps(props: Record<string, any>) {
|
|
116
|
+
switch (this.content.kind) {
|
|
117
|
+
case 'component': {
|
|
118
|
+
this.view.setInputs(props)
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
case 'flexRenderComponent': {
|
|
122
|
+
// No-op. When FlexRenderFlags.PropsReferenceChanged is set,
|
|
123
|
+
// FlexRenderComponent will be updated into `dirtyCheck`.
|
|
124
|
+
break
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override dirtyCheck() {
|
|
130
|
+
switch (this.content.kind) {
|
|
131
|
+
case 'component': {
|
|
132
|
+
// Component context is currently valuated with the cell context. Since it's reference
|
|
133
|
+
// shouldn't change, we force mark the component as dirty in order to re-evaluate function invocation in view.
|
|
134
|
+
// NOTE: this should behave like having a component with ChangeDetectionStrategy.Default
|
|
135
|
+
this.view.markAsDirty()
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
case 'flexRenderComponent': {
|
|
139
|
+
// Given context instance will always have a different reference than the previous one,
|
|
140
|
+
// so instead of recreating the entire view, we will only update the current view
|
|
141
|
+
if (this.view.eqType(this.content.content)) {
|
|
142
|
+
this.view.update(this.content.content)
|
|
143
|
+
}
|
|
144
|
+
this.view.markAsDirty()
|
|
145
|
+
break
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
override onDestroy(callback: Function) {
|
|
151
|
+
this.view.componentRef.onDestroy(callback)
|
|
152
|
+
}
|
|
153
|
+
}
|