fix(richtext-lexical): newTab not being able to be checked to true by default (#12389)
Previously the value of new tab checkbox in the link feature was not able to be set to true by default because we were passing `false` as a default value. This fixes that and adds test coverage for customising that link drawer.
This commit is contained in:
@@ -64,7 +64,6 @@ const toolbarGroups: ToolbarGroup[] = [
|
|||||||
|
|
||||||
const linkFields: Partial<LinkFields> = {
|
const linkFields: Partial<LinkFields> = {
|
||||||
doc: null,
|
doc: null,
|
||||||
newTab: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.dispatchCommand(TOGGLE_LINK_WITH_MODAL_COMMAND, {
|
editor.dispatchCommand(TOGGLE_LINK_WITH_MODAL_COMMAND, {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from './collections/Lexical/index.js'
|
} from './collections/Lexical/index.js'
|
||||||
import { LexicalAccessControl } from './collections/LexicalAccessControl/index.js'
|
import { LexicalAccessControl } from './collections/LexicalAccessControl/index.js'
|
||||||
import { LexicalInBlock } from './collections/LexicalInBlock/index.js'
|
import { LexicalInBlock } from './collections/LexicalInBlock/index.js'
|
||||||
|
import { LexicalLinkFeature } from './collections/LexicalLinkFeature/index.js'
|
||||||
import { LexicalLocalizedFields } from './collections/LexicalLocalized/index.js'
|
import { LexicalLocalizedFields } from './collections/LexicalLocalized/index.js'
|
||||||
import { LexicalMigrateFields } from './collections/LexicalMigrate/index.js'
|
import { LexicalMigrateFields } from './collections/LexicalMigrate/index.js'
|
||||||
import { LexicalObjectReferenceBugCollection } from './collections/LexicalObjectReferenceBug/index.js'
|
import { LexicalObjectReferenceBugCollection } from './collections/LexicalObjectReferenceBug/index.js'
|
||||||
@@ -28,6 +29,7 @@ export const baseConfig: Partial<Config> = {
|
|||||||
// ...extend config here
|
// ...extend config here
|
||||||
collections: [
|
collections: [
|
||||||
LexicalFullyFeatured,
|
LexicalFullyFeatured,
|
||||||
|
LexicalLinkFeature,
|
||||||
getLexicalFieldsCollection({
|
getLexicalFieldsCollection({
|
||||||
blocks: lexicalBlocks,
|
blocks: lexicalBlocks,
|
||||||
inlineBlocks: lexicalInlineBlocks,
|
inlineBlocks: lexicalInlineBlocks,
|
||||||
|
|||||||
79
test/lexical/collections/LexicalLinkFeature/e2e.spec.ts
Normal file
79
test/lexical/collections/LexicalLinkFeature/e2e.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { expect, test } from '@playwright/test'
|
||||||
|
import { AdminUrlUtil } from 'helpers/adminUrlUtil.js'
|
||||||
|
import { reInitializeDB } from 'helpers/reInitializeDB.js'
|
||||||
|
import { lexicalLinkFeatureSlug } from 'lexical/slugs.js'
|
||||||
|
import path from 'path'
|
||||||
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
|
import { ensureCompilationIsDone } from '../../../helpers.js'
|
||||||
|
import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js'
|
||||||
|
import { TEST_TIMEOUT_LONG } from '../../../playwright.config.js'
|
||||||
|
import { LexicalHelpers } from './utils.js'
|
||||||
|
const filename = fileURLToPath(import.meta.url)
|
||||||
|
const currentFolder = path.dirname(filename)
|
||||||
|
const dirname = path.resolve(currentFolder, '../../')
|
||||||
|
|
||||||
|
const { beforeAll, beforeEach, describe } = test
|
||||||
|
|
||||||
|
// Unlike the other suites, this one runs in parallel, as they run on the `lexical-fully-featured/create` URL and are "pure" tests
|
||||||
|
test.describe.configure({ mode: 'parallel' })
|
||||||
|
|
||||||
|
const { serverURL } = await initPayloadE2ENoConfig({
|
||||||
|
dirname,
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Lexical Link Feature', () => {
|
||||||
|
beforeAll(async ({ browser }, testInfo) => {
|
||||||
|
testInfo.setTimeout(TEST_TIMEOUT_LONG)
|
||||||
|
process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit
|
||||||
|
const page = await browser.newPage()
|
||||||
|
await ensureCompilationIsDone({ page, serverURL })
|
||||||
|
await page.close()
|
||||||
|
})
|
||||||
|
beforeEach(async ({ page }) => {
|
||||||
|
await reInitializeDB({
|
||||||
|
serverURL,
|
||||||
|
snapshotKey: 'fieldsTest',
|
||||||
|
uploadsDir: [
|
||||||
|
path.resolve(dirname, './collections/Upload/uploads'),
|
||||||
|
path.resolve(dirname, './collections/Upload2/uploads2'),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
const url = new AdminUrlUtil(serverURL, lexicalLinkFeatureSlug)
|
||||||
|
const lexical = new LexicalHelpers(page)
|
||||||
|
await page.goto(url.create)
|
||||||
|
await lexical.editor.first().focus()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('can add new custom fields in link feature modal', async ({ page }) => {
|
||||||
|
const lexical = new LexicalHelpers(page)
|
||||||
|
|
||||||
|
await lexical.editor.fill('link')
|
||||||
|
await lexical.editor.selectText()
|
||||||
|
|
||||||
|
const linkButtonClass = `.rich-text-lexical__wrap .fixed-toolbar .toolbar-popup__button-link`
|
||||||
|
const linkButton = page.locator(linkButtonClass).first()
|
||||||
|
|
||||||
|
await linkButton.click()
|
||||||
|
|
||||||
|
const customField = lexical.drawer.locator('#field-someText')
|
||||||
|
|
||||||
|
await expect(customField).toBeVisible()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('can set default value of newTab checkbox to checked', async ({ page }) => {
|
||||||
|
const lexical = new LexicalHelpers(page)
|
||||||
|
|
||||||
|
await lexical.editor.fill('link')
|
||||||
|
await lexical.editor.selectText()
|
||||||
|
|
||||||
|
const linkButtonClass = `.rich-text-lexical__wrap .fixed-toolbar .toolbar-popup__button-link`
|
||||||
|
const linkButton = page.locator(linkButtonClass).first()
|
||||||
|
|
||||||
|
await linkButton.click()
|
||||||
|
|
||||||
|
const checkboxField = lexical.drawer.locator(`[id^="field-newTab"]`)
|
||||||
|
|
||||||
|
await expect(checkboxField).toBeChecked()
|
||||||
|
})
|
||||||
|
})
|
||||||
44
test/lexical/collections/LexicalLinkFeature/index.ts
Normal file
44
test/lexical/collections/LexicalLinkFeature/index.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import type { CheckboxField, CollectionConfig } from 'payload'
|
||||||
|
|
||||||
|
import {
|
||||||
|
FixedToolbarFeature,
|
||||||
|
lexicalEditor,
|
||||||
|
LinkFeature,
|
||||||
|
TreeViewFeature,
|
||||||
|
} from '@payloadcms/richtext-lexical'
|
||||||
|
|
||||||
|
import { lexicalLinkFeatureSlug } from '../../slugs.js'
|
||||||
|
|
||||||
|
export const LexicalLinkFeature: CollectionConfig = {
|
||||||
|
slug: lexicalLinkFeatureSlug,
|
||||||
|
labels: {
|
||||||
|
singular: 'Lexical Link Feature',
|
||||||
|
plural: 'Lexical Link Feature',
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'richText',
|
||||||
|
type: 'richText',
|
||||||
|
editor: lexicalEditor({
|
||||||
|
features: ({ defaultFeatures }) => [
|
||||||
|
...defaultFeatures,
|
||||||
|
TreeViewFeature(),
|
||||||
|
LinkFeature({
|
||||||
|
fields: ({ defaultFields }) => {
|
||||||
|
const modifiedFields = defaultFields.map((field) => {
|
||||||
|
if (field.name === 'newTab') {
|
||||||
|
return { ...field, defaultValue: true } as CheckboxField
|
||||||
|
}
|
||||||
|
|
||||||
|
return field
|
||||||
|
})
|
||||||
|
|
||||||
|
return [...modifiedFields, { type: 'text', name: 'someText' }]
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
FixedToolbarFeature(),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
49
test/lexical/collections/LexicalLinkFeature/utils.ts
Normal file
49
test/lexical/collections/LexicalLinkFeature/utils.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import type { Page } from 'playwright'
|
||||||
|
|
||||||
|
import { expect } from '@playwright/test'
|
||||||
|
|
||||||
|
export class LexicalHelpers {
|
||||||
|
page: Page
|
||||||
|
constructor(page: Page) {
|
||||||
|
this.page = page
|
||||||
|
}
|
||||||
|
|
||||||
|
async save(container: 'document' | 'drawer') {
|
||||||
|
if (container === 'drawer') {
|
||||||
|
await this.drawer.getByText('Save').click()
|
||||||
|
} else {
|
||||||
|
throw new Error('Not implemented')
|
||||||
|
}
|
||||||
|
await this.page.waitForTimeout(1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
async slashCommand(
|
||||||
|
// prettier-ignore
|
||||||
|
command: 'block' | 'check' | 'code' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' |'h6' | 'inline'
|
||||||
|
| 'link' | 'ordered' | 'paragraph' | 'quote' | 'relationship' | 'unordered' | 'upload',
|
||||||
|
) {
|
||||||
|
await this.page.keyboard.press(`/`)
|
||||||
|
|
||||||
|
const slashMenuPopover = this.page.locator('#slash-menu .slash-menu-popup')
|
||||||
|
await expect(slashMenuPopover).toBeVisible()
|
||||||
|
await this.page.keyboard.type(command)
|
||||||
|
await this.page.keyboard.press(`Enter`)
|
||||||
|
await expect(slashMenuPopover).toBeHidden()
|
||||||
|
}
|
||||||
|
|
||||||
|
get decorator() {
|
||||||
|
return this.editor.locator('[data-lexical-decorator="true"]')
|
||||||
|
}
|
||||||
|
|
||||||
|
get drawer() {
|
||||||
|
return this.page.locator('.drawer__content')
|
||||||
|
}
|
||||||
|
|
||||||
|
get editor() {
|
||||||
|
return this.page.locator('[data-lexical-editor="true"]')
|
||||||
|
}
|
||||||
|
|
||||||
|
get paragraph() {
|
||||||
|
return this.editor.locator('p')
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -84,6 +84,7 @@ export interface Config {
|
|||||||
blocks: {};
|
blocks: {};
|
||||||
collections: {
|
collections: {
|
||||||
'lexical-fully-featured': LexicalFullyFeatured;
|
'lexical-fully-featured': LexicalFullyFeatured;
|
||||||
|
'lexical-link-feature': LexicalLinkFeature;
|
||||||
'lexical-fields': LexicalField;
|
'lexical-fields': LexicalField;
|
||||||
'lexical-migrate-fields': LexicalMigrateField;
|
'lexical-migrate-fields': LexicalMigrateField;
|
||||||
'lexical-localized-fields': LexicalLocalizedField;
|
'lexical-localized-fields': LexicalLocalizedField;
|
||||||
@@ -103,6 +104,7 @@ export interface Config {
|
|||||||
collectionsJoins: {};
|
collectionsJoins: {};
|
||||||
collectionsSelect: {
|
collectionsSelect: {
|
||||||
'lexical-fully-featured': LexicalFullyFeaturedSelect<false> | LexicalFullyFeaturedSelect<true>;
|
'lexical-fully-featured': LexicalFullyFeaturedSelect<false> | LexicalFullyFeaturedSelect<true>;
|
||||||
|
'lexical-link-feature': LexicalLinkFeatureSelect<false> | LexicalLinkFeatureSelect<true>;
|
||||||
'lexical-fields': LexicalFieldsSelect<false> | LexicalFieldsSelect<true>;
|
'lexical-fields': LexicalFieldsSelect<false> | LexicalFieldsSelect<true>;
|
||||||
'lexical-migrate-fields': LexicalMigrateFieldsSelect<false> | LexicalMigrateFieldsSelect<true>;
|
'lexical-migrate-fields': LexicalMigrateFieldsSelect<false> | LexicalMigrateFieldsSelect<true>;
|
||||||
'lexical-localized-fields': LexicalLocalizedFieldsSelect<false> | LexicalLocalizedFieldsSelect<true>;
|
'lexical-localized-fields': LexicalLocalizedFieldsSelect<false> | LexicalLocalizedFieldsSelect<true>;
|
||||||
@@ -179,6 +181,30 @@ export interface LexicalFullyFeatured {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "lexical-link-feature".
|
||||||
|
*/
|
||||||
|
export interface LexicalLinkFeature {
|
||||||
|
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;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "lexical-fields".
|
* via the `definition` "lexical-fields".
|
||||||
@@ -804,6 +830,10 @@ export interface PayloadLockedDocument {
|
|||||||
relationTo: 'lexical-fully-featured';
|
relationTo: 'lexical-fully-featured';
|
||||||
value: string | LexicalFullyFeatured;
|
value: string | LexicalFullyFeatured;
|
||||||
} | null)
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'lexical-link-feature';
|
||||||
|
value: string | LexicalLinkFeature;
|
||||||
|
} | null)
|
||||||
| ({
|
| ({
|
||||||
relationTo: 'lexical-fields';
|
relationTo: 'lexical-fields';
|
||||||
value: string | LexicalField;
|
value: string | LexicalField;
|
||||||
@@ -903,6 +933,15 @@ export interface LexicalFullyFeaturedSelect<T extends boolean = true> {
|
|||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "lexical-link-feature_select".
|
||||||
|
*/
|
||||||
|
export interface LexicalLinkFeatureSelect<T extends boolean = true> {
|
||||||
|
richText?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "lexical-fields_select".
|
* via the `definition` "lexical-fields_select".
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ export const usersSlug = 'users'
|
|||||||
|
|
||||||
export const lexicalFullyFeaturedSlug = 'lexical-fully-featured'
|
export const lexicalFullyFeaturedSlug = 'lexical-fully-featured'
|
||||||
export const lexicalFieldsSlug = 'lexical-fields'
|
export const lexicalFieldsSlug = 'lexical-fields'
|
||||||
|
|
||||||
|
export const lexicalLinkFeatureSlug = 'lexical-link-feature'
|
||||||
export const lexicalLocalizedFieldsSlug = 'lexical-localized-fields'
|
export const lexicalLocalizedFieldsSlug = 'lexical-localized-fields'
|
||||||
export const lexicalMigrateFieldsSlug = 'lexical-migrate-fields'
|
export const lexicalMigrateFieldsSlug = 'lexical-migrate-fields'
|
||||||
export const lexicalRelationshipFieldsSlug = 'lexical-relationship-fields'
|
export const lexicalRelationshipFieldsSlug = 'lexical-relationship-fields'
|
||||||
|
|||||||
Reference in New Issue
Block a user