Skip to content

Commit

Permalink
refactor(core/fields/diffs): use new types in Portable-text-diffs
Browse files Browse the repository at this point in the history
  • Loading branch information
skogsmaskin committed Dec 20, 2022
1 parent f1152f7 commit b2aa1f2
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 63 deletions.
@@ -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'
Expand Down
@@ -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'
Expand All @@ -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
Expand Down
@@ -1,20 +1,25 @@
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'
import {InlineBox, InlineText, PopoverContainer, PreviewContainer} from './styledComponents'

interface InlineObjectProps {
diff?: ObjectDiff
object: PortableTextChild
object: PortableTextObject
path: Path
schemaType?: ObjectSchemaType
}
Expand Down
@@ -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'

Expand Down Expand Up @@ -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) : []),
Expand All @@ -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)
Expand Down Expand Up @@ -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') {
Expand All @@ -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,
Expand Down Expand Up @@ -303,7 +309,7 @@ function renderDecorators({
seg: StringDiffSegment
segIndex: number
spanDiff: ObjectDiff
spanSchemaType: SchemaType
spanSchemaType: SpanSchemaType
}): JSX.Element {
let returned = <span key={`text-segment-${segIndex}`}>{children}</span>
const fromPtDiffText: string =
Expand Down Expand Up @@ -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' &&
Expand Down
66 changes: 40 additions & 26 deletions 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,
Expand All @@ -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()

Expand All @@ -47,15 +52,21 @@ const symbolRegex = new RegExp(`${allSymbols.join('|')}`, 'g')
const segmentRegex = new RegExp(`${allSymbols.join('|')}|\n`, 'g')

interface BlockSchemaType extends ObjectSchemaType {
diffComponent: DiffComponent<ObjectDiff<Block>> | DiffComponentOptions<ObjectDiff<Block>>
diffComponent:
| DiffComponent<ObjectDiff<PortableTextBlock>>
| DiffComponentOptions<ObjectDiff<PortableTextBlock>>
}

export function isPTSchemaType(schemaType: SchemaType): schemaType is BlockSchemaType {
return schemaType.jsonType === 'object' && schemaType.name === 'block'
}

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 {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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) {
Expand All @@ -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,
Expand All @@ -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]
Expand All @@ -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
Expand Down Expand Up @@ -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') : []),
]
Expand All @@ -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(
Expand Down
25 changes: 4 additions & 21 deletions 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<string, string[]>

export type InlineSymbolMap = Record<string, string>

0 comments on commit b2aa1f2

Please sign in to comment.