/
controls-defaults.ts
188 lines (169 loc) · 4.84 KB
/
controls-defaults.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
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
import { ContentFields, ContentTypeFieldValidation } from '../../entities/content-type-fields'
import { in_ } from './types'
const DROPDOWN_TYPES = ['Text', 'Symbol', 'Integer', 'Number', 'Boolean']
const INTERNAL_TO_API = {
Symbol: { type: 'Symbol' },
Text: { type: 'Text' },
RichText: { type: 'RichText' },
Integer: { type: 'Integer' },
Number: { type: 'Number' },
Boolean: { type: 'Boolean' },
Date: { type: 'Date' },
Location: { type: 'Location' },
Object: { type: 'Object' },
File: { type: 'File' },
Entry: { type: 'Link', linkType: 'Entry' },
Asset: { type: 'Link', linkType: 'Asset' },
Symbols: { type: 'Array', items: { type: 'Symbol' } },
Entries: { type: 'Array', items: { type: 'Link', linkType: 'Entry' } },
Assets: { type: 'Array', items: { type: 'Link', linkType: 'Asset' } },
} as const
export const FIELD_TYPES = Object.keys(INTERNAL_TO_API) as Array<keyof typeof INTERNAL_TO_API>
/**
* Returns an internal string identifier for an API field object.
*
* We use this string as a simplified reference to field types.
* Possible values are:
*
* - Symbol
* - Symbols
* - Text
* - RichText
* - Integer
* - Number
* - Boolean
* - Date
* - Location
* - Object
* - Entry
* - Entries
* - Asset
* - Assets
* - File
*/
export function toInternalFieldType(api: Partial<ContentFields>) {
return FIELD_TYPES.find((key) => {
const internalApi = INTERNAL_TO_API[key]
const stripped = {
type: api.type,
linkType: api.linkType,
items: api.items,
}
if (stripped.items) {
stripped.items = { type: stripped.items.type, linkType: stripped.items.linkType }
}
if (internalApi.type === 'Link') {
return internalApi.linkType === stripped.linkType
}
if (internalApi.type === 'Array' && internalApi.items && stripped.items) {
if (internalApi.items.type === 'Link') {
return internalApi.items.linkType === stripped.items.linkType
}
return internalApi.items.type === stripped.items.type
}
return internalApi.type === stripped.type
})
}
export const DEFAULTS_WIDGET = {
Text: { widgetId: 'markdown' },
Symbol: { widgetId: 'singleLine' },
Integer: { widgetId: 'numberEditor' },
Number: { widgetId: 'numberEditor' },
Boolean: { widgetId: 'boolean' },
Date: { widgetId: 'datePicker' },
Location: { widgetId: 'locationEditor' },
Object: { widgetId: 'objectEditor' },
RichText: { widgetId: 'richTextEditor' },
Entry: { widgetId: 'entryLinkEditor' },
Asset: { widgetId: 'assetLinkEditor' },
Symbols: { widgetId: 'tagEditor' },
Entries: { widgetId: 'entryLinksEditor' },
Assets: { widgetId: 'assetLinksEditor' },
File: { widgetId: 'fileEditor' },
}
export const DEFAULTS_SETTINGS = {
Boolean: {
falseLabel: 'No',
helpText: null,
trueLabel: 'Yes',
},
Date: {
helpText: null,
ampm: '24',
format: 'timeZ',
},
Entry: {
helpText: null,
showCreateEntityAction: true,
showLinkEntityAction: true,
},
Asset: {
helpText: null,
showCreateEntityAction: true,
showLinkEntityAction: true,
},
Entries: {
helpText: null,
bulkEditing: false,
showCreateEntityAction: true,
showLinkEntityAction: true,
},
Assets: {
helpText: null,
showCreateEntityAction: true,
showLinkEntityAction: true,
},
} as const
interface DefaultWidget {
widgetId: string
settings?: {
helpText: null | string
}
fieldId: string
widgetNamespace: 'builtin'
}
function getDefaultWidget(field: keyof typeof DEFAULTS_WIDGET, fieldId: string) {
const defaultWidget: DefaultWidget = {
...(DEFAULTS_WIDGET[field] as Pick<DefaultWidget, 'widgetId'>),
settings: {
helpText: null,
},
widgetNamespace: 'builtin',
fieldId,
}
if (in_(field, DEFAULTS_SETTINGS)) {
defaultWidget.settings = {
...defaultWidget.settings,
...DEFAULTS_SETTINGS[field],
}
}
return defaultWidget
}
// Given our internal identifier returns a minimal API field object.
export function toApiFieldType(internal: keyof typeof INTERNAL_TO_API) {
return INTERNAL_TO_API[internal]
}
/*
* Gets the default widget ID for a field:
* - If a field allows predefined values then `dropdown` widget is used
* in the presence of the `in` validation.
* - If a Text field is a title then the `singleLine` widget is used.
* - Otherwise a simple type-to-editor mapping is used.
*/
export default function getDefaultControlOfField(field: ContentFields) {
const fieldType = toInternalFieldType(field)
if (!fieldType) {
throw new Error('Invalid field type')
}
const hasInValidation = (field.validations || []).find(
(v: ContentTypeFieldValidation) => 'in' in v
)
if (hasInValidation && DROPDOWN_TYPES.includes(fieldType)) {
return {
widgetId: 'dropdown',
fieldId: field.id,
widgetNameSpace: 'builtin',
}
}
return getDefaultWidget(fieldType, field.id)
}