diff --git a/packages/richtext-lexical/src/field/features/format/bold/index.ts b/packages/richtext-lexical/src/field/features/format/bold/feature.client.tsx similarity index 68% rename from packages/richtext-lexical/src/field/features/format/bold/index.ts rename to packages/richtext-lexical/src/field/features/format/bold/feature.client.tsx index e2443e7e2f..79182a49ba 100644 --- a/packages/richtext-lexical/src/field/features/format/bold/index.ts +++ b/packages/richtext-lexical/src/field/features/format/bold/feature.client.tsx @@ -1,7 +1,10 @@ +'use client' import { $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical' -import type { FeatureProvider } from '../../types' +import type { FeatureProviderProviderClient } from '../../types' +import { BoldIcon } from '../../../lexical/ui/icons/Bold' +import { createClientComponent } from '../../createClientComponent' import { SectionWithEntries } from '../common/floatingSelectToolbarSection' import { BOLD_ITALIC_STAR, @@ -10,9 +13,9 @@ import { BOLD_UNDERSCORE, } from './markdownTransformers' -export const BoldTextFeature = (): FeatureProvider => { +const BoldFeatureClient: FeatureProviderProviderClient = (props) => { return { - dependenciesSoft: ['italic'], + clientFeatureProps: props, feature: ({ featureProviderMap }) => { const markdownTransformers = [BOLD_STAR, BOLD_UNDERSCORE] if (featureProviderMap.get('italic')) { @@ -20,13 +23,12 @@ export const BoldTextFeature = (): FeatureProvider => { } return { + clientFeatureProps: props, floatingSelectToolbar: { sections: [ SectionWithEntries([ { - ChildComponent: () => - // @ts-expect-error-next-line - import('../../../lexical/ui/icons/Bold').then((module) => module.BoldIcon), + ChildComponent: BoldIcon, isActive: ({ selection }) => { if ($isRangeSelection(selection)) { return selection.hasFormat('bold') @@ -42,10 +44,10 @@ export const BoldTextFeature = (): FeatureProvider => { ]), ], }, - markdownTransformers: markdownTransformers, - props: null, + markdownTransformers, } }, - key: 'bold', } } + +export const BoldFeatureClientComponent = createClientComponent(BoldFeatureClient) diff --git a/packages/richtext-lexical/src/field/features/format/bold/feature.server.ts b/packages/richtext-lexical/src/field/features/format/bold/feature.server.ts new file mode 100644 index 0000000000..bf0357c6d9 --- /dev/null +++ b/packages/richtext-lexical/src/field/features/format/bold/feature.server.ts @@ -0,0 +1,29 @@ +import type { FeatureProviderProviderServer } from '../../types' + +import { BoldFeatureClientComponent } from './feature.client' +import { + BOLD_ITALIC_STAR, + BOLD_ITALIC_UNDERSCORE, + BOLD_STAR, + BOLD_UNDERSCORE, +} from './markdownTransformers' + +export const BoldFeature: FeatureProviderProviderServer = (props) => { + return { + dependenciesSoft: ['italic'], + feature: ({ featureProviderMap }) => { + const markdownTransformers = [BOLD_STAR, BOLD_UNDERSCORE] + if (featureProviderMap.get('italic')) { + markdownTransformers.push(BOLD_ITALIC_UNDERSCORE, BOLD_ITALIC_STAR) + } + + return { + ClientComponent: BoldFeatureClientComponent, + markdownTransformers, + serverFeatureProps: props, + } + }, + key: 'bold', + serverFeatureProps: props, + } +} diff --git a/packages/richtext-lexical/src/field/features/format/inlinecode/index.ts b/packages/richtext-lexical/src/field/features/format/inlinecode/feature.client.tsx similarity index 64% rename from packages/richtext-lexical/src/field/features/format/inlinecode/index.ts rename to packages/richtext-lexical/src/field/features/format/inlinecode/feature.client.tsx index 502033ca0a..92efc2aff6 100644 --- a/packages/richtext-lexical/src/field/features/format/inlinecode/index.ts +++ b/packages/richtext-lexical/src/field/features/format/inlinecode/feature.client.tsx @@ -1,21 +1,25 @@ +'use client' + import { $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical' -import type { FeatureProvider } from '../../types' +import type { FeatureProviderProviderClient } from '../../types' +import { CodeIcon } from '../../../lexical/ui/icons/Code' +import { createClientComponent } from '../../createClientComponent' import { SectionWithEntries } from '../common/floatingSelectToolbarSection' import { INLINE_CODE } from './markdownTransformers' -export const InlineCodeTextFeature = (): FeatureProvider => { +const InlineCodeFeatureClient: FeatureProviderProviderClient = (props) => { return { + clientFeatureProps: props, feature: () => { return { + clientFeatureProps: props, floatingSelectToolbar: { sections: [ SectionWithEntries([ { - ChildComponent: () => - // @ts-expect-error-next-line - import('../../../lexical/ui/icons/Code').then((module) => module.CodeIcon), + ChildComponent: CodeIcon, isActive: ({ selection }) => { if ($isRangeSelection(selection)) { return selection.hasFormat('code') @@ -31,10 +35,11 @@ export const InlineCodeTextFeature = (): FeatureProvider => { ]), ], }, + markdownTransformers: [INLINE_CODE], - props: null, } }, - key: 'inlinecode', } } + +export const InlineCodeFeatureClientComponent = createClientComponent(InlineCodeFeatureClient) diff --git a/packages/richtext-lexical/src/field/features/format/inlinecode/feature.server.ts b/packages/richtext-lexical/src/field/features/format/inlinecode/feature.server.ts new file mode 100644 index 0000000000..3f0eabb1ac --- /dev/null +++ b/packages/richtext-lexical/src/field/features/format/inlinecode/feature.server.ts @@ -0,0 +1,18 @@ +import type { FeatureProviderProviderServer } from '../../types' + +import { InlineCodeFeatureClientComponent } from './feature.client' +import { INLINE_CODE } from './markdownTransformers' + +export const InlineCodeFeature: FeatureProviderProviderServer = (props) => { + return { + feature: () => { + return { + ClientComponent: InlineCodeFeatureClientComponent, + markdownTransformers: [INLINE_CODE], + serverFeatureProps: props, + } + }, + key: 'inlinecode', + serverFeatureProps: props, + } +} diff --git a/packages/richtext-lexical/src/field/features/format/italic/index.ts b/packages/richtext-lexical/src/field/features/format/italic/feature.client.tsx similarity index 65% rename from packages/richtext-lexical/src/field/features/format/italic/index.ts rename to packages/richtext-lexical/src/field/features/format/italic/feature.client.tsx index cdd15dcca2..1c874f18ff 100644 --- a/packages/richtext-lexical/src/field/features/format/italic/index.ts +++ b/packages/richtext-lexical/src/field/features/format/italic/feature.client.tsx @@ -1,21 +1,26 @@ +'use client' + import { $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical' -import type { FeatureProvider } from '../../types' +import type { FeatureProviderProviderClient } from '../../types' +import { ItalicIcon } from '../../../lexical/ui/icons/Italic' +import { createClientComponent } from '../../createClientComponent' import { SectionWithEntries } from '../common/floatingSelectToolbarSection' import { ITALIC_STAR, ITALIC_UNDERSCORE } from './markdownTransformers' -export const ItalicTextFeature = (): FeatureProvider => { +const ItalicFeatureClient: FeatureProviderProviderClient = (props) => { return { + clientFeatureProps: props, feature: () => { return { + clientFeatureProps: props, + floatingSelectToolbar: { sections: [ SectionWithEntries([ { - ChildComponent: () => - // @ts-expect-error-next-line - import('../../../lexical/ui/icons/Italic').then((module) => module.ItalicIcon), + ChildComponent: ItalicIcon, isActive: ({ selection }) => { if ($isRangeSelection(selection)) { return selection.hasFormat('italic') @@ -32,9 +37,9 @@ export const ItalicTextFeature = (): FeatureProvider => { ], }, markdownTransformers: [ITALIC_STAR, ITALIC_UNDERSCORE], - props: null, } }, - key: 'italic', } } + +export const ItalicFeatureClientComponent = createClientComponent(ItalicFeatureClient) diff --git a/packages/richtext-lexical/src/field/features/format/italic/feature.server.ts b/packages/richtext-lexical/src/field/features/format/italic/feature.server.ts new file mode 100644 index 0000000000..db69135e48 --- /dev/null +++ b/packages/richtext-lexical/src/field/features/format/italic/feature.server.ts @@ -0,0 +1,18 @@ +import type { FeatureProviderProviderServer } from '../../types' + +import { ItalicFeatureClientComponent } from './feature.client' +import { ITALIC_STAR, ITALIC_UNDERSCORE } from './markdownTransformers' + +export const ItalicFeature: FeatureProviderProviderServer = (props) => { + return { + feature: () => { + return { + ClientComponent: ItalicFeatureClientComponent, + markdownTransformers: [ITALIC_STAR, ITALIC_UNDERSCORE], + serverFeatureProps: props, + } + }, + key: 'italic', + serverFeatureProps: props, + } +} diff --git a/packages/richtext-lexical/src/field/features/format/strikethrough/index.ts b/packages/richtext-lexical/src/field/features/format/strikethrough/feature.client.tsx similarity index 63% rename from packages/richtext-lexical/src/field/features/format/strikethrough/index.ts rename to packages/richtext-lexical/src/field/features/format/strikethrough/feature.client.tsx index 949ec80b9c..79cc2782c3 100644 --- a/packages/richtext-lexical/src/field/features/format/strikethrough/index.ts +++ b/packages/richtext-lexical/src/field/features/format/strikethrough/feature.client.tsx @@ -1,23 +1,26 @@ +'use client' + import { $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical' -import type { FeatureProvider } from '../../types' +import type { FeatureProviderProviderClient } from '../../types' +import { StrikethroughIcon } from '../../../lexical/ui/icons/Strikethrough' +import { createClientComponent } from '../../createClientComponent' import { SectionWithEntries } from '../common/floatingSelectToolbarSection' import { STRIKETHROUGH } from './markdownTransformers' -export const StrikethroughTextFeature = (): FeatureProvider => { +const StrikethroughFeatureClient: FeatureProviderProviderClient = (props) => { return { + clientFeatureProps: props, feature: () => { return { + clientFeatureProps: props, + floatingSelectToolbar: { sections: [ SectionWithEntries([ { - ChildComponent: () => - // @ts-expect-error-next-line - import('../../../lexical/ui/icons/Strikethrough').then( - (module) => module.StrikethroughIcon, - ), + ChildComponent: StrikethroughIcon, isActive: ({ selection }) => { if ($isRangeSelection(selection)) { return selection.hasFormat('strikethrough') @@ -34,9 +37,9 @@ export const StrikethroughTextFeature = (): FeatureProvider => { ], }, markdownTransformers: [STRIKETHROUGH], - props: null, } }, - key: 'strikethrough', } } + +export const StrikethroughFeatureClientComponent = createClientComponent(StrikethroughFeatureClient) diff --git a/packages/richtext-lexical/src/field/features/format/strikethrough/feature.server.ts b/packages/richtext-lexical/src/field/features/format/strikethrough/feature.server.ts new file mode 100644 index 0000000000..5f98bdbbea --- /dev/null +++ b/packages/richtext-lexical/src/field/features/format/strikethrough/feature.server.ts @@ -0,0 +1,21 @@ +import type { FeatureProviderProviderServer } from '../../types' + +import { StrikethroughFeatureClientComponent } from './feature.client' +import { STRIKETHROUGH } from './markdownTransformers' + +export const StrikethroughFeature: FeatureProviderProviderServer = ( + props, +) => { + return { + feature: () => { + return { + ClientComponent: StrikethroughFeatureClientComponent, + + markdownTransformers: [STRIKETHROUGH], + serverFeatureProps: props, + } + }, + key: 'strikethrough', + serverFeatureProps: props, + } +} diff --git a/packages/richtext-lexical/src/field/features/format/subscript/index.ts b/packages/richtext-lexical/src/field/features/format/subscript/feature.client.tsx similarity index 61% rename from packages/richtext-lexical/src/field/features/format/subscript/index.ts rename to packages/richtext-lexical/src/field/features/format/subscript/feature.client.tsx index 962e816f77..4c1904b0a4 100644 --- a/packages/richtext-lexical/src/field/features/format/subscript/index.ts +++ b/packages/richtext-lexical/src/field/features/format/subscript/feature.client.tsx @@ -1,22 +1,24 @@ +'use client' + import { $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical' -import type { FeatureProvider } from '../../types' +import type { FeatureProviderProviderClient } from '../../types' +import { SubscriptIcon } from '../../../lexical/ui/icons/Subscript' +import { createClientComponent } from '../../createClientComponent' import { SectionWithEntries } from '../common/floatingSelectToolbarSection' -export const SubscriptTextFeature = (): FeatureProvider => { +const SubscriptFeatureClient: FeatureProviderProviderClient = (props) => { return { + clientFeatureProps: props, feature: () => { return { + clientFeatureProps: props, floatingSelectToolbar: { sections: [ SectionWithEntries([ { - ChildComponent: () => - // @ts-expect-error-next-line - import('../../../lexical/ui/icons/Subscript').then( - (module) => module.SubscriptIcon, - ), + ChildComponent: SubscriptIcon, isActive: ({ selection }) => { if ($isRangeSelection(selection)) { return selection.hasFormat('subscript') @@ -32,9 +34,9 @@ export const SubscriptTextFeature = (): FeatureProvider => { ]), ], }, - props: null, } }, - key: 'subscript', } } + +export const SubscriptFeatureClientComponent = createClientComponent(SubscriptFeatureClient) diff --git a/packages/richtext-lexical/src/field/features/format/subscript/feature.server.ts b/packages/richtext-lexical/src/field/features/format/subscript/feature.server.ts new file mode 100644 index 0000000000..a02f058d33 --- /dev/null +++ b/packages/richtext-lexical/src/field/features/format/subscript/feature.server.ts @@ -0,0 +1,16 @@ +import type { FeatureProviderProviderServer } from '../../types' + +import { SubscriptFeatureClientComponent } from './feature.client' + +export const SubscriptFeature: FeatureProviderProviderServer = (props) => { + return { + feature: () => { + return { + ClientComponent: SubscriptFeatureClientComponent, + serverFeatureProps: props, + } + }, + key: 'subscript', + serverFeatureProps: props, + } +} diff --git a/packages/richtext-lexical/src/field/features/format/superscript/index.ts b/packages/richtext-lexical/src/field/features/format/superscript/feature.client.tsx similarity index 60% rename from packages/richtext-lexical/src/field/features/format/superscript/index.ts rename to packages/richtext-lexical/src/field/features/format/superscript/feature.client.tsx index 0e2939c35a..e59f487712 100644 --- a/packages/richtext-lexical/src/field/features/format/superscript/index.ts +++ b/packages/richtext-lexical/src/field/features/format/superscript/feature.client.tsx @@ -1,22 +1,24 @@ +'use client' + import { $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical' -import type { FeatureProvider } from '../../types' +import type { FeatureProviderProviderClient } from '../../types' +import { SuperscriptIcon } from '../../../lexical/ui/icons/Superscript' +import { createClientComponent } from '../../createClientComponent' import { SectionWithEntries } from '../common/floatingSelectToolbarSection' -export const SuperscriptTextFeature = (): FeatureProvider => { +const SuperscriptFeatureClient: FeatureProviderProviderClient = (props) => { return { + clientFeatureProps: props, feature: () => { return { + clientFeatureProps: props, floatingSelectToolbar: { sections: [ SectionWithEntries([ { - ChildComponent: () => - // @ts-expect-error-next-line - import('../../../lexical/ui/icons/Superscript').then( - (module) => module.SuperscriptIcon, - ), + ChildComponent: SuperscriptIcon, isActive: ({ selection }) => { if ($isRangeSelection(selection)) { return selection.hasFormat('superscript') @@ -32,9 +34,9 @@ export const SuperscriptTextFeature = (): FeatureProvider => { ]), ], }, - props: null, } }, - key: 'superscript', } } + +export const SuperscriptFeatureClientComponent = createClientComponent(SuperscriptFeatureClient) diff --git a/packages/richtext-lexical/src/field/features/format/superscript/feature.server.ts b/packages/richtext-lexical/src/field/features/format/superscript/feature.server.ts new file mode 100644 index 0000000000..080b91a5d4 --- /dev/null +++ b/packages/richtext-lexical/src/field/features/format/superscript/feature.server.ts @@ -0,0 +1,16 @@ +import type { FeatureProviderProviderServer } from '../../types' + +import { SuperscriptFeatureClientComponent } from './feature.client' + +export const SuperscriptFeature: FeatureProviderProviderServer = (props) => { + return { + feature: () => { + return { + ClientComponent: SuperscriptFeatureClientComponent, + serverFeatureProps: props, + } + }, + key: 'superscript', + serverFeatureProps: props, + } +} diff --git a/packages/richtext-lexical/src/field/features/format/underline/index.ts b/packages/richtext-lexical/src/field/features/format/underline/feature.client.tsx similarity index 61% rename from packages/richtext-lexical/src/field/features/format/underline/index.ts rename to packages/richtext-lexical/src/field/features/format/underline/feature.client.tsx index d5e4cf26bf..e26bf06ba0 100644 --- a/packages/richtext-lexical/src/field/features/format/underline/index.ts +++ b/packages/richtext-lexical/src/field/features/format/underline/feature.client.tsx @@ -1,22 +1,24 @@ +'use client' + import { $isRangeSelection, FORMAT_TEXT_COMMAND } from 'lexical' -import type { FeatureProvider } from '../../types' +import type { FeatureProviderProviderClient } from '../../types' +import { UnderlineIcon } from '../../../lexical/ui/icons/Underline' +import { createClientComponent } from '../../createClientComponent' import { SectionWithEntries } from '../common/floatingSelectToolbarSection' -export const UnderlineTextFeature = (): FeatureProvider => { +const UnderlineFeatureClient: FeatureProviderProviderClient = (props) => { return { + clientFeatureProps: props, feature: () => { return { + clientFeatureProps: props, floatingSelectToolbar: { sections: [ SectionWithEntries([ { - ChildComponent: () => - // @ts-expect-error-next-line - import('../../../lexical/ui/icons/Underline').then( - (module) => module.UnderlineIcon, - ), + ChildComponent: UnderlineIcon, isActive: ({ selection }) => { if ($isRangeSelection(selection)) { return selection.hasFormat('underline') @@ -32,9 +34,9 @@ export const UnderlineTextFeature = (): FeatureProvider => { ]), ], }, - props: null, } }, - key: 'underline', } } + +export const UnderlineFeatureClientComponent = createClientComponent(UnderlineFeatureClient) diff --git a/packages/richtext-lexical/src/field/features/format/underline/feature.server.ts b/packages/richtext-lexical/src/field/features/format/underline/feature.server.ts new file mode 100644 index 0000000000..4f9fc087c0 --- /dev/null +++ b/packages/richtext-lexical/src/field/features/format/underline/feature.server.ts @@ -0,0 +1,16 @@ +import type { FeatureProviderProviderServer } from '../../types' + +import { UnderlineFeatureClientComponent } from './feature.client' + +export const UnderlineFeature: FeatureProviderProviderServer = (props) => { + return { + feature: () => { + return { + ClientComponent: UnderlineFeatureClientComponent, + serverFeatureProps: props, + } + }, + key: 'underline', + serverFeatureProps: props, + } +} diff --git a/packages/richtext-lexical/src/field/lexical/config/server/default.ts b/packages/richtext-lexical/src/field/lexical/config/server/default.ts index 37f0998e46..2f63767146 100644 --- a/packages/richtext-lexical/src/field/lexical/config/server/default.ts +++ b/packages/richtext-lexical/src/field/lexical/config/server/default.ts @@ -5,13 +5,13 @@ import type { SanitizedServerEditorConfig, ServerEditorConfig } from '../types' import { AlignFeature } from '../../../features/align/feature.server' import { BlockQuoteFeature } from '../../../features/blockquote/feature.server' -import { BoldTextFeature } from '../../../features/format/bold' -import { InlineCodeTextFeature } from '../../../features/format/inlinecode' -import { ItalicTextFeature } from '../../../features/format/italic' -import { StrikethroughTextFeature } from '../../../features/format/strikethrough' -import { SubscriptTextFeature } from '../../../features/format/subscript' -import { SuperscriptTextFeature } from '../../../features/format/superscript' -import { UnderlineTextFeature } from '../../../features/format/underline' +import { BoldFeature } from '../../../features/format/bold/feature.server' +import { InlineCodeFeature } from '../../../features/format/inlinecode/feature.server' +import { ItalicFeature } from '../../../features/format/italic/feature.server' +import { StrikethroughFeature } from '../../../features/format/strikethrough/feature.server' +import { SubscriptFeature } from '../../../features/format/subscript/feature.server' +import { SuperscriptFeature } from '../../../features/format/superscript/feature.server' +import { UnderlineFeature } from '../../../features/format/underline/feature.server' import { HeadingFeature } from '../../../features/heading' import { IndentFeature } from '../../../features/indent' import { LinkFeature } from '../../../features/link/feature.server' @@ -30,13 +30,13 @@ export const defaultEditorLexicalConfig: LexicalEditorConfig = { } export const defaultEditorFeatures: FeatureProviderServer[] = [ - BoldTextFeature(), - ItalicTextFeature(), - UnderlineTextFeature(), - StrikethroughTextFeature(), - SubscriptTextFeature(), - SuperscriptTextFeature(), - InlineCodeTextFeature(), + BoldFeature(), + ItalicFeature(), + UnderlineFeature(), + StrikethroughFeature(), + SubscriptFeature(), + SuperscriptFeature(), + InlineCodeFeature(), ParagraphFeature(), HeadingFeature({}), AlignFeature(), diff --git a/packages/richtext-lexical/src/index.ts b/packages/richtext-lexical/src/index.ts index f7f1064ed3..78165e5d7c 100644 --- a/packages/richtext-lexical/src/index.ts +++ b/packages/richtext-lexical/src/index.ts @@ -262,14 +262,14 @@ export { consolidateHTMLConverters } from './field/features/converters/html/fiel export { lexicalHTML } from './field/features/converters/html/field' export { TestRecorderFeature } from './field/features/debug/testrecorder/feature.server' export { TreeViewFeature } from './field/features/debug/treeview/feature.server' -export { BoldTextFeature } from './field/features/format/bold' +export { BoldFeature } from './field/features/format/bold/feature.server' export { SectionWithEntries as FormatSectionWithEntries } from './field/features/format/common/floatingSelectToolbarSection' -export { InlineCodeTextFeature } from './field/features/format/inlinecode' -export { ItalicTextFeature } from './field/features/format/italic' -export { StrikethroughTextFeature } from './field/features/format/strikethrough' -export { SubscriptTextFeature } from './field/features/format/subscript' -export { SuperscriptTextFeature } from './field/features/format/superscript' -export { UnderlineTextFeature } from './field/features/format/underline' +export { InlineCodeFeature } from './field/features/format/inlinecode/feature.server' +export { ItalicFeature } from './field/features/format/italic/feature.server' +export { StrikethroughFeature } from './field/features/format/strikethrough/feature.server' +export { SubscriptFeature } from './field/features/format/subscript/feature.server' +export { SuperscriptFeature } from './field/features/format/superscript/feature.server' +export { UnderlineFeature } from './field/features/format/underline/feature.server' export { HeadingFeature } from './field/features/heading' export { IndentFeature } from './field/features/indent' diff --git a/test/buildConfigWithDefaults.ts b/test/buildConfigWithDefaults.ts index 466e99ff44..a1c347da87 100644 --- a/test/buildConfigWithDefaults.ts +++ b/test/buildConfigWithDefaults.ts @@ -2,7 +2,15 @@ import { AlignFeature, BlockQuoteFeature, BlocksFeature, + BoldFeature, + InlineCodeFeature, + ItalicFeature, LinkFeature, + StrikethroughFeature, + SubscriptFeature, + SuperscriptFeature, + TreeViewFeature, + UnderlineFeature, lexicalEditor, } from '@payloadcms/richtext-lexical' import path from 'path' @@ -83,6 +91,14 @@ export function buildConfigWithDefaults(testConfig?: Partial): Promise