diff --git a/packages/sanity/src/core/field/types/portableText/diff/components/Annotation.tsx b/packages/sanity/src/core/field/types/portableText/diff/components/Annotation.tsx index 07fd0469140..f15fe1feae4 100644 --- a/packages/sanity/src/core/field/types/portableText/diff/components/Annotation.tsx +++ b/packages/sanity/src/core/field/types/portableText/diff/components/Annotation.tsx @@ -1,12 +1,11 @@ import {ChevronDownIcon} from '@sanity/icons' import {useClickOutside, Label, Popover, Flex} from '@sanity/ui' import {toString} from '@sanity/util/paths' -import {isKeySegment, ObjectSchemaType, Path} from '@sanity/types' +import {isKeySegment, ObjectSchemaType, Path, PortableTextChild} from '@sanity/types' import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react' import styled from 'styled-components' import {ChangeList, DiffContext, DiffTooltip, useDiffAnnotationColor} from '../../../../diff' import {ObjectDiff} from '../../../../types' -import {PortableTextChild} from '../types' import {isEmptyObject} from '../helpers' import {ConnectorContext, useReportedValues} from '../../../../../changeIndicators' import {InlineBox, InlineText, PopoverContainer, PreviewContainer} from './styledComponents' diff --git a/packages/sanity/src/core/field/types/portableText/diff/components/Block.tsx b/packages/sanity/src/core/field/types/portableText/diff/components/Block.tsx index 76ad5da5f74..655b72e25cc 100644 --- a/packages/sanity/src/core/field/types/portableText/diff/components/Block.tsx +++ b/packages/sanity/src/core/field/types/portableText/diff/components/Block.tsx @@ -1,9 +1,9 @@ import {Box, Card, Stack, Text} from '@sanity/ui' -import {Path} from '@sanity/types' +import {Path, PortableTextTextBlock} from '@sanity/types' import React, {useCallback, useContext} from 'react' import {DiffContext, DiffTooltip, useDiffAnnotationColor} from '../../../../diff' import {isHeader} from '../helpers' -import {PortableTextBlock, PortableTextDiff} from '../types' +import {PortableTextDiff} from '../types' import {ConnectorContext} from '../../../../../changeIndicators' import Blockquote from './Blockquote' import Header from './Header' @@ -13,7 +13,7 @@ const EMPTY_PATH: Path = [] export default function Block(props: { diff: PortableTextDiff - block: PortableTextBlock + block: PortableTextTextBlock children: JSX.Element }): JSX.Element { const {diff, block, children} = props diff --git a/packages/sanity/src/core/field/types/portableText/diff/components/InlineObject.tsx b/packages/sanity/src/core/field/types/portableText/diff/components/InlineObject.tsx index a20d2cf7c60..87c6d277a9e 100644 --- a/packages/sanity/src/core/field/types/portableText/diff/components/InlineObject.tsx +++ b/packages/sanity/src/core/field/types/portableText/diff/components/InlineObject.tsx @@ -1,12 +1,17 @@ import {ChevronDownIcon} from '@sanity/icons' -import {isKeySegment, ObjectSchemaType, Path} from '@sanity/types' +import { + isKeySegment, + ObjectSchemaType, + Path, + PortableTextChild, + PortableTextObject, +} from '@sanity/types' import {Card, Flex, Label, Popover, useClickOutside} from '@sanity/ui' import {FOCUS_TERMINATOR, toString} from '@sanity/util/paths' import React, {useCallback, useContext, useState, useEffect, useMemo} from 'react' import styled from 'styled-components' import {ChangeList, DiffContext, DiffTooltip, useDiffAnnotationColor} from '../../../../diff' import {ObjectDiff} from '../../../../types' -import {PortableTextChild} from '../types' import {isEmptyObject} from '../helpers' import {ConnectorContext, useReportedValues} from '../../../../../changeIndicators' import {Preview} from '../../../../../preview/components/Preview' @@ -14,7 +19,7 @@ import {InlineBox, InlineText, PopoverContainer, PreviewContainer} from './style interface InlineObjectProps { diff?: ObjectDiff - object: PortableTextChild + object: PortableTextObject path: Path schemaType?: ObjectSchemaType } diff --git a/packages/sanity/src/core/field/types/portableText/diff/components/PortableText.tsx b/packages/sanity/src/core/field/types/portableText/diff/components/PortableText.tsx index 9b824e1164c..d4c5db5246b 100644 --- a/packages/sanity/src/core/field/types/portableText/diff/components/PortableText.tsx +++ b/packages/sanity/src/core/field/types/portableText/diff/components/PortableText.tsx @@ -1,9 +1,15 @@ -import {ObjectSchemaType, SchemaType} from '@sanity/types' +import { + isPortableTextSpan, + ObjectSchemaType, + PortableTextChild, + PortableTextTextBlock, + SpanSchemaType, +} from '@sanity/types' import {startCase, uniq, xor} from 'lodash' import React, {ReactElement, useCallback, useMemo} from 'react' import {DiffCard} from '../../../../diff' import {ArrayDiff, ObjectDiff, StringDiff, StringDiffSegment} from '../../../../types' -import {PortableTextBlock, PortableTextChild, PortableTextDiff, SpanTypeSchema} from '../types' +import {PortableTextDiff} from '../types' import * as TextSymbols from '../symbols' @@ -43,7 +49,7 @@ type Props = { export default function PortableText(props: Props): JSX.Element { const {diff, schemaType} = props - const block = (diff.origin.toValue || diff.origin.fromValue) as PortableTextBlock + const block = (diff.origin.toValue || diff.origin.fromValue) as PortableTextTextBlock const inlineObjects = useMemo( () => (diff.origin.toValue ? getInlineObjects(diff.origin) : []), @@ -52,7 +58,7 @@ export default function PortableText(props: Props): JSX.Element { const renderChild = useCallback( (ptDiffChild: PortableTextChild) => { - const spanSchemaType = getChildSchemaType(schemaType.fields, ptDiffChild) as SpanTypeSchema + const spanSchemaType = getChildSchemaType(schemaType.fields, ptDiffChild) as SpanSchemaType let decoratorTypes: {title: string; value: string}[] = [] if (spanSchemaType) { decoratorTypes = getDecorators(spanSchemaType) @@ -243,7 +249,7 @@ function renderTextSegment({ decoratorTypes: {title: string; value: string}[] seg: StringDiffSegment segIndex: number - spanSchemaType: SpanTypeSchema + spanSchemaType: SpanSchemaType }): JSX.Element { // Newlines if (seg.text === '\n') { @@ -257,7 +263,7 @@ function renderTextSegment({ ) const spanDiff = child && findSpanDiffFromChild(diff.origin, child) // Render decorator diff info - const activeMarks = child.marks || [] + const activeMarks = isPortableTextSpan(child) ? child.marks || [] : [] if (spanDiff) { children = renderDecorators({ activeMarks, @@ -303,7 +309,7 @@ function renderDecorators({ seg: StringDiffSegment segIndex: number spanDiff: ObjectDiff - spanSchemaType: SchemaType + spanSchemaType: SpanSchemaType }): JSX.Element { let returned = {children} const fromPtDiffText: string = @@ -375,7 +381,7 @@ function renderDecorators({ return returned } -function isEmptyTextChange(block: PortableTextBlock, diff: PortableTextDiff) { +function isEmptyTextChange(block: PortableTextTextBlock, diff: PortableTextDiff) { return ( block.children.length === 1 && block.children[0]._type === 'span' && diff --git a/packages/sanity/src/core/field/types/portableText/diff/helpers.ts b/packages/sanity/src/core/field/types/portableText/diff/helpers.ts index d8feeff2cc5..512f829b27e 100644 --- a/packages/sanity/src/core/field/types/portableText/diff/helpers.ts +++ b/packages/sanity/src/core/field/types/portableText/diff/helpers.ts @@ -1,5 +1,17 @@ import {flatten, isEqual, orderBy} from 'lodash' -import {ArraySchemaType, Block, ObjectField, ObjectSchemaType, SchemaType} from '@sanity/types' +import { + ArraySchemaType, + isPortableTextSpan, + isPortableTextTextBlock, + ObjectField, + ObjectSchemaType, + PortableTextBlock, + PortableTextChild, + PortableTextObject, + PortableTextTextBlock, + SchemaType, + SpanSchemaType, +} from '@sanity/types' import { diff_match_patch as DiffMatchPatch, DIFF_DELETE, @@ -15,14 +27,7 @@ import { } from '../../../types' import * as TextSymbols from './symbols' -import { - InlineSymbolMap, - MarkSymbolMap, - PortableTextBlock, - PortableTextDiff, - PortableTextChild, - SpanTypeSchema, -} from './types' +import {InlineSymbolMap, MarkSymbolMap, PortableTextDiff} from './types' const dmp = new DiffMatchPatch() @@ -47,7 +52,9 @@ const symbolRegex = new RegExp(`${allSymbols.join('|')}`, 'g') const segmentRegex = new RegExp(`${allSymbols.join('|')}|\n`, 'g') interface BlockSchemaType extends ObjectSchemaType { - diffComponent: DiffComponent> | DiffComponentOptions> + diffComponent: + | DiffComponent> + | DiffComponentOptions> } export function isPTSchemaType(schemaType: SchemaType): schemaType is BlockSchemaType { @@ -55,7 +62,11 @@ export function isPTSchemaType(schemaType: SchemaType): schemaType is BlockSchem } export function isHeader(node: PortableTextBlock): boolean { - return !!node.style && ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(node.style) + return ( + isPortableTextTextBlock(node) && + !!node.style && + ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(node.style) + ) } export function findChildDiff(diff: ObjectDiff, child: PortableTextChild): ObjectDiff { @@ -83,27 +94,27 @@ export function getChildSchemaType( return cSchemaType } -export function getDecorators(spanSchemaType: SpanTypeSchema): {title: string; value: string}[] { +export function getDecorators(spanSchemaType: SpanSchemaType): {title: string; value: string}[] { if (spanSchemaType.decorators) { return orderBy(spanSchemaType.decorators, ['value'], ['asc']) } return [] } -export function getAnnotations(spanSchemaType: SpanTypeSchema): ObjectSchemaType[] { +export function getAnnotations(spanSchemaType: SpanSchemaType): ObjectSchemaType[] { if (spanSchemaType.annotations) { return orderBy(spanSchemaType.annotations, ['name'], ['asc']) } return [] } -export function isDecorator(name: string, schemaType: SpanTypeSchema): boolean { +export function isDecorator(name: string, schemaType: SpanSchemaType): boolean { return getDecorators(schemaType).some((dec) => dec.value === name) } export function blockToSymbolizedText( diff: ObjectDiff, - block: PortableTextBlock | undefined, + block: PortableTextTextBlock | undefined, decoratorMap: MarkSymbolMap, annotationMap: MarkSymbolMap, inlineMap: InlineSymbolMap @@ -113,8 +124,8 @@ export function blockToSymbolizedText( } return block.children .map((child) => { - let returned = child.text?.replace(symbolRegex, '') || '' // Make sure symbols aren't in the text already - if (child._type === 'span') { + let returned = isPortableTextSpan(child) ? child.text?.replace(symbolRegex, '') : '' // Make sure symbols aren't in the text already + if (isPortableTextSpan(child)) { // Attatch stringdiff segments const spanDiff = findSpanDiffFromChild(diff, child) const textDiff = spanDiff?.fields.text @@ -125,8 +136,8 @@ export function blockToSymbolizedText( textDiff.action !== 'unchanged' ) { returned = textDiff.segments - .filter((seg: any) => seg.action !== 'removed') - .map((seg: any) => seg.text.replace(symbolRegex, '')) + .filter((seg) => seg.action !== 'removed') + .map((seg) => seg.text.replace(symbolRegex, '')) .join(TextSymbols.SEGMENT_START_SYMBOL) } if (child.marks) { @@ -153,8 +164,8 @@ export function createPortableTextDiff( ): PortableTextDiff { const displayValue = diff.action === 'removed' - ? (diff.fromValue as PortableTextBlock) - : (diff.toValue as PortableTextBlock) + ? (diff.fromValue as PortableTextTextBlock) + : (diff.toValue as PortableTextTextBlock) const _diff: PortableTextDiff = { ...diff, origin: diff, @@ -165,7 +176,10 @@ export function createPortableTextDiff( const annotationMap: MarkSymbolMap = {} const decoratorMap: MarkSymbolMap = {} const inlineMap: InlineSymbolMap = {} - const spanSchemaType = getChildSchemaType(schemaType.fields, {_key: 'bogus', _type: 'span'}) + const spanSchemaType = getChildSchemaType(schemaType.fields, { + _key: 'bogus', + _type: 'span', + }) as SpanSchemaType if (spanSchemaType) { getDecorators(spanSchemaType).forEach((dec, index) => { decoratorMap[dec.value] = TextSymbols.DECORATOR_SYMBOLS[index] @@ -181,14 +195,14 @@ export function createPortableTextDiff( }) const fromText = blockToSymbolizedText( _diff.origin, - _diff.fromValue as PortableTextBlock, + _diff.fromValue as PortableTextTextBlock, decoratorMap, annotationMap, inlineMap ) const toText = blockToSymbolizedText( _diff.origin, - _diff.toValue as PortableTextBlock, + _diff.toValue as PortableTextTextBlock, decoratorMap, annotationMap, inlineMap @@ -337,7 +351,7 @@ function buildSegments(fromInput: string, toInput: string): StringDiffSegment[] ) } -export function getInlineObjects(diff: ObjectDiff): PortableTextChild[] { +export function getInlineObjects(diff: ObjectDiff): PortableTextObject[] { const allChildren = [ ...(diff.toValue ? diff.toValue.children.filter((cld: any) => cld._type !== 'span') : []), ] @@ -349,7 +363,7 @@ export function getInlineObjects(diff: ObjectDiff): PortableTextChild[] { allChildren.push(oCld) } }) - return orderBy(allChildren, ['_key'], ['asc']) as PortableTextChild[] + return orderBy(allChildren, ['_key'], ['asc']) as PortableTextObject[] } export function findSpanDiffFromChild( diff --git a/packages/sanity/src/core/field/types/portableText/diff/types.ts b/packages/sanity/src/core/field/types/portableText/diff/types.ts index f9d8197d20f..912caf6c1e0 100644 --- a/packages/sanity/src/core/field/types/portableText/diff/types.ts +++ b/packages/sanity/src/core/field/types/portableText/diff/types.ts @@ -1,28 +1,11 @@ -import {ObjectSchemaType, SchemaType} from '@sanity/types' +import {PortableTextTextBlock} from '@sanity/types' import {ObjectDiff} from '../../../types' -export type PortableTextBlock = { - _key: string - _type: string - children: PortableTextChild[] - markDefs?: {_key: string; _type: string}[] - style?: string +export type PortableTextDiff = ObjectDiff & { + displayValue: PortableTextTextBlock + origin: ObjectDiff } -export type PortableTextChild = { - _key: string - _type: string - marks?: string[] - text?: string -} - -export type SpanTypeSchema = SchemaType & { - decorators?: {title: string; value: string}[] - annotations?: ObjectSchemaType[] -} - -export type PortableTextDiff = ObjectDiff & {displayValue: PortableTextBlock; origin: ObjectDiff} - export type MarkSymbolMap = Record export type InlineSymbolMap = Record