diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 927ddb22f9..223fa6808c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -294,14 +294,10 @@ jobs: - fields__collections__Email - fields__collections__Indexed - fields__collections__JSON - - fields__collections__Lexical__e2e__main - - fields__collections__Lexical__e2e__blocks - - fields__collections__Lexical__e2e__blocks#config.blockreferences.ts - fields__collections__Number - fields__collections__Point - fields__collections__Radio - fields__collections__Relationship - - fields__collections__RichText - fields__collections__Row - fields__collections__Select - fields__collections__Tabs @@ -310,6 +306,10 @@ jobs: - fields__collections__UI - fields__collections__Upload - hooks + - lexical__collections__Lexical__e2e__main + - lexical__collections__Lexical__e2e__blocks + - lexical__collections__Lexical__e2e__blocks#config.blockreferences.ts + - lexical__collections__RichText - query-presets - form-state - live-preview diff --git a/test/access-control/config.ts b/test/access-control/config.ts index 182a834b50..917be5cb12 100644 --- a/test/access-control/config.ts +++ b/test/access-control/config.ts @@ -8,7 +8,7 @@ import type { Config, User } from './payload-types.js' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { devUser } from '../credentials.js' -import { textToLexicalJSON } from '../fields/collections/LexicalLocalized/textToLexicalJSON.js' +import { textToLexicalJSON } from '../lexical/collections/LexicalLocalized/textToLexicalJSON.js' import { Disabled } from './collections/Disabled/index.js' import { Hooks } from './collections/hooks/index.js' import { Regression1 } from './collections/Regression-1/index.js' diff --git a/test/fields/baseConfig.ts b/test/fields/baseConfig.ts index d185672e16..0967d726b7 100644 --- a/test/fields/baseConfig.ts +++ b/test/fields/baseConfig.ts @@ -20,22 +20,10 @@ import EmailFields from './collections/Email/index.js' import GroupFields from './collections/Group/index.js' import IndexedFields from './collections/Indexed/index.js' import JSONFields from './collections/JSON/index.js' -import { - getLexicalFieldsCollection, - lexicalBlocks, - lexicalInlineBlocks, -} from './collections/Lexical/index.js' -import { LexicalAccessControl } from './collections/LexicalAccessControl/index.js' -import { LexicalInBlock } from './collections/LexicalInBlock/index.js' -import { LexicalLocalizedFields } from './collections/LexicalLocalized/index.js' -import { LexicalMigrateFields } from './collections/LexicalMigrate/index.js' -import { LexicalObjectReferenceBugCollection } from './collections/LexicalObjectReferenceBug/index.js' -import { LexicalRelationshipsFields } from './collections/LexicalRelationships/index.js' import NumberFields from './collections/Number/index.js' import PointFields from './collections/Point/index.js' import RadioFields from './collections/Radio/index.js' import RelationshipFields from './collections/Relationship/index.js' -import RichTextFields from './collections/RichText/index.js' import RowFields from './collections/Row/index.js' import SelectFields from './collections/Select/index.js' import SelectVersionsFields from './collections/SelectVersions/index.js' @@ -50,17 +38,9 @@ import UploadsMultiPoly from './collections/UploadMultiPoly/index.js' import UploadsPoly from './collections/UploadPoly/index.js' import UploadRestricted from './collections/UploadRestricted/index.js' import Uploads3 from './collections/Uploads3/index.js' -import TabsWithRichText from './globals/TabsWithRichText.js' import { clearAndSeedEverything } from './seed.js' export const collectionSlugs: CollectionConfig[] = [ - getLexicalFieldsCollection({ - blocks: lexicalBlocks, - inlineBlocks: lexicalInlineBlocks, - }), - LexicalMigrateFields, - LexicalLocalizedFields, - LexicalObjectReferenceBugCollection, { slug: 'users', admin: { @@ -75,8 +55,6 @@ export const collectionSlugs: CollectionConfig[] = [ }, ], }, - LexicalInBlock, - LexicalAccessControl, SelectVersionsFields, ArrayFields, BlockFields, @@ -97,8 +75,6 @@ export const collectionSlugs: CollectionConfig[] = [ NumberFields, PointFields, RelationshipFields, - LexicalRelationshipsFields, - RichTextFields, SelectFields, TabsFields2, TabsFields, @@ -115,7 +91,6 @@ export const collectionSlugs: CollectionConfig[] = [ export const baseConfig: Partial = { collections: collectionSlugs, - globals: [TabsWithRichText], blocks: [ { slug: 'ConfigBlockTest', diff --git a/test/fields/config.blockreferences.ts b/test/fields/config.blockreferences.ts index 1eb221dafb..8c39c0bdcd 100644 --- a/test/fields/config.blockreferences.ts +++ b/test/fields/config.blockreferences.ts @@ -1,35 +1,10 @@ /* eslint-disable no-restricted-exports */ -import type { BlockSlug } from 'payload' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { autoDedupeBlocksPlugin } from '../helpers/autoDedupeBlocksPlugin/index.js' import { baseConfig } from './baseConfig.js' -import { - getLexicalFieldsCollection, - lexicalBlocks, - lexicalInlineBlocks, -} from './collections/Lexical/index.js' -import { lexicalFieldsSlug } from './slugs.js' export default buildConfigWithDefaults({ ...baseConfig, - blocks: [ - ...(baseConfig.blocks ?? []), - ...lexicalBlocks.filter((block) => typeof block !== 'string'), - ...lexicalInlineBlocks.filter((block) => typeof block !== 'string'), - ], - collections: baseConfig.collections?.map((collection) => { - if (collection.slug === lexicalFieldsSlug) { - return getLexicalFieldsCollection({ - blocks: lexicalBlocks.map((block) => - typeof block === 'string' ? block : block.slug, - ) as BlockSlug[], - inlineBlocks: lexicalInlineBlocks.map((block) => - typeof block === 'string' ? block : block.slug, - ) as BlockSlug[], - }) - } - return collection - }), plugins: [autoDedupeBlocksPlugin({ silent: true })], }) diff --git a/test/fields/int.spec.ts b/test/fields/int.spec.ts index b56670b05a..6796bbb745 100644 --- a/test/fields/int.spec.ts +++ b/test/fields/int.spec.ts @@ -2,11 +2,11 @@ import type { MongooseAdapter } from '@payloadcms/db-mongodb' import type { IndexDirection, IndexOptions } from 'mongoose' import path from 'path' -import { type PaginatedDocs, type Payload, reload } from 'payload' +import { type Payload, reload } from 'payload' import { fileURLToPath } from 'url' import type { NextRESTClient } from '../helpers/NextRESTClient.js' -import type { BlockField, GroupField, RichTextField } from './payload-types.js' +import type { BlockField, GroupField } from './payload-types.js' import { devUser } from '../credentials.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' @@ -3023,91 +3023,6 @@ describe('Fields', () => { }) }) - describe('richText', () => { - it('should allow querying on rich text content', async () => { - const emptyRichTextQuery = await payload.find({ - collection: 'rich-text-fields', - where: { - 'richText.children.text': { - like: 'doesnt exist', - }, - }, - }) - - expect(emptyRichTextQuery.docs).toHaveLength(0) - - const workingRichTextQuery = await payload.find({ - collection: 'rich-text-fields', - where: { - 'richText.children.text': { - like: 'hello', - }, - }, - }) - - expect(workingRichTextQuery.docs).toHaveLength(1) - }) - - it('should show center alignment', async () => { - const query = await payload.find({ - collection: 'rich-text-fields', - where: { - 'richText.children.text': { - like: 'hello', - }, - }, - }) - - expect(query.docs[0].richText[0].textAlign).toEqual('center') - }) - - it('should populate link relationship', async () => { - const query = await payload.find({ - collection: 'rich-text-fields', - where: { - 'richText.children.linkType': { - equals: 'internal', - }, - }, - }) - - const nodes = query.docs[0].richText - expect(nodes).toBeDefined() - const child = nodes.flatMap((n) => n.children).find((c) => c.doc) - expect(child).toMatchObject({ - type: 'link', - linkType: 'internal', - }) - expect(child.doc.relationTo).toEqual('array-fields') - - if (payload.db.defaultIDType === 'number') { - expect(typeof child.doc.value.id).toBe('number') - } else { - expect(typeof child.doc.value.id).toBe('string') - } - - expect(child.doc.value.items).toHaveLength(6) - }) - - it('should respect rich text depth parameter', async () => { - const query = `query { - RichTextFields { - docs { - richText(depth: 2) - } - } - }` - const { data } = await restClient - .GRAPHQL_POST({ - body: JSON.stringify({ query }), - }) - .then((res) => res.json()) - const { docs }: PaginatedDocs = data.RichTextFields - const uploadElement = docs[0].richText.find((el) => el.type === 'upload') as any - expect(uploadElement.value.media.filename).toStrictEqual('payload.png') - }) - }) - describe('relationships', () => { it('should not crash if querying with empty in operator', async () => { const query = await payload.find({ diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index b6babe2b1c..89fa819e9b 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -61,22 +61,6 @@ export type SupportedTimezones = | 'Pacific/Auckland' | 'Pacific/Fiji' | 'America/Monterrey'; -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "BlockColumns". - */ -export type BlockColumns = - | { - text?: string | null; - subArray?: - | { - requiredText: string; - id?: string | null; - }[] - | null; - id?: string | null; - }[] - | null; export interface Config { auth: { @@ -88,13 +72,7 @@ export interface Config { localizedTextReference2: LocalizedTextReference2; }; collections: { - 'lexical-fields': LexicalField; - 'lexical-migrate-fields': LexicalMigrateField; - 'lexical-localized-fields': LexicalLocalizedField; - lexicalObjectReferenceBug: LexicalObjectReferenceBug; users: User; - LexicalInBlock: LexicalInBlock; - 'lexical-access-control': LexicalAccessControl; 'select-versions-fields': SelectVersionsField; 'array-fields': ArrayField; 'block-fields': BlockField; @@ -115,8 +93,6 @@ export interface Config { 'number-fields': NumberField; 'point-fields': PointField; 'relationship-fields': RelationshipField; - 'lexical-relationship-fields': LexicalRelationshipField; - 'rich-text-fields': RichTextField; 'select-fields': SelectField; 'tabs-fields-2': TabsFields2; 'tabs-fields': TabsField; @@ -135,13 +111,7 @@ export interface Config { }; collectionsJoins: {}; collectionsSelect: { - 'lexical-fields': LexicalFieldsSelect | LexicalFieldsSelect; - 'lexical-migrate-fields': LexicalMigrateFieldsSelect | LexicalMigrateFieldsSelect; - 'lexical-localized-fields': LexicalLocalizedFieldsSelect | LexicalLocalizedFieldsSelect; - lexicalObjectReferenceBug: LexicalObjectReferenceBugSelect | LexicalObjectReferenceBugSelect; users: UsersSelect | UsersSelect; - LexicalInBlock: LexicalInBlockSelect | LexicalInBlockSelect; - 'lexical-access-control': LexicalAccessControlSelect | LexicalAccessControlSelect; 'select-versions-fields': SelectVersionsFieldsSelect | SelectVersionsFieldsSelect; 'array-fields': ArrayFieldsSelect | ArrayFieldsSelect; 'block-fields': BlockFieldsSelect | BlockFieldsSelect; @@ -162,8 +132,6 @@ export interface Config { 'number-fields': NumberFieldsSelect | NumberFieldsSelect; 'point-fields': PointFieldsSelect | PointFieldsSelect; 'relationship-fields': RelationshipFieldsSelect | RelationshipFieldsSelect; - 'lexical-relationship-fields': LexicalRelationshipFieldsSelect | LexicalRelationshipFieldsSelect; - 'rich-text-fields': RichTextFieldsSelect | RichTextFieldsSelect; 'select-fields': SelectFieldsSelect | SelectFieldsSelect; 'tabs-fields-2': TabsFields2Select | TabsFields2Select; 'tabs-fields': TabsFieldsSelect | TabsFieldsSelect; @@ -183,12 +151,8 @@ export interface Config { db: { defaultIDType: string; }; - globals: { - tabsWithRichText: TabsWithRichText; - }; - globalsSelect: { - tabsWithRichText: TabsWithRichTextSelect | TabsWithRichTextSelect; - }; + globals: {}; + globalsSelect: {}; locale: 'en' | 'es'; user: User & { collection: 'users'; @@ -246,242 +210,6 @@ export interface LocalizedTextReference2 { blockName?: string | null; blockType: 'localizedTextReference2'; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-fields". - */ -export interface LexicalField { - id: string; - title: string; - lexicalRootEditor?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalSimple?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalWithBlocks: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - }; - lexicalWithBlocks_markdown?: string | null; - updatedAt: string; - createdAt: string; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-migrate-fields". - */ -export interface LexicalMigrateField { - id: string; - title: string; - lexicalWithLexicalPluginData?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalWithSlateData?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalSimple?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalSimple_html?: string | null; - groupWithLexicalField?: { - lexicalInGroupField?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalInGroupField_html?: string | null; - }; - arrayWithLexicalField?: - | { - lexicalInArrayField?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalInArrayField_html?: string | null; - id?: string | null; - }[] - | null; - updatedAt: string; - createdAt: string; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-localized-fields". - */ -export interface LexicalLocalizedField { - id: string; - title: string; - /** - * Non-localized field with localized block subfields - */ - lexicalBlocksSubLocalized?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - /** - * Localized field with localized block subfields - */ - lexicalBlocksLocalized?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - updatedAt: string; - createdAt: string; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexicalObjectReferenceBug". - */ -export interface LexicalObjectReferenceBug { - id: string; - lexicalDefault?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - lexicalEditor?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - updatedAt: string; - createdAt: string; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -500,77 +228,6 @@ export interface User { lockUntil?: string | null; password?: string | null; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "LexicalInBlock". - */ -export interface LexicalInBlock { - id: string; - content?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - blocks?: - | { - lexical?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - id?: string | null; - blockName?: string | null; - blockType: 'lexicalInBlock2'; - }[] - | null; - updatedAt: string; - createdAt: string; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-access-control". - */ -export interface LexicalAccessControl { - id: string; - title?: string | null; - richText?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - updatedAt: string; - createdAt: string; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "select-versions-fields". @@ -1658,126 +1315,6 @@ export interface RelationshipField { updatedAt: string; createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-relationship-fields". - */ -export interface LexicalRelationshipField { - id: string; - richText?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - richText2?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - updatedAt: string; - createdAt: string; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "rich-text-fields". - */ -export interface RichTextField { - id: string; - title: string; - lexicalCustomFields: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - }; - lexicalCustomFields_html?: string | null; - /** - * This rich text field uses the lexical editor. - */ - lexical?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - /** - * This select field is rendered here to ensure its options dropdown renders above the rich text toolbar. - */ - selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null; - richText: { - [k: string]: unknown; - }[]; - richTextCustomFields?: - | { - [k: string]: unknown; - }[] - | null; - richTextReadOnly?: - | { - [k: string]: unknown; - }[] - | null; - blocks?: - | ( - | { - text?: string | null; - id?: string | null; - blockName?: string | null; - blockType: 'textBlock'; - } - | { - text?: - | { - [k: string]: unknown; - }[] - | null; - id?: string | null; - blockName?: string | null; - blockType: 'richTextBlockSlate'; - } - )[] - | null; - updatedAt: string; - createdAt: string; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "select-fields". @@ -2067,34 +1604,10 @@ export interface UiField { export interface PayloadLockedDocument { id: string; document?: - | ({ - relationTo: 'lexical-fields'; - value: string | LexicalField; - } | null) - | ({ - relationTo: 'lexical-migrate-fields'; - value: string | LexicalMigrateField; - } | null) - | ({ - relationTo: 'lexical-localized-fields'; - value: string | LexicalLocalizedField; - } | null) - | ({ - relationTo: 'lexicalObjectReferenceBug'; - value: string | LexicalObjectReferenceBug; - } | null) | ({ relationTo: 'users'; value: string | User; } | null) - | ({ - relationTo: 'LexicalInBlock'; - value: string | LexicalInBlock; - } | null) - | ({ - relationTo: 'lexical-access-control'; - value: string | LexicalAccessControl; - } | null) | ({ relationTo: 'select-versions-fields'; value: string | SelectVersionsField; @@ -2175,14 +1688,6 @@ export interface PayloadLockedDocument { relationTo: 'relationship-fields'; value: string | RelationshipField; } | null) - | ({ - relationTo: 'lexical-relationship-fields'; - value: string | LexicalRelationshipField; - } | null) - | ({ - relationTo: 'rich-text-fields'; - value: string | RichTextField; - } | null) | ({ relationTo: 'select-fields'; value: string | SelectField; @@ -2273,66 +1778,6 @@ export interface PayloadMigration { updatedAt: string; createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-fields_select". - */ -export interface LexicalFieldsSelect { - title?: T; - lexicalRootEditor?: T; - lexicalSimple?: T; - lexicalWithBlocks?: T; - lexicalWithBlocks_markdown?: T; - updatedAt?: T; - createdAt?: T; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-migrate-fields_select". - */ -export interface LexicalMigrateFieldsSelect { - title?: T; - lexicalWithLexicalPluginData?: T; - lexicalWithSlateData?: T; - lexicalSimple?: T; - lexicalSimple_html?: T; - groupWithLexicalField?: - | T - | { - lexicalInGroupField?: T; - lexicalInGroupField_html?: T; - }; - arrayWithLexicalField?: - | T - | { - lexicalInArrayField?: T; - lexicalInArrayField_html?: T; - id?: T; - }; - updatedAt?: T; - createdAt?: T; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-localized-fields_select". - */ -export interface LexicalLocalizedFieldsSelect { - title?: T; - lexicalBlocksSubLocalized?: T; - lexicalBlocksLocalized?: T; - updatedAt?: T; - createdAt?: T; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexicalObjectReferenceBug_select". - */ -export interface LexicalObjectReferenceBugSelect { - lexicalDefault?: T; - lexicalEditor?: T; - updatedAt?: T; - createdAt?: T; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". @@ -2349,36 +1794,6 @@ export interface UsersSelect { loginAttempts?: T; lockUntil?: T; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "LexicalInBlock_select". - */ -export interface LexicalInBlockSelect { - content?: T; - blocks?: - | T - | { - lexicalInBlock2?: - | T - | { - lexical?: T; - id?: T; - blockName?: T; - }; - }; - updatedAt?: T; - createdAt?: T; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-access-control_select". - */ -export interface LexicalAccessControlSelect { - title?: T; - richText?: T; - updatedAt?: T; - createdAt?: T; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "select-versions-fields_select". @@ -3374,50 +2789,6 @@ export interface RelationshipFieldsSelect { updatedAt?: T; createdAt?: T; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "lexical-relationship-fields_select". - */ -export interface LexicalRelationshipFieldsSelect { - richText?: T; - richText2?: T; - updatedAt?: T; - createdAt?: T; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "rich-text-fields_select". - */ -export interface RichTextFieldsSelect { - title?: T; - lexicalCustomFields?: T; - lexicalCustomFields_html?: T; - lexical?: T; - selectHasMany?: T; - richText?: T; - richTextCustomFields?: T; - richTextReadOnly?: T; - blocks?: - | T - | { - textBlock?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - richTextBlockSlate?: - | T - | { - text?: T; - id?: T; - blockName?: T; - }; - }; - updatedAt?: T; - createdAt?: T; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "select-fields_select". @@ -3766,93 +3137,6 @@ export interface PayloadMigrationsSelect { updatedAt?: T; createdAt?: T; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "tabsWithRichText". - */ -export interface TabsWithRichText { - id: string; - tab1?: { - rt1?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - }; - tab2?: { - rt2?: { - root: { - type: string; - children: { - type: string; - version: number; - [k: string]: unknown; - }[]; - direction: ('ltr' | 'rtl') | null; - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; - indent: number; - version: number; - }; - [k: string]: unknown; - } | null; - }; - updatedAt?: string | null; - createdAt?: string | null; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "tabsWithRichText_select". - */ -export interface TabsWithRichTextSelect { - tab1?: - | T - | { - rt1?: T; - }; - tab2?: - | T - | { - rt2?: T; - }; - updatedAt?: T; - createdAt?: T; - globalType?: T; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "LexicalBlocksRadioButtonsBlock". - */ -export interface LexicalBlocksRadioButtonsBlock { - radioButtons?: ('option1' | 'option2' | 'option3') | null; - id?: string | null; - blockName?: string | null; - blockType: 'radioButtons'; -} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "AvatarGroupBlock". - */ -export interface AvatarGroupBlock { - avatars?: - | { - image?: (string | null) | Upload; - id?: string | null; - }[] - | null; - id?: string | null; - blockName?: string | null; - blockType: 'AvatarGroup'; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "auth". diff --git a/test/fields/seed.ts b/test/fields/seed.ts index 65510dcc32..572a987f8d 100644 --- a/test/fields/seed.ts +++ b/test/fields/seed.ts @@ -6,7 +6,9 @@ import { fileURLToPath } from 'url' import { devUser } from '../credentials.js' import { seedDB } from '../helpers/seed.js' -import { anotherArrayDoc, arrayDoc } from './collections/Array/shared.js' +// TODO: decouple blocks from both test suites +import { richTextDocData } from '../lexical/collections/RichText/data.js' +import { arrayDoc } from './collections/Array/shared.js' import { blocksDoc } from './collections/Blocks/shared.js' import { codeDoc } from './collections/Code/shared.js' import { collapsibleDoc } from './collections/Collapsible/shared.js' @@ -16,14 +18,9 @@ import { dateDoc } from './collections/Date/shared.js' import { anotherEmailDoc, emailDoc } from './collections/Email/shared.js' import { groupDoc } from './collections/Group/shared.js' import { jsonDoc } from './collections/JSON/shared.js' -import { lexicalDocData } from './collections/Lexical/data.js' -import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js' -import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js' -import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js' import { numberDoc } from './collections/Number/shared.js' import { pointDoc } from './collections/Point/shared.js' import { radiosDoc } from './collections/Radio/shared.js' -import { richTextBulletsDocData, richTextDocData } from './collections/RichText/data.js' import { selectsDoc } from './collections/Select/shared.js' import { tabsDoc } from './collections/Tabs/shared.js' import { anotherTextDoc, textDoc } from './collections/Text/shared.js' @@ -43,22 +40,15 @@ import { emailFieldsSlug, groupFieldsSlug, jsonFieldsSlug, - lexicalFieldsSlug, - lexicalLocalizedFieldsSlug, - lexicalMigrateFieldsSlug, - lexicalRelationshipFieldsSlug, numberFieldsSlug, pointFieldsSlug, radioFieldsSlug, relationshipFieldsSlug, - richTextFieldsSlug, selectFieldsSlug, tabsFieldsSlug, textFieldsSlug, uiSlug, - uploads2Slug, uploadsMulti, - uploadsMultiPoly, uploadsPoly, uploadsSlug, usersSlug, @@ -86,13 +76,6 @@ export const seed = async (_payload: Payload) => { overrideAccess: true, }) - const createdAnotherArrayDoc = await _payload.create({ - collection: arrayFieldsSlug, - data: anotherArrayDoc, - depth: 0, - overrideAccess: true, - }) - const createdTextDoc = await _payload.create({ collection: textFieldsSlug, data: textDoc, @@ -177,7 +160,6 @@ export const seed = async (_payload: Payload) => { // media: { value: createdJPGDocSlug2.id, relationTo: uploads2Slug }, // }, // }) - const formattedID = _payload.db.defaultIDType === 'number' ? createdArrayDoc.id : `"${createdArrayDoc.id}"` @@ -193,29 +175,14 @@ export const seed = async (_payload: Payload) => { .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`), ) - const richTextBulletsDocWithRelId = JSON.parse( - JSON.stringify(richTextBulletsDocData) - .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`) - .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) - .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`), - ) - - const richTextDocWithRelationship = { ...richTextDocWithRelId } - const blocksDocWithRichText = { ...(blocksDoc as any), } + const richTextDocWithRelationship = { ...richTextDocWithRelId } blocksDocWithRichText.blocks[0].richText = richTextDocWithRelationship.richText blocksDocWithRichText.localizedBlocks[0].richText = richTextDocWithRelationship.richText - await _payload.create({ - collection: richTextFieldsSlug, - data: richTextBulletsDocWithRelId, - depth: 0, - overrideAccess: true, - }) - await _payload.create({ collection: emailFieldsSlug, data: emailDoc, @@ -230,32 +197,6 @@ export const seed = async (_payload: Payload) => { overrideAccess: true, }) - const createdRichTextDoc = await _payload.create({ - collection: richTextFieldsSlug, - data: richTextDocWithRelationship, - depth: 0, - overrideAccess: true, - }) - - const formattedRichTextDocID = - _payload.db.defaultIDType === 'number' ? createdRichTextDoc.id : `"${createdRichTextDoc.id}"` - - const lexicalDocWithRelId = JSON.parse( - JSON.stringify(lexicalDocData) - .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`) - .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) - .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`) - .replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`), - ) - - const lexicalMigrateDocWithRelId = JSON.parse( - JSON.stringify(lexicalMigrateDocData) - .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`) - .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) - .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`) - .replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`), - ) - await _payload.create({ collection: usersSlug, depth: 0, @@ -392,96 +333,6 @@ export const seed = async (_payload: Payload) => { console.error(e) } - await _payload.create({ - collection: lexicalFieldsSlug, - data: lexicalDocWithRelId, - depth: 0, - overrideAccess: true, - }) - - const lexicalLocalizedDoc1 = await _payload.create({ - collection: lexicalLocalizedFieldsSlug, - data: { - title: 'Localized Lexical en', - lexicalBlocksLocalized: textToLexicalJSON({ text: 'English text' }), - lexicalBlocksSubLocalized: generateLexicalLocalizedRichText( - 'Shared text', - 'English text in block', - ) as any, - }, - locale: 'en', - depth: 0, - overrideAccess: true, - }) - - await _payload.create({ - collection: lexicalRelationshipFieldsSlug, - data: { - richText: textToLexicalJSON({ text: 'English text' }), - }, - depth: 0, - overrideAccess: true, - }) - - await _payload.update({ - collection: lexicalLocalizedFieldsSlug, - id: lexicalLocalizedDoc1.id, - data: { - title: 'Localized Lexical es', - lexicalBlocksLocalized: textToLexicalJSON({ text: 'Spanish text' }), - lexicalBlocksSubLocalized: generateLexicalLocalizedRichText( - 'Shared text', - 'Spanish text in block', - (lexicalLocalizedDoc1.lexicalBlocksSubLocalized.root.children[1].fields as any).id, - ) as any, - }, - locale: 'es', - depth: 0, - overrideAccess: true, - }) - - const lexicalLocalizedDoc2 = await _payload.create({ - collection: lexicalLocalizedFieldsSlug, - data: { - title: 'Localized Lexical en 2', - - lexicalBlocksLocalized: textToLexicalJSON({ - text: 'English text 2', - lexicalLocalizedRelID: lexicalLocalizedDoc1.id, - }), - lexicalBlocksSubLocalized: textToLexicalJSON({ - text: 'English text 2', - lexicalLocalizedRelID: lexicalLocalizedDoc1.id, - }), - }, - locale: 'en', - depth: 0, - overrideAccess: true, - }) - - await _payload.update({ - collection: lexicalLocalizedFieldsSlug, - id: lexicalLocalizedDoc2.id, - data: { - title: 'Localized Lexical es 2', - - lexicalBlocksLocalized: textToLexicalJSON({ - text: 'Spanish text 2', - lexicalLocalizedRelID: lexicalLocalizedDoc1.id, - }), - }, - locale: 'es', - depth: 0, - overrideAccess: true, - }) - - await _payload.create({ - collection: lexicalMigrateFieldsSlug, - data: lexicalMigrateDocWithRelId, - depth: 0, - overrideAccess: true, - }) - await _payload.create({ collection: numberFieldsSlug, data: { number: 2 }, @@ -511,152 +362,6 @@ export const seed = async (_payload: Payload) => { depth: 0, }) - const getInlineBlock = () => ({ - type: 'inlineBlock', - fields: { - id: Math.random().toString(36).substring(2, 15), - text: 'text', - blockType: 'inlineBlockInLexical', - }, - version: 1, - }) - - await _payload.create({ - collection: 'LexicalInBlock', - depth: 0, - data: { - content: { - root: { - children: [ - { - format: '', - type: 'block', - version: 2, - fields: { - id: '6773773284be8978db7a498d', - lexicalInBlock: textToLexicalJSON({ text: 'text' }), - blockName: '', - blockType: 'blockInLexical', - }, - }, - ], - direction: null, - format: '', - indent: 0, - type: 'root', - version: 1, - }, - }, - blocks: [ - { - blockType: 'lexicalInBlock2', - blockName: '1', - lexical: textToLexicalJSON({ text: '1' }), - }, - { - blockType: 'lexicalInBlock2', - blockName: '2', - lexical: textToLexicalJSON({ text: '2' }), - }, - { - blockType: 'lexicalInBlock2', - lexical: { - root: { - children: [ - { - children: [...Array.from({ length: 20 }, () => getInlineBlock())], - direction: null, - format: '', - indent: 0, - type: 'paragraph', - version: 1, - textFormat: 0, - textStyle: '', - }, - ], - direction: null, - format: '', - indent: 0, - type: 'root', - version: 1, - }, - }, - id: '67e1af0b78de3228e23ef1d5', - blockName: '1', - }, - ], - }, - }) - - await _payload.create({ - collection: 'lexical-access-control', - data: { - richText: { - root: { - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'text ', - type: 'text', - version: 1, - }, - { - children: [ - { - detail: 0, - format: 0, - mode: 'normal', - style: '', - text: 'link', - type: 'text', - version: 1, - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'link', - version: 3, - fields: { - url: 'https://', - newTab: false, - linkType: 'custom', - blocks: [ - { - id: '67e45673cbd5181ca8cbeef7', - blockType: 'block', - }, - ], - }, - id: '67e4566fcbd5181ca8cbeef5', - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'paragraph', - version: 1, - textFormat: 0, - textStyle: '', - }, - ], - direction: 'ltr', - format: '', - indent: 0, - type: 'root', - version: 1, - }, - }, - title: 'title', - }, - depth: 0, - }) - await Promise.all([ _payload.create({ collection: customIDSlug, diff --git a/test/fields/slugs.ts b/test/fields/slugs.ts index e2374376ea..47c4bd6faf 100644 --- a/test/fields/slugs.ts +++ b/test/fields/slugs.ts @@ -13,18 +13,11 @@ export const emailFieldsSlug = 'email-fields' export const groupFieldsSlug = 'group-fields' export const indexedFieldsSlug = 'indexed-fields' export const jsonFieldsSlug = 'json-fields' -export const lexicalFieldsSlug = 'lexical-fields' -export const lexicalLocalizedFieldsSlug = 'lexical-localized-fields' -export const lexicalMigrateFieldsSlug = 'lexical-migrate-fields' -export const lexicalRelationshipFieldsSlug = 'lexical-relationship-fields' - -export const lexicalAccessControlSlug = 'lexical-access-control' export const numberFieldsSlug = 'number-fields' export const pointFieldsSlug = 'point-fields' export const radioFieldsSlug = 'radio-fields' export const relationshipFieldsSlug = 'relationship-fields' -export const richTextFieldsSlug = 'rich-text-fields' export const rowFieldsSlug = 'row-fields' export const selectFieldsSlug = 'select-fields' export const selectVersionsFieldsSlug = 'select-versions-fields' @@ -52,15 +45,10 @@ export const collectionSlugs = [ groupFieldsSlug, indexedFieldsSlug, jsonFieldsSlug, - lexicalFieldsSlug, - lexicalMigrateFieldsSlug, - lexicalRelationshipFieldsSlug, - lexicalAccessControlSlug, numberFieldsSlug, pointFieldsSlug, radioFieldsSlug, relationshipFieldsSlug, - richTextFieldsSlug, rowFieldsSlug, selectFieldsSlug, tabsFieldsSlug, diff --git a/test/lexical/baseConfig.ts b/test/lexical/baseConfig.ts new file mode 100644 index 0000000000..ca48a213b0 --- /dev/null +++ b/test/lexical/baseConfig.ts @@ -0,0 +1,63 @@ +import { fileURLToPath } from 'node:url' +import path from 'path' +import { type Config } from 'payload' + +import ArrayFields from './collections/Array/index.js' +import { + getLexicalFieldsCollection, + lexicalBlocks, + lexicalInlineBlocks, +} from './collections/Lexical/index.js' +import { LexicalAccessControl } from './collections/LexicalAccessControl/index.js' +import { LexicalInBlock } from './collections/LexicalInBlock/index.js' +import { LexicalLocalizedFields } from './collections/LexicalLocalized/index.js' +import { LexicalMigrateFields } from './collections/LexicalMigrate/index.js' +import { LexicalObjectReferenceBugCollection } from './collections/LexicalObjectReferenceBug/index.js' +import { LexicalRelationshipsFields } from './collections/LexicalRelationships/index.js' +import RichTextFields from './collections/RichText/index.js' +import TextFields from './collections/Text/index.js' +import Uploads from './collections/Upload/index.js' +import TabsWithRichText from './globals/TabsWithRichText.js' +import { clearAndSeedEverything } from './seed.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export const baseConfig: Partial = { + // ...extend config here + collections: [ + getLexicalFieldsCollection({ + blocks: lexicalBlocks, + inlineBlocks: lexicalInlineBlocks, + }), + LexicalMigrateFields, + LexicalLocalizedFields, + LexicalObjectReferenceBugCollection, + LexicalInBlock, + LexicalAccessControl, + LexicalRelationshipsFields, + RichTextFields, + TextFields, + Uploads, + ArrayFields, + ], + globals: [TabsWithRichText], + admin: { + importMap: { + baseDir: path.resolve(dirname), + }, + }, + onInit: async (payload) => { + if (process.env.SEED_IN_CONFIG_ONINIT !== 'false') { + await clearAndSeedEverything(payload) + } + }, + localization: { + defaultLocale: 'en', + fallback: true, + locales: ['en', 'es'], + }, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, +} diff --git a/test/lexical/collections/Array/AddRowButton.tsx b/test/lexical/collections/Array/AddRowButton.tsx new file mode 100644 index 0000000000..70ff25f80c --- /dev/null +++ b/test/lexical/collections/Array/AddRowButton.tsx @@ -0,0 +1,29 @@ +'use client' + +import { useForm } from '@payloadcms/ui' + +const AddRowButton = () => { + const { addFieldRow } = useForm() + + const handleClick = () => { + addFieldRow({ + path: 'externallyUpdatedArray', + schemaPath: 'externallyUpdatedArray', + subFieldState: { + text: { + initialValue: 'Hello, world!', + valid: true, + value: 'Hello, world!', + }, + }, + }) + } + + return ( + + ) +} + +export default AddRowButton diff --git a/test/lexical/collections/Array/CustomArrayField.tsx b/test/lexical/collections/Array/CustomArrayField.tsx new file mode 100644 index 0000000000..adad96b297 --- /dev/null +++ b/test/lexical/collections/Array/CustomArrayField.tsx @@ -0,0 +1,12 @@ +'use client' +import type { ArrayFieldClientComponent } from 'payload' + +import { ArrayField } from '@payloadcms/ui' + +export const CustomArrayField: ArrayFieldClientComponent = (props) => { + return ( +
+ +
+ ) +} diff --git a/test/lexical/collections/Array/CustomTextField.tsx b/test/lexical/collections/Array/CustomTextField.tsx new file mode 100644 index 0000000000..7bdcb8b4de --- /dev/null +++ b/test/lexical/collections/Array/CustomTextField.tsx @@ -0,0 +1,11 @@ +import type { TextFieldServerComponent } from 'payload' + +import { TextField } from '@payloadcms/ui' + +export const CustomTextField: TextFieldServerComponent = ({ clientField, path }) => { + return ( +
+ +
+ ) +} diff --git a/test/lexical/collections/Array/LabelComponent.tsx b/test/lexical/collections/Array/LabelComponent.tsx new file mode 100644 index 0000000000..2473988eab --- /dev/null +++ b/test/lexical/collections/Array/LabelComponent.tsx @@ -0,0 +1,15 @@ +'use client' + +import type { PayloadClientReactComponent, RowLabelComponent } from 'payload' + +import { useRowLabel } from '@payloadcms/ui' +import React from 'react' + +export const ArrayRowLabel: PayloadClientReactComponent = () => { + const { data } = useRowLabel<{ title: string }>() + return ( +
+ {data.title || 'Untitled'} +
+ ) +} diff --git a/test/lexical/collections/Array/index.ts b/test/lexical/collections/Array/index.ts new file mode 100644 index 0000000000..3e819094e9 --- /dev/null +++ b/test/lexical/collections/Array/index.ts @@ -0,0 +1,268 @@ +import type { CollectionConfig } from 'payload' + +import { arrayFieldsSlug } from '../../slugs.js' + +export const arrayDefaultValue = [{ text: 'row one' }, { text: 'row two' }] + +const ArrayFields: CollectionConfig = { + admin: { + enableRichTextLink: false, + }, + fields: [ + { + name: 'title', + type: 'text', + required: false, + }, + { + name: 'items', + defaultValue: arrayDefaultValue, + fields: [ + { + name: 'text', + type: 'text', + required: true, + }, + { + name: 'anotherText', + type: 'text', + }, + { + name: 'uiField', + type: 'ui', + admin: { + components: { + Field: { + path: './collections/Array/LabelComponent.js#ArrayRowLabel', + serverProps: { + // While this doesn't do anything, this will reproduce a bug where having server-only props in here will throw a "Functions cannot be passed directly to Client Components" error + someFn: () => 'Hello', + }, + }, + }, + }, + }, + { + name: 'localizedText', + type: 'text', + localized: true, + }, + { + name: 'subArray', + fields: [ + { + name: 'text', + type: 'text', + }, + { + name: 'textTwo', + label: 'Second text field', + type: 'text', + required: true, + defaultValue: 'default', + }, + { + type: 'row', + fields: [ + { + name: 'textInRow', + type: 'text', + required: true, + defaultValue: 'default', + }, + ], + }, + ], + type: 'array', + }, + ], + required: true, + type: 'array', + }, + { + name: 'collapsedArray', + admin: { + initCollapsed: true, + }, + fields: [ + { + name: 'text', + required: true, + type: 'text', + }, + ], + type: 'array', + }, + { + name: 'localized', + defaultValue: arrayDefaultValue, + fields: [ + { + name: 'text', + required: true, + type: 'text', + }, + ], + localized: true, + required: true, + type: 'array', + }, + { + name: 'readOnly', + admin: { + readOnly: true, + }, + defaultValue: [ + { + text: 'defaultValue', + }, + { + text: 'defaultValue2', + }, + ], + fields: [ + { + name: 'text', + type: 'text', + }, + ], + type: 'array', + }, + { + name: 'potentiallyEmptyArray', + fields: [ + { + name: 'text', + type: 'text', + }, + { + name: 'groupInRow', + fields: [ + { + name: 'textInGroupInRow', + type: 'text', + }, + ], + type: 'group', + }, + ], + type: 'array', + }, + { + name: 'rowLabelAsComponent', + admin: { + components: { + RowLabel: '/collections/Array/LabelComponent.js#ArrayRowLabel', + }, + description: 'Row labels rendered as react components.', + }, + fields: [ + { + name: 'title', + type: 'text', + }, + ], + type: 'array', + }, + { + name: 'arrayWithMinRows', + fields: [ + { + name: 'text', + type: 'text', + }, + ], + minRows: 2, + type: 'array', + }, + { + name: 'disableSort', + defaultValue: arrayDefaultValue, + admin: { + isSortable: false, + }, + fields: [ + { + name: 'text', + required: true, + type: 'text', + }, + ], + type: 'array', + }, + { + name: 'nestedArrayLocalized', + type: 'array', + fields: [ + { + type: 'array', + name: 'array', + fields: [ + { + name: 'text', + type: 'text', + localized: true, + }, + ], + }, + ], + }, + { + name: 'externallyUpdatedArray', + type: 'array', + fields: [ + { + name: 'customTextField', + type: 'ui', + admin: { + components: { + Field: '/collections/Array/CustomTextField.js#CustomTextField', + }, + }, + }, + ], + }, + { + name: 'customArrayField', + type: 'array', + admin: { + components: { + Field: '/collections/Array/CustomArrayField.js#CustomArrayField', + }, + }, + fields: [ + { + name: 'text', + type: 'text', + }, + ], + }, + { + name: 'ui', + type: 'ui', + admin: { + components: { + Field: '/collections/Array/AddRowButton.js', + }, + }, + }, + { + name: 'arrayWithLabels', + type: 'array', + labels: { + singular: ({ t }) => t('authentication:account'), + plural: ({ t }) => t('authentication:generate'), + }, + fields: [ + { + name: 'text', + type: 'text', + }, + ], + }, + ], + slug: arrayFieldsSlug, + versions: true, +} + +export default ArrayFields diff --git a/test/lexical/collections/Array/shared.ts b/test/lexical/collections/Array/shared.ts new file mode 100644 index 0000000000..0eb9ca7fc6 --- /dev/null +++ b/test/lexical/collections/Array/shared.ts @@ -0,0 +1,68 @@ +import type { RequiredDataFromCollection } from 'payload/types' + +import type { ArrayField } from '../../payload-types.js' + +export const arrayDoc: RequiredDataFromCollection = { + arrayWithMinRows: [ + { + text: 'first row', + }, + { + text: 'second row', + }, + ], + collapsedArray: [ + { + text: 'initialize collapsed', + }, + ], + items: [ + { + text: 'first row', + }, + { + text: 'second row', + }, + { + text: 'third row', + }, + { + text: 'fourth row', + }, + { + text: 'fifth row', + }, + { + text: 'sixth row', + }, + ], + title: 'array doc 1', +} + +export const anotherArrayDoc: RequiredDataFromCollection = { + arrayWithMinRows: [ + { + text: 'first row', + }, + { + text: 'second row', + }, + ], + collapsedArray: [ + { + text: 'initialize collapsed', + }, + ], + items: [ + { + text: 'first row', + }, + { + text: 'second row', + }, + { + text: 'third row', + }, + ], + title: 'array doc 2', +} diff --git a/test/fields/collections/Lexical/LexicalRendered.tsx b/test/lexical/collections/Lexical/LexicalRendered.tsx similarity index 100% rename from test/fields/collections/Lexical/LexicalRendered.tsx rename to test/lexical/collections/Lexical/LexicalRendered.tsx diff --git a/test/fields/collections/Lexical/ModifyInlineBlockFeature/feature.client.ts b/test/lexical/collections/Lexical/ModifyInlineBlockFeature/feature.client.ts similarity index 100% rename from test/fields/collections/Lexical/ModifyInlineBlockFeature/feature.client.ts rename to test/lexical/collections/Lexical/ModifyInlineBlockFeature/feature.client.ts diff --git a/test/fields/collections/Lexical/ModifyInlineBlockFeature/feature.server.ts b/test/lexical/collections/Lexical/ModifyInlineBlockFeature/feature.server.ts similarity index 100% rename from test/fields/collections/Lexical/ModifyInlineBlockFeature/feature.server.ts rename to test/lexical/collections/Lexical/ModifyInlineBlockFeature/feature.server.ts diff --git a/test/fields/collections/Lexical/ModifyInlineBlockFeature/plugin.tsx b/test/lexical/collections/Lexical/ModifyInlineBlockFeature/plugin.tsx similarity index 100% rename from test/fields/collections/Lexical/ModifyInlineBlockFeature/plugin.tsx rename to test/lexical/collections/Lexical/ModifyInlineBlockFeature/plugin.tsx diff --git a/test/fields/collections/Lexical/blockComponents/BlockComponent.tsx b/test/lexical/collections/Lexical/blockComponents/BlockComponent.tsx similarity index 100% rename from test/fields/collections/Lexical/blockComponents/BlockComponent.tsx rename to test/lexical/collections/Lexical/blockComponents/BlockComponent.tsx diff --git a/test/fields/collections/Lexical/blockComponents/BlockComponentRSC.tsx b/test/lexical/collections/Lexical/blockComponents/BlockComponentRSC.tsx similarity index 100% rename from test/fields/collections/Lexical/blockComponents/BlockComponentRSC.tsx rename to test/lexical/collections/Lexical/blockComponents/BlockComponentRSC.tsx diff --git a/test/fields/collections/Lexical/blockComponents/LabelComponent.tsx b/test/lexical/collections/Lexical/blockComponents/LabelComponent.tsx similarity index 100% rename from test/fields/collections/Lexical/blockComponents/LabelComponent.tsx rename to test/lexical/collections/Lexical/blockComponents/LabelComponent.tsx diff --git a/test/fields/collections/Lexical/blocks.ts b/test/lexical/collections/Lexical/blocks.ts similarity index 99% rename from test/fields/collections/Lexical/blocks.ts rename to test/lexical/collections/Lexical/blocks.ts index 28611c5148..b4886a6900 100644 --- a/test/fields/collections/Lexical/blocks.ts +++ b/test/lexical/collections/Lexical/blocks.ts @@ -2,7 +2,7 @@ import type { ArrayField, Block, TextFieldSingleValidation } from 'payload' import { BlocksFeature, FixedToolbarFeature, lexicalEditor } from '@payloadcms/richtext-lexical' -import { textFieldsSlug } from '../Text/shared.js' +import { textFieldsSlug } from '../../slugs.js' async function asyncFunction(param: string) { return new Promise((resolve) => { diff --git a/test/fields/collections/Lexical/components/ClearState.tsx b/test/lexical/collections/Lexical/components/ClearState.tsx similarity index 100% rename from test/fields/collections/Lexical/components/ClearState.tsx rename to test/lexical/collections/Lexical/components/ClearState.tsx diff --git a/test/fields/collections/Lexical/data.ts b/test/lexical/collections/Lexical/data.ts similarity index 100% rename from test/fields/collections/Lexical/data.ts rename to test/lexical/collections/Lexical/data.ts diff --git a/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts b/test/lexical/collections/Lexical/e2e/blocks/e2e.spec.ts similarity index 100% rename from test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts rename to test/lexical/collections/Lexical/e2e/blocks/e2e.spec.ts diff --git a/test/fields/collections/Lexical/e2e/main/e2e.spec.ts b/test/lexical/collections/Lexical/e2e/main/e2e.spec.ts similarity index 98% rename from test/fields/collections/Lexical/e2e/main/e2e.spec.ts rename to test/lexical/collections/Lexical/e2e/main/e2e.spec.ts index a6eb05fc82..44df6e68b4 100644 --- a/test/fields/collections/Lexical/e2e/main/e2e.spec.ts +++ b/test/lexical/collections/Lexical/e2e/main/e2e.spec.ts @@ -514,21 +514,8 @@ describe('lexicalMain', () => { await wait(500) await expect(page.locator('.shimmer-effect')).toHaveCount(0) - await uploadListDrawer.locator('.rs__control .value-container').first().click() - await wait(500) - await expect(uploadListDrawer.locator('.rs__option').nth(1)).toBeVisible() - await expect(uploadListDrawer.locator('.rs__option').nth(1)).toContainText('Upload 2') - await uploadListDrawer.locator('.rs__option').nth(1).click() - - // wait till the text appears in uploadListDrawer: "No Uploads 2 found. Either no Uploads 2 exist yet or none match the filters you've specified above." - await expect( - uploadListDrawer.getByText( - "No Uploads 2 found. Either no Uploads 2 exist yet or none match the filters you've specified above.", - ), - ).toBeVisible() - - await uploadListDrawer.getByText('Create New').first().click() - const createUploadDrawer = page.locator('dialog[id^=doc-drawer_uploads2_]').first() // IDs starting with list-drawer_1_ (there's some other symbol after the underscore) + await page.getByRole('dialog').getByLabel('Add new Upload').first().click() + const createUploadDrawer = page.locator('dialog[id^=doc-drawer_uploads_]').first() // IDs starting with list-drawer_1_ (there's some other symbol after the underscore) await expect(createUploadDrawer).toBeVisible() await wait(500) @@ -555,10 +542,10 @@ describe('lexicalMain', () => { await expect(secondUploadNode).toBeVisible() await expect(secondUploadNode.locator('.lexical-upload__bottomRow')).toContainText( - 'payload.jpg', + 'payload-1.jpg', ) await expect(secondUploadNode.locator('.lexical-upload__collectionLabel')).toContainText( - 'Upload 2', + 'Upload', ) }) diff --git a/test/fields/collections/Lexical/generateLexicalRichText.ts b/test/lexical/collections/Lexical/generateLexicalRichText.ts similarity index 100% rename from test/fields/collections/Lexical/generateLexicalRichText.ts rename to test/lexical/collections/Lexical/generateLexicalRichText.ts diff --git a/test/fields/collections/Lexical/index.ts b/test/lexical/collections/Lexical/index.ts similarity index 100% rename from test/fields/collections/Lexical/index.ts rename to test/lexical/collections/Lexical/index.ts diff --git a/test/fields/collections/Lexical/inlineBlockComponents/BlockComponent.tsx b/test/lexical/collections/Lexical/inlineBlockComponents/BlockComponent.tsx similarity index 100% rename from test/fields/collections/Lexical/inlineBlockComponents/BlockComponent.tsx rename to test/lexical/collections/Lexical/inlineBlockComponents/BlockComponent.tsx diff --git a/test/fields/collections/Lexical/inlineBlockComponents/LabelComponent.tsx b/test/lexical/collections/Lexical/inlineBlockComponents/LabelComponent.tsx similarity index 100% rename from test/fields/collections/Lexical/inlineBlockComponents/LabelComponent.tsx rename to test/lexical/collections/Lexical/inlineBlockComponents/LabelComponent.tsx diff --git a/test/fields/collections/Lexical/loremIpsum.ts b/test/lexical/collections/Lexical/loremIpsum.ts similarity index 100% rename from test/fields/collections/Lexical/loremIpsum.ts rename to test/lexical/collections/Lexical/loremIpsum.ts diff --git a/test/fields/collections/LexicalAccessControl/index.ts b/test/lexical/collections/LexicalAccessControl/index.ts similarity index 100% rename from test/fields/collections/LexicalAccessControl/index.ts rename to test/lexical/collections/LexicalAccessControl/index.ts diff --git a/test/fields/collections/LexicalInBlock/index.ts b/test/lexical/collections/LexicalInBlock/index.ts similarity index 100% rename from test/fields/collections/LexicalInBlock/index.ts rename to test/lexical/collections/LexicalInBlock/index.ts diff --git a/test/fields/collections/LexicalLocalized/generateLexicalRichText.ts b/test/lexical/collections/LexicalLocalized/generateLexicalRichText.ts similarity index 100% rename from test/fields/collections/LexicalLocalized/generateLexicalRichText.ts rename to test/lexical/collections/LexicalLocalized/generateLexicalRichText.ts diff --git a/test/fields/collections/LexicalLocalized/index.ts b/test/lexical/collections/LexicalLocalized/index.ts similarity index 100% rename from test/fields/collections/LexicalLocalized/index.ts rename to test/lexical/collections/LexicalLocalized/index.ts diff --git a/test/fields/collections/LexicalLocalized/textToLexicalJSON.ts b/test/lexical/collections/LexicalLocalized/textToLexicalJSON.ts similarity index 100% rename from test/fields/collections/LexicalLocalized/textToLexicalJSON.ts rename to test/lexical/collections/LexicalLocalized/textToLexicalJSON.ts diff --git a/test/fields/collections/LexicalMigrate/data.ts b/test/lexical/collections/LexicalMigrate/data.ts similarity index 100% rename from test/fields/collections/LexicalMigrate/data.ts rename to test/lexical/collections/LexicalMigrate/data.ts diff --git a/test/fields/collections/LexicalMigrate/generatePayloadPluginLexicalData.ts b/test/lexical/collections/LexicalMigrate/generatePayloadPluginLexicalData.ts similarity index 100% rename from test/fields/collections/LexicalMigrate/generatePayloadPluginLexicalData.ts rename to test/lexical/collections/LexicalMigrate/generatePayloadPluginLexicalData.ts diff --git a/test/fields/collections/LexicalMigrate/index.ts b/test/lexical/collections/LexicalMigrate/index.ts similarity index 100% rename from test/fields/collections/LexicalMigrate/index.ts rename to test/lexical/collections/LexicalMigrate/index.ts diff --git a/test/fields/collections/LexicalMigrate/shared.ts b/test/lexical/collections/LexicalMigrate/shared.ts similarity index 100% rename from test/fields/collections/LexicalMigrate/shared.ts rename to test/lexical/collections/LexicalMigrate/shared.ts diff --git a/test/fields/collections/LexicalObjectReferenceBug/index.ts b/test/lexical/collections/LexicalObjectReferenceBug/index.ts similarity index 100% rename from test/fields/collections/LexicalObjectReferenceBug/index.ts rename to test/lexical/collections/LexicalObjectReferenceBug/index.ts diff --git a/test/fields/collections/LexicalRelationships/index.ts b/test/lexical/collections/LexicalRelationships/index.ts similarity index 100% rename from test/fields/collections/LexicalRelationships/index.ts rename to test/lexical/collections/LexicalRelationships/index.ts diff --git a/test/fields/collections/RichText/blocks.ts b/test/lexical/collections/RichText/blocks.ts similarity index 100% rename from test/fields/collections/RichText/blocks.ts rename to test/lexical/collections/RichText/blocks.ts diff --git a/test/fields/collections/RichText/data.ts b/test/lexical/collections/RichText/data.ts similarity index 100% rename from test/fields/collections/RichText/data.ts rename to test/lexical/collections/RichText/data.ts diff --git a/test/fields/collections/RichText/e2e.spec.ts b/test/lexical/collections/RichText/e2e.spec.ts similarity index 95% rename from test/fields/collections/RichText/e2e.spec.ts rename to test/lexical/collections/RichText/e2e.spec.ts index ac5afdaafe..ae6227ebfe 100644 --- a/test/fields/collections/RichText/e2e.spec.ts +++ b/test/lexical/collections/RichText/e2e.spec.ts @@ -182,27 +182,6 @@ describe('Rich Text', () => { await expect(modalTrigger).toBeDisabled() }) - test('should only list RTE enabled upload collections in drawer', async () => { - await navigateToRichTextFields() - await wait(1000) - - // Open link drawer - await page - .locator('.rich-text__toolbar button:not([disabled]) .upload-rich-text-button') - .first() - .click() - - const drawer = page.locator('[id^=list-drawer_1_]') - await expect(drawer).toBeVisible() - - // open the list select menu - await page.locator('.list-drawer__select-collection-wrap .rs__control').click() - - const menu = page.locator('.list-drawer__select-collection-wrap .rs__menu') - // `uploads-3` has enableRichTextRelationship set to false - await expect(menu).not.toContainText('Uploads3') - }) - // TODO: this test can't find the selector for the search filter, but functionality works. // Need to debug test.skip('should search correct useAsTitle field after toggling collection in list drawer', async () => { diff --git a/test/fields/collections/RichText/generateLexicalRichText.ts b/test/lexical/collections/RichText/generateLexicalRichText.ts similarity index 100% rename from test/fields/collections/RichText/generateLexicalRichText.ts rename to test/lexical/collections/RichText/generateLexicalRichText.ts diff --git a/test/fields/collections/RichText/generateSlateRichText.ts b/test/lexical/collections/RichText/generateSlateRichText.ts similarity index 100% rename from test/fields/collections/RichText/generateSlateRichText.ts rename to test/lexical/collections/RichText/generateSlateRichText.ts diff --git a/test/fields/collections/RichText/index.ts b/test/lexical/collections/RichText/index.ts similarity index 100% rename from test/fields/collections/RichText/index.ts rename to test/lexical/collections/RichText/index.ts diff --git a/test/fields/collections/RichText/loremIpsum.ts b/test/lexical/collections/RichText/loremIpsum.ts similarity index 100% rename from test/fields/collections/RichText/loremIpsum.ts rename to test/lexical/collections/RichText/loremIpsum.ts diff --git a/test/lexical/collections/Text/CustomDescription.tsx b/test/lexical/collections/Text/CustomDescription.tsx new file mode 100644 index 0000000000..2df96191cc --- /dev/null +++ b/test/lexical/collections/Text/CustomDescription.tsx @@ -0,0 +1,5 @@ +import React from 'react' + +export default function CustomDescription() { + return
Custom Description
+} diff --git a/test/lexical/collections/Text/index.ts b/test/lexical/collections/Text/index.ts new file mode 100644 index 0000000000..4d1d5f8726 --- /dev/null +++ b/test/lexical/collections/Text/index.ts @@ -0,0 +1,200 @@ +import type { CollectionConfig } from 'payload' + +import { defaultText, textFieldsSlug } from './shared.js' + +const TextFields: CollectionConfig = { + slug: textFieldsSlug, + admin: { + useAsTitle: 'text', + }, + defaultSort: 'id', + fields: [ + { + name: 'text', + type: 'text', + required: true, + hooks: { + beforeDuplicate: [({ value }) => `${value} - duplicate`], + }, + }, + { + name: 'hiddenTextField', + type: 'text', + hidden: true, + }, + { + name: 'adminHiddenTextField', + type: 'text', + admin: { + hidden: true, + description: 'This field should be hidden', + }, + }, + { + name: 'disabledTextField', + type: 'text', + admin: { + disabled: true, + description: 'This field should be disabled', + }, + }, + { + type: 'row', + admin: { + components: { + Field: './components/CustomField.tsx#CustomField', + }, + }, + fields: [], + }, + { + name: 'localizedText', + type: 'text', + localized: true, + }, + { + name: 'i18nText', + type: 'text', + admin: { + description: { + en: 'en description', + es: 'es description', + }, + placeholder: { + en: 'en placeholder', + es: 'es placeholder', + }, + }, + label: { + en: 'Text en', + es: 'Text es', + }, + }, + { + name: 'defaultString', + type: 'text', + defaultValue: defaultText, + }, + { + name: 'defaultEmptyString', + type: 'text', + defaultValue: '', + }, + { + name: 'defaultFunction', + type: 'text', + defaultValue: () => defaultText, + }, + { + name: 'defaultAsync', + type: 'text', + defaultValue: async (): Promise => { + return new Promise((resolve) => + setTimeout(() => { + resolve(defaultText) + }, 1), + ) + }, + }, + { + name: 'overrideLength', + type: 'text', + label: 'Override the 40k text length default', + maxLength: 50000, + }, + { + name: 'fieldWithDefaultValue', + type: 'text', + defaultValue: async () => { + const defaultValue = new Promise((resolve) => setTimeout(() => resolve('some-value'), 1000)) + + return defaultValue + }, + }, + { + name: 'dependentOnFieldWithDefaultValue', + type: 'text', + hooks: { + beforeChange: [ + ({ data }) => { + return data?.fieldWithDefaultValue || '' + }, + ], + }, + }, + { + name: 'hasMany', + type: 'text', + hasMany: true, + }, + { + name: 'readOnlyHasMany', + type: 'text', + hasMany: true, + admin: { + readOnly: true, + }, + defaultValue: ['default'], + }, + { + name: 'validatesHasMany', + type: 'text', + hasMany: true, + minLength: 3, + }, + { + name: 'localizedHasMany', + type: 'text', + hasMany: true, + localized: true, + }, + { + name: 'withMinRows', + type: 'text', + hasMany: true, + minRows: 2, + }, + { + name: 'withMaxRows', + type: 'text', + hasMany: true, + maxRows: 4, + }, + { + name: 'defaultValueFromReq', + type: 'text', + defaultValue: async ({ req }) => { + return Promise.resolve(req.context.defaultValue) + }, + }, + { + name: 'array', + type: 'array', + fields: [ + { + name: 'texts', + type: 'text', + hasMany: true, + }, + ], + }, + { + name: 'blocks', + type: 'blocks', + blocks: [ + { + slug: 'blockWithText', + fields: [ + { + name: 'texts', + type: 'text', + hasMany: true, + }, + ], + }, + ], + }, + ], +} + +export default TextFields diff --git a/test/lexical/collections/Text/shared.ts b/test/lexical/collections/Text/shared.ts new file mode 100644 index 0000000000..34c20ba0d4 --- /dev/null +++ b/test/lexical/collections/Text/shared.ts @@ -0,0 +1,15 @@ +import type { RequiredDataFromCollection } from 'payload/types' + +import type { TextField } from '../../payload-types.js' + +export const defaultText = 'default-text' +export const textFieldsSlug = 'text-fields' + +export const textDoc: RequiredDataFromCollection = { + text: 'Seeded text document', + localizedText: 'Localized text', +} + +export const anotherTextDoc: RequiredDataFromCollection = { + text: 'Another text document', +} diff --git a/test/lexical/collections/Upload/.gitignore b/test/lexical/collections/Upload/.gitignore new file mode 100644 index 0000000000..3f549faf91 --- /dev/null +++ b/test/lexical/collections/Upload/.gitignore @@ -0,0 +1 @@ +uploads diff --git a/test/lexical/collections/Upload/index.ts b/test/lexical/collections/Upload/index.ts new file mode 100644 index 0000000000..e74514a461 --- /dev/null +++ b/test/lexical/collections/Upload/index.ts @@ -0,0 +1,37 @@ +import type { CollectionConfig } from 'payload' + +import path from 'path' +import { fileURLToPath } from 'url' + +import { uploadsSlug } from '../../slugs.js' +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +const Uploads: CollectionConfig = { + slug: uploadsSlug, + fields: [ + { + name: 'text', + type: 'text', + }, + { + name: 'media', + type: 'upload', + filterOptions: { + mimeType: { + equals: 'image/png', + }, + }, + relationTo: uploadsSlug, + }, + // { + // name: 'richText', + // type: 'richText', + // }, + ], + upload: { + staticDir: path.resolve(dirname, './uploads'), + }, +} + +export default Uploads diff --git a/test/lexical/collections/Upload/payload.jpg b/test/lexical/collections/Upload/payload.jpg new file mode 100644 index 0000000000..6197f6a2c3 Binary files /dev/null and b/test/lexical/collections/Upload/payload.jpg differ diff --git a/test/lexical/collections/Upload/shared.ts b/test/lexical/collections/Upload/shared.ts new file mode 100644 index 0000000000..aa1f5c70dc --- /dev/null +++ b/test/lexical/collections/Upload/shared.ts @@ -0,0 +1,5 @@ +import type { Upload } from '../../payload-types.js' + +export const uploadsDoc: Partial = { + text: 'An upload here', +} diff --git a/test/lexical/components/CustomField.tsx b/test/lexical/components/CustomField.tsx new file mode 100644 index 0000000000..51327976d2 --- /dev/null +++ b/test/lexical/components/CustomField.tsx @@ -0,0 +1,9 @@ +'use client' + +import type { TextFieldClientComponent } from 'payload' + +import React from 'react' + +export const CustomField: TextFieldClientComponent = ({ schemaPath }) => { + return
{schemaPath}
+} diff --git a/test/lexical/config.blockreferences.ts b/test/lexical/config.blockreferences.ts new file mode 100644 index 0000000000..ee01d50725 --- /dev/null +++ b/test/lexical/config.blockreferences.ts @@ -0,0 +1,36 @@ +/* eslint-disable no-restricted-exports */ + +import type { BlockSlug } from 'payload' + +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { autoDedupeBlocksPlugin } from '../helpers/autoDedupeBlocksPlugin/index.js' +import { baseConfig } from './baseConfig.js' +import { + getLexicalFieldsCollection, + lexicalBlocks, + lexicalInlineBlocks, +} from './collections/Lexical/index.js' +import { lexicalFieldsSlug } from './slugs.js' + +export default buildConfigWithDefaults({ + ...baseConfig, + blocks: [ + ...(baseConfig.blocks ?? []), + ...lexicalBlocks.filter((block) => typeof block !== 'string'), + ...lexicalInlineBlocks.filter((block) => typeof block !== 'string'), + ], + collections: baseConfig.collections?.map((collection) => { + if (collection.slug === lexicalFieldsSlug) { + return getLexicalFieldsCollection({ + blocks: lexicalBlocks.map((block) => + typeof block === 'string' ? block : block.slug, + ) as BlockSlug[], + inlineBlocks: lexicalInlineBlocks.map((block) => + typeof block === 'string' ? block : block.slug, + ) as BlockSlug[], + }) + } + return collection + }), + plugins: [autoDedupeBlocksPlugin({ silent: false })], +}) diff --git a/test/lexical/config.ts b/test/lexical/config.ts new file mode 100644 index 0000000000..22c3b1d82c --- /dev/null +++ b/test/lexical/config.ts @@ -0,0 +1,5 @@ +/* eslint-disable no-restricted-exports */ +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { baseConfig } from './baseConfig.js' + +export default buildConfigWithDefaults(baseConfig) diff --git a/test/fields/globals/TabsWithRichText.ts b/test/lexical/globals/TabsWithRichText.ts similarity index 100% rename from test/fields/globals/TabsWithRichText.ts rename to test/lexical/globals/TabsWithRichText.ts diff --git a/test/fields/lexical.int.spec.ts b/test/lexical/lexical.int.spec.ts similarity index 92% rename from test/fields/lexical.int.spec.ts rename to test/lexical/lexical.int.spec.ts index 865be617f1..1c06b3c949 100644 --- a/test/fields/lexical.int.spec.ts +++ b/test/lexical/lexical.int.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable jest/no-conditional-in-test */ import type { SerializedBlockNode, SerializedLinkNode, @@ -679,4 +680,71 @@ describe('Lexical', () => { ).toEqual(210) // Initial: 20. BeforeChange: +1 (21). AfterRead: *10 (210) }) }) + + describe('richText', () => { + it('should allow querying on rich text content', async () => { + const emptyRichTextQuery = await payload.find({ + collection: 'rich-text-fields', + where: { + 'richText.children.text': { + like: 'doesnt exist', + }, + }, + }) + + expect(emptyRichTextQuery.docs).toHaveLength(0) + + const workingRichTextQuery = await payload.find({ + collection: 'rich-text-fields', + where: { + 'richText.children.text': { + like: 'hello', + }, + }, + }) + + expect(workingRichTextQuery.docs).toHaveLength(1) + }) + + it('should show center alignment', async () => { + const query = await payload.find({ + collection: 'rich-text-fields', + where: { + 'richText.children.text': { + like: 'hello', + }, + }, + }) + + expect(query.docs[0]?.richText[0]?.textAlign).toEqual('center') + }) + + it('should populate link relationship', async () => { + const query = await payload.find({ + collection: 'rich-text-fields', + where: { + 'richText.children.linkType': { + equals: 'internal', + }, + }, + }) + + const nodes = query.docs[0]?.richText + expect(nodes).toBeDefined() + const child = nodes?.flatMap((n) => n.children).find((c) => c?.doc) + expect(child).toMatchObject({ + type: 'link', + linkType: 'internal', + }) + expect(child.doc.relationTo).toEqual('array-fields') + + if (payload.db.defaultIDType === 'number') { + expect(typeof child.doc.value.id).toBe('number') + } else { + expect(typeof child.doc.value.id).toBe('string') + } + + expect(child.doc.value.items).toHaveLength(6) + }) + }) }) diff --git a/test/lexical/payload-types.ts b/test/lexical/payload-types.ts new file mode 100644 index 0000000000..73373c85c9 --- /dev/null +++ b/test/lexical/payload-types.ts @@ -0,0 +1,1311 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * This file was automatically generated by Payload. + * DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config, + * and re-run `payload generate:types` to regenerate this file. + */ + +/** + * Supported timezones in IANA format. + * + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "supportedTimezones". + */ +export type SupportedTimezones = + | 'Pacific/Midway' + | 'Pacific/Niue' + | 'Pacific/Honolulu' + | 'Pacific/Rarotonga' + | 'America/Anchorage' + | 'Pacific/Gambier' + | 'America/Los_Angeles' + | 'America/Tijuana' + | 'America/Denver' + | 'America/Phoenix' + | 'America/Chicago' + | 'America/Guatemala' + | 'America/New_York' + | 'America/Bogota' + | 'America/Caracas' + | 'America/Santiago' + | 'America/Buenos_Aires' + | 'America/Sao_Paulo' + | 'Atlantic/South_Georgia' + | 'Atlantic/Azores' + | 'Atlantic/Cape_Verde' + | 'Europe/London' + | 'Europe/Berlin' + | 'Africa/Lagos' + | 'Europe/Athens' + | 'Africa/Cairo' + | 'Europe/Moscow' + | 'Asia/Riyadh' + | 'Asia/Dubai' + | 'Asia/Baku' + | 'Asia/Karachi' + | 'Asia/Tashkent' + | 'Asia/Calcutta' + | 'Asia/Dhaka' + | 'Asia/Almaty' + | 'Asia/Jakarta' + | 'Asia/Bangkok' + | 'Asia/Shanghai' + | 'Asia/Singapore' + | 'Asia/Tokyo' + | 'Asia/Seoul' + | 'Australia/Brisbane' + | 'Australia/Sydney' + | 'Pacific/Guam' + | 'Pacific/Noumea' + | 'Pacific/Auckland' + | 'Pacific/Fiji'; +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "BlockColumns". + */ +export type BlockColumns = + | { + text?: string | null; + subArray?: + | { + requiredText: string; + id?: string | null; + }[] + | null; + id?: string | null; + }[] + | null; + +export interface Config { + auth: { + users: UserAuthOperations; + }; + blocks: {}; + collections: { + 'lexical-fields': LexicalField; + 'lexical-migrate-fields': LexicalMigrateField; + 'lexical-localized-fields': LexicalLocalizedField; + lexicalObjectReferenceBug: LexicalObjectReferenceBug; + LexicalInBlock: LexicalInBlock; + 'lexical-access-control': LexicalAccessControl; + 'lexical-relationship-fields': LexicalRelationshipField; + 'rich-text-fields': RichTextField; + 'text-fields': TextField; + uploads: Upload; + 'array-fields': ArrayField; + users: User; + 'payload-locked-documents': PayloadLockedDocument; + 'payload-preferences': PayloadPreference; + 'payload-migrations': PayloadMigration; + }; + collectionsJoins: {}; + collectionsSelect: { + 'lexical-fields': LexicalFieldsSelect | LexicalFieldsSelect; + 'lexical-migrate-fields': LexicalMigrateFieldsSelect | LexicalMigrateFieldsSelect; + 'lexical-localized-fields': LexicalLocalizedFieldsSelect | LexicalLocalizedFieldsSelect; + lexicalObjectReferenceBug: LexicalObjectReferenceBugSelect | LexicalObjectReferenceBugSelect; + LexicalInBlock: LexicalInBlockSelect | LexicalInBlockSelect; + 'lexical-access-control': LexicalAccessControlSelect | LexicalAccessControlSelect; + 'lexical-relationship-fields': LexicalRelationshipFieldsSelect | LexicalRelationshipFieldsSelect; + 'rich-text-fields': RichTextFieldsSelect | RichTextFieldsSelect; + 'text-fields': TextFieldsSelect | TextFieldsSelect; + uploads: UploadsSelect | UploadsSelect; + 'array-fields': ArrayFieldsSelect | ArrayFieldsSelect; + users: UsersSelect | UsersSelect; + 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; + 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; + 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; + }; + db: { + defaultIDType: string; + }; + globals: { + tabsWithRichText: TabsWithRichText; + }; + globalsSelect: { + tabsWithRichText: TabsWithRichTextSelect | TabsWithRichTextSelect; + }; + locale: 'en' | 'es'; + user: User & { + collection: 'users'; + }; + jobs: { + tasks: unknown; + workflows: unknown; + }; +} +export interface UserAuthOperations { + forgotPassword: { + email: string; + password: string; + }; + login: { + email: string; + password: string; + }; + registerFirstUser: { + email: string; + password: string; + }; + unlock: { + email: string; + password: string; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-fields". + */ +export interface LexicalField { + id: string; + title: string; + lexicalRootEditor?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalSimple?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalWithBlocks: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + }; + lexicalWithBlocks_markdown?: string | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-migrate-fields". + */ +export interface LexicalMigrateField { + id: string; + title: string; + lexicalWithLexicalPluginData?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalWithSlateData?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalSimple?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalSimple_html?: string | null; + groupWithLexicalField?: { + lexicalInGroupField?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalInGroupField_html?: string | null; + }; + arrayWithLexicalField?: + | { + lexicalInArrayField?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalInArrayField_html?: string | null; + id?: string | null; + }[] + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-localized-fields". + */ +export interface LexicalLocalizedField { + id: string; + title: string; + /** + * Non-localized field with localized block subfields + */ + lexicalBlocksSubLocalized?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + /** + * Localized field with localized block subfields + */ + lexicalBlocksLocalized?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexicalObjectReferenceBug". + */ +export interface LexicalObjectReferenceBug { + id: string; + lexicalDefault?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalEditor?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "LexicalInBlock". + */ +export interface LexicalInBlock { + id: string; + content?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + blocks?: + | { + lexical?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + id?: string | null; + blockName?: string | null; + blockType: 'lexicalInBlock2'; + }[] + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-access-control". + */ +export interface LexicalAccessControl { + id: string; + title?: string | null; + richText?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-relationship-fields". + */ +export interface LexicalRelationshipField { + id: string; + richText?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + richText2?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "rich-text-fields". + */ +export interface RichTextField { + id: string; + title: string; + lexicalCustomFields: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + }; + lexicalCustomFields_html?: string | null; + /** + * This rich text field uses the lexical editor. + */ + lexical?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + /** + * This select field is rendered here to ensure its options dropdown renders above the rich text toolbar. + */ + selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null; + richText: { + [k: string]: unknown; + }[]; + richTextCustomFields?: + | { + [k: string]: unknown; + }[] + | null; + richTextReadOnly?: + | { + [k: string]: unknown; + }[] + | null; + blocks?: + | ( + | { + text?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'textBlock'; + } + | { + text?: + | { + [k: string]: unknown; + }[] + | null; + id?: string | null; + blockName?: string | null; + blockType: 'richTextBlockSlate'; + } + )[] + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "text-fields". + */ +export interface TextField { + id: string; + text: string; + hiddenTextField?: string | null; + /** + * This field should be hidden + */ + adminHiddenTextField?: string | null; + /** + * This field should be disabled + */ + disabledTextField?: string | null; + localizedText?: string | null; + /** + * en description + */ + i18nText?: string | null; + defaultString?: string | null; + defaultEmptyString?: string | null; + defaultFunction?: string | null; + defaultAsync?: string | null; + overrideLength?: string | null; + fieldWithDefaultValue?: string | null; + dependentOnFieldWithDefaultValue?: string | null; + hasMany?: string[] | null; + readOnlyHasMany?: string[] | null; + validatesHasMany?: string[] | null; + localizedHasMany?: string[] | null; + withMinRows?: string[] | null; + withMaxRows?: string[] | null; + defaultValueFromReq?: string | null; + array?: + | { + texts?: string[] | null; + id?: string | null; + }[] + | null; + blocks?: + | { + texts?: string[] | null; + id?: string | null; + blockName?: string | null; + blockType: 'blockWithText'; + }[] + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "uploads". + */ +export interface Upload { + id: string; + text?: string | null; + media?: (string | null) | Upload; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "array-fields". + */ +export interface ArrayField { + id: string; + title?: string | null; + items: { + text: string; + anotherText?: string | null; + localizedText?: string | null; + subArray?: + | { + text?: string | null; + textTwo: string; + textInRow: string; + id?: string | null; + }[] + | null; + id?: string | null; + }[]; + collapsedArray?: + | { + text: string; + id?: string | null; + }[] + | null; + localized: { + text: string; + id?: string | null; + }[]; + readOnly?: + | { + text?: string | null; + id?: string | null; + }[] + | null; + potentiallyEmptyArray?: + | { + text?: string | null; + groupInRow?: { + textInGroupInRow?: string | null; + }; + id?: string | null; + }[] + | null; + /** + * Row labels rendered as react components. + */ + rowLabelAsComponent?: + | { + title?: string | null; + id?: string | null; + }[] + | null; + arrayWithMinRows?: + | { + text?: string | null; + id?: string | null; + }[] + | null; + disableSort?: + | { + text: string; + id?: string | null; + }[] + | null; + nestedArrayLocalized?: + | { + array?: + | { + text?: string | null; + id?: string | null; + }[] + | null; + id?: string | null; + }[] + | null; + externallyUpdatedArray?: + | { + id?: string | null; + }[] + | null; + customArrayField?: + | { + text?: string | null; + id?: string | null; + }[] + | null; + arrayWithLabels?: + | { + text?: string | null; + id?: string | null; + }[] + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users". + */ +export interface User { + id: string; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + password?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents". + */ +export interface PayloadLockedDocument { + id: string; + document?: + | ({ + relationTo: 'lexical-fields'; + value: string | LexicalField; + } | null) + | ({ + relationTo: 'lexical-migrate-fields'; + value: string | LexicalMigrateField; + } | null) + | ({ + relationTo: 'lexical-localized-fields'; + value: string | LexicalLocalizedField; + } | null) + | ({ + relationTo: 'lexicalObjectReferenceBug'; + value: string | LexicalObjectReferenceBug; + } | null) + | ({ + relationTo: 'LexicalInBlock'; + value: string | LexicalInBlock; + } | null) + | ({ + relationTo: 'lexical-access-control'; + value: string | LexicalAccessControl; + } | null) + | ({ + relationTo: 'lexical-relationship-fields'; + value: string | LexicalRelationshipField; + } | null) + | ({ + relationTo: 'rich-text-fields'; + value: string | RichTextField; + } | null) + | ({ + relationTo: 'text-fields'; + value: string | TextField; + } | null) + | ({ + relationTo: 'uploads'; + value: string | Upload; + } | null) + | ({ + relationTo: 'array-fields'; + value: string | ArrayField; + } | null) + | ({ + relationTo: 'users'; + value: string | User; + } | null); + globalSlug?: string | null; + user: { + relationTo: 'users'; + value: string | User; + }; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences". + */ +export interface PayloadPreference { + id: string; + user: { + relationTo: 'users'; + value: string | User; + }; + key?: string | null; + value?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations". + */ +export interface PayloadMigration { + id: string; + name?: string | null; + batch?: number | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-fields_select". + */ +export interface LexicalFieldsSelect { + title?: T; + lexicalRootEditor?: T; + lexicalSimple?: T; + lexicalWithBlocks?: T; + lexicalWithBlocks_markdown?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-migrate-fields_select". + */ +export interface LexicalMigrateFieldsSelect { + title?: T; + lexicalWithLexicalPluginData?: T; + lexicalWithSlateData?: T; + lexicalSimple?: T; + lexicalSimple_html?: T; + groupWithLexicalField?: + | T + | { + lexicalInGroupField?: T; + lexicalInGroupField_html?: T; + }; + arrayWithLexicalField?: + | T + | { + lexicalInArrayField?: T; + lexicalInArrayField_html?: T; + id?: T; + }; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-localized-fields_select". + */ +export interface LexicalLocalizedFieldsSelect { + title?: T; + lexicalBlocksSubLocalized?: T; + lexicalBlocksLocalized?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexicalObjectReferenceBug_select". + */ +export interface LexicalObjectReferenceBugSelect { + lexicalDefault?: T; + lexicalEditor?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "LexicalInBlock_select". + */ +export interface LexicalInBlockSelect { + content?: T; + blocks?: + | T + | { + lexicalInBlock2?: + | T + | { + lexical?: T; + id?: T; + blockName?: T; + }; + }; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-access-control_select". + */ +export interface LexicalAccessControlSelect { + title?: T; + richText?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "lexical-relationship-fields_select". + */ +export interface LexicalRelationshipFieldsSelect { + richText?: T; + richText2?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "rich-text-fields_select". + */ +export interface RichTextFieldsSelect { + title?: T; + lexicalCustomFields?: T; + lexicalCustomFields_html?: T; + lexical?: T; + selectHasMany?: T; + richText?: T; + richTextCustomFields?: T; + richTextReadOnly?: T; + blocks?: + | T + | { + textBlock?: + | T + | { + text?: T; + id?: T; + blockName?: T; + }; + richTextBlockSlate?: + | T + | { + text?: T; + id?: T; + blockName?: T; + }; + }; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "text-fields_select". + */ +export interface TextFieldsSelect { + text?: T; + hiddenTextField?: T; + adminHiddenTextField?: T; + disabledTextField?: T; + localizedText?: T; + i18nText?: T; + defaultString?: T; + defaultEmptyString?: T; + defaultFunction?: T; + defaultAsync?: T; + overrideLength?: T; + fieldWithDefaultValue?: T; + dependentOnFieldWithDefaultValue?: T; + hasMany?: T; + readOnlyHasMany?: T; + validatesHasMany?: T; + localizedHasMany?: T; + withMinRows?: T; + withMaxRows?: T; + defaultValueFromReq?: T; + array?: + | T + | { + texts?: T; + id?: T; + }; + blocks?: + | T + | { + blockWithText?: + | T + | { + texts?: T; + id?: T; + blockName?: T; + }; + }; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "uploads_select". + */ +export interface UploadsSelect { + text?: T; + media?: T; + updatedAt?: T; + createdAt?: T; + url?: T; + thumbnailURL?: T; + filename?: T; + mimeType?: T; + filesize?: T; + width?: T; + height?: T; + focalX?: T; + focalY?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "array-fields_select". + */ +export interface ArrayFieldsSelect { + title?: T; + items?: + | T + | { + text?: T; + anotherText?: T; + localizedText?: T; + subArray?: + | T + | { + text?: T; + textTwo?: T; + textInRow?: T; + id?: T; + }; + id?: T; + }; + collapsedArray?: + | T + | { + text?: T; + id?: T; + }; + localized?: + | T + | { + text?: T; + id?: T; + }; + readOnly?: + | T + | { + text?: T; + id?: T; + }; + potentiallyEmptyArray?: + | T + | { + text?: T; + groupInRow?: + | T + | { + textInGroupInRow?: T; + }; + id?: T; + }; + rowLabelAsComponent?: + | T + | { + title?: T; + id?: T; + }; + arrayWithMinRows?: + | T + | { + text?: T; + id?: T; + }; + disableSort?: + | T + | { + text?: T; + id?: T; + }; + nestedArrayLocalized?: + | T + | { + array?: + | T + | { + text?: T; + id?: T; + }; + id?: T; + }; + externallyUpdatedArray?: + | T + | { + id?: T; + }; + customArrayField?: + | T + | { + text?: T; + id?: T; + }; + arrayWithLabels?: + | T + | { + text?: T; + id?: T; + }; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users_select". + */ +export interface UsersSelect { + updatedAt?: T; + createdAt?: T; + email?: T; + resetPasswordToken?: T; + resetPasswordExpiration?: T; + salt?: T; + hash?: T; + loginAttempts?: T; + lockUntil?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents_select". + */ +export interface PayloadLockedDocumentsSelect { + document?: T; + globalSlug?: T; + user?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences_select". + */ +export interface PayloadPreferencesSelect { + user?: T; + key?: T; + value?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations_select". + */ +export interface PayloadMigrationsSelect { + name?: T; + batch?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "tabsWithRichText". + */ +export interface TabsWithRichText { + id: string; + tab1?: { + rt1?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + }; + tab2?: { + rt2?: { + root: { + type: string; + children: { + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + }; + updatedAt?: string | null; + createdAt?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "tabsWithRichText_select". + */ +export interface TabsWithRichTextSelect { + tab1?: + | T + | { + rt1?: T; + }; + tab2?: + | T + | { + rt2?: T; + }; + updatedAt?: T; + createdAt?: T; + globalType?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "LexicalBlocksRadioButtonsBlock". + */ +export interface LexicalBlocksRadioButtonsBlock { + radioButtons?: ('option1' | 'option2' | 'option3') | null; + id?: string | null; + blockName?: string | null; + blockType: 'radioButtons'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "AvatarGroupBlock". + */ +export interface AvatarGroupBlock { + avatars?: + | { + image?: (string | null) | Upload; + id?: string | null; + }[] + | null; + id?: string | null; + blockName?: string | null; + blockType: 'AvatarGroup'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "auth". + */ +export interface Auth { + [k: string]: unknown; +} + + +declare module 'payload' { + // @ts-ignore + export interface GeneratedTypes extends Config {} +} \ No newline at end of file diff --git a/test/lexical/seed.ts b/test/lexical/seed.ts new file mode 100644 index 0000000000..351b6bb570 --- /dev/null +++ b/test/lexical/seed.ts @@ -0,0 +1,452 @@ +import type { Payload } from 'payload' + +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +import { lexicalDocData } from './collections/Lexical/data.js' +import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js' +import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js' +import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js' +import { richTextBulletsDocData, richTextDocData } from './collections/RichText/data.js' +import { + arrayFieldsSlug, + collectionSlugs, + lexicalFieldsSlug, + lexicalLocalizedFieldsSlug, + lexicalMigrateFieldsSlug, + lexicalRelationshipFieldsSlug, + richTextFieldsSlug, + textFieldsSlug, + uploadsSlug, + usersSlug, +} from './slugs.js' + +// import type { Payload } from 'payload' + +import { getFileByPath } from 'payload' + +import { devUser } from '../credentials.js' +import { seedDB } from '../helpers/seed.js' +import { arrayDoc } from './collections/Array/shared.js' +import { anotherTextDoc, textDoc } from './collections/Text/shared.js' +import { uploadsDoc } from './collections/Upload/shared.js' +// import { blocksDoc } from './collections/Blocks/shared.js' +// import { codeDoc } from './collections/Code/shared.js' +// import { collapsibleDoc } from './collections/Collapsible/shared.js' +// import { conditionalLogicDoc } from './collections/ConditionalLogic/shared.js' +// import { customRowID, customTabID, nonStandardID } from './collections/CustomID/shared.js' +// import { dateDoc } from './collections/Date/shared.js' +// import { anotherEmailDoc, emailDoc } from './collections/Email/shared.js' +// import { groupDoc } from './collections/Group/shared.js' +// import { jsonDoc } from './collections/JSON/shared.js' +// import { lexicalDocData } from './collections/Lexical/data.js' +// import { generateLexicalLocalizedRichText } from './collections/LexicalLocalized/generateLexicalRichText.js' +// import { textToLexicalJSON } from './collections/LexicalLocalized/textToLexicalJSON.js' +// import { lexicalMigrateDocData } from './collections/LexicalMigrate/data.js' +// import { numberDoc } from './collections/Number/shared.js' +// import { pointDoc } from './collections/Point/shared.js' +// import { radiosDoc } from './collections/Radio/shared.js' +// import { richTextBulletsDocData, richTextDocData } from './collections/RichText/data.js' +// import { selectsDoc } from './collections/Select/shared.js' +// import { tabsDoc } from './collections/Tabs/shared.js' +// import { anotherTextDoc, textDoc } from './collections/Text/shared.js' +// import { uploadsDoc } from './collections/Upload/shared.js' +// import { +// arrayFieldsSlug, +// blockFieldsSlug, +// checkboxFieldsSlug, +// codeFieldsSlug, +// collapsibleFieldsSlug, +// collectionSlugs, +// conditionalLogicSlug, +// customIDSlug, +// customRowIDSlug, +// customTabIDSlug, +// dateFieldsSlug, +// emailFieldsSlug, +// groupFieldsSlug, +// jsonFieldsSlug, +// lexicalFieldsSlug, +// lexicalLocalizedFieldsSlug, +// lexicalMigrateFieldsSlug, +// lexicalRelationshipFieldsSlug, +// numberFieldsSlug, +// pointFieldsSlug, +// radioFieldsSlug, +// relationshipFieldsSlug, +// richTextFieldsSlug, +// selectFieldsSlug, +// tabsFieldsSlug, +// textFieldsSlug, +// uiSlug, +// uploads2Slug, +// uploadsMulti, +// uploadsMultiPoly, +// uploadsPoly, +// uploadsSlug, +// usersSlug, +// } from './slugs.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export const seed = async (_payload: Payload) => { + const jpgPath = path.resolve(dirname, './collections/Upload/payload.jpg') + const pngPath = path.resolve(dirname, './uploads/payload.png') + + // Get both files in parallel + const [jpgFile, pngFile] = await Promise.all([getFileByPath(jpgPath), getFileByPath(pngPath)]) + + const createdArrayDoc = await _payload.create({ + collection: arrayFieldsSlug, + data: arrayDoc, + depth: 0, + overrideAccess: true, + }) + + const createdTextDoc = await _payload.create({ + collection: textFieldsSlug, + data: textDoc, + depth: 0, + overrideAccess: true, + }) + + await _payload.create({ + collection: textFieldsSlug, + data: anotherTextDoc, + depth: 0, + overrideAccess: true, + }) + + const createdPNGDoc = await _payload.create({ + collection: uploadsSlug, + data: {}, + file: pngFile, + depth: 0, + overrideAccess: true, + }) + + const createdJPGDoc = await _payload.create({ + collection: uploadsSlug, + data: { + ...uploadsDoc, + media: createdPNGDoc.id, + }, + file: jpgFile, + depth: 0, + overrideAccess: true, + }) + + const formattedID = + _payload.db.defaultIDType === 'number' ? createdArrayDoc.id : `"${createdArrayDoc.id}"` + + const formattedJPGID = + _payload.db.defaultIDType === 'number' ? createdJPGDoc.id : `"${createdJPGDoc.id}"` + + const formattedTextID = + _payload.db.defaultIDType === 'number' ? createdTextDoc.id : `"${createdTextDoc.id}"` + + const richTextDocWithRelId = JSON.parse( + JSON.stringify(richTextDocData) + .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`) + .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) + .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`), + ) + const richTextBulletsDocWithRelId = JSON.parse( + JSON.stringify(richTextBulletsDocData) + .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`) + .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) + .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`), + ) + + const richTextDocWithRelationship = { ...richTextDocWithRelId } + + await _payload.create({ + collection: richTextFieldsSlug, + data: richTextBulletsDocWithRelId, + depth: 0, + overrideAccess: true, + }) + + const createdRichTextDoc = await _payload.create({ + collection: richTextFieldsSlug, + data: richTextDocWithRelationship, + depth: 0, + overrideAccess: true, + }) + + const formattedRichTextDocID = + _payload.db.defaultIDType === 'number' ? createdRichTextDoc.id : `"${createdRichTextDoc.id}"` + + const lexicalDocWithRelId = JSON.parse( + JSON.stringify(lexicalDocData) + .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`) + .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) + .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`) + .replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`), + ) + + const lexicalMigrateDocWithRelId = JSON.parse( + JSON.stringify(lexicalMigrateDocData) + .replace(/"\{\{ARRAY_DOC_ID\}\}"/g, `${formattedID}`) + .replace(/"\{\{UPLOAD_DOC_ID\}\}"/g, `${formattedJPGID}`) + .replace(/"\{\{TEXT_DOC_ID\}\}"/g, `${formattedTextID}`) + .replace(/"\{\{RICH_TEXT_DOC_ID\}\}"/g, `${formattedRichTextDocID}`), + ) + + await _payload.create({ + collection: usersSlug, + depth: 0, + data: { + email: devUser.email, + password: devUser.password, + }, + overrideAccess: true, + }) + + await _payload.create({ + collection: lexicalFieldsSlug, + data: lexicalDocWithRelId, + depth: 0, + overrideAccess: true, + }) + + const lexicalLocalizedDoc1 = await _payload.create({ + collection: lexicalLocalizedFieldsSlug, + data: { + title: 'Localized Lexical en', + lexicalBlocksLocalized: textToLexicalJSON({ text: 'English text' }), + lexicalBlocksSubLocalized: generateLexicalLocalizedRichText( + 'Shared text', + 'English text in block', + ) as any, + }, + locale: 'en', + depth: 0, + overrideAccess: true, + }) + + await _payload.create({ + collection: lexicalRelationshipFieldsSlug, + data: { + richText: textToLexicalJSON({ text: 'English text' }), + }, + depth: 0, + overrideAccess: true, + }) + + await _payload.update({ + collection: lexicalLocalizedFieldsSlug, + id: lexicalLocalizedDoc1.id, + data: { + title: 'Localized Lexical es', + lexicalBlocksLocalized: textToLexicalJSON({ text: 'Spanish text' }), + lexicalBlocksSubLocalized: generateLexicalLocalizedRichText( + 'Shared text', + 'Spanish text in block', + (lexicalLocalizedDoc1.lexicalBlocksSubLocalized.root.children[1].fields as any).id, + ) as any, + }, + locale: 'es', + depth: 0, + overrideAccess: true, + }) + + const lexicalLocalizedDoc2 = await _payload.create({ + collection: lexicalLocalizedFieldsSlug, + data: { + title: 'Localized Lexical en 2', + + lexicalBlocksLocalized: textToLexicalJSON({ + text: 'English text 2', + lexicalLocalizedRelID: lexicalLocalizedDoc1.id, + }), + lexicalBlocksSubLocalized: textToLexicalJSON({ + text: 'English text 2', + lexicalLocalizedRelID: lexicalLocalizedDoc1.id, + }), + }, + locale: 'en', + depth: 0, + overrideAccess: true, + }) + + await _payload.update({ + collection: lexicalLocalizedFieldsSlug, + id: lexicalLocalizedDoc2.id, + data: { + title: 'Localized Lexical es 2', + + lexicalBlocksLocalized: textToLexicalJSON({ + text: 'Spanish text 2', + lexicalLocalizedRelID: lexicalLocalizedDoc1.id, + }), + }, + locale: 'es', + depth: 0, + overrideAccess: true, + }) + + await _payload.create({ + collection: lexicalMigrateFieldsSlug, + data: lexicalMigrateDocWithRelId, + depth: 0, + overrideAccess: true, + }) + + const getInlineBlock = () => ({ + type: 'inlineBlock', + fields: { + id: Math.random().toString(36).substring(2, 15), + text: 'text', + blockType: 'inlineBlockInLexical', + }, + version: 1, + }) + + await _payload.create({ + collection: 'LexicalInBlock', + depth: 0, + data: { + content: { + root: { + children: [ + { + format: '', + type: 'block', + version: 2, + fields: { + id: '6773773284be8978db7a498d', + lexicalInBlock: textToLexicalJSON({ text: 'text' }), + blockName: '', + blockType: 'blockInLexical', + }, + }, + ], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1, + }, + }, + blocks: [ + { + blockType: 'lexicalInBlock2', + blockName: '1', + lexical: textToLexicalJSON({ text: '1' }), + }, + { + blockType: 'lexicalInBlock2', + blockName: '2', + lexical: textToLexicalJSON({ text: '2' }), + }, + { + blockType: 'lexicalInBlock2', + lexical: { + root: { + children: [ + { + children: [...Array.from({ length: 20 }, () => getInlineBlock())], + direction: null, + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + ], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1, + }, + }, + id: '67e1af0b78de3228e23ef1d5', + blockName: '1', + }, + ], + }, + }) + + await _payload.create({ + collection: 'lexical-access-control', + data: { + richText: { + root: { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'text ', + type: 'text', + version: 1, + }, + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'link', + type: 'text', + version: 1, + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + url: 'https://', + newTab: false, + linkType: 'custom', + blocks: [ + { + id: '67e45673cbd5181ca8cbeef7', + blockType: 'block', + }, + ], + }, + id: '67e4566fcbd5181ca8cbeef5', + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + ], + direction: 'ltr', + format: '', + indent: 0, + type: 'root', + version: 1, + }, + }, + title: 'title', + }, + depth: 0, + }) +} + +export async function clearAndSeedEverything(_payload: Payload) { + return await seedDB({ + _payload, + collectionSlugs, + seedFunction: seed, + snapshotKey: 'fieldsTest', + uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), + }) +} diff --git a/test/lexical/slugs.ts b/test/lexical/slugs.ts new file mode 100644 index 0000000000..1f782022a4 --- /dev/null +++ b/test/lexical/slugs.ts @@ -0,0 +1,24 @@ +export const usersSlug = 'users' + +export const lexicalFieldsSlug = 'lexical-fields' +export const lexicalLocalizedFieldsSlug = 'lexical-localized-fields' +export const lexicalMigrateFieldsSlug = 'lexical-migrate-fields' +export const lexicalRelationshipFieldsSlug = 'lexical-relationship-fields' +export const lexicalAccessControlSlug = 'lexical-access-control' +export const richTextFieldsSlug = 'rich-text-fields' + +// Auxiliary slugs +export const textFieldsSlug = 'text-fields' +export const uploadsSlug = 'uploads' +export const arrayFieldsSlug = 'array-fields' + +export const collectionSlugs = [ + lexicalFieldsSlug, + lexicalLocalizedFieldsSlug, + lexicalMigrateFieldsSlug, + lexicalRelationshipFieldsSlug, + lexicalAccessControlSlug, + richTextFieldsSlug, + textFieldsSlug, + uploadsSlug, +] diff --git a/test/lexical/tsconfig.eslint.json b/test/lexical/tsconfig.eslint.json new file mode 100644 index 0000000000..b34cc7afbb --- /dev/null +++ b/test/lexical/tsconfig.eslint.json @@ -0,0 +1,13 @@ +{ + // extend your base config to share compilerOptions, etc + //"extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "./**/*.ts", + "./**/*.tsx" + ] +} diff --git a/test/lexical/tsconfig.json b/test/lexical/tsconfig.json new file mode 100644 index 0000000000..3c43903cfd --- /dev/null +++ b/test/lexical/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json" +} diff --git a/test/lexical/uploads/payload.png b/test/lexical/uploads/payload.png new file mode 100644 index 0000000000..39a580da7f Binary files /dev/null and b/test/lexical/uploads/payload.png differ