-
Notifications
You must be signed in to change notification settings - Fork 394
/
ComponentView.ts
78 lines (63 loc) · 2.23 KB
/
ComponentView.ts
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
import {SerializeOptions} from '../StructureNodes'
import {SerializeError, HELP_URL} from '../SerializeError'
import {isRecord} from '../../../util'
import type {UserViewComponent} from '../types'
import {BaseView, GenericViewBuilder} from './View'
export interface ComponentView<TOptions = Record<string, any>> extends BaseView {
type: 'component'
component: UserViewComponent
options: TOptions
}
const isComponentSpec = (spec: unknown): spec is ComponentView =>
isRecord(spec) && spec.type === 'component'
export class ComponentViewBuilder extends GenericViewBuilder<
Partial<ComponentView>,
ComponentViewBuilder
> {
protected spec: Partial<ComponentView>
constructor(componentOrSpec?: UserViewComponent | Partial<ComponentView>) {
const spec = isComponentSpec(componentOrSpec) ? {...componentOrSpec} : {options: {}}
super()
this.spec = spec
const userComponent =
typeof componentOrSpec === 'function' ? componentOrSpec : this.spec.component
if (userComponent) {
// Because we're cloning, this'll return a new instance, so grab the spec from it
this.spec = this.component(userComponent).spec
}
}
component(component: UserViewComponent): ComponentViewBuilder {
return this.clone({component})
}
getComponent(): Partial<ComponentView>['component'] {
return this.spec.component
}
options(options: {[key: string]: any}): ComponentViewBuilder {
return this.clone({options})
}
getOptions(): ComponentView['options'] {
return this.spec.options || {}
}
serialize(options: SerializeOptions = {path: []}): ComponentView {
const base = super.serialize(options)
const component = this.spec.component
if (typeof component !== 'function') {
throw new SerializeError(
'`component` is required and must be a function for `component()` view item',
options.path,
options.index
).withHelpUrl(HELP_URL.COMPONENT_REQUIRED)
}
return {
...base,
component,
options: this.spec.options || {},
type: 'component',
}
}
clone(withSpec?: Partial<ComponentView>): ComponentViewBuilder {
const builder = new ComponentViewBuilder()
builder.spec = {...this.spec, ...(withSpec || {})}
return builder
}
}