UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

120 lines (103 loc) 3.8 kB
import {isRecord} from 'sanity' import {HELP_URL, SerializeError} from '../SerializeError' import {type SerializeOptions} from '../StructureNodes' import {type UserViewComponent} from '../types' import {type BaseView, GenericViewBuilder} from './View' /** * Interface for component views. * * @public */ export interface ComponentView<TOptions = Record<string, any>> extends BaseView { type: 'component' /** Component view components. See {@link UserViewComponent} */ component: UserViewComponent /** Component view options */ options: TOptions } const isComponentSpec = (spec: unknown): spec is ComponentView => isRecord(spec) && spec.type === 'component' /** * Class for building a component view. * * @public */ export class ComponentViewBuilder extends GenericViewBuilder< Partial<ComponentView>, ComponentViewBuilder > { /** Partial Component view option object. See {@link ComponentView} */ protected spec: Partial<ComponentView> constructor( /** * Component view component or spec * @param componentOrSpec - user view component or partial component view. See {@link UserViewComponent} and {@link ComponentView} */ componentOrSpec?: UserViewComponent | Partial<ComponentView>, ) { const spec = isComponentSpec(componentOrSpec) ? {...componentOrSpec} : {options: {}} super() this.spec = spec const userComponent = typeof componentOrSpec === 'function' ? componentOrSpec : this.spec.component if (userComponent) { // Because we're cloning, this'll return a new instance, so grab the spec from it this.spec = this.component(userComponent).spec } } /** Set view Component * @param component - component view component. See {@link UserViewComponent} * @returns component view builder based on component view provided. See {@link ComponentViewBuilder} */ component(component: UserViewComponent): ComponentViewBuilder { return this.clone({component}) } /** Get view Component * @returns Partial component view. See {@link ComponentView} */ getComponent(): Partial<ComponentView>['component'] { return this.spec.component } /** Set view Component options * @param options - component view options * @returns component view builder based on options provided. See {@link ComponentViewBuilder} */ options(options: {[key: string]: any}): ComponentViewBuilder { return this.clone({options}) } /** Get view Component options * @returns component view options. See {@link ComponentView} */ getOptions(): ComponentView['options'] { return this.spec.options || {} } /** Serialize view Component * @param options - serialization options. See {@link SerializeOptions} * @returns component view based on path provided in options. See {@link ComponentView} * */ serialize(options: SerializeOptions = {path: []}): ComponentView { const base = super.serialize(options) const component = this.spec.component if (typeof component !== 'function') { throw new SerializeError( '`component` is required and must be a function for `component()` view item', options.path, options.index, ).withHelpUrl(HELP_URL.COMPONENT_REQUIRED) } return { ...base, component, options: this.spec.options || {}, type: 'component', } } /** Clone Component view builder (allows for options overriding) * @param withSpec - partial for component view option. See {@link ComponentView} * @returns component view builder. See {@link ComponentViewBuilder} */ clone(withSpec?: Partial<ComponentView>): ComponentViewBuilder { const builder = new ComponentViewBuilder() builder.spec = {...this.spec, ...(withSpec || {})} return builder } }