Compare commits

..

1 Commits

Author SHA1 Message Date
Elliot DeNolf
798515a0a8 chore(release): richtext-lexical/0.1.7 2023-10-13 12:48:19 -04:00
55 changed files with 354 additions and 1059 deletions

View File

@@ -129,7 +129,7 @@ To add a _new_ view to the Admin Panel, simply add another key to the `views` ob
}
```
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/master/test/admin/components)._
For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component).
@@ -399,12 +399,12 @@ Your custom view components will be given all the props that a React Router `<Ro
#### Example
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/main/test/admin/components/views). There, you'll find two custom views:
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/master/test/admin/components/views). There, you'll find two custom views:
1. A custom view that uses the `DefaultTemplate`, which is the built-in Payload template that displays the sidebar and "eyebrow nav"
1. A custom view that uses the `MinimalTemplate` - which is just a centered template used for things like logging in or out
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/main/test/admin/config.ts).
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/master/test/admin/config.ts).
### Fields

View File

@@ -20,8 +20,8 @@
"lint-staged": "lint-staged",
"pretest": "pnpm build",
"reinstall": "pnpm clean:unix && pnpm install",
"script:list-packages": "tsx ./scripts/list-packages.ts",
"script:release": "tsx ./scripts/release.ts",
"list:packages": "./scripts/list_published_packages.sh beta",
"script:release:beta": "./scripts/release_beta.sh",
"test": "pnpm test:int && pnpm test:components && pnpm test:e2e",
"test:components": "cross-env jest --config=jest.components.config.js",
"test:e2e": "npx playwright install --with-deps && ts-node -T ./test/runE2E.ts",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "0.1.5",
"version": "0.1.4",
"description": "The officially supported Postgres database adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,5 +1,6 @@
import type { Connect } from 'payload/database'
import { pushSchema } from 'drizzle-kit/utils'
import { eq, sql } from 'drizzle-orm'
import { drizzle } from 'drizzle-orm/node-postgres'
import { numeric, pgTable, timestamp, varchar } from 'drizzle-orm/pg-core'
@@ -39,8 +40,6 @@ export const connect: Connect = async function connect(this: PostgresAdapter, pa
)
return
const { pushSchema } = require('drizzle-kit/utils')
// This will prompt if clarifications are needed for Drizzle to push new schema
const { apply, hasDataLoss, statementsToExecute, warnings } = await pushSchema(
this.schema,

View File

@@ -2,6 +2,7 @@
import type { DrizzleSnapshotJSON } from 'drizzle-kit/utils'
import type { CreateMigration } from 'payload/database'
import { generateDrizzleJson, generateMigration } from 'drizzle-kit/utils'
import fs from 'fs'
import prompts from 'prompts'
@@ -60,8 +61,6 @@ export const createMigration: CreateMigration = async function createMigration(
fs.mkdirSync(dir)
}
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/utils')
const [yyymmdd, hhmmss] = new Date().toISOString().split('T')
const formattedDate = yyymmdd.replace(/\D/g, '')
const formattedTime = hhmmss.split('.')[0].replace(/\D/g, '')

View File

@@ -2,7 +2,9 @@
import type { Payload } from 'payload'
import type { Migration } from 'payload/database'
import { generateDrizzleJson } from 'drizzle-kit/utils'
import { readMigrationFiles } from 'payload/database'
import { DatabaseError } from 'pg'
import prompts from 'prompts'
import type { PostgresAdapter } from './types'
@@ -76,8 +78,6 @@ export async function migrate(this: PostgresAdapter): Promise<void> {
}
async function runMigrationFile(payload: Payload, migration: Migration, batch: number) {
const { generateDrizzleJson } = require('drizzle-kit/utils')
const start = Date.now()
payload.logger.info({ msg: `Migrating: ${migration.name}` })

View File

@@ -6,12 +6,11 @@
// drizzle-kit@utils
import { generateDrizzleJson, generateMigration, pushSchema } from 'drizzle-kit/utils'
import { drizzle } from 'drizzle-orm/node-postgres'
import { Pool } from 'pg'
async function generateUsage() {
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/utils')
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
const schema = await import('./data/users')
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
@@ -26,8 +25,6 @@ async function generateUsage() {
}
async function pushUsage() {
const { pushSchema } = require('drizzle-kit/utils')
// @ts-expect-error Just TypeScript being broken // TODO: Open TypeScript issue
const schemaAfter = await import('./data/users-after')

View File

@@ -208,7 +208,8 @@
"webpack": "^5.78.0"
},
"engines": {
"node": ">=14"
"node": ">=14",
"pnpm": ">=8"
},
"files": [
"bin.js",

View File

@@ -52,7 +52,7 @@
position: sticky;
top: var(--doc-controls-height);
width: 33.33%;
height: calc(100vh - var(--doc-controls-height));
height: 100%;
}
&__sidebar {

View File

@@ -56,7 +56,7 @@
position: sticky;
top: var(--doc-controls-height);
width: 33.33%;
height: calc(100vh - var(--doc-controls-height));
height: 100%;
}
&__sidebar {

View File

@@ -382,7 +382,7 @@ export const relationship: Validate<unknown, unknown, RelationshipField> = async
})
if (invalidRelationships.length > 0) {
return `This relationship field has the following invalid relationships: ${invalidRelationships
return `This field has the following invalid selections: ${invalidRelationships
.map((err, invalid) => {
return `${err} ${JSON.stringify(invalid)}`
})

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "0.1.8",
"version": "0.1.7",
"description": "The officially supported Lexical richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -16,38 +16,17 @@ export const RichTextCell: React.FC<
const [preview, setPreview] = React.useState('Loading...')
useEffect(() => {
let dataToUse = data
if (dataToUse == null) {
if (data == null) {
setPreview('')
return
}
// Transform data through load hooks
if (editorConfig?.features?.hooks?.load?.length) {
editorConfig.features.hooks.load.forEach((hook) => {
dataToUse = hook({ incomingEditorState: dataToUse })
})
}
// If data is from Slate and not Lexical
if (dataToUse && Array.isArray(dataToUse) && !('root' in dataToUse)) {
setPreview('')
return
}
// If data is from payload-plugin-lexical
if (dataToUse && 'jsonContent' in dataToUse) {
setPreview('')
return
}
// initialize headless editor
const headlessEditor = createHeadlessEditor({
namespace: editorConfig.lexical.namespace,
nodes: getEnabledNodes({ editorConfig }),
theme: editorConfig.lexical.theme,
})
headlessEditor.setEditorState(headlessEditor.parseEditorState(dataToUse))
headlessEditor.setEditorState(headlessEditor.parseEditorState(data))
const textContent =
headlessEditor.getEditorState().read(() => {

View File

@@ -89,16 +89,9 @@ const RichText: React.FC<FieldProps> = (props) => {
fieldProps={props}
initialState={initialValue}
onChange={(editorState, editor, tags) => {
let serializedEditorState = editorState.toJSON()
const json = editorState.toJSON()
// Transform state through save hooks
if (editorConfig?.features?.hooks?.save?.length) {
editorConfig.features.hooks.save.forEach((hook) => {
serializedEditorState = hook({ incomingEditorState: serializedEditorState })
})
}
setValue(serializedEditorState)
setValue(json)
}}
readOnly={readOnly}
setValue={setValue}

View File

@@ -1,5 +1,3 @@
import type { Block } from 'payload/types'
import { sanitizeFields } from 'payload/config'
import type { BlocksFeatureProps } from '.'
@@ -22,42 +20,40 @@ export const blockAfterReadPromiseHOC = (
showHiddenFields,
siblingDoc,
}) => {
const blocks: Block[] = props.blocks
const blockFieldData = node.fields.data
const promises: Promise<void>[] = []
// Sanitize block's fields here. This is done here and not in the feature, because the payload config is available here
const payloadConfig = req.payload.config
const validRelationships = payloadConfig.collections.map((c) => c.slug) || []
blocks.forEach((block) => {
block.fields = sanitizeFields({
props.blocks = props.blocks.map((block) => {
const unsanitizedBlock = { ...block }
unsanitizedBlock.fields = sanitizeFields({
config: payloadConfig,
fields: block.fields,
validRelationships,
})
return unsanitizedBlock
})
// find block used in this node
const block = props.blocks.find((block) => block.slug === blockFieldData.blockType)
if (!block || !block?.fields?.length || !blockFieldData) {
return promises
if (Array.isArray(props.blocks)) {
props.blocks.forEach((block) => {
if (block?.fields) {
recurseNestedFields({
afterReadPromises,
currentDepth,
data: node.fields.data || {},
depth,
fields: block.fields,
overrideAccess,
promises,
req,
showHiddenFields,
siblingDoc,
})
}
})
}
recurseNestedFields({
afterReadPromises,
currentDepth,
data: blockFieldData,
depth,
fields: block.fields,
overrideAccess,
promises,
req,
showHiddenFields,
// The afterReadPromise gets its data from looking for field.name inside of the siblingDoc. Thus, here we cannot pass the whole document's siblingDoc, but only the siblingDoc (sibling fields) of the current field.
siblingDoc: blockFieldData,
})
return promises
}

View File

@@ -15,12 +15,12 @@ export const blockValidationHOC = (
payloadConfig,
validation,
}) => {
const blockFieldData = node.fields.data
const blocks: Block[] = props.blocks
const blockFieldValues = node.fields.data
const blocks: Block[] = props.blocks
// Sanitize block's fields here. This is done here and not in the feature, because the payload config is available here
const validRelationships = payloadConfig.collections.map((c) => c.slug) || []
blocks.forEach((block) => {
const validRelationships = payloadConfig.collections.map((c) => c.slug) || []
block.fields = sanitizeFields({
config: payloadConfig,
fields: block.fields,
@@ -29,7 +29,7 @@ export const blockValidationHOC = (
})
// find block
const block = props.blocks.find((block) => block.slug === blockFieldData.blockType)
const block = props.blocks.find((block) => block.slug === blockFieldValues.blockType)
// validate block
if (!block) {

View File

@@ -52,7 +52,7 @@ export const linkAfterReadPromiseHOC = (
promises,
req,
showHiddenFields,
siblingDoc: node.fields || {},
siblingDoc,
})
}
return promises

View File

@@ -51,7 +51,7 @@ export const uploadAfterReadPromiseHOC = (
promises,
req,
showHiddenFields,
siblingDoc: node.fields || {},
siblingDoc,
})
}
}

View File

@@ -1,25 +0,0 @@
import type { SerializedHeadingNode } from '@lexical/rich-text'
import type { SlateNodeConverter } from '../types'
import { convertSlateNodesToLexical } from '..'
export const HeadingConverter: SlateNodeConverter = {
converter({ converters, slateNode }) {
return {
children: convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'heading',
slateNodes: slateNode.children || [],
}),
direction: 'ltr',
format: '',
indent: 0,
tag: slateNode.type as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6', // Slate puts the tag (h1 / h2 / ...) inside of node.type
type: 'heading',
version: 1,
} as const as SerializedHeadingNode
},
nodeTypes: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
}

View File

@@ -1,65 +0,0 @@
import type { SerializedLexicalNode, SerializedParagraphNode } from 'lexical'
import type { SlateNodeConverter } from '../types'
import { convertSlateNodesToLexical } from '..'
export const IndentConverter: SlateNodeConverter = {
converter({ converters, slateNode }) {
console.log('slateToLexical > IndentConverter > converter', JSON.stringify(slateNode, null, 2))
const convertChildren = (node: any, indentLevel: number = 0): SerializedLexicalNode => {
if (
(node?.type && (!node.children || node.type !== 'indent')) ||
(!node?.type && node?.text)
) {
console.log(
'slateToLexical > IndentConverter > convertChildren > node',
JSON.stringify(node, null, 2),
)
console.log(
'slateToLexical > IndentConverter > convertChildren > nodeOutput',
JSON.stringify(
convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'indent',
slateNodes: [node],
}),
null,
2,
),
)
return {
...convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'indent',
slateNodes: [node],
})[0],
indent: indentLevel,
} as const as SerializedLexicalNode
}
const children = node.children.map((child: any) => convertChildren(child, indentLevel + 1))
console.log('slateToLexical > IndentConverter > children', JSON.stringify(children, null, 2))
return {
children: children,
direction: 'ltr',
format: '',
indent: indentLevel,
type: 'paragraph',
version: 1,
} as const as SerializedParagraphNode
}
console.log(
'slateToLexical > IndentConverter > output',
JSON.stringify(convertChildren(slateNode), null, 2),
)
return convertChildren(slateNode)
},
nodeTypes: ['indent'],
}

View File

@@ -1,29 +0,0 @@
import type { SerializedLinkNode } from '../../../../Link/nodes/LinkNode'
import type { SlateNodeConverter } from '../types'
import { convertSlateNodesToLexical } from '..'
export const LinkConverter: SlateNodeConverter = {
converter({ converters, slateNode }) {
return {
children: convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'link',
slateNodes: slateNode.children || [],
}),
direction: 'ltr',
fields: {
doc: slateNode.doc || undefined,
linkType: slateNode.linkType || 'custom',
newTab: slateNode.newTab || false,
url: slateNode.url || undefined,
},
format: '',
indent: 0,
type: 'link',
version: 1,
} as const as SerializedLinkNode
},
nodeTypes: ['link'],
}

View File

@@ -1,26 +0,0 @@
import type { SerializedListItemNode } from '@lexical/list'
import type { SlateNodeConverter } from '../types'
import { convertSlateNodesToLexical } from '..'
export const ListItemConverter: SlateNodeConverter = {
converter({ childIndex, converters, slateNode }) {
return {
checked: undefined,
children: convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'listitem',
slateNodes: slateNode.children || [],
}),
direction: 'ltr',
format: '',
indent: 0,
type: 'listitem',
value: childIndex + 1,
version: 1,
} as const as SerializedListItemNode
},
nodeTypes: ['li'],
}

View File

@@ -1,27 +0,0 @@
import type { SerializedListNode } from '@lexical/list'
import type { SlateNodeConverter } from '../types'
import { convertSlateNodesToLexical } from '..'
export const OrderedListConverter: SlateNodeConverter = {
converter({ converters, slateNode }) {
return {
children: convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'list',
slateNodes: slateNode.children || [],
}),
direction: 'ltr',
format: '',
indent: 0,
listType: 'number',
start: 1,
tag: 'ol',
type: 'list',
version: 1,
} as const as SerializedListNode
},
nodeTypes: ['ol'],
}

View File

@@ -1,17 +0,0 @@
import type { SerializedRelationshipNode } from '../../../../../..'
import type { SlateNodeConverter } from '../types'
export const RelationshipConverter: SlateNodeConverter = {
converter({ slateNode }) {
return {
format: '',
relationTo: slateNode.relationTo,
type: 'relationship',
value: {
id: slateNode?.value?.id || '',
},
version: 1,
} as const as SerializedRelationshipNode
},
nodeTypes: ['relationship'],
}

View File

@@ -1,27 +0,0 @@
import type { SerializedUnknownConvertedNode } from '../../nodes/unknownConvertedNode'
import type { SlateNodeConverter } from '../types'
import { convertSlateNodesToLexical } from '..'
export const UnknownConverter: SlateNodeConverter = {
converter({ converters, slateNode }) {
return {
children: convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'unknownConverted',
slateNodes: slateNode.children || [],
}),
data: {
nodeData: slateNode,
nodeType: slateNode.type,
},
direction: 'ltr',
format: '',
indent: 0,
type: 'unknownConverted',
version: 1,
} as const as SerializedUnknownConvertedNode
},
nodeTypes: ['unknown'],
}

View File

@@ -1,27 +0,0 @@
import type { SerializedListNode } from '@lexical/list'
import type { SlateNodeConverter } from '../types'
import { convertSlateNodesToLexical } from '..'
export const UnorderedListConverter: SlateNodeConverter = {
converter({ converters, slateNode }) {
return {
children: convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'list',
slateNodes: slateNode.children || [],
}),
direction: 'ltr',
format: '',
indent: 0,
listType: 'bullet',
start: 1,
tag: 'ul',
type: 'list',
version: 1,
} as const as SerializedListNode
},
nodeTypes: ['ul'],
}

View File

@@ -1,20 +0,0 @@
import type { SerializedUploadNode } from '../../../../../..'
import type { SlateNodeConverter } from '../types'
export const UploadConverter: SlateNodeConverter = {
converter({ slateNode }) {
return {
fields: {
...slateNode.fields,
},
format: '',
relationTo: slateNode.relationTo,
type: 'upload',
value: {
id: slateNode.value?.id || '',
},
version: 1,
} as const as SerializedUploadNode
},
nodeTypes: ['upload'],
}

View File

@@ -1,23 +0,0 @@
import type { SlateNodeConverter } from './types'
import { HeadingConverter } from './converters/heading'
import { IndentConverter } from './converters/indent'
import { LinkConverter } from './converters/link'
import { ListItemConverter } from './converters/listItem'
import { OrderedListConverter } from './converters/orderedList'
import { RelationshipConverter } from './converters/relationship'
import { UnknownConverter } from './converters/unknown'
import { UnorderedListConverter } from './converters/unorderedList'
import { UploadConverter } from './converters/upload'
export const defaultConverters: SlateNodeConverter[] = [
UnknownConverter,
UploadConverter,
UnorderedListConverter,
OrderedListConverter,
RelationshipConverter,
ListItemConverter,
LinkConverter,
HeadingConverter,
IndentConverter,
]

View File

@@ -1,137 +0,0 @@
import type {
SerializedEditorState,
SerializedLexicalNode,
SerializedParagraphNode,
SerializedTextNode,
} from 'lexical'
import type { SlateNode, SlateNodeConverter } from './types'
import { NodeFormat } from '../../../../lexical/utils/nodeFormat'
export function convertSlateToLexical({
converters,
slateData,
}: {
converters: SlateNodeConverter[]
slateData: SlateNode[]
}): SerializedEditorState {
return {
root: {
children: convertSlateNodesToLexical({
canContainParagraphs: true,
converters,
parentNodeType: 'root',
slateNodes: slateData,
}),
direction: 'ltr',
format: '',
indent: 0,
type: 'root',
version: 1,
},
}
}
export function convertSlateNodesToLexical({
canContainParagraphs,
converters,
parentNodeType,
slateNodes,
}: {
canContainParagraphs: boolean
converters: SlateNodeConverter[]
/**
* Type of the parent lexical node (not the type of the original, parent slate type)
*/
parentNodeType: string
slateNodes: SlateNode[]
}): SerializedLexicalNode[] {
const unknownConverter = converters.find((converter) => converter.nodeTypes.includes('unknown'))
return (
slateNodes.map((slateNode, i) => {
if (!('type' in slateNode)) {
if (canContainParagraphs) {
// This is a paragraph node. They do not have a type property in Slate
return convertParagraphNode(converters, slateNode)
} else {
// This is a simple text node. canContainParagraphs may be false if this is nested inside of a paragraph already, since paragraphs cannot contain paragraphs
return convertTextNode(slateNode)
}
}
if (slateNode.type === 'p') {
return convertParagraphNode(converters, slateNode)
}
const converter = converters.find((converter) => converter.nodeTypes.includes(slateNode.type))
if (converter) {
return converter.converter({ childIndex: i, converters, parentNodeType, slateNode })
}
console.warn('slateToLexical > No converter found for node type: ' + slateNode.type)
return unknownConverter?.converter({
childIndex: i,
converters,
parentNodeType,
slateNode,
})
}) || []
)
}
export function convertParagraphNode(
converters: SlateNodeConverter[],
node: SlateNode,
): SerializedParagraphNode {
return {
children: convertSlateNodesToLexical({
canContainParagraphs: false,
converters,
parentNodeType: 'paragraph',
slateNodes: node.children || [],
}),
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
}
}
export function convertTextNode(node: SlateNode): SerializedTextNode {
return {
detail: 0,
format: convertNodeToFormat(node),
mode: 'normal',
style: '',
text: node.text,
type: 'text',
version: 1,
}
}
export function convertNodeToFormat(node: SlateNode): number {
let format = 0
if (node.bold) {
format = format | NodeFormat.IS_BOLD
}
if (node.italic) {
format = format | NodeFormat.IS_ITALIC
}
if (node.strikethrough) {
format = format | NodeFormat.IS_STRIKETHROUGH
}
if (node.underline) {
format = format | NodeFormat.IS_UNDERLINE
}
if (node.subscript) {
format = format | NodeFormat.IS_SUBSCRIPT
}
if (node.superscript) {
format = format | NodeFormat.IS_SUPERSCRIPT
}
if (node.code) {
format = format | NodeFormat.IS_CODE
}
return format
}

View File

@@ -1,22 +0,0 @@
import type { SerializedLexicalNode } from 'lexical'
export type SlateNodeConverter<T extends SerializedLexicalNode = SerializedLexicalNode> = {
converter: ({
childIndex,
converters,
parentNodeType,
slateNode,
}: {
childIndex: number
converters: SlateNodeConverter[]
parentNodeType: string
slateNode: SlateNode
}) => T
nodeTypes: string[]
}
export type SlateNode = {
[key: string]: any
children?: SlateNode[]
type?: string // doesn't always have type, e.g. for paragraphs
}

View File

@@ -1,56 +0,0 @@
import type { FeatureProvider } from '../../types'
import type { SlateNodeConverter } from './converter/types'
import { convertSlateToLexical } from './converter'
import { defaultConverters } from './converter/defaultConverters'
import { UnknownConvertedNode } from './nodes/unknownConvertedNode'
type Props = {
converters?:
| (({ defaultConverters }: { defaultConverters: SlateNodeConverter[] }) => SlateNodeConverter[])
| SlateNodeConverter[]
}
export const SlateToLexicalFeature = (props?: Props): FeatureProvider => {
if (!props) {
props = {}
}
props.converters =
props?.converters && typeof props?.converters === 'function'
? props.converters({ defaultConverters: defaultConverters })
: (props?.converters as SlateNodeConverter[]) || defaultConverters
return {
feature: ({ resolvedFeatures, unsanitizedEditorConfig }) => {
return {
hooks: {
load({ incomingEditorState }) {
if (
!incomingEditorState ||
!Array.isArray(incomingEditorState) ||
'root' in incomingEditorState
) {
// incomingEditorState null or not from Slate
return incomingEditorState
}
// Slate => convert to lexical
return convertSlateToLexical({
converters: props.converters as SlateNodeConverter[],
slateData: incomingEditorState,
})
},
},
nodes: [
{
node: UnknownConvertedNode,
type: UnknownConvertedNode.getType(),
},
],
props,
}
},
key: 'slateToLexical',
}
}

View File

@@ -1,16 +0,0 @@
@import 'payload/scss';
span.unknownConverted {
text-transform: uppercase;
font-family: 'Roboto Mono', monospace;
letter-spacing: 2px;
font-size: base(0.5);
margin: 0 0 base(1);
background: red;
color: white;
display: inline-block;
div {
background: red;
}
}

View File

@@ -1,97 +0,0 @@
import type { SerializedLexicalNode, Spread } from 'lexical'
import { addClassNamesToElement } from '@lexical/utils'
import { DecoratorNode, type EditorConfig, type LexicalNode, type NodeKey } from 'lexical'
import React from 'react'
import './index.scss'
export type UnknownConvertedNodeData = {
nodeData: unknown
nodeType: string
}
export type SerializedUnknownConvertedNode = Spread<
{
data: UnknownConvertedNodeData
},
SerializedLexicalNode
>
/** @noInheritDoc */
export class UnknownConvertedNode extends DecoratorNode<JSX.Element> {
__data: UnknownConvertedNodeData
constructor({ data, key }: { data: UnknownConvertedNodeData; key?: NodeKey }) {
super(key)
this.__data = data
}
static clone(node: UnknownConvertedNode): UnknownConvertedNode {
return new UnknownConvertedNode({
data: node.__data,
key: node.__key,
})
}
static getType(): string {
return 'unknownConverted'
}
static importJSON(serializedNode: SerializedUnknownConvertedNode): UnknownConvertedNode {
const node = $createUnknownConvertedNode({ data: serializedNode.data })
return node
}
canInsertTextAfter(): true {
return true
}
canInsertTextBefore(): true {
return true
}
createDOM(config: EditorConfig): HTMLElement {
const element = document.createElement('span')
addClassNamesToElement(element, 'unknownConverted')
return element
}
decorate(): JSX.Element | null {
return <div>Unknown converted Slate node: {this.__data?.nodeType}</div>
}
exportJSON(): SerializedUnknownConvertedNode {
return {
data: this.__data,
type: this.getType(),
version: 1,
}
}
// Mutation
isInline(): boolean {
return true
}
updateDOM(prevNode: UnknownConvertedNode, dom: HTMLElement): boolean {
return false
}
}
export function $createUnknownConvertedNode({
data,
}: {
data: UnknownConvertedNodeData
}): UnknownConvertedNode {
return new UnknownConvertedNode({
data,
})
}
export function $isUnknownConvertedNode(
node: LexicalNode | null | undefined,
): node is UnknownConvertedNode {
return node instanceof UnknownConvertedNode
}

View File

@@ -51,18 +51,6 @@ export type Feature = {
floatingSelectToolbar?: {
sections: FloatingToolbarSection[]
}
hooks?: {
load?: ({
incomingEditorState,
}: {
incomingEditorState: SerializedEditorState
}) => SerializedEditorState
save?: ({
incomingEditorState,
}: {
incomingEditorState: SerializedEditorState
}) => SerializedEditorState
}
markdownTransformers?: Transformer[]
nodes?: Array<{
afterReadPromises?: Array<AfterReadPromise>
@@ -135,22 +123,6 @@ export type SanitizedFeatures = Required<
floatingSelectToolbar: {
sections: FloatingToolbarSection[]
}
hooks: {
load: Array<
({
incomingEditorState,
}: {
incomingEditorState: SerializedEditorState
}) => SerializedEditorState
>
save: Array<
({
incomingEditorState,
}: {
incomingEditorState: SerializedEditorState
}) => SerializedEditorState
>
}
plugins?: Array<
| {
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality

View File

@@ -21,16 +21,7 @@ export type LexicalProviderProps = {
value: SerializedEditorState
}
export const LexicalProvider: React.FC<LexicalProviderProps> = (props) => {
const { editorConfig, fieldProps, onChange, readOnly, setValue } = props
let { initialState, value } = props
// Transform initialState through load hooks
if (editorConfig?.features?.hooks?.load?.length) {
editorConfig.features.hooks.load.forEach((hook) => {
initialState = hook({ incomingEditorState: initialState })
value = hook({ incomingEditorState: value })
})
}
const { editorConfig, fieldProps, initialState, onChange, readOnly, setValue, value } = props
if (
(value && Array.isArray(value) && !('root' in value)) ||

View File

@@ -10,10 +10,6 @@ export const sanitizeFeatures = (features: ResolvedFeatureMap): SanitizedFeature
floatingSelectToolbar: {
sections: [],
},
hooks: {
load: [],
save: [],
},
markdownTransformers: [],
nodes: [],
plugins: [],
@@ -25,15 +21,6 @@ export const sanitizeFeatures = (features: ResolvedFeatureMap): SanitizedFeature
}
features.forEach((feature) => {
if (feature.hooks) {
if (feature.hooks?.load?.length) {
sanitized.hooks.load = sanitized.hooks.load.concat(feature.hooks.load)
}
if (feature.hooks?.save?.length) {
sanitized.hooks.save = sanitized.hooks.save.concat(feature.hooks.save)
}
}
if (feature.nodes?.length) {
sanitized.nodes = sanitized.nodes.concat(feature.nodes)
feature.nodes.forEach((node) => {

View File

@@ -1,124 +0,0 @@
/* 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 here: https://github.com/facebook/lexical/blob/c2ceee223f46543d12c574e62155e619f9a18a5d/packages/lexical/src/LexicalConstants.ts
import type { ElementFormatType, TextFormatType } from 'lexical'
import type { TextDetailType, TextModeType } from 'lexical/nodes/LexicalTextNode'
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
// 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<TextFormatType | 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<TextDetailType | string, number> = {
directionless: NodeFormat.IS_DIRECTIONLESS,
unmergeable: NodeFormat.IS_UNMERGEABLE,
}
export const ELEMENT_TYPE_TO_FORMAT: Record<Exclude<ElementFormatType, ''>, 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, ElementFormatType> = {
[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<TextModeType, 0 | 1 | 2> = {
normal: NodeFormat.IS_NORMAL,
segmented: NodeFormat.IS_SEGMENTED,
token: NodeFormat.IS_TOKEN,
}
export const TEXT_TYPE_TO_MODE: Record<number, TextModeType> = {
[NodeFormat.IS_NORMAL]: 'normal',
[NodeFormat.IS_SEGMENTED]: 'segmented',
[NodeFormat.IS_TOKEN]: 'token',
}

View File

@@ -153,7 +153,6 @@ export { IndentFeature } from './field/features/indent'
export { CheckListFeature } from './field/features/lists/CheckList'
export { OrderedListFeature } from './field/features/lists/OrderedList'
export { UnoderedListFeature } from './field/features/lists/UnorderedList'
export { SlateToLexicalFeature } from './field/features/migrations/SlateToLexical'
export type {
AfterReadPromise,
Feature,
@@ -202,20 +201,6 @@ export { isHTMLElement } from './field/lexical/utils/guard'
export { invariant } from './field/lexical/utils/invariant'
export { joinClasses } from './field/lexical/utils/joinClasses'
export { createBlockNode } from './field/lexical/utils/markdown/createBlockNode'
export {
DETAIL_TYPE_TO_DETAIL,
DOUBLE_LINE_BREAK,
ELEMENT_FORMAT_TO_TYPE,
ELEMENT_TYPE_TO_FORMAT,
IS_ALL_FORMATTING,
LTR_REGEX,
NON_BREAKING_SPACE,
NodeFormat,
RTL_REGEX,
TEXT_MODE_TO_TYPE,
TEXT_TYPE_TO_FORMAT,
TEXT_TYPE_TO_MODE,
} from './field/lexical/utils/nodeFormat'
export { Point, isPoint } from './field/lexical/utils/point'
export { Rect } from './field/lexical/utils/rect'
export { setFloatingElemPosition } from './field/lexical/utils/setFloatingElemPosition'

View File

@@ -173,7 +173,7 @@ export const recurseNestedFields = ({
promises,
req,
showHiddenFields,
siblingDoc: data[field.name][i], // This has to be scoped to the blocks's fields, otherwise there may be population issues, e.g. for a relationship field with Blocks Node, with a Blocks Field, with a RichText Field, With Relationship Node. The last richtext field would try to find itself using siblingDoc[field.nane], which only works if the siblingDoc is scoped to the blocks's fields
siblingDoc,
})
}
})
@@ -191,13 +191,14 @@ export const recurseNestedFields = ({
promises,
req,
showHiddenFields,
siblingDoc, // TODO: if there's any population issues, this might have to be data[field.name][i] as well
siblingDoc,
})
})
}
}
if (field.type === 'richText') {
// TODO: This does not properly work yet. E.g. it does not handle a relationship inside of lexical inside of block inside of lexical
const editor: RichTextAdapter = field?.editor
if (editor?.afterReadPromise) {

View File

@@ -59,7 +59,7 @@ export const recurseRichText = ({
}
}
if ('children' in node && Array.isArray(node?.children) && node?.children?.length) {
if ('children' in node && node?.children) {
recurseRichText({
afterReadPromises,
children: node.children as SerializedLexicalNode[],

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-slate",
"version": "1.0.4",
"version": "1.0.3",
"description": "The officially supported Slate richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -1,4 +1,3 @@
'use client'
import type { CellComponentProps, RichTextField } from 'payload/types'
import React from 'react'

View File

@@ -1,4 +1,3 @@
'use client'
import type { ElementType } from 'react'
import { Tooltip } from 'payload/components'

View File

@@ -1,4 +1,3 @@
'use client'
import { Editor, Transforms } from 'slate'
import { ReactEditor } from 'slate-react'

View File

@@ -1,4 +1,3 @@
'use client'
import { ShimmerEffect } from 'payload/components'
import React, { Suspense, lazy } from 'react'

View File

@@ -1,4 +1,3 @@
'use client'
import React from 'react'
import { useSlate } from 'slate-react'

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# List all published packages
packages=$(find packages -name package.json -type f -exec grep -L '"private": true' {} \; | xargs jq -r '.name')
# sort alphabetically
packages=$(echo "$packages" | tr ' ' '\n' | sort -u | tr '\n' ' ')
# Loop through each package and print the name and version. Print as table
printf "%-30s %-20s %-20s\n" "package" "latest" "beta"
for package in $packages; do
info=$(npm view "$package" dist-tags --json)
latest=$(echo "$info" | jq -r '.latest')
beta=$(echo "$info" | jq -r '.beta')
printf "%-30s %-20s %-20s\n" "$package" "$latest" "$beta"
done

26
scripts/release_beta.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -ex
# Build packages/payload
package_name=$1
package_dir="packages/$package_name"
if [ -z "$package_name" ]; then
echo "Please specify a package to publish"
exit 1
fi
# Check if packages/$package_name exists
if [ ! -d "$package_dir" ]; then
echo "Package $package_name does not exist"
exit 1
fi
npm --prefix "$package_dir" version pre --preid beta
git add "$package_dir"/package.json
new_version=$(node -p "require('./$package_dir/package.json').version")
git commit -m "chore(release): $package_name@$new_version"
pnpm publish -C "$package_dir" --tag beta --no-git-checks

View File

@@ -65,24 +65,6 @@ export const Posts: CollectionConfig = {
},
],
},
{
name: 'group',
type: 'group',
fields: [
{
name: 'title',
type: 'text',
},
],
},
{
name: 'relationship',
type: 'relationship',
relationTo: 'posts',
admin: {
position: 'sidebar',
},
},
{
name: 'sidebarField',
type: 'text',

View File

@@ -330,12 +330,10 @@ describe('admin', () => {
await page.locator('input#select-all').check()
await page.locator('.edit-many__toggle').click()
await page.locator('.field-select .rs__control').click()
const options = page.locator('.rs__option')
const titleOption = options.locator('text=Title')
const titleOption = page.locator('.rs__option', {
hasText: exactText('Title'),
})
await expect(titleOption).toBeVisible()
await expect(titleOption).toHaveText('Title')
await titleOption.click()
const titleInput = page.locator('#field-title')

View File

@@ -13,17 +13,6 @@ export const TextBlock: Block = {
slug: 'text',
}
export const RichTextBlock: Block = {
fields: [
{
name: 'richText',
type: 'richText',
editor: lexicalEditor(),
},
],
slug: 'richText',
}
export const UploadAndRichTextBlock: Block = {
fields: [
{

View File

@@ -1,3 +1,5 @@
import { loremIpsum } from './loremIpsum'
export function generateLexicalRichText() {
return {
root: {
@@ -13,7 +15,210 @@ export function generateLexicalRichText() {
format: 0,
mode: 'normal',
style: '',
text: 'Upload Node:',
text: "Hello, I'm a rich text field.",
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: 'center',
indent: 0,
type: 'heading',
version: 1,
tag: 'h1',
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'I can do all kinds of fun stuff like ',
type: 'text',
version: 1,
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'render links',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'link',
version: 1,
fields: {
url: 'https://payloadcms.com',
newTab: true,
linkType: 'custom',
},
},
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: ', ',
type: 'text',
version: 1,
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'link to relationships',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'link',
version: 1,
fields: {
url: 'https://',
doc: {
value: {
id: '{{ARRAY_DOC_ID}}',
},
relationTo: 'array-fields',
},
newTab: false,
linkType: 'internal',
},
},
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: ', and store nested relationship fields:',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
format: '',
type: 'relationship',
version: 1,
value: {
id: '{{TEXT_DOC_ID}}',
},
relationTo: 'text-fields',
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'You can build your own elements, too.',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: "It's built with Lexical",
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'listitem',
version: 1,
value: 1,
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'It stores content as JSON so you can use it wherever you need',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'listitem',
version: 1,
value: 2,
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: "It's got a great editing experience for non-technical users",
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'listitem',
version: 1,
value: 3,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'list',
version: 1,
listType: 'bullet',
start: 1,
tag: 'ul',
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'And a whole lot more.',
type: 'text',
version: 1,
},
@@ -28,6 +233,10 @@ export function generateLexicalRichText() {
format: '',
type: 'upload',
version: 1,
relationTo: 'uploads',
value: {
id: '{{UPLOAD_DOC_ID}}',
},
fields: {
caption: {
root: {
@@ -36,151 +245,69 @@ export function generateLexicalRichText() {
indent: 0,
version: 1,
children: [
{
...[...Array(4)].map(() => ({
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Relationship inside Upload Caption:',
text: loremIpsum,
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
format: '',
type: 'relationship',
version: 1,
relationTo: 'text-fields',
value: {
id: '{{TEXT_DOC_ID}}',
},
},
})),
],
direction: 'ltr',
},
},
},
relationTo: 'uploads',
value: {
id: '{{UPLOAD_DOC_ID}}',
},
},
{
format: '',
type: 'block',
version: 1,
fields: {
data: {
id: '65298b13db4ef8c744a7faaa',
rel: '{{UPLOAD_DOC_ID}}',
blockName: 'Block Node, with Relationship Field',
blockType: 'relationshipBlock',
},
},
},
{
format: '',
type: 'block',
version: 1,
fields: {
data: {
id: '65298b1ddb4ef8c744a7faab',
richText: {
root: {
type: 'root',
format: '',
indent: 0,
version: 1,
children: [
{
format: '',
type: 'relationship',
version: 1,
relationTo: 'text-fields',
value: {
id: '{{TEXT_DOC_ID}}',
},
},
],
direction: null,
},
},
blockName: 'Block Node, with RichText Field, with Relationship Node',
blockType: 'richText',
},
},
},
{
format: '',
type: 'block',
version: 1,
fields: {
data: {
id: '65298b2bdb4ef8c744a7faac',
blockName:
'Block Node, with Blocks Field, With RichText Field, With Relationship Node',
blockType: 'subBlock',
subBlocks: [
{
id: '65298b2edb4ef8c744a7faad',
richText: {
root: {
type: 'root',
format: '',
indent: 0,
version: 1,
children: [
{
format: '',
type: 'relationship',
version: 1,
relationTo: 'text-fields',
value: {
id: '{{TEXT_DOC_ID}}',
},
},
],
direction: null,
},
},
blockType: 'contentBlock',
},
],
},
},
},
{
format: '',
type: 'block',
version: 1,
fields: {
data: {
id: '65298b49db4ef8c744a7faae',
upload: '{{UPLOAD_DOC_ID}}',
blockName: 'Block Node, With Upload Field',
blockType: 'uploadAndRichText',
},
},
},
{
children: [],
direction: null,
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
children: [],
direction: null,
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu.',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',
version: 1,
},
{
children: [
{
detail: 0,
format: 0,
mode: 'normal',
style: '',
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam hendrerit nisi sed sollicitudin pellentesque. Nunc posuere purus rhoncus pulvinar aliquam. Ut aliquet tristique nisl vitae volutpat. Nulla aliquet porttitor venenatis. Donec a dui et dui fringilla consectetur id nec massa. Aliquam erat volutpat. Sed ut dui ut lacus dictum fermentum vel tincidunt neque. Sed sed lacinia lectus. Duis sit amet sodales felis. Duis nunc eros, mattis at dui ac, convallis semper risus. In adipiscing ultrices tellus, in suscipit massa vehicula eu.',
type: 'text',
version: 1,
},
],
direction: 'ltr',
format: '',
indent: 0,
type: 'paragraph',

View File

@@ -9,7 +9,6 @@ import {
} from '../../../../packages/richtext-lexical/src'
import {
RelationshipBlock,
RichTextBlock,
SelectFieldBlock,
SubBlockBlock,
TextBlock,
@@ -21,7 +20,6 @@ export const LexicalFields: CollectionConfig = {
slug: 'lexical-fields',
admin: {
useAsTitle: 'title',
listSearchableFields: ['title', 'richTextLexicalCustomFields'],
},
access: {
read: () => true,
@@ -70,7 +68,6 @@ export const LexicalFields: CollectionConfig = {
}),
BlocksFeature({
blocks: [
RichTextBlock,
TextBlock,
UploadAndRichTextBlock,
SelectFieldBlock,
@@ -84,7 +81,7 @@ export const LexicalFields: CollectionConfig = {
],
}
export const LexicalRichTextDoc = {
export const lexicalRichTextDoc = {
title: 'Rich Text',
richTextLexicalCustomFields: generateLexicalRichText(),
}

View File

@@ -14,7 +14,7 @@ import DateFields, { dateDoc } from './collections/Date'
import GroupFields, { groupDoc } from './collections/Group'
import IndexedFields from './collections/Indexed'
import JSONFields, { jsonDoc } from './collections/JSON'
import { LexicalFields, LexicalRichTextDoc } from './collections/Lexical'
import { LexicalFields } from './collections/Lexical'
import NumberFields, { numberDoc } from './collections/Number'
import PointFields, { pointDoc } from './collections/Point'
import RadioFields, { radiosDoc } from './collections/Radio'
@@ -150,7 +150,7 @@ export default buildConfigWithDefaults({
)
const lexicalRichTextDocWithRelId = JSON.parse(
JSON.stringify(LexicalRichTextDoc)
JSON.stringify(richTextDoc)
.replace(/"\{\{ARRAY_DOC_ID\}\}"/g, formattedID)
.replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, formattedJPGID)
.replace(/"\{\{TEXT_DOC_ID\}\}"/g, formattedTextID),