UNPKG

3.04 kBPlain TextView Raw
1import {camelCase} from 'lodash'
2import {SerializeOptions, StructureNode, Serializable} from './StructureNodes'
3import {SerializeError, HELP_URL} from './SerializeError'
4import {MenuItem, MenuItemBuilder, maybeSerializeMenuItem} from './MenuItem'
5import {MenuItemGroup, MenuItemGroupBuilder, maybeSerializeMenuItemGroup} from './MenuItemGroup'
6
7export interface Component extends StructureNode {
8 component: Function
9 menuItems: MenuItem[]
10 menuItemGroups: MenuItemGroup[]
11}
12
13export interface ComponentInput extends StructureNode {
14 component: Function
15 menuItems?: (MenuItem | MenuItemBuilder)[]
16 menuItemGroups?: (MenuItemGroup | MenuItemGroupBuilder)[]
17}
18
19export interface BuildableComponent extends Partial<StructureNode> {
20 component?: Function
21 menuItems?: (MenuItem | MenuItemBuilder)[]
22 menuItemGroups?: (MenuItemGroup | MenuItemGroupBuilder)[]
23}
24
25interface ReactComponent extends Function {
26 displayName?: string
27}
28
29function getFunctionName(fn: ReactComponent) {
30 return typeof fn.displayName === 'string' ? fn.displayName : fn.name
31}
32
33export class ComponentBuilder implements Serializable {
34 protected spec: BuildableComponent
35
36 constructor(spec?: ComponentInput) {
37 this.spec = spec ? spec : {}
38 }
39
40 id(id: string) {
41 return this.clone({id})
42 }
43
44 getId() {
45 return this.spec.id
46 }
47
48 title(title: string) {
49 return this.clone({title, id: this.spec.id || camelCase(title)})
50 }
51
52 getTitle() {
53 return this.spec.title
54 }
55
56 component(component: Function) {
57 return this.clone({component, id: this.spec.id || getFunctionName(component)})
58 }
59
60 getComponent() {
61 return this.spec.component
62 }
63
64 menuItems(menuItems: (MenuItem | MenuItemBuilder)[]) {
65 return this.clone({menuItems})
66 }
67
68 getMenuItems() {
69 return this.spec.menuItems
70 }
71
72 menuItemGroups(menuItemGroups: (MenuItemGroup | MenuItemGroupBuilder)[]) {
73 return this.clone({menuItemGroups})
74 }
75
76 getMenuItemGroups() {
77 return this.spec.menuItemGroups
78 }
79
80 serialize(options: SerializeOptions = {path: []}): Component {
81 const {id, title, component} = this.spec
82 if (!id) {
83 throw new SerializeError(
84 '`id` is required for `component` structure item',
85 options.path,
86 options.index
87 ).withHelpUrl(HELP_URL.ID_REQUIRED)
88 }
89
90 if (!component) {
91 throw new SerializeError(
92 '`component` is required for `component` structure item',
93 options.path,
94 options.index
95 ).withHelpUrl(HELP_URL.ID_REQUIRED)
96 }
97
98 return {
99 id,
100 title,
101 type: 'component',
102 component,
103 menuItems: (this.spec.menuItems || []).map((item, i) =>
104 maybeSerializeMenuItem(item, i, options.path)
105 ),
106 menuItemGroups: (this.spec.menuItemGroups || []).map((item, i) =>
107 maybeSerializeMenuItemGroup(item, i, options.path)
108 )
109 }
110 }
111
112 clone(withSpec?: BuildableComponent): ComponentBuilder {
113 const builder = new ComponentBuilder()
114 builder.spec = {...this.spec, ...(withSpec || {})}
115 return builder
116 }
117}
118
\No newline at end of file