@lit-pigeon/core 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,752 @@
1
+ export declare function addColumn(rowId: string): Command;
2
+
3
+ /**
4
+ * Either a built-in {@link ContentBlock} or a registry-defined
5
+ * {@link CustomBlock}. Use this where code must accept plugin blocks as well as
6
+ * the built-ins (e.g. `createBlock`, canvas/MJML registry dispatch).
7
+ */
8
+ export declare type AnyBlock = ContentBlock | CustomBlock;
9
+
10
+ /**
11
+ * A managed image / file asset. Lives in an `AssetStorage` so editors and
12
+ * AI tools can search, tag, and reuse it without re-uploading.
13
+ */
14
+ export declare interface Asset {
15
+ /** Stable, URL-safe slug — used as the storage key. */
16
+ id: string;
17
+ /** Human-readable display name. */
18
+ name: string;
19
+ /** Public URL of the underlying file. */
20
+ src: string;
21
+ /** Accessibility alt text. Recommended for every image. */
22
+ alt?: string;
23
+ /** MIME type (e.g. `image/png`). */
24
+ mimeType?: string;
25
+ /** Total bytes. Useful for {@link AssetStorage.list} filtering. */
26
+ sizeBytes?: number;
27
+ /** Pixel width when known. */
28
+ width?: number;
29
+ /** Pixel height when known. */
30
+ height?: number;
31
+ /** Folder path (`/marketing/Q3`). Defaults to `/` (root). */
32
+ folder?: string;
33
+ /** Free-form tags for search + filtering. */
34
+ tags?: string[];
35
+ createdAt: string;
36
+ updatedAt: string;
37
+ }
38
+
39
+ /** Filters accepted by {@link AssetStorage.list}. */
40
+ export declare interface AssetListFilter {
41
+ /** Restrict to a folder path. Pass `/` for the root or omit for all folders. */
42
+ folder?: string;
43
+ /** Free-text search over `name`, `alt`, and `tags`. Case-insensitive. */
44
+ search?: string;
45
+ /** Restrict to assets that match every tag in this list. */
46
+ tags?: string[];
47
+ /** Pagination: max items to return. Default unlimited. */
48
+ limit?: number;
49
+ /** Pagination: skip this many items. Default 0. */
50
+ offset?: number;
51
+ }
52
+
53
+ export declare interface AssetManagerConfig {
54
+ enabled?: boolean;
55
+ uploadUrl?: string;
56
+ uploadHeaders?: Record<string, string>;
57
+ acceptedTypes?: string[];
58
+ maxFileSize?: number;
59
+ uploadHandler?: (file: File) => Promise<string>;
60
+ presignedUpload?: {
61
+ getUploadParams: (file: File) => Promise<PresignedUploadParams>;
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Pluggable persistence for image / file assets. Mirrors `TemplateStorage`
67
+ * and `BrandKitStorage`. Listing returns assets newest-first so picker UIs
68
+ * surface recent uploads at the top.
69
+ */
70
+ export declare interface AssetStorage {
71
+ list(filter?: AssetListFilter): Promise<Asset[]>;
72
+ get(id: string): Promise<Asset | null>;
73
+ save(asset: Asset): Promise<void>;
74
+ delete(id: string): Promise<void>;
75
+ /** Distinct folder paths in use across the store. */
76
+ listFolders(): Promise<string[]>;
77
+ }
78
+
79
+ export declare interface BlockDefinition {
80
+ type: string;
81
+ label: string;
82
+ icon: string;
83
+ defaultValues: Record<string, unknown>;
84
+ /**
85
+ * Declarative property form for a custom block. When set, selecting the
86
+ * block in the editor renders these fields (instead of just its label) and
87
+ * writes edits back to the block's `values`. Pairs with `renderCanvas` /
88
+ * `renderMjml` to make a registry block fully editable without forking.
89
+ */
90
+ propertySchema?: PropertyField[];
91
+ /**
92
+ * Optional canvas renderer for a custom block. Returns an HTML string shown
93
+ * in the editor canvas. Without it, a custom block renders as a labelled
94
+ * placeholder chip instead of failing. Built-in blocks ignore this — they
95
+ * have dedicated canvas components.
96
+ */
97
+ renderCanvas?: (block: RegisteredBlock) => string;
98
+ /**
99
+ * Optional MJML renderer for a custom block, used on export. Returns an MJML
100
+ * fragment (e.g. `<mj-text>…</mj-text>`). Without it, the block is emitted as
101
+ * an MJML comment and effectively skipped.
102
+ */
103
+ renderMjml?: (block: RegisteredBlock) => string;
104
+ }
105
+
106
+ export declare type BlockType = ContentBlock['type'];
107
+
108
+ /**
109
+ * A single saved color in a brand kit. Hex (`#rrggbb`/`#rgb`) recommended;
110
+ * any CSS color string is accepted at storage time.
111
+ */
112
+ export declare interface BrandColor {
113
+ /** Stable, URL-safe slug used as the storage key. */
114
+ id: string;
115
+ name: string;
116
+ value: string;
117
+ }
118
+
119
+ /**
120
+ * A saved font family with the weights the brand uses. `family` is the
121
+ * value that will appear in CSS `font-family`, including fallbacks.
122
+ */
123
+ export declare interface BrandFont {
124
+ id: string;
125
+ name: string;
126
+ family: string;
127
+ weights?: number[];
128
+ /** Where to load the webfont from, e.g. a Google Fonts URL. */
129
+ url?: string;
130
+ }
131
+
132
+ /**
133
+ * The full saved brand kit. Multiple kits can coexist (different sub-brands,
134
+ * regions, or seasonal palettes) so the storage layer is keyed by id.
135
+ */
136
+ export declare interface BrandKit {
137
+ id: string;
138
+ name: string;
139
+ description?: string;
140
+ colors: BrandColor[];
141
+ fonts: BrandFont[];
142
+ logos: BrandLogo[];
143
+ createdAt: string;
144
+ updatedAt: string;
145
+ }
146
+
147
+ /**
148
+ * Pluggable persistence for brand kits. Mirrors {@link TemplateStorage}.
149
+ */
150
+ export declare interface BrandKitStorage {
151
+ list(): Promise<BrandKit[]>;
152
+ get(id: string): Promise<BrandKit | null>;
153
+ save(kit: BrandKit): Promise<void>;
154
+ delete(id: string): Promise<void>;
155
+ }
156
+
157
+ /** A saved logo asset — typically a transparent-background image. */
158
+ export declare interface BrandLogo {
159
+ id: string;
160
+ name: string;
161
+ /** Public URL of the logo asset. */
162
+ src: string;
163
+ /** Width hint in px used when pre-populating logo-bearing blocks. */
164
+ width?: number;
165
+ }
166
+
167
+ export declare interface ButtonBlock {
168
+ id: string;
169
+ type: 'button';
170
+ values: {
171
+ content: string;
172
+ href: string;
173
+ backgroundColor: string;
174
+ textColor: string;
175
+ borderRadius: number;
176
+ padding: Spacing;
177
+ innerPadding: Spacing;
178
+ fontSize: number;
179
+ fontWeight: string;
180
+ alignment: 'left' | 'center' | 'right';
181
+ fullWidth: boolean;
182
+ };
183
+ }
184
+
185
+ export declare function canRedo(history: HistoryState): boolean;
186
+
187
+ export declare function canUndo(history: HistoryState): boolean;
188
+
189
+ export declare interface ColumnNode {
190
+ id: string;
191
+ type: 'column';
192
+ attributes: {
193
+ backgroundColor?: string;
194
+ padding: Spacing;
195
+ borderRadius?: number;
196
+ verticalAlign: 'top' | 'middle' | 'bottom';
197
+ };
198
+ blocks: ContentBlock[];
199
+ }
200
+
201
+ export declare type Command = (state: EditorStateSnapshot, dispatch?: (tr: TransactionSnapshot) => void) => boolean;
202
+
203
+ export declare type ContentBlock = TextBlock | ImageBlock | ButtonBlock | DividerBlock | SpacerBlock | SocialBlock | HtmlBlock | HeroBlock | NavBarBlock;
204
+
205
+ export declare function createBlock(type: BlockType, overrides?: Partial<ContentBlock['values']>): ContentBlock;
206
+
207
+ export declare function createBlock(type: string, overrides?: Record<string, unknown>): AnyBlock;
208
+
209
+ export declare function createBlockSelection(rowId: string, columnId: string, blockId: string): Selection_2;
210
+
211
+ export declare function createBodySelection(): Selection_2;
212
+
213
+ export declare function createColumn(blocks?: ContentBlock[]): ColumnNode;
214
+
215
+ export declare function createColumnSelection(rowId: string, columnId: string): Selection_2;
216
+
217
+ export declare function createDefaultDocument(name?: string): PigeonDocument;
218
+
219
+ export declare function createDocStep(type: string, path: string, recipe: (doc: PigeonDocument) => void, invertRecipe: (doc: PigeonDocument) => void): Step;
220
+
221
+ export declare function createHistoryPlugin(): PigeonPlugin;
222
+
223
+ export declare function createRow(columns?: ColumnNode[], columnRatios?: number[]): RowNode;
224
+
225
+ export declare function createRowSelection(rowId: string): Selection_2;
226
+
227
+ /**
228
+ * A block whose `type` was contributed at runtime via the block registry
229
+ * (`registerBlock`) rather than being one of the built-in {@link ContentBlock}
230
+ * kinds. Its `values` are an open record because the editor core can't know a
231
+ * plugin block's shape ahead of time.
232
+ */
233
+ export declare interface CustomBlock {
234
+ id: string;
235
+ type: string;
236
+ values: Record<string, unknown>;
237
+ }
238
+
239
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
240
+
241
+ export declare function defaultSpacing(all?: number): Spacing;
242
+
243
+ export declare function deleteBlock(rowId: string, columnId: string, blockId: string): Command;
244
+
245
+ export declare function deleteRow(rowId: string): Command;
246
+
247
+ export declare interface DividerBlock {
248
+ id: string;
249
+ type: 'divider';
250
+ values: {
251
+ borderColor: string;
252
+ borderWidth: number;
253
+ borderStyle: 'solid' | 'dashed' | 'dotted';
254
+ padding: Spacing;
255
+ width: string;
256
+ };
257
+ }
258
+
259
+ export declare function duplicateBlock(rowId: string, columnId: string, blockId: string): Command;
260
+
261
+ export declare function duplicateRow(rowId: string): Command;
262
+
263
+ export declare interface EditorConfig {
264
+ doc?: PigeonDocument;
265
+ plugins?: PigeonPlugin[];
266
+ assetManager?: AssetManagerConfig;
267
+ mergeTags?: MergeTagConfig;
268
+ /**
269
+ * Optional persistent asset library. When supplied, the asset modal shows
270
+ * a "Library" tab next to "Upload" so users can pick from previously saved
271
+ * assets without re-uploading. The data layer lives in `@lit-pigeon/core`
272
+ * (`AssetStorage`) and a filesystem-backed implementation ships in
273
+ * `@lit-pigeon/mcp-server` (`FsAssetStorage`).
274
+ */
275
+ assetStorage?: AssetStorage;
276
+ /**
277
+ * Optional brand kit (or storage for multiple kits) — saved colors and
278
+ * fonts can be surfaced as palette swatches in the property panels' color
279
+ * pickers and font-family pickers. When a `BrandKit` is passed it is used
280
+ * directly; a `BrandKitStorage` is resolved lazily on demand.
281
+ */
282
+ brandKit?: BrandKit | BrandKitStorage;
283
+ }
284
+
285
+ export declare class EditorState {
286
+ readonly doc: PigeonDocument;
287
+ readonly selection: Selection_2 | null;
288
+ readonly plugins: Map<string, unknown>;
289
+ private readonly _pluginList;
290
+ private constructor();
291
+ static create(config?: EditorConfig): EditorState;
292
+ createTransaction(): Transaction;
293
+ apply(tr: TransactionSnapshot): EditorState;
294
+ getPluginState<T>(pluginName: string): T | undefined;
295
+ }
296
+
297
+ export declare interface EditorStateSnapshot {
298
+ readonly doc: PigeonDocument;
299
+ readonly selection: Selection_2 | null;
300
+ readonly plugins: Map<string, unknown>;
301
+ createTransaction(): TransactionSnapshot;
302
+ }
303
+
304
+ export declare function generateId(): string;
305
+
306
+ export declare function getAllBlockDefinitions(): BlockDefinition[];
307
+
308
+ export declare function getBlockDefinition(type: string): BlockDefinition | undefined;
309
+
310
+ export declare function getDefaultValues(type: BlockType): ContentBlock['values'];
311
+
312
+ export declare function getStarterTemplate(id: string): Template | null;
313
+
314
+ export declare function getStarterTemplates(): Template[];
315
+
316
+ export declare interface HeroBlock {
317
+ id: string;
318
+ type: 'hero';
319
+ values: {
320
+ backgroundUrl: string;
321
+ backgroundPosition: 'center center' | 'top center' | 'bottom center' | 'left center' | 'right center';
322
+ mode: 'fixed-height' | 'fluid-height';
323
+ width: number;
324
+ height: number;
325
+ verticalAlign: 'top' | 'middle' | 'bottom';
326
+ padding: Spacing;
327
+ innerPadding: Spacing;
328
+ backgroundColor: string;
329
+ content: string;
330
+ };
331
+ }
332
+
333
+ export declare const HISTORY_PLUGIN_NAME = "history";
334
+
335
+ declare interface HistoryEntry {
336
+ steps: Step[];
337
+ doc: PigeonDocument;
338
+ timestamp: number;
339
+ }
340
+
341
+ export declare interface HistoryState {
342
+ undoStack: HistoryEntry[];
343
+ redoStack: HistoryEntry[];
344
+ }
345
+
346
+ export declare interface HtmlBlock {
347
+ id: string;
348
+ type: 'html';
349
+ values: {
350
+ content: string;
351
+ padding: Spacing;
352
+ };
353
+ }
354
+
355
+ export declare interface ImageBlock {
356
+ id: string;
357
+ type: 'image';
358
+ values: {
359
+ src: string;
360
+ alt: string;
361
+ width: number | 'auto';
362
+ href?: string;
363
+ padding: Spacing;
364
+ alignment: 'left' | 'center' | 'right';
365
+ borderRadius?: number;
366
+ };
367
+ }
368
+
369
+ /**
370
+ * Default `AssetStorage` — Map-backed, per-process. Search, folder filter,
371
+ * and tag filter are all client-side; for very large libraries, back this
372
+ * with an indexed storage (S3 + DynamoDB / Postgres / etc.).
373
+ */
374
+ export declare class InMemoryAssetStorage implements AssetStorage {
375
+ private readonly _byId;
376
+ constructor(opts?: InMemoryAssetStorageOptions);
377
+ list(filter?: AssetListFilter): Promise<Asset[]>;
378
+ get(id: string): Promise<Asset | null>;
379
+ save(asset: Asset): Promise<void>;
380
+ delete(id: string): Promise<void>;
381
+ listFolders(): Promise<string[]>;
382
+ }
383
+
384
+ export declare interface InMemoryAssetStorageOptions {
385
+ seed?: Asset[];
386
+ }
387
+
388
+ /**
389
+ * Default `BrandKitStorage` — `Map`-backed, per-process. Mirrors
390
+ * `InMemoryTemplateStorage`: deep-clones on read so callers can't poison
391
+ * the store by mutating returned objects.
392
+ */
393
+ export declare class InMemoryBrandKitStorage implements BrandKitStorage {
394
+ private readonly _byId;
395
+ constructor(opts?: InMemoryBrandKitStorageOptions);
396
+ list(): Promise<BrandKit[]>;
397
+ get(id: string): Promise<BrandKit | null>;
398
+ save(kit: BrandKit): Promise<void>;
399
+ delete(id: string): Promise<void>;
400
+ }
401
+
402
+ export declare interface InMemoryBrandKitStorageOptions {
403
+ /** Brand kits to seed the store with on construction. */
404
+ seed?: BrandKit[];
405
+ }
406
+
407
+ /**
408
+ * Default `TemplateStorage` implementation — backs templates in a `Map`
409
+ * inside a single process. Suitable for the editor's default config, the
410
+ * MCP server's per-session lifetime, and unit tests.
411
+ *
412
+ * Consumers that need persistence should implement `TemplateStorage` directly
413
+ * (e.g. wrapping localStorage, a REST endpoint, or the filesystem).
414
+ */
415
+ export declare class InMemoryTemplateStorage implements TemplateStorage {
416
+ private readonly _byId;
417
+ constructor(opts?: InMemoryTemplateStorageOptions);
418
+ list(): Promise<Template[]>;
419
+ get(id: string): Promise<Template | null>;
420
+ save(template: Template): Promise<void>;
421
+ delete(id: string): Promise<void>;
422
+ }
423
+
424
+ export declare interface InMemoryTemplateStorageOptions {
425
+ /** When true (default), the storage is seeded with the built-in starter templates. */
426
+ includeStarters?: boolean;
427
+ /** Additional templates to seed alongside the starters. */
428
+ seed?: Template[];
429
+ }
430
+
431
+ export declare function insertBlock(rowId: string, columnId: string, block: ContentBlock, index?: number): Command;
432
+
433
+ export declare function insertRow(row: RowNode, index?: number): Command;
434
+
435
+ export declare function isKnownBlockType(type: string): type is BlockType;
436
+
437
+ export declare function isValidDocument(doc: unknown): doc is PigeonDocument;
438
+
439
+ export declare interface MergeTag {
440
+ name: string;
441
+ label: string;
442
+ category?: string;
443
+ sample?: string;
444
+ }
445
+
446
+ export declare interface MergeTagConfig {
447
+ trigger?: string;
448
+ tags?: MergeTag[];
449
+ }
450
+
451
+ export declare function moveBlock(fromRowId: string, fromColumnId: string, blockId: string, toRowId: string, toColumnId: string, toIndex: number): Command;
452
+
453
+ export declare function moveRow(rowId: string, toIndex: number): Command;
454
+
455
+ export declare interface NavBarBlock {
456
+ id: string;
457
+ type: 'navbar';
458
+ values: {
459
+ links: NavLink[];
460
+ hamburger: 'hamburger' | 'none';
461
+ alignment: 'left' | 'center' | 'right';
462
+ padding: Spacing;
463
+ linkColor: string;
464
+ linkFontSize: number;
465
+ linkPadding: string;
466
+ };
467
+ }
468
+
469
+ export declare interface NavLink {
470
+ href: string;
471
+ text: string;
472
+ color?: string;
473
+ fontWeight?: string;
474
+ textDecoration?: string;
475
+ padding?: string;
476
+ }
477
+
478
+ export declare interface PigeonDocument {
479
+ version: '1.0';
480
+ metadata: {
481
+ name: string;
482
+ previewText?: string;
483
+ createdAt: string;
484
+ updatedAt: string;
485
+ };
486
+ body: {
487
+ attributes: {
488
+ width: number;
489
+ backgroundColor: string;
490
+ fontFamily: string;
491
+ contentAlignment: 'center' | 'left';
492
+ };
493
+ rows: RowNode[];
494
+ };
495
+ }
496
+
497
+ export declare interface PigeonPlugin {
498
+ name: string;
499
+ init?(state: EditorStateSnapshot): unknown;
500
+ apply?(tr: TransactionSnapshot, pluginState: unknown): unknown;
501
+ onStateChange?(newState: EditorStateSnapshot, oldState: EditorStateSnapshot): void;
502
+ blocks?: BlockDefinition[];
503
+ commands?: Record<string, Command>;
504
+ }
505
+
506
+ export declare class PluginRegistry {
507
+ private _plugins;
508
+ register(plugin: PigeonPlugin): void;
509
+ unregister(name: string): void;
510
+ get(name: string): PigeonPlugin | undefined;
511
+ getAll(): PigeonPlugin[];
512
+ getCommands(): Record<string, Command>;
513
+ has(name: string): boolean;
514
+ }
515
+
516
+ export declare interface PresignedUploadParams {
517
+ uploadUrl: string;
518
+ publicUrl: string;
519
+ method?: 'PUT' | 'POST';
520
+ headers?: Record<string, string>;
521
+ fields?: Record<string, string>;
522
+ }
523
+
524
+ /**
525
+ * A single editable field in a custom block's property panel. The editor
526
+ * renders the matching control and writes changes back to `block.values[key]`.
527
+ */
528
+ export declare interface PropertyField {
529
+ /** Key within the block's `values` this field reads and writes. */
530
+ key: string;
531
+ label: string;
532
+ type: 'text' | 'textarea' | 'number' | 'color' | 'checkbox' | 'select';
533
+ placeholder?: string;
534
+ /** For `number` fields. */
535
+ min?: number;
536
+ max?: number;
537
+ step?: number;
538
+ /** For `select` fields. */
539
+ options?: Array<{
540
+ label: string;
541
+ value: string;
542
+ }>;
543
+ }
544
+
545
+ export declare function redo(state: EditorStateSnapshot, dispatch?: (tr: TransactionSnapshot) => void): boolean;
546
+
547
+ export declare function registerBlock(definition: BlockDefinition): void;
548
+
549
+ /**
550
+ * The minimal block shape passed to a {@link BlockDefinition}'s render hooks.
551
+ * Structurally compatible with both built-in `ContentBlock`s and registry
552
+ * `CustomBlock`s.
553
+ */
554
+ export declare interface RegisteredBlock {
555
+ id: string;
556
+ type: string;
557
+ values: Record<string, unknown>;
558
+ }
559
+
560
+ export declare function removeColumn(rowId: string, columnId: string): Command;
561
+
562
+ export declare interface Renderer {
563
+ render(doc: PigeonDocument, options?: RenderOptions): Promise<RenderResult>;
564
+ }
565
+
566
+ export declare interface RenderError {
567
+ message: string;
568
+ line?: number;
569
+ tagName?: string;
570
+ }
571
+
572
+ export declare interface RenderOptions {
573
+ minify?: boolean;
574
+ inlineCss?: boolean;
575
+ beautify?: boolean;
576
+ /**
577
+ * When true (default), the MJML renderer injects Outlook (mso) and
578
+ * dark-mode rendering workarounds: a heading-margin reset `<mj-style>`,
579
+ * dark-mode color-scheme `<meta>` tags, and an `[if mso]` conditional
580
+ * block with Arial fallback and blockquote margin reset.
581
+ * Set to false to opt out (useful for testing the bare renderer output).
582
+ */
583
+ outlookWorkarounds?: boolean;
584
+ }
585
+
586
+ export declare interface RenderResult {
587
+ html: string;
588
+ errors: RenderError[];
589
+ }
590
+
591
+ export declare function resizeColumns(rowId: string, ratios: number[]): Command;
592
+
593
+ export declare interface RowNode {
594
+ id: string;
595
+ type: 'row';
596
+ attributes: {
597
+ backgroundColor?: string;
598
+ backgroundImage?: string;
599
+ padding: Spacing;
600
+ fullWidth: boolean;
601
+ /**
602
+ * Optional display condition. When set, the row only renders when the
603
+ * expression is truthy in the sending platform's template engine. The
604
+ * renderer wraps the section in `{{#if <condition>}} … {{/if}}` (Handlebars
605
+ * / Liquid-style, passed through verbatim), e.g. `condition: "user.premium"`.
606
+ */
607
+ condition?: string;
608
+ };
609
+ columns: ColumnNode[];
610
+ columnRatios: number[];
611
+ locked: boolean;
612
+ }
613
+
614
+ declare interface Selection_2 {
615
+ type: 'block' | 'row' | 'column' | 'body';
616
+ rowId?: string;
617
+ columnId?: string;
618
+ blockId?: string;
619
+ }
620
+ export { Selection_2 as Selection }
621
+
622
+ export declare function selectionsEqual(a: Selection_2 | null, b: Selection_2 | null): boolean;
623
+
624
+ export declare interface SocialBlock {
625
+ id: string;
626
+ type: 'social';
627
+ values: {
628
+ icons: SocialIcon[];
629
+ iconSize: number;
630
+ spacing: number;
631
+ alignment: 'left' | 'center' | 'right';
632
+ padding: Spacing;
633
+ };
634
+ }
635
+
636
+ export declare interface SocialIcon {
637
+ type: 'facebook' | 'twitter' | 'instagram' | 'linkedin' | 'youtube' | 'tiktok' | 'custom';
638
+ href: string;
639
+ label?: string;
640
+ iconUrl?: string;
641
+ }
642
+
643
+ export declare interface SpacerBlock {
644
+ id: string;
645
+ type: 'spacer';
646
+ values: {
647
+ height: number;
648
+ };
649
+ }
650
+
651
+ export declare interface Spacing {
652
+ top: number;
653
+ right: number;
654
+ bottom: number;
655
+ left: number;
656
+ }
657
+
658
+ export declare interface Step {
659
+ type: string;
660
+ path: string;
661
+ apply(doc: PigeonDocument): PigeonDocument;
662
+ invert(doc: PigeonDocument): Step;
663
+ }
664
+
665
+ export declare interface Template {
666
+ /** Stable, URL-safe slug. Doubles as filename when persisted. */
667
+ id: string;
668
+ /** Display name shown in pickers. */
669
+ name: string;
670
+ /** One-line summary used in template galleries. */
671
+ description?: string;
672
+ /** Optional category for grouping in UI. */
673
+ category?: TemplateCategory;
674
+ /** Optional preview image — base64 data URL or absolute URL. */
675
+ thumbnail?: string;
676
+ /** The full PigeonDocument the template materialises. */
677
+ document: PigeonDocument;
678
+ /** ISO-8601 timestamps. */
679
+ createdAt: string;
680
+ updatedAt: string;
681
+ }
682
+
683
+ export declare type TemplateCategory = 'welcome' | 'newsletter' | 'transactional' | 'promo' | 'announcement' | 'other';
684
+
685
+ /**
686
+ * Pluggable persistence layer for templates. The editor ships with an
687
+ * in-memory implementation that includes the starter templates; consumers
688
+ * implement this interface to back templates with localStorage, a REST
689
+ * endpoint, IndexedDB, or the filesystem.
690
+ */
691
+ export declare interface TemplateStorage {
692
+ list(): Promise<Template[]>;
693
+ get(id: string): Promise<Template | null>;
694
+ save(template: Template): Promise<void>;
695
+ delete(id: string): Promise<void>;
696
+ }
697
+
698
+ export declare interface TextBlock {
699
+ id: string;
700
+ type: 'text';
701
+ values: {
702
+ content: string;
703
+ padding: Spacing;
704
+ lineHeight: string;
705
+ textAlign: 'left' | 'center' | 'right';
706
+ };
707
+ }
708
+
709
+ export declare class Transaction {
710
+ private _steps;
711
+ private _selection;
712
+ private _selectionSet;
713
+ private _meta;
714
+ private _doc;
715
+ constructor(doc: PigeonDocument);
716
+ get steps(): ReadonlyArray<Step>;
717
+ get selection(): Selection_2 | null;
718
+ get selectionSet(): boolean;
719
+ get meta(): ReadonlyMap<string, unknown>;
720
+ get doc(): PigeonDocument;
721
+ addStep(step: Step): this;
722
+ setSelection(sel: Selection_2 | null): this;
723
+ setMeta(key: string, value: unknown): this;
724
+ getMeta(key: string): unknown;
725
+ }
726
+
727
+ export declare interface TransactionSnapshot {
728
+ readonly doc: PigeonDocument;
729
+ readonly steps: readonly Step[];
730
+ readonly selection: Selection_2 | null;
731
+ readonly selectionSet: boolean;
732
+ readonly meta: ReadonlyMap<string, unknown>;
733
+ addStep(step: Step): TransactionSnapshot;
734
+ setSelection(sel: Selection_2 | null): TransactionSnapshot;
735
+ setMeta(key: string, value: unknown): TransactionSnapshot;
736
+ getMeta(key: string): unknown;
737
+ }
738
+
739
+ export declare function undo(state: EditorStateSnapshot, dispatch?: (tr: TransactionSnapshot) => void): boolean;
740
+
741
+ export declare function updateBlock(rowId: string, columnId: string, blockId: string, values: Record<string, unknown>): Command;
742
+
743
+ export declare function updateRowAttributes(rowId: string, attributes: Partial<RowNode['attributes']>): Command;
744
+
745
+ export declare function validateDocument(doc: unknown): ValidationError[];
746
+
747
+ export declare interface ValidationError {
748
+ path: string;
749
+ message: string;
750
+ }
751
+
752
+ export { }