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

332 lines (297 loc) • 10.7 kB
import {type I18nTextRecord, type InitialValueTemplateItem, type PreviewLayoutKey} from 'sanity' import { type InitialValueTemplateItemBuilder, maybeSerializeInitialValueTemplateItem, } from './InitialValueTemplateItem' import {defaultIntentChecker, type IntentChecker} from './Intent' import {layoutOptions} from './Layout' import {maybeSerializeMenuItem, type MenuItem, type MenuItemBuilder} from './MenuItem' import { maybeSerializeMenuItemGroup, type MenuItemGroup, type MenuItemGroupBuilder, } from './MenuItemGroup' import {SerializeError} from './SerializeError' import { type Child, type Serializable, type SerializeOptions, type StructureNode, } from './StructureNodes' import {getStructureNodeId} from './util/getStructureNodeId' import {validateId} from './util/validateId' function noChildResolver() { return undefined } /** @internal */ export const shallowIntentChecker: IntentChecker = (intentName, params, {pane, index}): boolean => { return index <= 1 && defaultIntentChecker(intentName, params, {pane, index}) } /** * Interface for list display options * * @public */ export interface ListDisplayOptions { /** Check if list display should show icons */ showIcons?: boolean } /** * Interface for base generic list * * @public */ export interface BaseGenericList extends StructureNode { /** List layout key. */ defaultLayout?: PreviewLayoutKey /** Can handle intent. See {@link IntentChecker} */ canHandleIntent?: IntentChecker /** List display options. See {@link ListDisplayOptions} */ displayOptions?: ListDisplayOptions /** List child. See {@link Child} */ child: Child /** List initial values array. See {@link InitialValueTemplateItem} and {@link InitialValueTemplateItemBuilder} */ initialValueTemplates?: (InitialValueTemplateItem | InitialValueTemplateItemBuilder)[] } /** * Interface for generic list * * @public */ // "POJO"/verbatim-version - end result export interface GenericList extends BaseGenericList { /** List type */ type: string /** List menu items array. See {@link MenuItem} */ menuItems: MenuItem[] /** List menu item groups array. See {@link MenuItemGroup} */ menuItemGroups: MenuItemGroup[] } /** * Interface for buildable generic list * * @public */ // Used internally in builder classes to make everything optional export interface BuildableGenericList extends Partial<BaseGenericList> { /** List menu items array. See {@link MenuItem} and {@link MenuItemBuilder} */ menuItems?: (MenuItem | MenuItemBuilder)[] /** List menu items groups array. See {@link MenuItemGroup} and {@link MenuItemGroupBuilder} */ menuItemGroups?: (MenuItemGroup | MenuItemGroupBuilder)[] } /** * Interface for generic list input * Allows builders and only requires things not inferrable * * @public */ // Input version, allows builders and only requires things not inferrable export interface GenericListInput extends StructureNode { /** Input id */ id: string /** Input title */ title: string /** Input menu items groups. See {@link MenuItem} and {@link MenuItemBuilder} */ menuItems?: (MenuItem | MenuItemBuilder)[] /** Input menu items groups. See {@link MenuItemGroup} and {@link MenuItemGroupBuilder} */ menuItemGroups?: (MenuItemGroup | MenuItemGroupBuilder)[] /** Input initial value array. See {@link InitialValueTemplateItem} and {@link InitialValueTemplateItemBuilder} */ initialValueTemplates?: (InitialValueTemplateItem | InitialValueTemplateItemBuilder)[] /** Input default layout. */ defaultLayout?: PreviewLayoutKey /** If input can handle intent. See {@link IntentChecker} */ canHandleIntent?: IntentChecker /** Input child of type {@link Child} */ child?: Child } /** * Class for building generic lists * * @public */ export abstract class GenericListBuilder<TList extends BuildableGenericList, ConcreteImpl> implements Serializable<GenericList> { /** Check if initial value templates are set */ protected initialValueTemplatesSpecified = false /** Generic list option object */ protected spec: TList = {} as TList /** Set generic list ID * @param id - generic list ID * @returns generic list builder based on ID provided. */ id(id: string): ConcreteImpl { return this.clone({id}) } /** Get generic list ID * @returns generic list ID */ getId(): TList['id'] { return this.spec.id } /** Set generic list title * @param title - generic list title * @returns generic list builder based on title and ID provided. */ title(title: string): ConcreteImpl { return this.clone({title, id: getStructureNodeId(title, this.spec.id)}) } /** Get generic list title * @returns generic list title */ getTitle(): TList['title'] { return this.spec.title } /** Set the i18n key and namespace used to populate the localized title. * @param i18n - the key and namespaced used to populate the localized title. * @returns component builder based on i18n key and ns provided */ i18n(i18n: I18nTextRecord<'title'>): ConcreteImpl { return this.clone({i18n}) } /** Get i18n key and namespace used to populate the localized title * @returns the i18n key and namespace used to populate the localized title */ getI18n(): TList['i18n'] { return this.spec.i18n } /** Set generic list layout * @param defaultLayout - generic list layout key. * @returns generic list builder based on layout provided. */ defaultLayout(defaultLayout: PreviewLayoutKey): ConcreteImpl { return this.clone({defaultLayout}) } /** Get generic list layout * @returns generic list layout */ getDefaultLayout(): TList['defaultLayout'] { return this.spec.defaultLayout } /** Set generic list menu items * @param menuItems - generic list menu items. See {@link MenuItem} and {@link MenuItemBuilder} * @returns generic list builder based on menu items provided. */ menuItems(menuItems: (MenuItem | MenuItemBuilder)[] | undefined): ConcreteImpl { return this.clone({menuItems}) } /** Get generic list menu items * @returns generic list menu items */ getMenuItems(): TList['menuItems'] { return this.spec.menuItems } /** Set generic list menu item groups * @param menuItemGroups - generic list menu item groups. See {@link MenuItemGroup} and {@link MenuItemGroupBuilder} * @returns generic list builder based on menu item groups provided. */ menuItemGroups(menuItemGroups: (MenuItemGroup | MenuItemGroupBuilder)[]): ConcreteImpl { return this.clone({menuItemGroups}) } /** Get generic list menu item groups * @returns generic list menu item groups */ getMenuItemGroups(): TList['menuItemGroups'] { return this.spec.menuItemGroups } /** Set generic list child * @param child - generic list child. See {@link Child} * @returns generic list builder based on child provided (clone). */ child(child: Child): ConcreteImpl { return this.clone({child}) } /** Get generic list child * @returns generic list child */ getChild(): TList['child'] { return this.spec.child } /** Set generic list can handle intent * @param canHandleIntent - generic list intent checker. See {@link IntentChecker} * @returns generic list builder based on can handle intent provided. */ canHandleIntent(canHandleIntent?: IntentChecker): ConcreteImpl { return this.clone({canHandleIntent}) } /** Get generic list can handle intent * @returns generic list can handle intent */ getCanHandleIntent(): TList['canHandleIntent'] { return this.spec.canHandleIntent } /** Set generic list display options * @param enabled - allow / disallow for showing icons * @returns generic list builder based on display options (showIcons) provided. */ showIcons(enabled = true): ConcreteImpl { return this.clone({ displayOptions: {...(this.spec.displayOptions || {}), showIcons: enabled}, }) } /** Get generic list display options * @returns generic list display options (specifically showIcons) */ getShowIcons(): boolean | undefined { return this.spec.displayOptions ? this.spec.displayOptions.showIcons : undefined } /** Set generic list initial value templates * @param templates - generic list initial value templates. See {@link InitialValueTemplateItemBuilder} * @returns generic list builder based on templates provided. */ initialValueTemplates( templates: | InitialValueTemplateItem | InitialValueTemplateItemBuilder | Array<InitialValueTemplateItem | InitialValueTemplateItemBuilder>, ): ConcreteImpl { this.initialValueTemplatesSpecified = true return this.clone({initialValueTemplates: Array.isArray(templates) ? templates : [templates]}) } /** Get generic list initial value templates * @returns generic list initial value templates */ getInitialValueTemplates(): TList['initialValueTemplates'] { return this.spec.initialValueTemplates } /** Serialize generic list * @param options - serialization options. See {@link SerializeOptions} * @returns generic list object based on path provided in options. See {@link GenericList} */ serialize(options: SerializeOptions = {path: []}): GenericList { const id = this.spec.id || '' const path = options.path const defaultLayout = this.spec.defaultLayout if (defaultLayout && !layoutOptions.includes(defaultLayout)) { throw new SerializeError( `\`layout\` must be one of ${layoutOptions.map((item) => `"${item}"`).join(', ')}`, path, id || options.index, this.spec.title, ) } const initialValueTemplates = (this.spec.initialValueTemplates || []).map((item, i) => maybeSerializeInitialValueTemplateItem(item, i, path), ) return { id: validateId(id, options.path, id || options.index), title: this.spec.title, i18n: this.spec.i18n, type: 'genericList', defaultLayout, child: this.spec.child || noChildResolver, canHandleIntent: this.spec.canHandleIntent || shallowIntentChecker, displayOptions: this.spec.displayOptions, initialValueTemplates, menuItems: (this.spec.menuItems || []).map((item, i) => maybeSerializeMenuItem(item, i, path), ), menuItemGroups: (this.spec.menuItemGroups || []).map((item, i) => maybeSerializeMenuItemGroup(item, i, path), ), } } /** Clone generic list builder (allows for options overriding) * @param _withSpec - generic list options. * @returns generic list builder. */ abstract clone(_withSpec?: object): ConcreteImpl }