import { defineComponent, validateCustomApiName, type ComponentDefinition } from './component'; import type { JsonValue } from '../custom-object-page-layout'; import type { DefinedFunction } from './function'; type CanvasGridFields = { x?: number; y?: number; width?: number; height?: number; defaultWidth?: number; defaultHeight?: number; previousWidth?: number; previousHeight?: number; minWidth?: number; minHeight?: number; disableVerticalResize?: boolean; } & Record; export type CanvasGridPosition = CanvasGridFields & { x: number; y: number; width: number; height: number }; export type CanvasGridProperties = CanvasGridFields & { position: CanvasGridPosition }; export type CanvasPropertyMeta = { isExpression?: boolean } & Record; export type CanvasEventHandler = { event: string; type: string; properties: Record; } & Record; export type CanvasPropertyValues = { eventHandlers?: CanvasEventHandler[] | null; } & Record; export type CanvasProperties = { values?: CanvasPropertyValues | null; meta?: Record | null; } & Record; export type CanvasActionProperties = CanvasProperties & { values?: (CanvasPropertyValues & { functionApiName?: string | null }) | null; }; export type CanvasMedia = { name: string; mime_type: string; s3_bucket: string; s3_key: string; /** Decimal string or number; numeric strings are validated by the server during installation. */ aspect_ratio?: `${number}` | number; }; export type CanvasVersion = { major: number; minor: number }; export type CanvasComponent = { uuid: string; slug: string; type: string; gridProperties: CanvasGridProperties; properties?: CanvasProperties; parentComponent?: string | null; layoutContainer?: string | null; }; export type CanvasAction = { uuid: string; slug: string; type: string; properties?: CanvasActionProperties; }; export type CanvasVariable = { uuid: string; slug: string; type?: string; name?: string | null; description?: string | null; value?: string | null; properties: CanvasProperties; }; export interface DefineCanvasInstanceProps { apiName: `${string}__c`; name: string | null; components: CanvasComponent[]; actions?: CanvasAction[] | null; canvasActions?: CanvasAction[] | null; variables?: CanvasVariable[] | null; media?: Record | null; version?: CanvasVersion | null; /** Source ID from an extracted config; never used as the Canvas identity. */ sourceId?: string | null; /** Function definitions referenced by actions, included in the manifest. */ functions?: readonly DefinedFunction[]; } export interface DefinedCanvasInstance { readonly apiName: string; toDict(): { type: 'CANVAS_INSTANCE'; api_name: string; identity_format_version: 2; name: string | null; components: CanvasComponent[]; actions?: CanvasAction[] | null; canvas_actions?: CanvasAction[] | null; variables?: CanvasVariable[] | null; media?: Record | null; version?: CanvasVersion | null; obj_id?: string | null; }; } /** Defines Canvas metadata. Nested components and actions use the backend's wire format. */ export function defineCanvasInstance(props: DefineCanvasInstanceProps): DefinedCanvasInstance { const { apiName } = props; validateCustomApiName(apiName); return canvasInstanceComponent.register( { apiName, toDict: () => ({ type: 'CANVAS_INSTANCE' as const, api_name: apiName, identity_format_version: 2 as const, name: props.name, components: props.components, ...(props.actions === undefined ? {} : { actions: props.actions }), ...(props.canvasActions === undefined ? {} : { canvas_actions: props.canvasActions }), ...(props.variables === undefined ? {} : { variables: props.variables }), ...(props.media === undefined ? {} : { media: props.media }), ...(props.version === undefined ? {} : { version: props.version }), ...(props.sourceId === undefined ? {} : { obj_id: props.sourceId }), }), }, props, ); } const canvasInstanceComponent: ComponentDefinition = defineComponent({ type: 'CANVAS_INSTANCE', define: defineCanvasInstance, references: (_definition, props) => () => props.functions ?? [], });