@sanity/types
Version:
Type definitions for common Sanity data structures
1,747 lines • 112 kB
TypeScript
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