UNPKG

@stackbit/types

Version:

Types for Stackbit config and Content Source Interface

742 lines (662 loc) 24.1 kB
/** * Stackbit Field Types */ import { STYLE_PROPS } from './consts'; import type { DocumentWithSource } from './content-source-document'; import type { DocumentModelField, DocumentObjectField } from './content-source-document-fields'; import type { ConfigDelegate } from './config-delegate'; import type { CustomActionClientModel, CustomActionField, CustomActionObjectField } from './custom-actions'; import type { DistributiveOmit } from './utility-types'; import type { ModelWithSource } from './models'; import type { UpdateOperation } from './content-source-operation'; export type Field = | FieldString | FieldUrl | FieldSlug | FieldText | FieldMarkdown | FieldHtml | FieldNumber | FieldBoolean | FieldDate | FieldDatetime | FieldColor | FieldJson | FieldRichText | FieldFile | FieldEnum | FieldImage | FieldObject | FieldModel | FieldReference | FieldCrossReference | FieldStyle | FieldList; export type ClientField<T extends Field = Field> = DistributiveOmit<T, 'default' | 'const' | 'actions'> & { default?: unknown; const?: unknown; actions?: CustomActionClientModel<CustomActionField>[]; }; // Make all Field properties except the 'name' optional, including fields of nested objects and lists. // prettier-ignore export type DistributeFieldsExtension<Type extends Field> = Type extends { type: 'object' } ? Partial<Omit<Type, 'name' | 'fields'>> & { name: string; fields?: DistributeFieldsExtension<Field>[] } : Type extends { type: 'list' } ? Partial<Omit<Type, 'name' | 'items'>> & { name: string; items?: DistributePartialListItems<FieldListItems> } : // do not make style fields partial Type extends { type: 'style' } ? Type : // do not make cross-reference fields partial Type extends { type: 'cross-reference' } ? Type : Partial<Omit<Type, 'name'>> & { name: string }; // prettier-ignore export type DistributePartialListItems<Type extends FieldListItems> = Type extends { type: 'object' } ? Partial<Omit<Type, 'fields'>> & { fields?: DistributeFieldsExtension<Field>[] } : // do not make cross-reference fields partial Type extends { type: 'cross-reference' } ? Type : Partial<Type>; export type FieldExtension = DistributeFieldsExtension<Field>; export type FieldType = Field['type']; export type FieldSpecificProps = | FieldStringProps | FieldUrlProps | FieldSlugProps | FieldTextProps | FieldMarkdownProps | FieldHtmlProps | FieldNumberProps | FieldBooleanProps | FieldDateProps | FieldDatetimeProps | FieldColorProps | FieldJsonProps | FieldRichTextProps | FieldFileProps | FieldEnumProps | FieldImageProps | FieldObjectProps | FieldModelProps | FieldReferenceProps | FieldCrossReferenceProps | FieldStyleProps | FieldListProps; type ExtractByType<Union extends { type: FieldType }, Type extends FieldType> = Union extends { type: Type } ? Union : never; export type FieldForType<Type extends FieldType> = ExtractByType<Field, Type>; export type FieldSpecificPropsForType<Type extends FieldType> = ExtractByType<FieldSpecificProps, Type>; export type FieldSpecificPropsForField<Type extends Field> = ExtractByType<FieldSpecificProps, Type['type']>; export type FieldString = FieldCommonProps & FieldStringProps; export type FieldUrl = FieldCommonProps & FieldUrlProps; export type FieldSlug = FieldCommonProps & FieldSlugProps; export type FieldText = FieldCommonProps & FieldTextProps; export type FieldMarkdown = FieldCommonProps & FieldMarkdownProps; export type FieldHtml = FieldCommonProps & FieldHtmlProps; export type FieldNumber = FieldCommonProps & FieldNumberProps; export type FieldBoolean = FieldCommonProps & FieldBooleanProps; export type FieldDate = FieldCommonProps & FieldDateProps; export type FieldDatetime = FieldCommonProps & FieldDatetimeProps; export type FieldColor = FieldCommonProps & FieldColorProps; export type FieldJson = FieldCommonProps & FieldJsonProps; export type FieldRichText = FieldCommonProps & FieldRichTextProps; export type FieldFile = FieldCommonProps & FieldFileProps; export type FieldEnum = FieldCommonProps & FieldEnumProps; export type FieldImage = FieldCommonProps & FieldImageProps; export type FieldObject = Omit<FieldCommonProps, 'actions'> & FieldObjectProps; export type FieldModel = FieldCommonProps & FieldModelProps; export type FieldReference = FieldCommonProps & FieldReferenceProps; export type FieldCrossReference = FieldCommonProps & FieldCrossReferenceProps; export type FieldStyle = FieldCommonProps & FieldStyleProps; export type FieldList = FieldCommonProps & FieldListProps; export type FieldListObject = FieldCommonProps & FieldListItemsObjectProps; export type FieldListModel = FieldCommonProps & FieldListItemsModelProps; export type FieldListReference = FieldCommonProps & FieldListItemsReferenceProps; export type FieldListCrossReference = FieldCommonProps & FieldListItemsCrossReferenceProps; export interface FieldCommonProps { /** * The `name` property defines the name of the field key used to store its value in the content source. */ name: string; /** * Use the `label` property to provide the human-readable label for the field. If not specified, the * `name` property will be start-cased and used instead. */ label?: string; /** * The `description` is presented as a tooltip when hovering over the info icon in Stackbit UI. */ description?: string; /** * Use the `required` property to mark a field as required. Visual editor * will display an error message below the field if its value is not set, * and publishing the document containing this field will not be possible * until it has been filled in. */ required?: boolean; /** * Field Validations * An object specifying validation rules that must be met when saving the field. */ validations?: FieldValidationsCustom; /** * Use the `default` property to specify an initial value for a field * when no value provided when creating the parent object. */ default?: unknown | FieldInitialValueFunction; /** * Use the `group` field along with the `fieldGroups` model property, * to organize related fields into logical groups presented as tabs within the Stackbit UI. */ group?: string; /** * Use the `const` property to specify a value for a field when creating * the parent object. Setting this property implies that a field will be * read-only and cannot be changed via Stackbit UI. */ const?: unknown | FieldInitialValueFunction; /** * The `hidden` property can be used to hide fields from the Stackbit UI and prevent content * editors from modifying their values. This can be particularly useful for fields that are * controlled by internal processes, or for fields that have constant values specified using * the `const` property. */ hidden?: boolean; /** * You can use the `readOnly` property to restrict the editing of fields in the Stackbit UI. * * For primitive field types such as strings, numbers, and booleans, setting `readOnly` * to `true` will prevent the field from being edited. * * For complex field types like `reference`, `model`, `cross-reference`, and `object`, * setting `readOnly` to `true` will prevent editors from adding or removing the object * or reference to the document. However, it will not prevent editing of fields within * the nested or referenced object/document. To prevent editing of fields within an object, * `readOnly` must be set on each field that should not be editable. * * For `list` fields, setting `readOnly` to `true` will prevent editors from adding, removing, * or reordering items within the list. */ readOnly?: boolean; /** * To enable field localization, set the `localized` property to `true`. When a model field * is marked as localized, the document fields returned from the content source must also be * localized. */ localized?: boolean; actions?: CustomActionField[]; } export type FieldCustomControlType = | 'custom-modal-html' | 'custom-inline-html' | 'custom-modal-script' | 'custom-inline-script'; export interface FieldCustomControlTypeProps<ControlType = never> { /** * The `controlType` property can be utilized to define a custom UI control for the field. * If you choose to define it, you must also specify either the `controlUrl` or the * `controlFilePath` property. */ controlType?: FieldCustomControlType | ControlType; /** * Use `controlFilePath` to specify a path to the local HTML file containing * the custom field UI. The path should be relative to the folder containing * the stackbit.config.ts. * When specifying this property, you must also specify the `controlType` property. */ controlFilePath?: string; /** * Use `controlUrl` to specify the remote URL to the HTML containing a custom * field UI. * When specifying this property, you must also specify the `controlType` property. */ controlUrl?: string; } export type FieldInitialValueFunction = ( options: { data: Record<string, any>; locale?: string; } & ConfigDelegate ) => Promise<unknown>; export type FieldBasicProps = | FieldStringProps | FieldUrlProps | FieldSlugProps | FieldTextProps | FieldMarkdownProps | FieldHtmlProps | FieldBooleanProps | FieldDateProps | FieldDatetimeProps | FieldColorProps | FieldJsonProps | FieldRichTextProps | FieldFileProps; export interface FieldStringProps extends FieldCustomControlTypeProps { type: 'string'; validations?: FieldValidationsCustom & FieldValidationsStringLength & FieldValidationsRegExp & FieldValidationsUnique; } export interface FieldUrlProps extends FieldCustomControlTypeProps { type: 'url'; validations?: FieldValidationsCustom & FieldValidationsStringLength & FieldValidationsRegExp & FieldValidationsUnique; } export interface FieldSlugProps extends FieldCustomControlTypeProps { type: 'slug'; validations?: FieldValidationsCustom & FieldValidationsStringLength & FieldValidationsRegExp & FieldValidationsUnique; } export interface FieldTextProps extends FieldCustomControlTypeProps { type: 'text'; validations?: FieldValidationsCustom & FieldValidationsStringLength & FieldValidationsRegExp; } export interface FieldMarkdownProps extends FieldCustomControlTypeProps { type: 'markdown'; validations?: FieldValidationsCustom & FieldValidationsStringLength & FieldValidationsRegExp; } export interface FieldHtmlProps extends FieldCustomControlTypeProps { type: 'html'; validations?: FieldValidationsCustom & FieldValidationsStringLength & FieldValidationsRegExp; } export interface FieldBooleanProps extends FieldCustomControlTypeProps<'button-group' | 'checkbox'> { type: 'boolean'; validations?: FieldValidationsCustom; } export interface FieldDateProps extends FieldCustomControlTypeProps { type: 'date'; validations?: FieldValidationsCustom & FieldValidationsDateRange; } export interface FieldDatetimeProps extends FieldCustomControlTypeProps { type: 'datetime'; validations?: FieldValidationsCustom & FieldValidationsDateRange; } export interface FieldColorProps extends FieldCustomControlTypeProps { type: 'color'; validations?: FieldValidationsCustom; } export interface FieldJsonProps extends FieldCustomControlTypeProps { type: 'json'; validations?: FieldValidationsCustom; } export interface FieldRichTextProps extends FieldCustomControlTypeProps { type: 'richText'; validations?: FieldValidationsCustom; } export interface FieldFileProps extends FieldCustomControlTypeProps { type: 'file'; validations?: FieldValidationsCustom & FieldValidationsFile; } export type FieldEnumProps = | FieldEnumDropdownProps | FieldEnumThumbnailsProps | FieldEnumPaletteProps | FieldEnumPaletteColorsProps; export interface FieldEnumDropdownProps extends FieldCustomControlTypeProps<'dropdown' | 'button-group'> { type: 'enum'; options: FieldEnumOptionValue[] | FieldEnumOptionObject[]; validations?: FieldValidationsCustom & FieldValidationsUnique; } export interface FieldEnumThumbnailsProps { type: 'enum'; controlType: 'thumbnails'; options: FieldEnumOptionThumbnails[]; validations?: FieldValidationsCustom & FieldValidationsUnique; } export interface FieldEnumPaletteProps { type: 'enum'; controlType: 'palette'; options: FieldEnumOptionPalette[]; validations?: FieldValidationsCustom & FieldValidationsUnique; } export interface FieldEnumPaletteColorsProps { type: 'enum'; controlType: 'palette-colors'; options: FieldEnumOptionPaletteColors[]; validations?: FieldValidationsCustom & FieldValidationsUnique; } export type FieldEnumOptionValue = string | number; export interface FieldEnumOptionObject { label: string; value: FieldEnumOptionValue; } export interface FieldEnumOptionThumbnails extends FieldEnumOptionObject { thumbnail: string; } export interface FieldEnumOptionPalette extends FieldEnumOptionObject { textColor?: string; backgroundColor?: string; borderColor?: string; } export interface FieldEnumOptionPaletteColors extends FieldEnumOptionObject { colors: string[]; } export interface FieldImageProps extends FieldCustomControlTypeProps { type: 'image'; source?: string; validations?: FieldValidationsCustom & FieldValidationsImage; } export interface FieldNumberProps extends FieldCustomControlTypeProps<'slider'> { type: 'number'; subtype?: 'int' | 'float'; /** @deprecated Use [`validations.min`]{@link FieldValidationsNumberRange#min} property. */ min?: number; /** @deprecated Use [`validations.min`]{@link FieldValidationsNumberRange#max} property. */ max?: number; /** @deprecated Use [`validations.step`]{@link FieldValidationsNumberRange#step} property. */ step?: number; unit?: string; validations?: FieldValidationsCustom & FieldValidationsNumberRange & FieldValidationsUnique; } export interface FieldObjectProps extends FieldCustomControlTypeProps { type: 'object'; labelField?: string; preview?: DocumentFieldPreview; thumbnail?: string; variantField?: string; validations?: FieldValidationsCustom; actions?: (CustomActionField | CustomActionObjectField)[]; fieldGroups?: FieldGroupItem[]; fields: Field[]; } export interface FieldGroupItem { name: string; label: string; icon?: string; } export interface FieldModelProps extends FieldCustomControlTypeProps { type: 'model'; models: string[]; groups?: string[]; validations?: FieldValidationsCustom; } export interface FieldReferenceProps extends FieldCustomControlTypeProps { type: 'reference'; models: string[]; groups?: string[]; validations?: FieldValidationsCustom; } export interface FieldCrossReferenceProps extends FieldCustomControlTypeProps { type: 'cross-reference'; models: FieldCrossReferenceModel[]; validations?: FieldValidationsCustom; } export interface FieldCrossReferenceModel { modelName: string; srcType?: string; srcProjectId?: string; } export type StyleProps = (typeof STYLE_PROPS)[number]; export interface FieldStyleProps { type: 'style'; styles: Record<string, Partial<Record<StyleProps, any>>>; validations?: FieldValidationsCustom; } export interface FieldListProps extends FieldCustomControlTypeProps<'checkbox'> { type: 'list'; items: | FieldBasicProps | FieldEnumProps | FieldBooleanProps | FieldImageProps | FieldNumberProps | FieldObjectProps | FieldModelProps | FieldReferenceProps | FieldCrossReferenceProps; validations?: FieldValidationsCustom & FieldValidationsListLength & FieldValidationsUnique; } export type FieldListItems = FieldListProps['items']; export type FieldListItemsForType<Type extends FieldType> = ExtractByType<FieldListItems, Type>; export type DistributeFieldListItemsBasicProps<Type extends FieldBasicProps> = Type extends FieldBasicProps ? { type: 'list'; items: Type; } : never; export type FieldListItemsBasicProps = DistributeFieldListItemsBasicProps<FieldBasicProps>; export type DistributeFieldListItemsEnumProps<Type extends FieldEnumProps> = Type extends FieldEnumProps ? { type: 'list'; items: Type; } & FieldCustomControlTypeProps<'checkbox'> : never; export type FieldListItemsEnumProps = DistributeFieldListItemsEnumProps<FieldEnumProps>; export interface FieldListItemsImageProps extends FieldCustomControlTypeProps { type: 'list'; items: FieldImageProps; } export interface FieldListItemsNumberProps extends FieldCustomControlTypeProps { type: 'list'; items: FieldNumberProps; } export interface FieldListItemsObjectProps extends FieldCustomControlTypeProps { type: 'list'; items: FieldObjectProps; } export interface FieldListItemsModelProps extends FieldCustomControlTypeProps { type: 'list'; items: FieldModelProps; } export interface FieldListItemsReferenceProps extends FieldCustomControlTypeProps { type: 'list'; items: FieldReferenceProps; } export interface FieldListItemsCrossReferenceProps extends FieldCustomControlTypeProps { type: 'list'; items: FieldCrossReferenceProps; } export type DocumentPreview = DocumentPreviewFunction | PreviewFields; export type DocumentFieldPreview = ObjectPreviewFunction | PreviewFields; export type DocumentPreviewFunction = ( options: { document: DocumentWithSource; currentLocale?: string; } & ConfigDelegate ) => { title?: string; subtitle?: string; image?: string; }; export type ObjectPreviewFunction = ( options: { parentDocument: DocumentWithSource; documentField: DocumentModelField | DocumentObjectField; currentLocale?: string; } & ConfigDelegate ) => { title?: string; subtitle?: string; image?: string; }; export interface PreviewFields { title?: string; subtitle?: string; image?: string; } export type FieldPath = (string | number)[]; // Field Validations // ================= export type FieldValidationsCustom = { /** * The `validate` functions allows you to define custom validation logic for * a field. */ validate?: FieldValidationsCustomFunction | FieldValidationsCustomFunction[]; }; export type FieldValidationsCustomFunction = ( options: { updateOperation: UpdateOperation; document?: DocumentWithSource; model: ModelWithSource; } & ConfigDelegate ) => Promise<true | string>; export type FieldValidationsUnique = { /** * Use the `unique` property to make the field unique across all the * documents of the same type. */ unique?: boolean; errors?: { unique?: string; }; }; export type FieldValidationsRegExp = { regexp?: string; regexpNot?: string; regexpPattern?: FieldValidationsRegExpPatterns; errors?: { regexp?: string; regexpNot?: string; regexpPattern?: string; }; }; export type FieldValidationsRegExpPatterns = | 'uppercase' | 'lowercase' | 'email' | 'url' | 'date-us' | 'date-eu' | 'time-12h' | 'time-24h' | 'phone-us' | 'zip-code-us'; export type FieldValidationsStringLength = { /** Minimum length of string (inclusive). */ min?: number; /** Maximum length of string (inclusive). */ max?: number; /** Exact length of string. */ exact?: number; errors?: { min?: string; max?: string; exact?: string; }; }; export type FieldValidationsListLength = { /** Minimum number of elements in array (inclusive). */ min?: number; /** Maximum number of elements in array (inclusive). */ max?: number; /** Exact number of elements in array. */ exact?: number; errors?: { min?: string; max?: string; exact?: string; }; }; export type FieldValidationsDateRange = { /** Minimum date (inclusive) */ min?: string; /** Maximum date (inclusive). */ max?: string; /** Minimum date (non-inclusive) */ after?: string; /** Maximum date (non-inclusive). */ before?: string; errors?: { min?: string; max?: string; after?: string; before?: string; }; }; export type FieldValidationsNumberRange = { /** Minimum value (inclusive). */ min?: number; /** Maximum value (inclusive). */ max?: number; /** * Controls the step increments for fields with `controlType: "slider"`. * When using the default control type, the value will be corrected upon save to the closest available step. */ step?: number; /** Value must be less than the given limit. */ lessThan?: number; /** Value must be greater than the given limit. */ greaterThan?: number; errors?: { min?: string; max?: string; step?: string; lessThan?: string; greaterThan?: string; }; }; export type FieldValidationsImage = Omit<FieldValidationsFile, 'fileTypeGroups'> & { /** Minimum image width in pixels (inclusive). */ minWidth?: number; /** Maximum image width in pixels (inclusive). */ maxWidth?: number; /** Minimum image height in pixels (inclusive). */ minHeight?: number; /** Maximum image height in pixels (inclusive). */ maxHeight?: number; /** * The minimum ratio between image width and height i.e., min(width divided by height) * Can be set to string specifying the ratio separated by a colon, or a fractional number. * @example '4:3', 1.3333 => this will allow images with dimensions * (w:600px, h:450px), (w:600px, h:300px), and will not allow images with * dimensions (w:600px, h:600px), (w:300px, h:600px). */ minWidthToHeightRatio?: string | number; /** * The maximum ratio between image width and height i.e., max(width divided by height) * Can be set to string specifying the ratio separated by a colon, or a fractional number. * @example '2:1', 2 => this will allow images with dimensions * (w:600px, h:300px), (w:400px, h:400px), and will not allow images with * dimensions (w:600px, h:200px), (w:400px, h:100px). */ maxWidthToHeightRatio?: string | number; errors?: { minWidth?: string; maxWidth?: string; minHeight?: string; maxHeight?: string; minWidthToHeightRatio?: string; maxWidthToHeightRatio?: string; }; }; export type FieldValidationsFile = { /** Minimum file size in bytes (inclusive). */ fileMinSize?: number; /** Maximum file size in bytes (inclusive). */ fileMaxSize?: number; /** * Array of allowed file type extensions. * @example ['gif', 'png', 'jpg', 'jpeg', 'webp', 'svg'] */ fileTypes?: string[]; /** * Array of allowed file type groups. * The type groups contain predefined file types, and are added to the fileTypes array. * @example ['image', 'video'] */ fileTypeGroups?: FieldValidationsFileTypesGroup[]; errors?: { fileMinSize?: string; fileMaxSize?: string; fileTypes?: string; fileTypeGroups?: string; }; }; export type FieldValidationsFileTypesGroup = | 'image' | 'video' | 'audio' | 'text' | 'markup' | 'code' | 'document' | 'presentation' | 'spreadsheet' | 'archive';