chore(richtext-lexical): split up feature types in client & server feature types (#6921)
This commit is contained in:
@@ -7,7 +7,7 @@ import { useClientFunctions, useTableCell } from '@payloadcms/ui'
|
||||
import { $getRoot } from 'lexical'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
import type { FeatureProviderClient } from '../features/types.js'
|
||||
import type { FeatureProviderClient } from '../features/typesClient.js'
|
||||
import type { SanitizedClientEditorConfig } from '../lexical/config/types.js'
|
||||
import type { GeneratedFeatureProviderComponent, LexicalFieldAdminProps } from '../types.js'
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ export { RelationshipFeatureClient } from '../../features/relationship/feature.c
|
||||
export { toolbarAddDropdownGroupWithItems } from '../../features/shared/toolbar/addDropdownGroup.js'
|
||||
export { toolbarFeatureButtonsGroupWithItems } from '../../features/shared/toolbar/featureButtonsGroup.js'
|
||||
export { toolbarTextDropdownGroupWithItems } from '../../features/shared/toolbar/textDropdownGroup.js'
|
||||
export { FixedToolbarFeatureClientComponent } from '../../features/toolbars/fixed/feature.client.js'
|
||||
export { InlineToolbarFeatureClientComponent } from '../../features/toolbars/inline/feature.client.js'
|
||||
export { FixedToolbarFeatureClient } from '../../features/toolbars/fixed/feature.client.js'
|
||||
export { InlineToolbarFeatureClient } from '../../features/toolbars/inline/feature.client.js'
|
||||
export { ToolbarButton } from '../../features/toolbars/shared/ToolbarButton/index.js'
|
||||
|
||||
export { ToolbarDropdown } from '../../features/toolbars/shared/ToolbarDropdown/index.js'
|
||||
export { UploadFeatureClientComponent } from '../../features/upload/feature.client.js'
|
||||
export { UploadFeatureClient } from '../../features/upload/feature.client.js'
|
||||
|
||||
export { RichTextField } from '../../field/index.js'
|
||||
export {
|
||||
|
||||
@@ -25,7 +25,7 @@ import { getTranslation } from '@payloadcms/translations'
|
||||
import { getFormState } from '@payloadcms/ui/shared'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
import type { ClientComponentProps } from '../../types.js'
|
||||
import type { ClientComponentProps } from '../../typesClient.js'
|
||||
import type { BlocksFeatureClientProps } from '../feature.client.js'
|
||||
|
||||
import { useEditorConfigContext } from '../../../lexical/config/client/EditorConfigProvider.js'
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { $getNodeByKey, COMMAND_PRIORITY_EDITOR, createCommand } from 'lexical'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import type { ClientComponentProps } from '../../types.js'
|
||||
import type { ClientComponentProps } from '../../typesClient.js'
|
||||
import type { BlocksFeatureClientProps } from '../feature.client.js'
|
||||
|
||||
import { useEditorConfigContext } from '../../../lexical/config/client/EditorConfigProvider.js'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PopulationPromise } from '../types.js'
|
||||
import type { PopulationPromise } from '../typesServer.js'
|
||||
import type { BlocksFeatureProps } from './feature.server.js'
|
||||
import type { SerializedBlockNode } from './nodes/BlocksNode.js'
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from 'lexical'
|
||||
import React, { useEffect } from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../types.js'
|
||||
import type { PluginComponent } from '../../typesClient.js'
|
||||
import type { BlocksFeatureClientProps } from '../feature.client.js'
|
||||
import type { BlockFields } from '../nodes/BlocksNode.js'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { buildStateFromSchema } from '@payloadcms/ui/forms/buildStateFromSchema'
|
||||
|
||||
import type { NodeValidation } from '../types.js'
|
||||
import type { NodeValidation } from '../typesServer.js'
|
||||
import type { BlocksFeatureProps } from './feature.server.js'
|
||||
import type { BlockFields, SerializedBlockNode } from './nodes/BlocksNode.js'
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import type { FeatureProviderProviderClient, ServerFeature } from './types.js'
|
||||
import type { FeatureProviderProviderClient } from './typesClient.js'
|
||||
import type { ServerFeature } from './typesServer.js'
|
||||
|
||||
import { useLexicalFeature } from '../utilities/useLexicalFeature.js'
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { $createParagraphNode, $createTextNode, $getRoot } from 'lexical'
|
||||
import * as React from 'react'
|
||||
import { type JSX, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../../types.js'
|
||||
import type { PluginComponent } from '../../../typesClient.js'
|
||||
|
||||
import { IS_APPLE } from '../../../../lexical/utils/environment.js'
|
||||
import './index.scss'
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext
|
||||
import { TreeView } from '@lexical/react/LexicalTreeView.js'
|
||||
import * as React from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../../types.js'
|
||||
import type { PluginComponent } from '../../../typesClient.js'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { $insertNodeToNearestRoot } from '@lexical/utils'
|
||||
import { $getSelection, $isRangeSelection, COMMAND_PRIORITY_EDITOR } from 'lexical'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../types.js'
|
||||
import type { PluginComponent } from '../../typesClient.js'
|
||||
|
||||
import {
|
||||
$createHorizontalRuleNode,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PopulationPromise } from '../types.js'
|
||||
import type { PopulationPromise } from '../typesServer.js'
|
||||
import type { LinkFeatureServerProps } from './feature.server.js'
|
||||
import type { SerializedLinkNode } from './nodes/types.js'
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from 'lexical'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../../types.js'
|
||||
import type { PluginComponent } from '../../../typesClient.js'
|
||||
import type { ClientProps } from '../../feature.client.js'
|
||||
import type { LinkFields } from '../../nodes/types.js'
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ClickableLinkPlugin as LexicalClickableLinkPlugin } from '@lexical/react/LexicalClickableLinkPlugin.js'
|
||||
import React from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../../types.js'
|
||||
import type { PluginComponent } from '../../../typesClient.js'
|
||||
import type { ClientProps } from '../../feature.client.js'
|
||||
|
||||
export const ClickableLinkPlugin: PluginComponent<ClientProps> = () => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import * as React from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
|
||||
import type { PluginComponentWithAnchor } from '../../../types.js'
|
||||
import type { PluginComponentWithAnchor } from '../../../typesClient.js'
|
||||
import type { ClientProps } from '../../feature.client.js'
|
||||
|
||||
import { LinkEditor } from './LinkEditor/index.js'
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from 'lexical'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../../types.js'
|
||||
import type { PluginComponent } from '../../../typesClient.js'
|
||||
import type { ClientProps } from '../../feature.client.js'
|
||||
import type { LinkFields } from '../../nodes/types.js'
|
||||
import type { LinkPayload } from '../floatingLinkEditor/types.js'
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Field } from 'payload'
|
||||
|
||||
import { buildStateFromSchema } from '@payloadcms/ui/forms/buildStateFromSchema'
|
||||
|
||||
import type { NodeValidation } from '../types.js'
|
||||
import type { NodeValidation } from '../typesServer.js'
|
||||
import type { LinkFeatureServerProps } from './feature.server.js'
|
||||
import type { SerializedAutoLinkNode, SerializedLinkNode } from './nodes/types.js'
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { $isListNode, INSERT_CHECK_LIST_COMMAND, ListItemNode, ListNode } from '
|
||||
import { $isRangeSelection } from 'lexical'
|
||||
|
||||
import type { ToolbarGroup } from '../../toolbars/types.js'
|
||||
import type { ClientFeature } from '../../types.js'
|
||||
import type { ClientFeature } from '../../typesClient.js'
|
||||
|
||||
import { ChecklistIcon } from '../../../lexical/ui/icons/Checklist/index.js'
|
||||
import { createClientFeature } from '../../../utilities/createClientFeature.js'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin.js'
|
||||
import React from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../../types.js'
|
||||
import type { PluginComponent } from '../../../typesClient.js'
|
||||
|
||||
export const LexicalCheckListPlugin: PluginComponent<undefined> = () => {
|
||||
return <CheckListPlugin />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ListPlugin } from '@lexical/react/LexicalListPlugin.js'
|
||||
import React from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../types.js'
|
||||
import type { PluginComponent } from '../../typesClient.js'
|
||||
|
||||
export const LexicalListPlugin: PluginComponent<undefined> = () => {
|
||||
return <ListPlugin />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PopulationPromise } from '../types.js'
|
||||
import type { PopulationPromise } from '../typesServer.js'
|
||||
import type { RelationshipFeatureProps } from './feature.server.js'
|
||||
import type { SerializedRelationshipNode } from './nodes/RelationshipNode.js'
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from 'lexical'
|
||||
import React, { useEffect } from 'react'
|
||||
|
||||
import type { PluginComponent } from '../../types.js'
|
||||
import type { PluginComponent } from '../../typesClient.js'
|
||||
import type { RelationshipFeatureProps } from '../feature.server.js'
|
||||
import type { RelationshipData } from '../nodes/RelationshipNode.js'
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useMemo } from 'react'
|
||||
|
||||
import type { EditorConfigContextType } from '../../../../lexical/config/client/EditorConfigProvider.js'
|
||||
import type { SanitizedClientEditorConfig } from '../../../../lexical/config/types.js'
|
||||
import type { PluginComponentWithAnchor } from '../../../types.js'
|
||||
import type { PluginComponentWithAnchor } from '../../../typesClient.js'
|
||||
import type { ToolbarGroup, ToolbarGroupItem } from '../../types.js'
|
||||
import type { FixedToolbarFeatureProps } from '../feature.server.js'
|
||||
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
'use client'
|
||||
|
||||
import type { FeatureProviderProviderClient } from '../../types.js'
|
||||
import type { FixedToolbarFeatureProps } from './feature.server.js'
|
||||
|
||||
import { createClientComponent } from '../../createClientComponent.js'
|
||||
import { createClientFeature } from '../../../utilities/createClientFeature.js'
|
||||
import { FixedToolbarPlugin } from './Toolbar/index.js'
|
||||
|
||||
const FixedToolbarFeatureClient: FeatureProviderProviderClient<FixedToolbarFeatureProps> = (
|
||||
props,
|
||||
) => {
|
||||
return {
|
||||
clientFeatureProps: props,
|
||||
feature: {
|
||||
plugins: [
|
||||
{
|
||||
Component: FixedToolbarPlugin,
|
||||
position: 'aboveContainer',
|
||||
},
|
||||
],
|
||||
sanitizedClientFeatureProps: props,
|
||||
export const FixedToolbarFeatureClient = createClientFeature<FixedToolbarFeatureProps>({
|
||||
plugins: [
|
||||
{
|
||||
Component: FixedToolbarPlugin,
|
||||
position: 'aboveContainer',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const FixedToolbarFeatureClientComponent = createClientComponent(FixedToolbarFeatureClient)
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { FeatureProviderProviderServer } from '../../types.js'
|
||||
|
||||
// eslint-disable-next-line payload/no-imports-from-exports-dir
|
||||
import { FixedToolbarFeatureClientComponent } from '../../../exports/client/index.js'
|
||||
import { FixedToolbarFeatureClient } from '../../../exports/client/index.js'
|
||||
import { createServerFeature } from '../../../utilities/createServerFeature.js'
|
||||
|
||||
export type FixedToolbarFeatureProps = {
|
||||
/**
|
||||
@@ -20,29 +19,26 @@ export type FixedToolbarFeatureProps = {
|
||||
disableIfParentHasFixedToolbar?: boolean
|
||||
}
|
||||
|
||||
export const FixedToolbarFeature: FeatureProviderProviderServer<
|
||||
export const FixedToolbarFeature = createServerFeature<
|
||||
FixedToolbarFeatureProps,
|
||||
FixedToolbarFeatureProps,
|
||||
FixedToolbarFeatureProps
|
||||
> = (props) => {
|
||||
return {
|
||||
feature: () => {
|
||||
const sanitizedProps: FixedToolbarFeatureProps = {
|
||||
applyToFocusedEditor:
|
||||
props?.applyToFocusedEditor === undefined ? false : props.applyToFocusedEditor,
|
||||
disableIfParentHasFixedToolbar:
|
||||
props?.disableIfParentHasFixedToolbar === undefined
|
||||
? false
|
||||
: props.disableIfParentHasFixedToolbar,
|
||||
}
|
||||
>({
|
||||
feature: ({ props }) => {
|
||||
const sanitizedProps: FixedToolbarFeatureProps = {
|
||||
applyToFocusedEditor:
|
||||
props?.applyToFocusedEditor === undefined ? false : props.applyToFocusedEditor,
|
||||
disableIfParentHasFixedToolbar:
|
||||
props?.disableIfParentHasFixedToolbar === undefined
|
||||
? false
|
||||
: props.disableIfParentHasFixedToolbar,
|
||||
}
|
||||
|
||||
return {
|
||||
ClientFeature: FixedToolbarFeatureClientComponent,
|
||||
clientFeatureProps: sanitizedProps,
|
||||
sanitizedServerFeatureProps: sanitizedProps,
|
||||
}
|
||||
},
|
||||
key: 'toolbarFixed',
|
||||
serverFeatureProps: props,
|
||||
}
|
||||
}
|
||||
return {
|
||||
ClientFeature: FixedToolbarFeatureClient,
|
||||
clientFeatureProps: sanitizedProps,
|
||||
sanitizedServerFeatureProps: sanitizedProps,
|
||||
}
|
||||
},
|
||||
key: 'toolbarFixed',
|
||||
})
|
||||
|
||||
@@ -14,7 +14,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import * as React from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
|
||||
import type { PluginComponentWithAnchor } from '../../../types.js'
|
||||
import type { PluginComponentWithAnchor } from '../../../typesClient.js'
|
||||
import type { ToolbarGroup, ToolbarGroupItem } from '../../types.js'
|
||||
|
||||
import { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js'
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
'use client'
|
||||
|
||||
import type { FeatureProviderProviderClient } from '../../types.js'
|
||||
|
||||
import { createClientComponent } from '../../createClientComponent.js'
|
||||
import { createClientFeature } from '../../../utilities/createClientFeature.js'
|
||||
import { InlineToolbarPlugin } from './Toolbar/index.js'
|
||||
|
||||
const InlineToolbarFeatureClient: FeatureProviderProviderClient<undefined> = (props) => {
|
||||
return {
|
||||
clientFeatureProps: props,
|
||||
feature: () => ({
|
||||
plugins: [
|
||||
{
|
||||
Component: InlineToolbarPlugin,
|
||||
position: 'floatingAnchorElem',
|
||||
},
|
||||
],
|
||||
sanitizedClientFeatureProps: props,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export const InlineToolbarFeatureClientComponent = createClientComponent(InlineToolbarFeatureClient)
|
||||
export const InlineToolbarFeatureClient = createClientFeature({
|
||||
plugins: [
|
||||
{
|
||||
Component: InlineToolbarPlugin,
|
||||
position: 'floatingAnchorElem',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import type { FeatureProviderProviderServer } from '../../types.js'
|
||||
|
||||
// eslint-disable-next-line payload/no-imports-from-exports-dir
|
||||
import { InlineToolbarFeatureClientComponent } from '../../../exports/client/index.js'
|
||||
import { InlineToolbarFeatureClient } from '../../../exports/client/index.js'
|
||||
import { createServerFeature } from '../../../utilities/createServerFeature.js'
|
||||
|
||||
export const InlineToolbarFeature: FeatureProviderProviderServer<undefined, undefined> = (
|
||||
props,
|
||||
) => {
|
||||
return {
|
||||
feature: {
|
||||
ClientFeature: InlineToolbarFeatureClientComponent,
|
||||
sanitizedServerFeatureProps: props,
|
||||
},
|
||||
key: 'toolbarInline',
|
||||
serverFeatureProps: props,
|
||||
}
|
||||
}
|
||||
export const InlineToolbarFeature = createServerFeature({
|
||||
feature: {
|
||||
ClientFeature: InlineToolbarFeatureClient,
|
||||
},
|
||||
key: 'toolbarInline',
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { LexicalNode } from 'lexical'
|
||||
|
||||
import type { NodeWithHooks } from './types.js'
|
||||
import type { NodeWithHooks } from './typesServer.js'
|
||||
|
||||
/**
|
||||
* Utility function to create a node with hooks. You don't have to use this utility, but it improves type inference
|
||||
|
||||
251
packages/richtext-lexical/src/features/typesClient.ts
Normal file
251
packages/richtext-lexical/src/features/typesClient.ts
Normal file
@@ -0,0 +1,251 @@
|
||||
import type { Transformer } from '@lexical/markdown'
|
||||
import type {
|
||||
Klass,
|
||||
LexicalEditor,
|
||||
LexicalNode,
|
||||
LexicalNodeReplacement,
|
||||
SerializedEditorState,
|
||||
} from 'lexical'
|
||||
import type React from 'react'
|
||||
|
||||
import type { ClientEditorConfig } from '../lexical/config/types.js'
|
||||
import type { SlashMenuGroup } from '../lexical/plugins/SlashMenu/LexicalTypeaheadMenuPlugin/types.js'
|
||||
import type { ToolbarGroup } from './toolbars/types.js'
|
||||
|
||||
export type FeatureProviderProviderClient<
|
||||
UnSanitizedClientFeatureProps = undefined,
|
||||
ClientFeatureProps = UnSanitizedClientFeatureProps,
|
||||
> = (props: ClientComponentProps<ClientFeatureProps>) => FeatureProviderClient<ClientFeatureProps>
|
||||
|
||||
/**
|
||||
* No dependencies => Features need to be sorted on the server first, then sent to client in right order
|
||||
*/
|
||||
export type FeatureProviderClient<
|
||||
UnSanitizedClientFeatureProps = undefined,
|
||||
ClientFeatureProps = UnSanitizedClientFeatureProps,
|
||||
> = {
|
||||
/**
|
||||
* Return props, to make it easy to retrieve passed in props to this Feature for the client if anyone wants to
|
||||
*/
|
||||
clientFeatureProps: ClientComponentProps<UnSanitizedClientFeatureProps>
|
||||
feature:
|
||||
| ((props: {
|
||||
clientFunctions: Record<string, any>
|
||||
/** unSanitizedEditorConfig.features, but mapped */
|
||||
featureProviderMap: ClientFeatureProviderMap
|
||||
// other resolved features, which have been loaded before this one. All features declared in 'dependencies' should be available here
|
||||
resolvedFeatures: ResolvedClientFeatureMap
|
||||
// unSanitized EditorConfig,
|
||||
unSanitizedEditorConfig: ClientEditorConfig
|
||||
}) => ClientFeature<ClientFeatureProps>)
|
||||
| ClientFeature<ClientFeatureProps>
|
||||
}
|
||||
|
||||
export type PluginComponent<ClientFeatureProps = any> = React.FC<{
|
||||
clientProps: ClientFeatureProps
|
||||
}>
|
||||
export type PluginComponentWithAnchor<ClientFeatureProps = any> = React.FC<{
|
||||
anchorElem: HTMLElement
|
||||
clientProps: ClientFeatureProps
|
||||
}>
|
||||
|
||||
export type ClientFeature<ClientFeatureProps> = {
|
||||
hooks?: {
|
||||
load?: ({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
save?: ({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
}
|
||||
markdownTransformers?: Transformer[]
|
||||
nodes?: Array<Klass<LexicalNode> | LexicalNodeReplacement>
|
||||
/**
|
||||
* Plugins are react components which get added to the editor. You can use them to interact with lexical, e.g. to create a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
*/
|
||||
plugins?: Array<
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'aboveContainer' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'bottom' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'normal' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'top' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponentWithAnchor<ClientFeatureProps>
|
||||
position: 'floatingAnchorElem' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'belowContainer' // Determines at which position the Component will be added.
|
||||
}
|
||||
>
|
||||
/**
|
||||
* Return props, to make it easy to retrieve passed in props to this Feature for the client if anyone wants to
|
||||
*/
|
||||
sanitizedClientFeatureProps?: ClientComponentProps<ClientFeatureProps>
|
||||
slashMenu?: {
|
||||
/**
|
||||
* Dynamic groups allow you to add different groups depending on the query string (so, the text after the slash).
|
||||
* Thus, to re-calculate the available groups, this function will be called every time you type after the /.
|
||||
*
|
||||
* The groups provided by dynamicGroups will be merged with the static groups provided by the groups property.
|
||||
*/
|
||||
dynamicGroups?: ({
|
||||
editor,
|
||||
queryString,
|
||||
}: {
|
||||
editor: LexicalEditor
|
||||
queryString: string
|
||||
}) => SlashMenuGroup[]
|
||||
/**
|
||||
* Static array of groups together with the items in them. These will always be present.
|
||||
* While typing after the /, they will be filtered by the query string and the keywords, key and display name of the items.
|
||||
*/
|
||||
groups?: SlashMenuGroup[]
|
||||
}
|
||||
/**
|
||||
* An opt-in, classic fixed toolbar which stays at the top of the editor
|
||||
*/
|
||||
toolbarFixed?: {
|
||||
groups: ToolbarGroup[]
|
||||
}
|
||||
/**
|
||||
* The default, floating toolbar which appears when you select text.
|
||||
*/
|
||||
toolbarInline?: {
|
||||
/**
|
||||
* Array of toolbar groups / sections. Each section can contain multiple toolbar items.
|
||||
*/
|
||||
groups: ToolbarGroup[]
|
||||
}
|
||||
}
|
||||
|
||||
export type ClientComponentProps<ClientFeatureProps> = ClientFeatureProps extends undefined
|
||||
? {
|
||||
featureKey: string
|
||||
order: number
|
||||
}
|
||||
: {
|
||||
featureKey: string
|
||||
order: number
|
||||
} & ClientFeatureProps
|
||||
|
||||
export type ResolvedClientFeature<ClientFeatureProps> = ClientFeature<ClientFeatureProps> & {
|
||||
key: string
|
||||
order: number
|
||||
}
|
||||
|
||||
export type ResolvedClientFeatureMap = Map<string, ResolvedClientFeature<unknown>>
|
||||
|
||||
export type ClientFeatureProviderMap = Map<string, FeatureProviderClient<unknown, unknown>>
|
||||
|
||||
/**
|
||||
* Plugins are react components which get added to the editor. You can use them to interact with lexical, e.g. to create a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
*/
|
||||
export type SanitizedPlugin =
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'bottom' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'normal' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'top' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponentWithAnchor
|
||||
clientProps: any
|
||||
desktopOnly?: boolean
|
||||
key: string
|
||||
position: 'floatingAnchorElem' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'aboveContainer'
|
||||
}
|
||||
| {
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'belowContainer'
|
||||
}
|
||||
|
||||
export type SanitizedClientFeatures = Required<
|
||||
Pick<
|
||||
ResolvedClientFeature<unknown>,
|
||||
'markdownTransformers' | 'nodes' | 'toolbarFixed' | 'toolbarInline'
|
||||
>
|
||||
> & {
|
||||
/** The keys of all enabled features */
|
||||
enabledFeatures: string[]
|
||||
hooks: {
|
||||
load: Array<
|
||||
({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
>
|
||||
save: Array<
|
||||
({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
>
|
||||
}
|
||||
/**
|
||||
* Plugins are react components which get added to the editor. You can use them to interact with lexical, e.g. to create a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
*/
|
||||
plugins?: Array<SanitizedPlugin>
|
||||
slashMenu: {
|
||||
/**
|
||||
* Dynamic groups allow you to add different groups depending on the query string (so, the text after the slash).
|
||||
* Thus, to re-calculate the available groups, this function will be called every time you type after the /.
|
||||
*
|
||||
* The groups provided by dynamicGroups will be merged with the static groups provided by the groups property.
|
||||
*/
|
||||
dynamicGroups: Array<
|
||||
({ editor, queryString }: { editor: LexicalEditor; queryString: string }) => SlashMenuGroup[]
|
||||
>
|
||||
/**
|
||||
* Static array of groups together with the items in them. These will always be present.
|
||||
* While typing after the /, they will be filtered by the query string and the keywords, key and display name of the items.
|
||||
*/
|
||||
groups: SlashMenuGroup[]
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import type { GenericLanguages, I18nClient } from '@payloadcms/translations'
|
||||
import type { JSONSchema4 } from 'json-schema'
|
||||
import type {
|
||||
Klass,
|
||||
LexicalEditor,
|
||||
LexicalNode,
|
||||
LexicalNodeReplacement,
|
||||
SerializedEditorState,
|
||||
@@ -20,11 +19,10 @@ import type {
|
||||
} from 'payload'
|
||||
import type React from 'react'
|
||||
|
||||
import type { ClientEditorConfig, ServerEditorConfig } from '../lexical/config/types.js'
|
||||
import type { SlashMenuGroup } from '../lexical/plugins/SlashMenu/LexicalTypeaheadMenuPlugin/types.js'
|
||||
import type { ServerEditorConfig } from '../lexical/config/types.js'
|
||||
import type { AdapterProps } from '../types.js'
|
||||
import type { HTMLConverter } from './converters/html/converter/types.js'
|
||||
import type { ToolbarGroup } from './toolbars/types.js'
|
||||
import type { ClientComponentProps } from './typesClient.js'
|
||||
|
||||
export type PopulationPromise<T extends SerializedLexicalNode = SerializedLexicalNode> = ({
|
||||
context,
|
||||
@@ -121,143 +119,6 @@ export type FeatureProviderServer<
|
||||
serverFeatureProps: UnSanitizedServerFeatureProps
|
||||
}
|
||||
|
||||
export type FeatureProviderProviderClient<
|
||||
UnSanitizedClientFeatureProps = undefined,
|
||||
ClientFeatureProps = UnSanitizedClientFeatureProps,
|
||||
> = (props: ClientComponentProps<ClientFeatureProps>) => FeatureProviderClient<ClientFeatureProps>
|
||||
|
||||
/**
|
||||
* No dependencies => Features need to be sorted on the server first, then sent to client in right order
|
||||
*/
|
||||
export type FeatureProviderClient<
|
||||
UnSanitizedClientFeatureProps = undefined,
|
||||
ClientFeatureProps = UnSanitizedClientFeatureProps,
|
||||
> = {
|
||||
/**
|
||||
* Return props, to make it easy to retrieve passed in props to this Feature for the client if anyone wants to
|
||||
*/
|
||||
clientFeatureProps: ClientComponentProps<UnSanitizedClientFeatureProps>
|
||||
feature:
|
||||
| ((props: {
|
||||
clientFunctions: Record<string, any>
|
||||
/** unSanitizedEditorConfig.features, but mapped */
|
||||
featureProviderMap: ClientFeatureProviderMap
|
||||
// other resolved features, which have been loaded before this one. All features declared in 'dependencies' should be available here
|
||||
resolvedFeatures: ResolvedClientFeatureMap
|
||||
// unSanitized EditorConfig,
|
||||
unSanitizedEditorConfig: ClientEditorConfig
|
||||
}) => ClientFeature<ClientFeatureProps>)
|
||||
| ClientFeature<ClientFeatureProps>
|
||||
}
|
||||
|
||||
export type PluginComponent<ClientFeatureProps = any> = React.FC<{
|
||||
clientProps: ClientFeatureProps
|
||||
}>
|
||||
export type PluginComponentWithAnchor<ClientFeatureProps = any> = React.FC<{
|
||||
anchorElem: HTMLElement
|
||||
clientProps: ClientFeatureProps
|
||||
}>
|
||||
|
||||
export type ClientFeature<ClientFeatureProps> = {
|
||||
hooks?: {
|
||||
load?: ({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
save?: ({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
}
|
||||
markdownTransformers?: Transformer[]
|
||||
nodes?: Array<Klass<LexicalNode> | LexicalNodeReplacement>
|
||||
/**
|
||||
* Plugins are react components which get added to the editor. You can use them to interact with lexical, e.g. to create a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
*/
|
||||
plugins?: Array<
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'aboveContainer' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'bottom' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'normal' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'top' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponentWithAnchor<ClientFeatureProps>
|
||||
position: 'floatingAnchorElem' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
Component: PluginComponent<ClientFeatureProps>
|
||||
position: 'belowContainer' // Determines at which position the Component will be added.
|
||||
}
|
||||
>
|
||||
/**
|
||||
* Return props, to make it easy to retrieve passed in props to this Feature for the client if anyone wants to
|
||||
*/
|
||||
sanitizedClientFeatureProps?: ClientComponentProps<ClientFeatureProps>
|
||||
slashMenu?: {
|
||||
/**
|
||||
* Dynamic groups allow you to add different groups depending on the query string (so, the text after the slash).
|
||||
* Thus, to re-calculate the available groups, this function will be called every time you type after the /.
|
||||
*
|
||||
* The groups provided by dynamicGroups will be merged with the static groups provided by the groups property.
|
||||
*/
|
||||
dynamicGroups?: ({
|
||||
editor,
|
||||
queryString,
|
||||
}: {
|
||||
editor: LexicalEditor
|
||||
queryString: string
|
||||
}) => SlashMenuGroup[]
|
||||
/**
|
||||
* Static array of groups together with the items in them. These will always be present.
|
||||
* While typing after the /, they will be filtered by the query string and the keywords, key and display name of the items.
|
||||
*/
|
||||
groups?: SlashMenuGroup[]
|
||||
}
|
||||
/**
|
||||
* An opt-in, classic fixed toolbar which stays at the top of the editor
|
||||
*/
|
||||
toolbarFixed?: {
|
||||
groups: ToolbarGroup[]
|
||||
}
|
||||
/**
|
||||
* The default, floating toolbar which appears when you select text.
|
||||
*/
|
||||
toolbarInline?: {
|
||||
/**
|
||||
* Array of toolbar groups / sections. Each section can contain multiple toolbar items.
|
||||
*/
|
||||
groups: ToolbarGroup[]
|
||||
}
|
||||
}
|
||||
|
||||
export type ClientComponentProps<ClientFeatureProps> = ClientFeatureProps extends undefined
|
||||
? {
|
||||
featureKey: string
|
||||
order: number
|
||||
}
|
||||
: {
|
||||
featureKey: string
|
||||
order: number
|
||||
} & ClientFeatureProps
|
||||
|
||||
export type AfterReadNodeHookArgs<T extends SerializedLexicalNode> = {
|
||||
/**
|
||||
* Only available in `afterRead` hooks.
|
||||
@@ -472,62 +333,9 @@ export type ResolvedServerFeature<ServerProps, ClientFeatureProps> = ServerFeatu
|
||||
order: number
|
||||
}
|
||||
|
||||
export type ResolvedClientFeature<ClientFeatureProps> = ClientFeature<ClientFeatureProps> & {
|
||||
key: string
|
||||
order: number
|
||||
}
|
||||
|
||||
export type ResolvedServerFeatureMap = Map<string, ResolvedServerFeature<unknown, unknown>>
|
||||
export type ResolvedClientFeatureMap = Map<string, ResolvedClientFeature<unknown>>
|
||||
|
||||
export type ServerFeatureProviderMap = Map<string, FeatureProviderServer<unknown, unknown, unknown>>
|
||||
export type ClientFeatureProviderMap = Map<string, FeatureProviderClient<unknown, unknown>>
|
||||
|
||||
/**
|
||||
* Plugins are react components which get added to the editor. You can use them to interact with lexical, e.g. to create a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
*/
|
||||
export type SanitizedPlugin =
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'bottom' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'normal' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'top' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
// plugins are anything which is not directly part of the editor. Like, creating a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
Component: PluginComponentWithAnchor
|
||||
clientProps: any
|
||||
desktopOnly?: boolean
|
||||
key: string
|
||||
position: 'floatingAnchorElem' // Determines at which position the Component will be added.
|
||||
}
|
||||
| {
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'aboveContainer'
|
||||
}
|
||||
| {
|
||||
Component: PluginComponent
|
||||
clientProps: any
|
||||
key: string
|
||||
position: 'belowContainer'
|
||||
}
|
||||
|
||||
export type SanitizedServerFeatures = Required<
|
||||
Pick<ResolvedServerFeature<unknown, unknown>, 'i18n' | 'markdownTransformers' | 'nodes'>
|
||||
@@ -583,49 +391,3 @@ export type SanitizedServerFeatures = Required<
|
||||
/** The node types mapped to their validations */
|
||||
validations: Map<string, Array<NodeValidation>>
|
||||
}
|
||||
|
||||
export type SanitizedClientFeatures = Required<
|
||||
Pick<
|
||||
ResolvedClientFeature<unknown>,
|
||||
'markdownTransformers' | 'nodes' | 'toolbarFixed' | 'toolbarInline'
|
||||
>
|
||||
> & {
|
||||
/** The keys of all enabled features */
|
||||
enabledFeatures: string[]
|
||||
hooks: {
|
||||
load: Array<
|
||||
({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
>
|
||||
save: Array<
|
||||
({
|
||||
incomingEditorState,
|
||||
}: {
|
||||
incomingEditorState: SerializedEditorState
|
||||
}) => SerializedEditorState
|
||||
>
|
||||
}
|
||||
/**
|
||||
* Plugins are react components which get added to the editor. You can use them to interact with lexical, e.g. to create a command which creates a node, or opens a modal, or some other more "outside" functionality
|
||||
*/
|
||||
plugins?: Array<SanitizedPlugin>
|
||||
slashMenu: {
|
||||
/**
|
||||
* Dynamic groups allow you to add different groups depending on the query string (so, the text after the slash).
|
||||
* Thus, to re-calculate the available groups, this function will be called every time you type after the /.
|
||||
*
|
||||
* The groups provided by dynamicGroups will be merged with the static groups provided by the groups property.
|
||||
*/
|
||||
dynamicGroups: Array<
|
||||
({ editor, queryString }: { editor: LexicalEditor; queryString: string }) => SlashMenuGroup[]
|
||||
>
|
||||
/**
|
||||
* Static array of groups together with the items in them. These will always be present.
|
||||
* While typing after the /, they will be filtered by the query string and the keywords, key and display name of the items.
|
||||
*/
|
||||
groups: SlashMenuGroup[]
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
} from 'lexical'
|
||||
import React, { useCallback, useEffect, useReducer, useRef, useState } from 'react'
|
||||
|
||||
import type { ClientComponentProps } from '../../types.js'
|
||||
import type { ClientComponentProps } from '../../typesClient.js'
|
||||
import type { UploadFeaturePropsClient } from '../feature.client.js'
|
||||
import type { UploadData } from '../nodes/UploadNode.js'
|
||||
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
|
||||
import { $isNodeSelection } from 'lexical'
|
||||
|
||||
import type { FeatureProviderProviderClient } from '../types.js'
|
||||
|
||||
import { UploadIcon } from '../../lexical/ui/icons/Upload/index.js'
|
||||
import { createClientComponent } from '../createClientComponent.js'
|
||||
import { createClientFeature } from '../../utilities/createClientFeature.js'
|
||||
import { slashMenuBasicGroupWithItems } from '../shared/slashMenu/basicGroup.js'
|
||||
import { toolbarAddDropdownGroupWithItems } from '../shared/toolbar/addDropdownGroup.js'
|
||||
import { INSERT_UPLOAD_WITH_DRAWER_COMMAND } from './drawer/commands.js'
|
||||
@@ -20,65 +18,57 @@ export type UploadFeaturePropsClient = {
|
||||
}
|
||||
}
|
||||
|
||||
const UploadFeatureClient: FeatureProviderProviderClient<UploadFeaturePropsClient> = (props) => {
|
||||
return {
|
||||
clientFeatureProps: props,
|
||||
feature: () => ({
|
||||
nodes: [UploadNode],
|
||||
plugins: [
|
||||
export const UploadFeatureClient = createClientFeature<UploadFeaturePropsClient>({
|
||||
nodes: [UploadNode],
|
||||
plugins: [
|
||||
{
|
||||
Component: UploadPlugin,
|
||||
position: 'normal',
|
||||
},
|
||||
],
|
||||
slashMenu: {
|
||||
groups: [
|
||||
slashMenuBasicGroupWithItems([
|
||||
{
|
||||
Component: UploadPlugin,
|
||||
position: 'normal',
|
||||
Icon: UploadIcon,
|
||||
key: 'upload',
|
||||
keywords: ['upload', 'image', 'file', 'img', 'picture', 'photo', 'media'],
|
||||
label: ({ i18n }) => {
|
||||
return i18n.t('lexical:upload:label')
|
||||
},
|
||||
onSelect: ({ editor }) => {
|
||||
editor.dispatchCommand(INSERT_UPLOAD_WITH_DRAWER_COMMAND, {
|
||||
replace: false,
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
sanitizedClientFeatureProps: props,
|
||||
slashMenu: {
|
||||
groups: [
|
||||
slashMenuBasicGroupWithItems([
|
||||
{
|
||||
Icon: UploadIcon,
|
||||
key: 'upload',
|
||||
keywords: ['upload', 'image', 'file', 'img', 'picture', 'photo', 'media'],
|
||||
label: ({ i18n }) => {
|
||||
return i18n.t('lexical:upload:label')
|
||||
},
|
||||
onSelect: ({ editor }) => {
|
||||
editor.dispatchCommand(INSERT_UPLOAD_WITH_DRAWER_COMMAND, {
|
||||
replace: false,
|
||||
})
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
},
|
||||
toolbarFixed: {
|
||||
groups: [
|
||||
toolbarAddDropdownGroupWithItems([
|
||||
{
|
||||
ChildComponent: UploadIcon,
|
||||
isActive: ({ selection }) => {
|
||||
if (!$isNodeSelection(selection) || !selection.getNodes().length) {
|
||||
return false
|
||||
}
|
||||
]),
|
||||
],
|
||||
},
|
||||
toolbarFixed: {
|
||||
groups: [
|
||||
toolbarAddDropdownGroupWithItems([
|
||||
{
|
||||
ChildComponent: UploadIcon,
|
||||
isActive: ({ selection }) => {
|
||||
if (!$isNodeSelection(selection) || !selection.getNodes().length) {
|
||||
return false
|
||||
}
|
||||
|
||||
const firstNode = selection.getNodes()[0]
|
||||
return $isUploadNode(firstNode)
|
||||
},
|
||||
key: 'upload',
|
||||
label: ({ i18n }) => {
|
||||
return i18n.t('lexical:upload:label')
|
||||
},
|
||||
onSelect: ({ editor }) => {
|
||||
editor.dispatchCommand(INSERT_UPLOAD_WITH_DRAWER_COMMAND, {
|
||||
replace: false,
|
||||
})
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export const UploadFeatureClientComponent = createClientComponent(UploadFeatureClient)
|
||||
const firstNode = selection.getNodes()[0]
|
||||
return $isUploadNode(firstNode)
|
||||
},
|
||||
key: 'upload',
|
||||
label: ({ i18n }) => {
|
||||
return i18n.t('lexical:upload:label')
|
||||
},
|
||||
onSelect: ({ editor }) => {
|
||||
editor.dispatchCommand(INSERT_UPLOAD_WITH_DRAWER_COMMAND, {
|
||||
replace: false,
|
||||
})
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
@@ -11,12 +11,12 @@ import type {
|
||||
import { traverseFields } from '@payloadcms/ui/utilities/buildFieldSchemaMap/traverseFields'
|
||||
import { sanitizeFields } from 'payload'
|
||||
|
||||
import type { FeatureProviderProviderServer } from '../types.js'
|
||||
import type { UploadFeaturePropsClient } from './feature.client.js'
|
||||
|
||||
// eslint-disable-next-line payload/no-imports-from-exports-dir
|
||||
import { UploadFeatureClientComponent } from '../../exports/client/index.js'
|
||||
import { UploadFeatureClient } from '../../exports/client/index.js'
|
||||
import { populate } from '../../populateGraphQL/populate.js'
|
||||
import { createServerFeature } from '../../utilities/createServerFeature.js'
|
||||
import { createNode } from '../typeUtilities.js'
|
||||
import { uploadPopulationPromiseHOC } from './graphQLPopulationPromise.js'
|
||||
import { i18n } from './i18n.js'
|
||||
@@ -45,235 +45,230 @@ function getAbsoluteURL(url: string, payload: Payload): string {
|
||||
return url?.startsWith('http') ? url : (payload?.config?.serverURL || '') + url
|
||||
}
|
||||
|
||||
export const UploadFeature: FeatureProviderProviderServer<
|
||||
export const UploadFeature = createServerFeature<
|
||||
UploadFeatureProps,
|
||||
UploadFeatureProps,
|
||||
UploadFeaturePropsClient
|
||||
> = (props) => {
|
||||
if (!props) {
|
||||
props = { collections: {} }
|
||||
}
|
||||
|
||||
const clientProps: UploadFeaturePropsClient = {
|
||||
collections: {},
|
||||
}
|
||||
if (props.collections) {
|
||||
for (const collection in props.collections) {
|
||||
clientProps.collections[collection] = {
|
||||
hasExtraFields: props.collections[collection].fields.length >= 1,
|
||||
}
|
||||
>({
|
||||
feature: async ({ config: _config, isRoot, props }) => {
|
||||
if (!props) {
|
||||
props = { collections: {} }
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
feature: async ({ config: _config, isRoot }) => {
|
||||
const validRelationships = _config.collections.map((c) => c.slug) || []
|
||||
|
||||
const clientProps: UploadFeaturePropsClient = {
|
||||
collections: {},
|
||||
}
|
||||
if (props.collections) {
|
||||
for (const collection in props.collections) {
|
||||
if (props.collections[collection].fields?.length) {
|
||||
props.collections[collection].fields = await sanitizeFields({
|
||||
config: _config as unknown as Config,
|
||||
fields: props.collections[collection].fields,
|
||||
requireFieldLevelRichTextEditor: isRoot,
|
||||
validRelationships,
|
||||
})
|
||||
clientProps.collections[collection] = {
|
||||
hasExtraFields: props.collections[collection].fields.length >= 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ClientFeature: UploadFeatureClientComponent,
|
||||
clientFeatureProps: clientProps,
|
||||
generateSchemaMap: ({ config, i18n, props }) => {
|
||||
if (!props?.collections) return null
|
||||
const validRelationships = _config.collections.map((c) => c.slug) || []
|
||||
|
||||
const schemaMap = new Map<string, Field[]>()
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
for (const collection in props.collections) {
|
||||
if (props.collections[collection].fields?.length) {
|
||||
schemaMap.set(collection, props.collections[collection].fields)
|
||||
traverseFields({
|
||||
config,
|
||||
fields: props.collections[collection].fields,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath: collection,
|
||||
validRelationships,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return schemaMap
|
||||
},
|
||||
i18n,
|
||||
nodes: [
|
||||
createNode({
|
||||
converters: {
|
||||
html: {
|
||||
converter: async ({ node, req }) => {
|
||||
// @ts-expect-error
|
||||
const id = node?.value?.id || node?.value // for backwards-compatibility
|
||||
|
||||
if (req?.payload) {
|
||||
const uploadDocument: {
|
||||
value?: TypeWithID & FileData
|
||||
} = {}
|
||||
|
||||
try {
|
||||
await populate({
|
||||
id,
|
||||
collectionSlug: node.relationTo,
|
||||
currentDepth: 0,
|
||||
data: uploadDocument,
|
||||
depth: 1,
|
||||
draft: false,
|
||||
key: 'value',
|
||||
overrideAccess: false,
|
||||
req,
|
||||
showHiddenFields: false,
|
||||
})
|
||||
} catch (ignored) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
'Lexical upload node HTML converter: error fetching upload file',
|
||||
ignored,
|
||||
'Node:',
|
||||
node,
|
||||
)
|
||||
return `<img />`
|
||||
}
|
||||
|
||||
const url = getAbsoluteURL(uploadDocument?.value?.url, req?.payload)
|
||||
|
||||
/**
|
||||
* If the upload is not an image, return a link to the upload
|
||||
*/
|
||||
if (!uploadDocument?.value?.mimeType?.startsWith('image')) {
|
||||
return `<a href="${url}" rel="noopener noreferrer">${uploadDocument.value?.filename}</a>`
|
||||
}
|
||||
|
||||
/**
|
||||
* If the upload is a simple image with no different sizes, return a simple img tag
|
||||
*/
|
||||
if (
|
||||
!uploadDocument?.value?.sizes ||
|
||||
!Object.keys(uploadDocument?.value?.sizes).length
|
||||
) {
|
||||
return `<img src="${url}" alt="${uploadDocument?.value?.filename}" width="${uploadDocument?.value?.width}" height="${uploadDocument?.value?.height}"/>`
|
||||
}
|
||||
|
||||
/**
|
||||
* If the upload is an image with different sizes, return a picture element
|
||||
*/
|
||||
let pictureHTML = '<picture>'
|
||||
|
||||
// Iterate through each size in the data.sizes object
|
||||
for (const size in uploadDocument.value?.sizes) {
|
||||
const imageSize: FileSize & {
|
||||
url?: string
|
||||
} = uploadDocument.value?.sizes[size]
|
||||
|
||||
// Skip if any property of the size object is null
|
||||
if (
|
||||
!imageSize.width ||
|
||||
!imageSize.height ||
|
||||
!imageSize.mimeType ||
|
||||
!imageSize.filesize ||
|
||||
!imageSize.filename ||
|
||||
!imageSize.url
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const imageSizeURL = getAbsoluteURL(imageSize?.url, req?.payload)
|
||||
|
||||
pictureHTML += `<source srcset="${imageSizeURL}" media="(max-width: ${imageSize.width}px)" type="${imageSize.mimeType}">`
|
||||
}
|
||||
|
||||
// Add the default img tag
|
||||
pictureHTML += `<img src="${url}" alt="Image" width="${uploadDocument.value?.width}" height="${uploadDocument.value?.height}">`
|
||||
pictureHTML += '</picture>'
|
||||
return pictureHTML
|
||||
} else {
|
||||
return `<img src="${id}" />`
|
||||
}
|
||||
},
|
||||
nodeTypes: [UploadNode.getType()],
|
||||
},
|
||||
},
|
||||
getSubFields: ({ node, req }) => {
|
||||
const collection = req.payload.collections[node?.relationTo]
|
||||
|
||||
if (collection) {
|
||||
const collectionFieldSchema = props?.collections?.[node?.relationTo]?.fields
|
||||
|
||||
if (Array.isArray(collectionFieldSchema)) {
|
||||
if (!collectionFieldSchema?.length) {
|
||||
return null
|
||||
}
|
||||
return collectionFieldSchema
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
getSubFieldsData: ({ node }) => {
|
||||
return node?.fields
|
||||
},
|
||||
graphQLPopulationPromises: [uploadPopulationPromiseHOC(props)],
|
||||
hooks: {
|
||||
afterRead: [
|
||||
({
|
||||
currentDepth,
|
||||
depth,
|
||||
draft,
|
||||
node,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
showHiddenFields,
|
||||
}) => {
|
||||
if (!node?.value) {
|
||||
return node
|
||||
}
|
||||
const collection = req.payload.collections[node?.relationTo]
|
||||
|
||||
if (!collection) {
|
||||
return node
|
||||
}
|
||||
// @ts-expect-error
|
||||
const id = node?.value?.id || node?.value // for backwards-compatibility
|
||||
|
||||
const populateDepth =
|
||||
props?.maxDepth !== undefined && props?.maxDepth < depth
|
||||
? props?.maxDepth
|
||||
: depth
|
||||
|
||||
populationPromises.push(
|
||||
populate({
|
||||
id,
|
||||
collectionSlug: collection.config.slug,
|
||||
currentDepth,
|
||||
data: node,
|
||||
depth: populateDepth,
|
||||
draft,
|
||||
key: 'value',
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
}),
|
||||
)
|
||||
|
||||
return node
|
||||
},
|
||||
],
|
||||
},
|
||||
node: UploadNode,
|
||||
validations: [uploadValidation(props)],
|
||||
}),
|
||||
],
|
||||
sanitizedServerFeatureProps: props,
|
||||
for (const collection in props.collections) {
|
||||
if (props.collections[collection].fields?.length) {
|
||||
props.collections[collection].fields = await sanitizeFields({
|
||||
config: _config as unknown as Config,
|
||||
fields: props.collections[collection].fields,
|
||||
requireFieldLevelRichTextEditor: isRoot,
|
||||
validRelationships,
|
||||
})
|
||||
}
|
||||
},
|
||||
key: 'upload',
|
||||
serverFeatureProps: props,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ClientFeature: UploadFeatureClient,
|
||||
clientFeatureProps: clientProps,
|
||||
generateSchemaMap: ({ config, i18n, props }) => {
|
||||
if (!props?.collections) return null
|
||||
|
||||
const schemaMap = new Map<string, Field[]>()
|
||||
const validRelationships = config.collections.map((c) => c.slug) || []
|
||||
|
||||
for (const collection in props.collections) {
|
||||
if (props.collections[collection].fields?.length) {
|
||||
schemaMap.set(collection, props.collections[collection].fields)
|
||||
traverseFields({
|
||||
config,
|
||||
fields: props.collections[collection].fields,
|
||||
i18n,
|
||||
schemaMap,
|
||||
schemaPath: collection,
|
||||
validRelationships,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return schemaMap
|
||||
},
|
||||
i18n,
|
||||
nodes: [
|
||||
createNode({
|
||||
converters: {
|
||||
html: {
|
||||
converter: async ({ node, req }) => {
|
||||
// @ts-expect-error
|
||||
const id = node?.value?.id || node?.value // for backwards-compatibility
|
||||
|
||||
if (req?.payload) {
|
||||
const uploadDocument: {
|
||||
value?: TypeWithID & FileData
|
||||
} = {}
|
||||
|
||||
try {
|
||||
await populate({
|
||||
id,
|
||||
collectionSlug: node.relationTo,
|
||||
currentDepth: 0,
|
||||
data: uploadDocument,
|
||||
depth: 1,
|
||||
draft: false,
|
||||
key: 'value',
|
||||
overrideAccess: false,
|
||||
req,
|
||||
showHiddenFields: false,
|
||||
})
|
||||
} catch (ignored) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
'Lexical upload node HTML converter: error fetching upload file',
|
||||
ignored,
|
||||
'Node:',
|
||||
node,
|
||||
)
|
||||
return `<img />`
|
||||
}
|
||||
|
||||
const url = getAbsoluteURL(uploadDocument?.value?.url, req?.payload)
|
||||
|
||||
/**
|
||||
* If the upload is not an image, return a link to the upload
|
||||
*/
|
||||
if (!uploadDocument?.value?.mimeType?.startsWith('image')) {
|
||||
return `<a href="${url}" rel="noopener noreferrer">${uploadDocument.value?.filename}</a>`
|
||||
}
|
||||
|
||||
/**
|
||||
* If the upload is a simple image with no different sizes, return a simple img tag
|
||||
*/
|
||||
if (
|
||||
!uploadDocument?.value?.sizes ||
|
||||
!Object.keys(uploadDocument?.value?.sizes).length
|
||||
) {
|
||||
return `<img src="${url}" alt="${uploadDocument?.value?.filename}" width="${uploadDocument?.value?.width}" height="${uploadDocument?.value?.height}"/>`
|
||||
}
|
||||
|
||||
/**
|
||||
* If the upload is an image with different sizes, return a picture element
|
||||
*/
|
||||
let pictureHTML = '<picture>'
|
||||
|
||||
// Iterate through each size in the data.sizes object
|
||||
for (const size in uploadDocument.value?.sizes) {
|
||||
const imageSize: FileSize & {
|
||||
url?: string
|
||||
} = uploadDocument.value?.sizes[size]
|
||||
|
||||
// Skip if any property of the size object is null
|
||||
if (
|
||||
!imageSize.width ||
|
||||
!imageSize.height ||
|
||||
!imageSize.mimeType ||
|
||||
!imageSize.filesize ||
|
||||
!imageSize.filename ||
|
||||
!imageSize.url
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const imageSizeURL = getAbsoluteURL(imageSize?.url, req?.payload)
|
||||
|
||||
pictureHTML += `<source srcset="${imageSizeURL}" media="(max-width: ${imageSize.width}px)" type="${imageSize.mimeType}">`
|
||||
}
|
||||
|
||||
// Add the default img tag
|
||||
pictureHTML += `<img src="${url}" alt="Image" width="${uploadDocument.value?.width}" height="${uploadDocument.value?.height}">`
|
||||
pictureHTML += '</picture>'
|
||||
return pictureHTML
|
||||
} else {
|
||||
return `<img src="${id}" />`
|
||||
}
|
||||
},
|
||||
nodeTypes: [UploadNode.getType()],
|
||||
},
|
||||
},
|
||||
getSubFields: ({ node, req }) => {
|
||||
const collection = req.payload.collections[node?.relationTo]
|
||||
|
||||
if (collection) {
|
||||
const collectionFieldSchema = props?.collections?.[node?.relationTo]?.fields
|
||||
|
||||
if (Array.isArray(collectionFieldSchema)) {
|
||||
if (!collectionFieldSchema?.length) {
|
||||
return null
|
||||
}
|
||||
return collectionFieldSchema
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
getSubFieldsData: ({ node }) => {
|
||||
return node?.fields
|
||||
},
|
||||
graphQLPopulationPromises: [uploadPopulationPromiseHOC(props)],
|
||||
hooks: {
|
||||
afterRead: [
|
||||
({
|
||||
currentDepth,
|
||||
depth,
|
||||
draft,
|
||||
node,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
showHiddenFields,
|
||||
}) => {
|
||||
if (!node?.value) {
|
||||
return node
|
||||
}
|
||||
const collection = req.payload.collections[node?.relationTo]
|
||||
|
||||
if (!collection) {
|
||||
return node
|
||||
}
|
||||
// @ts-expect-error
|
||||
const id = node?.value?.id || node?.value // for backwards-compatibility
|
||||
|
||||
const populateDepth =
|
||||
props?.maxDepth !== undefined && props?.maxDepth < depth ? props?.maxDepth : depth
|
||||
|
||||
populationPromises.push(
|
||||
populate({
|
||||
id,
|
||||
collectionSlug: collection.config.slug,
|
||||
currentDepth,
|
||||
data: node,
|
||||
depth: populateDepth,
|
||||
draft,
|
||||
key: 'value',
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
}),
|
||||
)
|
||||
|
||||
return node
|
||||
},
|
||||
],
|
||||
},
|
||||
node: UploadNode,
|
||||
validations: [uploadValidation(props)],
|
||||
}),
|
||||
],
|
||||
sanitizedServerFeatureProps: props,
|
||||
}
|
||||
},
|
||||
key: 'upload',
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PopulationPromise } from '../types.js'
|
||||
import type { PopulationPromise } from '../typesServer.js'
|
||||
import type { UploadFeatureProps } from './feature.server.js'
|
||||
import type { SerializedUploadNode } from './nodes/UploadNode.js'
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from 'lexical'
|
||||
import React, { useEffect } from 'react'
|
||||
|
||||
import type { PluginComponentWithAnchor } from '../../types.js'
|
||||
import type { PluginComponentWithAnchor } from '../../typesClient.js'
|
||||
import type { UploadFeaturePropsClient } from '../feature.client.js'
|
||||
import type { UploadData } from '../nodes/UploadNode.js'
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { buildStateFromSchema } from '@payloadcms/ui/forms/buildStateFromSchema'
|
||||
import { isValidID } from 'payload'
|
||||
|
||||
import type { NodeValidation } from '../types.js'
|
||||
import type { NodeValidation } from '../typesServer.js'
|
||||
import type { UploadFeatureProps } from './feature.server.js'
|
||||
import type { SerializedUploadNode } from './nodes/UploadNode.js'
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { EditorConfig as LexicalEditorConfig } from 'lexical'
|
||||
import { ShimmerEffect, useClientFunctions, useFieldProps } from '@payloadcms/ui'
|
||||
import React, { Suspense, lazy, useEffect, useState } from 'react'
|
||||
|
||||
import type { FeatureProviderClient } from '../features/types.js'
|
||||
import type { FeatureProviderClient } from '../features/typesClient.js'
|
||||
import type { SanitizedClientEditorConfig } from '../lexical/config/types.js'
|
||||
import type { GeneratedFeatureProviderComponent, LexicalFieldAdminProps } from '../types.js'
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
withNullableJSONSchemaType,
|
||||
} from 'payload'
|
||||
|
||||
import type { FeatureProviderServer, ResolvedServerFeatureMap } from './features/types.js'
|
||||
import type { FeatureProviderServer, ResolvedServerFeatureMap } from './features/typesServer.js'
|
||||
import type { SanitizedServerEditorConfig } from './lexical/config/types.js'
|
||||
import type {
|
||||
AdapterProps,
|
||||
@@ -897,6 +897,20 @@ export { InlineToolbarFeature } from './features/toolbars/inline/feature.server.
|
||||
|
||||
export type { ToolbarGroup, ToolbarGroupItem } from './features/toolbars/types.js'
|
||||
export { createNode } from './features/typeUtilities.js' // Only useful in feature.server.ts
|
||||
export type {
|
||||
ClientComponentProps,
|
||||
ClientFeature,
|
||||
ClientFeatureProviderMap,
|
||||
FeatureProviderClient,
|
||||
FeatureProviderProviderClient,
|
||||
PluginComponent,
|
||||
PluginComponentWithAnchor,
|
||||
ResolvedClientFeature,
|
||||
ResolvedClientFeatureMap,
|
||||
SanitizedClientFeatures,
|
||||
SanitizedPlugin,
|
||||
} from './features/typesClient.js'
|
||||
|
||||
export type {
|
||||
AfterChangeNodeHook,
|
||||
AfterChangeNodeHookArgs,
|
||||
@@ -907,28 +921,17 @@ export type {
|
||||
BeforeChangeNodeHookArgs,
|
||||
BeforeValidateNodeHook,
|
||||
BeforeValidateNodeHookArgs,
|
||||
ClientComponentProps,
|
||||
ClientFeature,
|
||||
ClientFeatureProviderMap,
|
||||
FeatureProviderClient,
|
||||
FeatureProviderProviderClient,
|
||||
FeatureProviderProviderServer,
|
||||
FeatureProviderServer,
|
||||
NodeValidation,
|
||||
NodeWithHooks,
|
||||
PluginComponent,
|
||||
PluginComponentWithAnchor,
|
||||
PopulationPromise,
|
||||
ResolvedClientFeature,
|
||||
ResolvedClientFeatureMap,
|
||||
ResolvedServerFeature,
|
||||
ResolvedServerFeatureMap,
|
||||
SanitizedClientFeatures,
|
||||
SanitizedPlugin,
|
||||
SanitizedServerFeatures,
|
||||
ServerFeature,
|
||||
ServerFeatureProviderMap,
|
||||
} from './features/types.js'
|
||||
} from './features/typesServer.js'
|
||||
|
||||
export { UploadFeature } from './features/upload/feature.server.js'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { SanitizedPlugin } from '../features/types.js'
|
||||
import type { SanitizedPlugin } from '../features/typesClient.js'
|
||||
|
||||
export const EditorPlugin: React.FC<{
|
||||
anchorElem?: HTMLDivElement
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
ClientFeatureProviderMap,
|
||||
FeatureProviderClient,
|
||||
ResolvedClientFeatureMap,
|
||||
} from '../../../features/types.js'
|
||||
} from '../../../features/typesClient.js'
|
||||
import type { ClientEditorConfig } from '../types.js'
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
import type { EditorConfig as LexicalEditorConfig } from 'lexical'
|
||||
|
||||
import type { ResolvedClientFeatureMap, SanitizedClientFeatures } from '../../../features/types.js'
|
||||
import type {
|
||||
ResolvedClientFeatureMap,
|
||||
SanitizedClientFeatures,
|
||||
} from '../../../features/typesClient.js'
|
||||
import type { LexicalFieldAdminProps } from '../../../types.js'
|
||||
import type { SanitizedClientEditorConfig } from '../types.js'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EditorConfig as LexicalEditorConfig } from 'lexical'
|
||||
|
||||
import type { FeatureProviderServer } from '../../../features/types.js'
|
||||
import type { FeatureProviderServer } from '../../../features/typesServer.js'
|
||||
import type { ServerEditorConfig } from '../types.js'
|
||||
|
||||
import { AlignFeature } from '../../../features/align/feature.server.js'
|
||||
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
FeatureProviderServer,
|
||||
ResolvedServerFeatureMap,
|
||||
ServerFeatureProviderMap,
|
||||
} from '../../../features/types.js'
|
||||
} from '../../../features/typesServer.js'
|
||||
import type { ServerEditorConfig } from '../types.js'
|
||||
|
||||
type DependencyGraph = {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { SanitizedConfig } from 'payload'
|
||||
|
||||
import type { ResolvedServerFeatureMap, SanitizedServerFeatures } from '../../../features/types.js'
|
||||
import type {
|
||||
ResolvedServerFeatureMap,
|
||||
SanitizedServerFeatures,
|
||||
} from '../../../features/typesServer.js'
|
||||
import type { SanitizedServerEditorConfig, ServerEditorConfig } from '../types.js'
|
||||
|
||||
import { loadFeatures } from './loader.js'
|
||||
|
||||
@@ -2,12 +2,14 @@ import type { EditorConfig as LexicalEditorConfig } from 'lexical'
|
||||
|
||||
import type {
|
||||
FeatureProviderClient,
|
||||
FeatureProviderServer,
|
||||
ResolvedClientFeatureMap,
|
||||
ResolvedServerFeatureMap,
|
||||
SanitizedClientFeatures,
|
||||
} from '../../features/typesClient.js'
|
||||
import type {
|
||||
FeatureProviderServer,
|
||||
ResolvedServerFeatureMap,
|
||||
SanitizedServerFeatures,
|
||||
} from '../../features/types.js'
|
||||
} from '../../features/typesServer.js'
|
||||
import type { LexicalFieldAdminProps } from '../../types.js'
|
||||
|
||||
export type ServerEditorConfig = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { SerializedEditorState } from 'lexical'
|
||||
import type { RichTextAdapter } from 'payload'
|
||||
|
||||
import type { PopulationPromise } from '../features/types.js'
|
||||
import type { PopulationPromise } from '../features/typesServer.js'
|
||||
import type { AdapterProps } from '../types.js'
|
||||
|
||||
import { recurseNodes } from '../utilities/forEachNodeRecursively.js'
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Field, PayloadRequestWithData, RequestContext } from 'payload'
|
||||
|
||||
import { afterReadTraverseFields } from 'payload'
|
||||
|
||||
import type { PopulationPromise } from '../features/types.js'
|
||||
import type { PopulationPromise } from '../features/typesServer.js'
|
||||
|
||||
type NestedRichTextFieldsArgs = {
|
||||
context: RequestContext
|
||||
|
||||
@@ -8,7 +8,7 @@ import type {
|
||||
} from 'payload'
|
||||
import type React from 'react'
|
||||
|
||||
import type { FeatureProviderServer } from './features/types.js'
|
||||
import type { FeatureProviderServer } from './features/typesServer.js'
|
||||
import type { SanitizedServerEditorConfig } from './lexical/config/types.js'
|
||||
|
||||
export type LexicalFieldAdminProps = {
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
FeatureProviderClient,
|
||||
FeatureProviderProviderClient,
|
||||
ResolvedClientFeatureMap,
|
||||
} from '../features/types.js'
|
||||
} from '../features/typesClient.js'
|
||||
import type { ClientEditorConfig } from '../lexical/config/types.js'
|
||||
|
||||
import { createClientComponent } from '../features/createClientComponent.js'
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
ResolvedServerFeatureMap,
|
||||
ServerFeature,
|
||||
ServerFeatureProviderMap,
|
||||
} from '../features/types.js'
|
||||
} from '../features/typesServer.js'
|
||||
import type { ServerEditorConfig } from '../lexical/config/types.js'
|
||||
|
||||
export type CreateServerFeatureArgs<UnSanitizedProps, SanitizedProps, ClientProps> = Pick<
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { RichTextAdapter } from 'payload'
|
||||
import { mapFields } from '@payloadcms/ui/utilities/buildComponentMap'
|
||||
import React from 'react'
|
||||
|
||||
import type { ResolvedServerFeatureMap } from '../features/types.js'
|
||||
import type { ResolvedServerFeatureMap } from '../features/typesServer.js'
|
||||
import type { GeneratedFeatureProviderComponent } from '../types.js'
|
||||
|
||||
export const getGenerateComponentMap =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { RichTextAdapter } from 'payload'
|
||||
|
||||
import type { ResolvedServerFeatureMap } from '../features/types.js'
|
||||
import type { ResolvedServerFeatureMap } from '../features/typesServer.js'
|
||||
|
||||
export const getGenerateSchemaMap =
|
||||
(args: { resolvedFeatureMap: ResolvedServerFeatureMap }): RichTextAdapter['generateSchemaMap'] =>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useAddClientFunction, useFieldProps, useTableCell } from '@payloadcms/ui'
|
||||
|
||||
import type { FeatureProviderClient } from '../features/types.js'
|
||||
import type { FeatureProviderClient } from '../features/typesClient.js'
|
||||
|
||||
export const useLexicalFeature = <ClientFeatureProps,>(
|
||||
featureKey: string,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { SerializedEditorState, SerializedLexicalNode } from 'lexical'
|
||||
import type { RichTextField, ValidateOptions } from 'payload'
|
||||
|
||||
import type { NodeValidation } from '../features/types.js'
|
||||
import type { NodeValidation } from '../features/typesServer.js'
|
||||
|
||||
export async function validateNodes({
|
||||
nodeValidations,
|
||||
|
||||
Reference in New Issue
Block a user