From bbd32ae493fcb1cac5020c5b69258f455e418a36 Mon Sep 17 00:00:00 2001 From: Per-Kristian Nordnes Date: Wed, 7 Dec 2022 09:36:59 +0100 Subject: [PATCH] refactor(core/form): add block and annotation component schema extensions Object types can now be rendered as .block or .annotation in the PT-input through their Studio schema extension --- .../sanity/src/core/form/types/asserters.ts | 8 ++ .../sanity/src/core/form/types/blockProps.ts | 62 +++++++++ .../form/types/definitionExtensions.test.ts | 125 +----------------- .../core/form/types/definitionExtensions.ts | 65 +++++++-- packages/sanity/src/core/form/types/index.ts | 1 + 5 files changed, 125 insertions(+), 136 deletions(-) create mode 100644 packages/sanity/src/core/form/types/blockProps.ts diff --git a/packages/sanity/src/core/form/types/asserters.ts b/packages/sanity/src/core/form/types/asserters.ts index 2e9a8aa7484..6d2d02f3d98 100644 --- a/packages/sanity/src/core/form/types/asserters.ts +++ b/packages/sanity/src/core/form/types/asserters.ts @@ -1,4 +1,5 @@ import { + isArrayOfBlocksSchemaType, isArrayOfObjectsSchemaType, isArrayOfPrimitivesSchemaType, isBooleanSchemaType, @@ -59,6 +60,13 @@ export function isArrayOfObjectsInputProps( return isArrayOfObjectsSchemaType(inputProps.schemaType) } +/** @beta */ +export function isArrayOfBlocksInputProps( + inputProps: InputProps | Omit +): inputProps is ArrayOfObjectsInputProps { + return isArrayOfBlocksSchemaType(inputProps.schemaType) +} + /** @beta */ export function isArrayOfPrimitivesInputProps( inputProps: InputProps | Omit diff --git a/packages/sanity/src/core/form/types/blockProps.ts b/packages/sanity/src/core/form/types/blockProps.ts new file mode 100644 index 00000000000..f26aa00c601 --- /dev/null +++ b/packages/sanity/src/core/form/types/blockProps.ts @@ -0,0 +1,62 @@ +import {Path, PortableTextBlock, PortableTextObject, PortableTextTextBlock} from '@sanity/types' + +/** @alpha */ +export interface BlockDecoratorProps { + children: React.ReactElement + focused: boolean + renderDefault: (props: BlockDecoratorProps) => React.ReactElement + selected: boolean + title: string + value: string +} + +/** @alpha */ +export interface BlockStyleProps { + block: PortableTextTextBlock + children: React.ReactElement + focused: boolean + renderDefault: (props: BlockStyleProps) => React.ReactElement + selected: boolean + title: string + value: string +} + +/** @alpha */ +export interface BlockListItemProps { + block: PortableTextTextBlock + children: React.ReactElement + focused: boolean + level: number + renderDefault: (props: BlockListItemProps) => React.ReactElement + selected: boolean + title: string + value: string +} + +/** @alpha */ +export interface BlockAnnotationProps { + children: React.ReactElement + focused: boolean + onClose: () => void + onOpen: () => void + onRemove: () => void + open: boolean + path: Path + renderDefault: (props: BlockAnnotationProps) => React.ReactElement + selected: boolean + value: PortableTextObject +} + +/** @alpha */ +export interface BlockProps { + children: React.ReactElement + focused: boolean + onClose: () => void + onOpen: () => void + onRemove: () => void + open: boolean + path: Path + renderDefault: (props: BlockProps) => React.ReactElement + selected: boolean + value: PortableTextBlock +} diff --git a/packages/sanity/src/core/form/types/definitionExtensions.test.ts b/packages/sanity/src/core/form/types/definitionExtensions.test.ts index d0c218587cd..4f6e44a1330 100644 --- a/packages/sanity/src/core/form/types/definitionExtensions.test.ts +++ b/packages/sanity/src/core/form/types/definitionExtensions.test.ts @@ -13,6 +13,7 @@ import { } from '@sanity/types' import {defineConfig} from '../../config' import {PreviewProps} from '../../components' +import {CrossDatasetReferenceInputProps, ReferenceInputProps} from '../studio' import { ArrayOfObjectsInputProps, ArrayOfPrimitivesInputProps, @@ -35,7 +36,6 @@ import {ObjectItem, ObjectItemProps, PrimitiveItemProps} from './itemProps' import { ArrayOfObjectsComponents, ArrayOfPrimitivesComponents, - BlockComponents, BooleanComponents, CrossDatasetReferenceComponents, DateComponents, @@ -54,7 +54,6 @@ import { TextComponents, UrlComponents, } from './definitionExtensions' -import {CrossDatasetReferenceInputProps, ReferenceInputProps} from '../studio' describe('definitionExtensions', () => { describe('array-like types', () => { @@ -152,101 +151,6 @@ describe('definitionExtensions', () => { }, }) }) - - it('should extend components for block', () => { - const type = defineType({ - type: 'block', - name: 'test', - of: [{type: 'some-object'}], - components: { - diff: (props) => null, - field: (props) => { - const obj: ArrayFieldProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - input: (props) => { - const obj: ArrayOfObjectsInputProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - item: (props) => { - const obj: ObjectItemProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - preview: (props) => { - const obj: PreviewProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - }, - }) - - // this typing is not ideal, but leaving it as this until we decide to narrow array type - const components: ArrayOfObjectsComponents | undefined = type.components - - // ensure we can assign this to config.schema.types - defineConfig({ - name: 'test', - projectId: 'test', - dataset: 'test', - schema: { - types: [type], - }, - }) - }) - - it('should extend components for block', () => { - const type = defineType({ - type: 'block', - name: 'test', - of: [{type: 'some-object'}], - components: { - diff: (props) => null, - field: (props) => { - const obj: ArrayFieldProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - input: (props) => { - const obj: ArrayOfObjectsInputProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - item: (props) => { - const obj: ObjectItemProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - preview: (props) => { - const obj: PreviewProps = props - //@ts-expect-error ensures props is not any - const notObj: string = props - return null - }, - }, - }) - - const components: BlockComponents | undefined = type.components - - // ensure we can assign this to config.schema.types - defineConfig({ - name: 'test', - projectId: 'test', - dataset: 'test', - schema: { - types: [type], - }, - }) - }) }) it('should extend components for boolean', () => { @@ -691,33 +595,6 @@ describe('definitionExtensions', () => { }) const components: SlugComponents | undefined = type.components }) - - it('should extend components for span', () => { - const type = defineType({ - type: 'span', - name: 'test', - components: { - diff: (props) => null, - field: (props) => { - const obj: ObjectFieldProps = props - return null - }, - input: (props) => { - const obj: ObjectInputProps = props - return null - }, - item: (props) => { - const obj: ObjectItemProps = props - return null - }, - preview: (props) => { - const obj: PreviewProps = props - return null - }, - }, - }) - const components: SpanComponents | undefined = type.components - }) }) it('should allow components for fields without defineField', () => { diff --git a/packages/sanity/src/core/form/types/definitionExtensions.ts b/packages/sanity/src/core/form/types/definitionExtensions.ts index 3b77bc49e20..7ba75a18ad8 100644 --- a/packages/sanity/src/core/form/types/definitionExtensions.ts +++ b/packages/sanity/src/core/form/types/definitionExtensions.ts @@ -26,11 +26,20 @@ import { StringInputProps, } from './inputProps' import {ObjectItem, ObjectItemProps, PrimitiveItemProps} from './itemProps' +import { + BlockAnnotationProps, + BlockDecoratorProps, + BlockListItemProps, + BlockProps, + BlockStyleProps, +} from './blockProps' /** * @beta */ export interface ArrayOfObjectsComponents { + annotation?: ComponentType + block?: ComponentType diff?: ComponentType field?: ComponentType input?: ComponentType @@ -49,17 +58,6 @@ export interface ArrayOfPrimitivesComponents { preview?: ComponentType } -/** - * @beta - */ -export interface BlockComponents { - diff?: ComponentType - field?: ComponentType - input?: ComponentType - item?: ComponentType - preview?: ComponentType -} - /** * @beta */ @@ -152,6 +150,8 @@ export interface NumberComponents { * @beta */ export interface ObjectComponents { + annotation?: ComponentType + block?: ComponentType diff?: ComponentType field?: ComponentType input?: ComponentType @@ -163,6 +163,8 @@ export interface ObjectComponents { * @beta */ export interface ReferenceComponents { + annotation?: ComponentType + block?: ComponentType diff?: ComponentType field?: ComponentType> input?: ComponentType @@ -174,6 +176,8 @@ export interface ReferenceComponents { * @beta */ export interface CrossDatasetReferenceComponents { + annotation?: ComponentType + block?: ComponentType diff?: ComponentType field?: ComponentType> input?: ComponentType @@ -260,7 +264,44 @@ declare module '@sanity/types' { /** * @beta */ - components?: BlockComponents + components?: { + block?: ComponentType + } + } + + export interface BlockDecoratorDefinition { + /** + * @beta + */ + components?: { + item?: ComponentType + } + } + + export interface BlockStyleDefinition { + /** + * @beta + */ + components?: { + item?: ComponentType + } + } + export interface BlockListDefinition { + /** + * @beta + */ + components?: { + item?: ComponentType + } + } + + export interface BlockAnnotationDefinition { + /** + * @beta + */ + components?: { + annotation?: ComponentType + } } export interface BooleanDefinition { diff --git a/packages/sanity/src/core/form/types/index.ts b/packages/sanity/src/core/form/types/index.ts index 1ac7b5d86e0..a258cef8923 100644 --- a/packages/sanity/src/core/form/types/index.ts +++ b/packages/sanity/src/core/form/types/index.ts @@ -1,5 +1,6 @@ export * from './_transitional' export * from './asserters' +export * from './blockProps' export * from './event' export * from './fieldProps' export * from './inputProps'