diff --git a/packages/sanity/src/core/form/inputs/PortableText/BlockActions.tsx b/packages/sanity/src/core/form/inputs/PortableText/BlockActions.tsx index 6e0ba6fe07f..cd1ef7f0ae7 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/BlockActions.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/BlockActions.tsx @@ -1,10 +1,7 @@ -import { - PortableTextEditor, - PortableTextBlock, - usePortableTextEditor, -} from '@sanity/portable-text-editor' +import {PortableTextEditor, usePortableTextEditor} from '@sanity/portable-text-editor' import React, {useCallback, useMemo} from 'react' import styled from 'styled-components' +import {PortableTextBlock} from '@sanity/types' import {PatchArg} from '../../patch' import {RenderBlockActionsCallback, RenderBlockActionsProps} from './types' import {createInsertCallback, createSetCallback, createUnsetCallback} from './callbacks' @@ -20,21 +17,10 @@ const Root = styled.div` pointer-events: 'all'; ` -// function isClassComponent(component: React.ComponentType) { -// return typeof component === 'function' && !!component.prototype?.isReactComponent -// } - -// function isFunctionComponent(component: React.ComponentType) { -// return typeof component === 'function' && String(component).includes('return React.createElement') -// } - export function BlockActions(props: BlockActionsProps) { const editor = usePortableTextEditor() const {block, onChange, renderBlockActions} = props - const decoratorValues = useMemo( - () => PortableTextEditor.getPortableTextFeatures(editor).decorators.map((d) => d.value), - [editor] - ) + const decoratorValues = useMemo(() => editor.types.decorators.map((d) => d.value), [editor]) const blockActions = useMemo(() => { if (renderBlockActions) { @@ -45,12 +31,6 @@ export function BlockActions(props: BlockActionsProps) { unset: createUnsetCallback({block, onChange}), insert: createInsertCallback({allowedDecorators: decoratorValues, block, onChange}), } - - // // Support returning a class component for renderBlockActions (to keep backward compatability as it was possible before) - // if (isClassComponent(renderBlockActions) || isFunctionComponent(renderBlockActions)) { - // const RenderComponent = renderBlockActions - // return - // } return renderBlockActions(blockActionProps) } return undefined diff --git a/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx b/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx index 05bd2ccff9c..d76aac903ba 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx @@ -3,13 +3,13 @@ import { EditorSelection, OnCopyFn, OnPasteFn, - PortableTextBlock, - PortableTextEditor, usePortableTextEditor, HotkeyOptions, - RenderAttributes, + BlockRenderProps, + BlockChildRenderProps, + BlockAnnotationRenderProps, } from '@sanity/portable-text-editor' -import {ObjectSchemaType, Path} from '@sanity/types' +import {BlockSchemaType, Path, PortableTextBlock, PortableTextTextBlock} from '@sanity/types' import { BoundaryElementProvider, Portal, @@ -53,7 +53,7 @@ interface InputProps extends ArrayOfObjectsInputProps { export type PortableTextEditorElement = HTMLDivElement | HTMLSpanElement | null /** @internal */ -export function Compositor(props: InputProps) { +export function Compositor(props: Omit) { const { changed, focusPath = EMPTY_ARRAY, @@ -65,8 +65,9 @@ export function Compositor(props: InputProps) { onChange, onCopy, onActivate, - onItemOpen, onItemClose, + onItemOpen, + onItemRemove, onPaste, onToggleFullscreen, path, @@ -111,8 +112,8 @@ export function Compositor(props: InputProps) { const editorHotkeys = useHotkeys(hotkeysWithFullscreenToggle) - const ptFeatures = useMemo(() => PortableTextEditor.getPortableTextFeatures(editor), [editor]) - const hasContent = !!value + const _renderBlockActions = !!value && renderBlockActions ? renderBlockActions : undefined + const _renderCustomMarkers = !!value && renderCustomMarkers ? renderCustomMarkers : undefined const initialSelection = useMemo( (): EditorSelection => @@ -127,104 +128,113 @@ export function Compositor(props: InputProps) { ) const renderBlock = useCallback( - ( - block: PortableTextBlock, - blockType: ObjectSchemaType, - attributes: RenderAttributes, - defaultRender: (b: PortableTextBlock) => JSX.Element - ) => { - const isTextBlock = block._type === ptFeatures.types.block.name + (blockProps: BlockRenderProps) => { + const { + value: block, + type: blockType, + renderDefault, + focused: blockFocused, + selected, + path: blockPath, + } = blockProps + const isTextBlock = block._type === editor.types.block.name if (isTextBlock) { return ( - {defaultRender(block)} + {renderDefault(blockProps)} ) } - return ( ) }, [ - hasContent, + _renderBlockActions, + _renderCustomMarkers, + editor.types.block.name, isFullscreen, onChange, onItemOpen, - ptFeatures.types.block.name, + onItemClose, + onItemRemove, readOnly, - renderBlockActions, - renderCustomMarkers, renderPreview, ] ) const renderChild = useCallback( - (child: any, childType: any, attributes: any, defaultRender: any) => { - const isSpan = child._type === ptFeatures.types.span.name + (childProps: BlockChildRenderProps) => { + const { + focused: childFocused, + path: childPath, + renderDefault, + selected, + type: childType, + value: child, + } = childProps + const isSpan = child._type === editor.types.span.name if (isSpan) { - return defaultRender(child) + return renderDefault(childProps) } - return ( ) }, - [ - onItemOpen, - ptFeatures.types.span.name, - readOnly, - renderCustomMarkers, - renderPreview, - scrollElement, - ] + [editor, onItemOpen, readOnly, renderCustomMarkers, renderPreview, scrollElement] ) const renderAnnotation = useCallback( - (annotation: any, annotationType: any, attributes: any, defaultRender: any) => { + (annotationProps: BlockAnnotationRenderProps) => { return ( - {defaultRender()} - + /> ) }, - [onItemOpen, readOnly, renderCustomMarkers, scrollElement] + [onItemOpen, onItemClose, readOnly, renderCustomMarkers, scrollElement] ) const [portalElement, setPortalElement] = useState(null) diff --git a/packages/sanity/src/core/form/inputs/PortableText/Editor.tsx b/packages/sanity/src/core/form/inputs/PortableText/Editor.tsx index a41c6d4cdfd..b7a1f8cddfb 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/Editor.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/Editor.tsx @@ -10,6 +10,8 @@ import { EditorSelection, PortableTextEditor, usePortableTextEditor, + RenderStyleFunction, + RenderListItemFunction, } from '@sanity/portable-text-editor' import {Path} from '@sanity/types' import {BoundaryElementProvider, useBoundaryElement, useGlobalKeyDown, useLayer} from '@sanity/ui' @@ -26,6 +28,8 @@ import { } from './Editor.styles' import {useSpellcheck} from './hooks/useSpellCheck' import {useScrollSelectionIntoView} from './hooks/useScrollSelectionIntoView' +import {Style} from './text/Style' +import {ListItem} from './text/ListItem' interface EditorProps { hotkeys: HotkeyOptions @@ -46,8 +50,34 @@ interface EditorProps { setScrollElement: (scrollElement: HTMLElement | null) => void } -const renderDecorator: RenderDecoratorFunction = (mark, mType, attributes, defaultRender) => { - return {defaultRender()} +const renderDecorator: RenderDecoratorFunction = (props) => { + const {value, renderDefault, type, focused, selected} = props + const CustomComponent = type.components?.item + const rendered = renderDefault(props) + if (CustomComponent) { + // eslint-disable-next-line react/jsx-no-bind + return ( + {rendered}} + > + {rendered} + + ) + } + return {rendered} +} + +const renderStyle: RenderStyleFunction = (props) => { + return