From 4090aebb0e94e776258f0c1c761044a4744a1857 Mon Sep 17 00:00:00 2001
From: Jacob Fletcher
Date: Tue, 5 Dec 2023 00:53:11 -0500
Subject: [PATCH] fix(live-preview): populates rte uploads and relationships
(#4379)
---
packages/live-preview/src/traverseRichText.ts | 16 +-
test/live-preview/collections/Pages.ts | 10 +-
test/live-preview/int.spec.ts | 426 ++++++++++++++++--
.../app/(pages)/[slug]/page.client.tsx | 1 -
.../app/_blocks/Relationships/index.tsx | 10 +-
.../app/_components/RichText/index.tsx | 14 +-
.../_components/RichText/serializeLexical.tsx | 89 ++++
.../{serialize.tsx => serializeSlate.tsx} | 55 ++-
test/live-preview/next-app/payload-types.ts | 48 +-
test/live-preview/payload-types.ts | 25 +-
test/live-preview/seed/home.ts | 60 ++-
11 files changed, 677 insertions(+), 77 deletions(-)
create mode 100644 test/live-preview/next-app/app/_components/RichText/serializeLexical.tsx
rename test/live-preview/next-app/app/_components/RichText/{serialize.tsx => serializeSlate.tsx} (55%)
diff --git a/packages/live-preview/src/traverseRichText.ts b/packages/live-preview/src/traverseRichText.ts
index 0e25047f0c..e73e026d51 100644
--- a/packages/live-preview/src/traverseRichText.ts
+++ b/packages/live-preview/src/traverseRichText.ts
@@ -53,13 +53,20 @@ export const traverseRichText = ({
? Array.isArray(incomingData[key])
? []
: {}
- : incomingData[key]
+ : undefined
}
const isRelationship = key === 'value' && 'relationTo' in incomingData
if (isRelationship) {
- const needsPopulation = !result.value || typeof result.value !== 'object'
+ // or if there are no keys besides id
+ const needsPopulation =
+ !result.value ||
+ typeof result.value !== 'object' ||
+ (typeof result.value === 'object' &&
+ Object.keys(result.value).length === 1 &&
+ 'id' in result.value)
+
const hasChanged =
result &&
typeof result === 'object' &&
@@ -71,7 +78,10 @@ export const traverseRichText = ({
}
populationsByCollection[incomingData.relationTo].push({
- id: incomingData[key],
+ id:
+ incomingData[key] && typeof incomingData[key] === 'object'
+ ? incomingData[key].id
+ : incomingData[key],
accessor: 'value',
ref: result,
})
diff --git a/test/live-preview/collections/Pages.ts b/test/live-preview/collections/Pages.ts
index 5c4eae729b..fe5b483ad5 100644
--- a/test/live-preview/collections/Pages.ts
+++ b/test/live-preview/collections/Pages.ts
@@ -1,5 +1,6 @@
import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types'
+import { lexicalEditor } from '../../../packages/richtext-lexical/src'
import { Archive } from '../blocks/ArchiveBlock'
import { CallToAction } from '../blocks/CallToAction'
import { Content } from '../blocks/Content'
@@ -62,8 +63,15 @@ export const Pages: CollectionConfig = {
label: 'Test',
fields: [
{
- name: 'relationshipInRichText',
+ label: 'Rich Text — Slate',
type: 'richText',
+ name: 'richTextSlate',
+ },
+ {
+ label: 'Rich Text — Lexical',
+ type: 'richText',
+ name: 'richTextLexical',
+ editor: lexicalEditor({}),
},
{
name: 'relationshipAsUpload',
diff --git a/test/live-preview/int.spec.ts b/test/live-preview/int.spec.ts
index 1b3f5b603b..7a47dd9ec3 100644
--- a/test/live-preview/int.spec.ts
+++ b/test/live-preview/int.spec.ts
@@ -154,10 +154,7 @@ describe('Collections - Live Preview', () => {
expect(mergedData._numberOfRequests).toEqual(0)
})
- // TODO: this test is not working in Postgres
- // This is because of how relationships are handled in `mergeData`
- // This test passes in MongoDB, though
- it.skip('— uploads - adds and removes media', async () => {
+ it('— uploads - adds and removes media', async () => {
const initialData: Partial = {
title: 'Test Page',
}
@@ -198,6 +195,166 @@ describe('Collections - Live Preview', () => {
expect(mergedDataWithoutUpload.hero.media).toBeFalsy()
})
+
+ it('— uploads - populates within Slate rich text editor', async () => {
+ const initialData: Partial = {
+ title: 'Test Page',
+ }
+
+ // Add upload
+ const merge1 = await mergeData({
+ depth: 1,
+ fieldSchema: schemaJSON,
+ incomingData: {
+ ...initialData,
+ richTextSlate: [
+ {
+ type: 'upload',
+ relationTo: 'media',
+ value: media.id,
+ },
+ ],
+ },
+ initialData,
+ serverURL,
+ returnNumberOfRequests: true,
+ })
+
+ expect(merge1.richTextSlate).toHaveLength(1)
+ expect(merge1.richTextSlate[0].value).toMatchObject(media)
+ expect(merge1._numberOfRequests).toEqual(1)
+
+ // Remove upload
+ const merge2 = await mergeData({
+ depth: 1,
+ fieldSchema: schemaJSON,
+ incomingData: {
+ ...merge1,
+ richTextSlate: [
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: 'Hello, world!',
+ },
+ ],
+ },
+ ],
+ },
+ initialData,
+ serverURL,
+ returnNumberOfRequests: true,
+ })
+
+ expect(merge2.richTextSlate).toHaveLength(1)
+ expect(merge2.richTextSlate[0].value).toBeFalsy()
+ expect(merge2.richTextSlate[0].type).toEqual('paragraph')
+ expect(merge2._numberOfRequests).toEqual(0)
+ })
+
+ it('— uploads - populates within Lexical rich text editor', async () => {
+ const initialData: Partial = {
+ title: 'Test Page',
+ }
+
+ // Add upload
+ const merge1 = await mergeData({
+ depth: 1,
+ fieldSchema: schemaJSON,
+ incomingData: {
+ ...initialData,
+ richTextLexical: {
+ root: {
+ type: 'root',
+ format: '',
+ indent: 0,
+ version: 1,
+ children: [
+ {
+ children: [
+ {
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Hello, world!',
+ type: 'text',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ type: 'paragraph',
+ version: 1,
+ },
+ {
+ format: '',
+ type: 'upload',
+ relationTo: 'media',
+ version: 1,
+ value: media.id,
+ },
+ ],
+ direction: 'ltr',
+ },
+ },
+ },
+ initialData,
+ serverURL,
+ returnNumberOfRequests: true,
+ })
+
+ expect(merge1.richTextLexical.root.children).toHaveLength(2)
+ expect(merge1.richTextLexical.root.children[1].value).toMatchObject(media)
+ expect(merge1._numberOfRequests).toEqual(1)
+
+ // Remove upload
+ const merge2 = await mergeData({
+ depth: 1,
+ fieldSchema: schemaJSON,
+ incomingData: {
+ ...merge1,
+ richTextLexical: {
+ root: {
+ type: 'root',
+ format: '',
+ indent: 0,
+ version: 1,
+ children: [
+ {
+ children: [
+ {
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Hello, world!',
+ type: 'text',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ type: 'paragraph',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ },
+ },
+ },
+ initialData,
+ serverURL,
+ returnNumberOfRequests: true,
+ })
+
+ expect(merge2.richTextLexical.root.children).toHaveLength(1)
+ expect(merge2.richTextLexical.root.children[0].value).toBeFalsy()
+ expect(merge2.richTextLexical.root.children[0].type).toEqual('paragraph')
+ })
+
it('— relationships - populates monomorphic has one relationships', async () => {
const initialData: Partial = {
title: 'Test Page',
@@ -422,7 +579,7 @@ describe('Collections - Live Preview', () => {
},
],
},
- initialData,
+ initialData: merge1,
serverURL,
returnNumberOfRequests: true,
})
@@ -451,7 +608,130 @@ describe('Collections - Live Preview', () => {
])
})
- it('— relationships - populates within rich text', async () => {
+ it('— relationships - populates within Slate rich text editor', async () => {
+ const initialData: Partial = {
+ title: 'Test Page',
+ }
+
+ // Add a relationship and an upload
+ const merge1 = await mergeData({
+ depth: 1,
+ fieldSchema: schemaJSON,
+ incomingData: {
+ ...initialData,
+ richTextSlate: [
+ {
+ children: [
+ {
+ text: ' ',
+ },
+ ],
+ relationTo: 'posts',
+ type: 'relationship',
+ value: {
+ id: testPost.id,
+ },
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: '',
+ },
+ ],
+ },
+ {
+ children: [
+ {
+ text: '',
+ },
+ ],
+ relationTo: 'media',
+ type: 'upload',
+ value: {
+ id: media.id,
+ },
+ },
+ ],
+ },
+ initialData,
+ serverURL,
+ returnNumberOfRequests: true,
+ })
+
+ expect(merge1._numberOfRequests).toEqual(2)
+ expect(merge1.richTextSlate).toHaveLength(3)
+ expect(merge1.richTextSlate[0].type).toEqual('relationship')
+ expect(merge1.richTextSlate[0].value).toMatchObject(testPost)
+ expect(merge1.richTextSlate[1].type).toEqual('paragraph')
+ expect(merge1.richTextSlate[2].type).toEqual('upload')
+ expect(merge1.richTextSlate[2].value).toMatchObject(media)
+
+ // Add a new node between the relationship and the upload
+ const merge2 = await mergeData({
+ depth: 1,
+ fieldSchema: schemaJSON,
+ incomingData: {
+ ...merge1,
+ richTextSlate: [
+ {
+ children: [
+ {
+ text: ' ',
+ },
+ ],
+ relationTo: 'posts',
+ type: 'relationship',
+ value: {
+ id: testPost.id,
+ },
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: '',
+ },
+ ],
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: '',
+ },
+ ],
+ },
+ {
+ children: [
+ {
+ text: '',
+ },
+ ],
+ relationTo: 'media',
+ type: 'upload',
+ value: {
+ id: media.id,
+ },
+ },
+ ],
+ },
+ initialData: merge1,
+ serverURL,
+ returnNumberOfRequests: true,
+ })
+
+ expect(merge2._numberOfRequests).toEqual(1)
+ expect(merge2.richTextSlate).toHaveLength(4)
+ expect(merge2.richTextSlate[0].type).toEqual('relationship')
+ expect(merge2.richTextSlate[0].value).toMatchObject(testPost)
+ expect(merge2.richTextSlate[1].type).toEqual('paragraph')
+ expect(merge2.richTextSlate[2].type).toEqual('paragraph')
+ expect(merge2.richTextSlate[3].type).toEqual('upload')
+ expect(merge2.richTextSlate[3].value).toMatchObject(media)
+ })
+
+ it('— relationships - populates within Lexical rich text editor', async () => {
const initialData: Partial = {
title: 'Test Page',
}
@@ -462,56 +742,130 @@ describe('Collections - Live Preview', () => {
fieldSchema: schemaJSON,
incomingData: {
...initialData,
- relationshipInRichText: [
- {
- type: 'paragraph',
- text: 'Paragraph 1',
+ richTextLexical: {
+ root: {
+ type: 'root',
+ format: '',
+ indent: 0,
+ version: 1,
+ children: [
+ {
+ format: '',
+ type: 'relationship',
+ version: 1,
+ relationTo: 'posts',
+ value: {
+ id: testPost.id,
+ },
+ },
+ {
+ children: [],
+ direction: null,
+ format: '',
+ indent: 0,
+ type: 'paragraph',
+ version: 1,
+ },
+ {
+ format: '',
+ type: 'upload',
+ version: 1,
+ fields: null,
+ relationTo: 'media',
+ value: {
+ id: media.id,
+ },
+ },
+ ],
+ direction: null,
},
- {
- type: 'reference',
- reference: {
- relationTo: 'posts',
- value: testPost.id,
- },
- },
- ],
+ },
},
initialData,
serverURL,
returnNumberOfRequests: true,
})
- expect(merge1._numberOfRequests).toEqual(1)
- expect(merge1.relationshipInRichText).toHaveLength(2)
- expect(merge1.relationshipInRichText[1].reference.value).toMatchObject(testPost)
+ expect(merge1._numberOfRequests).toEqual(2)
+ expect(merge1.richTextLexical.root.children).toHaveLength(3)
+ expect(merge1.richTextLexical.root.children[0].type).toEqual('relationship')
+ expect(merge1.richTextLexical.root.children[0].value).toMatchObject(testPost)
+ expect(merge1.richTextLexical.root.children[1].type).toEqual('paragraph')
+ expect(merge1.richTextLexical.root.children[2].type).toEqual('upload')
+ expect(merge1.richTextLexical.root.children[2].value).toMatchObject(media)
- // Remove the relationship
+ // Add a node before the populated one
const merge2 = await mergeData({
depth: 1,
fieldSchema: schemaJSON,
incomingData: {
...merge1,
- relationshipInRichText: [
- {
- type: 'paragraph',
- text: 'Paragraph 1',
+ richTextLexical: {
+ root: {
+ type: 'root',
+ format: '',
+ indent: 0,
+ version: 1,
+ children: [
+ {
+ format: '',
+ type: 'relationship',
+ version: 1,
+ relationTo: 'posts',
+ value: {
+ id: testPost.id,
+ },
+ },
+ {
+ children: [],
+ direction: null,
+ format: '',
+ indent: 0,
+ type: 'paragraph',
+ version: 1,
+ },
+ {
+ children: [],
+ direction: null,
+ format: '',
+ indent: 0,
+ type: 'paragraph',
+ version: 1,
+ },
+ {
+ format: '',
+ type: 'upload',
+ version: 1,
+ fields: null,
+ relationTo: 'media',
+ value: {
+ id: media.id,
+ },
+ },
+ ],
+ direction: null,
},
- ],
+ },
},
- initialData,
+ initialData: merge1,
serverURL,
returnNumberOfRequests: true,
})
- expect(merge2._numberOfRequests).toEqual(0)
- expect(merge2.relationshipInRichText).toHaveLength(1)
- expect(merge2.relationshipInRichText[0].type).toEqual('paragraph')
+ expect(merge2._numberOfRequests).toEqual(1)
+ expect(merge2.richTextLexical.root.children).toHaveLength(4)
+ expect(merge2.richTextLexical.root.children[0].type).toEqual('relationship')
+ expect(merge2.richTextLexical.root.children[0].value).toMatchObject(testPost)
+ expect(merge2.richTextLexical.root.children[1].type).toEqual('paragraph')
+ expect(merge2.richTextLexical.root.children[2].type).toEqual('paragraph')
+ expect(merge2.richTextLexical.root.children[3].type).toEqual('upload')
+ expect(merge2.richTextLexical.root.children[3].value).toMatchObject(media)
})
it('— relationships - does not re-populate existing rich text relationships', async () => {
const initialData: Partial = {
title: 'Test Page',
- relationshipInRichText: [
+ richTextSlate: [
{
type: 'paragraph',
text: 'Paragraph 1',
@@ -532,7 +886,7 @@ describe('Collections - Live Preview', () => {
fieldSchema: schemaJSON,
incomingData: {
...initialData,
- relationshipInRichText: [
+ richTextSlate: [
{
type: 'paragraph',
text: 'Paragraph 1 (Updated)',
@@ -552,9 +906,9 @@ describe('Collections - Live Preview', () => {
})
expect(merge1._numberOfRequests).toEqual(0)
- expect(merge1.relationshipInRichText).toHaveLength(2)
- expect(merge1.relationshipInRichText[0].text).toEqual('Paragraph 1 (Updated)')
- expect(merge1.relationshipInRichText[1].reference.value).toMatchObject(testPost)
+ expect(merge1.richTextSlate).toHaveLength(2)
+ expect(merge1.richTextSlate[0].text).toEqual('Paragraph 1 (Updated)')
+ expect(merge1.richTextSlate[1].reference.value).toMatchObject(testPost)
})
it('— relationships - populates within blocks', async () => {
diff --git a/test/live-preview/next-app/app/(pages)/[slug]/page.client.tsx b/test/live-preview/next-app/app/(pages)/[slug]/page.client.tsx
index 7eb0ef707a..3b15594a31 100644
--- a/test/live-preview/next-app/app/(pages)/[slug]/page.client.tsx
+++ b/test/live-preview/next-app/app/(pages)/[slug]/page.client.tsx
@@ -6,7 +6,6 @@ import React from 'react'
import { PAYLOAD_SERVER_URL } from '@/app/_api/serverURL'
import { Hero } from '@/app/_components/Hero'
import { Blocks } from '@/app/_components/Blocks'
-import { RelationshipsBlock } from '@/app/_blocks/Relationships'
export const PageClient: React.FC<{
page: PageType
diff --git a/test/live-preview/next-app/app/_blocks/Relationships/index.tsx b/test/live-preview/next-app/app/_blocks/Relationships/index.tsx
index c85d8a9d9a..4dfea2d806 100644
--- a/test/live-preview/next-app/app/_blocks/Relationships/index.tsx
+++ b/test/live-preview/next-app/app/_blocks/Relationships/index.tsx
@@ -22,9 +22,15 @@ export const RelationshipsBlock: React.FC = (props) =>
This block is for testing purposes only. It renders every possible type of relationship.
- Rich Text:
+ Rich Text — Slate:
- {data?.relationshipInRichText && }
+ {data?.richTextSlate && }
+
+ Rich Text — Lexical:
+
+ {data?.richTextLexical && (
+
+ )}
Upload:
diff --git a/test/live-preview/next-app/app/_components/RichText/index.tsx b/test/live-preview/next-app/app/_components/RichText/index.tsx
index 657d2d8d21..57b462fc78 100644
--- a/test/live-preview/next-app/app/_components/RichText/index.tsx
+++ b/test/live-preview/next-app/app/_components/RichText/index.tsx
@@ -1,17 +1,25 @@
import React from 'react'
-import serialize from './serialize'
+import serializeSlate from './serializeSlate'
+import serializeLexical from './serializeLexical'
import classes from './index.module.scss'
-const RichText: React.FC<{ className?: string; content: any }> = ({ className, content }) => {
+const RichText: React.FC<{
+ className?: string
+ content: any
+ renderUploadFilenameOnly?: boolean
+ serializer?: 'lexical' | 'slate'
+}> = ({ className, content, renderUploadFilenameOnly, serializer = 'slate' }) => {
if (!content) {
return null
}
return (
- {serialize(content)}
+ {serializer === 'slate'
+ ? serializeSlate(content, renderUploadFilenameOnly)
+ : serializeLexical(content, renderUploadFilenameOnly)}
)
}
diff --git a/test/live-preview/next-app/app/_components/RichText/serializeLexical.tsx b/test/live-preview/next-app/app/_components/RichText/serializeLexical.tsx
new file mode 100644
index 0000000000..063a65d43c
--- /dev/null
+++ b/test/live-preview/next-app/app/_components/RichText/serializeLexical.tsx
@@ -0,0 +1,89 @@
+import type { SerializedEditorState } from 'lexical'
+import { CMSLink } from '../Link'
+import { Media } from '../Media'
+
+const serializer = (
+ content?: SerializedEditorState['root']['children'],
+ renderUploadFilenameOnly?: boolean,
+): React.ReactNode | React.ReactNode[] =>
+ content?.map((node, i) => {
+ switch (node.type) {
+ case 'h1':
+ return {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ case 'h2':
+ return {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ case 'h3':
+ return {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ case 'h4':
+ return {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ case 'h5':
+ return {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ case 'h6':
+ return {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ case 'quote':
+ return (
+
+ {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ )
+
+ case 'ul':
+ return {serializeLexical(node?.children, renderUploadFilenameOnly)}
+
+ case 'ol':
+ return {serializeLexical(node.children, renderUploadFilenameOnly)}
+
+ case 'li':
+ return {serializeLexical(node.children, renderUploadFilenameOnly)}
+
+ case 'relationship':
+ return (
+
+ {node.value && typeof node.value === 'object'
+ ? node.value.title || node.value.id
+ : node.value}
+
+ )
+
+ case 'link':
+ return (
+
+ {serializer(node?.children, renderUploadFilenameOnly)}
+
+ )
+
+ case 'upload':
+ if (renderUploadFilenameOnly) {
+ return {node.value.filename}
+ }
+
+ return
+
+ case 'paragraph':
+ return {serializer(node?.children, renderUploadFilenameOnly)}
+
+ case 'text':
+ return {node.text}
+ }
+ })
+
+const serializeLexical = (
+ content?: SerializedEditorState,
+ renderUploadFilenameOnly?: boolean,
+): React.ReactNode | React.ReactNode[] => {
+ return serializer(content?.root?.children, renderUploadFilenameOnly)
+}
+
+export default serializeLexical
diff --git a/test/live-preview/next-app/app/_components/RichText/serialize.tsx b/test/live-preview/next-app/app/_components/RichText/serializeSlate.tsx
similarity index 55%
rename from test/live-preview/next-app/app/_components/RichText/serialize.tsx
rename to test/live-preview/next-app/app/_components/RichText/serializeSlate.tsx
index 571a47a0a1..bc82ea2aa4 100644
--- a/test/live-preview/next-app/app/_components/RichText/serialize.tsx
+++ b/test/live-preview/next-app/app/_components/RichText/serializeSlate.tsx
@@ -1,8 +1,8 @@
import React, { Fragment } from 'react'
import escapeHTML from 'escape-html'
-import Link from 'next/link'
import { Text } from 'slate'
import { CMSLink } from '../Link'
+import { Media } from '../Media'
// eslint-disable-next-line no-use-before-define
type Children = Leaf[]
@@ -15,7 +15,10 @@ type Leaf = {
[key: string]: unknown
}
-const serialize = (children?: Children): React.ReactNode[] =>
+const serializeSlate = (
+ children?: Children,
+ renderUploadFilenameOnly?: boolean,
+): React.ReactNode[] =>
children?.map((node, i) => {
if (Text.isText(node)) {
let text =
@@ -57,25 +60,39 @@ const serialize = (children?: Children): React.ReactNode[] =>
switch (node.type) {
case 'h1':
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
case 'h2':
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
case 'h3':
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
case 'h4':
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
case 'h5':
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
case 'h6':
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
case 'quote':
- return {serialize(node?.children)}
+ return (
+
+ {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
+ )
+
case 'ul':
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
+
case 'ol':
- return {serialize(node.children)}
+ return {serializeSlate(node.children, renderUploadFilenameOnly)}
+
case 'li':
- return {serialize(node.children)}
+ return {serializeSlate(node.children, renderUploadFilenameOnly)}
+
case 'relationship':
return (
@@ -84,6 +101,7 @@ const serialize = (children?: Children): React.ReactNode[] =>
: node.value}
)
+
case 'link':
return (
reference={node.doc as any}
newTab={Boolean(node?.newTab)}
>
- {serialize(node?.children)}
+ {serializeSlate(node?.children, renderUploadFilenameOnly)}
)
+ case 'upload':
+ if (renderUploadFilenameOnly) {
+ return {node.value.filename}
+ }
+
+ return
+
default:
- return {serialize(node?.children)}
+ return {serializeSlate(node?.children, renderUploadFilenameOnly)}
}
}) || []
-export default serialize
+export default serializeSlate
diff --git a/test/live-preview/next-app/payload-types.ts b/test/live-preview/next-app/payload-types.ts
index 14c54a5b6a..e9f4006b35 100644
--- a/test/live-preview/next-app/payload-types.ts
+++ b/test/live-preview/next-app/payload-types.ts
@@ -11,6 +11,7 @@ export interface Config {
users: User
pages: Page
posts: Post
+ tenants: Tenant
categories: Category
media: Media
'payload-preferences': PayloadPreference
@@ -37,6 +38,7 @@ export interface User {
export interface Page {
id: string
slug: string
+ tenant?: (string | null) | Tenant
title: string
hero: {
type: 'none' | 'highImpact' | 'lowImpact'
@@ -152,16 +154,6 @@ export interface Page {
}
)[]
| null
- meta?: {
- title?: string | null
- description?: string | null
- image?: string | Media | null
- }
- relationshipInRichText?:
- | {
- [k: string]: unknown
- }[]
- | null
relationshipAsUpload?: string | Media | null
relationshipMonoHasOne?: (string | null) | Post
relationshipMonoHasMany?: (string | Post)[] | null
@@ -198,6 +190,41 @@ export interface Page {
id?: string | null
}[]
| null
+ richTextSlate?:
+ | {
+ [k: string]: unknown
+ }[]
+ | null
+ richTextLexical?: {
+ root: {
+ children: {
+ type: string
+ version: number
+ [k: string]: unknown
+ }[]
+ direction: ('ltr' | 'rtl') | null
+ format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
+ indent: number
+ type: string
+ version: number
+ }
+ [k: string]: unknown
+ } | null
+ tab: {
+ relationshipInTab?: (string | null) | Post
+ }
+ meta?: {
+ title?: string | null
+ description?: string | null
+ image?: string | Media | null
+ }
+ updatedAt: string
+ createdAt: string
+}
+export interface Tenant {
+ id: string
+ title: string
+ clientURL: string
updatedAt: string
createdAt: string
}
@@ -221,6 +248,7 @@ export interface Media {
export interface Post {
id: string
slug: string
+ tenant?: (string | null) | Tenant
title: string
hero: {
type: 'none' | 'highImpact' | 'lowImpact'
diff --git a/test/live-preview/payload-types.ts b/test/live-preview/payload-types.ts
index 7e61f60d31..e9f4006b35 100644
--- a/test/live-preview/payload-types.ts
+++ b/test/live-preview/payload-types.ts
@@ -154,11 +154,6 @@ export interface Page {
}
)[]
| null
- relationshipInRichText?:
- | {
- [k: string]: unknown
- }[]
- | null
relationshipAsUpload?: string | Media | null
relationshipMonoHasOne?: (string | null) | Post
relationshipMonoHasMany?: (string | Post)[] | null
@@ -195,6 +190,26 @@ export interface Page {
id?: string | null
}[]
| null
+ richTextSlate?:
+ | {
+ [k: string]: unknown
+ }[]
+ | null
+ richTextLexical?: {
+ root: {
+ children: {
+ type: string
+ version: number
+ [k: string]: unknown
+ }[]
+ direction: ('ltr' | 'rtl') | null
+ format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''
+ indent: number
+ type: string
+ version: number
+ }
+ [k: string]: unknown
+ } | null
tab: {
relationshipInTab?: (string | null) | Post
}
diff --git a/test/live-preview/seed/home.ts b/test/live-preview/seed/home.ts
index 1ad5eb8fbd..a5f7e298fa 100644
--- a/test/live-preview/seed/home.ts
+++ b/test/live-preview/seed/home.ts
@@ -95,7 +95,7 @@ export const home: Omit = {
},
],
relationshipAsUpload: '{{MEDIA_ID}}',
- relationshipInRichText: [
+ richTextSlate: [
{
children: [
{
@@ -108,7 +108,65 @@ export const home: Omit = {
id: '{{POST_1_ID}}',
},
},
+ {
+ type: 'paragraph',
+ children: [
+ {
+ text: '',
+ },
+ ],
+ },
+ {
+ children: [
+ {
+ text: '',
+ },
+ ],
+ relationTo: 'media',
+ type: 'upload',
+ value: {
+ id: '{{MEDIA_ID}}',
+ },
+ },
],
+ richTextLexical: {
+ root: {
+ type: 'root',
+ format: '',
+ indent: 0,
+ version: 1,
+ children: [
+ {
+ format: '',
+ type: 'relationship',
+ version: 1,
+ relationTo: 'posts',
+ value: {
+ id: '{{POST_1_ID}}',
+ },
+ },
+ {
+ children: [],
+ direction: null,
+ format: '',
+ indent: 0,
+ type: 'paragraph',
+ version: 1,
+ },
+ {
+ format: '',
+ type: 'upload',
+ version: 1,
+ fields: null,
+ relationTo: 'media',
+ value: {
+ id: '{{MEDIA_ID}}',
+ },
+ },
+ ],
+ direction: null,
+ },
+ },
relationshipMonoHasMany: ['{{POST_1_ID}}'],
relationshipMonoHasOne: '{{POST_1_ID}}',
relationshipPolyHasMany: [{ relationTo: 'posts', value: '{{POST_1_ID}}' }],