@tinacms/app 0.0.25 → 0.0.27

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.
@@ -50,9 +50,10 @@ const SetPreview = ({ outputFolder }: { outputFolder: string }) => {
50
50
  }
51
51
 
52
52
  export const TinaAdminWrapper = () => {
53
+ const schema = { ...config?.schema, config }
53
54
  return (
54
55
  // @ts-ignore JSX element type 'TinaCMS' does not have any construct or call signatures.ts(2604)
55
- <TinaCMS {...config} client={{ apiUrl: __API_URL__ }}>
56
+ <TinaCMS {...config} schema={schema} client={{ apiUrl: __API_URL__ }}>
56
57
  <SetPreview outputFolder={config.build.outputFolder} />
57
58
  <TinaAdmin preview={Preview} config={config} />
58
59
  </TinaCMS>
@@ -30111,6 +30111,49 @@ function remarkMdx(options = {}) {
30111
30111
  }
30112
30112
  }
30113
30113
 
30114
+ // ../../../node_modules/.pnpm/hast-util-whitespace@2.0.0/node_modules/hast-util-whitespace/index.js
30115
+ function whitespace(thing) {
30116
+ var value = thing && typeof thing === "object" && thing.type === "text" ? thing.value || "" : thing;
30117
+ return typeof value === "string" && value.replace(/[ \t\n\f\r]/g, "") === "";
30118
+ }
30119
+
30120
+ // ../../../node_modules/.pnpm/remark-unwrap-images@3.0.1/node_modules/remark-unwrap-images/index.js
30121
+ var unknown2 = 1;
30122
+ var containsImage = 2;
30123
+ var containsOther = 3;
30124
+ function remarkUnwrapImages() {
30125
+ return (tree) => {
30126
+ visit(tree, "paragraph", (node, index2, parent) => {
30127
+ if (parent && typeof index2 === "number" && applicable(node) === containsImage) {
30128
+ parent.children.splice(index2, 1, ...node.children);
30129
+ return [SKIP, index2];
30130
+ }
30131
+ });
30132
+ };
30133
+ }
30134
+ function applicable(node, inLink) {
30135
+ let image2 = unknown2;
30136
+ let index2 = -1;
30137
+ while (++index2 < node.children.length) {
30138
+ const child = node.children[index2];
30139
+ if (whitespace(child)) {
30140
+ } else if (child.type === "image" || child.type === "imageReference") {
30141
+ image2 = containsImage;
30142
+ } else if (!inLink && (child.type === "link" || child.type === "linkReference")) {
30143
+ const linkResult = applicable(child, true);
30144
+ if (linkResult === containsOther) {
30145
+ return containsOther;
30146
+ }
30147
+ if (linkResult === containsImage) {
30148
+ image2 = containsImage;
30149
+ }
30150
+ } else {
30151
+ return containsOther;
30152
+ }
30153
+ }
30154
+ return image2;
30155
+ }
30156
+
30114
30157
  // ../../../node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_freeGlobal.js
30115
30158
  var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
30116
30159
  var freeGlobal_default = freeGlobal;
@@ -30510,6 +30553,8 @@ var remarkToSlate = (root3, field, imageCallback) => {
30510
30553
  return code2(content4);
30511
30554
  case "paragraph":
30512
30555
  return paragraph2(content4);
30556
+ case "image":
30557
+ return image2(content4);
30513
30558
  case "mdxJsxFlowElement":
30514
30559
  return mdxJsxElement(content4, field, imageCallback);
30515
30560
  case "thematicBreak":
@@ -30816,6 +30861,7 @@ var markdownToAst = (value, field) => {
30816
30861
  if (!tree) {
30817
30862
  throw new Error("Error parsing markdown");
30818
30863
  }
30864
+ remarkUnwrapImages({})(tree);
30819
30865
  return tree;
30820
30866
  } catch (e) {
30821
30867
  throw new RichTextParseError(e, e.position);
@@ -304,8 +304,28 @@ export const formify = async ({
304
304
  const node = G.parse(`
305
305
  query Sample {
306
306
  ...on Document {
307
+ _internalValues: _values
307
308
  _internalSys: _sys {
309
+ breadcrumbs
310
+ basename
311
+ filename
308
312
  path
313
+ extension
314
+ relativePath
315
+ title
316
+ template
317
+ collection {
318
+ name
319
+ slug
320
+ label
321
+ path
322
+ format
323
+ matches
324
+ templates
325
+ fields
326
+ __typename
327
+ }
328
+ __typename
309
329
  }
310
330
  }
311
331
  }`)
@@ -25,7 +25,7 @@ export type FormType = Form<FormValues, FieldType>
25
25
 
26
26
  export type DataType = Record<string, unknown>
27
27
 
28
- type Data = {
28
+ export type Data = {
29
29
  _internalValues: object
30
30
  _internalSys: {
31
31
  breadcrumbs: string[]
@@ -136,10 +136,14 @@ export const documentMachine =
136
136
  services: {
137
137
  initializer: async (context) => {
138
138
  const tina = context.cms.api.tina as Client
139
- const response = await tina.request<{
140
- node: Data
141
- }>(
142
- `query GetNode($id: String!) {
139
+ let node: Data
140
+ if (context.data) {
141
+ node = context.data
142
+ } else {
143
+ const response = await tina.request<{
144
+ node: Data
145
+ }>(
146
+ `query GetNode($id: String!) {
143
147
  node(id: $id) {
144
148
  ...on Document {
145
149
  _internalValues: _values
@@ -168,14 +172,16 @@ export const documentMachine =
168
172
  }
169
173
  }
170
174
  }`,
171
- { variables: { id: context.id } }
172
- )
175
+ { variables: { id: context.id } }
176
+ )
177
+ node = response.node
178
+ }
173
179
  const schema = context.cms.api.tina.schema as TinaSchema
174
180
  if (!schema) {
175
181
  throw new Error(`Schema must be provided`)
176
182
  }
177
183
  const collection = schema.getCollection(
178
- response.node._internalSys.collection.name
184
+ node._internalSys.collection.name
179
185
  )
180
186
  let template: Templateable
181
187
  if (collection.templates) {
@@ -183,19 +189,19 @@ export const documentMachine =
183
189
  if (typeof template === 'string') {
184
190
  throw new Error(`Global templates not supported`)
185
191
  }
186
- return template.name === response.node._internalSys.template
192
+ return template.name === node._internalSys.template
187
193
  }) as Templateable
188
194
  } else {
189
195
  template = collection
190
196
  }
191
197
  if (!template) {
192
198
  throw new Error(
193
- `Unable to find template for node ${response.node._internalSys.path}`
199
+ `Unable to find template for node ${node._internalSys.path}`
194
200
  )
195
201
  }
196
202
  const resolvedForm = resolveForm({
197
203
  collection,
198
- basename: response.node._internalSys.filename,
204
+ basename: node._internalSys.filename,
199
205
  schema,
200
206
  template,
201
207
  })
@@ -211,10 +217,10 @@ export const documentMachine =
211
217
 
212
218
  await context.cms.api.tina.request(mutationString, {
213
219
  variables: {
214
- collection: response.node._internalSys.collection.name,
215
- relativePath: response.node._internalSys.relativePath,
220
+ collection: node._internalSys.collection.name,
221
+ relativePath: node._internalSys.relativePath,
216
222
  params: schema.transformPayload(
217
- response.node._internalSys.collection.name,
223
+ node._internalSys.collection.name,
218
224
  payload
219
225
  ),
220
226
  },
@@ -230,9 +236,8 @@ export const documentMachine =
230
236
  const formConfig = {
231
237
  id: context.id,
232
238
  label:
233
- response.node._internalSys.title ||
234
- response.node._internalSys.collection.label,
235
- initialValues: response.node._internalValues,
239
+ node._internalSys.title || node._internalSys.collection.label,
240
+ initialValues: node._internalValues,
236
241
  fields: resolvedForm.fields,
237
242
  onSubmit,
238
243
  }
@@ -250,7 +255,7 @@ export const documentMachine =
250
255
  true,
251
256
  onSubmit
252
257
  )
253
- return { form, data: response.node }
258
+ return { form, data: node }
254
259
  },
255
260
  },
256
261
  }
@@ -10,12 +10,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
10
  See the License for the specific language governing permissions and
11
11
  limitations under the License.
12
12
  */
13
- import { assign, ContextFrom, createMachine, spawn } from 'xstate'
13
+ import { assign, createMachine, spawn } from 'xstate'
14
14
  import {
15
15
  Form,
16
16
  TinaCMS,
17
17
  NAMER,
18
- Template,
19
18
  TinaFieldEnriched,
20
19
  TinaCollection,
21
20
  TinaSchema,
@@ -24,9 +23,8 @@ import {
24
23
  } from 'tinacms'
25
24
  import * as G from 'graphql'
26
25
  import { formify } from '../formify'
27
- import { documentMachine, FieldType, FormValues } from './document-machine'
26
+ import { Data, documentMachine } from './document-machine'
28
27
  import type { ActorRefFrom } from 'xstate'
29
- import { Blueprint2 } from '../formify'
30
28
 
31
29
  export type DataType = Record<string, unknown>
32
30
  type DocumentInfo = {
@@ -43,18 +41,21 @@ type ContextType = {
43
41
  id: null | string
44
42
  data: null | DataType
45
43
  cms: TinaCMS
46
- selectedDocument: string | null
44
+ documentNode: G.DocumentNode
45
+ variables: object
47
46
  iframe: null | HTMLIFrameElement
47
+ registerSubForms?: boolean
48
48
  formifyCallback: (args: any) => Form
49
49
  documentMap: DocumentMap
50
- blueprints: Blueprint2[]
50
+ documents: Data[]
51
51
  }
52
52
  export const initialContext: Omit<ContextType, 'cms' | 'formifyCallback'> = {
53
53
  id: null,
54
54
  data: null,
55
- selectedDocument: null,
56
- blueprints: [],
55
+ variables: {},
57
56
  documentMap: {},
57
+ documents: [],
58
+ documentNode: { kind: 'Document', definitions: [] },
58
59
  iframe: null,
59
60
  }
60
61
  export const queryMachine =
@@ -68,7 +69,6 @@ export const queryMachine =
68
69
  initializer: {
69
70
  data: {
70
71
  data: DataType
71
- blueprints: Blueprint2[]
72
72
  }
73
73
  }
74
74
  setter: {
@@ -120,6 +120,9 @@ export const queryMachine =
120
120
  }
121
121
  | {
122
122
  type: 'FIELD_CHANGE'
123
+ }
124
+ | {
125
+ type: 'EDIT_MODE'
123
126
  },
124
127
  },
125
128
  id: '(machine)',
@@ -194,9 +197,6 @@ export const queryMachine =
194
197
  REMOVE_QUERY: {
195
198
  target: 'idle',
196
199
  },
197
- SELECT_DOCUMENT: {
198
- actions: 'selectDocument',
199
- },
200
200
  FIELD_CHANGE: {
201
201
  target: 'pending',
202
202
  },
@@ -211,10 +211,6 @@ export const queryMachine =
211
211
  actions: {
212
212
  handleError: (_context, event) => console.error(event.data),
213
213
  handleMissingDocument: assign((context, event) => {
214
- count = count + 1
215
- if (count > 50) {
216
- throw new Error('infinite loop')
217
- }
218
214
  if (event.data instanceof QueryError) {
219
215
  if (context.documentMap[event.data.id]) {
220
216
  // Already exists
@@ -223,6 +219,9 @@ export const queryMachine =
223
219
  if (!event.data.id) {
224
220
  return context
225
221
  }
222
+ const existingData = context.documents.find(
223
+ (doc) => doc._internalSys.path === event.data.id
224
+ )
226
225
  const doc = {
227
226
  ref: spawn(
228
227
  documentMachine.withContext({
@@ -230,7 +229,7 @@ export const queryMachine =
230
229
  cms: context.cms,
231
230
  formifyCallback: context.formifyCallback,
232
231
  form: null,
233
- data: null,
232
+ data: existingData || null,
234
233
  })
235
234
  ),
236
235
  }
@@ -268,12 +267,6 @@ export const queryMachine =
268
267
  ...event.data,
269
268
  }
270
269
  }),
271
- selectDocument: assign((context, event) => {
272
- return {
273
- ...context,
274
- selectedDocument: event.value,
275
- }
276
- }),
277
270
  setIframe: assign((context, event) => {
278
271
  return {
279
272
  ...context,
@@ -296,41 +289,110 @@ export const queryMachine =
296
289
  },
297
290
  services: {
298
291
  setter: async (context) => {
299
- const walk = (obj: unknown, path: string[] = []) => {
300
- const accum: Record<string, unknown> = {}
301
- if (isScalar(obj)) {
302
- return obj
303
- }
304
- Object.entries(obj as object).map(([key, value]) => {
305
- if (Array.isArray(value)) {
306
- accum[key] = value.map((item) => walk(item, [...path, key]))
307
- } else {
308
- const blueprint = context.blueprints.find(
309
- (bp) => bp.path?.join('.') === [...path, key].join('.')
310
- )
311
- if (blueprint) {
312
- accum[key] = setData(value, blueprint, context)
292
+ const tinaSchema = context.cms.api.tina.schema as TinaSchema
293
+ const gqlSchema = context.cms.api.tina.gqlSchema
294
+ const missingForms: { id: string; skipFormRegister: boolean }[] = []
295
+ const newData = await G.graphql({
296
+ schema: gqlSchema,
297
+ source: G.print(context.documentNode),
298
+ rootValue: context.data,
299
+ variableValues: context.variables,
300
+ fieldResolver: (source, args, _context, info) => {
301
+ const fieldName = info.fieldName
302
+ /**
303
+ * Formify adds `_internalSys` and `_internalValues` to the query
304
+ * and a user's query might also include `_values` or `_sys`, but
305
+ * it may not contain all of the info we need, so the actual
306
+ * source of truth for these values is our alias ones, which are
307
+ * also guaranteed to include all of the values another `_sys` query
308
+ * might include
309
+ */
310
+ if (fieldName === '_sys') {
311
+ return source._internalSys
312
+ }
313
+ if (fieldName === '_values') {
314
+ return source._internalValues
315
+ }
316
+ if (isNodeType(info.returnType)) {
317
+ const existingValue = source[fieldName]
318
+ let skipFormRegister = false
319
+ if (!existingValue) {
320
+ return null
321
+ }
322
+ let path: string = ''
323
+ if (typeof existingValue === 'string') {
324
+ // this is a reference value (eg. post.author)
325
+ skipFormRegister = true
326
+ path = existingValue
313
327
  } else {
314
- accum[key] = walk(value, [...path, key])
328
+ path = existingValue._internalSys.path
329
+ }
330
+ if (context.documentMap[path]) {
331
+ const documentMachine = context.documentMap[path].ref
332
+ const documentContext = documentMachine.getSnapshot()?.context
333
+ if (!documentContext) {
334
+ throw new Error(
335
+ `Document not set up properly for id: ${path}`
336
+ )
337
+ }
338
+ const { data, form } = documentContext
339
+ const values = form?.values
340
+ if (!data || !form || !values) {
341
+ throw new Error(
342
+ `Document not set up properly for id: ${path}`
343
+ )
344
+ }
345
+ const collectionName = data._internalSys.collection.name
346
+ const extraValues = documentContext.data
347
+ const formVal = resolveFormValue({
348
+ fields: form.fields,
349
+ values: values,
350
+ tinaSchema,
351
+ })
352
+ const template = tinaSchema.getTemplateForData({
353
+ data: form.values,
354
+ collection: tinaSchema.getCollection(collectionName),
355
+ })
356
+ return {
357
+ ...extraValues,
358
+ ...formVal,
359
+ _sys: data._internalSys,
360
+ id: path,
361
+ __typename: NAMER.dataTypeName(template.namespace),
362
+ }
363
+ } else {
364
+ // TODO: when we support forms in lists, remove this check
365
+ // This checks that we're at least 2 levels deep, meaning top-level
366
+ // queries list page(relativePath: '...') will be registered, but
367
+ // not connection nodes like pageConnection.edges.node
368
+ if (info.path?.prev?.prev) {
369
+ skipFormRegister = true
370
+ }
371
+ missingForms.push({ id: path, skipFormRegister })
372
+ return null
315
373
  }
316
374
  }
317
- })
318
- return accum
375
+ return source[fieldName]
376
+ },
377
+ })
378
+ if (missingForms.length > 0) {
379
+ // Only run this one at a time
380
+ const missingForm = missingForms[0]
381
+ throw new QueryError(
382
+ `Unable to resolve form for initial document`,
383
+ missingForm.id,
384
+ missingForm.skipFormRegister
385
+ )
319
386
  }
320
- const accum = walk(context.data)
321
- return { data: accum }
387
+ return { data: newData.data }
322
388
  },
323
389
  initializer: async (context, event) => {
324
390
  const tina = context.cms.api.tina as Client
325
391
  const schema = await tina.getSchema()
326
392
  const documentNode = G.parse(event.value.query)
327
- const optimizedQuery = await tina.getOptimizedQuery(documentNode)
328
- if (!optimizedQuery) {
329
- throw new Error(`Unable to optimize query`)
330
- }
331
- const { blueprints, formifiedQuery } = await formify({
393
+ const { formifiedQuery } = await formify({
332
394
  schema,
333
- optimizedDocumentNode: optimizedQuery,
395
+ optimizedDocumentNode: documentNode,
334
396
  })
335
397
  const data = (await context.cms.api.tina.request(
336
398
  G.print(formifiedQuery),
@@ -338,17 +400,29 @@ export const queryMachine =
338
400
  variables: event.value.variables,
339
401
  }
340
402
  )) as DataType
403
+ const documents: Data[] = []
404
+ // step through every value in the payload to find the documents
405
+ JSON.stringify(data, (key, value) => {
406
+ if (value?._internalValues) {
407
+ documents.push(value)
408
+ }
409
+ return value
410
+ })
341
411
  return {
342
412
  data,
343
- blueprints,
413
+ documents,
414
+ variables: event.value.variables,
415
+ documentNode: formifiedQuery,
344
416
  id: event.value.id,
345
417
  }
346
418
  },
347
419
  onChangeCallback: (context) => (callback, _onReceive) => {
348
420
  const schema = context.cms.api.tina.schema as TinaSchema
349
421
  Object.values(context.documentMap).forEach((documentMachine) => {
350
- if (documentMachine.skipFormRegister) {
351
- return
422
+ if (!context.registerSubForms) {
423
+ if (documentMachine.skipFormRegister) {
424
+ return
425
+ }
352
426
  }
353
427
  const documentContext = documentMachine.ref.getSnapshot()?.context
354
428
  const collectionName =
@@ -394,242 +468,121 @@ class QueryError extends Error {
394
468
  this.skipFormRegister = skipFormRegister
395
469
  }
396
470
  }
397
- let count = 0
398
-
399
- // https://github.com/oleics/node-is-scalar/blob/master/index.js
400
- const withSymbol = typeof Symbol !== 'undefined'
401
- function isScalar(value: unknown) {
402
- const type = typeof value
403
- if (type === 'string') return true
404
- if (type === 'number') return true
405
- if (type === 'boolean') return true
406
- if (withSymbol === true && type === 'symbol') return true
407
-
408
- if (value == null) return true
409
- if (withSymbol === true && value instanceof Symbol) return true
410
- if (value instanceof String) return true
411
- if (value instanceof Number) return true
412
- if (value instanceof Boolean) return true
413
-
414
- return false
415
- }
416
471
 
417
- const setData = (
418
- data: { [key: string]: unknown },
419
- blueprint: Blueprint2,
420
- context: ContextFrom<typeof queryMachine>
421
- ) => {
422
- if (data?._internalSys) {
423
- const id = data._internalSys?.path
424
- const doc = context.documentMap[id]
425
- const docContext = doc?.ref?.getSnapshot()?.context
426
- const form = docContext?.form
427
- if (!form) {
428
- const skipFormRegiester = (blueprint.path?.length || 0) > 2
429
- throw new QueryError(
430
- `Unable to resolve form for initial document`,
431
- id,
432
- skipFormRegiester
433
- )
472
+ const isNodeType = (type: G.GraphQLOutputType) => {
473
+ const namedType = G.getNamedType(type)
474
+ if (G.isInterfaceType(namedType)) {
475
+ if (namedType.name === 'Node') {
476
+ return true
434
477
  }
435
- const _internalSys = docContext.data?._internalSys
436
- if (!_internalSys) {
437
- throw new Error(`No system information found for document ${id}`)
478
+ }
479
+ if (G.isUnionType(namedType)) {
480
+ const types = namedType.getTypes()
481
+ if (
482
+ types.every((type) => {
483
+ return type.getInterfaces().some((intfc) => intfc.name === 'Node')
484
+ })
485
+ ) {
486
+ return true
487
+ }
488
+ }
489
+ if (G.isObjectType(namedType)) {
490
+ if (namedType.getInterfaces().some((intfc) => intfc.name === 'Node')) {
491
+ return true
438
492
  }
439
-
440
- const fields = form.fields
441
- const result = resolveForm({
442
- id,
443
- fields,
444
- sys: _internalSys,
445
- values: form.values,
446
- fieldsToInclude: blueprint.fields,
447
- context,
448
- })
449
- return { ...docContext.data, ...result }
450
- } else {
451
- // this isn't a node
452
493
  }
453
- return data
454
494
  }
455
495
 
456
- const resolveForm = ({
457
- id,
496
+ const resolveFormValue = <T extends Record<string, unknown>>({
458
497
  fields,
459
- sys,
460
498
  values,
461
- fieldsToInclude,
462
- context,
499
+ tinaSchema,
463
500
  }: {
464
- id: string
465
- fields: FieldType[]
466
- sys: Record<string, unknown>
467
- values: FormValues | undefined
468
- fieldsToInclude: Blueprint2['fields']
469
- context: ContextFrom<typeof queryMachine>
470
- }) => {
501
+ fields: TinaFieldEnriched[]
502
+ values: T
503
+ tinaSchema: TinaSchema
504
+ }): T & { __typename?: string } => {
471
505
  const accum: Record<string, unknown> = {}
472
- if (!values) {
473
- return accum
474
- }
475
-
476
- fieldsToInclude?.forEach((fieldToInclude) => {
477
- const field = fields.find((field) => fieldToInclude.name === field.name)
478
- if (!field) {
479
- if (fieldToInclude.name === 'id') {
480
- accum[fieldToInclude.alias] = id
481
- } else if (fieldToInclude.name === '_sys') {
482
- if (fieldToInclude.alias !== '_internalSys') {
483
- const sysAccum: Record<string, unknown> = {}
484
- // TODO: loop through these and actually use their alias values
485
- fieldToInclude.fields?.forEach((field) => {
486
- sysAccum[field.alias] = sys[field.name]
487
- })
488
- accum[fieldToInclude.alias] = sysAccum
489
- }
490
- } else if (fieldToInclude.name === '__typename') {
491
- // field namespaces are one level deeper than what we need, so grab the first
492
- // one and remove the last string on the namespace
493
- accum[fieldToInclude.alias] = NAMER.dataTypeName(
494
- fields[0].namespace.slice(0, fields[0].namespace.length - 1)
495
- )
496
- } else if (fieldToInclude.name === '_values') {
497
- if (fieldToInclude.alias !== '_internalValues') {
498
- accum[fieldToInclude.alias] = values
499
- }
500
- } else {
501
- }
502
- } else {
503
- const result = resolveField({
504
- id,
505
- field,
506
- sys,
507
- value: values[field.name],
508
- fieldsToInclude: fieldsToInclude.find(({ name }) => name === field.name)
509
- ?.fields,
510
- context,
511
- })
512
- if (result) {
513
- accum[fieldToInclude.alias] = result
514
- }
506
+ fields.forEach((field) => {
507
+ const v = values[field.name]
508
+ if (!v) {
509
+ return
515
510
  }
511
+ accum[field.name] = resolveFieldValue({
512
+ field,
513
+ value: v,
514
+ tinaSchema,
515
+ })
516
516
  })
517
-
518
- return accum
517
+ return accum as T & { __typename?: string }
519
518
  }
520
- const resolveField = ({
521
- id,
519
+ const resolveFieldValue = ({
522
520
  field,
523
- sys,
524
521
  value,
525
- fieldsToInclude,
526
- context,
522
+ tinaSchema,
527
523
  }: {
528
- id: string
529
524
  field: TinaFieldEnriched
530
- sys: Record<string, unknown>
531
525
  value: unknown
532
- fieldsToInclude: Blueprint2['fields']
533
- context: ContextFrom<typeof queryMachine>
526
+ tinaSchema: TinaSchema
534
527
  }) => {
535
528
  switch (field.type) {
536
- case 'reference':
537
- if (!value) {
538
- return
539
- }
540
- if (typeof value === 'string') {
541
- const doc = context.documentMap[value]
542
- const docContext = doc?.ref?.getSnapshot()?.context
543
- const form = docContext?.form
544
- if (!form) {
545
- throw new QueryError(
546
- `Unable to resolve form for document`,
547
- value,
548
- true
549
- )
550
- }
551
- const _internalSys = docContext.data?._internalSys
552
- if (!_internalSys) {
553
- throw new Error(`No system information found for document ${id}`)
554
- }
555
- return resolveForm({
556
- id: value,
557
- fields: form.fields,
558
- sys: _internalSys,
559
- values: form.values,
560
- fieldsToInclude,
561
- context,
562
- })
563
- }
564
- throw new Error(`Unexpected value for type "reference"`)
565
- case 'object':
566
- if (field.fields) {
567
- if (typeof field.fields === 'string') {
568
- throw new Error('Global templates not supported')
569
- }
570
- field.fields
529
+ case 'object': {
530
+ if (field.templates) {
571
531
  if (field.list) {
572
532
  if (Array.isArray(value)) {
573
533
  return value.map((item) => {
574
- if (typeof field.fields === 'string') {
534
+ const template = field.templates[item._template]
535
+ if (typeof template === 'string') {
575
536
  throw new Error('Global templates not supported')
576
537
  }
577
- return resolveForm({
578
- id,
579
- fields: field.fields,
580
- sys,
581
- values: item,
582
- fieldsToInclude,
583
- context,
584
- })
538
+ return {
539
+ __typename: NAMER.dataTypeName(template.namespace),
540
+ ...resolveFormValue({
541
+ fields: template.fields,
542
+ values: item,
543
+ tinaSchema,
544
+ }),
545
+ }
585
546
  })
586
547
  }
587
548
  } else {
588
- return resolveForm({
589
- id,
590
- fields: field.fields,
591
- sys,
592
- values: value,
593
- fieldsToInclude,
594
- context,
595
- })
549
+ // not implemented
596
550
  }
597
551
  }
598
- if (field.templates) {
599
- if (field.list) {
600
- if (!value) {
601
- return
602
- }
603
- if (!Array.isArray(value)) {
604
- return
605
- }
552
+
553
+ const templateFields = field.fields
554
+ if (typeof templateFields === 'string') {
555
+ throw new Error('Global templates not supported')
556
+ }
557
+ if (!templateFields) {
558
+ throw new Error(`Expected to find sub-fields on field ${field.name}`)
559
+ }
560
+ if (field.list) {
561
+ if (Array.isArray(value)) {
606
562
  return value.map((item) => {
607
- let t: Template<true>
608
- Object.entries(field.templates).forEach(([name, template]) => {
609
- if (name === item._template) {
610
- if (typeof template === 'string') {
611
- throw new Error('Global templates not supported')
612
- }
613
- t = template
614
- }
615
- })
616
563
  return {
617
- _template: item._template,
618
- ...resolveForm({
619
- id,
620
- fields: t.fields,
621
- sys,
564
+ __typename: NAMER.dataTypeName(field.namespace),
565
+ ...resolveFormValue({
566
+ fields: templateFields,
622
567
  values: item,
623
- fieldsToInclude,
624
- context,
568
+ tinaSchema,
625
569
  }),
626
570
  }
627
571
  })
628
- } else {
629
- // not supported yet
572
+ }
573
+ } else {
574
+ return {
575
+ __typename: NAMER.dataTypeName(field.namespace),
576
+ ...resolveFormValue({
577
+ fields: templateFields,
578
+ values: value as any,
579
+ tinaSchema,
580
+ }),
630
581
  }
631
582
  }
632
- default:
583
+ }
584
+ default: {
633
585
  return value
586
+ }
634
587
  }
635
588
  }
@@ -13,12 +13,12 @@ limitations under the License.
13
13
  import React from 'react'
14
14
  import { useMachine } from '@xstate/react'
15
15
  import { queryMachine, initialContext } from './lib/machines/query-machine'
16
- import { useCMS, defineStaticConfig } from 'tinacms'
16
+ import { useCMS, defineConfig } from 'tinacms'
17
17
 
18
- type Config = Parameters<typeof defineStaticConfig>[0]
18
+ type Config = Parameters<typeof defineConfig>[0]
19
19
 
20
20
  type PostMessage = {
21
- type: 'open' | 'close'
21
+ type: 'open' | 'close' | 'isEditMode'
22
22
  id: string
23
23
  data: object
24
24
  }
@@ -80,6 +80,8 @@ const QueryMachine = (props: {
80
80
  queryMachine.withContext({
81
81
  ...initialContext,
82
82
  cms,
83
+ // Enable registration of sub forms
84
+ // registerSubForms: true,
83
85
  // @ts-ignore FIXME: add formifyCallback args to Config type
84
86
  formifyCallback: props.formifyCallback,
85
87
  }),
@@ -97,6 +99,13 @@ const QueryMachine = (props: {
97
99
 
98
100
  React.useEffect(() => {
99
101
  if (props.iframeRef.current) {
102
+ window.addEventListener('message', (event: MessageEvent<PostMessage>) => {
103
+ if (event?.data?.type === 'isEditMode') {
104
+ props.iframeRef?.current?.contentWindow?.postMessage({
105
+ type: 'tina:editMode',
106
+ })
107
+ }
108
+ })
100
109
  send({ type: 'IFRAME_MOUNTED', value: props.iframeRef.current })
101
110
  if (props.payload.type === 'open') {
102
111
  send({ type: 'ADD_QUERY', value: props.payload })
package/dist/index.js CHANGED
@@ -326,6 +326,7 @@ var prodHTML = `<!DOCTYPE html>
326
326
 
327
327
  // src/index.ts
328
328
  var server;
329
+ var hasCopiedFiles = false;
329
330
  var viteBuild = async ({
330
331
  rootPath,
331
332
  outputFolder,
@@ -336,7 +337,7 @@ var viteBuild = async ({
336
337
  const local = l;
337
338
  const localBuild = l;
338
339
  const node_env = JSON.stringify(process.env.NODE_ENV);
339
- const generatedPath = import_path2.default.join(rootPath, ".tina/__generated__");
340
+ const generatedPath = import_path2.default.join(rootPath, ".tina", "__generated__");
340
341
  const outputPath = import_path2.default.join(rootPath, publicFolder, outputFolder);
341
342
  const appCopyPath = import_path2.default.join(__dirname, "..", "appFiles");
342
343
  const appRootPath = import_path2.default.join(generatedPath, "app");
@@ -365,6 +366,10 @@ var viteBuild = async ({
365
366
  },
366
367
  logLevel: "silent"
367
368
  };
369
+ if (!hasCopiedFiles) {
370
+ import_fs_extra.default.remove(import_path2.default.join(generatedPath, "prebuild"));
371
+ import_fs_extra.default.remove(import_path2.default.join(generatedPath, "app"));
372
+ }
368
373
  await (0, import_vite.build)(prebuildConfig);
369
374
  const alias = {
370
375
  TINA_IMPORT: configPrebuildPath
@@ -398,26 +403,30 @@ var viteBuild = async ({
398
403
  },
399
404
  logLevel: "silent"
400
405
  };
401
- if (process.env.MONOREPO_DEV) {
402
- console.warn("Using monorepo dev mode, source files will be symlinked");
403
- await import_fs_extra.default.createSymlink(appCopyPath, appRootPath, "dir");
404
- } else {
405
- await import_fs_extra.default.copy(appCopyPath, appRootPath);
406
- }
407
- await execShellCommand(`npm --prefix ${appRootPath} i --legacy-peer-deps --omit=dev --no-package-lock`);
408
- await import_fs_extra.default.outputFile(import_path2.default.join(outputPath, ".gitignore"), `index.html
406
+ if (!hasCopiedFiles) {
407
+ if (process.env.MONOREPO_DEV) {
408
+ console.warn("Using monorepo dev mode, source files will be symlinked");
409
+ await import_fs_extra.default.createSymlink(appCopyPath, appRootPath, "dir");
410
+ } else {
411
+ await import_fs_extra.default.copy(appCopyPath, appRootPath);
412
+ }
413
+ await execShellCommand(`npm --prefix ${appRootPath} i --legacy-peer-deps --omit=dev --no-package-lock`);
414
+ await import_fs_extra.default.outputFile(import_path2.default.join(outputPath, ".gitignore"), `index.html
409
415
  assets/`);
416
+ }
410
417
  if (localBuild) {
411
- const replaceAll = (string, target, value) => {
412
- const regex = new RegExp(target, "g");
413
- return string.valueOf().replace(regex, value);
414
- };
415
- await import_fs_extra.default.outputFile(devHTMLPath, replaceAll(devHTML, "INSERT_OUTPUT_FOLDER_NAME", outputFolder));
416
- if (server) {
417
- await server.close();
418
+ if (!hasCopiedFiles) {
419
+ const replaceAll = (string, target, value) => {
420
+ const regex = new RegExp(target, "g");
421
+ return string.valueOf().replace(regex, value);
422
+ };
423
+ await import_fs_extra.default.outputFile(devHTMLPath, replaceAll(devHTML, "INSERT_OUTPUT_FOLDER_NAME", outputFolder));
424
+ }
425
+ if (!server) {
426
+ server = await (0, import_vite.createServer)(config);
427
+ await server.listen();
418
428
  }
419
- server = await (0, import_vite.createServer)(config);
420
- await server.listen();
429
+ hasCopiedFiles = true;
421
430
  } else {
422
431
  await import_fs_extra.default.outputFile(prodHTMLPath, prodHTML);
423
432
  await (0, import_vite.build)(config);
@@ -270,8 +270,28 @@ var formify = async ({
270
270
  var node = G.parse(`
271
271
  query Sample {
272
272
  ...on Document {
273
+ _internalValues: _values
273
274
  _internalSys: _sys {
275
+ breadcrumbs
276
+ basename
277
+ filename
274
278
  path
279
+ extension
280
+ relativePath
281
+ title
282
+ template
283
+ collection {
284
+ name
285
+ slug
286
+ label
287
+ path
288
+ format
289
+ matches
290
+ templates
291
+ fields
292
+ __typename
293
+ }
294
+ __typename
275
295
  }
276
296
  }
277
297
  }`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinacms/app",
3
- "version": "0.0.25",
3
+ "version": "0.0.27",
4
4
  "main": "dist/index.js",
5
5
  "exports": {
6
6
  ".": {
@@ -37,8 +37,8 @@
37
37
  "@types/react": "17.0.2",
38
38
  "@types/react-dom": "17.0.2",
39
39
  "@tinacms/scripts": "0.51.3",
40
- "tinacms": "0.69.21",
41
- "@tinacms/mdx": "0.61.14",
40
+ "tinacms": "0.70.1",
41
+ "@tinacms/mdx": "0.61.16",
42
42
  "jest": "^27.0.6"
43
43
  },
44
44
  "dependencies": {