@tinacms/app 0.0.0-00f6525-20241015065741

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/src/index.css ADDED
@@ -0,0 +1,384 @@
1
+ @import 'global.css';
2
+ @import 'preflight.css';
3
+ @tailwind base;
4
+ @tailwind components;
5
+ @tailwind utilities;
6
+
7
+ /* Tailwind reset clobbers some playground styles */
8
+ .graphiql-execute-button {
9
+ @apply bg-blue-600 !important;
10
+ }
11
+
12
+ .icon-parent svg {
13
+ fill: currentColor;
14
+ }
15
+
16
+ body {
17
+ margin: 0;
18
+ padding: 0;
19
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
20
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
21
+ sans-serif;
22
+ -webkit-font-smoothing: antialiased;
23
+ -moz-osx-font-smoothing: grayscale;
24
+ }
25
+
26
+ code {
27
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
28
+ monospace;
29
+ }
30
+
31
+ div.graphiql-explorer-root > div:last-child {
32
+ display: none;
33
+ }
34
+
35
+ .graphiql-container {
36
+ height: 100vh !important;
37
+ width: 100vw !important;
38
+ }
39
+
40
+ /* if the last block has margin-bottom it makes the text box larger but some of it isn't clickable */
41
+ .tina-prose [data-slate-editor='true'] {
42
+ padding-bottom: 0.5em;
43
+ /* Outline is placed on the parent element for styling consistency with other elements */
44
+ outline: none;
45
+ }
46
+ /* prose adds backticks, which look like they should be editable */
47
+ .tina-prose [data-slate-editor='true'] .slate-code::before {
48
+ content: '';
49
+ }
50
+ .tina-prose [data-slate-editor='true'] .slate-code::after {
51
+ content: '';
52
+ }
53
+ .tina-prose [data-slate-editor='true'] .slate-code_block {
54
+ margin: 0;
55
+ }
56
+ /* code lines as part of a block don't need the same background formatting */
57
+ .tina-prose [data-slate-editor='true'] .slate-code_block .slate-code {
58
+ background: none;
59
+ }
60
+ /* prose makes the first p in a block slightly larger */
61
+ .tina-prose [data-slate-editor='true'] p:first-of-type {
62
+ font-size: 1em;
63
+ }
64
+
65
+ /* experimental floating toolbar doesn't need a large text area */
66
+ .with-toolbar [data-slate-editor='true'] {
67
+ min-height: 72px;
68
+ }
69
+
70
+ @keyframes color-popup-keyframes {
71
+ 0% {
72
+ transform: translate3d(-50%, 0, 0) scale3d(0.5, 0.5, 1);
73
+ }
74
+ 100% {
75
+ transform: translate3d(-50%, 8px, 0) scale3d(1, 1, 1);
76
+ }
77
+ }
78
+
79
+ @keyframes color-popup-open-top-keyframes {
80
+ 0% {
81
+ transform: translate3d(-50%, -100%, 0) scale3d(0.5, 0.5, 1);
82
+ }
83
+ 100% {
84
+ transform: translate3d(-50%, calc(-100% - 8px), 0) scale3d(1, 1, 1);
85
+ }
86
+ }
87
+
88
+ @keyframes loading-dots-scale-up-and-down {
89
+ 0% {
90
+ transform: scale(0.1);
91
+ }
92
+
93
+ 50% {
94
+ transform: scale(1);
95
+ }
96
+
97
+ 90% {
98
+ transform: scale(0.1);
99
+ }
100
+
101
+ 100% {
102
+ transform: scale(0.1);
103
+ }
104
+ }
105
+
106
+ .color-picker-clip-path::before,
107
+ .color-picker-clip-path::after {
108
+ clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
109
+ }
110
+
111
+ .color-picker-on-top-clip-path::before,
112
+ .color-picker-on-top-clip-path::after {
113
+ clip-path: polygon(0% 0%, 100% 0%, 50% 100%);
114
+ }
115
+
116
+ .tina-date-field .rdt {
117
+ position: relative;
118
+ }
119
+
120
+ .tina-date-field .rdtPicker {
121
+ display: none;
122
+ position: absolute;
123
+ width: 100%;
124
+ max-width: 350px;
125
+ padding: 4px;
126
+ margin-top: 4px;
127
+ z-index: 99999 !important;
128
+ background: var(--tina-color-grey-0);
129
+ border-radius: var(--tina-radius-small);
130
+ box-shadow: var(--tina-shadow-big);
131
+ border: 1px solid var(--tina-color-grey-2);
132
+ }
133
+
134
+ .tina-date-field .rdtOpen .rdtPicker {
135
+ display: block;
136
+ }
137
+
138
+ .tina-date-field .rdtStatic .rdtPicker {
139
+ box-shadow: none;
140
+ position: static;
141
+ }
142
+
143
+ .tina-date-field .rdtPicker .rdtTimeToggle {
144
+ text-align: center;
145
+ }
146
+
147
+ .tina-date-field .rdtPicker table {
148
+ width: 100%;
149
+ margin: 0;
150
+ }
151
+
152
+ .tina-date-field .rdtPicker td,
153
+ .rdtPicker th {
154
+ text-align: center;
155
+ height: 28px;
156
+ }
157
+
158
+ .tina-date-field .rdtPicker td {
159
+ cursor: pointer;
160
+ }
161
+
162
+ .tina-date-field .rdtPicker td.rdtDay:hover,
163
+ .tina-date-field .rdtPicker td.rdtHour:hover,
164
+ .tina-date-field .rdtPicker td.rdtMinute:hover,
165
+ .tina-date-field .rdtPicker td.rdtSecond:hover,
166
+ .tina-date-field .rdtPicker .rdtTimeToggle:hover {
167
+ background: var(--tina-color-grey-2);
168
+ color: var(--tina-color-primary);
169
+ border-radius: var(--tina-radius-small);
170
+ cursor: pointer;
171
+ }
172
+
173
+ .tina-date-field .rdtPicker td.rdtDay:hover:active,
174
+ .tina-date-field .rdtPicker td.rdtHour:hover:active,
175
+ .tina-date-field .rdtPicker td.rdtMinute:hover:active,
176
+ .tina-date-field .rdtPicker td.rdtSecond:hover:active,
177
+ .tina-date-field .rdtPicker .rdtTimeToggle:hover:active {
178
+ background: var(--tina-color-primary);
179
+ color: var(--tina-color-grey-0);
180
+ border-radius: var(--tina-radius-small);
181
+ }
182
+
183
+ .tina-date-field .rdtPicker td.rdtOld,
184
+ .rdtPicker td.rdtNew {
185
+ color: var(--tina-color-grey-6);
186
+ }
187
+
188
+ .tina-date-field .rdtPicker td.rdtToday {
189
+ position: relative;
190
+ }
191
+
192
+ .tina-date-field .rdtPicker td.rdtToday:before {
193
+ content: '';
194
+ display: inline-block;
195
+ border-left: 7px solid transparent;
196
+ border-bottom: 7px solid var(--tina-color-primary);
197
+ border-radius: 20px;
198
+ border-top-color: rgba(0, 0, 0, 0.2);
199
+ position: absolute;
200
+ bottom: 4px;
201
+ right: 4px;
202
+ }
203
+
204
+ .tina-date-field .rdtPicker td.rdtActive,
205
+ .rdtPicker td.rdtActive:hover {
206
+ background-color: var(--tina-color-primary);
207
+ color: var(--tina-color-grey-0);
208
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
209
+ }
210
+
211
+ .tina-date-field .rdtPicker td.rdtActive.rdtToday:before {
212
+ border-bottom-color: var(--tina-color-grey-0);
213
+ }
214
+
215
+ .tina-date-field .rdtPicker td.rdtDisabled,
216
+ .rdtPicker td.rdtDisabled:hover {
217
+ background: none;
218
+ color: var(--tina-color-grey-6);
219
+ cursor: not-allowed;
220
+ }
221
+
222
+ .tina-date-field .rdtPicker td span.rdtOld {
223
+ color: var(--tina-color-grey-6);
224
+ }
225
+
226
+ .tina-date-field .rdtPicker td span.rdtDisabled,
227
+ .rdtPicker td span.rdtDisabled:hover {
228
+ background: none;
229
+ color: var(--tina-color-grey-6);
230
+ cursor: not-allowed;
231
+ }
232
+
233
+ .tina-date-field .rdtPicker th {
234
+ border-bottom: 1px solid var(--tina-color-grey-1);
235
+ }
236
+
237
+ .tina-date-field .rdtPicker .dow {
238
+ width: 14.2857%;
239
+ border-bottom: none;
240
+ cursor: default;
241
+ }
242
+
243
+ .tina-date-field .rdtPicker th.rdtSwitch {
244
+ width: 100px;
245
+ }
246
+
247
+ .tina-date-field .rdtPicker th.rdtNext,
248
+ .rdtPicker th.rdtPrev {
249
+ font-size: 21px;
250
+ vertical-align: top;
251
+ }
252
+
253
+ .tina-date-field .rdtPrev span,
254
+ .rdtNext span {
255
+ display: block;
256
+ -webkit-touch-callout: none;
257
+ /* iOS Safari */
258
+ -webkit-user-select: none;
259
+ /* Chrome/Safari/Opera */
260
+ -khtml-user-select: none;
261
+ /* Konqueror */
262
+ -moz-user-select: none;
263
+ /* Firefox */
264
+ -ms-user-select: none;
265
+ /* Internet Explorer/Edge */
266
+ user-select: none;
267
+ }
268
+
269
+ .tina-date-field .rdtPicker th.rdtDisabled,
270
+ .rdtPicker th.rdtDisabled:hover {
271
+ background: none;
272
+ color: var(--tina-color-grey-6);
273
+ cursor: not-allowed;
274
+ }
275
+
276
+ .tina-date-field .rdtPicker thead tr:first-child th {
277
+ cursor: pointer;
278
+ }
279
+
280
+ .tina-date-field .rdtPicker thead tr:first-child th:hover {
281
+ background: var(--tina-color-grey-2);
282
+ color: var(--tina-color-primary);
283
+ border-radius: var(--tina-radius-small);
284
+ }
285
+
286
+ .tina-date-field .rdtPicker tfoot {
287
+ border-top: 1px solid var(--tina-color-grey-1);
288
+ }
289
+
290
+ .tina-date-field .rdtPicker button {
291
+ border: none;
292
+ background: none;
293
+ cursor: pointer;
294
+ }
295
+
296
+ .tina-date-field .rdtPicker button:hover {
297
+ background: var(--tina-color-grey-2);
298
+ color: var(--tina-color-primary);
299
+ border-radius: var(--tina-radius-small);
300
+ }
301
+
302
+ .tina-date-field .rdtPicker thead button {
303
+ width: 100%;
304
+ height: 100%;
305
+ }
306
+
307
+ .tina-date-field td.rdtMonth,
308
+ td.rdtYear {
309
+ height: 50px;
310
+ width: 25%;
311
+ cursor: pointer;
312
+ }
313
+
314
+ .tina-date-field td.rdtMonth:hover,
315
+ td.rdtYear:hover {
316
+ background: var(--tina-color-grey-2);
317
+ color: var(--tina-color-primary);
318
+ border-radius: var(--tina-radius-small);
319
+ }
320
+
321
+ .tina-date-field .rdtCounters {
322
+ display: inline-block;
323
+ }
324
+
325
+ .tina-date-field .rdtCounters > div {
326
+ float: left;
327
+ }
328
+
329
+ .tina-date-field .rdtCounter {
330
+ height: 100px;
331
+ }
332
+
333
+ .tina-date-field .rdtCounter {
334
+ width: 40px;
335
+ }
336
+
337
+ .tina-date-field .rdtCounterSeparator {
338
+ line-height: 100px;
339
+ }
340
+
341
+ .tina-date-field .rdtCounter .rdtBtn {
342
+ height: 40%;
343
+ line-height: 40px;
344
+ cursor: pointer;
345
+ display: block;
346
+ -webkit-touch-callout: none;
347
+ /* iOS Safari */
348
+ -webkit-user-select: none;
349
+ /* Chrome/Safari/Opera */
350
+ -khtml-user-select: none;
351
+ /* Konqueror */
352
+ -moz-user-select: none;
353
+ /* Firefox */
354
+ -ms-user-select: none;
355
+ /* Internet Explorer/Edge */
356
+ user-select: none;
357
+ }
358
+
359
+ .tina-date-field .rdtCounter .rdtBtn:hover {
360
+ background: var(--tina-color-grey-2);
361
+ color: var(--tina-color-primary);
362
+ border-radius: var(--tina-radius-small);
363
+ }
364
+
365
+ .tina-date-field .rdtCounter .rdtCount {
366
+ height: 20%;
367
+ font-size: 1.2em;
368
+ }
369
+
370
+ .tina-date-field .rdtMilli {
371
+ vertical-align: middle;
372
+ padding-left: 8px;
373
+ width: 48px;
374
+ }
375
+
376
+ .tina-date-field .rdtMilli input {
377
+ width: 100%;
378
+ font-size: 1.2em;
379
+ margin-top: 37px;
380
+ }
381
+
382
+ .tina-date-field .rdtTime td {
383
+ cursor: default;
384
+ }
@@ -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,24 @@
1
+ import React from 'react'
2
+ import { TinaCMS } from 'tinacms'
3
+
4
+ const ErrorModalContent = (props: { title: string; errors: string[] }) => {
5
+ const { title, errors } = props
6
+ return (
7
+ <>
8
+ <div>{title}</div>
9
+ <ul>
10
+ {errors.map((error, i) => (
11
+ <li key={i}>{error}</li>
12
+ ))}
13
+ </ul>
14
+ </>
15
+ )
16
+ }
17
+
18
+ export const showErrorModal = (
19
+ title: string,
20
+ errors: string[],
21
+ cms: TinaCMS
22
+ ) => {
23
+ cms.alerts.error(() => <ErrorModalContent title={title} errors={errors} />)
24
+ }
@@ -0,0 +1,268 @@
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 CONTENT_SOURCE_FIELD: G.FieldNode = {
71
+ kind: G.Kind.FIELD,
72
+ name: {
73
+ kind: G.Kind.NAME,
74
+ value: '_content_source',
75
+ },
76
+ }
77
+ const METADATA_FIELD: G.FieldNode = {
78
+ kind: G.Kind.FIELD,
79
+ name: {
80
+ kind: G.Kind.NAME,
81
+ value: '_tina_metadata',
82
+ },
83
+ }
84
+
85
+ const TYPENAME_FIELD: G.FieldNode = {
86
+ kind: G.Kind.FIELD,
87
+ name: {
88
+ kind: G.Kind.NAME,
89
+ value: '__typename',
90
+ },
91
+ }
92
+
93
+ const addMetadataField = (
94
+ node: G.FieldNode | G.InlineFragmentNode | G.FragmentDefinitionNode
95
+ ): G.ASTNode => {
96
+ return {
97
+ ...node,
98
+ selectionSet: {
99
+ ...(node.selectionSet || {
100
+ kind: 'SelectionSet',
101
+ selections: [],
102
+ }),
103
+ selections:
104
+ [
105
+ ...(node.selectionSet?.selections || []),
106
+ METADATA_FIELD,
107
+ CONTENT_SOURCE_FIELD,
108
+ ] || [],
109
+ },
110
+ }
111
+ }
112
+
113
+ const addMetaFieldsToQuery = (
114
+ documentNode: G.DocumentNode,
115
+ typeInfo: G.TypeInfo
116
+ ) => {
117
+ const addMetaFields: G.VisitFn<G.ASTNode, G.FieldNode> = (
118
+ node: G.FieldNode
119
+ ): G.ASTNode => {
120
+ return {
121
+ ...node,
122
+ selectionSet: {
123
+ ...(node.selectionSet || {
124
+ kind: 'SelectionSet',
125
+ selections: [],
126
+ }),
127
+ selections:
128
+ [...(node.selectionSet?.selections || []), ...metaFields] || [],
129
+ },
130
+ }
131
+ }
132
+
133
+ const formifyVisitor: G.Visitor<G.ASTKindToNode, G.ASTNode> = {
134
+ FragmentDefinition: {
135
+ enter: (node, key, parent, path, ancestors) => {
136
+ typeInfo.enter(node)
137
+ const type = typeInfo.getType()
138
+ if (type) {
139
+ const namedType = G.getNamedType(type)
140
+ if (G.isObjectType(namedType)) {
141
+ if (namedType.getFields()['_tina_metadata']) {
142
+ return addMetadataField(node)
143
+ }
144
+ }
145
+ return node
146
+ }
147
+ },
148
+ },
149
+ InlineFragment: {
150
+ enter: (node, key, parent, path, ancestors) => {
151
+ typeInfo.enter(node)
152
+ const type = typeInfo.getType()
153
+ if (type) {
154
+ const namedType = G.getNamedType(type)
155
+ if (G.isObjectType(namedType)) {
156
+ if (namedType.getFields()['_tina_metadata']) {
157
+ return addMetadataField(node)
158
+ }
159
+ }
160
+ return node
161
+ }
162
+ },
163
+ },
164
+ Field: {
165
+ enter: (node, key, parent, path, ancestors) => {
166
+ typeInfo.enter(node)
167
+ const type = typeInfo.getType()
168
+ if (type) {
169
+ if (isNodeType(type)) {
170
+ return addMetaFields(node, key, parent, path, ancestors)
171
+ }
172
+ const namedType = G.getNamedType(type)
173
+ if (G.isObjectType(namedType)) {
174
+ if (namedType.getFields()['_tina_metadata']) {
175
+ return addMetadataField(node)
176
+ }
177
+ return node
178
+ }
179
+ }
180
+ return node
181
+ },
182
+ },
183
+ }
184
+ return G.visit(documentNode, G.visitWithTypeInfo(typeInfo, formifyVisitor))
185
+ }
186
+ /**
187
+ * This is a dummy query which we pull apart and spread
188
+ * back into the the selectionSet for all "Node" fields
189
+ */
190
+ const node = G.parse(`
191
+ query Sample {
192
+ ...on Document {
193
+ _internalValues: _values
194
+ _internalSys: _sys {
195
+ breadcrumbs
196
+ basename
197
+ filename
198
+ path
199
+ extension
200
+ relativePath
201
+ title
202
+ template
203
+ collection {
204
+ name
205
+ slug
206
+ label
207
+ path
208
+ format
209
+ matches
210
+ templates
211
+ fields
212
+ }
213
+ }
214
+ }
215
+ }`)
216
+ const metaFields: G.SelectionNode[] =
217
+ // @ts-ignore
218
+ node.definitions[0].selectionSet.selections
219
+
220
+ export const isNodeType = (type: G.GraphQLOutputType) => {
221
+ const namedType = G.getNamedType(type)
222
+ if (G.isInterfaceType(namedType)) {
223
+ if (namedType.name === 'Node') {
224
+ return true
225
+ }
226
+ }
227
+ if (G.isUnionType(namedType)) {
228
+ const types = namedType.getTypes()
229
+ if (
230
+ types.every((type) => {
231
+ return type.getInterfaces().some((intfc) => intfc.name === 'Node')
232
+ })
233
+ ) {
234
+ return true
235
+ }
236
+ }
237
+ if (G.isObjectType(namedType)) {
238
+ if (namedType.getInterfaces().some((intfc) => intfc.name === 'Node')) {
239
+ return true
240
+ }
241
+ }
242
+ }
243
+
244
+ export const isConnectionType = (type: G.GraphQLOutputType) => {
245
+ const namedType = G.getNamedType(type)
246
+ if (G.isInterfaceType(namedType)) {
247
+ if (namedType.name === 'Connection') {
248
+ return true
249
+ }
250
+ }
251
+ if (G.isUnionType(namedType)) {
252
+ const types = namedType.getTypes()
253
+ if (
254
+ types.every((type) => {
255
+ return type.getInterfaces().some((intfc) => intfc.name === 'Connection')
256
+ })
257
+ ) {
258
+ return true
259
+ }
260
+ }
261
+ if (G.isObjectType(namedType)) {
262
+ if (
263
+ namedType.getInterfaces().some((intfc) => intfc.name === 'Connection')
264
+ ) {
265
+ return true
266
+ }
267
+ }
268
+ }