diff --git a/packages/sanity/src/core/components/previews/__workshop__/GeneralPreviewStory.tsx b/packages/sanity/src/core/components/previews/__workshop__/GeneralPreviewStory.tsx index 577402056f9..a5f9cdd1162 100644 --- a/packages/sanity/src/core/components/previews/__workshop__/GeneralPreviewStory.tsx +++ b/packages/sanity/src/core/components/previews/__workshop__/GeneralPreviewStory.tsx @@ -102,8 +102,8 @@ export default function GeneralPreviewStory() { style={{lineHeight: 0}} > {createElement( - component as React.ComponentType, - previewProps as PreviewProps + component as React.ComponentType>, + previewProps )} diff --git a/packages/sanity/src/core/components/previews/__workshop__/PortableTextPreviewStory.tsx b/packages/sanity/src/core/components/previews/__workshop__/PortableTextPreviewStory.tsx index 72cb57d7e65..d2ac62b4a35 100644 --- a/packages/sanity/src/core/components/previews/__workshop__/PortableTextPreviewStory.tsx +++ b/packages/sanity/src/core/components/previews/__workshop__/PortableTextPreviewStory.tsx @@ -26,7 +26,9 @@ const LAYOUT_OPTIONS: Record = { // } const previewComponents: { - [TLayoutKey in PortableTextPreviewLayoutKey]: React.ComponentType> + [TLayoutKey in PortableTextPreviewLayoutKey]: React.ComponentType< + Omit, 'renderDefault'> + > } = { block: BlockPreview, blockImage: BlockImagePreview, @@ -100,7 +102,10 @@ export default function PortableTextPreviewStory() { - {createElement(component as ComponentType, previewProps as PreviewProps)} + {createElement( + component as ComponentType>, + previewProps + )} diff --git a/packages/sanity/src/core/components/previews/portableText/BlockImagePreview.tsx b/packages/sanity/src/core/components/previews/portableText/BlockImagePreview.tsx index f64dc9997a4..7ec7f486234 100644 --- a/packages/sanity/src/core/components/previews/portableText/BlockImagePreview.tsx +++ b/packages/sanity/src/core/components/previews/portableText/BlockImagePreview.tsx @@ -8,7 +8,7 @@ import {renderPreviewNode} from '../helpers' import {HeaderFlex, MediaCard, RootBox} from './BlockImagePreview.styled' /** @beta */ -export type BlockImagePreviewProps = PreviewProps<'blockImage'> +export type BlockImagePreviewProps = Omit, 'renderDefault'> const DEFAULT_MEDIA_DIMENSIONS: PreviewMediaDimensions = { ...PREVIEW_MEDIA_SIZE.blockImage, diff --git a/packages/sanity/src/core/components/previews/portableText/BlockPreview.tsx b/packages/sanity/src/core/components/previews/portableText/BlockPreview.tsx index 9664e1671b6..283d567057d 100644 --- a/packages/sanity/src/core/components/previews/portableText/BlockPreview.tsx +++ b/packages/sanity/src/core/components/previews/portableText/BlockPreview.tsx @@ -19,7 +19,7 @@ const HeaderFlex = styled(Flex).attrs({align: 'center'})` ` /** @beta */ -export function BlockPreview(props: PreviewProps<'block'>) { +export function BlockPreview(props: Omit, 'renderDefault'>) { const { actions, title, diff --git a/packages/sanity/src/core/config/components/index.ts b/packages/sanity/src/core/config/components/index.ts index 097f0632611..23da548b6da 100644 --- a/packages/sanity/src/core/config/components/index.ts +++ b/packages/sanity/src/core/config/components/index.ts @@ -1,2 +1 @@ -export * from './types' export * from './useMiddlewareComponents' diff --git a/packages/sanity/src/core/config/components/types.ts b/packages/sanity/src/core/config/components/types.ts deleted file mode 100644 index 0e2680fc8d4..00000000000 --- a/packages/sanity/src/core/config/components/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** @beta */ -export interface MiddlewareProps { - renderDefault: (props: T) => React.ReactElement -} diff --git a/packages/sanity/src/core/config/components/useMiddlewareComponents.ts b/packages/sanity/src/core/config/components/useMiddlewareComponents.ts index 26d33e2fed3..969f8af401f 100644 --- a/packages/sanity/src/core/config/components/useMiddlewareComponents.ts +++ b/packages/sanity/src/core/config/components/useMiddlewareComponents.ts @@ -1,31 +1,39 @@ -import {ComponentType, createElement, useMemo} from 'react' +/* eslint-disable @typescript-eslint/ban-types */ + +import {ComponentType, createElement, Fragment, useMemo} from 'react' import {useSource} from '../../studio' import {PluginOptions} from '../types' -interface MiddlewareProps { - renderDefault: (props: T) => React.ReactElement -} +const emptyRender = () => createElement(Fragment) -function _createMiddlewareComponent React.ReactElement}>( +function _createMiddlewareComponent( + defaultComponent: ComponentType, middlewareComponents: ComponentType[] ): ComponentType { - return (_props: T) => { - const _defaultItem = (props: T) => createElement(middlewareComponents[0], props) - - let next = _defaultItem - - for (const middleware of middlewareComponents.slice(1)) { - const defaultRender = next - - next = (props) => { - return createElement(middleware, { - ...props, - renderDefault: defaultRender, - }) - } + return (outerProps: T) => { + // This is the inner "layer" of the middleware chain + // Here we render the _default_ component (typically Sanity's component) + let next = (props: T) => createElement(defaultComponent, props) + + // Since the middleware array is actually a middleware _stack_ data structure, we are + // essentially looping backwards here. This makes it possible to define the _next_ layer for + // each layer. + for (const middleware of middlewareComponents) { + // As we progress through the chain, the meaning of "renderDefault" changes. + // At a given layer in the chain, the _next_ layer is the "default". + const renderDefault = next + + // Here we replace `next` so that the _previous_ layer may use this as its _next_. + next = (props) => createElement(middleware, {...props, renderDefault}) } - return next(_props) + return next({ + ...outerProps, + // NOTE: it's safe to pass the empty render function, since it'll be overwritten in the next step (above). + // NOTE: it's important that the default component does not use `renderDefault`, since it will + // get the `emptyRender` callback will be passed when the middleware stack is empty. + renderDefault: emptyRender, + }) } } @@ -59,18 +67,19 @@ function _pickFromPluginOptions( } /** @internal */ -export function useMiddlewareComponents>(props: { - pick: (plugin: PluginOptions) => ComponentType | undefined +export function useMiddlewareComponents(props: { + pick: (plugin: PluginOptions) => ComponentType defaultComponent: ComponentType }): ComponentType { const {options} = useSource().__internal const {defaultComponent, pick} = props - const middlewareComponents: ComponentType[] = useMemo(() => { - const middleware = _pickFromPluginOptions(options, pick) - - return [defaultComponent, ...middleware] - }, [defaultComponent, options, pick]) + const middlewareComponents = useMemo(() => { + return _pickFromPluginOptions(options, pick) + }, [options, pick]) - return useMemo(() => _createMiddlewareComponent(middlewareComponents), [middlewareComponents]) + return useMemo( + () => _createMiddlewareComponent(defaultComponent, middlewareComponents), + [defaultComponent, middlewareComponents] + ) } diff --git a/packages/sanity/src/core/form/form-components-hooks/componentHooks.ts b/packages/sanity/src/core/form/form-components-hooks/componentHooks.ts index 4d83a1760e2..87da2cdc174 100644 --- a/packages/sanity/src/core/form/form-components-hooks/componentHooks.ts +++ b/packages/sanity/src/core/form/form-components-hooks/componentHooks.ts @@ -13,7 +13,7 @@ import { /** * @internal */ -export function useInputComponent(): ComponentType { +export function useInputComponent(): ComponentType> { return useMiddlewareComponents({ defaultComponent: DefaultInput, pick: pickInputComponent, @@ -23,7 +23,7 @@ export function useInputComponent(): ComponentType { /** * @internal */ -export function useFieldComponent(): ComponentType { +export function useFieldComponent(): ComponentType> { return useMiddlewareComponents({ defaultComponent: DefaultField, pick: pickFieldComponent, @@ -33,7 +33,7 @@ export function useFieldComponent(): ComponentType { /** * @internal */ -export function usePreviewComponent(): ComponentType { +export function usePreviewComponent(): ComponentType> { return useMiddlewareComponents({ defaultComponent: DefaultPreview, pick: pickPreviewComponent, @@ -43,7 +43,7 @@ export function usePreviewComponent(): ComponentType { /** * @internal */ -export function useItemComponent(): ComponentType { +export function useItemComponent(): ComponentType> { return useMiddlewareComponents({ defaultComponent: DefaultItem, pick: pickItemComponent, diff --git a/packages/sanity/src/core/form/form-components-hooks/components.ts b/packages/sanity/src/core/form/form-components-hooks/components.ts index 634e28c6f39..61e5824b653 100644 --- a/packages/sanity/src/core/form/form-components-hooks/components.ts +++ b/packages/sanity/src/core/form/form-components-hooks/components.ts @@ -9,14 +9,19 @@ import { } from '../studio/inputResolver/inputResolver' import {InputProps, FieldProps, ItemProps} from '../types' -function useResolveDefaultComponent(props: { - componentProps: T & {schemaType: SchemaType} - componentResolver: (schemaType: SchemaType) => React.ComponentType +function useResolveDefaultComponent(props: { + componentProps: Omit + componentResolver: (schemaType: SchemaType) => React.ComponentType> }): React.ReactElement { const {componentResolver, componentProps} = props - const defaultResolvedComponent = componentResolver( - componentProps.schemaType - ) as React.ComponentType + + // NOTE: this will not happen, but we do this to avoid updating too many places + // TODO: We need to clean up the preview machinery + types to remove this + if (!componentProps.schemaType) { + throw new Error('the `schemaType` property must be defined') + } + + const defaultResolvedComponent = componentResolver(componentProps.schemaType) const renderDefault = useCallback( (parentTypeProps: T) => { @@ -29,9 +34,7 @@ function useResolveDefaultComponent(props: { // in order to prevent that a component is render itself // eslint-disable-next-line @typescript-eslint/no-unused-vars const {components, ...restSchemaType} = componentProps.schemaType - const parentTypeResolvedComponent = componentResolver( - restSchemaType - ) as React.ComponentType + const parentTypeResolvedComponent = componentResolver(restSchemaType as SchemaType) return createElement(parentTypeResolvedComponent, parentTypeProps) }, [componentProps.schemaType, componentResolver] @@ -46,8 +49,8 @@ function useResolveDefaultComponent(props: { /** * @internal */ -export function DefaultInput(props: InputProps): React.ReactElement { - return useResolveDefaultComponent({ +export function DefaultInput(props: Omit): React.ReactElement { + return useResolveDefaultComponent>({ componentProps: props, componentResolver: defaultResolveInputComponent, }) @@ -56,8 +59,8 @@ export function DefaultInput(props: InputProps): React.ReactElement /** * @internal */ -export function DefaultField(props: FieldProps): React.ReactElement { - return useResolveDefaultComponent({ +export function DefaultField(props: Omit): React.ReactElement { + return useResolveDefaultComponent>({ componentProps: props, componentResolver: defaultResolveFieldComponent, }) @@ -66,8 +69,8 @@ export function DefaultField(props: FieldProps): React.ReactElement /** * @internal */ -export function DefaultItem(props: ItemProps): React.ReactElement { - return useResolveDefaultComponent({ +export function DefaultItem(props: Omit): React.ReactElement { + return useResolveDefaultComponent>({ componentProps: props, componentResolver: defaultResolveItemComponent, }) @@ -76,9 +79,9 @@ export function DefaultItem(props: ItemProps): React.ReactElement { /** * @internal */ -export function DefaultPreview(props: PreviewProps): React.ReactElement { - return useResolveDefaultComponent({ - componentProps: props as any, +export function DefaultPreview(props: Omit): React.ReactElement { + return useResolveDefaultComponent>({ + componentProps: props, componentResolver: defaultResolvePreviewComponent, }) } diff --git a/packages/sanity/src/core/form/form-components-hooks/picks.ts b/packages/sanity/src/core/form/form-components-hooks/picks.ts index de74a02df3c..d85ce299440 100644 --- a/packages/sanity/src/core/form/form-components-hooks/picks.ts +++ b/packages/sanity/src/core/form/form-components-hooks/picks.ts @@ -3,18 +3,26 @@ import {PreviewProps} from '../../components/previews' import {PluginOptions} from '../../config' import {FieldProps, InputProps, ItemProps} from '../types' -export function pickInputComponent(plugin: PluginOptions): ComponentType { - return plugin.form?.components?.input as ComponentType +export function pickInputComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.form?.components?.input as ComponentType> } -export function pickFieldComponent(plugin: PluginOptions): ComponentType { - return plugin.form?.components?.field as ComponentType +export function pickFieldComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.form?.components?.field as ComponentType> } -export function pickPreviewComponent(plugin: PluginOptions): ComponentType { - return plugin.form?.components?.preview as ComponentType +export function pickPreviewComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.form?.components?.preview as ComponentType> } -export function pickItemComponent(plugin: PluginOptions): ComponentType { - return plugin.form?.components?.item as ComponentType +export function pickItemComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.form?.components?.item as ComponentType> } diff --git a/packages/sanity/src/core/form/inputs/ObjectInput/__tests__/ObjectFieldset.test.tsx b/packages/sanity/src/core/form/inputs/ObjectInput/__tests__/ObjectFieldset.test.tsx index 2d1636c35b2..5ad011e6aef 100644 --- a/packages/sanity/src/core/form/inputs/ObjectInput/__tests__/ObjectFieldset.test.tsx +++ b/packages/sanity/src/core/form/inputs/ObjectInput/__tests__/ObjectFieldset.test.tsx @@ -33,7 +33,7 @@ const fieldsetsTestType = defineField({ describe('fieldset with default options', () => { it('renders fields in a
{ - function FieldWithTestId(props: FieldProps) { + function FieldWithTestId(props: Omit) { return
{props.children}
} const {result} = await renderObjectInput({ diff --git a/packages/sanity/src/core/form/inputs/PortableText/__workshop__/_common/input.tsx b/packages/sanity/src/core/form/inputs/PortableText/__workshop__/_common/input.tsx index f8462a192b3..4ccc5db733f 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/__workshop__/_common/input.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/__workshop__/_common/input.tsx @@ -36,7 +36,7 @@ const DebugInput = forwardRef(function DebugInput(props: InputProps, ref) { export function inputResolver( input: SchemaType, form: SanityFormConfig -): React.ComponentType { +): React.ComponentType> { if (!input.type) { throw new Error('inputResolver: missing subtype') } diff --git a/packages/sanity/src/core/form/inputs/PortableText/object/BlockObjectPreview.tsx b/packages/sanity/src/core/form/inputs/PortableText/object/BlockObjectPreview.tsx index 7b645cee5d0..3e11e64616e 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/object/BlockObjectPreview.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/object/BlockObjectPreview.tsx @@ -139,7 +139,7 @@ export function BlockObjectPreview(props: BlockObjectPreviewProps): ReactElement if (isCustomPreviewComponent) { return ( - {renderPreview(previewProps as PreviewProps)} + {renderPreview(previewProps)} {actions} ) @@ -152,8 +152,8 @@ export function BlockObjectPreview(props: BlockObjectPreviewProps): ReactElement layout: isImageType ? 'blockImage' : 'block', schemaType: type, value, - media: isImageType ? value : undefined, - } as PreviewProps)} + media: (isImageType ? value : undefined) as any, // TODO + })} ) } 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 744d68609cc..262e7a9628c 100644 --- a/packages/sanity/src/core/form/inputs/PortableText/object/InlineObject.tsx +++ b/packages/sanity/src/core/form/inputs/PortableText/object/InlineObject.tsx @@ -155,7 +155,7 @@ export const InlineObject = React.forwardRef(function InlineObject( value, } - return {renderPreview(previewProps as PreviewProps)} + return {renderPreview(previewProps)} }, [renderPreview, type, value]) const markersToolTip = useMemo( diff --git a/packages/sanity/src/core/form/inputs/ReferenceInput/PreviewReferenceValue.tsx b/packages/sanity/src/core/form/inputs/ReferenceInput/PreviewReferenceValue.tsx index aded20b8ef0..ede9a6002f7 100644 --- a/packages/sanity/src/core/form/inputs/ReferenceInput/PreviewReferenceValue.tsx +++ b/packages/sanity/src/core/form/inputs/ReferenceInput/PreviewReferenceValue.tsx @@ -43,7 +43,7 @@ export function PreviewReferenceValue(props: { return ( - {renderPreview(previewProps as PreviewProps)} + {renderPreview(previewProps)} {showTypeLabel && ( diff --git a/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx b/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx index 90c4554c9a5..ed944724845 100644 --- a/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx +++ b/packages/sanity/src/core/form/inputs/ReferenceInput/ReferencePreview.tsx @@ -85,7 +85,7 @@ export function ReferencePreview(props: { return ( {availability.available ? ( - {renderPreview(previewProps as PreviewProps)} + {renderPreview(previewProps)} ) : ( diff --git a/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/ArrayInput.tsx b/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/ArrayInput.tsx index 66d57872d49..6f814afe7bb 100644 --- a/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/ArrayInput.tsx +++ b/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/ArrayInput.tsx @@ -254,7 +254,7 @@ export class ArrayInput extends React.PureComponent { } /** @internal */ - renderArrayItem = (itemProps: ItemProps) => { + renderArrayItem = (itemProps: Omit) => { if (!isObjectItemProps(itemProps)) { throw new Error('Expected item to be of object type') } diff --git a/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/CellItem.tsx b/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/CellItem.tsx index a871d4512b3..8c653af687f 100644 --- a/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/CellItem.tsx +++ b/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/CellItem.tsx @@ -173,7 +173,7 @@ export const CellItem = React.forwardRef(function ItemCell( onFocus={onFocus} __unstable_focusRing > - {renderPreview(previewProps as PreviewProps)} + {renderPreview(previewProps)} ) : ( diff --git a/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/RowItem.tsx b/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/RowItem.tsx index 5322f8b1359..02dc56c7fb0 100644 --- a/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/RowItem.tsx +++ b/packages/sanity/src/core/form/inputs/arrays/ArrayOfObjectsInput/item/RowItem.tsx @@ -123,7 +123,7 @@ export const RowItem = React.forwardRef(function RegularItem( onFocus={onFocus} __unstable_focusRing > - {renderPreview(previewProps as PreviewProps)} + {renderPreview(previewProps)} ) : ( diff --git a/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ArrayOfPrimitivesInput.tsx b/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ArrayOfPrimitivesInput.tsx index 3be22391087..9c88971319d 100644 --- a/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ArrayOfPrimitivesInput.tsx +++ b/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ArrayOfPrimitivesInput.tsx @@ -135,7 +135,7 @@ export class ArrayOfPrimitivesInput extends React.PureComponent { + renderArrayItem = (props: Omit) => { const {schemaType, readOnly} = this.props const isSortable = !readOnly && get(schemaType, 'options.sortable') !== false diff --git a/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ItemRow.tsx b/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ItemRow.tsx index f48559fd179..e1bcc547b71 100644 --- a/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ItemRow.tsx +++ b/packages/sanity/src/core/form/inputs/arrays/ArrayOfPrimitivesInput/ItemRow.tsx @@ -12,7 +12,7 @@ import {getEmptyValue} from './getEmptyValue' const dragHandle = -export type DefaultItemProps = PrimitiveItemProps & { +export type DefaultItemProps = Omit & { insertableTypes: SchemaType[] onEnterKey: (item: number) => void onEscapeKey: (item: number) => void diff --git a/packages/sanity/src/core/form/inputs/arrays/OptionsArrayInput/OptionsArrayInput.tsx b/packages/sanity/src/core/form/inputs/arrays/OptionsArrayInput/OptionsArrayInput.tsx index 17ffcfa6456..c2642a79eea 100644 --- a/packages/sanity/src/core/form/inputs/arrays/OptionsArrayInput/OptionsArrayInput.tsx +++ b/packages/sanity/src/core/form/inputs/arrays/OptionsArrayInput/OptionsArrayInput.tsx @@ -128,7 +128,7 @@ export class OptionsArrayInput extends React.PureComponent{title} ) : ( - {renderPreview(previewProps as PreviewProps)} + {renderPreview(previewProps)} ))} {!optionType && ( diff --git a/packages/sanity/src/core/form/inputs/files/FileInput/FileInput.tsx b/packages/sanity/src/core/form/inputs/files/FileInput/FileInput.tsx index 18ad01e21b4..926e9fded00 100644 --- a/packages/sanity/src/core/form/inputs/files/FileInput/FileInput.tsx +++ b/packages/sanity/src/core/form/inputs/files/FileInput/FileInput.tsx @@ -326,7 +326,7 @@ export class BaseFileInput extends React.PureComponent ( + return (inputProps: Omit) => ( <> {isStale && ( diff --git a/packages/sanity/src/core/form/inputs/files/ImageInput/ImageInput.tsx b/packages/sanity/src/core/form/inputs/files/ImageInput/ImageInput.tsx index 7daa65100f6..43c036a2b60 100644 --- a/packages/sanity/src/core/form/inputs/files/ImageInput/ImageInput.tsx +++ b/packages/sanity/src/core/form/inputs/files/ImageInput/ImageInput.tsx @@ -368,7 +368,7 @@ export class BaseImageInput extends React.PureComponent { + renderHotspotInput = (hotspotInputProps: Omit) => { const {value, changed, id, imageUrlBuilder} = this.props const withImageTool = this.isImageToolEnabled() && value && value.asset @@ -706,7 +706,7 @@ export class BaseImageInput extends React.PureComponent ( + return (inputProps: Omit) => ( <> {isStale && ( diff --git a/packages/sanity/src/core/form/inputs/files/ImageToolInput/ImageToolInput.tsx b/packages/sanity/src/core/form/inputs/files/ImageToolInput/ImageToolInput.tsx index 180b78bd51d..05cf6c24a86 100644 --- a/packages/sanity/src/core/form/inputs/files/ImageToolInput/ImageToolInput.tsx +++ b/packages/sanity/src/core/form/inputs/files/ImageToolInput/ImageToolInput.tsx @@ -13,7 +13,7 @@ import {ImageTool, HotspotImage, DEFAULT_CROP, DEFAULT_HOTSPOT} from './imagetoo import {useLoadImage} from './useLoadImage' export interface ImageToolInputProps - extends Omit, 'markers'> { + extends Omit, 'markers' | 'renderDefault'> { imageUrl: string } diff --git a/packages/sanity/src/core/form/members/fields/ArrayOfObjectsField.tsx b/packages/sanity/src/core/form/members/fields/ArrayOfObjectsField.tsx index 491971046c5..f678ac1e1ce 100644 --- a/packages/sanity/src/core/form/members/fields/ArrayOfObjectsField.tsx +++ b/packages/sanity/src/core/form/members/fields/ArrayOfObjectsField.tsx @@ -281,10 +281,7 @@ export function ArrayOfObjectsField(props: { elementProps, ]) - const renderedInput = useMemo( - () => renderInput(inputProps as ArrayOfObjectsInputProps), - [inputProps, renderInput] - ) + const renderedInput = useMemo(() => renderInput(inputProps), [inputProps, renderInput]) const fieldProps = useMemo((): Omit => { return { @@ -336,7 +333,7 @@ export function ArrayOfObjectsField(props: { onPathBlur={onPathBlur} onPathFocus={onPathFocus} > - {useMemo(() => renderField(fieldProps as ArrayFieldProps), [fieldProps, renderField])} + {useMemo(() => renderField(fieldProps), [fieldProps, renderField])} ) } diff --git a/packages/sanity/src/core/form/members/fields/ArrayOfPrimitivesField.tsx b/packages/sanity/src/core/form/members/fields/ArrayOfPrimitivesField.tsx index 810c7637f62..9c7c074db81 100644 --- a/packages/sanity/src/core/form/members/fields/ArrayOfPrimitivesField.tsx +++ b/packages/sanity/src/core/form/members/fields/ArrayOfPrimitivesField.tsx @@ -254,12 +254,9 @@ export function ArrayOfPrimitivesField(props: { renderPreview, ]) - const renderedInput = useMemo( - () => renderInput(inputProps as ArrayOfPrimitivesInputProps), - [inputProps, renderInput] - ) + const renderedInput = useMemo(() => renderInput(inputProps), [inputProps, renderInput]) - const fieldProps = useMemo((): Omit => { + const fieldProps: Omit = useMemo(() => { return { name: member.name, index: member.index, diff --git a/packages/sanity/src/core/form/members/fields/ObjectField.tsx b/packages/sanity/src/core/form/members/fields/ObjectField.tsx index 76d1ed6cc17..d19b8d986ce 100644 --- a/packages/sanity/src/core/form/members/fields/ObjectField.tsx +++ b/packages/sanity/src/core/form/members/fields/ObjectField.tsx @@ -4,7 +4,6 @@ import {useDidUpdate} from '../../hooks/useDidUpdate' import {FieldMember, ObjectFormNode} from '../../store' import { ArrayOfObjectsInputProps, - InputProps, ObjectFieldProps, ObjectInputProps, RenderArrayOfObjectsItemCallback, @@ -200,10 +199,7 @@ export const ObjectField = function ObjectField(props: { renderPreview, ]) - const renderedInput = useMemo( - () => renderInput(inputProps as ObjectInputProps), - [inputProps, renderInput] - ) + const renderedInput = useMemo(() => renderInput(inputProps), [inputProps, renderInput]) const fieldProps = useMemo((): Omit => { return { @@ -265,7 +261,7 @@ export const ObjectField = function ObjectField(props: { onPathBlur={onPathBlur} onPathFocus={onPathFocus} > - {useMemo(() => renderField(fieldProps as ObjectFieldProps), [fieldProps, renderField])} + {useMemo(() => renderField(fieldProps), [fieldProps, renderField])} ) } diff --git a/packages/sanity/src/core/form/members/fields/PrimitiveField.tsx b/packages/sanity/src/core/form/members/fields/PrimitiveField.tsx index d1449238b0b..953161e2c6d 100644 --- a/packages/sanity/src/core/form/members/fields/PrimitiveField.tsx +++ b/packages/sanity/src/core/form/members/fields/PrimitiveField.tsx @@ -130,10 +130,7 @@ export function PrimitiveField(props: { elementProps, ]) - const renderedInput = useMemo( - () => renderInput(inputProps as PrimitiveInputProps), - [inputProps, renderInput] - ) + const renderedInput = useMemo(() => renderInput(inputProps), [inputProps, renderInput]) const fieldProps = useMemo((): Omit => { return { @@ -167,5 +164,5 @@ export function PrimitiveField(props: { inputProps, ]) - return <>{renderField(fieldProps as PrimitiveFieldProps)} + return <>{renderField(fieldProps)} } diff --git a/packages/sanity/src/core/form/members/items/ArrayOfObjectsItem.tsx b/packages/sanity/src/core/form/members/items/ArrayOfObjectsItem.tsx index fc64ea4a8bc..a77cb20651d 100644 --- a/packages/sanity/src/core/form/members/items/ArrayOfObjectsItem.tsx +++ b/packages/sanity/src/core/form/members/items/ArrayOfObjectsItem.tsx @@ -225,10 +225,7 @@ export function ArrayOfObjectsItem(props: MemberItemProps) { renderPreview, ]) - const renderedInput = useMemo( - () => renderInput(inputProps as ObjectInputProps), - [inputProps, renderInput] - ) + const renderedInput = useMemo(() => renderInput(inputProps), [inputProps, renderInput]) const itemProps = useMemo((): Omit => { return { @@ -294,7 +291,7 @@ export function ArrayOfObjectsItem(props: MemberItemProps) { onPathBlur={onPathBlur} onPathFocus={onPathFocus} > - {useMemo(() => renderItem(itemProps as ObjectItemProps), [itemProps, renderItem])} + {useMemo(() => renderItem(itemProps), [itemProps, renderItem])} ) } diff --git a/packages/sanity/src/core/form/members/items/ArrayOfPrimitivesItem.tsx b/packages/sanity/src/core/form/members/items/ArrayOfPrimitivesItem.tsx index caaddde0c19..eb49fddd8ba 100644 --- a/packages/sanity/src/core/form/members/items/ArrayOfPrimitivesItem.tsx +++ b/packages/sanity/src/core/form/members/items/ArrayOfPrimitivesItem.tsx @@ -134,10 +134,7 @@ export function ArrayOfPrimitivesItem(props: PrimitiveMemberItemProps) { elementProps, ]) - const renderedInput = useMemo( - () => renderInput(inputProps as PrimitiveInputProps), - [inputProps, renderInput] - ) + const renderedInput = useMemo(() => renderInput(inputProps), [inputProps, renderInput]) const onRemove = useCallback(() => { onChange(PatchEvent.from([unset([member.index])])) diff --git a/packages/sanity/src/core/form/studio/FormBuilder.tsx b/packages/sanity/src/core/form/studio/FormBuilder.tsx index fb057b866dc..f23aa532163 100644 --- a/packages/sanity/src/core/form/studio/FormBuilder.tsx +++ b/packages/sanity/src/core/form/studio/FormBuilder.tsx @@ -199,5 +199,5 @@ function RootInput() { value, } - return <>{renderInput(rootInputProps as ObjectInputProps)} + return <>{renderInput(rootInputProps)} } diff --git a/packages/sanity/src/core/form/studio/FormProvider.tsx b/packages/sanity/src/core/form/studio/FormProvider.tsx index eb4d38c8bdb..71e13fec66e 100644 --- a/packages/sanity/src/core/form/studio/FormProvider.tsx +++ b/packages/sanity/src/core/form/studio/FormProvider.tsx @@ -88,11 +88,20 @@ export function FormProvider(props: FormProviderProps) { const Preview = usePreviewComponent() const Item = useItemComponent() - const renderInput = useCallback((inputProps: InputProps) => , [Input]) - const renderField = useCallback((fieldProps: FieldProps) => , [Field]) - const renderItem = useCallback((itemProps: ItemProps) => , [Item]) + const renderInput = useCallback( + (inputProps: Omit) => , + [Input] + ) + const renderField = useCallback( + (fieldProps: Omit) => , + [Field] + ) + const renderItem = useCallback( + (itemProps: Omit) => , + [Item] + ) const renderPreview = useCallback( - (previewProps: PreviewProps) => , + (previewProps: Omit) => , [Preview] ) diff --git a/packages/sanity/src/core/form/studio/inputResolver/inputResolver.tsx b/packages/sanity/src/core/form/studio/inputResolver/inputResolver.tsx index dca65bf183b..422e0b7d4b1 100644 --- a/packages/sanity/src/core/form/studio/inputResolver/inputResolver.tsx +++ b/packages/sanity/src/core/form/studio/inputResolver/inputResolver.tsx @@ -57,7 +57,7 @@ function getTypeChain(type: SchemaType | undefined, visited: Set): S export function defaultResolveInputComponent( schemaType: SchemaType -): React.ComponentType { +): React.ComponentType> { if (schemaType.components?.input) return schemaType.components.input const componentFromTypeVariants = resolveComponentFromTypeVariants(schemaType) @@ -153,7 +153,7 @@ function ImageOrFileField(field: ObjectFieldProps) { export function defaultResolveFieldComponent( schemaType: SchemaType -): React.ComponentType { +): React.ComponentType> { if (schemaType.components?.field) return schemaType.components.field if (isBooleanSchemaType(schemaType)) { @@ -161,24 +161,26 @@ export function defaultResolveFieldComponent( } if (getTypeChain(schemaType, new Set()).some((t) => t.name === 'image' || t.name === 'file')) { - return ImageOrFileField as React.ComponentType + return ImageOrFileField as React.ComponentType> } if (schemaType.jsonType !== 'object' && schemaType.jsonType !== 'array') { - return PrimitiveField + return PrimitiveField as React.ComponentType> } - return ObjectOrArrayField as React.ComponentType + return ObjectOrArrayField as React.ComponentType> } export function defaultResolveItemComponent( schemaType: SchemaType -): React.ComponentType { +): React.ComponentType> { if (schemaType.components?.item) return schemaType.components.item return NoopField } -export function defaultResolvePreviewComponent(): React.ComponentType { +export function defaultResolvePreviewComponent(): React.ComponentType< + Omit +> { return SanityPreview as any } diff --git a/packages/sanity/src/core/form/types/asserters.ts b/packages/sanity/src/core/form/types/asserters.ts index 4e2d46ea7bd..2e9a8aa7484 100644 --- a/packages/sanity/src/core/form/types/asserters.ts +++ b/packages/sanity/src/core/form/types/asserters.ts @@ -18,40 +18,50 @@ import { import {ItemProps, ObjectItemProps} from './itemProps' /** @beta */ -export function isObjectItemProps(item: ItemProps): item is ObjectItemProps { +export function isObjectItemProps( + item: ItemProps | Omit +): item is ObjectItemProps { return isObjectSchemaType(item.schemaType) } /** @beta */ -export function isObjectInputProps(inputProps: InputProps): inputProps is ObjectInputProps { +export function isObjectInputProps( + inputProps: InputProps | Omit +): inputProps is ObjectInputProps { return isObjectSchemaType(inputProps.schemaType) } /** @beta */ -export function isStringInputProps(inputProps: InputProps): inputProps is StringInputProps { +export function isStringInputProps( + inputProps: InputProps | Omit +): inputProps is StringInputProps { return isStringSchemaType(inputProps.schemaType) } /** @beta */ -export function isNumberInputProps(inputProps: InputProps): inputProps is NumberInputProps { +export function isNumberInputProps( + inputProps: InputProps | Omit +): inputProps is NumberInputProps { return isNumberSchemaType(inputProps.schemaType) } /** @beta */ -export function isBooleanInputProps(inputProps: InputProps): inputProps is BooleanInputProps { +export function isBooleanInputProps( + inputProps: InputProps | Omit +): inputProps is BooleanInputProps { return isBooleanSchemaType(inputProps.schemaType) } /** @beta */ export function isArrayOfObjectsInputProps( - inputProps: InputProps + inputProps: InputProps | Omit ): inputProps is ArrayOfObjectsInputProps { return isArrayOfObjectsSchemaType(inputProps.schemaType) } /** @beta */ export function isArrayOfPrimitivesInputProps( - inputProps: InputProps + inputProps: InputProps | Omit ): inputProps is ArrayOfPrimitivesInputProps { return isArrayOfPrimitivesSchemaType(inputProps.schemaType) } diff --git a/packages/sanity/src/core/form/types/fieldProps.ts b/packages/sanity/src/core/form/types/fieldProps.ts index ed211131fe5..7eea6add3c7 100644 --- a/packages/sanity/src/core/form/types/fieldProps.ts +++ b/packages/sanity/src/core/form/types/fieldProps.ts @@ -8,6 +8,7 @@ import { SchemaType, StringSchemaType, } from '@sanity/types' +import {ReactElement, ReactNode} from 'react' import {FormNodePresence} from '../../presence' import { ArrayOfObjectsInputProps, @@ -33,8 +34,8 @@ export interface BaseFieldProps { name: string index: number changed: boolean - children: React.ReactNode - renderDefault: (props: FieldProps) => React.ReactElement + children: ReactNode + renderDefault: (props: FieldProps) => ReactElement } /** @public */ diff --git a/packages/sanity/src/core/form/types/inputProps.ts b/packages/sanity/src/core/form/types/inputProps.ts index 07a5c10dcb8..8535b354bb4 100644 --- a/packages/sanity/src/core/form/types/inputProps.ts +++ b/packages/sanity/src/core/form/types/inputProps.ts @@ -29,7 +29,7 @@ import {InsertItemEvent, MoveItemEvent} from './event' /** @public */ export interface BaseInputProps { - renderDefault: (props: InputProps) => React.ReactElement + renderDefault: (props: InputProps) => React.ReactElement } /** @public */ diff --git a/packages/sanity/src/core/form/types/itemProps.ts b/packages/sanity/src/core/form/types/itemProps.ts index e33a35caa89..975e4c203d6 100644 --- a/packages/sanity/src/core/form/types/itemProps.ts +++ b/packages/sanity/src/core/form/types/itemProps.ts @@ -39,7 +39,7 @@ export interface BaseItemProps { /** @beta */ presence: FormNodePresence[] - renderDefault: (props: ItemProps) => React.ReactElement + renderDefault: (props: ItemProps) => React.ReactElement } /** @public */ diff --git a/packages/sanity/src/core/form/types/renderCallback.ts b/packages/sanity/src/core/form/types/renderCallback.ts index 3fccf3e7763..6fd7b97bb48 100644 --- a/packages/sanity/src/core/form/types/renderCallback.ts +++ b/packages/sanity/src/core/form/types/renderCallback.ts @@ -5,19 +5,29 @@ import {FieldProps} from './fieldProps' import {InputProps} from './inputProps' /** @public */ -export type RenderArrayOfObjectsItemCallback = (itemProps: ObjectItemProps) => ReactNode +export type RenderArrayOfObjectsItemCallback = ( + itemProps: Omit +) => ReactNode /** @public */ -export type RenderArrayOfPrimitivesItemCallback = (itemProps: PrimitiveItemProps) => ReactNode +export type RenderArrayOfPrimitivesItemCallback = ( + itemProps: Omit +) => ReactNode /** @public */ -export type RenderItemCallback = (itemProps: ObjectItemProps | PrimitiveItemProps) => ReactNode +export type RenderItemCallback = ( + itemProps: Omit | Omit +) => ReactNode /** @public */ -export type RenderFieldCallback = (fieldProps: T) => ReactNode +export type RenderFieldCallback = ( + fieldProps: Omit +) => ReactNode /** @public */ -export type RenderInputCallback = (inputProps: T) => ReactNode +export type RenderInputCallback = ( + inputProps: Omit +) => ReactNode /** @beta */ -export type RenderPreviewCallback = (props: PreviewProps) => ReactNode +export type RenderPreviewCallback = (props: Omit) => ReactNode diff --git a/packages/sanity/src/core/form/utils/asserters.ts b/packages/sanity/src/core/form/utils/asserters.ts index 98c1f234b25..89f6a35ee75 100644 --- a/packages/sanity/src/core/form/utils/asserters.ts +++ b/packages/sanity/src/core/form/utils/asserters.ts @@ -13,22 +13,32 @@ export function assertType(v: unknown): asserts v is T { // intentionally empty } -export function isObjectInputProps(inputProps: InputProps): inputProps is ObjectInputProps { +export function isObjectInputProps( + inputProps: InputProps | Omit +): inputProps is ObjectInputProps { return isObjectSchemaType(inputProps.schemaType) } -export function isArrayInputProps(inputProps: InputProps): inputProps is ArrayOfObjectsInputProps { +export function isArrayInputProps( + inputProps: InputProps | Omit +): inputProps is ArrayOfObjectsInputProps { return isArraySchemaType(inputProps.schemaType) } -export function isPrimitiveField(fieldProps: FieldProps): fieldProps is PrimitiveFieldProps { +export function isPrimitiveField( + fieldProps: FieldProps | Omit +): fieldProps is PrimitiveFieldProps { return !isObjectSchemaType(fieldProps.schemaType) && !isArraySchemaType(fieldProps.schemaType) } -export function isBooleanField(fieldProps: FieldProps): fieldProps is BooleanFieldProps { +export function isBooleanField( + fieldProps: FieldProps | Omit +): fieldProps is BooleanFieldProps { return isBooleanSchemaType(fieldProps.schemaType) } -export function isObjectField(fieldProps: FieldProps): fieldProps is ObjectFieldProps { +export function isObjectField( + fieldProps: FieldProps | Omit +): fieldProps is ObjectFieldProps { return isObjectSchemaType(fieldProps.schemaType) } diff --git a/packages/sanity/src/core/preview/components/SanityDefaultPreview.tsx b/packages/sanity/src/core/preview/components/SanityDefaultPreview.tsx index 82ff4f4031f..de61d0187b7 100644 --- a/packages/sanity/src/core/preview/components/SanityDefaultPreview.tsx +++ b/packages/sanity/src/core/preview/components/SanityDefaultPreview.tsx @@ -2,6 +2,7 @@ import {DocumentIcon} from '@sanity/icons' import imageUrlBuilder from '@sanity/image-url' import {ImageUrlFitMode, isImage, isReference} from '@sanity/types' import React, { + ComponentType, createElement, ElementType, isValidElement, @@ -45,8 +46,7 @@ export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactEle const client = useClient(DEFAULT_STUDIO_CLIENT_OPTIONS) const imageBuilder = useMemo(() => imageUrlBuilder(client), [client]) - const component = (_previewComponents[layout || 'default'] || - _previewComponents.default) as ElementType + const component = _previewComponents[layout || 'default'] || _previewComponents.default const {_upload, value} = useMemo(() => { return valueProp ? _extractUploadState(valueProp) : {_upload: undefined, value: undefined} @@ -150,5 +150,8 @@ export function SanityDefaultPreview(props: SanityDefaultPreviewProps): ReactEle ] ) - return createElement(component, previewProps as PreviewProps) + return createElement( + component as ComponentType>, + previewProps + ) } diff --git a/packages/sanity/src/core/preview/components/SanityPreview.tsx b/packages/sanity/src/core/preview/components/SanityPreview.tsx index 65ef5066fc1..c2b3eb87f1f 100644 --- a/packages/sanity/src/core/preview/components/SanityPreview.tsx +++ b/packages/sanity/src/core/preview/components/SanityPreview.tsx @@ -83,7 +83,7 @@ export function SanityPreview(props: SanityPreviewProps & {style?: CSSProperties return (
- {createElement(component, {...previewProps, schemaType: restSchemaType} as PreviewProps)} + {createElement(component, {...previewProps, schemaType: restSchemaType})}
) } diff --git a/packages/sanity/src/core/preview/components/_resolvePreviewComponent.ts b/packages/sanity/src/core/preview/components/_resolvePreviewComponent.ts index 981b062fd0a..636011fce13 100644 --- a/packages/sanity/src/core/preview/components/_resolvePreviewComponent.ts +++ b/packages/sanity/src/core/preview/components/_resolvePreviewComponent.ts @@ -4,7 +4,7 @@ import {PreviewProps} from '../../components/previews' import {SanityDefaultPreview} from './SanityDefaultPreview' type PreviewElementType = ElementType< - PreviewProps & { + Omit & { icon?: React.ElementType schemaType?: SchemaType } diff --git a/packages/sanity/src/core/studio/studio-components-hooks/componentHooks.ts b/packages/sanity/src/core/studio/studio-components-hooks/componentHooks.ts index 4e47f7122cd..22b5053dd92 100644 --- a/packages/sanity/src/core/studio/studio-components-hooks/componentHooks.ts +++ b/packages/sanity/src/core/studio/studio-components-hooks/componentHooks.ts @@ -15,9 +15,9 @@ import { */ export function useToolMenuComponent(): ComponentType> { return useMiddlewareComponents({ - defaultComponent: StudioToolMenu, + defaultComponent: StudioToolMenu as ComponentType>, pick: pickToolMenuComponent, - }) as ComponentType> + }) } /** @@ -25,9 +25,9 @@ export function useToolMenuComponent(): ComponentType> { return useMiddlewareComponents({ - defaultComponent: StudioNavbar, + defaultComponent: StudioNavbar as ComponentType>, pick: pickNavbarComponent, - }) as ComponentType> + }) } /** @@ -35,9 +35,9 @@ export function useNavbarComponent(): ComponentType> { return useMiddlewareComponents({ - defaultComponent: StudioLogo, + defaultComponent: StudioLogo as ComponentType>, pick: pickLogoComponent, - }) as ComponentType> + }) } /** @@ -45,7 +45,7 @@ export function useLogoComponent(): ComponentType> { return useMiddlewareComponents({ - defaultComponent: StudioLayout, + defaultComponent: StudioLayout as ComponentType>, pick: pickLayoutComponent, - }) as ComponentType> + }) } diff --git a/packages/sanity/src/core/studio/studio-components-hooks/picks.ts b/packages/sanity/src/core/studio/studio-components-hooks/picks.ts index bc257f6bf49..988d597195d 100644 --- a/packages/sanity/src/core/studio/studio-components-hooks/picks.ts +++ b/packages/sanity/src/core/studio/studio-components-hooks/picks.ts @@ -1,18 +1,26 @@ import {ComponentType} from 'react' import {LayoutProps, LogoProps, NavbarProps, PluginOptions, ToolMenuProps} from '../../config' -export function pickToolMenuComponent(plugin: PluginOptions): ComponentType { - return plugin.studio?.components?.toolMenu as ComponentType +export function pickToolMenuComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.studio?.components?.toolMenu as ComponentType> } -export function pickNavbarComponent(plugin: PluginOptions): ComponentType { - return plugin.studio?.components?.navbar as ComponentType +export function pickNavbarComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.studio?.components?.navbar as ComponentType> } -export function pickLayoutComponent(plugin: PluginOptions): ComponentType { - return plugin.studio?.components?.layout as ComponentType +export function pickLayoutComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.studio?.components?.layout as ComponentType> } -export function pickLogoComponent(plugin: PluginOptions): ComponentType { - return plugin.studio?.components?.logo as ComponentType +export function pickLogoComponent( + plugin: PluginOptions +): ComponentType> { + return plugin.studio?.components?.logo as ComponentType> }