@formfeed/engine 0.3.9 → 0.3.11

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.
Files changed (49) hide show
  1. package/index.cjs +2471 -354
  2. package/index.js +2471 -354
  3. package/package.json +1 -1
  4. package/types/frame/fit.d.cts +13 -0
  5. package/types/frame/fit.d.ts +13 -0
  6. package/types/frame/fit.entry.d.cts +1 -0
  7. package/types/frame/fit.entry.d.ts +1 -0
  8. package/types/frame/stage.d.cts +22 -0
  9. package/types/frame/stage.d.ts +22 -0
  10. package/types/frame/stage.entry.d.cts +1 -0
  11. package/types/frame/stage.entry.d.ts +1 -0
  12. package/types/frame/text-edit.d.cts +75 -0
  13. package/types/frame/text-edit.d.ts +75 -0
  14. package/types/frame/text-edit.entry.d.cts +1 -0
  15. package/types/frame/text-edit.entry.d.ts +1 -0
  16. package/types/index.d.cts +21 -14
  17. package/types/index.d.ts +21 -14
  18. package/types/lib/assemble.d.cts +5 -0
  19. package/types/lib/assemble.d.ts +5 -0
  20. package/types/lib/design/emit.d.cts +20 -0
  21. package/types/lib/design/emit.d.ts +20 -0
  22. package/types/lib/design/fonts.d.cts +27 -0
  23. package/types/lib/design/fonts.d.ts +27 -0
  24. package/types/lib/design/hash.d.cts +6 -0
  25. package/types/lib/design/hash.d.ts +6 -0
  26. package/types/lib/design/index.d.cts +12 -0
  27. package/types/lib/design/index.d.ts +12 -0
  28. package/types/lib/design/layers.d.cts +12 -0
  29. package/types/lib/design/layers.d.ts +12 -0
  30. package/types/lib/design/parse.d.cts +25 -0
  31. package/types/lib/design/parse.d.ts +25 -0
  32. package/types/lib/design/starters.d.cts +14 -0
  33. package/types/lib/design/starters.d.ts +14 -0
  34. package/types/lib/design/types.d.cts +171 -0
  35. package/types/lib/design/types.d.ts +171 -0
  36. package/types/lib/dialect.d.cts +32 -0
  37. package/types/lib/dialect.d.ts +32 -0
  38. package/types/lib/generated/frames.d.cts +6 -0
  39. package/types/lib/generated/frames.d.ts +6 -0
  40. package/types/lib/preview.d.cts +16 -2
  41. package/types/lib/preview.d.ts +16 -2
  42. package/types/lib/source-edit.d.cts +112 -0
  43. package/types/lib/source-edit.d.ts +112 -0
  44. package/types/lib/source-positions.d.cts +12 -3
  45. package/types/lib/source-positions.d.ts +12 -3
  46. package/types/lib/source-scan.d.cts +61 -0
  47. package/types/lib/source-scan.d.ts +61 -0
  48. package/types/lib/translation.d.cts +17 -0
  49. package/types/lib/translation.d.ts +17 -0
@@ -0,0 +1,14 @@
1
+ import { type CanvasSize, type DesignDocument } from './types.cjs';
2
+ /**
3
+ * Designs a new image template can start from (plan 16 §4.2). Titles stay English here; the app words
4
+ * them per locale by `id`. Sample data uses the placeholders of CLAUDE.md, never names that could be
5
+ * real.
6
+ */
7
+ export interface DesignStarter {
8
+ id: 'blank' | 'article' | 'quote' | 'event';
9
+ title: string;
10
+ size: CanvasSize;
11
+ design: DesignDocument;
12
+ sampleData: Record<string, unknown>;
13
+ }
14
+ export declare const designStarters: DesignStarter[];
@@ -0,0 +1,14 @@
1
+ import { type CanvasSize, type DesignDocument } from './types.js';
2
+ /**
3
+ * Designs a new image template can start from (plan 16 §4.2). Titles stay English here; the app words
4
+ * them per locale by `id`. Sample data uses the placeholders of CLAUDE.md, never names that could be
5
+ * real.
6
+ */
7
+ export interface DesignStarter {
8
+ id: 'blank' | 'article' | 'quote' | 'event';
9
+ title: string;
10
+ size: CanvasSize;
11
+ design: DesignDocument;
12
+ sampleData: Record<string, unknown>;
13
+ }
14
+ export declare const designStarters: DesignStarter[];
@@ -0,0 +1,171 @@
1
+ /**
2
+ * A visual design (plan 16 §4.1): the layer model the editor's canvas edits, stored as
3
+ * `settings.design` and turned into the template's body and CSS by `emitDesign`. Renders never read
4
+ * it; the emitted HTML is the template. Coordinates are CSS pixels of the image, whose size stays in
5
+ * `settings.image`.
6
+ */
7
+ export declare const DESIGN_VERSION = 1;
8
+ /** A colour: a literal, or a brand kit colour by name with the literal it falls back to. */
9
+ export type Paint = {
10
+ color: string;
11
+ } | {
12
+ brand: string;
13
+ fallback: string;
14
+ };
15
+ export interface Shadow {
16
+ x: number;
17
+ y: number;
18
+ blur: number;
19
+ color: string;
20
+ }
21
+ export interface Stroke {
22
+ width: number;
23
+ paint: Paint;
24
+ }
25
+ /** A font: a family by source, or one of the brand kit's two. */
26
+ export type FontChoice = {
27
+ family: string;
28
+ source: 'google' | 'organisation' | 'system';
29
+ } | {
30
+ brand: 'heading' | 'body';
31
+ };
32
+ /** How a data value is shown: through one of the helpers every engine has. */
33
+ export type TextFormat = {
34
+ helper: 'upper' | 'lower' | 'title' | 'money';
35
+ } | {
36
+ helper: 'number';
37
+ decimals: number;
38
+ } | {
39
+ helper: 'date';
40
+ pattern: string;
41
+ } | {
42
+ helper: 'truncate';
43
+ length: number;
44
+ } | {
45
+ helper: 'default';
46
+ value: string;
47
+ };
48
+ /** Text of a text layer: literal text, a data path (a chip in the editor), a line break. */
49
+ export type TextItem = {
50
+ text: string;
51
+ } | {
52
+ path: string;
53
+ format?: TextFormat;
54
+ } | {
55
+ break: true;
56
+ };
57
+ export interface TextStyle {
58
+ font: FontChoice;
59
+ weight: number;
60
+ size: number;
61
+ lineHeight: number;
62
+ letterSpacing: number;
63
+ color: Paint;
64
+ align: 'left' | 'center' | 'right' | 'justify';
65
+ italic?: boolean;
66
+ uppercase?: boolean;
67
+ underline?: boolean;
68
+ /** A line through the text; with `underline` both lines are drawn. */
69
+ strike?: boolean;
70
+ }
71
+ /** Where an image comes from; an empty `url`, `asset` or `path` is one not chosen yet (`imageIsEmpty`). */
72
+ export type ImageSource = {
73
+ url: string;
74
+ } | {
75
+ asset: string;
76
+ } | {
77
+ path: string;
78
+ } | {
79
+ brandLogo: 'primary' | 'inverse' | 'mark';
80
+ };
81
+ /** What a code encodes: literal text or a data path. */
82
+ export type Binding = {
83
+ text: string;
84
+ } | {
85
+ path: string;
86
+ };
87
+ export type BarcodeSymbology = 'code128' | 'ean13' | 'ean8' | 'upca' | 'itf14' | 'code39';
88
+ export interface LayerBase {
89
+ /** Stable, `[a-z][a-z0-9-]{0,31}`: the class `l-<id>` and `data-ff-layer`. Never renamed. */
90
+ id: string;
91
+ /** What the layers panel shows. */
92
+ name: string;
93
+ x: number;
94
+ y: number;
95
+ width: number;
96
+ height: number;
97
+ /** Degrees, clockwise like CSS. */
98
+ rotation: number;
99
+ opacity: number;
100
+ /** False: the layer is not emitted at all. */
101
+ visible: boolean;
102
+ /** Editor only. */
103
+ locked?: boolean;
104
+ /** Emitted inside an if block: shown only when the data path has a value. */
105
+ showWhen?: {
106
+ path: string;
107
+ } | null;
108
+ radius?: number;
109
+ shadow?: Shadow | null;
110
+ stroke?: Stroke | null;
111
+ }
112
+ export interface TextLayer extends LayerBase {
113
+ type: 'text';
114
+ content: TextItem[];
115
+ style: TextStyle;
116
+ /** `fixed` clips, `shrink` makes the text smaller until it fits (`data-ff-fit`), `grow` lets the box grow. */
117
+ sizing: 'fixed' | 'shrink' | 'grow';
118
+ minFontSize?: number;
119
+ maxLines?: number;
120
+ valign: 'top' | 'middle' | 'bottom';
121
+ fill?: Paint | null;
122
+ padding?: number;
123
+ }
124
+ export interface ImageLayer extends LayerBase {
125
+ type: 'image';
126
+ source: ImageSource;
127
+ fit: 'cover' | 'contain' | 'fill';
128
+ /** Which point stays in view when `cover` crops, in percent. */
129
+ focus?: {
130
+ x: number;
131
+ y: number;
132
+ };
133
+ }
134
+ export interface ShapeLayer extends LayerBase {
135
+ type: 'shape';
136
+ shape: 'rectangle' | 'ellipse' | 'line';
137
+ fill: Paint | null;
138
+ }
139
+ export interface QrLayer extends LayerBase {
140
+ type: 'qr';
141
+ value: Binding;
142
+ ecc: 'L' | 'M' | 'Q' | 'H';
143
+ color: Paint;
144
+ background: Paint | null;
145
+ }
146
+ export interface BarcodeLayer extends LayerBase {
147
+ type: 'barcode';
148
+ value: Binding;
149
+ symbology: BarcodeSymbology;
150
+ showText: boolean;
151
+ }
152
+ export type DesignLayer = TextLayer | ImageLayer | ShapeLayer | QrLayer | BarcodeLayer;
153
+ export type LayerType = DesignLayer['type'];
154
+ export interface DesignDocument {
155
+ version: typeof DESIGN_VERSION;
156
+ /** Hash of the body and CSS the emitter last wrote (`designOutputHash`); other code means it was edited. */
157
+ output: string;
158
+ /** The canvas colour; null is transparent, which only shows when `settings.image.transparent` is set. */
159
+ background: Paint | null;
160
+ /** Bottom to top: the stacking order is the order in the HTML. */
161
+ layers: DesignLayer[];
162
+ guides?: {
163
+ x: number[];
164
+ y: number[];
165
+ };
166
+ }
167
+ /** The image a design is drawn on, from `settings.image`. */
168
+ export interface CanvasSize {
169
+ width: number;
170
+ height: number;
171
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * A visual design (plan 16 §4.1): the layer model the editor's canvas edits, stored as
3
+ * `settings.design` and turned into the template's body and CSS by `emitDesign`. Renders never read
4
+ * it; the emitted HTML is the template. Coordinates are CSS pixels of the image, whose size stays in
5
+ * `settings.image`.
6
+ */
7
+ export declare const DESIGN_VERSION = 1;
8
+ /** A colour: a literal, or a brand kit colour by name with the literal it falls back to. */
9
+ export type Paint = {
10
+ color: string;
11
+ } | {
12
+ brand: string;
13
+ fallback: string;
14
+ };
15
+ export interface Shadow {
16
+ x: number;
17
+ y: number;
18
+ blur: number;
19
+ color: string;
20
+ }
21
+ export interface Stroke {
22
+ width: number;
23
+ paint: Paint;
24
+ }
25
+ /** A font: a family by source, or one of the brand kit's two. */
26
+ export type FontChoice = {
27
+ family: string;
28
+ source: 'google' | 'organisation' | 'system';
29
+ } | {
30
+ brand: 'heading' | 'body';
31
+ };
32
+ /** How a data value is shown: through one of the helpers every engine has. */
33
+ export type TextFormat = {
34
+ helper: 'upper' | 'lower' | 'title' | 'money';
35
+ } | {
36
+ helper: 'number';
37
+ decimals: number;
38
+ } | {
39
+ helper: 'date';
40
+ pattern: string;
41
+ } | {
42
+ helper: 'truncate';
43
+ length: number;
44
+ } | {
45
+ helper: 'default';
46
+ value: string;
47
+ };
48
+ /** Text of a text layer: literal text, a data path (a chip in the editor), a line break. */
49
+ export type TextItem = {
50
+ text: string;
51
+ } | {
52
+ path: string;
53
+ format?: TextFormat;
54
+ } | {
55
+ break: true;
56
+ };
57
+ export interface TextStyle {
58
+ font: FontChoice;
59
+ weight: number;
60
+ size: number;
61
+ lineHeight: number;
62
+ letterSpacing: number;
63
+ color: Paint;
64
+ align: 'left' | 'center' | 'right' | 'justify';
65
+ italic?: boolean;
66
+ uppercase?: boolean;
67
+ underline?: boolean;
68
+ /** A line through the text; with `underline` both lines are drawn. */
69
+ strike?: boolean;
70
+ }
71
+ /** Where an image comes from; an empty `url`, `asset` or `path` is one not chosen yet (`imageIsEmpty`). */
72
+ export type ImageSource = {
73
+ url: string;
74
+ } | {
75
+ asset: string;
76
+ } | {
77
+ path: string;
78
+ } | {
79
+ brandLogo: 'primary' | 'inverse' | 'mark';
80
+ };
81
+ /** What a code encodes: literal text or a data path. */
82
+ export type Binding = {
83
+ text: string;
84
+ } | {
85
+ path: string;
86
+ };
87
+ export type BarcodeSymbology = 'code128' | 'ean13' | 'ean8' | 'upca' | 'itf14' | 'code39';
88
+ export interface LayerBase {
89
+ /** Stable, `[a-z][a-z0-9-]{0,31}`: the class `l-<id>` and `data-ff-layer`. Never renamed. */
90
+ id: string;
91
+ /** What the layers panel shows. */
92
+ name: string;
93
+ x: number;
94
+ y: number;
95
+ width: number;
96
+ height: number;
97
+ /** Degrees, clockwise like CSS. */
98
+ rotation: number;
99
+ opacity: number;
100
+ /** False: the layer is not emitted at all. */
101
+ visible: boolean;
102
+ /** Editor only. */
103
+ locked?: boolean;
104
+ /** Emitted inside an if block: shown only when the data path has a value. */
105
+ showWhen?: {
106
+ path: string;
107
+ } | null;
108
+ radius?: number;
109
+ shadow?: Shadow | null;
110
+ stroke?: Stroke | null;
111
+ }
112
+ export interface TextLayer extends LayerBase {
113
+ type: 'text';
114
+ content: TextItem[];
115
+ style: TextStyle;
116
+ /** `fixed` clips, `shrink` makes the text smaller until it fits (`data-ff-fit`), `grow` lets the box grow. */
117
+ sizing: 'fixed' | 'shrink' | 'grow';
118
+ minFontSize?: number;
119
+ maxLines?: number;
120
+ valign: 'top' | 'middle' | 'bottom';
121
+ fill?: Paint | null;
122
+ padding?: number;
123
+ }
124
+ export interface ImageLayer extends LayerBase {
125
+ type: 'image';
126
+ source: ImageSource;
127
+ fit: 'cover' | 'contain' | 'fill';
128
+ /** Which point stays in view when `cover` crops, in percent. */
129
+ focus?: {
130
+ x: number;
131
+ y: number;
132
+ };
133
+ }
134
+ export interface ShapeLayer extends LayerBase {
135
+ type: 'shape';
136
+ shape: 'rectangle' | 'ellipse' | 'line';
137
+ fill: Paint | null;
138
+ }
139
+ export interface QrLayer extends LayerBase {
140
+ type: 'qr';
141
+ value: Binding;
142
+ ecc: 'L' | 'M' | 'Q' | 'H';
143
+ color: Paint;
144
+ background: Paint | null;
145
+ }
146
+ export interface BarcodeLayer extends LayerBase {
147
+ type: 'barcode';
148
+ value: Binding;
149
+ symbology: BarcodeSymbology;
150
+ showText: boolean;
151
+ }
152
+ export type DesignLayer = TextLayer | ImageLayer | ShapeLayer | QrLayer | BarcodeLayer;
153
+ export type LayerType = DesignLayer['type'];
154
+ export interface DesignDocument {
155
+ version: typeof DESIGN_VERSION;
156
+ /** Hash of the body and CSS the emitter last wrote (`designOutputHash`); other code means it was edited. */
157
+ output: string;
158
+ /** The canvas colour; null is transparent, which only shows when `settings.image.transparent` is set. */
159
+ background: Paint | null;
160
+ /** Bottom to top: the stacking order is the order in the HTML. */
161
+ layers: DesignLayer[];
162
+ guides?: {
163
+ x: number[];
164
+ y: number[];
165
+ };
166
+ }
167
+ /** The image a design is drawn on, from `settings.image`. */
168
+ export interface CanvasSize {
169
+ width: number;
170
+ height: number;
171
+ }
@@ -0,0 +1,32 @@
1
+ import type { EngineId } from './types.cjs';
2
+ /**
3
+ * Template syntax per engine, for code that writes templates: the snippet library (spec 06 §2) and
4
+ * the design emitter (plan 16 §4.2). Jinja2 passes filter arguments in parentheses, Liquid after a
5
+ * colon (and cannot build object literals, so options are keyword arguments), Handlebars calls
6
+ * helpers with positional arguments and a hash.
7
+ */
8
+ /** Handlebars has no loop variable: inside `{{#each}}` the item's fields are read directly. */
9
+ export declare const loop: (engine: EngineId, item: string, list: string, body: string) => string;
10
+ /** An expression, optionally through one filter written the Jinja2 way (`date('dd.MM.yyyy')`). */
11
+ export declare const val: (engine: EngineId, expr: string, filter?: string) => string;
12
+ export declare const ifElse: (engine: EngineId, cond: string, then: string, otherwise: string) => string;
13
+ /** A `t` call with optional placeholder params (`{ rate: 'invoice.vat_rate' }`, values are expressions). */
14
+ export declare const tr: (engine: EngineId, key: string, params?: Record<string, string>) => string;
15
+ /** `body` only when `cond` has a value. */
16
+ export declare const ifBlock: (engine: EngineId, cond: string, body: string) => string;
17
+ /**
18
+ * A string literal the engine reads back as `value`. Liquid has no escapes, so it takes whichever
19
+ * quote the value lacks and turns an apostrophe into a typographic one when it contains both.
20
+ */
21
+ export declare function stringLiteral(engine: EngineId, value: string): string;
22
+ /**
23
+ * `input` through a filter with literal-or-expression arguments, as one output tag: Jinja2
24
+ * `{{ x | f(a, b) }}`, Liquid `{{ x | f: a, b }}`, Handlebars `{{f x a b}}`.
25
+ */
26
+ export declare function filterCall(engine: EngineId, input: string, name: string, args?: string[]): string;
27
+ /**
28
+ * A helper that takes an input and named options, as one output tag: Jinja2
29
+ * `{{ f(x, { a: 1 }) }}`, Liquid `{{ x | f: a: 1 }}`, Handlebars `{{f x a=1}}`. Option values are
30
+ * expressions or literals the caller wrote with `stringLiteral`.
31
+ */
32
+ export declare function helperCall(engine: EngineId, name: string, input: string, options?: Record<string, string>): string;
@@ -0,0 +1,32 @@
1
+ import type { EngineId } from './types.js';
2
+ /**
3
+ * Template syntax per engine, for code that writes templates: the snippet library (spec 06 §2) and
4
+ * the design emitter (plan 16 §4.2). Jinja2 passes filter arguments in parentheses, Liquid after a
5
+ * colon (and cannot build object literals, so options are keyword arguments), Handlebars calls
6
+ * helpers with positional arguments and a hash.
7
+ */
8
+ /** Handlebars has no loop variable: inside `{{#each}}` the item's fields are read directly. */
9
+ export declare const loop: (engine: EngineId, item: string, list: string, body: string) => string;
10
+ /** An expression, optionally through one filter written the Jinja2 way (`date('dd.MM.yyyy')`). */
11
+ export declare const val: (engine: EngineId, expr: string, filter?: string) => string;
12
+ export declare const ifElse: (engine: EngineId, cond: string, then: string, otherwise: string) => string;
13
+ /** A `t` call with optional placeholder params (`{ rate: 'invoice.vat_rate' }`, values are expressions). */
14
+ export declare const tr: (engine: EngineId, key: string, params?: Record<string, string>) => string;
15
+ /** `body` only when `cond` has a value. */
16
+ export declare const ifBlock: (engine: EngineId, cond: string, body: string) => string;
17
+ /**
18
+ * A string literal the engine reads back as `value`. Liquid has no escapes, so it takes whichever
19
+ * quote the value lacks and turns an apostrophe into a typographic one when it contains both.
20
+ */
21
+ export declare function stringLiteral(engine: EngineId, value: string): string;
22
+ /**
23
+ * `input` through a filter with literal-or-expression arguments, as one output tag: Jinja2
24
+ * `{{ x | f(a, b) }}`, Liquid `{{ x | f: a, b }}`, Handlebars `{{f x a b}}`.
25
+ */
26
+ export declare function filterCall(engine: EngineId, input: string, name: string, args?: string[]): string;
27
+ /**
28
+ * A helper that takes an input and named options, as one output tag: Jinja2
29
+ * `{{ f(x, { a: 1 }) }}`, Liquid `{{ x | f: a: 1 }}`, Handlebars `{{f x a=1}}`. Option values are
30
+ * expressions or literals the caller wrote with `stringLiteral`.
31
+ */
32
+ export declare function helperCall(engine: EngineId, name: string, input: string, options?: Record<string, string>): string;
@@ -0,0 +1,6 @@
1
+ /** Bundled from src/frame/text-edit.entry.ts. */
2
+ export declare const textEditRuntime = "\"use strict\";(()=>{var H=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function R(s,l={}){let g=l.clicks!==!1,p=l.live===!0,o=s.document,i=null,a=null,c=e=>{try{s.parent.postMessage(e,\"*\")}catch{}},b=o.createElement(\"style\");b.setAttribute(\"data-formfeed\",\"edit\"),b.setAttribute(\"data-pagedjs-ignore\",\"\"),b.textContent=H,(o.head??o.documentElement).appendChild(b),g&&o.documentElement.classList.add(\"ff-edit-mode\");let D=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;o.addEventListener(\"click\",e=>{if(!g)return;if(i&&!i.done&&i.element.contains(e.target)){e.stopImmediatePropagation();return}let t=D(e.target);if(!t)return;e.preventDefault(),e.stopImmediatePropagation(),i&&!i.done&&y();let n=t.getAttribute(\"data-ff-src\")??\"\",r=t.getBoundingClientRect();a={src:n,element:t,x:e.clientX,y:e.clientY},c({type:\"formfeed:edit-request\",src:n,edit:t.getAttribute(\"data-ff-edit\"),text:t.textContent??\"\",count:o.querySelectorAll(`[data-ff-src=\"${n.replace(/\"/g,\"\")}\"]`).length,split:t.hasAttribute(\"data-split-from\")||t.hasAttribute(\"data-split-to\"),rect:{left:r.left,top:r.top,width:r.width,height:r.height}})},!0),o.addEventListener(\"keydown\",e=>{if(!g||i&&!i.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),c({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),s.addEventListener(\"message\",e=>{if(e.source!==s.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?F(t):(t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\")&&(a=null,i&&!i.done&&h(!1)))});function F(e){i&&!i.done&&h(!1);let t=e.layer?o.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):a&&a.src===e.src?a.element:o.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),n=e.at,r=e.layer?n&&Number.isFinite(n.x)&&Number.isFinite(n.y)?{x:Number(n.x),y:Number(n.y)}:null:a&&a.src===e.src?a:null;if(a=null,!t||!Array.isArray(e.items)){c({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let m=Array.from(t.childNodes),f=o.createDocumentFragment();for(let u of e.items)if(u.kind===\"text\")f.appendChild(o.createTextNode(String(u.text)));else if(u.kind===\"break\")f.appendChild(o.createElement(\"br\"));else if(u.kind===\"chip\"){let d=o.createElement(\"span\");d.className=\"ff-chip\",d.setAttribute(\"data-ff-chip\",String(u.index)),d.setAttribute(\"contenteditable\",\"false\"),u.title&&(d.title=String(u.title)),d.textContent=String(u.text),f.appendChild(d)}for(let u of m)t.removeChild(u);t.appendChild(f),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,i={token:String(e.token),element:t,saved:m,allowBreaks:e.allowBreaks===!0,badge:e.note?B(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",E),t.addEventListener(\"beforeinput\",v),t.addEventListener(\"paste\",C),t.addEventListener(\"drop\",L),t.addEventListener(\"focusout\",A),p&&t.addEventListener(\"input\",x),t.focus(),e.select===\"all\"?w(t):P(t,r),c({type:\"formfeed:edit-started\",token:i.token}),typeof e.insert==\"string\"&&e.insert&&k(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function k(e){if(typeof o.execCommand==\"function\"&&o.execCommand(\"insertText\",!1,e))return;let t=s.getSelection(),n=t&&t.rangeCount?t.getRangeAt(0):null;n&&(n.deleteContents(),n.insertNode(o.createTextNode(e)),n.collapse(!1),p&&x())}function x(){i&&!i.done&&c({type:\"formfeed:edit-input\",token:i.token,items:S(i.element)})}function B(e,t){let n=o.createElement(\"div\");n.className=\"ff-edit-badge\",n.textContent=t;let r=e.getBoundingClientRect();return n.style.left=`${r.left+s.scrollX}px`,n.style.top=`${Math.max(0,r.top+s.scrollY-22)}px`,o.body.appendChild(n),n}function w(e){let t=s.getSelection();if(!t)return;let n=o.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}function P(e,t){let n=s.getSelection();if(!n)return;let r=null,m=o;if(t){if(m.caretRangeFromPoint)r=m.caretRangeFromPoint(t.x,t.y);else if(m.caretPositionFromPoint){let f=m.caretPositionFromPoint(t.x,t.y);f&&(r=o.createRange(),r.setStart(f.offsetNode,f.offset))}}if(!r||!e.contains(r.startContainer))r=o.createRange(),r.selectNodeContents(e),r.collapse(!1);else if(t){let f=r.startContainer,d=(f.nodeType===1?f:f.parentElement)?.closest(\"[data-ff-chip]\")??null;if(d&&d!==e&&e.contains(d)){let N=d.getBoundingClientRect();r=o.createRange(),t.x<N.left+N.width/2?r.setStartBefore(d):r.setStartAfter(d),r.collapse(!0)}}n.removeAllRanges(),n.addRange(r)}function E(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),h(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),y()):t===\"Enter\"?(e.preventDefault(),i?.allowBreaks&&M()):t===\"Tab\"?(e.preventDefault(),y()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),p&&i&&!e.altKey&&c({type:\"formfeed:edit-style\",token:i.token,key:t.toLowerCase()}))}function v(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function C(e){e.preventDefault(),k((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function L(e){e.preventDefault()}function A(){s.setTimeout(()=>{i&&!i.done&&(!o.hasFocus()||!i.element.contains(o.activeElement))&&y()},0)}function M(){let e=s.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let n=o.createElement(\"br\");t.insertNode(n),n.nextSibling||n.parentNode?.appendChild(o.createElement(\"br\"));let r=o.createRange();r.setStartAfter(n),r.collapse(!0),e.removeAllRanges(),e.addRange(r)}function T(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",E),t.removeEventListener(\"beforeinput\",v),t.removeEventListener(\"paste\",C),t.removeEventListener(\"drop\",L),t.removeEventListener(\"focusout\",A),t.removeEventListener(\"input\",x),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),i===e&&(i=null)}function y(){let e=i;if(!e||e.done)return;let t=S(e.element);T(e),c({type:\"formfeed:edit-commit\",token:e.token,items:t})}function h(e){let t=i;if(!t||t.done)return;let n=t.element;for(;n.firstChild;)n.removeChild(n.firstChild);for(let r of t.saved)n.appendChild(r);T(t),e&&c({type:\"formfeed:edit-cancel\",token:t.token})}}function S(s){let l=[],g=o=>{let i=l[l.length-1];i?.kind===\"text\"?i.text+=o:o&&l.push({kind:\"text\",text:o})},p=o=>{for(let i of Array.from(o.childNodes))if(i.nodeType===3)g(i.data);else if(i.nodeType===1){let a=i,c=a.getAttribute(\"data-ff-chip\");c!==null?l.push({kind:\"chip\",index:Number(c)}):a.tagName===\"BR\"?l.push({kind:\"break\"}):((a.tagName===\"DIV\"||a.tagName===\"P\")&&l.length&&l.push({kind:\"break\"}),p(a))}};for(p(s);l[l.length-1]?.kind===\"break\";)l.pop();return l}R(window);})();";
3
+ /** Bundled from src/frame/fit.entry.ts. */
4
+ export declare const fitRuntime = "\"use strict\";(()=>{function a(t,e,n){if(e===t)return t.scrollHeight<=t.clientHeight+.5&&t.scrollWidth<=t.clientWidth+.5;let o=n.getComputedStyle(t),i=t.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);return e.scrollHeight<=i+.5&&e.scrollWidth<=e.clientWidth+.5}function m(t,e){let n=t.firstElementChild??t;n.style.fontSize=\"\";let o=parseFloat(e.getComputedStyle(n).fontSize)||16,i=Math.min(o,parseFloat(t.getAttribute(\"data-ff-fit-min\")??\"\")||o/2);if(a(t,n,e))return o;let l=i,s=o;for(let d=0;d<14;d++){let r=(l+s)/2;n.style.fontSize=`${r}px`,a(t,n,e)?l=r:s=r}let f=Math.floor(l*100)/100;return n.style.fontSize=`${f}px`,f}function c(t){let e=()=>{for(let o of Array.from(t.document.querySelectorAll('[data-ff-fit=\"shrink\"]')))m(o,t);t.document.documentElement.setAttribute(\"data-ff-fit\",\"done\")};t.formfeedFit=e;let n=t.document.fonts;n?n.ready.then(e):t.addEventListener(\"load\",e)}c(window);})();";
5
+ /** Bundled from src/frame/stage.entry.ts. */
6
+ export declare const stageRuntime = "\"use strict\";(()=>{var I=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function D(a,l={}){let f=l.clicks!==!1,c=l.live===!0,o=a.document,n=null,s=null,u=e=>{try{a.parent.postMessage(e,\"*\")}catch{}},p=o.createElement(\"style\");p.setAttribute(\"data-formfeed\",\"edit\"),p.setAttribute(\"data-pagedjs-ignore\",\"\"),p.textContent=I,(o.head??o.documentElement).appendChild(p),f&&o.documentElement.classList.add(\"ff-edit-mode\");let d=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;o.addEventListener(\"click\",e=>{if(!f)return;if(n&&!n.done&&n.element.contains(e.target)){e.stopImmediatePropagation();return}let t=d(e.target);if(!t)return;e.preventDefault(),e.stopImmediatePropagation(),n&&!n.done&&v();let r=t.getAttribute(\"data-ff-src\")??\"\",i=t.getBoundingClientRect();s={src:r,element:t,x:e.clientX,y:e.clientY},u({type:\"formfeed:edit-request\",src:r,edit:t.getAttribute(\"data-ff-edit\"),text:t.textContent??\"\",count:o.querySelectorAll(`[data-ff-src=\"${r.replace(/\"/g,\"\")}\"]`).length,split:t.hasAttribute(\"data-split-from\")||t.hasAttribute(\"data-split-to\"),rect:{left:i.left,top:i.top,width:i.width,height:i.height}})},!0),o.addEventListener(\"keydown\",e=>{if(!f||n&&!n.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),u({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),a.addEventListener(\"message\",e=>{if(e.source!==a.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?b(t):(t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\")&&(s=null,n&&!n.done&&L(!1)))});function b(e){n&&!n.done&&L(!1);let t=e.layer?o.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):s&&s.src===e.src?s.element:o.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),r=e.at,i=e.layer?r&&Number.isFinite(r.x)&&Number.isFinite(r.y)?{x:Number(r.x),y:Number(r.y)}:null:s&&s.src===e.src?s:null;if(s=null,!t||!Array.isArray(e.items)){u({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let x=Array.from(t.childNodes),g=o.createDocumentFragment();for(let y of e.items)if(y.kind===\"text\")g.appendChild(o.createTextNode(String(y.text)));else if(y.kind===\"break\")g.appendChild(o.createElement(\"br\"));else if(y.kind===\"chip\"){let m=o.createElement(\"span\");m.className=\"ff-chip\",m.setAttribute(\"data-ff-chip\",String(y.index)),m.setAttribute(\"contenteditable\",\"false\"),y.title&&(m.title=String(y.title)),m.textContent=String(y.text),g.appendChild(m)}for(let y of x)t.removeChild(y);t.appendChild(g),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,n={token:String(e.token),element:t,saved:x,allowBreaks:e.allowBreaks===!0,badge:e.note?E(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",C),t.addEventListener(\"beforeinput\",S),t.addEventListener(\"paste\",A),t.addEventListener(\"drop\",T),t.addEventListener(\"focusout\",N),c&&t.addEventListener(\"input\",k),t.focus(),e.select===\"all\"?H(t):M(t,i),u({type:\"formfeed:edit-started\",token:n.token}),typeof e.insert==\"string\"&&e.insert&&h(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function h(e){if(typeof o.execCommand==\"function\"&&o.execCommand(\"insertText\",!1,e))return;let t=a.getSelection(),r=t&&t.rangeCount?t.getRangeAt(0):null;r&&(r.deleteContents(),r.insertNode(o.createTextNode(e)),r.collapse(!1),c&&k())}function k(){n&&!n.done&&u({type:\"formfeed:edit-input\",token:n.token,items:w(n.element)})}function E(e,t){let r=o.createElement(\"div\");r.className=\"ff-edit-badge\",r.textContent=t;let i=e.getBoundingClientRect();return r.style.left=`${i.left+a.scrollX}px`,r.style.top=`${Math.max(0,i.top+a.scrollY-22)}px`,o.body.appendChild(r),r}function H(e){let t=a.getSelection();if(!t)return;let r=o.createRange();r.selectNodeContents(e),t.removeAllRanges(),t.addRange(r)}function M(e,t){let r=a.getSelection();if(!r)return;let i=null,x=o;if(t){if(x.caretRangeFromPoint)i=x.caretRangeFromPoint(t.x,t.y);else if(x.caretPositionFromPoint){let g=x.caretPositionFromPoint(t.x,t.y);g&&(i=o.createRange(),i.setStart(g.offsetNode,g.offset))}}if(!i||!e.contains(i.startContainer))i=o.createRange(),i.selectNodeContents(e),i.collapse(!1);else if(t){let g=i.startContainer,m=(g.nodeType===1?g:g.parentElement)?.closest(\"[data-ff-chip]\")??null;if(m&&m!==e&&e.contains(m)){let F=m.getBoundingClientRect();i=o.createRange(),t.x<F.left+F.width/2?i.setStartBefore(m):i.setStartAfter(m),i.collapse(!0)}}r.removeAllRanges(),r.addRange(i)}function C(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),L(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),v()):t===\"Enter\"?(e.preventDefault(),n?.allowBreaks&&P()):t===\"Tab\"?(e.preventDefault(),v()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),c&&n&&!e.altKey&&u({type:\"formfeed:edit-style\",token:n.token,key:t.toLowerCase()}))}function S(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function A(e){e.preventDefault(),h((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function T(e){e.preventDefault()}function N(){a.setTimeout(()=>{n&&!n.done&&(!o.hasFocus()||!n.element.contains(o.activeElement))&&v()},0)}function P(){let e=a.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let r=o.createElement(\"br\");t.insertNode(r),r.nextSibling||r.parentNode?.appendChild(o.createElement(\"br\"));let i=o.createRange();i.setStartAfter(r),i.collapse(!0),e.removeAllRanges(),e.addRange(i)}function R(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",C),t.removeEventListener(\"beforeinput\",S),t.removeEventListener(\"paste\",A),t.removeEventListener(\"drop\",T),t.removeEventListener(\"focusout\",N),t.removeEventListener(\"input\",k),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),n===e&&(n=null)}function v(){let e=n;if(!e||e.done)return;let t=w(e.element);R(e),u({type:\"formfeed:edit-commit\",token:e.token,items:t})}function L(e){let t=n;if(!t||t.done)return;let r=t.element;for(;r.firstChild;)r.removeChild(r.firstChild);for(let i of t.saved)r.appendChild(i);R(t),e&&u({type:\"formfeed:edit-cancel\",token:t.token})}}function w(a){let l=[],f=o=>{let n=l[l.length-1];n?.kind===\"text\"?n.text+=o:o&&l.push({kind:\"text\",text:o})},c=o=>{for(let n of Array.from(o.childNodes))if(n.nodeType===3)f(n.data);else if(n.nodeType===1){let s=n,u=s.getAttribute(\"data-ff-chip\");u!==null?l.push({kind:\"chip\",index:Number(u)}):s.tagName===\"BR\"?l.push({kind:\"break\"}):((s.tagName===\"DIV\"||s.tagName===\"P\")&&l.length&&l.push({kind:\"break\"}),c(s))}};for(c(a);l[l.length-1]?.kind===\"break\";)l.pop();return l}function K(a,l){return Array.from(a.querySelectorAll(\"[data-ff-layer]\")).map(f=>{let c=f.querySelector(\":scope > .ff-text\"),o=!1;if(c&&f.style.height!==\"auto\"){let n=l.getComputedStyle(f),s=f.clientHeight-(parseFloat(n.paddingTop)||0)-(parseFloat(n.paddingBottom)||0);o=n.overflow===\"hidden\"&&(c.scrollHeight>s+1||c.scrollWidth>c.clientWidth+1)}return{id:f.getAttribute(\"data-ff-layer\")??\"\",width:f.offsetWidth,height:f.offsetHeight,overflow:o}})}function B(a){let l=a.document,f=p=>{try{a.parent.postMessage(p,\"*\")}catch{}},c=p=>typeof p==\"string\"?l.querySelector(`[data-ff-layer=\"${p.replace(/\"/g,\"\")}\"]`):null,o=()=>{for(let p of Array.from(l.querySelectorAll(\"[data-ff-layer]\")))for(let d of[\"left\",\"top\",\"width\",\"height\",\"transform\"])p.style.removeProperty(d)},n=()=>{a.formfeedFit?.(),f({type:\"formfeed:ready\",layers:K(l,a)})};a.addEventListener(\"message\",p=>{if(p.source!==a.parent)return;let d=p.data;if(!(!d||typeof d.type!=\"string\")){if(d.type===\"formfeed:layer-style\"){let b=c(d.id);if(!b)return;let h=(k,E)=>{typeof E==\"number\"&&Number.isFinite(E)&&b.style.setProperty(k,`${E}px`)};h(\"left\",d.left),h(\"top\",d.top),h(\"width\",d.width),h(\"height\",d.height),typeof d.rotation==\"number\"&&Number.isFinite(d.rotation)&&b.style.setProperty(\"transform\",d.rotation?`rotate(${d.rotation}deg)`:\"none\")}else if(d.type===\"formfeed:layer-style-clear\")o();else if(d.type===\"formfeed:css\"&&typeof d.css==\"string\"){let b=l.querySelector('style[data-formfeed=\"template\"]');b&&(b.textContent=d.css),o(),n()}}}),D(a,{clicks:!1,live:!0});let s=l.fonts,u=()=>s?void s.ready.then(n):n();l.readyState===\"complete\"?u():a.addEventListener(\"load\",u)}B(window);})();";
@@ -0,0 +1,6 @@
1
+ /** Bundled from src/frame/text-edit.entry.ts. */
2
+ export declare const textEditRuntime = "\"use strict\";(()=>{var H=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function R(s,l={}){let g=l.clicks!==!1,p=l.live===!0,o=s.document,i=null,a=null,c=e=>{try{s.parent.postMessage(e,\"*\")}catch{}},b=o.createElement(\"style\");b.setAttribute(\"data-formfeed\",\"edit\"),b.setAttribute(\"data-pagedjs-ignore\",\"\"),b.textContent=H,(o.head??o.documentElement).appendChild(b),g&&o.documentElement.classList.add(\"ff-edit-mode\");let D=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;o.addEventListener(\"click\",e=>{if(!g)return;if(i&&!i.done&&i.element.contains(e.target)){e.stopImmediatePropagation();return}let t=D(e.target);if(!t)return;e.preventDefault(),e.stopImmediatePropagation(),i&&!i.done&&y();let n=t.getAttribute(\"data-ff-src\")??\"\",r=t.getBoundingClientRect();a={src:n,element:t,x:e.clientX,y:e.clientY},c({type:\"formfeed:edit-request\",src:n,edit:t.getAttribute(\"data-ff-edit\"),text:t.textContent??\"\",count:o.querySelectorAll(`[data-ff-src=\"${n.replace(/\"/g,\"\")}\"]`).length,split:t.hasAttribute(\"data-split-from\")||t.hasAttribute(\"data-split-to\"),rect:{left:r.left,top:r.top,width:r.width,height:r.height}})},!0),o.addEventListener(\"keydown\",e=>{if(!g||i&&!i.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),c({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),s.addEventListener(\"message\",e=>{if(e.source!==s.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?F(t):(t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\")&&(a=null,i&&!i.done&&h(!1)))});function F(e){i&&!i.done&&h(!1);let t=e.layer?o.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):a&&a.src===e.src?a.element:o.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),n=e.at,r=e.layer?n&&Number.isFinite(n.x)&&Number.isFinite(n.y)?{x:Number(n.x),y:Number(n.y)}:null:a&&a.src===e.src?a:null;if(a=null,!t||!Array.isArray(e.items)){c({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let m=Array.from(t.childNodes),f=o.createDocumentFragment();for(let u of e.items)if(u.kind===\"text\")f.appendChild(o.createTextNode(String(u.text)));else if(u.kind===\"break\")f.appendChild(o.createElement(\"br\"));else if(u.kind===\"chip\"){let d=o.createElement(\"span\");d.className=\"ff-chip\",d.setAttribute(\"data-ff-chip\",String(u.index)),d.setAttribute(\"contenteditable\",\"false\"),u.title&&(d.title=String(u.title)),d.textContent=String(u.text),f.appendChild(d)}for(let u of m)t.removeChild(u);t.appendChild(f),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,i={token:String(e.token),element:t,saved:m,allowBreaks:e.allowBreaks===!0,badge:e.note?B(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",E),t.addEventListener(\"beforeinput\",v),t.addEventListener(\"paste\",C),t.addEventListener(\"drop\",L),t.addEventListener(\"focusout\",A),p&&t.addEventListener(\"input\",x),t.focus(),e.select===\"all\"?w(t):P(t,r),c({type:\"formfeed:edit-started\",token:i.token}),typeof e.insert==\"string\"&&e.insert&&k(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function k(e){if(typeof o.execCommand==\"function\"&&o.execCommand(\"insertText\",!1,e))return;let t=s.getSelection(),n=t&&t.rangeCount?t.getRangeAt(0):null;n&&(n.deleteContents(),n.insertNode(o.createTextNode(e)),n.collapse(!1),p&&x())}function x(){i&&!i.done&&c({type:\"formfeed:edit-input\",token:i.token,items:S(i.element)})}function B(e,t){let n=o.createElement(\"div\");n.className=\"ff-edit-badge\",n.textContent=t;let r=e.getBoundingClientRect();return n.style.left=`${r.left+s.scrollX}px`,n.style.top=`${Math.max(0,r.top+s.scrollY-22)}px`,o.body.appendChild(n),n}function w(e){let t=s.getSelection();if(!t)return;let n=o.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}function P(e,t){let n=s.getSelection();if(!n)return;let r=null,m=o;if(t){if(m.caretRangeFromPoint)r=m.caretRangeFromPoint(t.x,t.y);else if(m.caretPositionFromPoint){let f=m.caretPositionFromPoint(t.x,t.y);f&&(r=o.createRange(),r.setStart(f.offsetNode,f.offset))}}if(!r||!e.contains(r.startContainer))r=o.createRange(),r.selectNodeContents(e),r.collapse(!1);else if(t){let f=r.startContainer,d=(f.nodeType===1?f:f.parentElement)?.closest(\"[data-ff-chip]\")??null;if(d&&d!==e&&e.contains(d)){let N=d.getBoundingClientRect();r=o.createRange(),t.x<N.left+N.width/2?r.setStartBefore(d):r.setStartAfter(d),r.collapse(!0)}}n.removeAllRanges(),n.addRange(r)}function E(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),h(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),y()):t===\"Enter\"?(e.preventDefault(),i?.allowBreaks&&M()):t===\"Tab\"?(e.preventDefault(),y()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),p&&i&&!e.altKey&&c({type:\"formfeed:edit-style\",token:i.token,key:t.toLowerCase()}))}function v(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function C(e){e.preventDefault(),k((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function L(e){e.preventDefault()}function A(){s.setTimeout(()=>{i&&!i.done&&(!o.hasFocus()||!i.element.contains(o.activeElement))&&y()},0)}function M(){let e=s.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let n=o.createElement(\"br\");t.insertNode(n),n.nextSibling||n.parentNode?.appendChild(o.createElement(\"br\"));let r=o.createRange();r.setStartAfter(n),r.collapse(!0),e.removeAllRanges(),e.addRange(r)}function T(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",E),t.removeEventListener(\"beforeinput\",v),t.removeEventListener(\"paste\",C),t.removeEventListener(\"drop\",L),t.removeEventListener(\"focusout\",A),t.removeEventListener(\"input\",x),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),i===e&&(i=null)}function y(){let e=i;if(!e||e.done)return;let t=S(e.element);T(e),c({type:\"formfeed:edit-commit\",token:e.token,items:t})}function h(e){let t=i;if(!t||t.done)return;let n=t.element;for(;n.firstChild;)n.removeChild(n.firstChild);for(let r of t.saved)n.appendChild(r);T(t),e&&c({type:\"formfeed:edit-cancel\",token:t.token})}}function S(s){let l=[],g=o=>{let i=l[l.length-1];i?.kind===\"text\"?i.text+=o:o&&l.push({kind:\"text\",text:o})},p=o=>{for(let i of Array.from(o.childNodes))if(i.nodeType===3)g(i.data);else if(i.nodeType===1){let a=i,c=a.getAttribute(\"data-ff-chip\");c!==null?l.push({kind:\"chip\",index:Number(c)}):a.tagName===\"BR\"?l.push({kind:\"break\"}):((a.tagName===\"DIV\"||a.tagName===\"P\")&&l.length&&l.push({kind:\"break\"}),p(a))}};for(p(s);l[l.length-1]?.kind===\"break\";)l.pop();return l}R(window);})();";
3
+ /** Bundled from src/frame/fit.entry.ts. */
4
+ export declare const fitRuntime = "\"use strict\";(()=>{function a(t,e,n){if(e===t)return t.scrollHeight<=t.clientHeight+.5&&t.scrollWidth<=t.clientWidth+.5;let o=n.getComputedStyle(t),i=t.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);return e.scrollHeight<=i+.5&&e.scrollWidth<=e.clientWidth+.5}function m(t,e){let n=t.firstElementChild??t;n.style.fontSize=\"\";let o=parseFloat(e.getComputedStyle(n).fontSize)||16,i=Math.min(o,parseFloat(t.getAttribute(\"data-ff-fit-min\")??\"\")||o/2);if(a(t,n,e))return o;let l=i,s=o;for(let d=0;d<14;d++){let r=(l+s)/2;n.style.fontSize=`${r}px`,a(t,n,e)?l=r:s=r}let f=Math.floor(l*100)/100;return n.style.fontSize=`${f}px`,f}function c(t){let e=()=>{for(let o of Array.from(t.document.querySelectorAll('[data-ff-fit=\"shrink\"]')))m(o,t);t.document.documentElement.setAttribute(\"data-ff-fit\",\"done\")};t.formfeedFit=e;let n=t.document.fonts;n?n.ready.then(e):t.addEventListener(\"load\",e)}c(window);})();";
5
+ /** Bundled from src/frame/stage.entry.ts. */
6
+ export declare const stageRuntime = "\"use strict\";(()=>{var I=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit=\"t\"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function D(a,l={}){let f=l.clicks!==!1,c=l.live===!0,o=a.document,n=null,s=null,u=e=>{try{a.parent.postMessage(e,\"*\")}catch{}},p=o.createElement(\"style\");p.setAttribute(\"data-formfeed\",\"edit\"),p.setAttribute(\"data-pagedjs-ignore\",\"\"),p.textContent=I,(o.head??o.documentElement).appendChild(p),f&&o.documentElement.classList.add(\"ff-edit-mode\");let d=e=>(e&&typeof e.closest==\"function\"?e:null)?.closest(\"[data-ff-edit]\")??null;o.addEventListener(\"click\",e=>{if(!f)return;if(n&&!n.done&&n.element.contains(e.target)){e.stopImmediatePropagation();return}let t=d(e.target);if(!t)return;e.preventDefault(),e.stopImmediatePropagation(),n&&!n.done&&v();let r=t.getAttribute(\"data-ff-src\")??\"\",i=t.getBoundingClientRect();s={src:r,element:t,x:e.clientX,y:e.clientY},u({type:\"formfeed:edit-request\",src:r,edit:t.getAttribute(\"data-ff-edit\"),text:t.textContent??\"\",count:o.querySelectorAll(`[data-ff-src=\"${r.replace(/\"/g,\"\")}\"]`).length,split:t.hasAttribute(\"data-split-from\")||t.hasAttribute(\"data-split-to\"),rect:{left:i.left,top:i.top,width:i.width,height:i.height}})},!0),o.addEventListener(\"keydown\",e=>{if(!f||n&&!n.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t===\"z\"||t===\"y\")&&(e.preventDefault(),u({type:t===\"y\"||e.shiftKey?\"formfeed:redo\":\"formfeed:undo\"}))}),a.addEventListener(\"message\",e=>{if(e.source!==a.parent)return;let t=e.data;!t||typeof t.type!=\"string\"||(t.type===\"formfeed:edit-begin\"?b(t):(t.type===\"formfeed:edit-refuse\"||t.type===\"formfeed:edit-end\")&&(s=null,n&&!n.done&&L(!1)))});function b(e){n&&!n.done&&L(!1);let t=e.layer?o.querySelector(`[data-ff-layer=\"${String(e.layer).replace(/\"/g,\"\")}\"] > .ff-text`):s&&s.src===e.src?s.element:o.querySelector(`[data-ff-src=\"${String(e.src).replace(/\"/g,\"\")}\"]`),r=e.at,i=e.layer?r&&Number.isFinite(r.x)&&Number.isFinite(r.y)?{x:Number(r.x),y:Number(r.y)}:null:s&&s.src===e.src?s:null;if(s=null,!t||!Array.isArray(e.items)){u({type:\"formfeed:edit-cancel\",token:String(e.token)});return}let x=Array.from(t.childNodes),g=o.createDocumentFragment();for(let y of e.items)if(y.kind===\"text\")g.appendChild(o.createTextNode(String(y.text)));else if(y.kind===\"break\")g.appendChild(o.createElement(\"br\"));else if(y.kind===\"chip\"){let m=o.createElement(\"span\");m.className=\"ff-chip\",m.setAttribute(\"data-ff-chip\",String(y.index)),m.setAttribute(\"contenteditable\",\"false\"),y.title&&(m.title=String(y.title)),m.textContent=String(y.text),g.appendChild(m)}for(let y of x)t.removeChild(y);t.appendChild(g),t.contentEditable=\"true\",t.classList.add(\"ff-editing\"),t.setAttribute(\"role\",\"textbox\"),e.label&&t.setAttribute(\"aria-label\",String(e.label)),t.spellcheck=!0,n={token:String(e.token),element:t,saved:x,allowBreaks:e.allowBreaks===!0,badge:e.note?E(t,String(e.note)):null,done:!1},t.addEventListener(\"keydown\",C),t.addEventListener(\"beforeinput\",S),t.addEventListener(\"paste\",A),t.addEventListener(\"drop\",T),t.addEventListener(\"focusout\",N),c&&t.addEventListener(\"input\",k),t.focus(),e.select===\"all\"?H(t):M(t,i),u({type:\"formfeed:edit-started\",token:n.token}),typeof e.insert==\"string\"&&e.insert&&h(e.insert.replace(/\\r\\n?|\\n/g,\" \"))}function h(e){if(typeof o.execCommand==\"function\"&&o.execCommand(\"insertText\",!1,e))return;let t=a.getSelection(),r=t&&t.rangeCount?t.getRangeAt(0):null;r&&(r.deleteContents(),r.insertNode(o.createTextNode(e)),r.collapse(!1),c&&k())}function k(){n&&!n.done&&u({type:\"formfeed:edit-input\",token:n.token,items:w(n.element)})}function E(e,t){let r=o.createElement(\"div\");r.className=\"ff-edit-badge\",r.textContent=t;let i=e.getBoundingClientRect();return r.style.left=`${i.left+a.scrollX}px`,r.style.top=`${Math.max(0,i.top+a.scrollY-22)}px`,o.body.appendChild(r),r}function H(e){let t=a.getSelection();if(!t)return;let r=o.createRange();r.selectNodeContents(e),t.removeAllRanges(),t.addRange(r)}function M(e,t){let r=a.getSelection();if(!r)return;let i=null,x=o;if(t){if(x.caretRangeFromPoint)i=x.caretRangeFromPoint(t.x,t.y);else if(x.caretPositionFromPoint){let g=x.caretPositionFromPoint(t.x,t.y);g&&(i=o.createRange(),i.setStart(g.offsetNode,g.offset))}}if(!i||!e.contains(i.startContainer))i=o.createRange(),i.selectNodeContents(e),i.collapse(!1);else if(t){let g=i.startContainer,m=(g.nodeType===1?g:g.parentElement)?.closest(\"[data-ff-chip]\")??null;if(m&&m!==e&&e.contains(m)){let F=m.getBoundingClientRect();i=o.createRange(),t.x<F.left+F.width/2?i.setStartBefore(m):i.setStartAfter(m),i.collapse(!0)}}r.removeAllRanges(),r.addRange(i)}function C(e){let t=e.key;t===\"Escape\"?(e.preventDefault(),L(!0)):t===\"Enter\"&&!e.shiftKey?(e.preventDefault(),v()):t===\"Enter\"?(e.preventDefault(),n?.allowBreaks&&P()):t===\"Tab\"?(e.preventDefault(),v()):(e.ctrlKey||e.metaKey)&&[\"b\",\"i\",\"u\"].includes(t.toLowerCase())&&(e.preventDefault(),c&&n&&!e.altKey&&u({type:\"formfeed:edit-style\",token:n.token,key:t.toLowerCase()}))}function S(e){let t=e.inputType??\"\";(t.startsWith(\"format\")||t===\"insertFromDrop\"||t===\"insertParagraph\"||t===\"insertLineBreak\")&&e.preventDefault()}function A(e){e.preventDefault(),h((e.clipboardData?.getData(\"text/plain\")??\"\").replace(/\\r\\n?|\\n/g,\" \"))}function T(e){e.preventDefault()}function N(){a.setTimeout(()=>{n&&!n.done&&(!o.hasFocus()||!n.element.contains(o.activeElement))&&v()},0)}function P(){let e=a.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let r=o.createElement(\"br\");t.insertNode(r),r.nextSibling||r.parentNode?.appendChild(o.createElement(\"br\"));let i=o.createRange();i.setStartAfter(r),i.collapse(!0),e.removeAllRanges(),e.addRange(i)}function R(e){e.done=!0;let t=e.element;t.removeEventListener(\"keydown\",C),t.removeEventListener(\"beforeinput\",S),t.removeEventListener(\"paste\",A),t.removeEventListener(\"drop\",T),t.removeEventListener(\"focusout\",N),t.removeEventListener(\"input\",k),t.removeAttribute(\"contenteditable\"),t.removeAttribute(\"role\"),t.removeAttribute(\"aria-label\"),t.classList.remove(\"ff-editing\"),e.badge?.remove(),n===e&&(n=null)}function v(){let e=n;if(!e||e.done)return;let t=w(e.element);R(e),u({type:\"formfeed:edit-commit\",token:e.token,items:t})}function L(e){let t=n;if(!t||t.done)return;let r=t.element;for(;r.firstChild;)r.removeChild(r.firstChild);for(let i of t.saved)r.appendChild(i);R(t),e&&u({type:\"formfeed:edit-cancel\",token:t.token})}}function w(a){let l=[],f=o=>{let n=l[l.length-1];n?.kind===\"text\"?n.text+=o:o&&l.push({kind:\"text\",text:o})},c=o=>{for(let n of Array.from(o.childNodes))if(n.nodeType===3)f(n.data);else if(n.nodeType===1){let s=n,u=s.getAttribute(\"data-ff-chip\");u!==null?l.push({kind:\"chip\",index:Number(u)}):s.tagName===\"BR\"?l.push({kind:\"break\"}):((s.tagName===\"DIV\"||s.tagName===\"P\")&&l.length&&l.push({kind:\"break\"}),c(s))}};for(c(a);l[l.length-1]?.kind===\"break\";)l.pop();return l}function K(a,l){return Array.from(a.querySelectorAll(\"[data-ff-layer]\")).map(f=>{let c=f.querySelector(\":scope > .ff-text\"),o=!1;if(c&&f.style.height!==\"auto\"){let n=l.getComputedStyle(f),s=f.clientHeight-(parseFloat(n.paddingTop)||0)-(parseFloat(n.paddingBottom)||0);o=n.overflow===\"hidden\"&&(c.scrollHeight>s+1||c.scrollWidth>c.clientWidth+1)}return{id:f.getAttribute(\"data-ff-layer\")??\"\",width:f.offsetWidth,height:f.offsetHeight,overflow:o}})}function B(a){let l=a.document,f=p=>{try{a.parent.postMessage(p,\"*\")}catch{}},c=p=>typeof p==\"string\"?l.querySelector(`[data-ff-layer=\"${p.replace(/\"/g,\"\")}\"]`):null,o=()=>{for(let p of Array.from(l.querySelectorAll(\"[data-ff-layer]\")))for(let d of[\"left\",\"top\",\"width\",\"height\",\"transform\"])p.style.removeProperty(d)},n=()=>{a.formfeedFit?.(),f({type:\"formfeed:ready\",layers:K(l,a)})};a.addEventListener(\"message\",p=>{if(p.source!==a.parent)return;let d=p.data;if(!(!d||typeof d.type!=\"string\")){if(d.type===\"formfeed:layer-style\"){let b=c(d.id);if(!b)return;let h=(k,E)=>{typeof E==\"number\"&&Number.isFinite(E)&&b.style.setProperty(k,`${E}px`)};h(\"left\",d.left),h(\"top\",d.top),h(\"width\",d.width),h(\"height\",d.height),typeof d.rotation==\"number\"&&Number.isFinite(d.rotation)&&b.style.setProperty(\"transform\",d.rotation?`rotate(${d.rotation}deg)`:\"none\")}else if(d.type===\"formfeed:layer-style-clear\")o();else if(d.type===\"formfeed:css\"&&typeof d.css==\"string\"){let b=l.querySelector('style[data-formfeed=\"template\"]');b&&(b.textContent=d.css),o(),n()}}}),D(a,{clicks:!1,live:!0});let s=l.fonts,u=()=>s?void s.ready.then(n):n();l.readyState===\"complete\"?u():a.addEventListener(\"load\",u)}B(window);})();";
@@ -22,6 +22,14 @@ export declare function paperOf(settings: TemplateSettings): {
22
22
  * the element stays so its styling applies.
23
23
  */
24
24
  export declare const pageNumberSpans: (html: string, page: string, total: string) => string;
25
+ /** Options of the flow and paged previews. */
26
+ export interface PreviewOptions {
27
+ /**
28
+ * The editor's edit mode: text in elements marked `data-ff-edit` (`annotateSourcePositions` with
29
+ * `editable`) can be edited in place, and the frame talks to the editor about it by message.
30
+ */
31
+ editing?: boolean;
32
+ }
25
33
  /** What the preview frame reports about content wider than the page, or `null` when nothing is. */
26
34
  export interface PreviewOverflow {
27
35
  /** How far the widest element reaches past the right edge of the page's content area. */
@@ -43,8 +51,14 @@ export interface PreviewOverflow {
43
51
  * The office quick preview's frame uses the same script.
44
52
  */
45
53
  export declare const zoomGestureScript = "<script>\n(function () {\n var say = function (message) { try { parent.postMessage(message, '*'); } catch (e) {} };\n window.addEventListener('wheel', function (event) {\n if (!event.ctrlKey && !event.metaKey) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', deltaY: event.deltaY, deltaMode: event.deltaMode });\n }, { passive: false });\n window.addEventListener('keydown', function (event) {\n if (!(event.ctrlKey || event.metaKey) || event.altKey) return;\n var step = event.key === '+' || event.key === '=' ? 'in' : event.key === '-' ? 'out' : event.key === '0' ? 'reset' : null;\n if (!step) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', step: step });\n });\n})();\n</script>";
46
- export declare function flowDocument(draft: RenderedDraft): string;
47
- export interface PagedOptions {
54
+ export declare function flowDocument(draft: RenderedDraft, options?: PreviewOptions): string;
55
+ /**
56
+ * The design stage's document (plan 16 §4.6): the assembled image template exactly as rendered, with
57
+ * no preview chrome around it (the stage draws its own background), and the stage runtime, which
58
+ * measures layers and takes drag styles and stylesheet patches by message.
59
+ */
60
+ export declare function canvasDocument(draft: RenderedDraft): string;
61
+ export interface PagedOptions extends PreviewOptions {
48
62
  /** URL of the Paged.js polyfill the frame can load. */
49
63
  pagedScriptUrl: string;
50
64
  }
@@ -22,6 +22,14 @@ export declare function paperOf(settings: TemplateSettings): {
22
22
  * the element stays so its styling applies.
23
23
  */
24
24
  export declare const pageNumberSpans: (html: string, page: string, total: string) => string;
25
+ /** Options of the flow and paged previews. */
26
+ export interface PreviewOptions {
27
+ /**
28
+ * The editor's edit mode: text in elements marked `data-ff-edit` (`annotateSourcePositions` with
29
+ * `editable`) can be edited in place, and the frame talks to the editor about it by message.
30
+ */
31
+ editing?: boolean;
32
+ }
25
33
  /** What the preview frame reports about content wider than the page, or `null` when nothing is. */
26
34
  export interface PreviewOverflow {
27
35
  /** How far the widest element reaches past the right edge of the page's content area. */
@@ -43,8 +51,14 @@ export interface PreviewOverflow {
43
51
  * The office quick preview's frame uses the same script.
44
52
  */
45
53
  export declare const zoomGestureScript = "<script>\n(function () {\n var say = function (message) { try { parent.postMessage(message, '*'); } catch (e) {} };\n window.addEventListener('wheel', function (event) {\n if (!event.ctrlKey && !event.metaKey) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', deltaY: event.deltaY, deltaMode: event.deltaMode });\n }, { passive: false });\n window.addEventListener('keydown', function (event) {\n if (!(event.ctrlKey || event.metaKey) || event.altKey) return;\n var step = event.key === '+' || event.key === '=' ? 'in' : event.key === '-' ? 'out' : event.key === '0' ? 'reset' : null;\n if (!step) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', step: step });\n });\n})();\n</script>";
46
- export declare function flowDocument(draft: RenderedDraft): string;
47
- export interface PagedOptions {
54
+ export declare function flowDocument(draft: RenderedDraft, options?: PreviewOptions): string;
55
+ /**
56
+ * The design stage's document (plan 16 §4.6): the assembled image template exactly as rendered, with
57
+ * no preview chrome around it (the stage draws its own background), and the stage runtime, which
58
+ * measures layers and takes drag styles and stylesheet patches by message.
59
+ */
60
+ export declare function canvasDocument(draft: RenderedDraft): string;
61
+ export interface PagedOptions extends PreviewOptions {
48
62
  /** URL of the Paged.js polyfill the frame can load. */
49
63
  pagedScriptUrl: string;
50
64
  }