| 1 | /** |
| 2 | * Types for DOM-based PPTX export system |
| 3 | */ |
| 4 | |
| 5 | // Position and dimensions in pixels (relative to slide container) |
| 6 | export interface ElementPosition { |
| 7 | x: number; |
| 8 | y: number; |
| 9 | width: number; |
| 10 | height: number; |
| 11 | /** Original pixel aspect ratio (width/height) for preserving shape integrity in PPT export */ |
| 12 | aspectRatio?: number; |
| 13 | /** Which dimension to preserve when using aspectRatio: 'width' recalculates height, 'height' recalculates width */ |
| 14 | aspectRatioBase?: "width" | "height"; |
| 15 | /** Center the resized aspect-ratio box within the original measured bounds */ |
| 16 | centerAspectRatio?: boolean; |
| 17 | } |
| 18 | |
| 19 | // Text styling extracted from DOM |
| 20 | interface TextStyles { |
| 21 | fontFamily: string; |
| 22 | fontSize: number; // in px |
| 23 | fontWeight: string | number; |
| 24 | color: string; // hex color |
| 25 | backgroundColor?: string; |
| 26 | textAlign?: "left" | "center" | "right" | "justify"; |
| 27 | textDecoration?: string; |
| 28 | fontStyle?: string; |
| 29 | lineHeight?: number; |
| 30 | bold?: boolean; |
| 31 | italic?: boolean; |
| 32 | underline?: boolean; |
| 33 | } |
| 34 | |
| 35 | // Border styling |
| 36 | interface BorderStyles { |
| 37 | width: number; |
| 38 | color: string; |
| 39 | style: string; |
| 40 | radius?: number; |
| 41 | } |
| 42 | |
| 43 | // Element types we extract |
| 44 | // Element types we extract |
| 45 | type ExportElementType = |
| 46 | | "text" |
| 47 | | "table" |
| 48 | | "image" |
| 49 | | "decor" |
| 50 | | "shape" |
| 51 | | "backgroundRect"; |
| 52 | |
| 53 | // Base export element |
| 54 | interface BaseExportElement { |
| 55 | type: ExportElementType; |
| 56 | position: ElementPosition; |
| 57 | borderStyles?: BorderStyles; |
| 58 | backgroundColor?: string; |
| 59 | borderRadius?: string; |
| 60 | } |
| 61 | |
| 62 | // Text element (simple text block) |
| 63 | export interface TextExportElement extends BaseExportElement { |
| 64 | type: "text"; |
| 65 | textContent: string; |
| 66 | textStyles: TextStyles; |
| 67 | /** Original PlateJS node type (e.g., "h1", "h2", "p", "blockquote") for standard font sizing */ |
| 68 | nodeType?: string; |
| 69 | } |
| 70 | |
| 71 | // Table cell |
| 72 | export interface TableCell { |
| 73 | text: string; |
| 74 | isHeader: boolean; |
| 75 | colSpan?: number; |
| 76 | rowSpan?: number; |
| 77 | backgroundColor?: string; |
| 78 | textStyles?: TextStyles; |
| 79 | widthRatio?: number; // Deprecated in favor of box |
| 80 | box?: { |
| 81 | x: number; |
| 82 | y: number; |
| 83 | width: number; |
| 84 | height: number; |
| 85 | }; |
| 86 | } |
| 87 | |
| 88 | // Table row |
| 89 | export interface TableRow { |
| 90 | cells: TableCell[]; |
| 91 | } |
| 92 | |
| 93 | // Table element |
| 94 | export interface TableExportElement extends BaseExportElement { |
| 95 | type: "table"; |
| 96 | rows: TableRow[]; |
| 97 | headerRowCount?: number; |
| 98 | } |
| 99 | |
| 100 | // Image element (in-editor images, not root image) |
| 101 | export interface ImageExportElement extends BaseExportElement { |
| 102 | type: "image"; |
| 103 | url: string; |
| 104 | alt?: string; |
| 105 | imageSource?: "generate" | "search" | "gif" | "upload"; |
| 106 | sizing?: "contain" | "cover" | "fill"; |
| 107 | stockImageProvider?: string; |
| 108 | } |
| 109 | |
| 110 | // Decorative element with data-decor attribute |
| 111 | export interface DecorExportElement extends BaseExportElement { |
| 112 | type: "decor"; |
| 113 | decorType: string; |
| 114 | base64Data?: string; |
| 115 | sizing: "contain" | "cover" | "fill"; |
| 116 | } |
| 117 | |
| 118 | export type NativeShapeType = |
| 119 | | "arrow" |
| 120 | | "pill" |
| 121 | | "parallelogram" |
| 122 | | "rect" |
| 123 | | "ellipse"; |
| 124 | |
| 125 | // Native Shape element (for arrows, pills, parallelograms, and timeline marks) |
| 126 | export interface ShapeExportElement extends BaseExportElement { |
| 127 | type: "shape"; |
| 128 | shapeType: NativeShapeType; |
| 129 | orientation: "horizontal" | "vertical"; |
| 130 | fillColor: string; |
| 131 | textContent?: string; |
| 132 | textColor?: string; |
| 133 | } |
| 134 | |
| 135 | // Background rectangle element (for component backgrounds like box-item, cycle-item) |
| 136 | export interface BackgroundRectExportElement extends BaseExportElement { |
| 137 | type: "backgroundRect"; |
| 138 | fillColor: string; // Background color (hex) |
| 139 | cornerRadius?: number; // In pixels |
| 140 | borderColor?: string; // Border color if present |
| 141 | borderWidth?: number; // Border width in pixels |
| 142 | background?: string; // Full CSS background string for gradient support |
| 143 | } |
| 144 | |
| 145 | // Union type for all export elements |
| 146 | export type ExportElement = |
| 147 | | TextExportElement |
| 148 | | TableExportElement |
| 149 | | ImageExportElement |
| 150 | | DecorExportElement |
| 151 | | ShapeExportElement |
| 152 | | BackgroundRectExportElement; |
| 153 | |
| 154 | // Scanned slide data |
| 155 | export interface ScanResult { |
| 156 | slideId: string; |
| 157 | width: number; // px |
| 158 | height: number; // px |
| 159 | /** Untransformed source slide width used for px-to-PPT font conversion */ |
| 160 | sourceWidth: number; |
| 161 | /** Untransformed source slide height */ |
| 162 | sourceHeight: number; |
| 163 | elements: ExportElement[]; |
| 164 | // Resolved presentation styles |
| 165 | styles: PresentationStyles; |
| 166 | // Root image data (scanned from DOM) |
| 167 | rootImage?: RootImageData; |
| 168 | // Background image URL (for "background" layout type) |
| 169 | backgroundImageUrl?: string; |
| 170 | } |
| 171 | |
| 172 | // Resolved presentation styles from CSS variables |
| 173 | export interface PresentationStyles { |
| 174 | // Colors |
| 175 | primaryColor: string; |
| 176 | secondaryColor: string; |
| 177 | accentColor: string; |
| 178 | backgroundColor: string; |
| 179 | textColor: string; |
| 180 | headingColor: string; |
| 181 | cardBackground: string; |
| 182 | |
| 183 | // Fonts |
| 184 | headingFont: string; |
| 185 | bodyFont: string; |
| 186 | |
| 187 | cardBorderRadius: string; |
| 188 | slideBorderRadius: string; |
| 189 | buttonBorderRadius: string; |
| 190 | |
| 191 | // Shadows |
| 192 | cardShadow: string; |
| 193 | buttonShadow: string; |
| 194 | slideShadow: string; |
| 195 | |
| 196 | // Transitions |
| 197 | transition: string; |
| 198 | |
| 199 | // Other |
| 200 | smartLayoutColor: string; |
| 201 | |
| 202 | // Mask |
| 203 | mask?: { |
| 204 | clipPath?: string; |
| 205 | maskImage?: string; |
| 206 | maskSize?: string; |
| 207 | maskPosition?: string; |
| 208 | maskRepeat?: string; |
| 209 | }; |
| 210 | // Background image URL for slides with background layout |
| 211 | backgroundImageUrl?: string; |
| 212 | } |
| 213 | |
| 214 | // Root image data |
| 215 | export interface RootImageData { |
| 216 | url: string; // Either original URL or base64 data URL |
| 217 | position: ElementPosition; |
| 218 | isBase64?: boolean; // True if url is base64 data (captured image) |
| 219 | originalUrl?: string; // Original URL of the image (before capture) |
| 220 | imageSource?: "generate" | "search" | "gif" | "upload"; |
| 221 | stockImageProvider?: string; |
| 222 | } |
| 223 |