works!
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
||||
import { getClientConfig } from '@payloadcms/ui/utilities/getClientConfig'
|
||||
import { getClientSchemaMap } from '@payloadcms/ui/utilities/getClientSchemaMap'
|
||||
import { getSchemaMap } from '@payloadcms/ui/utilities/getSchemaMap'
|
||||
import {
|
||||
createClientField,
|
||||
@@ -10,7 +12,6 @@ import {
|
||||
|
||||
import {
|
||||
type DefaultTypedEditorState,
|
||||
lexicalEditor,
|
||||
type LexicalFieldAdminProps,
|
||||
type LexicalRichTextAdapter,
|
||||
type SanitizedServerEditorConfig,
|
||||
@@ -19,11 +20,11 @@ import {
|
||||
export type RenderLexicalServerFunctionArgs = {
|
||||
admin?: LexicalFieldAdminProps
|
||||
/**
|
||||
* 'default' or {global|collections}.entitySlug.fieldSchemaPath
|
||||
* {global|collection}.entitySlug.fieldSchemaPath
|
||||
*
|
||||
* @example collections.posts.richText
|
||||
* @example collection.posts.richText
|
||||
*/
|
||||
editorTarget: 'default' | ({} & string)
|
||||
editorTarget: string
|
||||
/**
|
||||
* Pass the value this richtext field will receive when rendering it on the server.
|
||||
* This helps provide initial state for sub-fields that are immediately rendered (like blocks)
|
||||
@@ -41,9 +42,8 @@ export type RenderLexicalServerFunctionArgs = {
|
||||
path?: string
|
||||
/**
|
||||
* Schema path to the field to render.
|
||||
* @default field name
|
||||
*/
|
||||
schemaPath?: string
|
||||
schemaPath: string
|
||||
}
|
||||
export type RenderLexicalServerFunctionReturnType = { Component: React.ReactNode }
|
||||
|
||||
@@ -53,38 +53,31 @@ export type RenderLexicalServerFunctionReturnType = { Component: React.ReactNode
|
||||
export const _internal_renderLexical: ServerFunction<
|
||||
RenderLexicalServerFunctionArgs,
|
||||
Promise<RenderLexicalServerFunctionReturnType>
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
> = async ({ name, admin, editorTarget, importMap, initialValue, path, req, schemaPath }) => {
|
||||
if (!req.user) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
let sanitizedEditor: LexicalRichTextAdapter
|
||||
const [entityType, entitySlug, ...fieldPath] = editorTarget.split('.')
|
||||
|
||||
if (editorTarget === 'default') {
|
||||
sanitizedEditor = await lexicalEditor()({
|
||||
config: req.payload.config,
|
||||
isRoot: false,
|
||||
parentIsLocalized: false,
|
||||
})
|
||||
} else {
|
||||
const [entityType, entitySlug, ...fieldPath] = editorTarget.split('.')
|
||||
const schemaMap = getSchemaMap({
|
||||
collectionSlug: entityType === 'collection' ? entitySlug : undefined,
|
||||
config: req.payload.config,
|
||||
globalSlug: entityType === 'global' ? entitySlug : undefined,
|
||||
i18n: req.i18n,
|
||||
})
|
||||
|
||||
const schemaMap = getSchemaMap({
|
||||
collectionSlug: entityType === 'collections' ? entitySlug : undefined,
|
||||
config: req.payload.config,
|
||||
globalSlug: entityType === 'globals' ? entitySlug : undefined,
|
||||
i18n: req.i18n,
|
||||
})
|
||||
const targetField = schemaMap.get(`${entitySlug}.${fieldPath.join('.')}`) as
|
||||
| RichTextField
|
||||
| undefined
|
||||
|
||||
const field = schemaMap.get(`${entitySlug}.${fieldPath.join('.')}`) as RichTextField | undefined
|
||||
|
||||
if (!field?.editor || typeof field.editor === 'function') {
|
||||
throw new Error(`No editor found for target: ${editorTarget}`)
|
||||
}
|
||||
|
||||
sanitizedEditor = field.editor as LexicalRichTextAdapter
|
||||
if (!targetField?.editor || typeof targetField.editor === 'function') {
|
||||
throw new Error(`No editor found for target: ${editorTarget}`)
|
||||
}
|
||||
|
||||
const sanitizedEditor = targetField.editor as LexicalRichTextAdapter
|
||||
|
||||
if (!sanitizedEditor) {
|
||||
throw new Error(`No editor found for target: ${editorTarget}`)
|
||||
}
|
||||
@@ -95,6 +88,21 @@ export const _internal_renderLexical: ServerFunction<
|
||||
editor: sanitizedEditor,
|
||||
}
|
||||
|
||||
// Provide client schema map as it would have been provided if the target editor field would have been rendered.
|
||||
// Only then will it contain all the lexical-internal entries
|
||||
const clientSchemaMap = getClientSchemaMap({
|
||||
collectionSlug: entityType === 'collection' ? entitySlug : undefined,
|
||||
config: getClientConfig({
|
||||
config: req.payload.config,
|
||||
i18n: req.i18n,
|
||||
importMap: req.payload.importMap,
|
||||
}),
|
||||
globalSlug: entityType === 'global' ? entitySlug : undefined,
|
||||
i18n: req.i18n,
|
||||
payload: req.payload,
|
||||
schemaMap,
|
||||
})
|
||||
|
||||
const FieldComponent = RenderServerComponent({
|
||||
Component: sanitizedEditor.FieldComponent,
|
||||
importMap,
|
||||
@@ -106,11 +114,12 @@ export const _internal_renderLexical: ServerFunction<
|
||||
i18n: req.i18n,
|
||||
importMap,
|
||||
}) as RichTextFieldClient,
|
||||
clientFieldSchemaMap: new Map<string, RichTextFieldClient>(),
|
||||
collectionSlug: '-',
|
||||
clientFieldSchemaMap: clientSchemaMap,
|
||||
// collectionSlug is typed incorrectly - @todo make it accept undefined in 4.0
|
||||
collectionSlug: entityType === 'collection' && entitySlug ? entitySlug : '-',
|
||||
data: {},
|
||||
field,
|
||||
fieldSchemaMap: new Map<string, RichTextField>(),
|
||||
fieldSchemaMap: schemaMap,
|
||||
forceRender: true,
|
||||
formState: {},
|
||||
i18n: req.i18n,
|
||||
|
||||
@@ -18,18 +18,18 @@ import type {
|
||||
* @experimental - may break in minor releases
|
||||
*/
|
||||
export const useRenderEditor_internal_ = (
|
||||
args: Omit<RenderLexicalServerFunctionArgs, 'initialValue'>,
|
||||
args: Omit<RenderLexicalServerFunctionArgs, 'initialValue' | 'schemaPath'>,
|
||||
) => {
|
||||
const { name, admin, editorTarget, path, schemaPath } = args
|
||||
const { name, admin, editorTarget, path } = args
|
||||
const [Component, setComponent] = React.useState<null | React.ReactNode>(null)
|
||||
const serverFunctionContext = useServerFunctions()
|
||||
const { serverFunction } = serverFunctionContext
|
||||
|
||||
const [entityType, entitySlug, ...fieldPath] = editorTarget.split('.')
|
||||
|
||||
const renderLexical = useCallback(
|
||||
(args?: Pick<RenderLexicalServerFunctionArgs, 'initialValue'>) => {
|
||||
async function render() {
|
||||
const [entityType, entitySlug, ...fieldPath] = editorTarget.split('.')
|
||||
|
||||
const { Component } = (await serverFunction({
|
||||
name: 'render-lexical',
|
||||
args: {
|
||||
@@ -46,7 +46,7 @@ export const useRenderEditor_internal_ = (
|
||||
}
|
||||
void render()
|
||||
},
|
||||
[serverFunction, admin, editorTarget, name, path, schemaPath],
|
||||
[serverFunction, name, admin, editorTarget, path, entitySlug, fieldPath],
|
||||
)
|
||||
|
||||
const WrappedComponent = React.useMemo(() => {
|
||||
@@ -66,8 +66,6 @@ export const useRenderEditor_internal_ = (
|
||||
return null
|
||||
}
|
||||
|
||||
const [entityType, entitySlug, ...fieldPath] = editorTarget.split('.')
|
||||
|
||||
/**
|
||||
* By default, the lexical will make form state requests (e.g. to get drawer fields), passing in the arguments
|
||||
* of the current field. However, we need to override those arguments to get it to make requests based on the
|
||||
@@ -76,23 +74,10 @@ export const useRenderEditor_internal_ = (
|
||||
const lexicalServerFunctionContext: ServerFunctionsContextType = {
|
||||
...serverFunctionContext,
|
||||
getFormState: async (getFormStateArgs) => {
|
||||
const currentSchemaPathWithoutEntitySlug = schemaPath ?? name
|
||||
const editorTargetSchemaPath = `${entitySlug}.${fieldPath.join('.')}`
|
||||
|
||||
console.log('getFormStateArgs.schemaPath', getFormStateArgs.schemaPath)
|
||||
|
||||
const correctedSchemaPath = getFormStateArgs.schemaPath.startsWith(
|
||||
currentSchemaPathWithoutEntitySlug,
|
||||
)
|
||||
? editorTargetSchemaPath +
|
||||
getFormStateArgs.schemaPath.slice(currentSchemaPathWithoutEntitySlug.length)
|
||||
: getFormStateArgs.schemaPath
|
||||
|
||||
return serverFunctionContext.getFormState({
|
||||
...getFormStateArgs,
|
||||
collectionSlug: entityType === 'collection' ? entitySlug : undefined,
|
||||
globalSlug: entityType === 'global' ? entitySlug : undefined,
|
||||
//schemaPath: correctedSchemaPath,
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -125,7 +110,7 @@ export const useRenderEditor_internal_ = (
|
||||
}
|
||||
|
||||
return Memoized
|
||||
}, [Component, name, path, serverFunctionContext, editorTarget, schemaPath, name])
|
||||
}, [Component, serverFunctionContext, path, name, entityType, entitySlug])
|
||||
|
||||
return { Component: WrappedComponent, renderLexical }
|
||||
}
|
||||
|
||||
@@ -287,6 +287,8 @@ export { Warning as WarningIcon } from '../../providers/ToastContainer/icons/War
|
||||
export {
|
||||
type RenderDocumentResult,
|
||||
type RenderDocumentServerFunction,
|
||||
ServerFunctionsContext,
|
||||
type ServerFunctionsContextType,
|
||||
ServerFunctionsProvider,
|
||||
useServerFunctions,
|
||||
} from '../../providers/ServerFunctions/index.js'
|
||||
|
||||
@@ -100,7 +100,7 @@ type GetFolderResultsComponentAndDataClient = (
|
||||
} & Omit<GetFolderResultsComponentAndDataArgs, 'req'>,
|
||||
) => ReturnType<typeof getFolderResultsComponentAndDataHandler>
|
||||
|
||||
type ServerFunctionsContextType = {
|
||||
export type ServerFunctionsContextType = {
|
||||
copyDataFromLocale: CopyDataFromLocaleClient
|
||||
getDocumentSlots: GetDocumentSlots
|
||||
getFolderResultsComponentAndData: GetFolderResultsComponentAndDataClient
|
||||
|
||||
@@ -6,10 +6,12 @@ import type { JSONFieldClientComponent } from 'payload'
|
||||
import { buildEditorState, useRenderEditor_internal_ } from '@payloadcms/richtext-lexical/client'
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { lexicalFullyFeaturedSlug } from '../../../lexical/slugs.js'
|
||||
|
||||
export const Component: JSONFieldClientComponent = (args) => {
|
||||
const { Component, renderLexical } = useRenderEditor_internal_({
|
||||
name: 'richText',
|
||||
editorTarget: 'default',
|
||||
editorTarget: `collection.${lexicalFullyFeaturedSlug}.richText`,
|
||||
})
|
||||
const mounted = useRef(false)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { lexicalFullyFeaturedSlug } from '../../slugs.js'
|
||||
export const Component: JSONFieldClientComponent = (args) => {
|
||||
const { Component, renderLexical } = useRenderEditor_internal_({
|
||||
name: 'richText2',
|
||||
editorTarget: `collections.${lexicalFullyFeaturedSlug}.richText`,
|
||||
editorTarget: `collection.${lexicalFullyFeaturedSlug}.richText`,
|
||||
})
|
||||
const mounted = useRef(false)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user