import { ReactElement, ReactNode } from 'react'; import { Glob } from "../config.js"; import { ChildField } from "./fields/child.js"; import { Awareness } from 'y-protocols/awareness'; export type FormFieldInputProps = { value: Value; onChange(value: Value): void; autoFocus: boolean; /** * This will be true when validate has returned false and the user has attempted to close the form * or when the form is open and they attempt to save the item */ forceValidation: boolean; }; export type JsonYamlValue = string | number | boolean | null | Date | readonly JsonYamlValue[] | { [key: string]: JsonYamlValue; }; type JsonYamlValueWithoutNull = JsonYamlValue & {}; export type FormFieldStoredValue = JsonYamlValueWithoutNull | undefined; export type BasicFormField = { kind: 'form'; formKind?: undefined; Input(props: FormFieldInputProps): ReactElement | null; defaultValue(): ParsedValue; parse(value: FormFieldStoredValue): ParsedValue; /** * If undefined is returned, the field will generally not be written, * except in array fields where it will be stored as null */ serialize(value: ParsedValue): { value: FormFieldStoredValue; }; validate(value: ParsedValue): ValidatedValue; reader: { parse(value: FormFieldStoredValue): ReaderValue; }; label?: string; }; export type SlugFormField = { kind: 'form'; formKind: 'slug'; Input(props: FormFieldInputProps): ReactElement | null; defaultValue(): ParsedValue; parse(value: FormFieldStoredValue, extra: { slug: string; } | undefined): ParsedValue; serialize(value: ParsedValue): { value: FormFieldStoredValue; }; serializeWithSlug(value: ParsedValue): { slug: string; value: FormFieldStoredValue; }; validate(value: ParsedValue, extra: { slugField: { slugs: Set; glob: Glob; }; } | undefined): ValidatedValue; reader: { parse(value: FormFieldStoredValue): ReaderValue; parseWithSlug(value: FormFieldStoredValue, extra: { slug: string; glob: Glob; }): ReaderValueAsSlugField; }; label?: string; }; export type AssetFormField = { kind: 'form'; formKind: 'asset'; Input(props: FormFieldInputProps): ReactElement | null; directory?: string; defaultValue(): ParsedValue; filename(value: FormFieldStoredValue, extra: { suggestedFilenamePrefix: string | undefined; slug: string | undefined; }): string | undefined; parse(value: FormFieldStoredValue, extra: { asset: Uint8Array | undefined; slug: string | undefined; }): ParsedValue; serialize(value: ParsedValue, extra: { suggestedFilenamePrefix: string | undefined; slug: string | undefined; }): { value: FormFieldStoredValue; asset: { content: Uint8Array; filename: string; } | undefined; }; validate(value: ParsedValue): ValidatedValue; reader: { parse(value: FormFieldStoredValue): ReaderValue; }; label?: string; }; export type AssetsFormField = { kind: 'form'; formKind: 'assets'; directories?: string[]; Input(props: FormFieldInputProps): ReactElement | null; defaultValue(): ParsedValue; parse(value: FormFieldStoredValue, args: { other: ReadonlyMap; external: ReadonlyMap>; slug: string | undefined; }): ParsedValue; serialize(value: ParsedValue, extra: { slug: string | undefined; }): { value: FormFieldStoredValue; other: ReadonlyMap; external: ReadonlyMap>; }; validate(value: ParsedValue): ValidatedValue; reader: { parse(value: FormFieldStoredValue): ReaderValue; }; collaboration?: { toYjs: (value: ParsedValue) => unknown; fromYjs: (yjsValue: unknown, awareness: Awareness) => ParsedValue; }; }; export type ContentFormField = { kind: 'form'; formKind: 'content'; contentExtension: string; directories?: string[]; Input(props: FormFieldInputProps): ReactElement | null; defaultValue(): ParsedValue; parse(value: FormFieldStoredValue, args: { content: Uint8Array | undefined; other: ReadonlyMap; external: ReadonlyMap>; slug: string | undefined; }): ParsedValue; serialize(value: ParsedValue, extra: { slug: string | undefined; }): { value: FormFieldStoredValue; content: Uint8Array | undefined; other: ReadonlyMap; external: ReadonlyMap>; }; validate(value: ParsedValue): ValidatedValue; reader: { parse(value: FormFieldStoredValue, extra: { content: Uint8Array | undefined; }): ReaderValue; }; collaboration?: { toYjs: (value: ParsedValue) => unknown; fromYjs: (yjsValue: unknown, awareness: Awareness) => ParsedValue; }; }; export type FormField = BasicFormField | SlugFormField | AssetFormField | ContentFormField | AssetsFormField; export type DocumentNode = DocumentElement | DocumentText; export type DocumentElement = { children: DocumentNode[]; [key: string]: unknown; }; export type DocumentText = { text: string; [key: string]: unknown; }; export type { ChildField } from "./fields/child.js"; export type ArrayField = { kind: 'array'; element: ElementField; label: string; description?: string; itemLabel?(props: unknown): string; asChildTag?: string; slugField?: string; validation?: { length?: { min?: number; max?: number; }; }; Input?(props: unknown): ReactElement | null; }; export type ObjectFieldOptions = { label?: string; description?: string; /** * Define the number of columns each field should span. The grid layout * supports 12 possible columns. * @example [6, 6] - "one row, equal columns" * @example [12, 8, 4] - "one field in the first row, two fields in the second row" */ layout?: number[]; }; export interface ObjectField = Record> extends ObjectFieldOptions { kind: 'object'; fields: Fields; Input?(props: unknown): ReactElement | null; } export type ConditionalField, ConditionalValues extends { [Key in `${ReturnType}`]: ComponentSchema; }> = { kind: 'conditional'; discriminant: DiscriminantField; values: ConditionalValues; Input?(props: unknown): ReactElement | null; }; type ArrayFieldInComponentSchema = { kind: 'array'; element: ComponentSchema; label: string; description?: string; itemLabel?(props: unknown): string; asChildTag?: string; slugField?: string; validation?: { length?: { min?: number; max?: number; }; }; Input?(props: unknown): ReactElement | null; }; export type ComponentSchema = ChildField | FormField | ObjectField | ConditionalField, { [key: string]: ComponentSchema; }> | ArrayFieldInComponentSchema; export * as fields from "./fields/index.js"; export type ComponentBlock = Record> = { preview: (props: any) => ReactElement | null; schema: Fields; label: string; toolbarIcon?: ReactElement; } & ({ chromeless: true; toolbar?: (props: { props: Record; onRemove(): void; }) => ReactElement; } | { chromeless?: false; toolbar?: (props: { props: Record; onShowEditMode(): void; onRemove(): void; isValid: boolean; }) => ReactElement; }); type ChildFieldPreviewProps = { readonly element: ChildFieldElement; readonly schema: Schema; }; type FormFieldPreviewProps> = { readonly value: ReturnType; onChange(value: ReturnType): void; readonly schema: Schema; }; type ObjectFieldPreviewProps, ChildFieldElement> = { readonly fields: { readonly [Key in keyof Schema['fields']]: GenericPreviewProps; }; onChange(value: { readonly [Key in keyof Schema['fields']]?: InitialOrUpdateValueFromComponentPropField; }): void; readonly schema: Schema; }; type ConditionalFieldPreviewProps, any>, ChildFieldElement> = { readonly [Key in keyof Schema['values']]: { readonly discriminant: DiscriminantStringToDiscriminantValue; onChange>(discriminant: Discriminant, value?: InitialOrUpdateValueFromComponentPropField): void; readonly value: GenericPreviewProps; readonly schema: Schema; }; }[keyof Schema['values']]; type ArrayFieldPreviewProps, ChildFieldElement> = { readonly elements: readonly (GenericPreviewProps & { readonly key: string; })[]; readonly onChange: (value: readonly { key: string | undefined; value?: InitialOrUpdateValueFromComponentPropField; }[]) => void; readonly schema: Schema; }; export type GenericPreviewProps = Schema extends ChildField ? ChildFieldPreviewProps : Schema extends FormField ? FormFieldPreviewProps : Schema extends ObjectField ? ObjectFieldPreviewProps : Schema extends ConditionalField ? ConditionalFieldPreviewProps : Schema extends ArrayField ? ArrayFieldPreviewProps : never; export type PreviewProps = GenericPreviewProps; export type InitialOrUpdateValueFromComponentPropField = Schema extends ChildField ? undefined : Schema extends FormField ? ParsedValue | undefined : Schema extends ObjectField ? { readonly [Key in keyof Value]?: InitialOrUpdateValueFromComponentPropField; } : Schema extends ConditionalField ? { readonly [Key in keyof Values]: { readonly discriminant: DiscriminantStringToDiscriminantValue; readonly value?: InitialOrUpdateValueFromComponentPropField; }; }[keyof Values] : Schema extends ArrayField ? readonly { key: string | undefined; value?: InitialOrUpdateValueFromComponentPropField; }[] : never; type DiscriminantStringToDiscriminantValue, DiscriminantString extends PropertyKey> = ReturnType extends boolean ? 'true' extends DiscriminantString ? true : 'false' extends DiscriminantString ? false : never : DiscriminantString & string; export type PreviewPropsForToolbar = GenericPreviewProps; export declare function component(options: { /** The preview component shown in the editor */ preview: (props: PreviewProps> & { onRemove(): void; }) => ReactElement | null; /** The schema for the props that the preview component, toolbar and rendered component will receive */ schema: Schema; /** The label to show in the insert menu and chrome around the block if chromeless is false */ label: string; /** An icon to show in the toolbar for this component block. Component blocks with `toolbarIcon` are shown in the toolbar directly instead of the insert menu */ toolbarIcon?: ReactElement; } & ({ chromeless: true; toolbar?: null | ((props: { props: PreviewPropsForToolbar>; onRemove(): void; }) => ReactElement); } | { chromeless?: false; toolbar?: (props: { props: PreviewPropsForToolbar>; onShowEditMode(): void; onRemove(): void; }) => ReactElement; })): ComponentBlock; type Comp = (props: Props) => ReactElement | null; export type ParsedValueForComponentSchema = Schema extends ChildField ? null : Schema extends FormField ? Value : Schema extends ObjectField ? { readonly [Key in keyof Value]: ParsedValueForComponentSchema; } : Schema extends ConditionalField ? { readonly [Key in keyof Values]: { readonly discriminant: DiscriminantStringToDiscriminantValue; readonly value: ParsedValueForComponentSchema; }; }[keyof Values] : Schema extends ArrayField ? readonly ParsedValueForComponentSchema[] : never; export type ValueForReading = Schema extends ChildField ? null : Schema extends ContentFormField ? () => Promise : Schema extends BasicFormField ? Value : Schema extends SlugFormField ? Value : Schema extends AssetFormField ? Value : Schema extends AssetsFormField ? Value : Schema extends ObjectField ? { readonly [Key in keyof Value]: ValueForReading; } : Schema extends ConditionalField ? { readonly [Key in keyof Values]: { readonly discriminant: DiscriminantStringToDiscriminantValue; readonly value: ValueForReading; }; }[keyof Values] : Schema extends ArrayField ? readonly ValueForReading[] : never; export type ValueForReadingDeep = Schema extends ChildField ? null : Schema extends FormField ? Value : Schema extends ObjectField ? { readonly [Key in keyof Value]: ValueForReadingDeep; } : Schema extends ConditionalField ? { readonly [Key in keyof Values]: { readonly discriminant: DiscriminantStringToDiscriminantValue; readonly value: ValueForReadingDeep; }; }[keyof Values] : Schema extends ArrayField ? readonly ValueForReadingDeep[] : never; export type InferRenderersForComponentBlocks>> = { [Key in keyof ComponentBlocks]: Comp>>; };