@sanity-labs/slides 0.0.0

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 (224) hide show
  1. package/README.md +241 -0
  2. package/SKILL.md +119 -0
  3. package/dist/cli.d.ts +38 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +386 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/components.d.ts +179 -0
  8. package/dist/core/components.d.ts.map +1 -0
  9. package/dist/core/components.js +40 -0
  10. package/dist/core/components.js.map +1 -0
  11. package/dist/core/fake-runtime.d.ts +138 -0
  12. package/dist/core/fake-runtime.d.ts.map +1 -0
  13. package/dist/core/fake-runtime.js +210 -0
  14. package/dist/core/fake-runtime.js.map +1 -0
  15. package/dist/core/font-resolver.d.ts +28 -0
  16. package/dist/core/font-resolver.d.ts.map +1 -0
  17. package/dist/core/font-resolver.js +30 -0
  18. package/dist/core/font-resolver.js.map +1 -0
  19. package/dist/core/geometry.d.ts +71 -0
  20. package/dist/core/geometry.d.ts.map +1 -0
  21. package/dist/core/geometry.js +44 -0
  22. package/dist/core/geometry.js.map +1 -0
  23. package/dist/core/index.d.ts +19 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/index.js +20 -0
  26. package/dist/core/index.js.map +1 -0
  27. package/dist/core/manifest.d.ts +123 -0
  28. package/dist/core/manifest.d.ts.map +1 -0
  29. package/dist/core/manifest.js +43 -0
  30. package/dist/core/manifest.js.map +1 -0
  31. package/dist/core/op-translator-pptx.d.ts +150 -0
  32. package/dist/core/op-translator-pptx.d.ts.map +1 -0
  33. package/dist/core/op-translator-pptx.js +245 -0
  34. package/dist/core/op-translator-pptx.js.map +1 -0
  35. package/dist/core/pptx-runtime.d.ts +103 -0
  36. package/dist/core/pptx-runtime.d.ts.map +1 -0
  37. package/dist/core/pptx-runtime.js +405 -0
  38. package/dist/core/pptx-runtime.js.map +1 -0
  39. package/dist/core/reconciler.d.ts +113 -0
  40. package/dist/core/reconciler.d.ts.map +1 -0
  41. package/dist/core/reconciler.js +453 -0
  42. package/dist/core/reconciler.js.map +1 -0
  43. package/dist/core/runtime.d.ts +161 -0
  44. package/dist/core/runtime.d.ts.map +1 -0
  45. package/dist/core/runtime.js +11 -0
  46. package/dist/core/runtime.js.map +1 -0
  47. package/dist/core/template.d.ts +32 -0
  48. package/dist/core/template.d.ts.map +1 -0
  49. package/dist/core/template.js +3 -0
  50. package/dist/core/template.js.map +1 -0
  51. package/dist/dev/auto-examples.d.ts +6 -0
  52. package/dist/dev/auto-examples.d.ts.map +1 -0
  53. package/dist/dev/auto-examples.js +79 -0
  54. package/dist/dev/auto-examples.js.map +1 -0
  55. package/dist/dev/bin/slides-dev.d.ts +3 -0
  56. package/dist/dev/bin/slides-dev.d.ts.map +1 -0
  57. package/dist/dev/bin/slides-dev.js +87 -0
  58. package/dist/dev/bin/slides-dev.js.map +1 -0
  59. package/dist/dev/bin/slides-dev.mjs +24 -0
  60. package/dist/dev/compose-deck.d.ts +18 -0
  61. package/dist/dev/compose-deck.d.ts.map +1 -0
  62. package/dist/dev/compose-deck.js +19 -0
  63. package/dist/dev/compose-deck.js.map +1 -0
  64. package/dist/dev/deck-viewer.d.ts +19 -0
  65. package/dist/dev/deck-viewer.d.ts.map +1 -0
  66. package/dist/dev/deck-viewer.js +237 -0
  67. package/dist/dev/deck-viewer.js.map +1 -0
  68. package/dist/dev/dev-server/client/entry.d.ts +2 -0
  69. package/dist/dev/dev-server/client/entry.d.ts.map +1 -0
  70. package/dist/dev/dev-server/client/entry.js +12 -0
  71. package/dist/dev/dev-server/client/entry.js.map +1 -0
  72. package/dist/dev/dev-server/output.d.ts +8 -0
  73. package/dist/dev/dev-server/output.d.ts.map +1 -0
  74. package/dist/dev/dev-server/output.js +32 -0
  75. package/dist/dev/dev-server/output.js.map +1 -0
  76. package/dist/dev/dev-server/server-only-stub.d.ts +7 -0
  77. package/dist/dev/dev-server/server-only-stub.d.ts.map +1 -0
  78. package/dist/dev/dev-server/server-only-stub.js +12 -0
  79. package/dist/dev/dev-server/server-only-stub.js.map +1 -0
  80. package/dist/dev/dev-server/start.d.ts +14 -0
  81. package/dist/dev/dev-server/start.d.ts.map +1 -0
  82. package/dist/dev/dev-server/start.js +135 -0
  83. package/dist/dev/dev-server/start.js.map +1 -0
  84. package/dist/dev/index.d.ts +5 -0
  85. package/dist/dev/index.d.ts.map +1 -0
  86. package/dist/dev/index.js +5 -0
  87. package/dist/dev/index.js.map +1 -0
  88. package/dist/dev/lib/cn.d.ts +3 -0
  89. package/dist/dev/lib/cn.d.ts.map +1 -0
  90. package/dist/dev/lib/cn.js +3 -0
  91. package/dist/dev/lib/cn.js.map +1 -0
  92. package/dist/dev/slide-canvas.d.ts +12 -0
  93. package/dist/dev/slide-canvas.d.ts.map +1 -0
  94. package/dist/dev/slide-canvas.js +123 -0
  95. package/dist/dev/slide-canvas.js.map +1 -0
  96. package/dist/dev/styles.css +37 -0
  97. package/dist/dev/ui/icon-button.d.ts +12 -0
  98. package/dist/dev/ui/icon-button.d.ts.map +1 -0
  99. package/dist/dev/ui/icon-button.js +6 -0
  100. package/dist/dev/ui/icon-button.js.map +1 -0
  101. package/dist/dev/ui/kbd.d.ts +6 -0
  102. package/dist/dev/ui/kbd.d.ts.map +1 -0
  103. package/dist/dev/ui/kbd.js +4 -0
  104. package/dist/dev/ui/kbd.js.map +1 -0
  105. package/dist/dev/ui/text-button.d.ts +10 -0
  106. package/dist/dev/ui/text-button.d.ts.map +1 -0
  107. package/dist/dev/ui/text-button.js +6 -0
  108. package/dist/dev/ui/text-button.js.map +1 -0
  109. package/dist/dev/url-state.d.ts +7 -0
  110. package/dist/dev/url-state.d.ts.map +1 -0
  111. package/dist/dev/url-state.js +13 -0
  112. package/dist/dev/url-state.js.map +1 -0
  113. package/dist/dev/use-keyboard-nav.d.ts +17 -0
  114. package/dist/dev/use-keyboard-nav.d.ts.map +1 -0
  115. package/dist/dev/use-keyboard-nav.js +53 -0
  116. package/dist/dev/use-keyboard-nav.js.map +1 -0
  117. package/dist/index.d.ts +17 -0
  118. package/dist/index.d.ts.map +1 -0
  119. package/dist/index.js +17 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/mcp/errors.d.ts +57 -0
  122. package/dist/mcp/errors.d.ts.map +1 -0
  123. package/dist/mcp/errors.js +44 -0
  124. package/dist/mcp/errors.js.map +1 -0
  125. package/dist/mcp/index.d.ts +29 -0
  126. package/dist/mcp/index.d.ts.map +1 -0
  127. package/dist/mcp/index.js +29 -0
  128. package/dist/mcp/index.js.map +1 -0
  129. package/dist/mcp/naming.d.ts +37 -0
  130. package/dist/mcp/naming.d.ts.map +1 -0
  131. package/dist/mcp/naming.js +43 -0
  132. package/dist/mcp/naming.js.map +1 -0
  133. package/dist/mcp/render.d.ts +45 -0
  134. package/dist/mcp/render.d.ts.map +1 -0
  135. package/dist/mcp/render.js +77 -0
  136. package/dist/mcp/render.js.map +1 -0
  137. package/dist/mcp/schema.d.ts +54 -0
  138. package/dist/mcp/schema.d.ts.map +1 -0
  139. package/dist/mcp/schema.js +55 -0
  140. package/dist/mcp/schema.js.map +1 -0
  141. package/dist/mcp/server.d.ts +63 -0
  142. package/dist/mcp/server.d.ts.map +1 -0
  143. package/dist/mcp/server.js +196 -0
  144. package/dist/mcp/server.js.map +1 -0
  145. package/dist/scaffold/index.d.ts +39 -0
  146. package/dist/scaffold/index.d.ts.map +1 -0
  147. package/dist/scaffold/index.js +84 -0
  148. package/dist/scaffold/index.js.map +1 -0
  149. package/dist/scaffold/template-base/README.md +134 -0
  150. package/dist/scaffold/template-base/_gitignore +4 -0
  151. package/dist/scaffold/template-base/package.json +35 -0
  152. package/dist/scaffold/template-base/src/components/Cover.tsx +30 -0
  153. package/dist/scaffold/template-base/src/index.ts +27 -0
  154. package/dist/scaffold/template-base/src/preview.tsx +9 -0
  155. package/dist/scaffold/template-base/tsconfig.build.json +10 -0
  156. package/dist/scaffold/template-base/tsconfig.json +18 -0
  157. package/package.json +164 -0
  158. package/src/__tests__/fixtures/test-template/index.tsx +77 -0
  159. package/src/__tests__/pptx-mcp.test.ts +85 -0
  160. package/src/__tests__/pptx-smoke.test.ts +45 -0
  161. package/src/__tests__/preview.test.ts +28 -0
  162. package/src/cli.ts +426 -0
  163. package/src/core/__snapshots__/reconciler.test.ts.snap +320 -0
  164. package/src/core/components.test.ts +57 -0
  165. package/src/core/components.ts +196 -0
  166. package/src/core/fake-runtime.test.ts +174 -0
  167. package/src/core/fake-runtime.ts +302 -0
  168. package/src/core/font-resolver.ts +46 -0
  169. package/src/core/geometry.test.ts +58 -0
  170. package/src/core/geometry.ts +91 -0
  171. package/src/core/index.ts +69 -0
  172. package/src/core/manifest.test.ts +33 -0
  173. package/src/core/manifest.ts +150 -0
  174. package/src/core/op-translator-pptx.test.ts +204 -0
  175. package/src/core/op-translator-pptx.ts +365 -0
  176. package/src/core/pptx-runtime.test.ts +137 -0
  177. package/src/core/pptx-runtime.ts +504 -0
  178. package/src/core/reconciler.test.ts +644 -0
  179. package/src/core/reconciler.ts +603 -0
  180. package/src/core/runtime.ts +150 -0
  181. package/src/core/template.test.ts +136 -0
  182. package/src/core/template.ts +37 -0
  183. package/src/dev/auto-examples.ts +89 -0
  184. package/src/dev/bin/slides-dev.mjs +24 -0
  185. package/src/dev/bin/slides-dev.ts +101 -0
  186. package/src/dev/compose-deck.test.ts +68 -0
  187. package/src/dev/compose-deck.ts +40 -0
  188. package/src/dev/deck-viewer.tsx +677 -0
  189. package/src/dev/dev-server/client/entry.tsx +15 -0
  190. package/src/dev/dev-server/client/index.html +24 -0
  191. package/src/dev/dev-server/output.ts +37 -0
  192. package/src/dev/dev-server/server-only-stub.ts +12 -0
  193. package/src/dev/dev-server/start.ts +155 -0
  194. package/src/dev/index.ts +4 -0
  195. package/src/dev/lib/cn.ts +3 -0
  196. package/src/dev/slide-canvas.test.tsx +66 -0
  197. package/src/dev/slide-canvas.tsx +170 -0
  198. package/src/dev/styles.css +37 -0
  199. package/src/dev/ui/icon-button.tsx +31 -0
  200. package/src/dev/ui/kbd.tsx +20 -0
  201. package/src/dev/ui/text-button.tsx +31 -0
  202. package/src/dev/url-state.test.ts +22 -0
  203. package/src/dev/url-state.ts +17 -0
  204. package/src/dev/use-keyboard-nav.ts +64 -0
  205. package/src/index.ts +17 -0
  206. package/src/mcp/errors.test.ts +51 -0
  207. package/src/mcp/errors.ts +76 -0
  208. package/src/mcp/index.ts +45 -0
  209. package/src/mcp/naming.test.ts +39 -0
  210. package/src/mcp/naming.ts +49 -0
  211. package/src/mcp/render.ts +110 -0
  212. package/src/mcp/schema.test.ts +86 -0
  213. package/src/mcp/schema.ts +93 -0
  214. package/src/mcp/server.test.ts +309 -0
  215. package/src/mcp/server.ts +276 -0
  216. package/src/scaffold/index.ts +102 -0
  217. package/src/scaffold/template-base/README.md +134 -0
  218. package/src/scaffold/template-base/_gitignore +4 -0
  219. package/src/scaffold/template-base/package.json +35 -0
  220. package/src/scaffold/template-base/src/components/Cover.tsx +30 -0
  221. package/src/scaffold/template-base/src/index.ts +27 -0
  222. package/src/scaffold/template-base/src/preview.tsx +9 -0
  223. package/src/scaffold/template-base/tsconfig.build.json +10 -0
  224. package/src/scaffold/template-base/tsconfig.json +18 -0
@@ -0,0 +1,138 @@
1
+ /**
2
+ * In-memory `SlidesRuntime` for tests.
3
+ *
4
+ * **The single test seam.** Every layer of the testing pyramid (component
5
+ * units, reconciler goldens, MCP integration) goes through `SlidesRuntime`.
6
+ * `FakeSlidesRuntime` records every call and maintains a coherent in-memory
7
+ * deck so reads are consistent with writes — no HTTP-level mocks, no
8
+ * brittle nock fixtures.
9
+ *
10
+ * See `docs/testing-strategy.md` for the rationale.
11
+ *
12
+ * # What it does
13
+ *
14
+ * - Implements every method of `SlidesRuntime`.
15
+ * - `applyOps` walks the op stream and updates the in-memory deck model.
16
+ * - `getOpsLog()` returns every op ever applied across all decks (in order),
17
+ * for tests that want to assert on the *call sequence*.
18
+ * - `getDeck(deckId)` returns the current in-memory state of a deck — slides,
19
+ * shapes, text content — for tests that want to assert on the *result*.
20
+ *
21
+ * # What it deliberately doesn't do
22
+ *
23
+ * - Simulate any specific backend's autoresize, font fallback, page-element
24
+ * inheritance, etc. The fake is a *contract honoring* fake, not a
25
+ * *behavior simulating* fake. If a test depends on auto-resize behavior,
26
+ * that's a smoke-test concern, not a fake-runtime concern.
27
+ * - Persist state across instances. Each `FakeSlidesRuntime` is fresh.
28
+ */
29
+ import type { GenerationManifest } from './manifest.js';
30
+ import type { ApplyOpsResult, ParagraphStyle, ShapeKind, ShapeProperties, SlideOp, SlidesRuntime, TextStyle } from './runtime.js';
31
+ /** Configuration for a fake-runtime instance. */
32
+ export interface FakeSlidesRuntimeOptions {
33
+ /**
34
+ * If set, `createDeckFromMaster` returns this deck ID. Otherwise the fake
35
+ * mints fresh `fake-deck-<n>` IDs.
36
+ */
37
+ readonly fixedDeckId?: string;
38
+ /** Override the clock used for revision tokens (deterministic snapshots). */
39
+ readonly now?: () => number;
40
+ }
41
+ /** A single shape in the fake deck. */
42
+ export interface FakeShape {
43
+ readonly objectId: string;
44
+ readonly kind: ShapeKind;
45
+ readonly slideId: string;
46
+ rect: {
47
+ x: number;
48
+ y: number;
49
+ w: number;
50
+ h: number;
51
+ };
52
+ text: string;
53
+ /**
54
+ * Style spans recorded in document order. Later spans on overlapping
55
+ * ranges win (last-write-wins). The reconciler emits spans in op order;
56
+ * the runtime is responsible for composing them at render time.
57
+ */
58
+ textStyleSpans: Array<{
59
+ range: {
60
+ start: number;
61
+ end: number;
62
+ };
63
+ style: TextStyle;
64
+ }>;
65
+ paragraphStyleSpans: Array<{
66
+ range: {
67
+ start: number;
68
+ end: number;
69
+ };
70
+ style: ParagraphStyle;
71
+ }>;
72
+ shapeProperties: ShapeProperties;
73
+ /** For images, the source URL. `undefined` for non-image shapes. */
74
+ imageUrl?: string;
75
+ /** For images, the alt-text. */
76
+ altText?: string;
77
+ }
78
+ /** A single slide in the fake deck. */
79
+ export interface FakeSlide {
80
+ readonly slideId: string;
81
+ /** Insertion index recorded at create time, for ordering. */
82
+ readonly insertAt: number;
83
+ /** Object IDs of shapes on this slide, in creation order. */
84
+ readonly shapeIds: string[];
85
+ }
86
+ /** The in-memory model of a deck. */
87
+ export interface FakeDeck {
88
+ readonly deckId: string;
89
+ readonly title: string;
90
+ readonly masterRef: string | null;
91
+ readonly slides: Map<string, FakeSlide>;
92
+ readonly shapes: Map<string, FakeShape>;
93
+ /** Slide IDs in their committed order. */
94
+ readonly slideOrder: string[];
95
+ /** Monotonic revision; bumped after each `applyOps`. */
96
+ revision: number;
97
+ }
98
+ /** A fake test runtime. See module docstring. */
99
+ export declare class FakeSlidesRuntime implements SlidesRuntime {
100
+ private readonly opsLog;
101
+ private readonly decks;
102
+ private readonly manifests;
103
+ private deckCounter;
104
+ private readonly fixedDeckId?;
105
+ private readonly now;
106
+ constructor(options?: FakeSlidesRuntimeOptions);
107
+ applyOps(deckId: string, ops: readonly SlideOp[]): Promise<ApplyOpsResult>;
108
+ createDeckFromMaster(masterRef: string, title: string): Promise<{
109
+ deckId: string;
110
+ }>;
111
+ write(_deckId: string): Promise<{
112
+ filePath: string;
113
+ }>;
114
+ attachManifest(deckId: string, manifest: GenerationManifest): void;
115
+ /**
116
+ * The complete sequence of ops applied across every deck, in apply order.
117
+ *
118
+ * Most reconciler-golden tests work directly on the ops the reconciler
119
+ * *produces* (without applying them to a runtime). This log is for tests
120
+ * that exercise the runtime contract end-to-end, e.g., MCP integration
121
+ * tests.
122
+ */
123
+ getOpsLog(): ReadonlyArray<{
124
+ deckId: string;
125
+ op: SlideOp;
126
+ }>;
127
+ /** Snapshot the in-memory deck. Returns `undefined` if it doesn't exist. */
128
+ getDeck(deckId: string): FakeDeck | undefined;
129
+ /** Retrieve a deck's manifest (if attached). Test-inspection helper. */
130
+ getManifest(deckId: string): GenerationManifest | undefined;
131
+ /** All deck IDs the fake knows about. */
132
+ listDeckIds(): readonly string[];
133
+ /** Throw an Error with a useful message if the deck doesn't exist. */
134
+ private requireDeck;
135
+ private applyOp;
136
+ private requireShape;
137
+ }
138
+ //# sourceMappingURL=fake-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-runtime.d.ts","sourceRoot":"","sources":["../../src/core/fake-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * In-memory `SlidesRuntime` for tests.
3
+ *
4
+ * **The single test seam.** Every layer of the testing pyramid (component
5
+ * units, reconciler goldens, MCP integration) goes through `SlidesRuntime`.
6
+ * `FakeSlidesRuntime` records every call and maintains a coherent in-memory
7
+ * deck so reads are consistent with writes — no HTTP-level mocks, no
8
+ * brittle nock fixtures.
9
+ *
10
+ * See `docs/testing-strategy.md` for the rationale.
11
+ *
12
+ * # What it does
13
+ *
14
+ * - Implements every method of `SlidesRuntime`.
15
+ * - `applyOps` walks the op stream and updates the in-memory deck model.
16
+ * - `getOpsLog()` returns every op ever applied across all decks (in order),
17
+ * for tests that want to assert on the *call sequence*.
18
+ * - `getDeck(deckId)` returns the current in-memory state of a deck — slides,
19
+ * shapes, text content — for tests that want to assert on the *result*.
20
+ *
21
+ * # What it deliberately doesn't do
22
+ *
23
+ * - Simulate any specific backend's autoresize, font fallback, page-element
24
+ * inheritance, etc. The fake is a *contract honoring* fake, not a
25
+ * *behavior simulating* fake. If a test depends on auto-resize behavior,
26
+ * that's a smoke-test concern, not a fake-runtime concern.
27
+ * - Persist state across instances. Each `FakeSlidesRuntime` is fresh.
28
+ */
29
+ /** A fake test runtime. See module docstring. */
30
+ export class FakeSlidesRuntime {
31
+ opsLog = [];
32
+ decks = new Map();
33
+ manifests = new Map();
34
+ deckCounter = 0;
35
+ fixedDeckId;
36
+ now;
37
+ constructor(options = {}) {
38
+ this.fixedDeckId = options.fixedDeckId;
39
+ this.now = options.now ?? Date.now;
40
+ }
41
+ // -- SlidesRuntime --------------------------------------------------------
42
+ async applyOps(deckId, ops) {
43
+ const deck = this.requireDeck(deckId);
44
+ const createdObjectIds = {};
45
+ for (const op of ops) {
46
+ this.opsLog.push({ deckId, op });
47
+ this.applyOp(deck, op, createdObjectIds);
48
+ }
49
+ deck.revision += 1;
50
+ return {
51
+ createdObjectIds,
52
+ revisionId: `rev-${deck.revision}-${this.now()}`,
53
+ };
54
+ }
55
+ async createDeckFromMaster(masterRef, title) {
56
+ this.deckCounter += 1;
57
+ const deckId = this.fixedDeckId ?? `fake-deck-${this.deckCounter}`;
58
+ if (this.decks.has(deckId)) {
59
+ throw new Error(`FakeSlidesRuntime: deck "${deckId}" already exists.`);
60
+ }
61
+ this.decks.set(deckId, {
62
+ deckId,
63
+ title,
64
+ masterRef,
65
+ slides: new Map(),
66
+ shapes: new Map(),
67
+ slideOrder: [],
68
+ revision: 0,
69
+ });
70
+ return { deckId };
71
+ }
72
+ // -- SlidesRuntime (continued) --------------------------------------------
73
+ async write(_deckId) {
74
+ throw new Error('FakeSlidesRuntime does not write files. Use PptxSlidesRuntime for file output.');
75
+ }
76
+ attachManifest(deckId, manifest) {
77
+ this.requireDeck(deckId);
78
+ this.manifests.set(deckId, manifest);
79
+ }
80
+ // -- Test inspection helpers ---------------------------------------------
81
+ /**
82
+ * The complete sequence of ops applied across every deck, in apply order.
83
+ *
84
+ * Most reconciler-golden tests work directly on the ops the reconciler
85
+ * *produces* (without applying them to a runtime). This log is for tests
86
+ * that exercise the runtime contract end-to-end, e.g., MCP integration
87
+ * tests.
88
+ */
89
+ getOpsLog() {
90
+ return this.opsLog;
91
+ }
92
+ /** Snapshot the in-memory deck. Returns `undefined` if it doesn't exist. */
93
+ getDeck(deckId) {
94
+ return this.decks.get(deckId);
95
+ }
96
+ /** Retrieve a deck's manifest (if attached). Test-inspection helper. */
97
+ getManifest(deckId) {
98
+ return this.manifests.get(deckId);
99
+ }
100
+ /** All deck IDs the fake knows about. */
101
+ listDeckIds() {
102
+ return [...this.decks.keys()];
103
+ }
104
+ /** Throw an Error with a useful message if the deck doesn't exist. */
105
+ requireDeck(deckId) {
106
+ const deck = this.decks.get(deckId);
107
+ if (!deck) {
108
+ throw new Error(`FakeSlidesRuntime: deck "${deckId}" does not exist. Create it via createDeckFromMaster() first.`);
109
+ }
110
+ return deck;
111
+ }
112
+ // -- Op application ------------------------------------------------------
113
+ applyOp(deck, op, createdObjectIds) {
114
+ switch (op.type) {
115
+ case 'createSlide': {
116
+ if (deck.slides.has(op.slideId)) {
117
+ throw new Error(`FakeSlidesRuntime: slide "${op.slideId}" already exists.`);
118
+ }
119
+ const slide = {
120
+ slideId: op.slideId,
121
+ insertAt: op.insertAt ?? deck.slideOrder.length,
122
+ shapeIds: [],
123
+ };
124
+ deck.slides.set(op.slideId, slide);
125
+ const insertIdx = Math.min(slide.insertAt, deck.slideOrder.length);
126
+ deck.slideOrder.splice(insertIdx, 0, op.slideId);
127
+ createdObjectIds[op.slideId] = op.slideId;
128
+ return;
129
+ }
130
+ case 'createShape': {
131
+ const slide = deck.slides.get(op.slideId);
132
+ if (!slide) {
133
+ throw new Error(`FakeSlidesRuntime: createShape references unknown slide "${op.slideId}".`);
134
+ }
135
+ if (deck.shapes.has(op.shapeId)) {
136
+ throw new Error(`FakeSlidesRuntime: shape "${op.shapeId}" already exists.`);
137
+ }
138
+ const shape = {
139
+ objectId: op.shapeId,
140
+ kind: op.shape,
141
+ slideId: op.slideId,
142
+ rect: { x: op.rect.x, y: op.rect.y, w: op.rect.w, h: op.rect.h },
143
+ text: '',
144
+ textStyleSpans: [],
145
+ paragraphStyleSpans: [],
146
+ shapeProperties: {},
147
+ };
148
+ deck.shapes.set(op.shapeId, shape);
149
+ slide.shapeIds.push(op.shapeId);
150
+ createdObjectIds[op.shapeId] = op.shapeId;
151
+ return;
152
+ }
153
+ case 'createImage': {
154
+ const slide = deck.slides.get(op.slideId);
155
+ if (!slide) {
156
+ throw new Error(`FakeSlidesRuntime: createImage references unknown slide "${op.slideId}".`);
157
+ }
158
+ if (deck.shapes.has(op.imageId)) {
159
+ throw new Error(`FakeSlidesRuntime: image "${op.imageId}" already exists.`);
160
+ }
161
+ const image = {
162
+ objectId: op.imageId,
163
+ kind: 'RECTANGLE', // Slides treats images as a separate kind; we collapse for the fake.
164
+ slideId: op.slideId,
165
+ rect: { x: op.rect.x, y: op.rect.y, w: op.rect.w, h: op.rect.h },
166
+ text: '',
167
+ textStyleSpans: [],
168
+ paragraphStyleSpans: [],
169
+ shapeProperties: {},
170
+ imageUrl: op.url,
171
+ ...(op.altText !== undefined ? { altText: op.altText } : {}),
172
+ };
173
+ deck.shapes.set(op.imageId, image);
174
+ slide.shapeIds.push(op.imageId);
175
+ createdObjectIds[op.imageId] = op.imageId;
176
+ return;
177
+ }
178
+ case 'insertText': {
179
+ const shape = this.requireShape(deck, op.objectId, 'insertText');
180
+ // The reconciler always inserts into an empty shape, so this is a
181
+ // full-text replace.
182
+ shape.text = op.text;
183
+ return;
184
+ }
185
+ case 'updateTextStyle': {
186
+ const shape = this.requireShape(deck, op.objectId, 'updateTextStyle');
187
+ shape.textStyleSpans.push({ range: { ...op.range }, style: { ...op.style } });
188
+ return;
189
+ }
190
+ case 'updateParagraphStyle': {
191
+ const shape = this.requireShape(deck, op.objectId, 'updateParagraphStyle');
192
+ shape.paragraphStyleSpans.push({ range: { ...op.range }, style: { ...op.style } });
193
+ return;
194
+ }
195
+ case 'updateShapeProperties': {
196
+ const shape = this.requireShape(deck, op.objectId, 'updateShapeProperties');
197
+ shape.shapeProperties = { ...shape.shapeProperties, ...op.properties };
198
+ return;
199
+ }
200
+ }
201
+ }
202
+ requireShape(deck, objectId, opName) {
203
+ const shape = deck.shapes.get(objectId);
204
+ if (!shape) {
205
+ throw new Error(`FakeSlidesRuntime: ${opName} targets unknown object "${objectId}".`);
206
+ }
207
+ return shape;
208
+ }
209
+ }
210
+ //# sourceMappingURL=fake-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-runtime.js","sourceRoot":"","sources":["../../src/core/fake-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Synchronous font-role resolution at the reconciler boundary.
3
+ *
4
+ * The reconciler invokes `resolveFontRole` immediately before pushing
5
+ * every text-style op, so downstream translators never see a role keyword
6
+ * (`'display'`, `'body'`, `'mono'`) as a literal family.
7
+ */
8
+ import type { FontRole } from './runtime.js';
9
+ /**
10
+ * Per-role ordered preference. Earlier entries are higher fidelity. Templates
11
+ * should always include a system-safe last entry (e.g., `"Arial"`).
12
+ */
13
+ export interface FontStack {
14
+ display: readonly string[];
15
+ body: readonly string[];
16
+ mono: readonly string[];
17
+ }
18
+ /**
19
+ * Resolve a font role to the brand's first-preference family.
20
+ *
21
+ * Strict-fails on an empty stack rather than silently picking Arial.
22
+ *
23
+ * @throws {EmptyFontStackError} if `stack[role]` is empty.
24
+ */
25
+ export declare const resolveFontRole: (stack: FontStack, role: FontRole) => string;
26
+ /** Type guard: is `value` one of the reserved font role keywords? */
27
+ export declare const isFontRole: (value: string) => value is FontRole;
28
+ //# sourceMappingURL=font-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-resolver.d.ts","sourceRoot":"","sources":["../../src/core/font-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACzB;AAYD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,SAAS,EAAE,MAAM,QAAQ,KAAG,MAIlE,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,KAAK,IAAI,QACS,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Synchronous font-role resolution at the reconciler boundary.
3
+ *
4
+ * The reconciler invokes `resolveFontRole` immediately before pushing
5
+ * every text-style op, so downstream translators never see a role keyword
6
+ * (`'display'`, `'body'`, `'mono'`) as a literal family.
7
+ */
8
+ /** Configuration error: a role's preference list is empty. */
9
+ class EmptyFontStackError extends Error {
10
+ constructor(role) {
11
+ super(`FontStack.${role} is empty. Every role (display, body, mono) needs at least one font, with a system-safe last entry (e.g., "Arial").`);
12
+ this.name = 'EmptyFontStackError';
13
+ }
14
+ }
15
+ /**
16
+ * Resolve a font role to the brand's first-preference family.
17
+ *
18
+ * Strict-fails on an empty stack rather than silently picking Arial.
19
+ *
20
+ * @throws {EmptyFontStackError} if `stack[role]` is empty.
21
+ */
22
+ export const resolveFontRole = (stack, role) => {
23
+ const first = stack[role][0];
24
+ if (first === undefined)
25
+ throw new EmptyFontStackError(role);
26
+ return first;
27
+ };
28
+ /** Type guard: is `value` one of the reserved font role keywords? */
29
+ export const isFontRole = (value) => value === 'display' || value === 'body' || value === 'mono';
30
+ //# sourceMappingURL=font-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-resolver.js","sourceRoot":"","sources":["../../src/core/font-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,8DAA8D;AAC9D,MAAM,mBAAoB,SAAQ,KAAK;IACrC,YAAY,IAAY;QACtB,KAAK,CACH,aAAa,IAAI,qHAAqH,CACvI,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAgB,EAAE,IAAc,EAAU,EAAE;IAC1E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,qEAAqE;AACrE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAqB,EAAE,CAC7D,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Geometry primitives for slide layout.
3
+ *
4
+ * Two unit systems matter:
5
+ * - **Points (pt)** — the *authoring* unit. Designers and component code
6
+ * think in pt. 72 pt = 1 inch. Most slide measurements are integers at
7
+ * human-relevant scales.
8
+ * - **English Metric Units (EMU)** — the Office Open XML / PPTX coordinate
9
+ * unit. 914,400 EMU = 1 inch. Effectively never appears outside the
10
+ * runtime boundary.
11
+ *
12
+ * The conversion happens at *exactly one* point in the system: the boundary
13
+ * between the reconciler and the runtime. Everything above is pt; everything
14
+ * below is EMU.
15
+ *
16
+ * Font sizes are an exception: backends consume font size in pt directly
17
+ * (PPTX/Office Open XML and Google Slides both expose pt). `ptToEmu` should
18
+ * never be called on a font size.
19
+ */
20
+ /** Authoring unit — what designers and component code use. */
21
+ export type Pt = number;
22
+ /** Office Open XML coordinate unit — what PPTX shape positions use. */
23
+ export type Emu = number;
24
+ /** EMU per inch (Office Open XML convention). */
25
+ export declare const EMU_PER_INCH = 914400;
26
+ /** EMU per point. `914400 / 72 = 12700`. */
27
+ export declare const EMU_PER_POINT = 12700;
28
+ /** Points per inch (typographic standard). */
29
+ export declare const PT_PER_INCH = 72;
30
+ /** Convert authoring points to API EMU. Rounds to integer EMU. */
31
+ export declare const ptToEmu: (pt: Pt) => Emu;
32
+ /** Convert inches to API EMU. Rounds to integer EMU. */
33
+ export declare const inToEmu: (inches: number) => Emu;
34
+ /** Convert points to inches. */
35
+ export declare const ptToIn: (pt: Pt) => number;
36
+ /** Convert inches to points. */
37
+ export declare const inToPt: (inches: number) => Pt;
38
+ /** A 2D point on the slide canvas. Origin top-left. */
39
+ export interface Point {
40
+ x: Pt;
41
+ y: Pt;
42
+ }
43
+ /** A 2D size on the slide canvas. */
44
+ export interface Size {
45
+ w: Pt;
46
+ h: Pt;
47
+ }
48
+ /** A canvas-aligned rectangle. */
49
+ export interface Rect extends Point, Size {
50
+ }
51
+ /**
52
+ * A canvas size + its precomputed EMU dimensions.
53
+ *
54
+ * Constructed once per supported aspect ratio. Reconciler reads `emuW`/`emuH`
55
+ * when emitting page-creation ops.
56
+ */
57
+ export interface Canvas {
58
+ /** Canvas width in points. */
59
+ readonly w: Pt;
60
+ /** Canvas height in points. */
61
+ readonly h: Pt;
62
+ /** Canvas width in EMU (precomputed). */
63
+ readonly emuW: Emu;
64
+ /** Canvas height in EMU (precomputed). */
65
+ readonly emuH: Emu;
66
+ }
67
+ /** 16:9 widescreen — the standard default. 13.333" × 7.5" → 960pt × 540pt. */
68
+ export declare const CANVAS_16_9: Canvas;
69
+ /** 4:3 classic — 10" × 7.5" → 720pt × 540pt. */
70
+ export declare const CANVAS_4_3: Canvas;
71
+ //# sourceMappingURL=geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/core/geometry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,8DAA8D;AAC9D,MAAM,MAAM,EAAE,GAAG,MAAM,CAAC;AAExB,uEAAuE;AACvE,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC;AAEzB,iDAAiD;AACjD,eAAO,MAAM,YAAY,SAAU,CAAC;AAEpC,4CAA4C;AAC5C,eAAO,MAAM,aAAa,QAAS,CAAC;AAEpC,8CAA8C;AAC9C,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,kEAAkE;AAClE,eAAO,MAAM,OAAO,GAAI,IAAI,EAAE,KAAG,GAAqC,CAAC;AAEvE,wDAAwD;AACxD,eAAO,MAAM,OAAO,GAAI,QAAQ,MAAM,KAAG,GAAwC,CAAC;AAElF,gCAAgC;AAChC,eAAO,MAAM,MAAM,GAAI,IAAI,EAAE,KAAG,MAA0B,CAAC;AAE3D,gCAAgC;AAChC,eAAO,MAAM,MAAM,GAAI,QAAQ,MAAM,KAAG,EAA0B,CAAC;AAEnE,uDAAuD;AACvD,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,EAAE,CAAC;IACN,CAAC,EAAE,EAAE,CAAC;CACP;AAED,qCAAqC;AACrC,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,EAAE,CAAC;IACN,CAAC,EAAE,EAAE,CAAC;CACP;AAED,kCAAkC;AAClC,MAAM,WAAW,IAAK,SAAQ,KAAK,EAAE,IAAI;CAAG;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,8BAA8B;IAC9B,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC;IACf,+BAA+B;IAC/B,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC;IACf,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;CACpB;AASD,8EAA8E;AAC9E,eAAO,MAAM,WAAW,EAAE,MAA6B,CAAC;AAExD,gDAAgD;AAChD,eAAO,MAAM,UAAU,EAAE,MAA6B,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Geometry primitives for slide layout.
3
+ *
4
+ * Two unit systems matter:
5
+ * - **Points (pt)** — the *authoring* unit. Designers and component code
6
+ * think in pt. 72 pt = 1 inch. Most slide measurements are integers at
7
+ * human-relevant scales.
8
+ * - **English Metric Units (EMU)** — the Office Open XML / PPTX coordinate
9
+ * unit. 914,400 EMU = 1 inch. Effectively never appears outside the
10
+ * runtime boundary.
11
+ *
12
+ * The conversion happens at *exactly one* point in the system: the boundary
13
+ * between the reconciler and the runtime. Everything above is pt; everything
14
+ * below is EMU.
15
+ *
16
+ * Font sizes are an exception: backends consume font size in pt directly
17
+ * (PPTX/Office Open XML and Google Slides both expose pt). `ptToEmu` should
18
+ * never be called on a font size.
19
+ */
20
+ /** EMU per inch (Office Open XML convention). */
21
+ export const EMU_PER_INCH = 914_400;
22
+ /** EMU per point. `914400 / 72 = 12700`. */
23
+ export const EMU_PER_POINT = 12_700;
24
+ /** Points per inch (typographic standard). */
25
+ export const PT_PER_INCH = 72;
26
+ /** Convert authoring points to API EMU. Rounds to integer EMU. */
27
+ export const ptToEmu = (pt) => Math.round(pt * EMU_PER_POINT);
28
+ /** Convert inches to API EMU. Rounds to integer EMU. */
29
+ export const inToEmu = (inches) => Math.round(inches * EMU_PER_INCH);
30
+ /** Convert points to inches. */
31
+ export const ptToIn = (pt) => pt / PT_PER_INCH;
32
+ /** Convert inches to points. */
33
+ export const inToPt = (inches) => inches * PT_PER_INCH;
34
+ const makeCanvas = (w, h) => ({
35
+ w,
36
+ h,
37
+ emuW: ptToEmu(w),
38
+ emuH: ptToEmu(h),
39
+ });
40
+ /** 16:9 widescreen — the standard default. 13.333" × 7.5" → 960pt × 540pt. */
41
+ export const CANVAS_16_9 = makeCanvas(960, 540);
42
+ /** 4:3 classic — 10" × 7.5" → 720pt × 540pt. */
43
+ export const CANVAS_4_3 = makeCanvas(720, 540);
44
+ //# sourceMappingURL=geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../src/core/geometry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,iDAAiD;AACjD,MAAM,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC;AAEpC,4CAA4C;AAC5C,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AAEpC,8CAA8C;AAC9C,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAE9B,kEAAkE;AAClE,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EAAM,EAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC;AAEvE,wDAAwD;AACxD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAO,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;AAElF,gCAAgC;AAChC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,EAAM,EAAU,EAAE,CAAC,EAAE,GAAG,WAAW,CAAC;AAE3D,gCAAgC;AAChC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAc,EAAM,EAAE,CAAC,MAAM,GAAG,WAAW,CAAC;AAkCnE,MAAM,UAAU,GAAG,CAAC,CAAK,EAAE,CAAK,EAAU,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,CAAC;IACD,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;CACjB,CAAC,CAAC;AAEH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,WAAW,GAAW,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAExD,gDAAgD;AAChD,MAAM,CAAC,MAAM,UAAU,GAAW,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public surface of `react-pptx`. The high-frequency symbols a template
3
+ * author or MCP framework needs.
4
+ *
5
+ * Specialized internals (PPTX op-translator, fake-runtime model types, etc.)
6
+ * live behind sub-path imports (`react-pptx/op-translator-pptx`,
7
+ * `react-pptx/fake-runtime`, …) so tree-shaking stays clean.
8
+ */
9
+ export { CANVAS_16_9, CANVAS_4_3, type Canvas, type Emu, type Pt, type Rect, ptToEmu, inToEmu, } from './geometry.js';
10
+ export type { Template, TypographyToken } from './template.js';
11
+ export { defineTemplate, defineTemplateComponent, type TemplateComponent } from './template.js';
12
+ export { type FontStack } from './font-resolver.js';
13
+ export type { ApplyOpsResult, EmuRect, HexColor, ShapeKind, ShapeProperties, SlideOp, SlidesRuntime, TextRange, TextStyle, ParagraphStyle, } from './runtime.js';
14
+ export { Slide, Box, Text, Color, Image, type SlideProps, type BoxProps, type BoxFill, type TextProps, type ColorProps, type ImageProps, type ImageRef, } from './components.js';
15
+ export { renderToOps, ReconcilerError, type RenderToOpsInput } from './reconciler.js';
16
+ export type { ArtifactRef, GenerationManifest, ReconcileResult, SlotId } from './manifest.js';
17
+ export { FakeSlidesRuntime, type FakeDeck } from './fake-runtime.js';
18
+ export { PptxSlidesRuntime, DEFAULT_PPTX_FONT_SUBSTITUTION, type PptxSlidesRuntimeOptions, } from './pptx-runtime.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACL,WAAW,EACX,UAAU,EACV,KAAK,MAAM,EACX,KAAK,GAAG,EACR,KAAK,EAAE,EACP,KAAK,IAAI,EACT,OAAO,EACP,OAAO,GACR,MAAM,eAAe,CAAC;AAGvB,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,YAAY,EACV,cAAc,EACd,OAAO,EACP,QAAQ,EACR,SAAS,EACT,eAAe,EACf,OAAO,EACP,aAAa,EACb,SAAS,EACT,SAAS,EACT,cAAc,GACf,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,KAAK,EACL,GAAG,EACH,IAAI,EACJ,KAAK,EACL,KAAK,EACL,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,QAAQ,GACd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGtF,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG9F,OAAO,EAAE,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EACL,iBAAiB,EACjB,8BAA8B,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Public surface of `react-pptx`. The high-frequency symbols a template
3
+ * author or MCP framework needs.
4
+ *
5
+ * Specialized internals (PPTX op-translator, fake-runtime model types, etc.)
6
+ * live behind sub-path imports (`react-pptx/op-translator-pptx`,
7
+ * `react-pptx/fake-runtime`, …) so tree-shaking stays clean.
8
+ */
9
+ // Canvas + units
10
+ export { CANVAS_16_9, CANVAS_4_3, ptToEmu, inToEmu, } from './geometry.js';
11
+ export { defineTemplate, defineTemplateComponent } from './template.js';
12
+ export {} from './font-resolver.js';
13
+ // JSX primitives a template's components build on
14
+ export { Slide, Box, Text, Color, Image, } from './components.js';
15
+ // Reconciler entry point
16
+ export { renderToOps, ReconcilerError } from './reconciler.js';
17
+ // Runtimes
18
+ export { FakeSlidesRuntime } from './fake-runtime.js';
19
+ export { PptxSlidesRuntime, DEFAULT_PPTX_FONT_SUBSTITUTION, } from './pptx-runtime.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,iBAAiB;AACjB,OAAO,EACL,WAAW,EACX,UAAU,EAKV,OAAO,EACP,OAAO,GACR,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAA0B,MAAM,eAAe,CAAC;AAChG,OAAO,EAAkB,MAAM,oBAAoB,CAAC;AAgBpD,kDAAkD;AAClD,OAAO,EACL,KAAK,EACL,GAAG,EACH,IAAI,EACJ,KAAK,EACL,KAAK,GAQN,MAAM,iBAAiB,CAAC;AAEzB,yBAAyB;AACzB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAyB,MAAM,iBAAiB,CAAC;AAKtF,WAAW;AACX,OAAO,EAAE,iBAAiB,EAAiB,MAAM,mBAAmB,CAAC;AACrE,OAAO,EACL,iBAAiB,EACjB,8BAA8B,GAE/B,MAAM,mBAAmB,CAAC"}