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

234 lines (201 loc) • 8.35 kB
import {AddIcon} from '@sanity/icons' import {type InitialValueTemplateItem} from 'sanity' import {type BaseIntentParams, type IntentParams} from './Intent' import {type MenuItem, MenuItemBuilder} from './MenuItem' import {HELP_URL, SerializeError} from './SerializeError' import {type Serializable, type SerializeOptions, type SerializePath} from './StructureNodes' import {type StructureContext} from './types' /** * A `InitialValueTemplateItemBuilder` is used to build a document node with an initial value set. * * @public */ export class InitialValueTemplateItemBuilder implements Serializable<InitialValueTemplateItem> { /** Initial Value template item option object. See {@link InitialValueTemplateItem} */ protected spec: Partial<InitialValueTemplateItem> constructor( /** * Structure context. See {@link StructureContext} */ protected _context: StructureContext, spec?: Partial<InitialValueTemplateItem>, ) { this.spec = spec ? spec : {} } /** Set initial value template item builder ID * @param id - initial value template item ID * @returns initial value template item based on ID provided. See {@link InitialValueTemplateItemBuilder} */ id(id: string): InitialValueTemplateItemBuilder { return this.clone({id}) } /** Get initial value template item builder ID * @returns initial value template item ID. See {@link InitialValueTemplateItem} */ getId(): Partial<InitialValueTemplateItem>['id'] { return this.spec.id } /** Set initial value template item title * @param title - initial value template item title * @returns initial value template item based on title provided. See {@link InitialValueTemplateItemBuilder} */ title(title: string): InitialValueTemplateItemBuilder { return this.clone({title}) } /** Get initial value template item title * @returns initial value template item title. See {@link InitialValueTemplateItem} */ getTitle(): Partial<InitialValueTemplateItem>['title'] { return this.spec.title } /** Set initial value template item description * @param description - initial value template item description * @returns initial value template item builder based on description provided. See {@link InitialValueTemplateItemBuilder} */ description(description: string): InitialValueTemplateItemBuilder { return this.clone({description}) } /** Get initial value template item description * @returns initial value template item description. See {@link InitialValueTemplateItem} */ getDescription(): Partial<InitialValueTemplateItem>['description'] { return this.spec.description } /** Set initial value template ID * @param templateId - initial value template item template ID * @returns initial value template item based builder on template ID provided. See {@link InitialValueTemplateItemBuilder} */ templateId(templateId: string): InitialValueTemplateItemBuilder { // Let's try to be a bit helpful and assign an ID from template ID if none is specified const paneId = this.spec.id || templateId return this.clone({ id: paneId, templateId, }) } /** Get initial value template item template ID * @returns initial value template item ID. See {@link InitialValueTemplateItem} */ getTemplateId(): Partial<InitialValueTemplateItem>['templateId'] { return this.spec.templateId } /** Get initial value template item template parameters * @param parameters - initial value template item parameters * @returns initial value template item builder based on parameters provided. See {@link InitialValueTemplateItemBuilder} */ parameters(parameters: {[key: string]: any}): InitialValueTemplateItemBuilder { return this.clone({parameters}) } /** Get initial value template item template parameters * @returns initial value template item parameters. See {@link InitialValueTemplateItem} */ getParameters(): Partial<InitialValueTemplateItem>['parameters'] { return this.spec.parameters } /** Serialize initial value template item * @param options - serialization options. See {@link SerializeOptions} * @returns initial value template item object based on the path, index and hint provided in options. See {@link InitialValueTemplateItem} */ serialize({path = [], index, hint}: SerializeOptions = {path: []}): InitialValueTemplateItem { const {spec, _context} = this const {templates} = _context if (typeof spec.id !== 'string' || !spec.id) { throw new SerializeError( '`id` is required for initial value template item nodes', path, index, hint, ).withHelpUrl(HELP_URL.ID_REQUIRED) } if (!spec.templateId) { throw new SerializeError( 'template id (`templateId`) is required for initial value template item nodes', path, spec.id, hint, ).withHelpUrl(HELP_URL.ID_REQUIRED) } const template = templates.find((t) => t.id === spec.templateId) if (!template) { throw new SerializeError( 'template id (`templateId`) is required for initial value template item nodes', path, spec.id, hint, ).withHelpUrl(HELP_URL.ID_REQUIRED) } return { id: spec.id, templateId: spec.id, schemaType: template.schemaType, type: 'initialValueTemplateItem', description: spec.description || template.description, title: spec.title || template.title, subtitle: spec.subtitle, icon: spec.icon || template.icon, initialDocumentId: spec.initialDocumentId, parameters: spec.parameters, } } /** Clone generic view builder (allows for options overriding) * @param withSpec - initial value template item builder options. See {@link InitialValueTemplateItemBuilder} * @returns initial value template item builder based on the context and options provided. See {@link InitialValueTemplateItemBuilder} */ clone(withSpec: Partial<InitialValueTemplateItem> = {}): InitialValueTemplateItemBuilder { const builder = new InitialValueTemplateItemBuilder(this._context) builder.spec = {...this.spec, ...withSpec} return builder } } /** @internal */ export function defaultInitialValueTemplateItems( context: StructureContext, ): InitialValueTemplateItemBuilder[] { const {schema, getStructureBuilder, templates} = context // Sort templates by their schema type, in order or definition const typeNames = schema.getTypeNames() const ordered = templates // Don't list templates that require parameters // TODO: this should use the new-document template items instead maybe? .filter((tpl) => !tpl.parameters?.length) .sort((a, b) => typeNames.indexOf(a.schemaType) - typeNames.indexOf(b.schemaType)) // Create actual template items out of the templates return ordered.map((tpl) => getStructureBuilder().initialValueTemplateItem(tpl.id)) } /** @internal */ export function maybeSerializeInitialValueTemplateItem( item: InitialValueTemplateItem | InitialValueTemplateItemBuilder, index: number, path: SerializePath, ): InitialValueTemplateItem { return item instanceof InitialValueTemplateItemBuilder ? item.serialize({path, index}) : item } /** @internal */ export function menuItemsFromInitialValueTemplateItems( context: StructureContext, templateItems: InitialValueTemplateItem[], ): MenuItem[] { const {schema, templates} = context return templateItems.map((item) => { const template = templates.find((t) => t.id === item.templateId) const title = item.title || template?.title || 'Create' const params: BaseIntentParams = {} if (template && template.schemaType) { params.type = template.schemaType } if (item.templateId) { params.template = item.templateId } const intentParams: IntentParams = item.parameters ? [params, item.parameters] : params const schemaType = template && schema.get(template.schemaType) const i18n = item.i18n || template?.i18n let builder = new MenuItemBuilder(context) .title(title) .icon((template && template.icon) || schemaType?.icon || AddIcon) .intent({type: 'create', params: intentParams}) if (i18n) { builder = builder.i18n(i18n) } return builder.serialize() }) }