diff --git a/packages/sanity/src/_singletons/context/PortableTextMemberItemElementRefsContext.ts b/packages/sanity/src/_singletons/context/PortableTextMemberItemElementRefsContext.ts new file mode 100644 index 00000000000..9d009f19014 --- /dev/null +++ b/packages/sanity/src/_singletons/context/PortableTextMemberItemElementRefsContext.ts @@ -0,0 +1,12 @@ +import {BehaviorSubject} from 'rxjs' +import {createContext} from 'sanity/_createContext' + +/** @internal */ +export type PortableTextEditorElement = HTMLDivElement | HTMLSpanElement + +/** + * @internal + */ +export const PortableTextMemberItemElementRefsContext = createContext< + BehaviorSubject> +>('sanity/_singletons/context/portable-text-member-item-element-refs', new BehaviorSubject({})) diff --git a/packages/sanity/src/_singletons/index.ts b/packages/sanity/src/_singletons/index.ts index 6679e2e0282..0c63fb90f18 100644 --- a/packages/sanity/src/_singletons/index.ts +++ b/packages/sanity/src/_singletons/index.ts @@ -37,6 +37,7 @@ export * from './context/PaneContext' export * from './context/PaneLayoutContext' export * from './context/PaneRouterContext' export * from './context/PortableTextMarkersContext' +export * from './context/PortableTextMemberItemElementRefsContext' export * from './context/PortableTextMemberItemsContext' export * from './context/PresenceContext' export * from './context/PresenceTrackerContexts' diff --git a/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx b/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx index ad7d13e4192..f587579ea1b 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/Compositor.tsx @@ -25,12 +25,14 @@ import { import {type RenderBlockActionsCallback} from '../../types/_transitional' import {UploadTargetCard} from '../arrays/common/UploadTargetCard' import {ExpandedLayer, Root} from './Compositor.styles' +import {useSetPortableTextMemberItemElementRef} from './contexts/PortableTextMemberItemElementRefsProvider' import {Editor} from './Editor' import {useHotkeys} from './hooks/useHotKeys' import {useTrackFocusPath} from './hooks/useTrackFocusPath' import {Annotation} from './object/Annotation' import {BlockObject} from './object/BlockObject' import {InlineObject} from './object/InlineObject' +import {AnnotationObjectEditModal} from './object/modals/AnnotationObjectEditModal' import {TextBlock} from './text' interface InputProps extends ArrayOfObjectsInputProps { @@ -51,9 +53,6 @@ interface InputProps extends ArrayOfObjectsInputProps { renderEditable?: PortableTextInputProps['renderEditable'] } -/** @internal */ -export type PortableTextEditorElement = HTMLDivElement | HTMLSpanElement - /** @internal */ export function Compositor(props: Omit): ReactNode { const { @@ -94,6 +93,7 @@ export function Compositor(props: Omit(null) @@ -155,6 +155,7 @@ export function Compositor(props: Omit {children} @@ -180,6 +181,7 @@ export function Compositor(props: Omit ) @@ -239,6 +242,7 @@ export function Compositor(props: Omit ) @@ -312,6 +317,7 @@ export function Compositor(props: Omit {children} @@ -369,6 +376,7 @@ export function Compositor(props: Omit {isFullscreen ? {editorNode} : editorNode} +
diff --git a/packages/sanity/src/core/form/inputs/PortableText/PortableTextInput.tsx b/packages/sanity/src/core/form/inputs/PortableText/PortableTextInput.tsx index 961ebafe0b5..2c56a8ee883 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/PortableTextInput.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/PortableTextInput.tsx @@ -16,7 +16,6 @@ import {Box, Flex, Text, useToast} from '@sanity/ui' import {randomKey} from '@sanity/util/content' import {sortBy} from 'lodash' import { - type MutableRefObject, type ReactNode, startTransition, useCallback, @@ -39,7 +38,7 @@ import {immutableReconcile} from '../../store/utils/immutableReconcile' import {type ResolvedUploader} from '../../studio/uploads/types' import {type PortableTextInputProps} from '../../types' import {extractPastedFiles} from '../common/fileTarget/utils/extractFiles' -import {Compositor, type PortableTextEditorElement} from './Compositor' +import {Compositor} from './Compositor' import {PortableTextMarkersProvider} from './contexts/PortableTextMarkers' import {PortableTextMemberItemsProvider} from './contexts/PortableTextMembers' import {usePortableTextMemberItemsFromProps} from './hooks/usePortableTextMembers' @@ -66,7 +65,6 @@ export interface PortableTextMemberItem { key: string member: ArrayOfObjectsItemMember node: ObjectFormNode - elementRef?: MutableRefObject input?: ReactNode } /** @public */ diff --git a/packages/sanity/src/core/form/inputs/PortableText/contexts/PortableTextMemberItemElementRefsProvider.tsx b/packages/sanity/src/core/form/inputs/PortableText/contexts/PortableTextMemberItemElementRefsProvider.tsx new file mode 100644 index 00000000000..9485bf727ec --- /dev/null +++ b/packages/sanity/src/core/form/inputs/PortableText/contexts/PortableTextMemberItemElementRefsProvider.tsx @@ -0,0 +1,38 @@ +import {useCallback, useContext} from 'react' +import {useObservable} from 'react-rx' +import {type PortableTextMemberItem} from 'sanity' +import { + type PortableTextEditorElement, + PortableTextMemberItemElementRefsContext, +} from 'sanity/_singletons' + +export type SetPortableTextMemberItemElementRef = ({ + key, + elementRef, +}: { + key: PortableTextMemberItem['member']['key'] + elementRef: PortableTextEditorElement | null +}) => void + +export function usePortableTextMemberItemElementRefs(): Record< + PortableTextMemberItem['member']['key'], + PortableTextEditorElement | null | undefined +> { + const behaviorSubject = useContext(PortableTextMemberItemElementRefsContext) + + return useObservable(behaviorSubject, {}) +} + +export function useSetPortableTextMemberItemElementRef(): SetPortableTextMemberItemElementRef { + const behaviorSubject = useContext(PortableTextMemberItemElementRefsContext) + + return useCallback( + ({key, elementRef}) => { + behaviorSubject.next({ + ...behaviorSubject.value, + [key]: elementRef, + }) + }, + [behaviorSubject], + ) +} diff --git a/packages/sanity/src/core/form/inputs/PortableText/hooks/usePortableTextMembers.tsx b/packages/sanity/src/core/form/inputs/PortableText/hooks/usePortableTextMembers.tsx index d4e5ad07c02..919caf236f1 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/hooks/usePortableTextMembers.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/hooks/usePortableTextMembers.tsx @@ -1,5 +1,5 @@ import {isEqual, pathFor} from '@sanity/util/paths' -import {createRef, type MutableRefObject, type ReactNode, useContext, useMemo, useRef} from 'react' +import {type MutableRefObject, type ReactNode, useContext, useMemo, useRef} from 'react' import {type FormPatch, type Path, set} from 'sanity' import {PortableTextMemberItemsContext} from 'sanity/_singletons' @@ -10,7 +10,6 @@ import {isMemberArrayOfObjects} from '../../../members/object/fields/asserters' import {type ArrayOfObjectsItemMember, type ObjectFormNode} from '../../../store' import {type ObjectInputProps, type PortableTextInputProps} from '../../../types' import {isArrayOfObjectsFieldMember, isBlockType} from '../_helpers' -import {type PortableTextEditorElement} from '../Compositor' import {type PortableTextMemberItem} from '../PortableTextInput' export function usePortableTextMemberItem(key: string): PortableTextMemberItem | undefined { @@ -201,7 +200,6 @@ export function usePortableTextMemberItemsFromProps( key, member: item.member, node: item.node, - elementRef: createRef(), input, } }) diff --git a/packages/sanity/src/core/form/inputs/PortableText/hooks/useTrackFocusPath.tsx b/packages/sanity/src/core/form/inputs/PortableText/hooks/useTrackFocusPath.tsx index 9ee5ae33a44..f4dfd914e44 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/hooks/useTrackFocusPath.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/hooks/useTrackFocusPath.tsx @@ -8,6 +8,7 @@ import {isEqual} from '@sanity/util/paths' import {useLayoutEffect} from 'react' import scrollIntoView from 'scroll-into-view-if-needed' +import {usePortableTextMemberItemElementRefs} from '../contexts/PortableTextMemberItemElementRefsProvider' import {usePortableTextMemberItems} from './usePortableTextMembers' interface Props { @@ -21,6 +22,7 @@ export function useTrackFocusPath(props: Props): void { const {focusPath, boundaryElement, onItemClose} = props const portableTextMemberItems = usePortableTextMemberItems() + const elementRefs = usePortableTextMemberItemElementRefs() const editor = usePortableTextEditor() const selection = usePortableTextEditorSelection() @@ -46,8 +48,9 @@ export function useTrackFocusPath(props: Props): void { // The related editor member to scroll to, or focus, according to the given focusPath const relatedEditorItem = focusedItem || openItem + const elementRef = relatedEditorItem ? elementRefs[relatedEditorItem.member.key] : undefined - if (relatedEditorItem && relatedEditorItem.elementRef?.current) { + if (relatedEditorItem && elementRef) { if (boundaryElement) { // Scroll the boundary element into view (the scrollable element itself) scrollIntoView(boundaryElement, { @@ -56,7 +59,7 @@ export function useTrackFocusPath(props: Props): void { inline: 'start', }) // Scroll the member into view (the member within the scroll-boundary) - scrollIntoView(relatedEditorItem.elementRef.current, { + scrollIntoView(elementRef, { scrollMode: 'if-needed', boundary: boundaryElement, block: 'nearest', @@ -126,6 +129,7 @@ export function useTrackFocusPath(props: Props): void { }, [ boundaryElement, editor, + elementRefs, focusPath, onItemClose, portableTextMemberItems, diff --git a/packages/sanity/src/core/form/inputs/PortableText/object/Annotation.tsx b/packages/sanity/src/core/form/inputs/PortableText/object/Annotation.tsx index aa81211c797..c37a92b7bbd 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/object/Annotation.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/object/Annotation.tsx @@ -28,13 +28,13 @@ import { } from '../../../types' import {useFormBuilder} from '../../../useFormBuilder' import {DefaultMarkers} from '../_legacyDefaultParts/Markers' +import {type SetPortableTextMemberItemElementRef} from '../contexts/PortableTextMemberItemElementRefsProvider' import {debugRender} from '../debugRender' import {useMemberValidation} from '../hooks/useMemberValidation' import {usePortableTextMarkers} from '../hooks/usePortableTextMarkers' import {usePortableTextMemberItem} from '../hooks/usePortableTextMembers' import {Root, TooltipBox} from './Annotation.styles' import {AnnotationToolbarPopover} from './AnnotationToolbarPopover' -import {ObjectEditModal} from './modals/ObjectEditModal' interface AnnotationProps { children: ReactElement @@ -56,6 +56,7 @@ interface AnnotationProps { renderItem: RenderArrayOfObjectsItemCallback renderPreview: RenderPreviewCallback selected: boolean + setElementRef: SetPortableTextMemberItemElementRef schemaType: ObjectSchemaType value: PortableTextObject } @@ -82,6 +83,7 @@ export function Annotation(props: AnnotationProps): ReactNode { renderPreview, schemaType, selected, + setElementRef, value, } = props const {Markers = DefaultMarkers} = useFormBuilder().__internal.components @@ -224,12 +226,12 @@ export function Annotation(props: AnnotationProps): ReactNode { const setRef = useCallback( (elm: HTMLSpanElement) => { - if (memberItem?.elementRef) { - memberItem.elementRef.current = elm + if (memberItem) { + setElementRef({key: memberItem.member.key, elementRef: elm}) } setSpanElement(elm) // update state here so the reference element is available on first render }, - [memberItem], + [memberItem, setElementRef, setSpanElement], ) return useMemo( @@ -252,9 +254,7 @@ export const DefaultAnnotationComponent = (props: BlockAnnotationProps) => { __unstable_referenceBoundary: referenceBoundary, __unstable_referenceElement: referenceElement, children, - focused, markers, - onClose, onOpen, onRemove, open, @@ -313,19 +313,6 @@ export const DefaultAnnotationComponent = (props: BlockAnnotationProps) => { } /> )} - {open && ( - - {children} - - )} ) } diff --git a/packages/sanity/src/core/form/inputs/PortableText/object/BlockObject.tsx b/packages/sanity/src/core/form/inputs/PortableText/object/BlockObject.tsx index 337268f2efa..1e2822854ac 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/object/BlockObject.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/object/BlockObject.tsx @@ -6,7 +6,6 @@ import {isEqual} from '@sanity/util/paths' import { type MouseEvent, type PropsWithChildren, - type RefObject, useCallback, useEffect, useMemo, @@ -34,6 +33,7 @@ import {type RenderBlockActionsCallback} from '../../../types/_transitional' import {useFormBuilder} from '../../../useFormBuilder' import {ReviewChangesHighlightBlock, StyledChangeIndicatorWithProvidedFullPath} from '../_common' import {BlockActions} from '../BlockActions' +import {type SetPortableTextMemberItemElementRef} from '../contexts/PortableTextMemberItemElementRefsProvider' import {debugRender} from '../debugRender' import {useMemberValidation} from '../hooks/useMemberValidation' import {usePortableTextMarkers} from '../hooks/usePortableTextMarkers' @@ -73,6 +73,7 @@ interface BlockObjectProps extends PropsWithChildren { renderPreview: RenderPreviewCallback schemaType: ObjectSchemaType selected: boolean + setElementRef: SetPortableTextMemberItemElementRef value: PortableTextBlock } @@ -99,6 +100,7 @@ export function BlockObject(props: BlockObjectProps) { renderPreview, schemaType, selected, + setElementRef, value, } = props const {onChange} = useFormCallbacks() @@ -106,6 +108,7 @@ export function BlockObject(props: BlockObjectProps) { const [reviewChangesHovered, setReviewChangesHovered] = useState(false) const markers = usePortableTextMarkers(path) const editor = usePortableTextEditor() + const [divElement, setDivElement] = useState(null) const memberItem = usePortableTextMemberItem(pathToString(path)) const isDeleting = useRef(false) @@ -209,13 +212,13 @@ export function BlockObject(props: BlockObjectProps) { const isOpen = Boolean(memberItem?.member.open) const input = memberItem?.input const nodePath = memberItem?.node.path || EMPTY_ARRAY - const referenceElement = memberItem?.elementRef?.current + const referenceElement = divElement const componentProps: BlockProps = useMemo( () => ({ __unstable_floatingBoundary: floatingBoundary, __unstable_referenceBoundary: referenceBoundary, - __unstable_referenceElement: (referenceElement || null) as HTMLElement | null, + __unstable_referenceElement: referenceElement, children: input, focused, markers, @@ -274,12 +277,19 @@ export function BlockObject(props: BlockObjectProps) { const blockActionsEnabled = renderBlockActions && value && !readOnly const changeIndicatorVisible = isFullscreen && memberItem + const setRef = useCallback( + (elm: HTMLDivElement) => { + if (memberItem) { + setElementRef({key: memberItem.member.key, elementRef: elm}) + } + setDivElement(elm) // update state here so the reference element is available on first render + }, + [memberItem, setElementRef, setDivElement], + ) + return useMemo( () => ( - | undefined} - contentEditable={false} - > + @@ -341,6 +351,7 @@ export function BlockObject(props: BlockObjectProps) { renderBlock, renderBlockActions, reviewChangesHovered, + setRef, toolTipContent, tooltipEnabled, value, diff --git a/packages/sanity/src/core/form/inputs/PortableText/object/InlineObject.tsx b/packages/sanity/src/core/form/inputs/PortableText/object/InlineObject.tsx index 4bea1a104c7..d9c194fe814 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/object/InlineObject.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/object/InlineObject.tsx @@ -24,6 +24,7 @@ import { type RenderPreviewCallback, } from '../../../types' import {useFormBuilder} from '../../../useFormBuilder' +import {type SetPortableTextMemberItemElementRef} from '../contexts/PortableTextMemberItemElementRefsProvider' import {useMemberValidation} from '../hooks/useMemberValidation' import {usePortableTextMarkers} from '../hooks/usePortableTextMarkers' import {usePortableTextMemberItem} from '../hooks/usePortableTextMembers' @@ -51,6 +52,7 @@ interface InlineObjectProps { renderPreview: RenderPreviewCallback schemaType: ObjectSchemaType selected: boolean + setElementRef: SetPortableTextMemberItemElementRef value: PortableTextChild } @@ -75,11 +77,13 @@ export const InlineObject = (props: InlineObjectProps) => { renderPreview, schemaType, selected, + setElementRef, value, } = props const {Markers} = useFormBuilder().__internal.components const editor = usePortableTextEditor() const markers = usePortableTextMarkers(path) + const [divElement, setDivElement] = useState(null) const memberItem = usePortableTextMemberItem(pathToString(path)) const {validation, hasError, hasInfo, hasWarning} = useMemberValidation(memberItem?.node) const parentSchemaType = editor.schemaTypes.block @@ -114,7 +118,7 @@ export const InlineObject = (props: InlineObjectProps) => { const isOpen = Boolean(memberItem?.member.open) const input = memberItem?.input const nodePath = memberItem?.node.path || EMPTY_ARRAY - const referenceElement = memberItem?.elementRef?.current + const referenceElement = divElement const presence = useChildPresence(path, true) const rootPresence = useMemo( @@ -126,7 +130,7 @@ export const InlineObject = (props: InlineObjectProps) => { () => ({ __unstable_floatingBoundary: floatingBoundary, __unstable_referenceBoundary: referenceBoundary, - __unstable_referenceElement: referenceElement as HTMLElement | null, + __unstable_referenceElement: referenceElement, children: input, focused, onClose, @@ -201,9 +205,19 @@ export const InlineObject = (props: InlineObjectProps) => { [Markers, markers, renderCustomMarkers, tooltipEnabled, validation], ) + const setRef = useCallback( + (elm: HTMLDivElement) => { + if (memberItem) { + setElementRef({key: memberItem.member.key, elementRef: elm}) + } + setDivElement(elm) // update state here so the reference element is available on first render + }, + [memberItem, setElementRef, setDivElement], + ) + return useMemo( () => ( - + { ), - [ - componentProps, - memberItem?.elementRef, - renderInlineBlock, - toolTipContent, - tooltipEnabled, - isOpen, - ], + [componentProps, renderInlineBlock, setRef, toolTipContent, tooltipEnabled, isOpen], ) } diff --git a/packages/sanity/src/core/form/inputs/PortableText/object/modals/AnnotationObjectEditModal.tsx b/packages/sanity/src/core/form/inputs/PortableText/object/modals/AnnotationObjectEditModal.tsx new file mode 100644 index 00000000000..7c8ad68f300 --- /dev/null +++ b/packages/sanity/src/core/form/inputs/PortableText/object/modals/AnnotationObjectEditModal.tsx @@ -0,0 +1,60 @@ +import {PortableTextEditor, usePortableTextEditor} from '@portabletext/editor' +import {useBoundaryElement} from '@sanity/ui' +import {useCallback, useMemo} from 'react' + +import {isEmptyItem} from '../../../../store/utils/isEmptyItem' +import {usePortableTextMemberItemElementRefs} from '../../contexts/PortableTextMemberItemElementRefsProvider' +import {usePortableTextMemberItems} from '../../hooks/usePortableTextMembers' +import {ObjectEditModal} from './ObjectEditModal' + +export function AnnotationObjectEditModal(props: { + focused: boolean | undefined + onItemClose: () => void + referenceBoundary: HTMLElement | null +}) { + const editor = usePortableTextEditor() + const boundaryElement = useBoundaryElement().element + const portableTextMemberItems = usePortableTextMemberItems() + const elementRefs = usePortableTextMemberItemElementRefs() + const openAnnotation = useMemo(() => { + return portableTextMemberItems.find((m) => m.kind === 'annotation' && m.member.open) + }, [portableTextMemberItems]) + + const onClose = useCallback(() => { + if (!openAnnotation) { + return + } + + props.onItemClose() + + if (openAnnotation.node.value && isEmptyItem(openAnnotation.node.value) && openAnnotation) { + PortableTextEditor.removeAnnotation(editor, openAnnotation.node.schemaType) + } + + PortableTextEditor.focus(editor) + }, [editor, props, openAnnotation]) + + if (!openAnnotation) { + return null + } + + const elementRef = elementRefs[openAnnotation.member.key] + + if (!elementRef) { + return null + } + + return ( + + {openAnnotation.input} + + ) +} diff --git a/packages/sanity/src/core/form/inputs/PortableText/object/modals/PopoverModal.tsx b/packages/sanity/src/core/form/inputs/PortableText/object/modals/PopoverModal.tsx index 022acb735d5..a2cf1285a48 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/object/modals/PopoverModal.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/object/modals/PopoverModal.tsx @@ -3,11 +3,11 @@ import {CloseIcon} from '@sanity/icons' import {Box, Flex, Text, useClickOutsideEvent, useGlobalKeyDown} from '@sanity/ui' import {type ReactNode, useCallback, useEffect, useRef, useState} from 'react' +import {type PortableTextEditorElement} from 'sanity/_singletons' import {Button, type PopoverProps} from '../../../../../../ui-components' import {PresenceOverlay} from '../../../../../presence' import {VirtualizerScrollInstanceProvider} from '../../../arrays/ArrayOfObjectsInput/List/VirtualizerScrollInstanceProvider' -import {type PortableTextEditorElement} from '../../Compositor' import {ContentHeaderBox, ContentScrollerBox, RootPopover} from './PopoverModal.styles' import {type ModalWidth} from './types' diff --git a/packages/sanity/src/core/form/inputs/PortableText/text/TextBlock.tsx b/packages/sanity/src/core/form/inputs/PortableText/text/TextBlock.tsx index f01f7d14a2a..19499277caf 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/text/TextBlock.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/text/TextBlock.tsx @@ -2,7 +2,7 @@ import {type EditorSelection, PortableTextEditor, usePortableTextEditor} from '@ import {type ObjectSchemaType, type Path, type PortableTextTextBlock} from '@sanity/types' import {Box, Flex, type ResponsivePaddingProps, Text} from '@sanity/ui' import {isEqual} from '@sanity/util/paths' -import {type ReactNode, type RefObject, useCallback, useMemo, useState} from 'react' +import {type ReactNode, useCallback, useMemo, useState} from 'react' import {Tooltip} from '../../../../../ui-components' import {pathToString} from '../../../../field' @@ -23,6 +23,7 @@ import {type RenderBlockActionsCallback} from '../../../types/_transitional' import {useFormBuilder} from '../../../useFormBuilder' import {ReviewChangesHighlightBlock, StyledChangeIndicatorWithProvidedFullPath} from '../_common' import {BlockActions} from '../BlockActions' +import {type SetPortableTextMemberItemElementRef} from '../contexts/PortableTextMemberItemElementRefsProvider' import {debugRender} from '../debugRender' import {useMemberValidation} from '../hooks/useMemberValidation' import {usePortableTextMarkers} from '../hooks/usePortableTextMarkers' @@ -63,6 +64,7 @@ export interface TextBlockProps { renderPreview: RenderPreviewCallback schemaType: ObjectSchemaType selected: boolean + setElementRef: SetPortableTextMemberItemElementRef spellCheck?: boolean value: PortableTextTextBlock } @@ -90,12 +92,14 @@ export function TextBlock(props: TextBlockProps) { renderPreview, schemaType, selected, + setElementRef, spellCheck, value, } = props const {Markers} = useFormBuilder().__internal.components const [reviewChangesHovered, setReviewChangesHovered] = useState(false) const markers = usePortableTextMarkers(path) + const [divElement, setDivElement] = useState(null) const memberItem = usePortableTextMemberItem(pathToString(path)) const editor = usePortableTextEditor() const {onChange} = useFormCallbacks() @@ -182,12 +186,13 @@ export function TextBlock(props: TextBlockProps) { const isOpen = Boolean(memberItem?.member.open) const parentSchemaType = editor.schemaTypes.portableText + const referenceElement = divElement const componentProps: BlockProps = useMemo( () => ({ __unstable_floatingBoundary: floatingBoundary, __unstable_referenceBoundary: referenceBoundary, - __unstable_referenceElement: (memberItem?.elementRef?.current || null) as HTMLElement | null, + __unstable_referenceElement: referenceElement, children: text, focused, markers, @@ -218,7 +223,6 @@ export function TextBlock(props: TextBlockProps) { focused, isOpen, markers, - memberItem?.elementRef, memberItem?.node.path, onItemClose, onOpen, @@ -227,6 +231,7 @@ export function TextBlock(props: TextBlockProps) { parentSchemaType, readOnly, referenceBoundary, + referenceElement, renderAnnotation, renderBlock, renderField, @@ -261,14 +266,19 @@ export function TextBlock(props: TextBlockProps) { const blockActionsEnabled = renderBlockActions && !readOnly const changeIndicatorVisible = isFullscreen && memberItem + const setRef = useCallback( + (elm: HTMLDivElement) => { + if (memberItem) { + setElementRef({key: memberItem.member.key, elementRef: elm}) + } + setDivElement(elm) // update state here so the reference element is available on first render + }, + [memberItem, setElementRef, setDivElement], + ) + return useMemo( () => ( - } - style={debugRender()} - > + @@ -345,6 +355,7 @@ export function TextBlock(props: TextBlockProps) { renderBlock, renderBlockActions, reviewChangesHovered, + setRef, spellCheck, toolTipContent, tooltipEnabled, diff --git a/packages/sanity/src/core/form/inputs/index.ts b/packages/sanity/src/core/form/inputs/index.ts index b7eccb584c7..bec8f04f782 100644 --- a/packages/sanity/src/core/form/inputs/index.ts +++ b/packages/sanity/src/core/form/inputs/index.ts @@ -14,7 +14,6 @@ export * from './EmailInput' export * from './files/types' export * from './NumberInput' export * from './ObjectInput' -export type {PortableTextEditorElement} from './PortableText/Compositor' export * from './PortableText/PortableTextInput' export {PortableTextInput as BlockEditor} from './PortableText/PortableTextInput' export * from './SelectInput'