@tinacms/app 0.0.0-20230516154119 → 0.0.0-20230516164752

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 CHANGED
@@ -1,13 +1,14 @@
1
1
  # @tinacms/app
2
2
 
3
- ## 0.0.0-20230516154119
3
+ ## 0.0.0-20230516164752
4
4
 
5
5
  ### Patch Changes
6
6
 
7
7
  - 7f95c1ce5: Reorganize the way fields are presented on the form to allow for deep-linking
8
+ - Updated dependencies [b3d98d159]
8
9
  - Updated dependencies [7f95c1ce5]
9
- - @tinacms/toolkit@0.0.0-20230516154119
10
- - tinacms@0.0.0-20230516154119
10
+ - @tinacms/toolkit@0.0.0-20230516164752
11
+ - tinacms@0.0.0-20230516164752
11
12
 
12
13
  ## 1.2.12
13
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinacms/app",
3
- "version": "0.0.0-20230516154119",
3
+ "version": "0.0.0-20230516164752",
4
4
  "main": "src/main.tsx",
5
5
  "license": "Apache-2.0",
6
6
  "devDependencies": {
@@ -13,6 +13,8 @@
13
13
  "@headlessui/react": "1.6.6",
14
14
  "@heroicons/react": "1.0.6",
15
15
  "@monaco-editor/react": "4.4.5",
16
+ "@tinacms/mdx": "1.3.10",
17
+ "@tinacms/toolkit": "0.0.0-20230516164752",
16
18
  "@xstate/react": "3.0.0",
17
19
  "final-form": "4.20.7",
18
20
  "graphiql": "^2.4.0",
@@ -25,10 +27,8 @@
25
27
  "react-is": "17.0.2",
26
28
  "react-router-dom": "6.3.0",
27
29
  "tailwindcss": "^3.2.7",
30
+ "tinacms": "0.0.0-20230516164752",
28
31
  "typescript": "^4.6.4",
29
- "zod": "^3.14.3",
30
- "@tinacms/mdx": "1.3.10",
31
- "@tinacms/toolkit": "0.0.0-20230516154119",
32
- "tinacms": "0.0.0-20230516154119"
32
+ "zod": "^3.14.3"
33
33
  }
34
34
  }
@@ -67,13 +67,6 @@ const addTypenameToDocument = (doc: G.DocumentNode) => {
67
67
  })
68
68
  }
69
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
70
  const METADATA_FIELD: G.FieldNode = {
78
71
  kind: G.Kind.FIELD,
79
72
  name: {
@@ -101,11 +94,7 @@ const addMetadataField = (
101
94
  selections: [],
102
95
  }),
103
96
  selections:
104
- [
105
- ...(node.selectionSet?.selections || []),
106
- METADATA_FIELD,
107
- CONTENT_SOURCE_FIELD,
108
- ] || [],
97
+ [...(node.selectionSet?.selections || []), METADATA_FIELD] || [],
109
98
  },
110
99
  }
111
100
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import * as G from 'graphql'
3
3
  import { getIn } from 'final-form'
4
- import { z } from 'zod'
4
+ import { z, ZodError } from 'zod'
5
5
  // @ts-expect-error
6
6
  import schemaJson from 'SCHEMA_IMPORT'
7
7
  import { expandQuery, isConnectionType, isNodeType } from './expand-query'
@@ -25,10 +25,9 @@ import type {
25
25
  PostMessage,
26
26
  Payload,
27
27
  SystemInfo,
28
+ Document,
28
29
  ResolvedDocument,
29
30
  } from './types'
30
- import { getFormAndFieldNameFromMetadata } from './util'
31
- import { useSearchParams } from 'react-router-dom'
32
31
 
33
32
  const sysSchema = z.object({
34
33
  breadcrumbs: z.array(z.string()),
@@ -58,50 +57,6 @@ const astNode = schemaJson as G.DocumentNode
58
57
  const astNodeWithMeta: G.DocumentNode = {
59
58
  ...astNode,
60
59
  definitions: astNode.definitions.map((def) => {
61
- if (def.kind === 'InterfaceTypeDefinition') {
62
- return {
63
- ...def,
64
- fields: [
65
- ...(def.fields || []),
66
- {
67
- kind: 'FieldDefinition',
68
- name: {
69
- kind: 'Name',
70
- value: '_tina_metadata',
71
- },
72
- arguments: [],
73
- type: {
74
- kind: 'NonNullType',
75
- type: {
76
- kind: 'NamedType',
77
- name: {
78
- kind: 'Name',
79
- value: 'JSON',
80
- },
81
- },
82
- },
83
- },
84
- {
85
- kind: 'FieldDefinition',
86
- name: {
87
- kind: 'Name',
88
- value: '_content_source',
89
- },
90
- arguments: [],
91
- type: {
92
- kind: 'NonNullType',
93
- type: {
94
- kind: 'NamedType',
95
- name: {
96
- kind: 'Name',
97
- value: 'JSON',
98
- },
99
- },
100
- },
101
- },
102
- ],
103
- }
104
- }
105
60
  if (def.kind === 'ObjectTypeDefinition') {
106
61
  return {
107
62
  ...def,
@@ -125,24 +80,6 @@ const astNodeWithMeta: G.DocumentNode = {
125
80
  },
126
81
  },
127
82
  },
128
- {
129
- kind: 'FieldDefinition',
130
- name: {
131
- kind: 'Name',
132
- value: '_content_source',
133
- },
134
- arguments: [],
135
- type: {
136
- kind: 'NonNullType',
137
- type: {
138
- kind: 'NamedType',
139
- name: {
140
- kind: 'Name',
141
- value: 'JSON',
142
- },
143
- },
144
- },
145
- },
146
83
  ],
147
84
  }
148
85
  }
@@ -159,18 +96,6 @@ export const useGraphQLReducer = (
159
96
  const cms = useCMS()
160
97
  const tinaSchema = cms.api.tina.schema as TinaSchema
161
98
  const [payloads, setPayloads] = React.useState<Payload[]>([])
162
- const [searchParams, setSearchParams] = useSearchParams()
163
- const [results, setResults] = React.useState<
164
- {
165
- id: string
166
- data:
167
- | {
168
- [key: string]: any
169
- }
170
- | null
171
- | undefined
172
- }[]
173
- >([])
174
99
  const [documentsToResolve, setDocumentsToResolve] = React.useState<string[]>(
175
100
  []
176
101
  )
@@ -179,11 +104,6 @@ export const useGraphQLReducer = (
179
104
  >([])
180
105
  const [operationIndex, setOperationIndex] = React.useState(0)
181
106
 
182
- const helper = React.useMemo(() => {
183
- const previewPlugins = cms.plugins.getType('preview-helper')
184
- return previewPlugins.find('preview-helper')
185
- }, [cms])
186
-
187
107
  React.useEffect(() => {
188
108
  const run = async () => {
189
109
  return Promise.all(
@@ -225,7 +145,7 @@ export const useGraphQLReducer = (
225
145
  setPayloads(updatedPayloads)
226
146
  })
227
147
  }
228
- }, [JSON.stringify(payloads), cms])
148
+ }, [payloads.map(({ id }) => id).join('.'), cms])
229
149
 
230
150
  const processPayload = React.useCallback(
231
151
  (payload: Payload) => {
@@ -272,13 +192,6 @@ export const useGraphQLReducer = (
272
192
  if (fieldName === '_values') {
273
193
  return source._internalValues
274
194
  }
275
- if (info.fieldName === '_content_source') {
276
- const pathArray = G.responsePathAsArray(info.path)
277
- return {
278
- queryId: payload.id,
279
- path: pathArray.slice(0, pathArray.length - 1),
280
- }
281
- }
282
195
  if (info.fieldName === '_tina_metadata') {
283
196
  if (value) {
284
197
  return value
@@ -288,7 +201,6 @@ export const useGraphQLReducer = (
288
201
  return {
289
202
  id: null,
290
203
  fields: [],
291
- prefix: '',
292
204
  }
293
205
  }
294
206
  if (isConnectionType(info.returnType)) {
@@ -359,9 +271,13 @@ export const useGraphQLReducer = (
359
271
  return pathString.startsWith(item.path)
360
272
  }
361
273
  })
362
- const parent = ancestors[ancestors.length - 1]
274
+ let parent = ancestors[ancestors.length - 1]
363
275
  if (parent) {
364
276
  if (parent.type === 'document') {
277
+ // console.log(
278
+ // 'its a parent',
279
+ // JSON.stringify({ id, value, pathString, parent }, null, 2)
280
+ // )
365
281
  parent.subItems.push({
366
282
  type: 'document',
367
283
  path: pathString,
@@ -391,12 +307,7 @@ export const useGraphQLReducer = (
391
307
  },
392
308
  { values: true }
393
309
  )
394
- return resolveDocument(
395
- resolvedDocument,
396
- template,
397
- form,
398
- pathString
399
- )
310
+ return resolveDocument(resolvedDocument, template, form)
400
311
  } else {
401
312
  existingForm.tinaForm.addQuery(payload.id)
402
313
  const { template } = getTemplateForDocument(
@@ -407,19 +318,10 @@ export const useGraphQLReducer = (
407
318
  return resolveDocument(
408
319
  resolvedDocument,
409
320
  template,
410
- existingForm.tinaForm,
411
- pathString
321
+ existingForm.tinaForm
412
322
  )
413
323
  }
414
324
  }
415
- if (typeof value === 'string' && source?._tina_metadata) {
416
- // FIXME: hack to prevent breaking images
417
- if (helper) {
418
- const pathArray = G.responsePathAsArray(info.path)
419
-
420
- return helper.encode(pathArray.join('.'), value, payload.id)
421
- }
422
- }
423
325
  return value
424
326
  },
425
327
  })
@@ -442,32 +344,6 @@ export const useGraphQLReducer = (
442
344
  }
443
345
  })
444
346
  } else {
445
- if (result.data) {
446
- setResults((results) => [
447
- ...results,
448
- { id: payload.id, data: result.data },
449
- ])
450
- }
451
- const activeField = searchParams.get('active-field')
452
- if (activeField) {
453
- setSearchParams({})
454
- const [queryId, eventFieldName] = activeField.split('---')
455
- if (queryId === payload.id) {
456
- if (result?.data) {
457
- cms.dispatch({
458
- type: 'forms:set-active-field-name',
459
- value: getFormAndFieldNameFromMetadata(
460
- result.data,
461
- eventFieldName
462
- ),
463
- })
464
- }
465
- cms.dispatch({
466
- type: 'sidebar:set-display-state',
467
- value: 'openOrFull',
468
- })
469
- }
470
- }
471
347
  iframe.current?.contentWindow?.postMessage({
472
348
  type: 'updateData',
473
349
  id: payload.id,
@@ -487,40 +363,24 @@ export const useGraphQLReducer = (
487
363
  [resolvedDocuments.map((doc) => doc._internalSys.path).join('.')]
488
364
  )
489
365
 
490
- const handleMessage = React.useCallback(
366
+ const notifyEditMode = React.useCallback(
491
367
  (event: MessageEvent<PostMessage>) => {
492
- if (event?.data?.type === 'quick-edit') {
493
- cms.dispatch({
494
- type: 'set-quick-editing-supported',
495
- value: event.data.value,
496
- })
497
- }
498
368
  if (event?.data?.type === 'isEditMode') {
499
369
  iframe?.current?.contentWindow?.postMessage({
500
370
  type: 'tina:editMode',
501
371
  })
502
372
  }
503
- if (event.data.type === 'field:selected') {
504
- const [queryId, eventFieldName] = event.data.fieldName.split('---')
505
- const result = results.find((res) => res.id === queryId)
506
- if (result?.data) {
507
- cms.dispatch({
508
- type: 'forms:set-active-field-name',
509
- value: getFormAndFieldNameFromMetadata(result.data, eventFieldName),
510
- })
511
- }
512
- cms.dispatch({
513
- type: 'sidebar:set-display-state',
514
- value: 'openOrFull',
515
- })
516
- }
373
+ },
374
+ []
375
+ )
376
+ const handleOpenClose = React.useCallback(
377
+ (event: MessageEvent<PostMessage>) => {
517
378
  if (event.data.type === 'close') {
518
379
  const payloadSchema = z.object({ id: z.string() })
519
380
  const { id } = payloadSchema.parse(event.data)
520
381
  setPayloads((previous) =>
521
382
  previous.filter((payload) => payload.id !== id)
522
383
  )
523
- setResults((previous) => previous.filter((result) => result.id !== id))
524
384
  cms.forms.all().map((form) => {
525
385
  form.removeQuery(id)
526
386
  })
@@ -541,7 +401,7 @@ export const useGraphQLReducer = (
541
401
  ])
542
402
  }
543
403
  },
544
- [cms, JSON.stringify(results)]
404
+ [cms]
545
405
  )
546
406
 
547
407
  React.useEffect(() => {
@@ -555,31 +415,23 @@ export const useGraphQLReducer = (
555
415
  React.useEffect(() => {
556
416
  return () => {
557
417
  setPayloads([])
558
- setResults([])
559
418
  cms.removeAllForms()
560
419
  cms.dispatch({ type: 'form-lists:clear' })
561
420
  }
562
421
  }, [url])
563
422
 
564
423
  React.useEffect(() => {
565
- iframe.current?.contentWindow?.postMessage({
566
- type: 'quickEditEnabled',
567
- value: cms.state.quickEditEnabled,
568
- })
569
- }, [cms.state.quickEditEnabled])
570
-
571
- React.useEffect(() => {
572
- cms.dispatch({ type: 'set-edit-mode', value: 'visual' })
573
424
  if (iframe) {
574
- window.addEventListener('message', handleMessage)
425
+ window.addEventListener('message', handleOpenClose)
426
+ window.addEventListener('message', notifyEditMode)
575
427
  }
576
428
 
577
429
  return () => {
578
- window.removeEventListener('message', handleMessage)
430
+ window.removeEventListener('message', handleOpenClose)
431
+ window.removeEventListener('message', notifyEditMode)
579
432
  cms.removeAllForms()
580
- cms.dispatch({ type: 'set-edit-mode', value: 'basic' })
581
433
  }
582
- }, [iframe.current, JSON.stringify(results)])
434
+ }, [iframe.current])
583
435
  }
584
436
 
585
437
  const onSubmit = async (
@@ -617,8 +469,7 @@ type Path = (string | number)[]
617
469
  const resolveDocument = (
618
470
  doc: ResolvedDocument,
619
471
  template: Template<true>,
620
- form: Form,
621
- pathToDocument: string
472
+ form: Form
622
473
  ): ResolvedDocument => {
623
474
  // @ts-ignore AnyField and TinaField don't mix
624
475
  const fields = form.fields as TinaField<true>[]
@@ -629,7 +480,6 @@ const resolveDocument = (
629
480
  values: form.values,
630
481
  path,
631
482
  id,
632
- pathToDocument,
633
483
  })
634
484
  const metadataFields: Record<string, string> = {}
635
485
  Object.keys(formValues).forEach((key) => {
@@ -642,9 +492,7 @@ const resolveDocument = (
642
492
  sys: doc._internalSys,
643
493
  values: form.values,
644
494
  _tina_metadata: {
645
- prefix: pathToDocument,
646
495
  id: doc._internalSys.path,
647
- name: '',
648
496
  fields: metadataFields,
649
497
  },
650
498
  _internalSys: doc._internalSys,
@@ -658,14 +506,12 @@ const resolveFormValue = <T extends Record<string, unknown>>({
658
506
  values,
659
507
  path,
660
508
  id,
661
- pathToDocument,
662
509
  }: // tinaSchema,
663
510
  {
664
511
  fields: TinaField<true>[]
665
512
  values: T
666
513
  path: Path
667
514
  id: string
668
- pathToDocument: string
669
515
  // tinaSchema: TinaSchema
670
516
  }): T & { __typename?: string } => {
671
517
  const accum: Record<string, unknown> = {}
@@ -682,7 +528,6 @@ const resolveFormValue = <T extends Record<string, unknown>>({
682
528
  value: v,
683
529
  path,
684
530
  id,
685
- pathToDocument,
686
531
  })
687
532
  })
688
533
  return accum as T & { __typename?: string }
@@ -692,13 +537,11 @@ const resolveFieldValue = ({
692
537
  value,
693
538
  path,
694
539
  id,
695
- pathToDocument,
696
540
  }: {
697
541
  field: TinaField<true>
698
542
  value: unknown
699
543
  path: Path
700
544
  id: string
701
- pathToDocument: string
702
545
  }) => {
703
546
  switch (field.type) {
704
547
  case 'object': {
@@ -719,16 +562,13 @@ const resolveFieldValue = ({
719
562
  __typename: NAMER.dataTypeName(template.namespace),
720
563
  _tina_metadata: {
721
564
  id,
722
- name: nextPath.join('.'),
723
565
  fields: metadataFields,
724
- prefix: pathToDocument,
725
566
  },
726
567
  ...resolveFormValue({
727
568
  fields: template.fields,
728
569
  values: item,
729
570
  path: nextPath,
730
571
  id,
731
- pathToDocument,
732
572
  }),
733
573
  }
734
574
  })
@@ -757,16 +597,13 @@ const resolveFieldValue = ({
757
597
  __typename: NAMER.dataTypeName(field.namespace),
758
598
  _tina_metadata: {
759
599
  id,
760
- name: nextPath.join('.'),
761
600
  fields: metadataFields,
762
- prefix: pathToDocument,
763
601
  },
764
602
  ...resolveFormValue({
765
603
  fields: templateFields,
766
604
  values: item,
767
- path: nextPath,
605
+ path,
768
606
  id,
769
- pathToDocument,
770
607
  }),
771
608
  }
772
609
  })
@@ -781,16 +618,13 @@ const resolveFieldValue = ({
781
618
  __typename: NAMER.dataTypeName(field.namespace),
782
619
  _tina_metadata: {
783
620
  id,
784
- name: nextPath.join('.'),
785
621
  fields: metadataFields,
786
- prefix: pathToDocument,
787
622
  },
788
623
  ...resolveFormValue({
789
624
  fields: templateFields,
790
625
  values: value as any,
791
- path: nextPath,
626
+ path,
792
627
  id,
793
- pathToDocument,
794
628
  }),
795
629
  }
796
630
  }
@@ -853,7 +687,7 @@ const expandPayload = async (payload: Payload, cms: TinaCMS) => {
853
687
  documentNode,
854
688
  })
855
689
  const expandedQueryForResolver = G.print(expandedDocumentNodeForResolver)
856
- return { ...payload, expandedQuery, expandedData, expandedQueryForResolver }
690
+ return { ...payload, expandQuery, expandedData, expandedQueryForResolver }
857
691
  }
858
692
 
859
693
  /**
package/src/lib/types.ts CHANGED
@@ -1,11 +1,8 @@
1
- export type PostMessage =
2
- | {
3
- type: 'open' | 'close' | 'isEditMode'
4
- id: string
5
- data: object
6
- }
7
- | { type: 'field:selected'; fieldName: string }
8
- | { type: 'quick-edit'; value: boolean }
1
+ export type PostMessage = {
2
+ type: 'open' | 'close' | 'isEditMode'
3
+ id: string
4
+ data: object
5
+ }
9
6
 
10
7
  export type Payload = {
11
8
  id: string
package/src/lib/util.ts DELETED
@@ -1,124 +0,0 @@
1
- const charCodeOfDot = '.'.charCodeAt(0)
2
- const reEscapeChar = /\\(\\)?/g
3
- const rePropName = RegExp(
4
- // Match anything that isn't a dot or bracket.
5
- '[^.[\\]]+' +
6
- '|' +
7
- // Or match property names within brackets.
8
- '\\[(?:' +
9
- // Match a non-string expression.
10
- '([^"\'][^[]*)' +
11
- '|' +
12
- // Or match strings (supports escaping characters).
13
- '(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' +
14
- ')\\]' +
15
- '|' +
16
- // Or match "" as the space between consecutive dots or empty brackets.
17
- '(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))',
18
- 'g'
19
- )
20
-
21
- /**
22
- * Converts `string` to a property path array.
23
- *
24
- * @private
25
- * @param {string} string The string to convert.
26
- * @returns {Array} Returns the property path array.
27
- */
28
- const stringToPath = (string: string) => {
29
- const result = []
30
- if (string.charCodeAt(0) === charCodeOfDot) {
31
- result.push('')
32
- }
33
- string.replace(rePropName, (match, expression, quote, subString) => {
34
- let key = match
35
- if (quote) {
36
- key = subString.replace(reEscapeChar, '$1')
37
- } else if (expression) {
38
- key = expression.trim()
39
- }
40
- result.push(key)
41
- })
42
- return result
43
- }
44
-
45
- const keysCache: { [key: string]: string[] } = {}
46
- const keysRegex = /[.[\]]+/
47
-
48
- const toPath = (key: string): string[] => {
49
- if (key === null || key === undefined || !key.length) {
50
- return []
51
- }
52
- if (typeof key !== 'string') {
53
- throw new Error('toPath() expects a string')
54
- }
55
- if (keysCache[key] == null) {
56
- /**
57
- * The following patch fixes issue 456, introduced since v4.20.3:
58
- *
59
- * Before v4.20.3, i.e. in v4.20.2, a `key` like 'choices[]' would map to ['choices']
60
- * (e.g. an array of choices used where 'choices[]' is name attribute of an input of type checkbox).
61
- *
62
- * Since v4.20.3, a `key` like 'choices[]' would map to ['choices', ''] which is wrong and breaks
63
- * this kind of inputs e.g. in React.
64
- *
65
- * v4.20.3 introduced an unwanted breaking change, this patch fixes it, see the issue at the link below.
66
- *
67
- * @see https://github.com/final-form/final-form/issues/456
68
- */
69
- if (key.endsWith('[]')) {
70
- // v4.20.2 (a `key` like 'choices[]' should map to ['choices'], which is fine).
71
- keysCache[key] = key.split(keysRegex).filter(Boolean)
72
- } else {
73
- // v4.20.3 (a `key` like 'choices[]' maps to ['choices', ''], which breaks applications relying on inputs like `<input type="checkbox" name="choices[]" />`).
74
- keysCache[key] = stringToPath(key)
75
- }
76
- }
77
- return keysCache[key]
78
- }
79
- export const getDeepestMetadata = (state: Object, complexKey: string): any => {
80
- // Intentionally using iteration rather than recursion
81
- const path = toPath(complexKey)
82
- let current: any = state
83
- let metadata: any
84
- for (let i = 0; i < path.length; i++) {
85
- const key = path[i]
86
- if (
87
- current === undefined ||
88
- current === null ||
89
- typeof current !== 'object' ||
90
- (Array.isArray(current) && isNaN(Number(key)))
91
- ) {
92
- return undefined
93
- }
94
- const value = current[key]
95
- if (value?._tina_metadata) {
96
- metadata = value._tina_metadata
97
- }
98
- current = value
99
- }
100
- return metadata
101
- }
102
- export const getFormAndFieldNameFromMetadata = (
103
- object: object,
104
- eventFieldName: string
105
- ) => {
106
- let formId
107
- let n
108
- const value = getDeepestMetadata(object, eventFieldName)
109
- if (value) {
110
- if (value.prefix) {
111
- const fieldName = eventFieldName.slice(value?.prefix?.length + 1)
112
- const localFieldName = value.name
113
- ? fieldName.slice(value?.name?.length + 1)
114
- : fieldName
115
- if (localFieldName) {
116
- n = value.fields[localFieldName]
117
- } else {
118
- n = value.name
119
- }
120
- formId = value.id
121
- }
122
- }
123
- return { formId, fieldName: n }
124
- }