import type { EditorPlugin as MarkdownPlugin, EditorType as MarkdownEditorType, } from '@toast-ui/editor/types/editor'; import type { ToolbarItemOptions as MarkdownToolbarItemOptions } from '@toast-ui/editor/types/ui'; import type { PropertiesSchema } from 'ajv/dist/types/json-schema'; import type { ComponentType, ReactNode } from 'react'; import type { t, TranslateProps as ReactPolyglotTranslateProps } from 'react-polyglot'; import type { MediaFile as BackendMediaFile } from './backend'; import type { EditorControlProps } from './components/Editor/EditorControlPane/EditorControl'; import type { formatExtensions } from './formats/formats'; import type { I18N_STRUCTURE } from './lib/i18n'; import type { AllowedEvent } from './lib/registry'; import type Cursor from './lib/util/Cursor'; import type AssetProxy from './valueObjects/AssetProxy'; import type { MediaHolder } from './widgets/markdown/hooks/useMedia'; export interface SlugConfig { encoding: string; clean_accents: boolean; sanitize_replacement: string; } export interface Pages { [collection: string]: { isFetching?: boolean; page?: number; ids: string[] }; } export type SortableField = | { key: string; name: string; label: string; } | ({ key: string; } & Field); export interface SortObject { key: string; direction: SortDirection; } export type SortMap = Record; export type Sort = Record; export type FilterMap = ViewFilter & { active?: boolean }; export type GroupMap = ViewGroup & { active?: boolean }; export type Filter = Record>; // collection.field.active export type Group = Record>; // collection.field.active export interface GroupOfEntries { id: string; label: string; value: string | boolean | undefined; paths: Set; } export type ObjectValue = { [key: string]: ValueOrNestedValue; }; export type ValueOrNestedValue = | string | number | boolean | string[] | null | undefined | ObjectValue | ObjectValue[]; export type EntryData = ObjectValue | undefined | null; export interface Entry { collection: string; slug: string; path: string; partial: boolean; raw: string; data: T | undefined | null; label: string | null; isModification: boolean | null; mediaFiles: MediaFile[]; author: string; updatedOn: string; status?: string; newRecord?: boolean; isFetching?: boolean; isPersisting?: boolean; isDeleting?: boolean; error?: string; i18n?: { [locale: string]: { data: EntryData; }; }; } export type Entities = Record; export interface FieldError { type: string; message?: string; } export interface FieldsErrors { [field: string]: FieldError[]; } export interface FieldValidationMethodProps { field: F; value: T | undefined | null; t: t; } export type FieldValidationMethod = ( props: FieldValidationMethodProps, ) => false | FieldError | Promise; export interface EntryDraft { entry: Entry; fieldsErrors: FieldsErrors; } export interface FilterRule { value: string; field: string; } export interface EditorConfig { preview?: boolean; frame?: boolean; } export interface CollectionFile { name: string; label: string; file: string; fields: Field[]; label_singular?: string; description?: string; media_folder?: string; public_folder?: string; i18n?: boolean | I18nInfo; editor?: EditorConfig; } interface Nested { summary?: string; depth: number; } export interface I18nSettings { currentLocale: string; defaultLocale: string; locales: string[]; } export type Format = keyof typeof formatExtensions; export interface i18nCollection extends Omit { i18n: Required['i18n']; } export interface Collection { name: string; description?: string; icon?: string; folder?: string; files?: CollectionFile[]; fields: Field[]; isFetching?: boolean; media_folder?: string; public_folder?: string; preview_path?: string; preview_path_date_field?: string; summary?: string; filter?: FilterRule; type: 'file_based_collection' | 'folder_based_collection'; extension?: string; format?: Format; frontmatter_delimiter?: string | [string, string]; create?: boolean; delete?: boolean; identifier_field?: string; path?: string; slug?: string; label_singular?: string; label: string; sortable_fields: SortableFields; view_filters: ViewFilter[]; view_groups: ViewGroup[]; nested?: Nested; i18n?: boolean | I18nInfo; hide?: boolean; editor?: EditorConfig; } export type Collections = Record; export interface MediaLibraryInstance { show: (args: { id?: string; value?: string | string[]; config: Record; allowMultiple?: boolean; imagesOnly?: boolean; }) => void; hide?: () => void; onClearControl?: (args: { id: string }) => void; onRemoveControl?: (args: { id: string }) => void; enableStandalone: () => boolean; } export type MediaFile = BackendMediaFile & { key?: string }; export interface DisplayURLState { isFetching: boolean; url?: string; err?: Error; } export type Hook = string | boolean; export type TranslatedProps = T & ReactPolyglotTranslateProps; export type GetAssetFunction = (path: string, field?: Field) => Promise; export interface WidgetControlProps { clearFieldErrors: EditorControlProps['clearFieldErrors']; clearSearch: EditorControlProps['clearSearch']; collection: Collection; config: Config; entry: Entry; field: F; fieldsErrors: FieldsErrors; submitted: boolean; forList: boolean; getAsset: GetAssetFunction; isDisabled: boolean; isFetching: boolean; isFieldDuplicate: EditorControlProps['isFieldDuplicate']; isFieldHidden: EditorControlProps['isFieldHidden']; label: string; loadEntry: EditorControlProps['loadEntry']; locale: string | undefined; mediaPaths: Record; onChange: (value: T | null | undefined) => void; clearMediaControl: EditorControlProps['clearMediaControl']; openMediaLibrary: EditorControlProps['openMediaLibrary']; removeInsertedMedia: EditorControlProps['removeInsertedMedia']; removeMediaControl: EditorControlProps['removeMediaControl']; i18n: I18nSettings | undefined; hasErrors: boolean; path: string; query: EditorControlProps['query']; t: t; value: T | undefined | null; } export interface WidgetPreviewProps { config: Config; collection: Collection; entry: Entry; field: RenderedField; getAsset: GetAssetFunction; resolveWidget: (name: string) => Widget; value: T | undefined | null; } export type WidgetPreviewComponent = // eslint-disable-next-line @typescript-eslint/no-explicit-any | React.ReactElement> | ComponentType>; export interface TemplatePreviewProps { collection: Collection; fields: Field[]; entry: Entry; document: Document | undefined | null; window: Window | undefined | null; getAsset: GetAssetFunction; widgetFor: (name: string) => ReactNode; widgetsFor: (name: string) => | { data: EntryData | null; widgets: Record; } | { data: EntryData | null; widgets: Record; }[]; } export type TemplatePreviewComponent = // eslint-disable-next-line @typescript-eslint/no-explicit-any | React.ReactElement> | ComponentType; export interface WidgetOptions { validator?: Widget['validator']; getValidValue?: Widget['getValidValue']; schema?: Widget['schema']; allowMapValue?: boolean; } export interface Widget { control: ComponentType>; preview?: WidgetPreviewComponent; validator: FieldValidationMethod; getValidValue: (value: T | undefined | null) => T | undefined | null; schema?: PropertiesSchema; allowMapValue?: boolean; } export interface WidgetParam { name: string; controlComponent: Widget['control']; previewComponent?: Widget['preview']; options?: WidgetOptions; } export interface PersistOptions { newEntry?: boolean; commitMessage: string; collectionName?: string; status?: string; } export interface ImplementationEntry { data: string; file: { path: string; label?: string; id?: string | null; author?: string; updatedOn?: string }; } export interface DisplayURLObject { id: string; path: string; } export type DisplayURL = DisplayURLObject | string; export interface ImplementationMediaFile { name: string; id: string; size?: number; displayURL?: DisplayURL; path: string; draft?: boolean; url?: string; file?: File; field?: Field; } export interface DataFile { path: string; slug: string; raw: string; newPath?: string; } export interface BackendEntry { dataFiles: DataFile[]; assets: AssetProxy[]; } export type DeleteOptions = {}; export interface Credentials { token: string | {}; refresh_token?: string; } export type User = Credentials & { backendName?: string; login?: string; name?: string; avatar_url?: string; }; export interface ImplementationFile { id?: string | null | undefined; label?: string; path: string; } export interface AuthenticatorConfig { site_id?: string; base_url?: string; auth_endpoint?: string; auth_token_endpoint?: string; auth_url?: string; app_id?: string; clearHash?: () => void; } export abstract class BackendClass { // eslint-disable-next-line @typescript-eslint/no-empty-function constructor(_config: Config, _options: BackendInitializerOptions) {} abstract authComponent(): (props: TranslatedProps) => JSX.Element; abstract restoreUser(user: User): Promise; abstract authenticate(credentials: Credentials): Promise; abstract logout(): Promise | void | null; abstract getToken(): Promise; abstract getEntry(path: string): Promise; abstract entriesByFolder( folder: string, extension: string, depth: number, ): Promise; abstract entriesByFiles(files: ImplementationFile[]): Promise; abstract getMediaDisplayURL(displayURL: DisplayURL): Promise; abstract getMedia(folder?: string): Promise; abstract getMediaFile(path: string): Promise; abstract persistEntry(entry: BackendEntry, opts: PersistOptions): Promise; abstract persistMedia(file: AssetProxy, opts: PersistOptions): Promise; abstract deleteFiles(paths: string[], commitMessage: string): Promise; abstract allEntriesByFolder( folder: string, extension: string, depth: number, ): Promise; abstract traverseCursor( cursor: Cursor, action: string, ): Promise<{ entries: ImplementationEntry[]; cursor: Cursor }>; abstract isGitBackend(): boolean; abstract status(): Promise<{ auth: { status: boolean }; api: { status: boolean; statusPage: string }; }>; } export interface LocalePhrasesRoot { [property: string]: LocalePhrases; } export type LocalePhrases = string | { [property: string]: LocalePhrases }; export type CustomIcon = () => JSX.Element; export type WidgetValueSerializer = { serialize: (value: ValueOrNestedValue) => ValueOrNestedValue; deserialize: (value: ValueOrNestedValue) => ValueOrNestedValue; }; export type MediaLibraryOptions = Record; export interface MediaLibraryInitOptions { options: Record | undefined; handleInsert: (url: string | string[]) => void; } export interface MediaLibraryExternalLibrary { name: string; config?: MediaLibraryOptions; init: ({ options, handleInsert }: MediaLibraryInitOptions) => Promise; } export interface MediaLibraryInternalOptions { allow_multiple?: boolean; choose_url?: boolean; } export type MediaLibrary = MediaLibraryExternalLibrary | MediaLibraryInternalOptions; export type BackendType = | 'azure' | 'git-gateway' | 'github' | 'gitlab' | 'bitbucket' | 'test-repo' | 'proxy'; export type MapWidgetType = 'Point' | 'LineString' | 'Polygon'; export type MarkdownWidgetButton = | 'bold' | 'italic' | 'code' | 'link' | 'heading-one' | 'heading-two' | 'heading-three' | 'heading-four' | 'heading-five' | 'heading-six' | 'quote' | 'code-block' | 'bulleted-list' | 'numbered-list'; export interface SelectWidgetOptionObject { label: string; value: string; } export type AuthScope = 'repo' | 'public_repo'; export type SlugEncoding = 'unicode' | 'ascii'; export type RenderedField = Omit & { fields?: ReactNode[]; }; export interface BaseField { name: string; label?: string; required?: boolean; hint?: string; pattern?: [string, string]; i18n?: boolean | 'translate' | 'duplicate' | 'none'; comment?: string; } export interface BooleanField extends BaseField { widget: 'boolean'; default?: boolean; } export interface CodeField extends BaseField { widget: 'code'; default?: string | { [key: string]: string }; default_language?: string; allow_language_selection?: boolean; keys?: { code: string; lang: string }; output_code_only?: boolean; code_mirror_config: { extra_keys?: Record; } & Record; } export interface ColorField extends BaseField { widget: 'color'; default?: string; allow_input?: boolean; enable_alpha?: boolean; } export interface DateTimeField extends BaseField { widget: 'datetime'; default?: string; format?: string; date_format?: boolean | string; time_format?: boolean | string; picker_utc?: boolean; } export interface FileOrImageField extends BaseField { widget: 'file' | 'image'; default?: string; media_library?: MediaLibrary; media_folder?: string; public_folder?: string; private?: boolean; } export interface ObjectField extends BaseField { widget: 'object'; default?: ObjectValue; collapsed?: boolean; summary?: string; fields: Field[]; } export interface ListField extends BaseField { widget: 'list'; default?: ObjectValue[]; allow_add?: boolean; collapsed?: boolean; summary?: string; label_singular?: string; fields?: Field[]; max?: number; min?: number; add_to_top?: boolean; types?: ObjectField[]; type_key?: string; } export interface MapField extends BaseField { widget: 'map'; default?: string; decimals?: number; type?: MapWidgetType; height?: string; } export interface MarkdownField extends BaseField { widget: 'markdown'; default?: string; media_library?: MediaLibrary; media_folder?: string; public_folder?: string; } export interface NumberField extends BaseField { widget: 'number'; default?: string | number; value_type?: 'int' | 'float' | string; min?: number; max?: number; step?: number; } export interface SelectField extends BaseField { widget: 'select'; default?: string | string[]; options: string[] | SelectWidgetOptionObject[]; multiple?: boolean; min?: number; max?: number; } export interface RelationField extends BaseField { widget: 'relation'; default?: string | string[]; collection: string; value_field: string; search_fields: string[]; file?: string; display_fields?: string[]; multiple?: boolean; min?: number; max?: number; options_length?: number; } export interface HiddenField extends BaseField { widget: 'hidden'; default?: ValueOrNestedValue; } export interface StringOrTextField extends BaseField { // This is the default widget, so declaring its type is optional. widget?: 'string' | 'text'; default?: string; } export type Field = | BooleanField | CodeField | ColorField | DateTimeField | FileOrImageField | ListField | MapField | MarkdownField | NumberField | ObjectField | RelationField | SelectField | HiddenField | StringOrTextField; export interface ViewFilter { id: string; label: string; field: string; pattern: string; } export interface ViewGroup { id: string; label: string; field: string; pattern?: string; } export enum SortDirection { Ascending = 'Ascending', Descending = 'Descending', None = 'None', } export interface SortableFieldsDefault { field: string; direction?: SortDirection; } export interface SortableFields { default?: SortableFieldsDefault; fields: string[]; } export interface Backend { name: BackendType; auth_scope?: AuthScope; repo?: string; branch?: string; api_root?: string; api_version?: string; tenant_id?: string; site_domain?: string; base_url?: string; auth_endpoint?: string; app_id?: string; auth_type?: 'implicit' | 'pkce'; proxy_url?: string; large_media_url?: string; login?: boolean; use_large_media_transforms_in_media_library?: boolean; identity_url?: string; gateway_url?: string; commit_messages?: { create?: string; update?: string; delete?: string; uploadMedia?: string; deleteMedia?: string; }; } export interface Slug { encoding?: SlugEncoding; clean_accents?: boolean; sanitize_replacement?: string; } export interface LocalBackend { url?: string; allowed_hosts?: string[]; } export interface Config { backend: Backend; collections: Collection[]; locale?: string; site_id?: string; site_url?: string; display_url?: string; base_url?: string; logo_url?: string; media_folder?: string; public_folder?: string; media_folder_relative?: boolean; media_library?: MediaLibrary; load_config_file?: boolean; integrations?: Integration[]; slug?: Slug; i18n?: I18nInfo; local_backend?: boolean | LocalBackend; editor?: EditorConfig; search?: boolean; } export interface InitOptions { config: Config; } export interface BackendInitializerOptions { updateUserCredentials: (credentials: Credentials) => void; } export interface BackendInitializer { init: (config: Config, options: BackendInitializerOptions) => BackendClass; } export interface EventData { entry: Entry; author: { login: string | undefined; name: string }; } export interface EventListener { name: AllowedEvent; handler: ( data: EventData, options: Record, ) => Promise; } export type EventListenerOptions = Record; export interface AdditionalLink { id: string; title: string; data: string | (() => JSX.Element); options?: { iconName?: string; }; } export interface AuthenticationPageProps { onLogin: (user: User) => void; inProgress?: boolean; base_url?: string; siteId?: string; authEndpoint?: string; config: Config; error?: string | undefined; clearHash?: () => void; } export type Integration = { collections?: '*' | string[]; } & (AlgoliaIntegration | AssetStoreIntegration); export type IntegrationProvider = Integration['provider']; export type SearchIntegrationProvider = 'algolia'; export type MediaIntegrationProvider = 'assetStore'; export interface AlgoliaIntegration extends AlgoliaConfig { provider: 'algolia'; } export interface AlgoliaConfig { hooks: ['search' | 'listEntries']; applicationID: string; apiKey: string; indexPrefix?: string; } export interface AssetStoreIntegration extends AssetStoreConfig { provider: 'assetStore'; } export interface AssetStoreConfig { hooks: ['assetStore']; shouldConfirmUpload?: boolean; getSignedFormURL: string; } export interface SearchResponse { entries: Entry[]; pagination: number; } export interface SearchQueryResponse { hits: Entry[]; query: string; } export interface EditorPersistOptions { createNew?: boolean; duplicate?: boolean; } export interface I18nInfo { locales: string[]; defaultLocale: string; structure?: I18N_STRUCTURE; } export interface ProcessedCodeLanguage { label: string; identifiers: string[]; codemirror_mode: string; codemirror_mime_type: string; } export interface FileMetadata { author: string; updatedOn: string; } export interface PreviewStyleOptions { raw?: boolean; } export interface PreviewStyle { value: string; raw: boolean; } export interface MarkdownPluginFactoryProps { config: Config; field: MarkdownField; media: MediaHolder; mode: 'editor' | 'preview'; } export type MarkdownPluginFactory = (props: MarkdownPluginFactoryProps) => MarkdownPlugin; export interface MarkdownToolbarItemsFactoryProps { imageToolbarButton: MarkdownToolbarItemOptions; } export type MarkdownToolbarItemsFactory = ( props: MarkdownToolbarItemsFactoryProps, ) => (string | MarkdownToolbarItemOptions)[][]; export interface MarkdownEditorOptions { initialEditType?: MarkdownEditorType; height?: string; toolbarItems?: MarkdownToolbarItemsFactory; plugins?: MarkdownPluginFactory[]; }