UNPKG

@sanity/types

Version:

Type definitions for common Sanity data structures

1,747 lines 112 kB
import { ComponentType, ElementType, ReactNode } from "react"; import { ClientPerspective, SanityClient, StackablePerspective } from "@sanity/client"; import { Asset as Asset$1, AssetInstanceDocument } from "@sanity/media-library-types"; /** @public */ interface SanityDocument { _id: string; _type: string; _createdAt: string; _updatedAt: string; _rev: string; [key: string]: unknown; } /** * Similar to `SanityDocument` but only requires the `_id` and `_type` * * @see SanityDocument * * @public */ interface SanityDocumentLike { _id: string; _type: string; _createdAt?: string; _updatedAt?: string; _rev?: string; _system?: { delete?: boolean; }; [key: string]: unknown; } /** @public */ interface TypedObject { [key: string]: unknown; _type: string; } /** @public */ interface KeyedObject { [key: string]: unknown; _key: string; } /** * @internal */ interface DocumentSystemRef { _ref: string; _weak: true; } /** * @internal */ interface DocumentSystem { /** * It will be empty for the group document (aka published document) */ bundleId?: 'drafts' | (string & {}); /** * A weak reference to the release document that the version belongs to. */ release?: DocumentSystemRef; /** * A weak reference to the variant document that the version belongs to. */ variant?: DocumentSystemRef; /** * A weak reference to the group document (aka published document). */ group: DocumentSystemRef; /** * Available only for version documents. */ scopeId?: string; } /** * @internal */ interface StrictVersionLayeringOptions { /** * By default, version layering includes all document versions, regardless of their expected * publication time—or lack thereof. For example, it includes all ASAP and undecided versions, * despite ASAP and undecided versions having no fixed chronology. There is no way to determine * which ASAP or undecided version is expected to be published before another. * * It also includes any existing draft, which has no fixed chronology, either. * * This functionality is useful for listing all document versions in a deterministic order, but * doesn't accurately portray the upstream and downstream versions based on expected publication * time. * * In strict mode, version layering instead only includes versions that have a fixed chronology. * **Cross-version layering is only effective for scheduled versions, with all other * versions being layered directly onto the published version (if it exists).** */ strict?: boolean; } /** @public */ declare function isSanityDocument(document: unknown): document is SanityDocument; /** @public */ declare function isTypedObject(obj: unknown): obj is TypedObject; /** @public */ declare function isKeyedObject(obj: unknown): obj is KeyedObject; /** @public */ type KeyedSegment = { _key: string; }; /** @public */ type IndexTuple = [number | '', number | '']; /** @public */ type PathSegment = string | number | KeyedSegment | IndexTuple; /** @public */ type Path = PathSegment[]; /** @internal */ declare function isIndexSegment(segment: PathSegment): segment is number; /** @internal */ declare function isKeySegment(segment: PathSegment): segment is KeyedSegment; /** @internal */ declare function isIndexTuple(segment: PathSegment): segment is IndexTuple; /** @beta */ interface CrossDatasetReferenceValue { _type: string; _dataset: string; _projectId: string; _ref: string; _key?: string; _weak?: boolean; } /** @beta */ interface WeakCrossDatasetReferenceValue extends CrossDatasetReferenceValue { _weak: true; } /** @beta */ type CrossDatasetReferenceFilterSearchOptions = { filter?: string; params?: Record<string, unknown>; tag?: string; }; /** @beta */ type CrossDatasetReferenceFilterResolver = (options: { document: SanityDocument; parent?: Record<string, unknown> | Record<string, unknown>[]; parentPath: Path; }) => CrossDatasetReferenceFilterSearchOptions | Promise<CrossDatasetReferenceFilterSearchOptions>; /** @beta */ interface CrossDatasetType { type: string; title?: string; icon: ComponentType; preview: PreviewConfig; /** @deprecated Unused. Configuring search is no longer supported for cross-dataset references. */ __experimental_search?: ObjectSchemaType['__experimental_search']; } /** @beta */ interface CrossDatasetReferenceSchemaType extends Omit<ObjectSchemaType, 'options'> { jsonType: 'object'; to: CrossDatasetType[]; dataset: string; studioUrl?: (document: { id: string; type?: string; }) => string | null; weak?: boolean; options?: ReferenceFilterOptions; } /** @beta */ declare function isCrossDatasetReference(reference: unknown): reference is CrossDatasetReferenceValue; /** @public */ interface Role { name: string; title: string; description?: string; } /** @public */ type UserAttributeType = 'string' | 'string-array' | 'integer' | 'integer-array' | 'number' | 'number-array' | 'boolean'; type UserAttributeValueByType = { 'string': string; 'string-array': string[]; 'integer': number; 'integer-array': number[]; 'number': number; 'number-array': number[]; 'boolean': boolean; }; /** @public */ type UserAttributeValue = UserAttributeValueByType[UserAttributeType]; /** @public */ type CurrentUserAttribute = { [T in UserAttributeType]: { key: string; type: T; value: UserAttributeValueByType[T]; } }[UserAttributeType]; /** @public */ interface CurrentUser { id: string; name: string; email: string; profileImage?: string; provider?: string; /** @deprecated use `roles` instead */ role: string; roles: Role[]; /** * Organization-scoped user attributes for the current project. * Only present when returned by `/users/me` with a project context. */ attributes?: CurrentUserAttribute[]; } /** @public */ interface User { id: string; displayName?: string; imageUrl?: string; email?: string; } /** @public */ interface ValidationMarker { level: 'error' | 'warning' | 'info'; /** * The validation message for this marker. E.g. "Must be greater than 0" */ message: string; /** * @deprecated use `message` instead */ item?: ValidationError; /** * The sanity path _relative to the root of the current document_ to this * marker. * * NOTE: Sanity paths may contain keyed segments (i.e. `{_key: string}`) that * are not compatible with deep getters like lodash/get */ path: Path; /** * Extra metadata for the validation marker. Currently used by the Media Library asset source to ignore * certain validation markers when validating asset source media library assets. * * @internal */ __internal_metadata?: unknown; } /** @internal */ declare function isValidationErrorMarker(marker: ValidationMarker): marker is ValidationMarker & { level: 'error'; }; /** @internal */ declare function isValidationWarningMarker(marker: ValidationMarker): marker is ValidationMarker & { level: 'warning'; }; /** @internal */ declare function isValidationInfoMarker(marker: ValidationMarker): marker is ValidationMarker & { level: 'info'; }; /** * A slug object, currently holding a `current` property * * In the future, this may be extended with a `history` property * * @public */ interface Slug { _type: 'slug'; current: string; } /** @public */ type SlugParent = Record<string, unknown> | Record<string, unknown>[]; /** @public */ interface SlugSourceContext { parentPath: Path; parent: SlugParent; projectId: string; dataset: string; schema: Schema; currentUser: CurrentUser | null; getClient: (options: { apiVersion: string; }) => SanityClient; } /** @public */ type SlugSourceFn = (document: SanityDocument, context: SlugSourceContext) => string | Promise<string>; /** @public */ type SlugifierFn = (source: string, schemaType: SlugSchemaType, context: SlugSourceContext) => string | Promise<string>; /** * Checks whether the given `thing` is a slug, eg an object with a `current` string property. * * @param thing - The thing to check * @returns True if slug, false otherwise * @public */ declare function isSlug(thing: unknown): thing is Slug; /** @public */ type RuleTypeConstraint = 'Array' | 'Boolean' | 'Date' | 'Number' | 'Object' | 'String'; /** @public */ type FieldRules = { [fieldKey: string]: SchemaValidationValue; }; /** * Holds localized validation messages for a given field. * * @example Custom message for English (US) and Norwegian (Bokmål): * ``` * { * 'en-US': 'Needs to start with a capital letter', * 'no-NB': 'Må starte med stor bokstav', * } * ``` * @public */ interface LocalizedValidationMessages { [locale: string]: string; } /** * Note: `RuleClass` and `Rule` are split to fit the current `@sanity/types` * setup. Classes are a bit weird in the `@sanity/types` package because classes * create an actual javascript class while simultaneously creating a type * definition. * * This implicitly creates two types: * 1. the instance type — `Rule` and * 2. the static/class type - `RuleClass` * * The `RuleClass` type contains the static methods and the `Rule` instance * contains the instance methods. Downstream in the validation package, the Rule * implementation asserts the class declaration is of this type. * * @internal */ interface RuleClass { FIELD_REF: symbol; array: (def?: SchemaType) => Rule; object: (def?: SchemaType) => Rule; string: (def?: SchemaType) => Rule; number: (def?: SchemaType) => Rule; boolean: (def?: SchemaType) => Rule; dateTime: (def?: SchemaType) => Rule; valueOfField: Rule['valueOfField']; new (typeDef?: SchemaType): Rule; } /** * Holds a reference to a different field * NOTE: Only use this through {@link Rule.valueOfField} * * @public */ interface FieldReference { type: symbol; path: string | string[]; } /** @public */ interface UriValidationOptions { scheme?: (string | RegExp) | Array<string | RegExp>; allowRelative?: boolean; relativeOnly?: boolean; allowCredentials?: boolean; } /** @public */ interface Rule { /** * @internal * @deprecated internal use only */ _type: RuleTypeConstraint | undefined; /** * @internal * @deprecated internal use only */ _level: 'error' | 'warning' | 'info' | undefined; /** * @internal * @deprecated internal use only */ _required: 'required' | 'optional' | undefined; /** * @internal * @deprecated internal use only */ _typeDef: SchemaType | undefined; /** * @internal * @deprecated internal use only */ _message: string | LocalizedValidationMessages | undefined; /** * @internal * @deprecated internal use only */ _rules: RuleSpec[]; /** * @internal * @deprecated internal use only */ _fieldRules: FieldRules | undefined; /** * Takes in a path and returns an object with a symbol. * * When the validation lib sees this symbol, it will use the provided path to * get a value from the current field's parent and use that value as the input * to the Rule. * * The path that's given is forwarded to `lodash/get` * * ```js * fields: [ * // ... * { * // ... * name: 'highestTemperature', * type: 'number', * validation: (Rule) => Rule.positive().min(Rule.valueOfField('lowestTemperature')), * // ... * }, * ] * ``` */ valueOfField: (path: string | string[]) => FieldReference; error(message?: string | LocalizedValidationMessages): Rule; warning(message?: string | LocalizedValidationMessages): Rule; info(message?: string | LocalizedValidationMessages): Rule; reset(): this; isRequired(): boolean; clone(): Rule; cloneWithRules(rules: RuleSpec[]): Rule; merge(rule: Rule): Rule; type(targetType: RuleTypeConstraint | Lowercase<RuleTypeConstraint>): Rule; all(children: Rule[]): Rule; either(children: Rule[]): Rule; optional(): Rule; required(): Rule; skip(): Rule; custom<T = unknown>(fn: CustomValidator<T>, options?: { bypassConcurrencyLimit?: boolean; }): Rule; media<T extends MediaAssetTypes = MediaAssetTypes>(fn: MediaValidator<T>): Rule; min(len: number | string | FieldReference): Rule; max(len: number | string | FieldReference): Rule; length(len: number | FieldReference): Rule; valid(value: unknown | unknown[]): Rule; integer(): Rule; precision(limit: number | FieldReference): Rule; positive(): Rule; negative(): Rule; greaterThan(num: number | FieldReference): Rule; lessThan(num: number | FieldReference): Rule; uppercase(): Rule; lowercase(): Rule; regex(pattern: RegExp, name: string, options: { name?: string; invert?: boolean; }): Rule; regex(pattern: RegExp, options: { name?: string; invert?: boolean; }): Rule; regex(pattern: RegExp, name: string): Rule; regex(pattern: RegExp): Rule; email(): Rule; uri(options?: UriValidationOptions): Rule; unique(): Rule; reference(): Rule; fields(rules: FieldRules): Rule; assetRequired(): Rule; validate(value: unknown, options: ValidationContext & { /** * @deprecated Internal use only * @internal */ __internal?: { customValidationConcurrencyLimiter?: { ready: () => Promise<void>; release: () => void; }; }; }): Promise<ValidationMarker[]>; } /** @public */ type RuleSpec = { flag: 'integer'; } | { flag: 'email'; } | { flag: 'unique'; } | { flag: 'reference'; } | { flag: 'type'; constraint: RuleTypeConstraint; } | { flag: 'all'; constraint: Rule[]; } | { flag: 'either'; constraint: Rule[]; } | { flag: 'presence'; constraint: 'optional' | 'required'; } | { flag: 'custom'; constraint: CustomValidator; } | { flag: 'min'; constraint: number | string | FieldReference; } | { flag: 'max'; constraint: number | string | FieldReference; } | { flag: 'length'; constraint: number | FieldReference; } | { flag: 'valid'; constraint: unknown[]; } | { flag: 'precision'; constraint: number | FieldReference; } | { flag: 'lessThan'; constraint: number | FieldReference; } | { flag: 'greaterThan'; constraint: number | FieldReference; } | { flag: 'stringCasing'; constraint: 'uppercase' | 'lowercase'; } | { flag: 'assetRequired'; constraint: { assetType: 'asset' | 'image' | 'file'; }; } | { flag: 'media'; constraint: MediaValidator<any>; } | { flag: 'regex'; constraint: { pattern: RegExp; name?: string; invert: boolean; }; } | { flag: 'uri'; constraint: { options: { scheme: RegExp[]; allowRelative: boolean; relativeOnly: boolean; allowCredentials: boolean; }; }; }; /** * this is used to get allow index access (e.g. `RuleSpec['constraint']`) to * constraint when a rule spec might not have a `constraint` prop * * @internal */ type ConditionalIndexAccess<T, U> = U extends keyof T ? T[U] : undefined; /** @internal */ type RuleSpecConstraint<T extends RuleSpec['flag']> = ConditionalIndexAccess<Extract<RuleSpec, { flag: T; }>, 'constraint'>; /** * A context object passed around during validation. This includes the * `Rule.custom` context. * * e.g. * * ```js * Rule.custom((_, validationContext) => { * // ... * })` * ``` * * @public */ interface ValidationContext { getClient: (options: { apiVersion: string; }) => SanityClient; schema: Schema; parent?: unknown; type?: SchemaType; document?: SanityDocument; path?: Path; getDocumentExists?: (options: { id: string; }) => Promise<boolean>; environment: 'cli' | 'studio'; /** * Whether this field is hidden for any reason (either itself or any of its ancestors). */ hidden?: boolean; } /** * The base type for all validators in the validation library. Takes in a * `RuleSpec`'s constraint, the value to check, an optional override message, * and the validation context. * * @see Rule.validate from `sanity/src/core/validation/Rule` * * @internal */ type Validator<T = any, Value = any> = (constraint: T, value: Value, message: string | undefined, context: ValidationContext) => ValidationError[] | ValidationError | string | true | Promise<ValidationError[] | ValidationError | string | true>; /** * A type helper used to define a group of validators. The type of the * `RuleSpec` constraint is inferred via the key. * * E.g. * * ```ts * const booleanValidators: Validators = { * ...genericValidator, * * presence: (v, value, message) => { * if (v === 'required' && typeof value !== 'boolean') return message || 'Required' * return true * }, * } * ``` * * @internal */ type Validators = Partial<{ [P in RuleSpec['flag']]: Validator<Exclude<ConditionalIndexAccess<Extract<RuleSpec, { flag: P; }>, 'constraint'>, FieldReference>> }>; /** @internal */ interface ValidationErrorOptions { paths?: Path[]; children?: ValidationMarker[]; operation?: 'AND' | 'OR'; } /** * This follows the same pattern as `RuleClass` and `Rule` above * Note: this class does not actually extend `Error` since it's never thrown * within the validation library * * @deprecated It is preferred to a plain object that adheres to `ValidationError` * @internal */ interface ValidationErrorClass { new (message: string, options?: ValidationErrorOptions): ValidationError; } /** * The shape that can be returned from a custom validator to be converted into * a validation marker by the validation logic. Inside of a custom validator, * you can return an array of these in order to specify multiple paths within * an object or array. * * @public */ interface ValidationError { /** * The message describing why the value is not valid. This message will be * included in the validation markers after validation has finished running. */ message: string; /** * If writing a custom validator, you can return validation messages to * specific path inside of the current value (object or array) by populating * this `path` prop. * * NOTE: This path is relative to the current value and _not_ relative to * the document. */ path?: Path; /** * Extra metadata for the validation error. Currently used by the Media Library asset source to ignore * certain validation markers when validating asset source media library assets. * * @internal */ __internal_metadata?: unknown; /** * Same as `path` but allows more than one value. If provided, the same * message will create two markers from each path with the same message * provided. * * @deprecated prefer `path` */ paths?: Path[]; /** * @deprecated Unused. Was used to store the results from `.either()` /`.all()` */ children?: ValidationMarker[]; /** * @deprecated Unused. Was used to signal if this error came from an `.either()`/`.all()`. */ operation?: 'AND' | 'OR'; /** * @deprecated Unused. Was relevant when validation error was used as a class. */ cloneWithMessage?(message: string): ValidationError; } /** @public */ type CustomValidatorResult = true | string | ValidationError | ValidationError[] | LocalizedValidationMessages; /** @public */ interface CustomValidator<T = unknown> { (value: T, context: ValidationContext): CustomValidatorResult | Promise<CustomValidatorResult>; bypassConcurrencyLimit?: boolean; } /** @public */ type MediaAssetTypes = AssetInstanceDocument['_type']; /** @public */ interface MediaValidator<T extends MediaAssetTypes = MediaAssetTypes> { (value: MediaValidationValue<T>, context: ValidationContext): CustomValidatorResult | Promise<CustomValidatorResult>; } /** @public */ interface MediaValidationValue<T extends MediaAssetTypes = MediaAssetTypes> { /** * Media information */ media: { /** * The Media Library Asset. */ asset: Asset$1 & { currentVersion: Extract<AssetInstanceDocument, { _type: T; }>; }; }; /** * The field value which the media is used in. */ value: unknown; } /** @public */ interface SlugValidationContext extends ValidationContext { parent: SlugParent; type: SlugSchemaType; defaultIsUnique: SlugIsUniqueValidator; } /** @public */ type SlugIsUniqueValidator = (slug: string, context: SlugValidationContext) => boolean | Promise<boolean>; /** @public */ interface FormNodeValidation { level: 'error' | 'warning' | 'info'; message: string; path: Path; } /** @internal */ declare function isValidationError(node: FormNodeValidation): node is FormNodeValidation & { level: 'error'; }; /** @internal */ declare function isValidationWarning(node: FormNodeValidation): node is FormNodeValidation & { level: 'warning'; }; /** @internal */ declare function isValidationInfo(node: FormNodeValidation): node is FormNodeValidation & { level: 'info'; }; /** @alpha This API may change */ declare interface InsertMenuOptions { /** * @defaultValue `'auto'` * `filter: 'auto'` automatically turns on filtering if there are more than 5 * schema types added to the menu. */ filter?: "auto" | boolean | undefined; groups?: Array<{ name: string; title?: string; of?: Array<string>; }> | undefined; /** defaultValue `true` */ showIcons?: boolean | undefined; /** @defaultValue `[{name: 'list'}]` */ views?: Array<{ name: "list"; } | { name: "grid"; previewImageUrl?: (schemaTypeName: string) => string | undefined; }> | undefined; } /** @public */ interface RuleDef<T, FieldValue = unknown> { required: () => T; skip: () => T; custom: <LenientFieldValue extends FieldValue>(fn: CustomValidator<LenientFieldValue | undefined>) => T; info: (message?: string | LocalizedValidationMessages) => T; error: (message?: string | LocalizedValidationMessages) => T; warning: (message?: string | LocalizedValidationMessages) => T; valueOfField: (path: string | string[]) => FieldReference; } /** @public */ type RuleBuilder<T extends RuleDef<T, FieldValue>, FieldValue = unknown> = T | T[]; /** @public */ type ValidationBuilder<T extends RuleDef<T, FieldValue>, FieldValue = unknown> = (rule: T, context?: ValidationContext) => RuleBuilder<T, FieldValue>; /** @public */ interface ObjectOptions extends BaseSchemaTypeOptions { collapsible?: boolean; collapsed?: boolean; columns?: number; modal?: ModalOptions; } /** @public */ interface ObjectRule extends RuleDef<ObjectRule, Record<string, unknown>> {} /** @public */ interface ObjectDefinition extends BaseSchemaDefinition { type: 'object'; /** * Object must have at least one field. This is validated at Studio startup. */ fields: FieldDefinition[]; groups?: FieldGroupDefinition[]; fieldsets?: FieldsetDefinition[]; preview?: PreviewConfig; options?: ObjectOptions; validation?: ValidationBuilder<ObjectRule, Record<string, unknown>>; initialValue?: InitialValueProperty<any, Record<string, unknown>>; } /** @public */ interface FieldsetDefinition { name: string; title?: string; description?: string; group?: string; hidden?: ConditionalProperty; readOnly?: ConditionalProperty; options?: ObjectOptions; } /** @public */ type FieldGroupDefinition = { name: string; title?: string; hidden?: ConditionalProperty; icon?: ComponentType; default?: boolean; i18n?: I18nTextRecord<'title'>; }; /** * Options for configuring how Sanity Create interfaces with the type or field. * * @public */ interface SanityCreateOptions { /** Set to true to exclude a type or field from appearing in Sanity Create */ exclude?: boolean; /** * A short description of what the type or field is used for. * Purpose can be used to improve how and when content mapping uses the field. * */ purpose?: string; } /** * Options for configuring how Canvas app interfaces with the type or field. * * @public */ interface CanvasAppOptions { /** Set to true to exclude a type or field from appearing in Canvas */ exclude?: boolean; /** * A short description of what the type or field is used for. * Purpose can be used to improve how and when content mapping uses the field. * */ purpose?: string; } /** * `BaseOptions` applies to all type options. * * It can be extended by interface declaration merging in plugins to provide generic options to all types and fields. * * @public * */ interface BaseSchemaTypeOptions { sanityCreate?: SanityCreateOptions; canvasApp?: CanvasAppOptions; } /** @public */ interface BaseSchemaDefinition { name: string; title?: string; description?: string | React.JSX.Element; hidden?: ConditionalProperty; readOnly?: ConditionalProperty; icon?: ComponentType | ReactNode; validation?: unknown; initialValue?: unknown; deprecated?: DeprecatedProperty; } /** @public */ interface TitledListValue<V = unknown> { _key?: string; title: string; value?: V; } /** @public */ interface I18nTitledListValue<V = unknown> { _key?: string; title: string; i18nTitleKey?: string; value?: V; } /** @public */ interface EnumListProps<V = unknown> { list?: Array<TitledListValue<V> | V>; layout?: 'radio' | 'dropdown'; direction?: 'horizontal' | 'vertical'; } /** @public */ interface SearchConfiguration { search?: { /** * Defines a search weight for this field to prioritize its importance * during search operations in the Studio. This setting allows the specified * field to be ranked higher in search results compared to other fields. * * By default, all fields are assigned a weight of 1. However, if a field is * chosen as the `title` in the preview configuration's `select` option, it * will automatically receive a default weight of 10. Similarly, if selected * as the `subtitle`, the default weight is 5. Fields marked as * `hidden: true` (no function) are assigned a weight of 0 by default. * * Note: Search weight configuration is currently supported only for fields * of type string or portable text arrays. */ weight?: number; }; } /** * Types of array actions that can be performed * @beta */ type ArrayActionName = /** * Add any item to the array at any position */ 'add' /** * Add item after an existing item */ | 'addBefore' /** * Add item after an existing item */ | 'addAfter' /** * Remove any item */ | 'remove' /** * Duplicate item */ | 'duplicate' /** * Copy item */ | 'copy'; /** @public */ interface ArrayOptions<V = unknown> extends SearchConfiguration, BaseSchemaTypeOptions { list?: TitledListValue<V>[] | V[]; layout?: 'list' | 'tags' | 'grid'; /** @deprecated This option does not have any effect anymore */ direction?: 'horizontal' | 'vertical'; sortable?: boolean; modal?: ModalOptions; /** @alpha This API may change */ insertMenu?: InsertMenuOptions; /** * A boolean flag to enable or disable tree editing for the array. * If there are any nested arrays, they will inherit this value. * @deprecated tree editing beta feature has been disabled */ treeEditing?: boolean; /** * A list of array actions to disable * Possible options are defined by {@link ArrayActionName} * @beta */ disableActions?: ArrayActionName[]; } /** @public */ interface ArrayRule<Value> extends RuleDef<ArrayRule<Value>, Value> { min: (length: number | FieldReference) => ArrayRule<Value>; max: (length: number | FieldReference) => ArrayRule<Value>; length: (length: number | FieldReference) => ArrayRule<Value>; unique: () => ArrayRule<Value>; } /** @public */ type ArrayOfEntry<T> = Omit<T, 'name' | 'hidden'> & { name?: string; }; /** @public */ type IntrinsicArrayOfDefinition = { [K in keyof IntrinsicDefinitions]: Omit<ArrayOfEntry<IntrinsicDefinitions[K]>, 'validation' | 'initialValue'> & { validation?: SchemaValidationValue; initialValue?: InitialValueProperty<any, any>; } }; /** @public */ type ArrayOfType<TType extends IntrinsicTypeName = IntrinsicTypeName, TAlias extends IntrinsicTypeName | undefined = undefined> = IntrinsicArrayOfDefinition[TType] | ArrayOfEntry<TypeAliasDefinition<AutocompleteString, TAlias>>; /** @public */ interface ArrayDefinition extends BaseSchemaDefinition { type: 'array'; of: ArrayOfType[]; initialValue?: InitialValueProperty<any, unknown[]>; validation?: ValidationBuilder<ArrayRule<unknown[]>, unknown[]>; options?: ArrayOptions; } /** @public */ type PortableTextBlock = PortableTextTextBlock | PortableTextObject; /** @public */ interface PortableTextTextBlock<TChild = PortableTextSpan | PortableTextObject> { _type: string; _key: string; children: TChild[]; markDefs?: PortableTextObject[]; listItem?: string; style?: string; level?: number; } /** @public */ interface PortableTextObject { _type: string; _key: string; [other: string]: unknown; } /** @public */ interface PortableTextSpan { _key: string; _type: 'span'; text: string; marks?: string[]; } /** @public */ type PortableTextChild = PortableTextObject | PortableTextSpan; /** @public */ interface PortableTextListBlock extends PortableTextTextBlock { listItem: string; level: number; } /** * Assert that a given object is a portable-text text-block type object * * @remarks * * The `markDefs` and `style` property of a block is optional. * * Block types can be named, so expect anything of the _type property. * * @alpha */ declare function isPortableTextTextBlock<T = PortableTextSpan | PortableTextObject>(value: unknown): value is PortableTextTextBlock<T>; /** * Assert that a given object is a portable-text span-type object * * @remarks * The `marks` property of a block is optional. * * @alpha */ declare function isPortableTextSpan(value: unknown): value is PortableTextSpan; /** * Assert that a given object is a portable-text list-text-block-type object * * @remarks * Uses `isPortableTextTextBlock` and checks for `listItem` and `level` * * @see isPortableTextTextBlock * * @alpha */ declare function isPortableTextListBlock<T = PortableTextSpan | PortableTextObject>(value: unknown): value is PortableTextTextBlock<T>; /** * Schema options for a Block schema definition * @public */ interface BlockOptions extends BaseSchemaTypeOptions { /** * Turn on or off the builtin browser spellchecking. Default is on. */ spellCheck?: boolean; unstable_whitespaceOnPasteMode?: 'preserve' | 'normalize' | 'remove'; /** * When enabled, the editor will restrict all line breaks and soft breaks, * forcing content to remain on a single line. This will also update * the styling of the editor to reflect the single-line constraint. * * Pasting content that is on multiple lines will be normalized to a single line, if possible. * * @defaultValue false */ oneLine?: boolean; } /** @public */ interface BlockRule extends RuleDef<BlockRule, PortableTextBlock> {} /** * Schema definition for text block decorators. * * @public * @example The default set of decorators * ```ts * { * name: 'blockContent', * title: 'Content', * type: 'array', * of: [ * { * type: 'block', * marks: { * decorators: [ * {title: 'Strong', value: 'strong'}, * {title: 'Emphasis', value: 'em'}, * {title: 'Underline', value: 'underline'}, * {title: 'Strike', value: 'strike-through'}, * {title: 'Code', value: 'code'}, * ] * } * } * ] * } * ``` */ interface BlockDecoratorDefinition { title: string; i18nTitleKey?: string; value: string; icon?: ReactNode | ComponentType; } /** * Schema definition for a text block style. * A text block may have a block style like 'header', 'normal', 'lead' * attached to it, which is stored on the `.style` property for that block. * * @public * @remarks The first defined style will become the default style.´´ * @example The default set of styles * ```ts * { * name: 'blockContent', * title: 'Content', * type: 'array', * of: [ * { * type: 'block', * styles: [ * {title: 'Normal', value: 'normal'}, * {title: 'H1', value: 'h1'}, * {title: 'H2', value: 'h2'}, * {title: 'H3', value: 'h3'}, * {title: 'H4', value: 'h4'}, * {title: 'H5', value: 'h5'}, * {title: 'H6', value: 'h6'}, * {title: 'Quote', value: 'blockquote'} * ] * } * ] * } * ``` * @example Example of defining a block type with custom styles and render components. * ```ts * defineArrayMember({ * type: 'block', * styles: [ * { * title: 'Paragraph', * value: 'paragraph', * component: ParagraphStyle, * }, * { * title: 'Lead', * value: 'lead', * component: LeadStyle, * }, * { * title: 'Heading', * value: 'heading', * component: HeadingStyle, * }, * ], * }) * ``` */ interface BlockStyleDefinition { title: string; value: string; i18nTitleKey?: string; icon?: ReactNode | ComponentType; } /** * Schema definition for a text block list style. * * @public * @example The defaults lists * ```ts * { * name: 'blockContent', * title: 'Content', * type: 'array', * of: [ * { * type: 'block', * lists: [ * {title: 'Bullet', value: 'bullet'}, * {title: 'Number', value: 'number'}, * ] * } * ] * } * ``` */ interface BlockListDefinition { title: string; i18nTitleKey?: string; value: string; icon?: ReactNode | ComponentType; } /** * Schema definition for a text block annotation object. * * @public * @example The default link annotation * ```ts * { * name: 'blockContent', * title: 'Content', * type: 'array', * of: [ * { * type: 'block', * marks: { * annotations: [ * { * type: 'object', * name: 'link', * fields: [ * { * type: 'string', * name: 'href', * }, * ], * }, * ] * }, * } * ] * } * ``` */ interface BlockAnnotationDefinition extends ObjectDefinition { icon?: ReactNode | ComponentType; } /** * Schema definition for text block marks (decorators and annotations). * * @public */ interface BlockMarksDefinition { decorators?: BlockDecoratorDefinition[]; annotations?: ArrayOfType<'object' | 'reference'>[]; } /** * Schema definition for text blocks. * * @public * @example the default block definition * ```ts * { * name: 'blockContent', * title: 'Content', * type: 'array', * of: [ * { * type: 'block', * marks: { * decorators: [ * {title: 'Strong', value: 'strong'}, * {title: 'Emphasis', value: 'em'}, * {title: 'Underline', value: 'underline'}, * {title: 'Strike', value: 'strike-through'}, * {title: 'Code', value: 'code'}, * ], * annotations: [ * { * type: 'object', * name: 'link', * fields: [ * { * type: 'string', * name: 'href', * }, * ], * }, * ] * }, * styles: [ * {title: 'Normal', value: 'normal'}, * {title: 'H1', value: 'h1'}, * {title: 'H2', value: 'h2'}, * {title: 'H3', value: 'h3'}, * {title: 'H4', value: 'h4'}, * {title: 'H5', value: 'h5'}, * {title: 'H6', value: 'h6'}, * {title: 'Quote', value: 'blockquote'} * ], * lists: [ * {title: 'Bullet', value: 'bullet'}, * {title: 'Number', value: 'number'}, * ], * }, * ] * } * ``` */ interface BlockDefinition extends BaseSchemaDefinition { type: 'block'; styles?: BlockStyleDefinition[]; lists?: BlockListDefinition[]; marks?: BlockMarksDefinition; of?: ArrayOfType<'object' | 'reference'>[]; /** Block types do not support initialValue - the runtime schema validation rejects it. */ initialValue?: never; options?: BlockOptions; validation?: ValidationBuilder<BlockRule, PortableTextBlock>; } /** @public */ interface BooleanOptions extends BaseSchemaTypeOptions { layout?: 'switch' | 'checkbox'; } /** @public */ interface BooleanRule extends RuleDef<BooleanRule, boolean> {} /** @public */ interface BooleanDefinition extends BaseSchemaDefinition { type: 'boolean'; options?: BooleanOptions; initialValue?: InitialValueProperty<any, boolean>; validation?: ValidationBuilder<BooleanRule, boolean>; } /** @public */ type ReferenceValue = Reference; /** @public */ interface ReferenceRule extends RuleDef<ReferenceRule, ReferenceValue> {} /** @public */ type ReferenceTo = SchemaTypeDefinition | TypeReference | Array<SchemaTypeDefinition | TypeReference>; /** * Types are closed for extension. To add properties via declaration merging to this type, * redeclare and add the properties to the interfaces that make up ReferenceOptions type. * * @see ReferenceFilterOptions * @see ReferenceFilterResolverOptions * @see ReferenceBaseOptions * * @public */ type ReferenceOptions = ReferenceBaseOptions & ReferenceFilterOptions; /** @public */ interface ReferenceDefinition extends BaseSchemaDefinition { type: 'reference'; to: ReferenceTo; weak?: boolean; options?: ReferenceOptions; validation?: ValidationBuilder<ReferenceRule, ReferenceValue>; initialValue?: InitialValueProperty<any, Omit<ReferenceValue, '_type'>>; } /** @public */ interface CrossDatasetReferenceDefinition extends BaseSchemaDefinition { type: 'crossDatasetReference'; weak?: boolean; to: { type: string; title?: string; icon?: ComponentType; preview?: PreviewConfig; /** * @deprecated Unused. Configuring search is no longer supported. */ __experimental_search?: { path: string | string[]; weight?: number; mapWith?: string; }[]; }[]; dataset: string; studioUrl?: (document: { id: string; type?: string; }) => string | null; tokenId?: string; options?: ReferenceOptions; /** * @deprecated Cross-project references are no longer supported, only cross-dataset */ projectId?: string; } /** @public */ interface DateOptions extends BaseSchemaTypeOptions { dateFormat?: string; } /** @public */ interface DateRule extends RuleDef<DateRule, string> { /** * @param minDate - Minimum date (inclusive). minDate should be in ISO 8601 format. */ min: (minDate: string | FieldReference) => DateRule; /** * @param maxDate - Maximum date (inclusive). maxDate should be in ISO 8601 format. */ max: (maxDate: string | FieldReference) => DateRule; } /** @public */ interface DateDefinition extends BaseSchemaDefinition { type: 'date'; options?: DateOptions; placeholder?: string; validation?: ValidationBuilder<DateRule, string>; initialValue?: InitialValueProperty<any, string>; } /** @public */ interface DatetimeOptions extends BaseSchemaTypeOptions { dateFormat?: string; timeFormat?: string; timeStep?: number; displayTimeZone?: string; allowTimeZoneSwitch?: boolean; } /** @public */ interface DatetimeRule extends RuleDef<DatetimeRule, string> { /** * @param minDate - Minimum date (inclusive). minDate should be in ISO 8601 format. */ min: (minDate: string | FieldReference) => DatetimeRule; /** * @param maxDate - Maximum date (inclusive). maxDate should be in ISO 8601 format. */ max: (maxDate: string | FieldReference) => DatetimeRule; } /** @public */ interface DatetimeDefinition extends BaseSchemaDefinition { type: 'datetime'; options?: DatetimeOptions; placeholder?: string; validation?: ValidationBuilder<DatetimeRule, string>; initialValue?: InitialValueProperty<any, string>; } /** * This exists only to allow for extensions using declaration-merging. * * @public */ interface DocumentOptions extends BaseSchemaTypeOptions {} /** @public */ interface DocumentRule extends RuleDef<DocumentRule, SanityDocument> {} /** @public */ interface DocumentDefinition extends Omit<ObjectDefinition, 'type'> { type: 'document'; liveEdit?: boolean; /** @beta */ orderings?: SortOrdering[]; options?: DocumentOptions; validation?: ValidationBuilder<DocumentRule, SanityDocument>; initialValue?: InitialValueProperty<any, Record<string, unknown>>; /** @deprecated Unused. Use the new field-level search config. */ __experimental_search?: { path: string; weight: number; mapWith?: string; }[]; /** @alpha */ __experimental_omnisearch_visibility?: boolean; /** * Determines whether the large preview title is displayed in the document pane form * @alpha * */ __experimental_formPreviewTitle?: boolean; } /** @public */ interface EmailRule extends RuleDef<EmailRule, string> {} /** @public */ interface EmailOptions extends BaseSchemaTypeOptions {} /** @public */ interface EmailDefinition extends BaseSchemaDefinition { type: 'email'; options?: EmailOptions; placeholder?: string; validation?: ValidationBuilder<EmailRule, string>; initialValue?: InitialValueProperty<any, string>; } /** @public */ interface MediaLibraryFilter { name: string; query: string; } /** @public */ interface MediaLibraryOptions { filters?: MediaLibraryFilter[]; } /** @public */ interface FileOptions extends ObjectOptions { storeOriginalFilename?: boolean; accept?: string; sources?: AssetSource[]; mediaLibrary?: MediaLibraryOptions; /** * When set to `true`, hides the upload UI, only allowing selection of existing assets from the media library. * Useful for centralized asset management workflows where ad-hoc uploads should be prevented. */ disableNew?: boolean; } /** @public */ interface FileRule extends RuleDef<FileRule, FileValue> { /** * Require a file field has an asset. * * @example * ```ts * defineField({ * name: 'file', * title: 'File', * type: 'file', * validation: (Rule) => Rule.required().assetRequired(), * }) * ``` */ assetRequired(): FileRule; } /** @public */ interface FileValue { asset?: Reference; [index: string]: unknown; } /** @public */ interface FileDefinition extends Omit<ObjectDefinition, 'type' | 'fields' | 'options' | 'groups' | 'validation'> { type: 'file'; fields?: ObjectDefinition['fields']; options?: FileOptions; validation?: ValidationBuilder<FileRule, FileValue>; initialValue?: InitialValueProperty<any, FileValue>; } /** * Geographical point representing a pair of latitude and longitude coordinates, * stored as degrees, in the World Geodetic System 1984 (WGS 84) format. Also * includes an optional `alt` property representing the altitude in meters. * * @public */ interface GeopointValue { /** * Type of the object. Must be `geopoint`. */ _type: 'geopoint'; /** * Latitude in degrees */ lat: number; /** * Longitude in degrees */ lng: number; /** * Altitude in meters */ alt?: number; } /** @public */ interface GeopointRule extends RuleDef<GeopointRule, GeopointValue> {} /** @public */ interface GeopointOptions extends ObjectOptions {} /** @public */ interface GeopointDefinition extends BaseSchemaDefinition { type: 'geopoint'; options?: GeopointOptions; validation?: ValidationBuilder<GeopointRule, GeopointValue>; initialValue?: InitialValueProperty<any, Omit<GeopointValue, '_type'>>; } /** @public */ interface GlobalDocumentReferenceDefinition extends BaseSchemaDefinition { type: 'globalDocumentReference'; weak?: boolean; to: { type: string; title?: string; icon?: ComponentType; preview?: PreviewConfig; }[]; resourceType: string; resourceId: string; options?: ReferenceOptions; studioUrl?: string | ((document: { id: string; type?: string; }) => string | null); } /** @public */ type ImageMetadataType = 'blurhash' | 'thumbhash' | 'lqip' | 'palette' | 'exif' | 'image' | 'location'; /** @public */ interface HotspotPreview { title: string; aspectRatio: number; } /** @public */ interface HotspotOptions { previews?: HotspotPreview[]; } /** @public */ interface ImageOptions extends FileOptions { metadata?: ImageMetadataType[]; hotspot?: boolean | HotspotOptions; } /** @public */ interface ImageValue extends FileValue { crop?: ImageCrop; hotspot?: ImageHotspot; [index: string]: unknown; } /** @public */ interface ImageRule extends RuleDef<ImageRule, ImageValue> { /** * Require an image field has an asset. * * @example * ```ts * defineField({ * name: 'image', * title: 'Image', * type: 'image', * validation: (Rule) => Rule.required().assetRequired(), * }) * ``` */ assetRequired(): ImageRule; } /** @public */ interface ImageDefinition extends Omit<ObjectDefinition, 'type' | 'fields' | 'options' | 'groups' | 'validation'> { type: 'image'; fields?: FieldDefinition[]; options?: ImageOptions; validation?: ValidationBuilder<ImageRule, ImageValue>; initialValue?: InitialValueProperty<any, ImageValue>; } /** @public */ interface NumberOptions extends EnumListProps<number>, BaseSchemaTypeOptions {} /** @public */ interface NumberRule extends RuleDef<NumberRule, number> { min: (minNumber: number | FieldReference) => NumberRule; max: (maxNumber: number | FieldReference) => NumberRule; lessThan: (limit: number | FieldReference) => NumberRule; greaterThan: (limit: number | FieldReference) => NumberRule; integer: () => NumberRule; precision: (limit: number | FieldReference) => NumberRule; positive: () => NumberRule; negative: () => NumberRule; } /** @public */ interface NumberDefinition extends BaseSchemaDefinition { type: 'number'; options?: NumberOptions; placeholder?: string; validation?: ValidationBuilder<NumberRule, number>; initialValue?: InitialValueProperty<any, number>; } /** @public */ interface SlugValue { _type: 'slug'; current?: string; } /** @public */ interface SlugRule extends RuleDef<SlugRule, SlugValue> {} /** @public */ interface SlugOptions extends SearchConfiguration, BaseSchemaTypeOptions { source?: string | Path | SlugSourceFn; maxLength?: number; slugify?: SlugifierFn; isUnique?: SlugIsUniqueValidator; disableArrayWarning?: boolean; } /** @public */ interface SlugDefinition extends BaseSchemaDefinition { type: 'slug'; options?: SlugOptions; validation?: ValidationBuilder<SlugRule, SlugValue>; initialValue?: InitialValueProperty<any, Omit<SlugValue, '_type'>>; } /** @public */ interface StringOptions extends EnumListProps<string>, SearchConfiguration, BaseSchemaTypeOptions {} /** @public */ interface StringRule extends RuleDef<StringRule, string> { min: (minNumber: number | FieldReference) => StringRule; max: (maxNumber: number | FieldReference) => StringRule; length: (exactLength: number | FieldReference) => StringRule; uppercase: () => StringRule; lowercase: () => StringRule; regex(pattern: RegExp, name: string, options: { name?: string; invert?: boolean; }): StringRule; regex(pattern: RegExp, options: { name?: string; invert?: boolean; }): StringRule; regex(pattern: RegExp, name: string): StringRule; regex(pattern: RegExp): StringRule; email(): StringRule; } /** @public */ interface StringDefinition extends BaseSchemaDefinition { type: 'string'; options?: StringOptions; placeholder?: string; validation?: ValidationBuilder<StringRule, string>; initialValue?: InitialValueProperty<any, string>; } /** @public */ interface TextRule extends StringRule {} /** @public */ interface TextOptions extends StringOptions {} /** @public */ interface TextDefinition extends BaseSchemaDefinition { type: 'text'; rows?: number; options?: TextOptions; placeholder?: string; validation?: ValidationBuilder<TextRule, string>; initialValue?: InitialValueProperty<any, string>; } /** @public */ interface UrlRule extends RuleDef<UrlRule, string> { uri(options: UriValidationOptions): UrlRule; } /** @public */ interface UrlOptions extends BaseSchemaTypeOptions {} /** @public */ interface UrlDefinition extends BaseSchemaDefinition { type: 'url'; options?: UrlOptions; placeholder?: string; validation?: ValidationBuilder<UrlRule, string>; initialValue?: InitialValueProperty<any, string>; } /** @beta */ interface DefineSchemaOptions<TStrict extends StrictDefinition, TAlias extends IntrinsicTypeName | undefined> { /** * `strict: false` allows unknown properties in the schema. * Use this when adding customizations to the schema that are not part of sanity core. * * If you want to extend the Sanity Schema types with your own properties or options to make them typesafe, * you can use [TypeScript declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html). * * See {@link defineType} for more. * * @see defineType */ strict?: TStrict; /** Should be provided when type is a non-intrinsic type, ie type is a type alias */ aliasFor?: TAlias extends IntrinsicTypeName ? TAlias : never; } /** @beta */ type IntrinsicBase = { [K in keyof IntrinsicDefinitions]: Omit<IntrinsicDefinitions[K], 'preview'> }; /** @beta */ type IntrinsicArrayOfBase = { [K in keyof IntrinsicDefinitions]: Omit<ArrayOfEntry<IntrinsicDefinitions[K]>, 'preview'> }; /** @beta */ type DefineSchemaBase<TType extends string, TAlias extends IntrinsicTypeName | undefined> = TType extends IntrinsicTypeName ? IntrinsicBase[TType] : TypeAliasDefinition<TType, TAlias>; /** @beta */ type DefineSchemaType<TType extends string, TAlias extends IntrinsicTypeName | undefined> = TType extends IntrinsicTypeName ? IntrinsicDefinitions[TType] : TypeAliasDefinition<TType, TAlias>; /** @beta */ type DefineArrayMemberBase<TType extends string, TAlias extends IntrinsicTypeName | undefined> = TType extends IntrinsicTypeName ? I