@tinacms/app 1.2.7 → 1.2.9
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/CHANGELOG.md +18 -0
- package/package.json +6 -7
- package/src/lib/build-form.ts +49 -0
- package/src/lib/expand-query.ts +231 -0
- package/src/lib/graphql-reducer.ts +753 -0
- package/src/lib/types.ts +48 -0
- package/src/preview.tsx +3 -105
- package/src/assets/react.svg +0 -1
- package/src/lib/formify/index.ts +0 -325
- package/src/lib/machines/document-machine.ts +0 -338
- package/src/lib/machines/query-machine.ts +0 -701
- package/src/lib/machines/util.ts +0 -196
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @tinacms/app
|
|
2
2
|
|
|
3
|
+
## 1.2.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [e7f4c0a96]
|
|
8
|
+
- Updated dependencies [ff8673515]
|
|
9
|
+
- tinacms@1.5.2
|
|
10
|
+
|
|
11
|
+
## 1.2.8
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- eba7e5e5e: Simplify formify logic
|
|
16
|
+
- Updated dependencies [790b1e1ae]
|
|
17
|
+
- Updated dependencies [eba7e5e5e]
|
|
18
|
+
- tinacms@1.5.1
|
|
19
|
+
- @tinacms/toolkit@1.7.1
|
|
20
|
+
|
|
3
21
|
## 1.2.7
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/app",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"main": "src/main.tsx",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"devDependencies": {
|
|
@@ -12,24 +12,23 @@
|
|
|
12
12
|
"@graphiql/toolkit": "^0.8.2",
|
|
13
13
|
"@headlessui/react": "1.6.6",
|
|
14
14
|
"@heroicons/react": "1.0.6",
|
|
15
|
+
"@monaco-editor/react": "4.4.5",
|
|
15
16
|
"@tinacms/mdx": "1.3.9",
|
|
16
|
-
"@tinacms/toolkit": "1.7.
|
|
17
|
+
"@tinacms/toolkit": "1.7.1",
|
|
17
18
|
"@xstate/react": "3.0.0",
|
|
18
19
|
"final-form": "4.20.7",
|
|
19
20
|
"graphiql": "^2.4.0",
|
|
20
21
|
"graphql": "15.8.0",
|
|
22
|
+
"monaco-editor": "0.31.0",
|
|
21
23
|
"postcss": "^8.4.14",
|
|
22
24
|
"postcss-nested": "^5.0.6",
|
|
23
25
|
"react": "17.0.2",
|
|
24
26
|
"react-dom": "17.0.2",
|
|
25
27
|
"react-is": "17.0.2",
|
|
26
28
|
"react-router-dom": "6.3.0",
|
|
27
|
-
"tinacms": "1.5.0",
|
|
28
|
-
"xstate": "4.32.1",
|
|
29
29
|
"tailwindcss": "^3.2.7",
|
|
30
|
+
"tinacms": "1.5.2",
|
|
30
31
|
"typescript": "^4.6.4",
|
|
31
|
-
"
|
|
32
|
-
"monaco-editor": "0.31.0",
|
|
33
|
-
"webfontloader": "1.6.28"
|
|
32
|
+
"zod": "^3.14.3"
|
|
34
33
|
}
|
|
35
34
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Field, Form, FormOptions, TinaCMS, TinaField } from 'tinacms'
|
|
2
|
+
|
|
3
|
+
export type FieldType = Field & TinaField
|
|
4
|
+
export type FormValues = Record<string, unknown>
|
|
5
|
+
export type FormType = Form<FormValues, FieldType>
|
|
6
|
+
|
|
7
|
+
type FormCreator = (formConfig: FormOptions<any>) => Form
|
|
8
|
+
interface GlobalFormOptions {
|
|
9
|
+
icon?: any
|
|
10
|
+
layout: 'fullscreen' | 'popup'
|
|
11
|
+
}
|
|
12
|
+
type GlobalFormCreator = (
|
|
13
|
+
formConfig: FormOptions<any>,
|
|
14
|
+
options?: GlobalFormOptions
|
|
15
|
+
) => Form
|
|
16
|
+
interface GlobalFormOptions {
|
|
17
|
+
icon?: any
|
|
18
|
+
layout: 'fullscreen' | 'popup'
|
|
19
|
+
}
|
|
20
|
+
export interface FormifyArgs {
|
|
21
|
+
formConfig: FormOptions<any>
|
|
22
|
+
createForm: FormCreator
|
|
23
|
+
createGlobalForm: FormCreator
|
|
24
|
+
skip?: () => void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type FormifyCallback = (args: FormifyArgs, cms: TinaCMS) => Form | void
|
|
28
|
+
export type onSubmitArgs = {
|
|
29
|
+
/**
|
|
30
|
+
* @deprecated queryString is actually a mutation string, use `mutationString` instead
|
|
31
|
+
*/
|
|
32
|
+
queryString: string
|
|
33
|
+
mutationString: string
|
|
34
|
+
variables: object
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const createForm = (formConfig: FormOptions<any, any>) => {
|
|
38
|
+
return new Form(formConfig)
|
|
39
|
+
}
|
|
40
|
+
export const createGlobalForm: GlobalFormCreator = (
|
|
41
|
+
formConfig,
|
|
42
|
+
options?: { icon?: any; layout: 'fullscreen' | 'popup' }
|
|
43
|
+
) => {
|
|
44
|
+
const form = new Form({
|
|
45
|
+
...formConfig,
|
|
46
|
+
global: { global: true, ...options },
|
|
47
|
+
})
|
|
48
|
+
return form
|
|
49
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import * as G from 'graphql'
|
|
2
|
+
|
|
3
|
+
export const expandQuery = ({
|
|
4
|
+
schema,
|
|
5
|
+
documentNode,
|
|
6
|
+
}: {
|
|
7
|
+
schema: G.GraphQLSchema
|
|
8
|
+
documentNode: G.DocumentNode
|
|
9
|
+
}): G.DocumentNode => {
|
|
10
|
+
const documentNodeWithTypenames = addTypenameToDocument(documentNode)
|
|
11
|
+
return addMetaFieldsToQuery(documentNodeWithTypenames, new G.TypeInfo(schema))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const addTypenameToDocument = (doc: G.DocumentNode) => {
|
|
15
|
+
function isField(selection: G.SelectionNode): selection is G.FieldNode {
|
|
16
|
+
return selection.kind === 'Field'
|
|
17
|
+
}
|
|
18
|
+
return G.visit(doc, {
|
|
19
|
+
SelectionSet: {
|
|
20
|
+
enter(node, _key, parent) {
|
|
21
|
+
// Don't add __typename to OperationDefinitions.
|
|
22
|
+
if (
|
|
23
|
+
parent &&
|
|
24
|
+
(parent as G.OperationDefinitionNode).kind ===
|
|
25
|
+
G.Kind.OPERATION_DEFINITION
|
|
26
|
+
) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// No changes if no selections.
|
|
31
|
+
const { selections } = node
|
|
32
|
+
if (!selections) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// If selections already have a __typename, or are part of an
|
|
37
|
+
// introspection query, do nothing.
|
|
38
|
+
const skip = selections.some((selection) => {
|
|
39
|
+
return (
|
|
40
|
+
isField(selection) &&
|
|
41
|
+
(selection.name.value === '__typename' ||
|
|
42
|
+
selection.name.value.lastIndexOf('__', 0) === 0)
|
|
43
|
+
)
|
|
44
|
+
})
|
|
45
|
+
if (skip) {
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If this SelectionSet is @export-ed as an input variable, it should
|
|
50
|
+
// not have a __typename field (see issue #4691).
|
|
51
|
+
const field = parent as G.FieldNode
|
|
52
|
+
if (
|
|
53
|
+
isField(field) &&
|
|
54
|
+
field.directives &&
|
|
55
|
+
field.directives.some((d) => d.name.value === 'export')
|
|
56
|
+
) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Create and return a new SelectionSet with a __typename Field.
|
|
61
|
+
return {
|
|
62
|
+
...node,
|
|
63
|
+
selections: [...selections, TYPENAME_FIELD],
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const METADATA_FIELD: G.FieldNode = {
|
|
71
|
+
kind: G.Kind.FIELD,
|
|
72
|
+
name: {
|
|
73
|
+
kind: G.Kind.NAME,
|
|
74
|
+
value: '_tina_metadata',
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const TYPENAME_FIELD: G.FieldNode = {
|
|
79
|
+
kind: G.Kind.FIELD,
|
|
80
|
+
name: {
|
|
81
|
+
kind: G.Kind.NAME,
|
|
82
|
+
value: '__typename',
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const addMetadataField = (
|
|
87
|
+
node: G.FieldNode | G.InlineFragmentNode | G.FragmentDefinitionNode
|
|
88
|
+
): G.ASTNode => {
|
|
89
|
+
return {
|
|
90
|
+
...node,
|
|
91
|
+
selectionSet: {
|
|
92
|
+
...(node.selectionSet || {
|
|
93
|
+
kind: 'SelectionSet',
|
|
94
|
+
selections: [],
|
|
95
|
+
}),
|
|
96
|
+
selections:
|
|
97
|
+
[...(node.selectionSet?.selections || []), METADATA_FIELD] || [],
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const addMetaFieldsToQuery = (
|
|
103
|
+
documentNode: G.DocumentNode,
|
|
104
|
+
typeInfo: G.TypeInfo
|
|
105
|
+
) => {
|
|
106
|
+
const addMetaFields: G.VisitFn<G.ASTNode, G.FieldNode> = (
|
|
107
|
+
node: G.FieldNode
|
|
108
|
+
): G.ASTNode => {
|
|
109
|
+
return {
|
|
110
|
+
...node,
|
|
111
|
+
selectionSet: {
|
|
112
|
+
...(node.selectionSet || {
|
|
113
|
+
kind: 'SelectionSet',
|
|
114
|
+
selections: [],
|
|
115
|
+
}),
|
|
116
|
+
selections:
|
|
117
|
+
[...(node.selectionSet?.selections || []), ...metaFields] || [],
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const formifyVisitor: G.Visitor<G.ASTKindToNode, G.ASTNode> = {
|
|
123
|
+
FragmentDefinition: {
|
|
124
|
+
enter: (node, key, parent, path, ancestors) => {
|
|
125
|
+
typeInfo.enter(node)
|
|
126
|
+
const type = typeInfo.getType()
|
|
127
|
+
if (type) {
|
|
128
|
+
const namedType = G.getNamedType(type)
|
|
129
|
+
if (G.isObjectType(namedType)) {
|
|
130
|
+
if (namedType.getFields()['_tina_metadata']) {
|
|
131
|
+
return addMetadataField(node)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return node
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
InlineFragment: {
|
|
139
|
+
enter: (node, key, parent, path, ancestors) => {
|
|
140
|
+
typeInfo.enter(node)
|
|
141
|
+
const type = typeInfo.getType()
|
|
142
|
+
if (type) {
|
|
143
|
+
const namedType = G.getNamedType(type)
|
|
144
|
+
if (G.isObjectType(namedType)) {
|
|
145
|
+
if (namedType.getFields()['_tina_metadata']) {
|
|
146
|
+
return addMetadataField(node)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return node
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
Field: {
|
|
154
|
+
enter: (node, key, parent, path, ancestors) => {
|
|
155
|
+
typeInfo.enter(node)
|
|
156
|
+
const type = typeInfo.getType()
|
|
157
|
+
if (type) {
|
|
158
|
+
if (isNodeType(type)) {
|
|
159
|
+
return addMetaFields(node, key, parent, path, ancestors)
|
|
160
|
+
}
|
|
161
|
+
const namedType = G.getNamedType(type)
|
|
162
|
+
if (G.isObjectType(namedType)) {
|
|
163
|
+
if (namedType.getFields()['_tina_metadata']) {
|
|
164
|
+
return addMetadataField(node)
|
|
165
|
+
}
|
|
166
|
+
return node
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return node
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
return G.visit(documentNode, G.visitWithTypeInfo(typeInfo, formifyVisitor))
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* This is a dummy query which we pull apart and spread
|
|
177
|
+
* back into the the selectionSet for all "Node" fields
|
|
178
|
+
*/
|
|
179
|
+
const node = G.parse(`
|
|
180
|
+
query Sample {
|
|
181
|
+
...on Document {
|
|
182
|
+
_internalValues: _values
|
|
183
|
+
_internalSys: _sys {
|
|
184
|
+
breadcrumbs
|
|
185
|
+
basename
|
|
186
|
+
filename
|
|
187
|
+
path
|
|
188
|
+
extension
|
|
189
|
+
relativePath
|
|
190
|
+
title
|
|
191
|
+
template
|
|
192
|
+
collection {
|
|
193
|
+
name
|
|
194
|
+
slug
|
|
195
|
+
label
|
|
196
|
+
path
|
|
197
|
+
format
|
|
198
|
+
matches
|
|
199
|
+
templates
|
|
200
|
+
fields
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}`)
|
|
205
|
+
const metaFields: G.SelectionNode[] =
|
|
206
|
+
// @ts-ignore
|
|
207
|
+
node.definitions[0].selectionSet.selections
|
|
208
|
+
|
|
209
|
+
export const isNodeType = (type: G.GraphQLOutputType) => {
|
|
210
|
+
const namedType = G.getNamedType(type)
|
|
211
|
+
if (G.isInterfaceType(namedType)) {
|
|
212
|
+
if (namedType.name === 'Node') {
|
|
213
|
+
return true
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (G.isUnionType(namedType)) {
|
|
217
|
+
const types = namedType.getTypes()
|
|
218
|
+
if (
|
|
219
|
+
types.every((type) => {
|
|
220
|
+
return type.getInterfaces().some((intfc) => intfc.name === 'Node')
|
|
221
|
+
})
|
|
222
|
+
) {
|
|
223
|
+
return true
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (G.isObjectType(namedType)) {
|
|
227
|
+
if (namedType.getInterfaces().some((intfc) => intfc.name === 'Node')) {
|
|
228
|
+
return true
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|