feat(plugin-form-builder): Lexical support (#4487)
* chore(plugin-form-builder): upgrade dependencies * chore(plugin-form-builder): update demo * feat(plugin-form-builder): lexical support * chore(plugin-form-builder): add yarn.lock * chore(plugin-form-builder): undo changes to demo * fix(plugin-form-builder): get plugin to build for payload 2.0
This commit is contained in:
@@ -25,16 +25,16 @@
|
||||
"escape-html": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/escape-html": "^1.0.1",
|
||||
"@types/escape-html": "^1.0.4",
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@types/express": "^4.17.9",
|
||||
"@types/react": "18.0.21",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/react": "18.2.15",
|
||||
"copyfiles": "^2.4.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"nodemon": "^2.0.6",
|
||||
"payload": "^1.3.0",
|
||||
"nodemon": "^3.0.2",
|
||||
"payload": "workspace:*",
|
||||
"react": "^18.0.0",
|
||||
"ts-node": "^9.1.1"
|
||||
"ts-node": "10.9.1"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { Email, FormattedEmail, PluginConfig } from '../../../types'
|
||||
|
||||
import { serializeLexical } from '../../../utilities/lexical/serializeLexical'
|
||||
import { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys'
|
||||
import { serialize } from '../../../utilities/serializeRichText'
|
||||
import { serializeSlate } from '../../../utilities/slate/serializeSlate'
|
||||
|
||||
const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
||||
const { data, operation } = beforeChangeData
|
||||
@@ -26,8 +27,8 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
|
||||
const { emails } = form
|
||||
|
||||
if (emails && emails.length) {
|
||||
const formattedEmails: FormattedEmail[] = emails.map(
|
||||
(email: Email): FormattedEmail | null => {
|
||||
const formattedEmails: FormattedEmail[] = await Promise.all(
|
||||
emails.map(async (email: Email): Promise<FormattedEmail | null> => {
|
||||
const {
|
||||
bcc: emailBCC,
|
||||
cc: emailCC,
|
||||
@@ -44,16 +45,22 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
|
||||
const from = replaceDoubleCurlys(emailFrom, submissionData)
|
||||
const replyTo = replaceDoubleCurlys(emailReplyTo || emailFrom, submissionData)
|
||||
|
||||
const isLexical = message && !Array.isArray(message) && 'root' in message
|
||||
|
||||
const serializedMessage = isLexical
|
||||
? await serializeLexical(message, submissionData)
|
||||
: serializeSlate(message, submissionData)
|
||||
|
||||
return {
|
||||
bcc,
|
||||
cc,
|
||||
from,
|
||||
html: `<div>${serialize(message, submissionData)}</div>`,
|
||||
html: `<div>${serializedMessage}</div>`,
|
||||
replyTo,
|
||||
subject: replaceDoubleCurlys(subject, submissionData),
|
||||
to,
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
let emailsToSend = formattedEmails
|
||||
@@ -72,7 +79,9 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
|
||||
return emailPromise
|
||||
} catch (err: unknown) {
|
||||
payload.logger.error({
|
||||
err: `Error while sending email to address: ${to}. Email not sent: ${err}`,
|
||||
err: `Error while sending email to address: ${to}. Email not sent: ${JSON.stringify(
|
||||
err,
|
||||
)}`,
|
||||
})
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -49,8 +49,10 @@ export const DynamicPriceSelector: React.FC<TextFieldType> = (props) => {
|
||||
return <Text {...props} />
|
||||
}
|
||||
|
||||
const localLabels = typeof label === 'object' ? label : { [locale]: label }
|
||||
const labelValue = localLabels[locale] || localLabels['en'] || ''
|
||||
const localeCode = typeof locale === 'object' && 'code' in locale ? locale.code : locale
|
||||
|
||||
const localLabels = typeof label === 'object' ? label : { [localeCode]: label }
|
||||
const labelValue = localLabels[localeCode] || localLabels['en'] || ''
|
||||
|
||||
if (valueType === 'valueOfField' && !isNumberField) {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
|
||||
export const HeadingHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent }) {
|
||||
const childrenText = await convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes: node.children,
|
||||
parent: {
|
||||
...node,
|
||||
parent,
|
||||
},
|
||||
})
|
||||
|
||||
return '<' + node?.tag + '>' + childrenText + '</' + node?.tag + '>'
|
||||
},
|
||||
nodeTypes: ['heading'],
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
|
||||
export const LinebreakHTMLConverter: HTMLConverter<any> = {
|
||||
converter() {
|
||||
return `<br>`
|
||||
},
|
||||
nodeTypes: ['linebreak'],
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
|
||||
export const LinkHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent }) {
|
||||
const childrenText = await convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes: node.children,
|
||||
parent: {
|
||||
...node,
|
||||
parent,
|
||||
},
|
||||
})
|
||||
|
||||
const rel: string = node.fields.newTab ? ' rel="noopener noreferrer"' : ''
|
||||
|
||||
const href: string =
|
||||
node.fields.linkType === 'custom' ? node.fields.url : node.fields.doc?.value?.id
|
||||
|
||||
return `<a href="${href}"${rel}>${childrenText}</a>`
|
||||
},
|
||||
nodeTypes: ['link'],
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
|
||||
export const ListHTMLConverter: HTMLConverter<any> = {
|
||||
converter: async ({ converters, node, parent }) => {
|
||||
const childrenText = await convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes: node.children,
|
||||
parent: {
|
||||
...node,
|
||||
parent,
|
||||
},
|
||||
})
|
||||
|
||||
return `<${node?.tag} class="${node?.listType}">${childrenText}</${node?.tag}>`
|
||||
},
|
||||
nodeTypes: ['list'],
|
||||
}
|
||||
|
||||
export const ListItemHTMLConverter: HTMLConverter<any> = {
|
||||
converter: async ({ converters, node, parent }) => {
|
||||
const childrenText = await convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes: node.children,
|
||||
parent: {
|
||||
...node,
|
||||
parent,
|
||||
},
|
||||
})
|
||||
|
||||
if ('listType' in parent && parent?.listType === 'check') {
|
||||
return `<li aria-checked=${node.checked ? 'true' : 'false'} class="${
|
||||
'list-item-checkbox' + node.checked
|
||||
? 'list-item-checkbox-checked'
|
||||
: 'list-item-checkbox-unchecked'
|
||||
}"
|
||||
role="checkbox"
|
||||
tabIndex=${-1}
|
||||
value=${node?.value}
|
||||
>
|
||||
{serializedChildren}
|
||||
</li>`
|
||||
} else {
|
||||
return `<li value=${node?.value}>${childrenText}</li>`
|
||||
}
|
||||
},
|
||||
nodeTypes: ['listitem'],
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
|
||||
export const ParagraphHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent }) {
|
||||
const childrenText = await convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes: node.children,
|
||||
parent: {
|
||||
...node,
|
||||
parent,
|
||||
},
|
||||
})
|
||||
return `<p>${childrenText}</p>`
|
||||
},
|
||||
nodeTypes: ['paragraph'],
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
|
||||
export const QuoteHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent }) {
|
||||
const childrenText = await convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes: node.children,
|
||||
parent: {
|
||||
...node,
|
||||
parent,
|
||||
},
|
||||
})
|
||||
|
||||
return `<blockquote>${childrenText}</blockquote>`
|
||||
},
|
||||
nodeTypes: ['quote'],
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
|
||||
import { NodeFormat } from '../nodeFormat'
|
||||
|
||||
export const TextHTMLConverter: HTMLConverter<any> = {
|
||||
converter({ node }) {
|
||||
let text = node.text
|
||||
|
||||
if (node.format & NodeFormat.IS_BOLD) {
|
||||
text = `<strong>${text}</strong>`
|
||||
}
|
||||
if (node.format & NodeFormat.IS_ITALIC) {
|
||||
text = `<em>${text}</em>`
|
||||
}
|
||||
if (node.format & NodeFormat.IS_STRIKETHROUGH) {
|
||||
text = `<span style="text-decoration: line-through">${text}</span>`
|
||||
}
|
||||
if (node.format & NodeFormat.IS_UNDERLINE) {
|
||||
text = `<span style="text-decoration: underline">${text}</span>`
|
||||
}
|
||||
if (node.format & NodeFormat.IS_CODE) {
|
||||
text = `<code>${text}</code>`
|
||||
}
|
||||
if (node.format & NodeFormat.IS_SUBSCRIPT) {
|
||||
text = `<sub>${text}</sub>`
|
||||
}
|
||||
if (node.format & NodeFormat.IS_SUPERSCRIPT) {
|
||||
text = `<sup>${text}</sup>`
|
||||
}
|
||||
|
||||
return text
|
||||
},
|
||||
nodeTypes: ['text'],
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { HTMLConverter } from './types'
|
||||
|
||||
import { HeadingHTMLConverter } from './converters/heading'
|
||||
import { LinebreakHTMLConverter } from './converters/linebreak'
|
||||
import { LinkHTMLConverter } from './converters/link'
|
||||
import { ListHTMLConverter, ListItemHTMLConverter } from './converters/list'
|
||||
import { ParagraphHTMLConverter } from './converters/paragraph'
|
||||
import { QuoteHTMLConverter } from './converters/quote'
|
||||
import { TextHTMLConverter } from './converters/text'
|
||||
|
||||
export const defaultHTMLConverters: HTMLConverter[] = [
|
||||
ParagraphHTMLConverter,
|
||||
TextHTMLConverter,
|
||||
LinebreakHTMLConverter,
|
||||
LinkHTMLConverter,
|
||||
HeadingHTMLConverter,
|
||||
QuoteHTMLConverter,
|
||||
ListHTMLConverter,
|
||||
ListItemHTMLConverter,
|
||||
]
|
||||
113
packages/plugin-form-builder/src/utilities/lexical/nodeFormat.ts
Normal file
113
packages/plugin-form-builder/src/utilities/lexical/nodeFormat.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint-disable perfectionist/sort-objects */
|
||||
/* eslint-disable regexp/no-obscure-range */
|
||||
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
|
||||
//This copy-and-pasted from lexical here: https://github.com/facebook/lexical/blob/c2ceee223f46543d12c574e62155e619f9a18a5d/packages/lexical/src/LexicalConstants.ts
|
||||
|
||||
// DOM
|
||||
export const NodeFormat = {
|
||||
DOM_ELEMENT_TYPE: 1,
|
||||
DOM_TEXT_TYPE: 3,
|
||||
// Reconciling
|
||||
NO_DIRTY_NODES: 0,
|
||||
HAS_DIRTY_NODES: 1,
|
||||
FULL_RECONCILE: 2,
|
||||
// Text node modes
|
||||
IS_NORMAL: 0,
|
||||
IS_TOKEN: 1,
|
||||
IS_SEGMENTED: 2,
|
||||
IS_INERT: 3,
|
||||
// Text node formatting
|
||||
IS_BOLD: 1,
|
||||
IS_ITALIC: 1 << 1,
|
||||
IS_STRIKETHROUGH: 1 << 2,
|
||||
IS_UNDERLINE: 1 << 3,
|
||||
IS_CODE: 1 << 4,
|
||||
IS_SUBSCRIPT: 1 << 5,
|
||||
IS_SUPERSCRIPT: 1 << 6,
|
||||
IS_HIGHLIGHT: 1 << 7,
|
||||
// Text node details
|
||||
IS_DIRECTIONLESS: 1,
|
||||
IS_UNMERGEABLE: 1 << 1,
|
||||
// Element node formatting
|
||||
IS_ALIGN_LEFT: 1,
|
||||
IS_ALIGN_CENTER: 2,
|
||||
IS_ALIGN_RIGHT: 3,
|
||||
IS_ALIGN_JUSTIFY: 4,
|
||||
IS_ALIGN_START: 5,
|
||||
IS_ALIGN_END: 6,
|
||||
} as const
|
||||
|
||||
export const IS_ALL_FORMATTING =
|
||||
NodeFormat.IS_BOLD |
|
||||
NodeFormat.IS_ITALIC |
|
||||
NodeFormat.IS_STRIKETHROUGH |
|
||||
NodeFormat.IS_UNDERLINE |
|
||||
NodeFormat.IS_CODE |
|
||||
NodeFormat.IS_SUBSCRIPT |
|
||||
NodeFormat.IS_SUPERSCRIPT |
|
||||
NodeFormat.IS_HIGHLIGHT
|
||||
|
||||
// Reconciliation
|
||||
export const NON_BREAKING_SPACE = '\u00A0'
|
||||
|
||||
export const DOUBLE_LINE_BREAK = '\n\n'
|
||||
|
||||
// For FF, we need to use a non-breaking space, or it gets composition
|
||||
// in a stuck state.
|
||||
|
||||
const RTL = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC'
|
||||
const LTR =
|
||||
'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' +
|
||||
'\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' +
|
||||
'\uFE00-\uFE6F\uFEFD-\uFFFF'
|
||||
|
||||
// eslint-disable-next-line no-misleading-character-class
|
||||
export const RTL_REGEX = new RegExp('^[^' + LTR + ']*[' + RTL + ']')
|
||||
// eslint-disable-next-line no-misleading-character-class
|
||||
export const LTR_REGEX = new RegExp('^[^' + RTL + ']*[' + LTR + ']')
|
||||
|
||||
export const TEXT_TYPE_TO_FORMAT: Record<any | string, number> = {
|
||||
bold: NodeFormat.IS_BOLD,
|
||||
code: NodeFormat.IS_CODE,
|
||||
highlight: NodeFormat.IS_HIGHLIGHT,
|
||||
italic: NodeFormat.IS_ITALIC,
|
||||
strikethrough: NodeFormat.IS_STRIKETHROUGH,
|
||||
subscript: NodeFormat.IS_SUBSCRIPT,
|
||||
superscript: NodeFormat.IS_SUPERSCRIPT,
|
||||
underline: NodeFormat.IS_UNDERLINE,
|
||||
}
|
||||
|
||||
export const DETAIL_TYPE_TO_DETAIL: Record<any | string, number> = {
|
||||
directionless: NodeFormat.IS_DIRECTIONLESS,
|
||||
unmergeable: NodeFormat.IS_UNMERGEABLE,
|
||||
}
|
||||
|
||||
export const ELEMENT_TYPE_TO_FORMAT: Record<Exclude<any, ''>, number> = {
|
||||
center: NodeFormat.IS_ALIGN_CENTER,
|
||||
end: NodeFormat.IS_ALIGN_END,
|
||||
justify: NodeFormat.IS_ALIGN_JUSTIFY,
|
||||
left: NodeFormat.IS_ALIGN_LEFT,
|
||||
right: NodeFormat.IS_ALIGN_RIGHT,
|
||||
start: NodeFormat.IS_ALIGN_START,
|
||||
}
|
||||
|
||||
export const ELEMENT_FORMAT_TO_TYPE: Record<number, any> = {
|
||||
[NodeFormat.IS_ALIGN_CENTER]: 'center',
|
||||
[NodeFormat.IS_ALIGN_END]: 'end',
|
||||
[NodeFormat.IS_ALIGN_JUSTIFY]: 'justify',
|
||||
[NodeFormat.IS_ALIGN_LEFT]: 'left',
|
||||
[NodeFormat.IS_ALIGN_RIGHT]: 'right',
|
||||
[NodeFormat.IS_ALIGN_START]: 'start',
|
||||
}
|
||||
|
||||
export const TEXT_MODE_TO_TYPE: Record<any, 0 | 1 | 2> = {
|
||||
normal: NodeFormat.IS_NORMAL,
|
||||
segmented: NodeFormat.IS_SEGMENTED,
|
||||
token: NodeFormat.IS_TOKEN,
|
||||
}
|
||||
|
||||
export const TEXT_TYPE_TO_MODE: Record<number, any> = {
|
||||
[NodeFormat.IS_NORMAL]: 'normal',
|
||||
[NodeFormat.IS_SEGMENTED]: 'segmented',
|
||||
[NodeFormat.IS_TOKEN]: 'token',
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { HTMLConverter, SerializedLexicalNodeWithParent } from './types'
|
||||
|
||||
import { defaultHTMLConverters } from './defaultConverters'
|
||||
|
||||
export async function serializeLexical(data?: any, submissionData?: any): Promise<string> {
|
||||
const converters: HTMLConverter[] = defaultHTMLConverters
|
||||
|
||||
if (data?.root?.children?.length) {
|
||||
return await convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes: data?.root?.children,
|
||||
parent: data?.root,
|
||||
})
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
export async function convertLexicalNodesToHTML({
|
||||
converters,
|
||||
lexicalNodes,
|
||||
parent,
|
||||
}: {
|
||||
converters: HTMLConverter[]
|
||||
lexicalNodes: any[]
|
||||
parent: SerializedLexicalNodeWithParent
|
||||
}): Promise<string> {
|
||||
const unknownConverter = converters.find((converter) => converter.nodeTypes.includes('unknown'))
|
||||
|
||||
const htmlArray = await Promise.all(
|
||||
lexicalNodes.map(async (node, i) => {
|
||||
const converterForNode = converters.find((converter) =>
|
||||
converter.nodeTypes.includes(node.type),
|
||||
)
|
||||
if (!converterForNode) {
|
||||
if (unknownConverter) {
|
||||
return unknownConverter.converter({ childIndex: i, converters, node, parent })
|
||||
}
|
||||
return '<span>unknown node</span>'
|
||||
}
|
||||
return converterForNode.converter({
|
||||
childIndex: i,
|
||||
converters,
|
||||
node,
|
||||
parent,
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
return htmlArray.join('') || ''
|
||||
}
|
||||
18
packages/plugin-form-builder/src/utilities/lexical/types.ts
Normal file
18
packages/plugin-form-builder/src/utilities/lexical/types.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export type HTMLConverter<T = any> = {
|
||||
converter: ({
|
||||
childIndex,
|
||||
converters,
|
||||
node,
|
||||
parent,
|
||||
}: {
|
||||
childIndex: number
|
||||
converters: HTMLConverter[]
|
||||
node: T
|
||||
parent: SerializedLexicalNodeWithParent
|
||||
}) => Promise<string> | string
|
||||
nodeTypes: string[]
|
||||
}
|
||||
|
||||
export type SerializedLexicalNodeWithParent = any & {
|
||||
parent?: any
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import escapeHTML from 'escape-html'
|
||||
|
||||
import { replaceDoubleCurlys } from './replaceDoubleCurlys'
|
||||
import { replaceDoubleCurlys } from '../replaceDoubleCurlys'
|
||||
|
||||
interface Node {
|
||||
bold?: boolean
|
||||
@@ -16,7 +16,7 @@ const isTextNode = (node: Node): node is Node & { text: string } => {
|
||||
return 'text' in node
|
||||
}
|
||||
|
||||
export const serialize = (children?: Node[], submissionData?: any): string | undefined =>
|
||||
export const serializeSlate = (children?: Node[], submissionData?: any): string | undefined =>
|
||||
children
|
||||
?.map((node: Node) => {
|
||||
if (isTextNode(node)) {
|
||||
@@ -57,56 +57,80 @@ export const serialize = (children?: Node[], submissionData?: any): string | und
|
||||
case 'h1':
|
||||
return `
|
||||
<h1>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</h1>
|
||||
`
|
||||
case 'h2':
|
||||
return `
|
||||
<h2>
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</h2>
|
||||
`
|
||||
case 'h3':
|
||||
return `
|
||||
<h3>
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</h3>
|
||||
`
|
||||
case 'h4':
|
||||
return `
|
||||
<h4>
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</h4>
|
||||
`
|
||||
case 'h5':
|
||||
return `
|
||||
<h5>
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</h5>
|
||||
`
|
||||
case 'h6':
|
||||
return `
|
||||
<h6>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</h6>
|
||||
`
|
||||
case 'quote':
|
||||
return `
|
||||
<blockquote>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</blockquote>
|
||||
`
|
||||
case 'ul':
|
||||
return `
|
||||
<ul>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</ul>
|
||||
`
|
||||
case 'ol':
|
||||
return `
|
||||
<ol>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</ol>
|
||||
`
|
||||
case 'li':
|
||||
return `
|
||||
<li>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</li>
|
||||
`
|
||||
case 'indent':
|
||||
return `
|
||||
<p style="padding-left: 20px">
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</p>
|
||||
`
|
||||
case 'link':
|
||||
return `
|
||||
<a href={${escapeHTML(node.url)}}>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</a>
|
||||
`
|
||||
|
||||
default:
|
||||
return `
|
||||
<p>
|
||||
${serialize(node.children, submissionData)}
|
||||
${serializeSlate(node.children, submissionData)}
|
||||
</p>
|
||||
`
|
||||
}
|
||||
85
pnpm-lock.yaml
generated
85
pnpm-lock.yaml
generated
@@ -1151,14 +1151,14 @@ importers:
|
||||
specifier: workspace:*
|
||||
version: link:../eslint-config-payload
|
||||
'@types/escape-html':
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.3
|
||||
specifier: ^1.0.4
|
||||
version: 1.0.4
|
||||
'@types/express':
|
||||
specifier: ^4.17.9
|
||||
version: 4.17.17
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
'@types/react':
|
||||
specifier: 18.0.21
|
||||
version: 18.0.21
|
||||
specifier: 18.2.15
|
||||
version: 18.2.15
|
||||
copyfiles:
|
||||
specifier: ^2.4.1
|
||||
version: 2.4.1
|
||||
@@ -1166,17 +1166,17 @@ importers:
|
||||
specifier: ^7.0.3
|
||||
version: 7.0.3
|
||||
nodemon:
|
||||
specifier: ^2.0.6
|
||||
version: 2.0.22
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
payload:
|
||||
specifier: ^1.3.0
|
||||
version: 1.15.8(@types/react@18.0.21)(typescript@5.2.2)
|
||||
specifier: workspace:*
|
||||
version: link:../payload
|
||||
react:
|
||||
specifier: ^18.0.0
|
||||
version: 18.2.0
|
||||
ts-node:
|
||||
specifier: ^9.1.1
|
||||
version: 9.1.1(typescript@5.2.2)
|
||||
specifier: 10.9.1
|
||||
version: 10.9.1(@swc/core@1.3.76)(@types/node@16.18.58)(typescript@5.2.2)
|
||||
|
||||
packages/plugin-nested-docs:
|
||||
devDependencies:
|
||||
@@ -5754,7 +5754,7 @@ packages:
|
||||
/@types/connect@3.4.36:
|
||||
resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==}
|
||||
dependencies:
|
||||
'@types/node': 16.18.58
|
||||
'@types/node': 20.6.2
|
||||
dev: true
|
||||
|
||||
/@types/conventional-changelog-core@4.2.5:
|
||||
@@ -5810,8 +5810,8 @@ packages:
|
||||
resolution: {integrity: sha512-E9ZPeZwh81/gDPVH4XpvcS4ewH/Ub4XJeM5xYAUP0BexGORIyCRYzSivlGOuGbVc4MH3//+z3h4CbrnMZMeUdA==}
|
||||
dev: true
|
||||
|
||||
/@types/escape-html@1.0.3:
|
||||
resolution: {integrity: sha512-QbNxKa2IX2y/9eGiy4w8rrwk//ERHXA6zwYVRA3+ayA/D3pkz+/bLL4b5uSLA0L0kPuNX1Jbv9HyPzv9T4zbJQ==}
|
||||
/@types/escape-html@1.0.4:
|
||||
resolution: {integrity: sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==}
|
||||
dev: true
|
||||
|
||||
/@types/eslint-scope@3.7.4:
|
||||
@@ -5860,6 +5860,15 @@ packages:
|
||||
'@types/serve-static': 1.15.2
|
||||
dev: true
|
||||
|
||||
/@types/express@4.17.21:
|
||||
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
|
||||
dependencies:
|
||||
'@types/body-parser': 1.19.2
|
||||
'@types/express-serve-static-core': 4.17.35
|
||||
'@types/qs': 6.9.7
|
||||
'@types/serve-static': 1.15.2
|
||||
dev: true
|
||||
|
||||
/@types/extract-text-webpack-plugin@3.0.7:
|
||||
resolution: {integrity: sha512-y1sAp2P5sCfqaUDWS7TSB/xemrHGpw9dsjiLE4lC+7bxDC8024Rzl7EdgDVM6wDpJ26H1tWuHRwxLFz1MD95Uw==}
|
||||
dependencies:
|
||||
@@ -6150,7 +6159,7 @@ packages:
|
||||
/@types/passport-strategy@0.2.35:
|
||||
resolution: {integrity: sha512-o5D19Jy2XPFoX2rKApykY15et3Apgax00RRLf0RUotPDUsYrQa7x4howLYr9El2mlUApHmCMv5CZ1IXqKFQ2+g==}
|
||||
dependencies:
|
||||
'@types/express': 4.17.17
|
||||
'@types/express': 4.17.21
|
||||
'@types/passport': 1.0.12
|
||||
dev: true
|
||||
|
||||
@@ -6294,7 +6303,7 @@ packages:
|
||||
resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==}
|
||||
dependencies:
|
||||
'@types/mime': 1.3.2
|
||||
'@types/node': 16.18.58
|
||||
'@types/node': 20.6.2
|
||||
dev: true
|
||||
|
||||
/@types/serve-static@1.15.2:
|
||||
@@ -6302,7 +6311,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/http-errors': 2.0.2
|
||||
'@types/mime': 2.0.3
|
||||
'@types/node': 16.18.58
|
||||
'@types/node': 20.6.2
|
||||
dev: true
|
||||
|
||||
/@types/sharp@0.31.1:
|
||||
@@ -10803,7 +10812,7 @@ packages:
|
||||
/gopd@1.0.1:
|
||||
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.1
|
||||
get-intrinsic: 1.2.2
|
||||
|
||||
/got@11.8.6:
|
||||
resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==}
|
||||
@@ -10988,7 +10997,7 @@ packages:
|
||||
/has-property-descriptors@1.0.0:
|
||||
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.1
|
||||
get-intrinsic: 1.2.2
|
||||
|
||||
/has-proto@1.0.1:
|
||||
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
|
||||
@@ -16533,8 +16542,8 @@ packages:
|
||||
/side-channel@1.0.4:
|
||||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
get-intrinsic: 1.2.1
|
||||
call-bind: 1.0.5
|
||||
get-intrinsic: 1.2.2
|
||||
object-inspect: 1.12.3
|
||||
|
||||
/sift@16.0.1:
|
||||
@@ -17480,6 +17489,38 @@ packages:
|
||||
yargs-parser: 21.1.1
|
||||
dev: true
|
||||
|
||||
/ts-node@10.9.1(@swc/core@1.3.76)(@types/node@16.18.58)(typescript@5.2.2):
|
||||
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@swc/core': '>=1.2.50'
|
||||
'@swc/wasm': '>=1.2.50'
|
||||
'@types/node': '*'
|
||||
typescript: '>=2.7'
|
||||
peerDependenciesMeta:
|
||||
'@swc/core':
|
||||
optional: true
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@swc/core': 1.3.76
|
||||
'@tsconfig/node10': 1.0.9
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 16.18.58
|
||||
acorn: 8.10.0
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.2
|
||||
make-error: 1.3.6
|
||||
typescript: 5.2.2
|
||||
v8-compile-cache-lib: 3.0.1
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
|
||||
/ts-node@10.9.1(@swc/core@1.3.76)(@types/node@20.5.7)(typescript@5.2.2):
|
||||
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
|
||||
hasBin: true
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
{ "path": "./packages/richtext-lexical" },
|
||||
{ "path": "./packages/payload" },
|
||||
{ "path": "./packages/plugin-nested-docs" },
|
||||
{ "path": "./packages/plugin-form-builder" },
|
||||
{ "path": "./packages/plugin-cloud-storage" },
|
||||
{ "path": "./packages/plugin-cloud" },
|
||||
{ "path": "./packages/live-preview" },
|
||||
{ "path": "./packages/live-preview-react" }
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user