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

377 lines (346 loc) 9.67 kB
import {type SchemaType} from '@sanity/types' import {type Observable} from 'rxjs' import { type ConfigContext, type DocumentFieldActionNode, type DocumentStore, type GeneralPreviewLayoutKey, type I18nTextRecord, type InitialValueTemplateItem, type LocaleSource, } from 'sanity' import { type DefaultDocumentNodeResolver, type Intent, type MenuItem as StructureToolMenuItem, type StructureBuilder, type StructureContext, type UserComponent, type View, } from './structureBuilder' /** @internal */ export interface StructureToolFeatures { /** * @hidden * @beta */ backButton: boolean resizablePanes: boolean reviewChanges: boolean splitPanes: boolean splitViews: boolean } /** @internal */ export interface StructureToolContextValue { features: StructureToolFeatures layoutCollapsed: boolean setLayoutCollapsed: (layoutCollapsed: boolean) => void rootPaneNode: UnresolvedPaneNode structureContext: StructureContext } /** * Structure tool context. Extends from {@link ConfigContext}. * @hidden * @public */ export interface StructureResolverContext extends ConfigContext { /** * This can be replaced by a different API in the future. * It is provided as-is to support common structure patterns found in V2 in V3. * @alpha * */ documentStore: DocumentStore /** @alpha */ i18n: LocaleSource } /** * Lets you configure how lists, documents, views, menus, and initial value templates are organized in the Sanity Studio’s structure-tool. * * @public * * @returns A structure builder, or null/undefined if no structure should be returned. See {@link StructureBuilder} * @example Configuring structure * ```ts * // sanity.config.js * * import {defineConfig} from 'sanity' * import {structureTool} from 'sanity/structure' * import {schemaTypes} from './schema' * * export default defineConfig({ * name: 'default', * title: 'My Cool Project', * projectId: 'my-project-id', * dataset: 'production', * plugins: [ * structureTool({ * structure: (S, context) => { * console.log(context) // returns { currentUser, dataset, projectId, schema, getClient, documentStore } * return S.documentTypeList('post') * }, * }) * ], * schema: schemaTypes * }) * ``` * */ export type StructureResolver = ( /** * S - An instance of the structure builder, that can be used to build the lists/items/panes for the structure tool * context - an object holding various context that may be used to customize the structure, for instance the current user. * Defaults to * ```ts * (S) => S.defaults() * ``` * See {@link StructureBuilder} */ S: StructureBuilder, /** * An object containing pane and index information for the current structure tool. * See {@link StructureResolverContext} */ context: StructureResolverContext, ) => unknown /** @internal */ export type StructureToolPaneActionHandler = (params: any, scope?: unknown) => void /** * The params for the `structureTool` api. See {@link structureTool} * * @public */ export interface StructureToolOptions { /* * React icon component for the tool, used in navigation bar. Defaults to MasterDetailIcon from @sanity/icons */ icon?: React.ComponentType /* * The name you want this structure to have (among other places, this name is used in routing, * if name is set to “structure”, it is shown on /structure). Usually lowercase or camelcase by convention. Defaults to structure. */ name?: string /** * A workspace can have different "sources". These sources were meant to allow using multiple datasets within the same workspace, for instance. * This is not supported yet, but the API is still here. * @hidden @alpha */ source?: string /** * A structure resolver function. See {@link StructureResolver} */ structure?: StructureResolver /** * A resolver function used to return the default document node used when editing documents. See {@link DefaultDocumentNodeResolver} */ defaultDocumentNode?: DefaultDocumentNodeResolver /** * The title that will be displayed for the tool. Defaults to Structure */ title?: string } /** * Represents the state of the `panes` inside the structure-tool router * * - The structure tool stores the state of the current panes inside of the router. * - The panes are stored in groups delimited in the URL by `;`. * - In each group, there can be one or more sibling (aka split) panes delimited * by `|`. * - Each item pane can contain it's own parameters and payloads * - Per item pane in each group, if not specified separately, the ID, params, * and payload will be inherited from the first item pane in the pane group * (unless it's an `exclusiveParam`) * * E.g. `/structure/books;book-123|,view=preview` will parse to: * * ```js * [ * // first pane group * [{id: 'book'}], * * // second pane group * [ * [ * // first pane item * {id: 'book-123'}, * // second pane item * {id: 'book-123', params: {view: 'preview'}}, * ], * ], * ] * ``` * * @hidden * @beta */ export type RouterPanes = RouterPaneGroup[] /** * Represents a "pane group" in the router. * * @see RouterPanes * * * @hidden * @beta */ export type RouterPaneGroup = RouterPaneSibling[] /** * Represents a "sibling pane" or "split pane" in the router. * * @see RouterPanes * * * @hidden * @beta */ export interface RouterPaneSibling { id: string params?: Record<string, string | undefined> payload?: unknown } // TODO: unify this with the structure builder ChildResolver type /** * Passed as the second argument to the item of resolving pane children * * @see RouterPanes * * @internal */ export interface RouterPaneSiblingContext { id: string parent: PaneNode | null index: number splitIndex: number path: string[] params: Record<string, string | undefined> payload: unknown structureContext: StructureContext // used in structure builder serializeOptions?: { path: (string | number)[] index?: number hint?: string } } /** @internal */ export {type StructureToolMenuItem} /** * Represents what can be passed into `menuItems` inside of structure-tool panes * * @see BaseResolvedPaneNode * * @internal */ export interface PaneMenuItem extends StructureToolMenuItem { // TODO: these would be great options in the `MenuItemBuilder` // currently, they are only used in the `DocumentPaneProvider` isDisabled?: boolean shortcut?: string selected?: boolean tone?: 'primary' | 'positive' | 'caution' | 'critical' } /** @internal */ export interface PaneMenuItemGroup { id: string title?: string i18n?: I18nTextRecord<'title'> } /** @internal */ export interface BaseResolvedPaneNode<T extends PaneNode['type']> { id: string type: T title: string i18n?: I18nTextRecord<'title'> menuItems?: PaneMenuItem[] menuItemGroups?: PaneMenuItemGroup[] canHandleIntent?: ( intentName: string, params: Record<string, string | undefined>, options: {pane: PaneNode; index: number}, ) => boolean child?: UnresolvedPaneNode } /** @internal */ export interface CustomComponentPaneNode extends BaseResolvedPaneNode<'component'> { component: UserComponent options?: Record<string, unknown> // component: React.ComponentType<Props> | React.ReactNode } /** @internal */ export interface DocumentPaneNode extends BaseResolvedPaneNode<'document'> { options: { id: string type: string template?: string templateParameters?: Record<string, unknown> } source?: string views?: View[] } /** @internal */ export interface DocumentListPaneNode extends BaseResolvedPaneNode<'documentList'> { defaultLayout?: GeneralPreviewLayoutKey displayOptions?: {showIcons?: boolean} initialValueTemplates?: InitialValueTemplateItem[] options: { filter: string defaultOrdering?: Array<{field: string; direction: 'asc' | 'desc'}> params?: Record<string, unknown> apiVersion?: string } schemaTypeName: string source?: string } /** @internal */ export interface PaneListItem<TParams = unknown> { type: 'listItem' id: string // these are specific to `DocumentListItem` _id?: string schemaType?: SchemaType title: string i18n?: I18nTextRecord<'title'> icon?: React.ComponentType | false displayOptions?: {showIcon?: boolean} action?: (t: TParams) => unknown params?: TParams } /** @internal */ export interface PaneListItemDivider { type: 'divider' } /** @internal */ export interface ListPaneNode extends BaseResolvedPaneNode<'list'> { defaultLayout?: GeneralPreviewLayoutKey displayOptions?: {showIcons?: boolean} items?: Array<PaneListItem | PaneListItemDivider> // TODO: mark as unstable or remove source?: string } /** @internal */ export type PaneNode = | CustomComponentPaneNode | DocumentPaneNode | DocumentListPaneNode | ListPaneNode /** @internal */ export type SerializablePaneNode = { // TODO: unify this context with `SerializeOptions` serialize(context: RouterPaneSiblingContext): UnresolvedPaneNode } /** @internal */ export type PaneNodeResolver = (id: string, context: RouterPaneSiblingContext) => UnresolvedPaneNode // TODO: these types need to be unified with the buidlers `ListBuilder /** @internal */ export type UnresolvedPaneNode = | PaneNodeResolver | SerializablePaneNode | Observable<UnresolvedPaneNode> | PromiseLike<UnresolvedPaneNode> | PaneNode /** * @hidden * @beta */ export type DocumentFieldMenuActionNode = DocumentFieldActionNode & { intent?: Intent }