@office-kit/pptx-dsl 0.3.0 → 0.5.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.
package/README.md CHANGED
@@ -50,24 +50,103 @@ Layout is explicit: CSS and automatic UI layout are not implemented.
50
50
 
51
51
  ## Elements
52
52
 
53
- | Element | Input |
54
- | -------------- | ------------------------------------------------------------------------ |
55
- | `Presentation` | Optional source PPTX bytes or `size`, theme, `mode` |
56
- | `Slide` | Source `from` or edit `target`, layout, background, notes |
57
- | `Text` | Literal children or core `ParagraphSpec[]` via `paragraphs`, text format |
58
- | `Shape` | Core preset geometry, fill, stroke, effects, optional text |
59
- | `Image` | Bytes in `data`, optional format and fit |
60
- | `Media` | `kind` `video` / `audio` with bytes in `data`, or `online` with a `url` |
61
- | `Chart` | Complete core `ChartSpec` via `spec` |
62
- | `Table` | String rows, column widths, row heights, cell/header styles, stripe fill |
63
- | `Fill` | Existing shape target, replacement text, optional format |
64
- | `Remove` | Existing shape target |
65
- | `Raw` | Deferred callback receiving the presentation and enclosing slide/shape |
53
+ | Element | Input |
54
+ | -------------- | ------------------------------------------------------------------------- |
55
+ | `Presentation` | Optional source PPTX bytes or `size`, theme, `mode` |
56
+ | `Slide` | Source `from` or edit `target`, layout, background, notes |
57
+ | `Text` | Literal children or core `ParagraphSpec[]` via `paragraphs`, text format |
58
+ | `Shape` | Core preset geometry, fill, stroke, effects, optional text |
59
+ | `Line` | End points `x1` `y1` `x2` `y2`, `color`, `width` |
60
+ | `Group` | Groups the shapes its children create; optional `name` |
61
+ | `Image` | Bytes in `data`, optional format and fit |
62
+ | `Media` | `kind` `video` / `audio` with bytes in `data`, or `online` with a `url` |
63
+ | `Chart` | Complete core `ChartSpec` via `spec` |
64
+ | `Table` | Rows of strings, rich cells or merges; sizes; cell styles and `styleCell` |
65
+ | `Fill` | Existing shape target, replacement text, optional format and `autoFit` |
66
+ | `Remove` | Existing shape target |
67
+ | `Raw` | Deferred callback receiving the presentation and enclosing slide/shape |
66
68
 
67
69
  Bounds are required for newly created visual objects. Shape styles support solid
68
70
  and gradient fills, stroke, rotation, shadow, glow and click actions. `Text`
69
- accepts the core `TextFormat` properties directly, plus alignment, anchor and
70
- text auto-fit. Table cell formats are merged with header overrides.
71
+ accepts the core `TextFormat` properties directly, plus alignment, anchor,
72
+ text auto-fit, `bullets` and `paragraphSpacing` (both apply to every paragraph; a
73
+ newline in the text starts one). A `Shape` with `text` takes `align` and `anchor`.
74
+
75
+ Each entry of `paragraphs` is a core `ParagraphSpec` that also takes its own `bullet`
76
+ and `level`. The paragraph's `bullet` wins over `bullets`, so `bullet: 'none'` keeps a
77
+ heading line out of the list. `level` is the `TextLevel` type, `0` to `8`, and nests
78
+ the list; `tsc` rejects any other number.
79
+
80
+ ```tsx
81
+ <Text
82
+ x={1}
83
+ y={1}
84
+ width={8}
85
+ height={3}
86
+ bullets="bullet"
87
+ paragraphs={[
88
+ { runs: [{ text: 'What changed' }], bullet: 'none' },
89
+ { runs: [{ text: 'Churn fell to 4.2%' }] },
90
+ { runs: [{ text: 'Driver: simpler setup' }], level: 1, bullet: { char: '–' } },
91
+ ]}
92
+ />
93
+ ```
94
+
95
+ A `Line` runs from (`x1`, `y1`) to (`x2`, `y2`) instead of taking bounds. A
96
+ `Group` holds two or more visual elements and may contain other groups; the
97
+ result moves and resizes as one object in PowerPoint.
98
+
99
+ A table cell style sets `fill`, `format`, `anchor`, `align` and `borders` (per
100
+ side, `width` in points). Styles merge in this order, later ones winning per
101
+ field: `cellStyle`, `headerStyle` (row 0), `stripeFill` (even body rows), then
102
+ `styleCell`, a callback that receives `{ row, column, value }`:
103
+
104
+ ```tsx
105
+ <Table
106
+ x={1}
107
+ y={1}
108
+ width={8}
109
+ height={3}
110
+ rows={rows}
111
+ cellStyle={{ borders: { bottom: { color: '#D5D9E0', width: 0.75 } } }}
112
+ styleCell={({ row, value }) =>
113
+ row > 0 && value === 'At risk' ? { fill: '#D64545', format: { color: '#FFFFFF' } } : undefined
114
+ }
115
+ />
116
+ ```
117
+
118
+ A cell in `rows` is a string or a cell object, `{ text }` or `{ paragraphs }`, never
119
+ both or neither. `paragraphs` takes core `ParagraphSpec[]` for more than one run or
120
+ paragraph in a cell. The merged cell style is the base of every run, so a run states
121
+ only what differs, and the style's `align` applies unless a paragraph has its own.
122
+ `styleCell` receives a rich cell's `value` as its run texts joined, one line per
123
+ paragraph.
124
+
125
+ `colSpan` and `rowSpan` on a cell object make it the top-left of a merge. `rows` stays
126
+ a full rectangular grid, so a column index means the same in every row: each position
127
+ the merge covers is written as `''`, and anything else there is an error because
128
+ a covered cell's text is never shown. The merged block takes its fill and borders from
129
+ its top-left cell (this is how the preview renders it), so covered positions get no
130
+ style and `styleCell` is not called for them. Spans that leave the grid or overlap throw the core error.
131
+
132
+ ```tsx
133
+ <Table
134
+ x={1}
135
+ y={1}
136
+ width={8}
137
+ height={3}
138
+ rows={[
139
+ [{ text: 'Plan', rowSpan: 2 }, { text: 'Effect', colSpan: 2 }, ''],
140
+ ['', 'Count', 'Change'],
141
+ [
142
+ 'FAQ',
143
+ '372',
144
+ { paragraphs: [{ runs: [{ text: '+26% ' }, { text: 'QoQ', format: { bold: true } }] }] },
145
+ ],
146
+ ]}
147
+ cellStyle={{ format: { size: 14 } }}
148
+ />
149
+ ```
71
150
 
72
151
  `Media` embeds a video or audio clip from bytes, or links an online video by
73
152
  URL (YouTube page URLs are rewritten to the embed form). `poster` supplies the
@@ -102,6 +181,8 @@ slides; use `<Slide from={{index: 0}}>` to duplicate an original slide. Referenc
102
181
  always refer to the source sequence, and each compilation loads the source fresh.
103
182
  A source deck is not reconstructed from DSL-understood fields: the core package
104
183
  retains existing parts. Editing text intentionally replaces that shape's text.
184
+ `Fill` takes the same `autoFit` values as `Text` (`"normal"` shrinks text that is
185
+ longer than the placeholder); omitted, the shape keeps the template's setting.
105
186
  `size` applies only to new decks; source decks retain their original dimensions.
106
187
  `theme` accepts the core theme overrides and follows its first-theme semantics.
107
188
 
@@ -136,11 +217,50 @@ context-specific handles and a nesting check. Without scope, contextual handles
136
217
  are optional. Text also
137
218
  accepts Raw children. An enclosing shape does not accept new Slide-level objects.
138
219
 
220
+ ## Embedding `compile()` in your own build
221
+
222
+ An `office-pptx init` project comes with a build that records source locations and
223
+ a `check` script that runs `tsc --noEmit`. A host that calls `compile()` from its own
224
+ build (a server compiling generated TSX, a bundler plugin) has to arrange both.
225
+
226
+ **Build with the dev JSX transform to get source locations.** `compile()` prefixes
227
+ an error with `file:line:col <Element>:` for each enclosing element, but only when the
228
+ module was built with the dev runtime, which records where each element was written.
229
+ `office-pptx` always builds that way.
230
+
231
+ | Tool | Setting |
232
+ | ---------- | ---------------------------------------------- |
233
+ | TypeScript | `"jsx": "react-jsxdev"` instead of `react-jsx` |
234
+ | esbuild | `jsx: 'automatic', jsxDev: true` |
235
+
236
+ ```text
237
+ react-jsx Shape reference matched 0 shapes: {"name":"Titel 1"}
238
+ react-jsxdev deck.tsx:6:7 <Slide>: deck.tsx:7:9 <Fill>: Shape reference matched 0 shapes: {"name":"Titel 1"}
239
+ ```
240
+
241
+ **Type-check authored modules with `tsc` in strict mode.** The runtime does not
242
+ validate prop names, so `<Table cellFills={...}>` compiles and the unknown prop is
243
+ ignored. Type checking is what rejects it, along with a misspelt literal such as
244
+ `anchor="ctr"`. A transpile-only build (esbuild, swc) skips that check, and a prop
245
+ passed through an object spread escapes it even in `tsc`.
246
+
247
+ **Compile and save.** `compile(root)` takes the root `Presentation` element (a
248
+ module's default export) and resolves to the core presentation; `savePresentation`
249
+ from `@office-kit/pptx` turns that into `.pptx` bytes. Template bytes go in through
250
+ `<Presentation source={bytes}>`, from wherever the host holds them.
251
+
252
+ ```ts
253
+ import { savePresentation } from '@office-kit/pptx';
254
+ import { compile } from '@office-kit/pptx-dsl';
255
+
256
+ const { default: root } = await import(builtModuleUrl);
257
+ const bytes = await savePresentation(await compile(root));
258
+ ```
259
+
139
260
  ## Current coverage
140
261
 
141
262
  This is an initial DSL, not complete OOXML coverage. Typed master/layout creation,
142
- animations, transitions, connectors, groups, media playback, and structured table
143
- cells still require additional declarative elements or core work. Raw can invoke
263
+ animations, transitions, connectors, groups and media playback still require additional declarative elements or core work. Raw can invoke
144
264
  available core capabilities but does not count as typed declarative support.
145
265
  Cross-presentation imports are not exposed because the current core import API
146
266
  can discard unsupported relationships. Do not use it as a lossless import path.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { c as Node, l as PresentationNode, o as Child, s as Children, t as Fragment, u as RawContext } from "./jsx-runtime-C-Ggfem1.js";
1
+ import { c as Node, l as PresentationNode, o as Child, s as Children, t as Fragment, u as RawContext } from "./jsx-runtime-D7IpzvWG.js";
2
2
  import * as api from "@office-kit/pptx";
3
3
 
4
4
  //#region src/index.d.ts
@@ -84,17 +84,34 @@ interface ShapeStyle {
84
84
  glow?: api.GlowOptions;
85
85
  click?: api.ShapeClickAction;
86
86
  }
87
+ /** A paragraph's indent level: 0 is the top, 8 the deepest PowerPoint has. */
88
+ type TextLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
89
+ interface TextParagraph extends api.ParagraphSpec {
90
+ /** This paragraph's own bullet; wins over `bullets`. */
91
+ bullet?: api.BulletStyle;
92
+ level?: TextLevel;
93
+ }
87
94
  interface TextProps extends Bounds, ShapeStyle, api.TextFormat, Children {
88
- paragraphs?: readonly api.ParagraphSpec[];
95
+ paragraphs?: readonly TextParagraph[];
89
96
  align?: api.ParagraphAlignment;
90
97
  anchor?: api.TextAnchor;
91
98
  autoFit?: api.TextAutoFit;
99
+ /** Bullet or numbering for every paragraph; a newline in the text starts a paragraph. */
100
+ bullets?: api.BulletStyle;
101
+ /** Space before / after every paragraph, in points. */
102
+ paragraphSpacing?: {
103
+ before?: number;
104
+ after?: number;
105
+ };
92
106
  }
93
107
  declare function Text(props: TextProps): Node;
94
108
  interface ShapeProps extends Bounds, ShapeStyle, Children {
95
109
  preset: Parameters<typeof api.addSlideShape>[1]['preset'];
96
110
  text?: string;
97
111
  format?: api.TextFormat;
112
+ /** Alignment and anchor of `text` inside the shape. */
113
+ align?: api.ParagraphAlignment;
114
+ anchor?: api.TextAnchor;
98
115
  }
99
116
  declare function Shape(props: ShapeProps): Node;
100
117
  interface ImageProps extends Bounds, ShapeStyle, Children {
@@ -113,29 +130,79 @@ interface ChartProps extends Bounds, ShapeStyle, Children {
113
130
  spec: api.ChartSpec;
114
131
  }
115
132
  declare function Chart(props: ChartProps): Node;
133
+ type CellBorderSide = 'left' | 'right' | 'top' | 'bottom';
116
134
  interface CellStyle {
117
135
  fill?: string;
118
136
  format?: api.TextFormat;
119
137
  anchor?: api.TextAnchor;
138
+ align?: api.ParagraphAlignment;
139
+ /** Border per side. `width` is in points; without it the line has no explicit width. */
140
+ borders?: Partial<Record<CellBorderSide, {
141
+ color: string;
142
+ width?: number;
143
+ }>>;
144
+ }
145
+ interface TableCellInfo {
146
+ /** Zero-based; row 0 is the header. */
147
+ row: number;
148
+ column: number;
149
+ /** A cell's text; for `paragraphs`, the run texts joined, one line per paragraph. */
150
+ value: string;
120
151
  }
152
+ /** Exactly one of `text` and `paragraphs`. An empty cell is the string `''`. */
153
+ type TableCellContent = {
154
+ text: string;
155
+ paragraphs?: never;
156
+ } | {
157
+ text?: never;
158
+ paragraphs: readonly api.ParagraphSpec[];
159
+ };
160
+ type TableCellSpec = TableCellContent & {
161
+ /** This cell is the top-left of a merge. The positions it covers stay in `rows` as `''`. */colSpan?: number;
162
+ rowSpan?: number;
163
+ };
164
+ type TableCell = string | TableCellSpec;
121
165
  interface TableProps extends Bounds, Children {
122
- rows: readonly (readonly string[])[];
166
+ rows: readonly (readonly TableCell[])[];
123
167
  columnWidths?: readonly number[];
124
168
  rowHeights?: readonly number[];
125
169
  cellStyle?: CellStyle;
126
170
  headerStyle?: CellStyle;
127
171
  stripeFill?: string;
172
+ /**
173
+ * Style for one cell, merged over `cellStyle`, `headerStyle` and
174
+ * `stripeFill` — for a status column, a total row, a highlighted figure.
175
+ */
176
+ styleCell?: (cell: TableCellInfo) => CellStyle | undefined;
128
177
  }
129
178
  declare function Table(props: TableProps): Node;
179
+ interface LineProps {
180
+ x1: number;
181
+ y1: number;
182
+ x2: number;
183
+ y2: number;
184
+ color?: string;
185
+ /** Stroke width in points. */
186
+ width?: number;
187
+ name?: string;
188
+ }
189
+ declare function Line(props: LineProps): Node;
190
+ interface GroupProps extends Children {
191
+ name?: string;
192
+ }
193
+ /** Groups the shapes its children create, so they move and resize as one object. */
194
+ declare function Group(props: GroupProps): Node;
130
195
  interface FillProps extends Children {
131
196
  target: Target;
132
197
  text?: string;
133
198
  format?: api.TextFormat;
199
+ /** Omitted keeps whatever the template's `<a:bodyPr>` says. */
200
+ autoFit?: api.TextAutoFit;
134
201
  }
135
202
  declare function Fill(props: FillProps): Node;
136
203
  declare function Remove(props: {
137
204
  target: Target;
138
205
  }): Node;
139
206
  //#endregion
140
- export { Bounds, CellStyle, Chart, ChartProps, type Child, type Children, Fill, FillProps, Fragment, Image, ImageProps, LayoutRef, Media, MediaProps, type Node, Presentation, type PresentationNode, PresentationProps, Raw, type RawContext, RawProps, Remove, Shape, ShapeProps, ShapeStyle, Slide, SlideProps, SlideRef, Table, TableProps, Target, Text, TextProps, compile };
207
+ export { Bounds, CellBorderSide, CellStyle, Chart, ChartProps, type Child, type Children, Fill, FillProps, Fragment, Group, GroupProps, Image, ImageProps, LayoutRef, Line, LineProps, Media, MediaProps, type Node, Presentation, type PresentationNode, PresentationProps, Raw, type RawContext, RawProps, Remove, Shape, ShapeProps, ShapeStyle, Slide, SlideProps, SlideRef, Table, TableCell, TableCellInfo, TableCellSpec, TableProps, Target, Text, TextLevel, TextParagraph, TextProps, compile };
141
208
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as literal, c as textContent, l as visit, o as node, s as requireSlide, t as Fragment } from "./jsx-runtime-BgfNl42k.js";
1
+ import { a as created, c as requireSlide, l as textContent, o as literal, s as node, t as Fragment, u as visit } from "./jsx-runtime-DoUxctgW.js";
2
2
  import * as api from "@office-kit/pptx";
3
3
  //#region src/index.ts
4
4
  function Presentation(props) {
@@ -106,16 +106,31 @@ function Text(props) {
106
106
  const slide = requireSlide(context);
107
107
  const content = textContent(props.children);
108
108
  if (props.paragraphs && content.text.trim()) throw new Error("Text accepts either text children or paragraphs.");
109
- const shape = api.addSlideTextBox(slide, {
109
+ const shape = created(context, api.addSlideTextBox(slide, {
110
110
  ...bounds(props),
111
111
  ...props.name ? { name: props.name } : {},
112
112
  text: content.text
113
- });
113
+ }));
114
114
  if (props.paragraphs) api.setShapeParagraphs(shape, props.paragraphs);
115
115
  api.setShapeTextFormat(shape, props);
116
116
  if (props.align) api.setShapeAlignment(shape, props.align);
117
117
  if (props.anchor) api.setShapeTextAnchor(shape, props.anchor);
118
118
  if (props.autoFit) api.setShapeTextAutoFit(shape, props.autoFit);
119
+ props.paragraphs?.forEach((paragraph, index) => {
120
+ if (paragraph.level !== void 0) api.setParagraphLevel(shape, index, paragraph.level);
121
+ });
122
+ if (props.bullets !== void 0) api.setShapeBullets(shape, props.bullets);
123
+ props.paragraphs?.forEach((paragraph, index) => {
124
+ if (paragraph.bullet !== void 0) api.setParagraphBullet(shape, index, paragraph.bullet);
125
+ });
126
+ if (props.paragraphSpacing) {
127
+ const { before, after } = props.paragraphSpacing;
128
+ const spacing = {
129
+ ...before !== void 0 ? { beforePts: before } : {},
130
+ ...after !== void 0 ? { afterPts: after } : {}
131
+ };
132
+ for (let i = 0; i < api.getShapeParagraphCount(shape); i++) api.setParagraphSpacing(shape, i, spacing);
133
+ }
119
134
  style(shape, props);
120
135
  await visit(content.elements, {
121
136
  ...context,
@@ -127,14 +142,17 @@ function Text(props) {
127
142
  }
128
143
  function Shape(props) {
129
144
  return node("Shape", async (context) => {
130
- const shape = api.addSlideShape(requireSlide(context), {
145
+ if ((props.align || props.anchor) && props.text === void 0) throw new Error("Shape align and anchor position its text; set text as well.");
146
+ const shape = created(context, api.addSlideShape(requireSlide(context), {
131
147
  ...bounds(props),
132
148
  preset: props.preset,
133
149
  ...props.name ? { name: props.name } : {},
134
150
  ...props.text !== void 0 ? { text: props.text } : {}
135
- });
151
+ }));
136
152
  style(shape, props);
137
153
  if (props.format) api.setShapeTextFormat(shape, props.format);
154
+ if (props.align) api.setShapeAlignment(shape, props.align);
155
+ if (props.anchor) api.setShapeTextAnchor(shape, props.anchor);
138
156
  await visit(props.children, {
139
157
  ...context,
140
158
  shape,
@@ -144,12 +162,12 @@ function Shape(props) {
144
162
  }
145
163
  function Image(props) {
146
164
  return node("Image", async (context) => {
147
- const shape = api.addSlideImage(requireSlide(context), props.data, {
165
+ const shape = created(context, api.addSlideImage(requireSlide(context), props.data, {
148
166
  ...bounds(props),
149
167
  ...props.format ? { format: props.format } : {},
150
168
  ...props.fit ? { fit: props.fit } : {},
151
169
  ...props.name ? { name: props.name } : {}
152
- });
170
+ }));
153
171
  style(shape, props);
154
172
  await visit(props.children, {
155
173
  ...context,
@@ -161,10 +179,10 @@ function Image(props) {
161
179
  function Media(props) {
162
180
  return node("Media", async (context) => {
163
181
  const { x: _x, y: _y, width: _width, height: _height, children, ...media } = props;
164
- const shape = api.addSlideMedia(requireSlide(context), {
182
+ const shape = created(context, api.addSlideMedia(requireSlide(context), {
165
183
  ...media,
166
184
  ...bounds(props)
167
- });
185
+ }));
168
186
  await visit(children, {
169
187
  ...context,
170
188
  shape,
@@ -174,11 +192,11 @@ function Media(props) {
174
192
  }
175
193
  function Chart(props) {
176
194
  return node("Chart", async (context) => {
177
- const shape = api.addSlideChart(requireSlide(context), {
195
+ const shape = created(context, api.addSlideChart(requireSlide(context), {
178
196
  ...bounds(props),
179
197
  spec: props.spec,
180
198
  ...props.name ? { name: props.name } : {}
181
- });
199
+ }));
182
200
  style(shape, props);
183
201
  await visit(props.children, {
184
202
  ...context,
@@ -187,28 +205,119 @@ function Chart(props) {
187
205
  });
188
206
  });
189
207
  }
208
+ function cellBorders(borders) {
209
+ const sides = {};
210
+ for (const side of [
211
+ "left",
212
+ "right",
213
+ "top",
214
+ "bottom"
215
+ ]) {
216
+ const border = borders[side];
217
+ if (!border) continue;
218
+ sides[side] = {
219
+ color: border.color,
220
+ ...border.width !== void 0 ? { widthEmu: api.pt(border.width) } : {}
221
+ };
222
+ }
223
+ return sides;
224
+ }
225
+ const positionKey = (row, col) => `${row}:${col}`;
226
+ const cellSpec = (cell) => typeof cell === "string" ? { text: cell } : cell;
227
+ const cellValue = (spec) => spec.paragraphs ? spec.paragraphs.map((paragraph) => paragraph.runs.map((run) => run.text).join("")).join("\n") : spec.text;
228
+ /** Maps every position a merge covers to that merge's top-left cell. */
229
+ function coveredPositions(rows) {
230
+ const covered = /* @__PURE__ */ new Map();
231
+ rows.forEach((cells, row) => cells.forEach((cell, col) => {
232
+ const { rowSpan = 1, colSpan = 1 } = cellSpec(cell);
233
+ const lastRow = Math.min(row + rowSpan, rows.length);
234
+ const lastCol = Math.min(col + colSpan, cells.length);
235
+ for (let r = row; r < lastRow; r++) for (let c = col; c < lastCol; c++) if (r !== row || c !== col) covered.set(positionKey(r, c), {
236
+ row,
237
+ col
238
+ });
239
+ }));
240
+ return covered;
241
+ }
242
+ function checkCells(rows, covered) {
243
+ rows.forEach((cells, row) => cells.forEach((cell, col) => {
244
+ const spec = cellSpec(cell);
245
+ if (spec.text === void 0 === (spec.paragraphs === void 0)) throw new Error(`Table cell (${row}, ${col}) accepts either text or paragraphs.`);
246
+ const anchor = covered.get(positionKey(row, col));
247
+ if (anchor && cell !== "") throw new Error(`Table cell (${row}, ${col}) is covered by the merge at (${anchor.row}, ${anchor.col}); write it as ''.`);
248
+ }));
249
+ }
190
250
  function Table(props) {
191
251
  return node("Table", async (context) => {
192
- const shape = api.addSlideTable(requireSlide(context), {
252
+ const covered = coveredPositions(props.rows);
253
+ checkCells(props.rows, covered);
254
+ const shape = created(context, api.addSlideTable(requireSlide(context), {
193
255
  ...bounds(props),
194
- rows: props.rows,
256
+ rows: props.rows.map((cells) => cells.map((cell) => cellSpec(cell).text ?? "")),
195
257
  ...props.columnWidths ? { colWidths: props.columnWidths.map(api.inches) } : {},
196
258
  ...props.rowHeights ? { rowHeights: props.rowHeights.map(api.inches) } : {}
197
- });
198
- props.rows.forEach((row, r) => row.forEach((_, c) => {
259
+ }));
260
+ props.rows.forEach((row, r) => row.forEach((entry, c) => {
261
+ if (covered.has(positionKey(r, c))) return;
262
+ const spec = cellSpec(entry);
199
263
  const cell = api.getTableCell(shape, r, c);
264
+ const header = r === 0 ? props.headerStyle : void 0;
265
+ const own = props.styleCell?.({
266
+ row: r,
267
+ column: c,
268
+ value: cellValue(spec)
269
+ });
270
+ const striped = r > 0 && r % 2 === 0 ? props.stripeFill : void 0;
200
271
  const appearance = {
201
272
  ...props.cellStyle,
202
- ...r === 0 ? props.headerStyle : {},
273
+ ...header,
274
+ ...striped !== void 0 ? { fill: striped } : {},
275
+ ...own,
203
276
  format: {
204
277
  ...props.cellStyle?.format,
205
- ...r === 0 ? props.headerStyle?.format : {}
278
+ ...header?.format,
279
+ ...own?.format
206
280
  }
207
281
  };
208
282
  if (appearance.fill) api.setTableCellFill(cell, appearance.fill);
209
- if (r > 0 && r % 2 === 0 && props.stripeFill) api.setTableCellFill(cell, props.stripeFill);
210
- if (appearance.format) api.setTableCellTextFormat(cell, appearance.format);
283
+ if (spec.paragraphs) {
284
+ const built = api.getTableCellParagraphs(cell)[0]?.elements[0];
285
+ const base = {
286
+ ...built?.kind === "r" ? built.format : {},
287
+ ...appearance.format
288
+ };
289
+ const { align } = appearance;
290
+ api.setTableCellParagraphs(cell, spec.paragraphs.map((paragraph) => ({
291
+ ...paragraph,
292
+ ...paragraph.align === void 0 && align ? { align } : {},
293
+ runs: paragraph.runs.map((run) => ({
294
+ ...run,
295
+ format: {
296
+ ...base,
297
+ ...run.format
298
+ }
299
+ }))
300
+ })));
301
+ } else {
302
+ if (appearance.format) api.setTableCellTextFormat(cell, appearance.format);
303
+ if (appearance.align) api.setTableCellAlignment(cell, appearance.align);
304
+ }
211
305
  if (appearance.anchor) api.setTableCellAnchor(cell, appearance.anchor);
306
+ const borders = cellBorders({
307
+ ...props.cellStyle?.borders,
308
+ ...header?.borders,
309
+ ...own?.borders
310
+ });
311
+ if (Object.keys(borders).length > 0) api.setTableCellBorders(cell, borders);
312
+ }));
313
+ props.rows.forEach((row, r) => row.forEach((entry, c) => {
314
+ const { rowSpan = 1, colSpan = 1 } = cellSpec(entry);
315
+ if (rowSpan !== 1 || colSpan !== 1) api.mergeTableCells(shape, {
316
+ row: r,
317
+ col: c,
318
+ rowSpan,
319
+ colSpan
320
+ });
212
321
  }));
213
322
  await visit(props.children, {
214
323
  ...context,
@@ -217,6 +326,35 @@ function Table(props) {
217
326
  });
218
327
  });
219
328
  }
329
+ function Line(props) {
330
+ return node("Line", (context) => {
331
+ created(context, api.addSlideLine(requireSlide(context), {
332
+ from: {
333
+ x: api.inches(props.x1),
334
+ y: api.inches(props.y1)
335
+ },
336
+ to: {
337
+ x: api.inches(props.x2),
338
+ y: api.inches(props.y2)
339
+ },
340
+ ...props.color !== void 0 ? { color: props.color } : {},
341
+ ...props.width !== void 0 ? { widthEmu: api.pt(props.width) } : {},
342
+ ...props.name ? { name: props.name } : {}
343
+ }));
344
+ });
345
+ }
346
+ /** Groups the shapes its children create, so they move and resize as one object. */
347
+ function Group(props) {
348
+ return node("Group", async (context) => {
349
+ requireSlide(context);
350
+ const members = [];
351
+ await visit(props.children, {
352
+ ...context,
353
+ members
354
+ });
355
+ created(context, api.groupShapes(members, props.name ? { name: props.name } : {}));
356
+ });
357
+ }
220
358
  function selectShape(slide, target) {
221
359
  const matches = api.getSlideShapes(slide).filter((shape) => {
222
360
  if ("name" in target) return api.getShapeName(shape) === target.name;
@@ -232,6 +370,7 @@ function Fill(props) {
232
370
  const shape = selectShape(requireSlide(context), props.target);
233
371
  api.setShapeText(shape, props.text ?? literal(props.children));
234
372
  if (props.format) api.setShapeTextFormat(shape, props.format);
373
+ if (props.autoFit) api.setShapeTextAutoFit(shape, props.autoFit);
235
374
  });
236
375
  }
237
376
  function Remove(props) {
@@ -241,6 +380,6 @@ function Remove(props) {
241
380
  });
242
381
  }
243
382
  //#endregion
244
- export { Chart, Fill, Fragment, Image, Media, Presentation, Raw, Remove, Shape, Slide, Table, Text, compile };
383
+ export { Chart, Fill, Fragment, Group, Image, Line, Media, Presentation, Raw, Remove, Shape, Slide, Table, Text, compile };
245
384
 
246
385
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import * as api from '@office-kit/pptx';\nimport {\n textContent,\n literal,\n node,\n requireSlide,\n visit,\n type Children,\n type Context,\n type Node,\n type PresentationNode,\n type RawContext,\n} from './model.ts';\nexport type { Child, Children, Node, PresentationNode, RawContext } from './model.ts';\nexport { Fragment } from './jsx-runtime.ts';\n\nexport type PresentationProps = Children &\n (\n | { source: api.PresentationInput; size?: never }\n | { source?: never; size?: api.PresentationSize }\n ) & {\n theme?: Parameters<typeof api.setPresentationTheme>[1];\n /** Compose replaces the slide sequence; edit retains the original sequence. */\n mode?: 'compose' | 'edit';\n };\nexport function Presentation(props: PresentationProps): PresentationNode {\n return {\n kind: 'Presentation',\n evaluate: () => {\n throw new Error('Presentation must be the root.');\n },\n async compile() {\n if (props.source !== undefined && props.size !== undefined)\n throw new Error('Presentation source retains its original size; do not specify size.');\n const presentation =\n props.source === undefined\n ? api.createPresentation(props.size === undefined ? {} : { size: props.size })\n : await api.loadPresentation(props.source);\n if (props.theme) api.setPresentationTheme(presentation, props.theme);\n const originals = [...api.getSlides(presentation)];\n const context: Context = {\n presentation,\n originals,\n mode: props.mode ?? (props.source === undefined ? 'compose' : 'edit'),\n scope: 'presentation',\n deferred: [],\n };\n await visit(props.children, context);\n for (const apply of context.deferred) await apply();\n if (context.mode === 'compose') {\n for (const slide of originals) api.removeSlide(presentation, slide);\n }\n return presentation;\n },\n };\n}\nexport async function compile(root: Node): Promise<api.PresentationData> {\n if (!('compile' in root) || typeof root.compile !== 'function')\n throw new Error('Export a Presentation as the root.');\n return root.compile();\n}\n\nexport type LayoutRef = { name: string } | { part: string } | { type: string };\nexport type SlideRef = { index: number } | { part: string } | { title: string };\nexport type Target =\n | { name: string }\n | { id: number }\n | { placeholder: { type?: string; idx?: number } };\nexport type SlideProps = Children &\n ({ from?: SlideRef; target?: never } | { from?: never; target: SlideRef }) & {\n layout?: LayoutRef;\n background?: string;\n notes?: string;\n };\nfunction selectSlide(context: Context, ref: SlideRef): api.SlideData {\n const matches = context.originals.filter((slide, index) =>\n 'index' in ref\n ? index === ref.index\n : 'part' in ref\n ? api.getSlidePartName(slide) === ref.part\n : api.getSlideTitle(slide) === ref.title,\n );\n if (matches.length !== 1)\n throw new Error(`Slide reference matched ${matches.length} slides: ${JSON.stringify(ref)}`);\n return matches[0]!;\n}\nfunction selectLayout(presentation: api.PresentationData, ref: LayoutRef): api.SlideLayoutData {\n const matches = api\n .getSlideLayouts(presentation)\n .filter((layout) =>\n 'name' in ref\n ? api.getSlideLayoutName(layout) === ref.name\n : 'part' in ref\n ? api.getSlideLayoutPartName(layout) === ref.part\n : api.getSlideLayoutType(layout) === ref.type,\n );\n if (matches.length !== 1)\n throw new Error(`Layout reference matched ${matches.length} layouts: ${JSON.stringify(ref)}`);\n return matches[0]!;\n}\nexport function Slide(props: SlideProps): Node {\n return node('Slide', async (context) => {\n if (context.scope !== 'presentation') throw new Error('Slide must be inside Presentation.');\n if (props.target && context.mode !== 'edit')\n throw new Error('Slide target requires Presentation mode=\"edit\".');\n if (props.from && props.target) throw new Error('Slide cannot specify both from and target.');\n const layout = props.layout ? selectLayout(context.presentation, props.layout) : undefined;\n const slide = props.target\n ? selectSlide(context, props.target)\n : props.from\n ? api.duplicateSlide(context.presentation, selectSlide(context, props.from))\n : layout\n ? api.addSlide(context.presentation, { layout })\n : api.addBlankSlide(context.presentation);\n if (layout && (props.from || props.target)) api.setSlideLayout(slide, layout);\n if (props.background !== undefined) api.setSlideBackground(slide, props.background);\n if (props.notes !== undefined) api.setSlideNotes(slide, props.notes);\n await visit(props.children, { ...context, slide, scope: 'slide' });\n });\n}\nexport type RawProps =\n | { scope?: undefined; apply: (context: RawContext) => void | Promise<void> }\n | {\n scope: 'presentation';\n apply: (context: Pick<RawContext, 'presentation'>) => void | Promise<void>;\n }\n | {\n scope: 'slide';\n apply: (context: RawContext & { slide: api.SlideData }) => void | Promise<void>;\n }\n | { scope: 'shape'; apply: (context: Required<RawContext>) => void | Promise<void> };\n\nexport function Raw(props: RawProps): Node {\n return node('Raw', (context) => {\n if (props.scope !== undefined && props.scope !== context.scope) {\n throw new Error(`Raw scope=\"${props.scope}\" cannot run inside ${context.scope}.`);\n }\n context.deferred.push(() => {\n if (props.scope === 'shape') {\n if (!context.shape || !context.slide) throw new Error('Raw requires a shape context.');\n return props.apply({\n presentation: context.presentation,\n slide: context.slide,\n shape: context.shape,\n });\n }\n if (props.scope === 'slide') {\n if (!context.slide) throw new Error('Raw requires a slide context.');\n return props.apply({ ...context, slide: context.slide });\n }\n return props.apply(context);\n });\n });\n}\nexport interface Bounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\nexport interface ShapeStyle {\n name?: string;\n fill?: string | api.GradientFillOptions;\n stroke?: { color: string; width?: number } | false;\n rotation?: number;\n shadow?: api.ShadowOptions;\n glow?: api.GlowOptions;\n click?: api.ShapeClickAction;\n}\nfunction bounds(props: Bounds) {\n return {\n x: api.inches(props.x),\n y: api.inches(props.y),\n w: api.inches(props.width),\n h: api.inches(props.height),\n };\n}\nfunction style(shape: api.SlideShapeData, props: ShapeStyle) {\n if (props.fill !== undefined) {\n if (typeof props.fill === 'string') api.setShapeFill(shape, props.fill);\n else api.setShapeGradientFill(shape, props.fill);\n }\n if (props.stroke === false) api.setShapeNoStroke(shape);\n else if (props.stroke)\n api.setShapeStroke(shape, {\n color: props.stroke.color,\n widthEmu: api.pt(props.stroke.width ?? 1),\n });\n if (props.rotation !== undefined) api.setShapeRotation(shape, props.rotation);\n if (props.shadow) api.setShapeShadow(shape, props.shadow);\n if (props.glow) api.setShapeGlow(shape, props.glow);\n if (props.click) api.setShapeClickAction(shape, props.click);\n}\nexport interface TextProps extends Bounds, ShapeStyle, api.TextFormat, Children {\n paragraphs?: readonly api.ParagraphSpec[];\n align?: api.ParagraphAlignment;\n anchor?: api.TextAnchor;\n autoFit?: api.TextAutoFit;\n}\nexport function Text(props: TextProps): Node {\n return node('Text', async (context) => {\n const slide = requireSlide(context);\n const content = textContent(props.children);\n if (props.paragraphs && content.text.trim())\n throw new Error('Text accepts either text children or paragraphs.');\n const shape = api.addSlideTextBox(slide, {\n ...bounds(props),\n ...(props.name ? { name: props.name } : {}),\n text: content.text,\n });\n if (props.paragraphs) api.setShapeParagraphs(shape, props.paragraphs);\n api.setShapeTextFormat(shape, props);\n if (props.align) api.setShapeAlignment(shape, props.align);\n if (props.anchor) api.setShapeTextAnchor(shape, props.anchor);\n if (props.autoFit) api.setShapeTextAutoFit(shape, props.autoFit);\n style(shape, props);\n await visit(content.elements, { ...context, slide, shape, scope: 'shape' });\n });\n}\nexport interface ShapeProps extends Bounds, ShapeStyle, Children {\n preset: Parameters<typeof api.addSlideShape>[1]['preset'];\n text?: string;\n format?: api.TextFormat;\n}\nexport function Shape(props: ShapeProps): Node {\n return node('Shape', async (context) => {\n const shape = api.addSlideShape(requireSlide(context), {\n ...bounds(props),\n preset: props.preset,\n ...(props.name ? { name: props.name } : {}),\n ...(props.text !== undefined ? { text: props.text } : {}),\n });\n style(shape, props);\n if (props.format) api.setShapeTextFormat(shape, props.format);\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\nexport interface ImageProps extends Bounds, ShapeStyle, Children {\n data: Uint8Array;\n format?: api.ImageFormat;\n fit?: api.ImageFit;\n}\nexport function Image(props: ImageProps): Node {\n return node('Image', async (context) => {\n const shape = api.addSlideImage(requireSlide(context), props.data, {\n ...bounds(props),\n ...(props.format ? { format: props.format } : {}),\n ...(props.fit ? { fit: props.fit } : {}),\n ...(props.name ? { name: props.name } : {}),\n });\n style(shape, props);\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\n// No ShapeStyle: a clip's picture already carries the `ppaction://media` click\n// action that makes it playable, which `click` would replace.\nexport type MediaProps = Bounds &\n Children &\n api.SlideMediaSource & {\n name?: string;\n poster?: Uint8Array;\n posterFormat?: api.ImageFormat;\n };\nexport function Media(props: MediaProps): Node {\n return node('Media', async (context) => {\n const { x: _x, y: _y, width: _width, height: _height, children, ...media } = props;\n const shape = api.addSlideMedia(requireSlide(context), { ...media, ...bounds(props) });\n await visit(children, { ...context, shape, scope: 'shape' });\n });\n}\nexport interface ChartProps extends Bounds, ShapeStyle, Children {\n spec: api.ChartSpec;\n}\nexport function Chart(props: ChartProps): Node {\n return node('Chart', async (context) => {\n const shape = api.addSlideChart(requireSlide(context), {\n ...bounds(props),\n spec: props.spec,\n ...(props.name ? { name: props.name } : {}),\n });\n style(shape, props);\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\nexport interface CellStyle {\n fill?: string;\n format?: api.TextFormat;\n anchor?: api.TextAnchor;\n}\nexport interface TableProps extends Bounds, Children {\n rows: readonly (readonly string[])[];\n columnWidths?: readonly number[];\n rowHeights?: readonly number[];\n cellStyle?: CellStyle;\n headerStyle?: CellStyle;\n stripeFill?: string;\n}\nexport function Table(props: TableProps): Node {\n return node('Table', async (context) => {\n const shape = api.addSlideTable(requireSlide(context), {\n ...bounds(props),\n rows: props.rows,\n ...(props.columnWidths ? { colWidths: props.columnWidths.map(api.inches) } : {}),\n ...(props.rowHeights ? { rowHeights: props.rowHeights.map(api.inches) } : {}),\n });\n props.rows.forEach((row, r) =>\n row.forEach((_, c) => {\n const cell = api.getTableCell(shape, r, c);\n const appearance = {\n ...props.cellStyle,\n ...(r === 0 ? props.headerStyle : {}),\n format: { ...props.cellStyle?.format, ...(r === 0 ? props.headerStyle?.format : {}) },\n };\n if (appearance.fill) api.setTableCellFill(cell, appearance.fill);\n if (r > 0 && r % 2 === 0 && props.stripeFill) api.setTableCellFill(cell, props.stripeFill);\n if (appearance.format) api.setTableCellTextFormat(cell, appearance.format);\n if (appearance.anchor) api.setTableCellAnchor(cell, appearance.anchor);\n }),\n );\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\nfunction selectShape(slide: api.SlideData, target: Target): api.SlideShapeData {\n const matches = api.getSlideShapes(slide).filter((shape) => {\n if ('name' in target) return api.getShapeName(shape) === target.name;\n if ('id' in target) return api.getShapeId(shape) === target.id;\n const ph = target.placeholder;\n return (\n (ph.type !== undefined || ph.idx !== undefined) &&\n (ph.type === undefined || api.getShapePlaceholderType(shape) === ph.type) &&\n (ph.idx === undefined || api.getShapePlaceholderIdx(shape) === ph.idx)\n );\n });\n if (matches.length !== 1)\n throw new Error(`Shape reference matched ${matches.length} shapes: ${JSON.stringify(target)}`);\n return matches[0]!;\n}\nexport interface FillProps extends Children {\n target: Target;\n text?: string;\n format?: api.TextFormat;\n}\nexport function Fill(props: FillProps): Node {\n return node('Fill', (context) => {\n const shape = selectShape(requireSlide(context), props.target);\n api.setShapeText(shape, props.text ?? literal(props.children));\n if (props.format) api.setShapeTextFormat(shape, props.format);\n });\n}\nexport function Remove(props: { target: Target }): Node {\n return node('Remove', (context) => {\n const slide = requireSlide(context);\n api.removeShape(selectShape(slide, props.target));\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import * as api from '@office-kit/pptx';\nimport {\n created,\n textContent,\n literal,\n node,\n requireSlide,\n visit,\n type Children,\n type Context,\n type Node,\n type PresentationNode,\n type RawContext,\n} from './model.ts';\nexport type { Child, Children, Node, PresentationNode, RawContext } from './model.ts';\nexport { Fragment } from './jsx-runtime.ts';\n\nexport type PresentationProps = Children &\n (\n | { source: api.PresentationInput; size?: never }\n | { source?: never; size?: api.PresentationSize }\n ) & {\n theme?: Parameters<typeof api.setPresentationTheme>[1];\n /** Compose replaces the slide sequence; edit retains the original sequence. */\n mode?: 'compose' | 'edit';\n };\nexport function Presentation(props: PresentationProps): PresentationNode {\n return {\n kind: 'Presentation',\n evaluate: () => {\n throw new Error('Presentation must be the root.');\n },\n async compile() {\n if (props.source !== undefined && props.size !== undefined)\n throw new Error('Presentation source retains its original size; do not specify size.');\n const presentation =\n props.source === undefined\n ? api.createPresentation(props.size === undefined ? {} : { size: props.size })\n : await api.loadPresentation(props.source);\n if (props.theme) api.setPresentationTheme(presentation, props.theme);\n const originals = [...api.getSlides(presentation)];\n const context: Context = {\n presentation,\n originals,\n mode: props.mode ?? (props.source === undefined ? 'compose' : 'edit'),\n scope: 'presentation',\n deferred: [],\n };\n await visit(props.children, context);\n for (const apply of context.deferred) await apply();\n if (context.mode === 'compose') {\n for (const slide of originals) api.removeSlide(presentation, slide);\n }\n return presentation;\n },\n };\n}\nexport async function compile(root: Node): Promise<api.PresentationData> {\n if (!('compile' in root) || typeof root.compile !== 'function')\n throw new Error('Export a Presentation as the root.');\n return root.compile();\n}\n\nexport type LayoutRef = { name: string } | { part: string } | { type: string };\nexport type SlideRef = { index: number } | { part: string } | { title: string };\nexport type Target =\n | { name: string }\n | { id: number }\n | { placeholder: { type?: string; idx?: number } };\nexport type SlideProps = Children &\n ({ from?: SlideRef; target?: never } | { from?: never; target: SlideRef }) & {\n layout?: LayoutRef;\n background?: string;\n notes?: string;\n };\nfunction selectSlide(context: Context, ref: SlideRef): api.SlideData {\n const matches = context.originals.filter((slide, index) =>\n 'index' in ref\n ? index === ref.index\n : 'part' in ref\n ? api.getSlidePartName(slide) === ref.part\n : api.getSlideTitle(slide) === ref.title,\n );\n if (matches.length !== 1)\n throw new Error(`Slide reference matched ${matches.length} slides: ${JSON.stringify(ref)}`);\n return matches[0]!;\n}\nfunction selectLayout(presentation: api.PresentationData, ref: LayoutRef): api.SlideLayoutData {\n const matches = api\n .getSlideLayouts(presentation)\n .filter((layout) =>\n 'name' in ref\n ? api.getSlideLayoutName(layout) === ref.name\n : 'part' in ref\n ? api.getSlideLayoutPartName(layout) === ref.part\n : api.getSlideLayoutType(layout) === ref.type,\n );\n if (matches.length !== 1)\n throw new Error(`Layout reference matched ${matches.length} layouts: ${JSON.stringify(ref)}`);\n return matches[0]!;\n}\nexport function Slide(props: SlideProps): Node {\n return node('Slide', async (context) => {\n if (context.scope !== 'presentation') throw new Error('Slide must be inside Presentation.');\n if (props.target && context.mode !== 'edit')\n throw new Error('Slide target requires Presentation mode=\"edit\".');\n if (props.from && props.target) throw new Error('Slide cannot specify both from and target.');\n const layout = props.layout ? selectLayout(context.presentation, props.layout) : undefined;\n const slide = props.target\n ? selectSlide(context, props.target)\n : props.from\n ? api.duplicateSlide(context.presentation, selectSlide(context, props.from))\n : layout\n ? api.addSlide(context.presentation, { layout })\n : api.addBlankSlide(context.presentation);\n if (layout && (props.from || props.target)) api.setSlideLayout(slide, layout);\n if (props.background !== undefined) api.setSlideBackground(slide, props.background);\n if (props.notes !== undefined) api.setSlideNotes(slide, props.notes);\n await visit(props.children, { ...context, slide, scope: 'slide' });\n });\n}\nexport type RawProps =\n | { scope?: undefined; apply: (context: RawContext) => void | Promise<void> }\n | {\n scope: 'presentation';\n apply: (context: Pick<RawContext, 'presentation'>) => void | Promise<void>;\n }\n | {\n scope: 'slide';\n apply: (context: RawContext & { slide: api.SlideData }) => void | Promise<void>;\n }\n | { scope: 'shape'; apply: (context: Required<RawContext>) => void | Promise<void> };\n\nexport function Raw(props: RawProps): Node {\n return node('Raw', (context) => {\n if (props.scope !== undefined && props.scope !== context.scope) {\n throw new Error(`Raw scope=\"${props.scope}\" cannot run inside ${context.scope}.`);\n }\n context.deferred.push(() => {\n if (props.scope === 'shape') {\n if (!context.shape || !context.slide) throw new Error('Raw requires a shape context.');\n return props.apply({\n presentation: context.presentation,\n slide: context.slide,\n shape: context.shape,\n });\n }\n if (props.scope === 'slide') {\n if (!context.slide) throw new Error('Raw requires a slide context.');\n return props.apply({ ...context, slide: context.slide });\n }\n return props.apply(context);\n });\n });\n}\nexport interface Bounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\nexport interface ShapeStyle {\n name?: string;\n fill?: string | api.GradientFillOptions;\n stroke?: { color: string; width?: number } | false;\n rotation?: number;\n shadow?: api.ShadowOptions;\n glow?: api.GlowOptions;\n click?: api.ShapeClickAction;\n}\nfunction bounds(props: Bounds) {\n return {\n x: api.inches(props.x),\n y: api.inches(props.y),\n w: api.inches(props.width),\n h: api.inches(props.height),\n };\n}\nfunction style(shape: api.SlideShapeData, props: ShapeStyle) {\n if (props.fill !== undefined) {\n if (typeof props.fill === 'string') api.setShapeFill(shape, props.fill);\n else api.setShapeGradientFill(shape, props.fill);\n }\n if (props.stroke === false) api.setShapeNoStroke(shape);\n else if (props.stroke)\n api.setShapeStroke(shape, {\n color: props.stroke.color,\n widthEmu: api.pt(props.stroke.width ?? 1),\n });\n if (props.rotation !== undefined) api.setShapeRotation(shape, props.rotation);\n if (props.shadow) api.setShapeShadow(shape, props.shadow);\n if (props.glow) api.setShapeGlow(shape, props.glow);\n if (props.click) api.setShapeClickAction(shape, props.click);\n}\n/** A paragraph's indent level: 0 is the top, 8 the deepest PowerPoint has. */\nexport type TextLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;\nexport interface TextParagraph extends api.ParagraphSpec {\n /** This paragraph's own bullet; wins over `bullets`. */\n bullet?: api.BulletStyle;\n level?: TextLevel;\n}\nexport interface TextProps extends Bounds, ShapeStyle, api.TextFormat, Children {\n paragraphs?: readonly TextParagraph[];\n align?: api.ParagraphAlignment;\n anchor?: api.TextAnchor;\n autoFit?: api.TextAutoFit;\n /** Bullet or numbering for every paragraph; a newline in the text starts a paragraph. */\n bullets?: api.BulletStyle;\n /** Space before / after every paragraph, in points. */\n paragraphSpacing?: { before?: number; after?: number };\n}\nexport function Text(props: TextProps): Node {\n return node('Text', async (context) => {\n const slide = requireSlide(context);\n const content = textContent(props.children);\n if (props.paragraphs && content.text.trim())\n throw new Error('Text accepts either text children or paragraphs.');\n const shape = created(\n context,\n api.addSlideTextBox(slide, {\n ...bounds(props),\n ...(props.name ? { name: props.name } : {}),\n text: content.text,\n }),\n );\n if (props.paragraphs) api.setShapeParagraphs(shape, props.paragraphs);\n api.setShapeTextFormat(shape, props);\n if (props.align) api.setShapeAlignment(shape, props.align);\n if (props.anchor) api.setShapeTextAnchor(shape, props.anchor);\n if (props.autoFit) api.setShapeTextAutoFit(shape, props.autoFit);\n // Before any bullet: core 0.17.0, still in the peer range, sizes a bullet's hanging\n // indent from the level at that moment and never moves it afterwards.\n props.paragraphs?.forEach((paragraph, index) => {\n if (paragraph.level !== undefined) api.setParagraphLevel(shape, index, paragraph.level);\n });\n if (props.bullets !== undefined) api.setShapeBullets(shape, props.bullets);\n props.paragraphs?.forEach((paragraph, index) => {\n if (paragraph.bullet !== undefined) api.setParagraphBullet(shape, index, paragraph.bullet);\n });\n if (props.paragraphSpacing) {\n const { before, after } = props.paragraphSpacing;\n const spacing = {\n ...(before !== undefined ? { beforePts: before } : {}),\n ...(after !== undefined ? { afterPts: after } : {}),\n };\n for (let i = 0; i < api.getShapeParagraphCount(shape); i++) {\n api.setParagraphSpacing(shape, i, spacing);\n }\n }\n style(shape, props);\n await visit(content.elements, { ...context, slide, shape, scope: 'shape' });\n });\n}\nexport interface ShapeProps extends Bounds, ShapeStyle, Children {\n preset: Parameters<typeof api.addSlideShape>[1]['preset'];\n text?: string;\n format?: api.TextFormat;\n /** Alignment and anchor of `text` inside the shape. */\n align?: api.ParagraphAlignment;\n anchor?: api.TextAnchor;\n}\nexport function Shape(props: ShapeProps): Node {\n return node('Shape', async (context) => {\n if ((props.align || props.anchor) && props.text === undefined)\n throw new Error('Shape align and anchor position its text; set text as well.');\n const shape = created(\n context,\n api.addSlideShape(requireSlide(context), {\n ...bounds(props),\n preset: props.preset,\n ...(props.name ? { name: props.name } : {}),\n ...(props.text !== undefined ? { text: props.text } : {}),\n }),\n );\n style(shape, props);\n if (props.format) api.setShapeTextFormat(shape, props.format);\n if (props.align) api.setShapeAlignment(shape, props.align);\n if (props.anchor) api.setShapeTextAnchor(shape, props.anchor);\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\nexport interface ImageProps extends Bounds, ShapeStyle, Children {\n data: Uint8Array;\n format?: api.ImageFormat;\n fit?: api.ImageFit;\n}\nexport function Image(props: ImageProps): Node {\n return node('Image', async (context) => {\n const shape = created(\n context,\n api.addSlideImage(requireSlide(context), props.data, {\n ...bounds(props),\n ...(props.format ? { format: props.format } : {}),\n ...(props.fit ? { fit: props.fit } : {}),\n ...(props.name ? { name: props.name } : {}),\n }),\n );\n style(shape, props);\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\n// No ShapeStyle: a clip's picture already carries the `ppaction://media` click\n// action that makes it playable, which `click` would replace.\nexport type MediaProps = Bounds &\n Children &\n api.SlideMediaSource & {\n name?: string;\n poster?: Uint8Array;\n posterFormat?: api.ImageFormat;\n };\nexport function Media(props: MediaProps): Node {\n return node('Media', async (context) => {\n const { x: _x, y: _y, width: _width, height: _height, children, ...media } = props;\n const shape = created(\n context,\n api.addSlideMedia(requireSlide(context), { ...media, ...bounds(props) }),\n );\n await visit(children, { ...context, shape, scope: 'shape' });\n });\n}\nexport interface ChartProps extends Bounds, ShapeStyle, Children {\n spec: api.ChartSpec;\n}\nexport function Chart(props: ChartProps): Node {\n return node('Chart', async (context) => {\n const shape = created(\n context,\n api.addSlideChart(requireSlide(context), {\n ...bounds(props),\n spec: props.spec,\n ...(props.name ? { name: props.name } : {}),\n }),\n );\n style(shape, props);\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\nexport type CellBorderSide = 'left' | 'right' | 'top' | 'bottom';\nexport interface CellStyle {\n fill?: string;\n format?: api.TextFormat;\n anchor?: api.TextAnchor;\n align?: api.ParagraphAlignment;\n /** Border per side. `width` is in points; without it the line has no explicit width. */\n borders?: Partial<Record<CellBorderSide, { color: string; width?: number }>>;\n}\nexport interface TableCellInfo {\n /** Zero-based; row 0 is the header. */\n row: number;\n column: number;\n /** A cell's text; for `paragraphs`, the run texts joined, one line per paragraph. */\n value: string;\n}\n/** Exactly one of `text` and `paragraphs`. An empty cell is the string `''`. */\ntype TableCellContent =\n | { text: string; paragraphs?: never }\n | { text?: never; paragraphs: readonly api.ParagraphSpec[] };\nexport type TableCellSpec = TableCellContent & {\n /** This cell is the top-left of a merge. The positions it covers stay in `rows` as `''`. */\n colSpan?: number;\n rowSpan?: number;\n};\nexport type TableCell = string | TableCellSpec;\nexport interface TableProps extends Bounds, Children {\n rows: readonly (readonly TableCell[])[];\n columnWidths?: readonly number[];\n rowHeights?: readonly number[];\n cellStyle?: CellStyle;\n headerStyle?: CellStyle;\n stripeFill?: string;\n /**\n * Style for one cell, merged over `cellStyle`, `headerStyle` and\n * `stripeFill` — for a status column, a total row, a highlighted figure.\n */\n styleCell?: (cell: TableCellInfo) => CellStyle | undefined;\n}\nfunction cellBorders(borders: NonNullable<CellStyle['borders']>) {\n const sides: Partial<Record<CellBorderSide, { color: string; widthEmu?: number }>> = {};\n for (const side of ['left', 'right', 'top', 'bottom'] as const) {\n const border = borders[side];\n if (!border) continue;\n sides[side] = {\n color: border.color,\n ...(border.width !== undefined ? { widthEmu: api.pt(border.width) } : {}),\n };\n }\n return sides;\n}\ntype CellPosition = { row: number; col: number };\nconst positionKey = (row: number, col: number) => `${row}:${col}`;\nconst cellSpec = (cell: TableCell): TableCellSpec =>\n typeof cell === 'string' ? { text: cell } : cell;\nconst cellValue = (spec: TableCellSpec): string =>\n spec.paragraphs\n ? spec.paragraphs.map((paragraph) => paragraph.runs.map((run) => run.text).join('')).join('\\n')\n : spec.text;\n\n/** Maps every position a merge covers to that merge's top-left cell. */\nfunction coveredPositions(rows: TableProps['rows']): Map<string, CellPosition> {\n const covered = new Map<string, CellPosition>();\n rows.forEach((cells, row) =>\n cells.forEach((cell, col) => {\n const { rowSpan = 1, colSpan = 1 } = cellSpec(cell);\n // Clamped to the grid: the core rejects an oversized span later, and an\n // unbounded loop must not run first.\n const lastRow = Math.min(row + rowSpan, rows.length);\n const lastCol = Math.min(col + colSpan, cells.length);\n for (let r = row; r < lastRow; r++)\n for (let c = col; c < lastCol; c++)\n if (r !== row || c !== col) covered.set(positionKey(r, c), { row, col });\n }),\n );\n return covered;\n}\nfunction checkCells(rows: TableProps['rows'], covered: Map<string, CellPosition>) {\n rows.forEach((cells, row) =>\n cells.forEach((cell, col) => {\n const spec = cellSpec(cell);\n if ((spec.text === undefined) === (spec.paragraphs === undefined))\n throw new Error(`Table cell (${row}, ${col}) accepts either text or paragraphs.`);\n const anchor = covered.get(positionKey(row, col));\n // PowerPoint paints only the merge's top-left cell, so anything written\n // here would vanish from the slide without a trace.\n if (anchor && cell !== '')\n throw new Error(\n `Table cell (${row}, ${col}) is covered by the merge at (${anchor.row}, ${anchor.col}); write it as ''.`,\n );\n }),\n );\n}\nexport function Table(props: TableProps): Node {\n return node('Table', async (context) => {\n const covered = coveredPositions(props.rows);\n checkCells(props.rows, covered);\n const shape = created(\n context,\n api.addSlideTable(requireSlide(context), {\n ...bounds(props),\n rows: props.rows.map((cells) => cells.map((cell) => cellSpec(cell).text ?? '')),\n ...(props.columnWidths ? { colWidths: props.columnWidths.map(api.inches) } : {}),\n ...(props.rowHeights ? { rowHeights: props.rowHeights.map(api.inches) } : {}),\n }),\n );\n props.rows.forEach((row, r) =>\n row.forEach((entry, c) => {\n // A merged block is painted from its top-left cell alone, fill and all\n // four borders, so a covered position gets no style and no styleCell call.\n if (covered.has(positionKey(r, c))) return;\n const spec = cellSpec(entry);\n const cell = api.getTableCell(shape, r, c);\n const header = r === 0 ? props.headerStyle : undefined;\n const own = props.styleCell?.({ row: r, column: c, value: cellValue(spec) });\n const striped = r > 0 && r % 2 === 0 ? props.stripeFill : undefined;\n const appearance: CellStyle = {\n ...props.cellStyle,\n ...header,\n ...(striped !== undefined ? { fill: striped } : {}),\n ...own,\n format: { ...props.cellStyle?.format, ...header?.format, ...own?.format },\n };\n if (appearance.fill) api.setTableCellFill(cell, appearance.fill);\n if (spec.paragraphs) {\n // addSlideTable bakes the deck's body-text color into each run so text\n // stays readable on an inverted color map; new runs must keep it.\n const built = api.getTableCellParagraphs(cell)[0]?.elements[0];\n const base = { ...(built?.kind === 'r' ? built.format : {}), ...appearance.format };\n const { align } = appearance;\n api.setTableCellParagraphs(\n cell,\n spec.paragraphs.map((paragraph) => ({\n ...paragraph,\n ...(paragraph.align === undefined && align ? { align } : {}),\n runs: paragraph.runs.map((run) => ({ ...run, format: { ...base, ...run.format } })),\n })),\n );\n } else {\n if (appearance.format) api.setTableCellTextFormat(cell, appearance.format);\n if (appearance.align) api.setTableCellAlignment(cell, appearance.align);\n }\n if (appearance.anchor) api.setTableCellAnchor(cell, appearance.anchor);\n // Only when a side is set: an empty call would still give every cell a <a:tcPr>.\n const borders = cellBorders({\n ...props.cellStyle?.borders,\n ...header?.borders,\n ...own?.borders,\n });\n if (Object.keys(borders).length > 0) api.setTableCellBorders(cell, borders);\n }),\n );\n props.rows.forEach((row, r) =>\n row.forEach((entry, c) => {\n const { rowSpan = 1, colSpan = 1 } = cellSpec(entry);\n if (rowSpan !== 1 || colSpan !== 1)\n api.mergeTableCells(shape, { row: r, col: c, rowSpan, colSpan });\n }),\n );\n await visit(props.children, { ...context, shape, scope: 'shape' });\n });\n}\nexport interface LineProps {\n x1: number;\n y1: number;\n x2: number;\n y2: number;\n color?: string;\n /** Stroke width in points. */\n width?: number;\n name?: string;\n}\nexport function Line(props: LineProps): Node {\n return node('Line', (context) => {\n created(\n context,\n api.addSlideLine(requireSlide(context), {\n from: { x: api.inches(props.x1), y: api.inches(props.y1) },\n to: { x: api.inches(props.x2), y: api.inches(props.y2) },\n ...(props.color !== undefined ? { color: props.color } : {}),\n ...(props.width !== undefined ? { widthEmu: api.pt(props.width) } : {}),\n ...(props.name ? { name: props.name } : {}),\n }),\n );\n });\n}\nexport interface GroupProps extends Children {\n name?: string;\n}\n/** Groups the shapes its children create, so they move and resize as one object. */\nexport function Group(props: GroupProps): Node {\n return node('Group', async (context) => {\n requireSlide(context);\n const members: api.SlideShapeData[] = [];\n await visit(props.children, { ...context, members });\n created(context, api.groupShapes(members, props.name ? { name: props.name } : {}));\n });\n}\nfunction selectShape(slide: api.SlideData, target: Target): api.SlideShapeData {\n const matches = api.getSlideShapes(slide).filter((shape) => {\n if ('name' in target) return api.getShapeName(shape) === target.name;\n if ('id' in target) return api.getShapeId(shape) === target.id;\n const ph = target.placeholder;\n return (\n (ph.type !== undefined || ph.idx !== undefined) &&\n (ph.type === undefined || api.getShapePlaceholderType(shape) === ph.type) &&\n (ph.idx === undefined || api.getShapePlaceholderIdx(shape) === ph.idx)\n );\n });\n if (matches.length !== 1)\n throw new Error(`Shape reference matched ${matches.length} shapes: ${JSON.stringify(target)}`);\n return matches[0]!;\n}\nexport interface FillProps extends Children {\n target: Target;\n text?: string;\n format?: api.TextFormat;\n /** Omitted keeps whatever the template's `<a:bodyPr>` says. */\n autoFit?: api.TextAutoFit;\n}\nexport function Fill(props: FillProps): Node {\n return node('Fill', (context) => {\n const shape = selectShape(requireSlide(context), props.target);\n api.setShapeText(shape, props.text ?? literal(props.children));\n if (props.format) api.setShapeTextFormat(shape, props.format);\n if (props.autoFit) api.setShapeTextAutoFit(shape, props.autoFit);\n });\n}\nexport function Remove(props: { target: Target }): Node {\n return node('Remove', (context) => {\n const slide = requireSlide(context);\n api.removeShape(selectShape(slide, props.target));\n });\n}\n"],"mappings":"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"}
@@ -15,6 +15,8 @@ interface Context extends RawContext {
15
15
  scope: 'presentation' | 'slide' | 'shape';
16
16
  originals: readonly api.SlideData[];
17
17
  deferred: Array<() => void | Promise<void>>;
18
+ /** Set inside a `Group`: every shape created there, in drawing order. */
19
+ members?: api.SlideShapeData[];
18
20
  }
19
21
  interface Node {
20
22
  readonly kind: string;
@@ -47,4 +49,4 @@ declare namespace JSX {
47
49
  }
48
50
  //#endregion
49
51
  export { jsxs as a, Node as c, jsxDEV as i, PresentationNode as l, JSX as n, Child as o, jsx as r, Children as s, Fragment as t, RawContext as u };
50
- //# sourceMappingURL=jsx-runtime-C-Ggfem1.d.ts.map
52
+ //# sourceMappingURL=jsx-runtime-D7IpzvWG.d.ts.map
@@ -24,6 +24,11 @@ function requireSlide(context) {
24
24
  if (!context.slide || context.scope !== "slide") throw new Error("This element must be a child of Slide.");
25
25
  return context.slide;
26
26
  }
27
+ /** Reports a new shape to the enclosing `Group`, if there is one. */
28
+ function created(context, shape) {
29
+ context.members?.push(shape);
30
+ return shape;
31
+ }
27
32
  function literal(children) {
28
33
  if (children == null || typeof children === "boolean") return "";
29
34
  if (typeof children === "string" || typeof children === "number") return String(children);
@@ -65,6 +70,6 @@ function Fragment({ children }) {
65
70
  return node("Fragment", (context) => visit(children, context));
66
71
  }
67
72
  //#endregion
68
- export { literal as a, textContent as c, jsxs as i, visit as l, jsx as n, node as o, jsxDEV as r, requireSlide as s, Fragment as t };
73
+ export { created as a, requireSlide as c, jsxs as i, textContent as l, jsx as n, literal as o, jsxDEV as r, node as s, Fragment as t, visit as u };
69
74
 
70
- //# sourceMappingURL=jsx-runtime-BgfNl42k.js.map
75
+ //# sourceMappingURL=jsx-runtime-DoUxctgW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-runtime-DoUxctgW.js","names":[],"sources":["../src/model.ts","../src/jsx-runtime.ts"],"sourcesContent":["import type * as api from '@office-kit/pptx';\n\nexport type Child = Node | string | number | boolean | null | undefined | readonly Child[];\nexport interface Children {\n children?: Child;\n}\nexport interface RawContext {\n presentation: api.PresentationData;\n slide?: api.SlideData;\n shape?: api.SlideShapeData;\n}\nexport interface Context extends RawContext {\n mode: 'compose' | 'edit';\n scope: 'presentation' | 'slide' | 'shape';\n originals: readonly api.SlideData[];\n deferred: Array<() => void | Promise<void>>;\n /** Set inside a `Group`: every shape created there, in drawing order. */\n members?: api.SlideShapeData[];\n}\nexport interface Node {\n readonly kind: string;\n readonly source?: { fileName: string; lineNumber: number; columnNumber: number };\n readonly evaluate: (context: Context) => void | Promise<void>;\n}\nexport interface PresentationNode extends Node {\n readonly compile: () => Promise<api.PresentationData>;\n}\nexport function node(kind: string, evaluate: Node['evaluate']): Node {\n return { kind, evaluate };\n}\nexport async function visit(children: Child, context: Context): Promise<void> {\n if (children == null || typeof children === 'boolean') return;\n if (typeof children === 'string' || typeof children === 'number') {\n if (String(children).trim()) throw new Error('Text content must be inside Text or Fill.');\n return;\n }\n if ('evaluate' in children) {\n try {\n await children.evaluate(context);\n } catch (cause) {\n if (!children.source) throw cause;\n const { fileName, lineNumber, columnNumber } = children.source;\n throw new Error(\n `${fileName}:${lineNumber}:${columnNumber} <${children.kind}>: ${cause instanceof Error ? cause.message : String(cause)}`,\n { cause },\n );\n }\n } else {\n for (const child of children) await visit(child, context);\n }\n}\nexport function requireSlide(context: Context): api.SlideData {\n if (!context.slide || context.scope !== 'slide')\n throw new Error('This element must be a child of Slide.');\n return context.slide;\n}\n/** Reports a new shape to the enclosing `Group`, if there is one. */\nexport function created(context: Context, shape: api.SlideShapeData): api.SlideShapeData {\n context.members?.push(shape);\n return shape;\n}\nexport function literal(children: Child): string {\n if (children == null || typeof children === 'boolean') return '';\n if (typeof children === 'string' || typeof children === 'number') return String(children);\n if ('evaluate' in children)\n throw new Error('Use paragraphs for rich text; element children are not text.');\n return children.map(literal).join('');\n}\n\n/** Separate inline text from shape-scoped escape hatches without evaluating them. */\nexport function textContent(children: Child): { text: string; elements: Node[] } {\n const elements: Node[] = [];\n function collect(child: Child): string {\n if (child == null || typeof child === 'boolean') return '';\n if (typeof child === 'string' || typeof child === 'number') return String(child);\n if ('evaluate' in child) {\n elements.push(child);\n return '';\n }\n return child.map(collect).join('');\n }\n return { text: collect(children), elements };\n}\n","import { node, visit, type Child, type Children, type Node } from './model.ts';\n\nexport function jsx<P>(component: (props: P) => Node, props: P, _key?: string | number): Node {\n if (typeof component !== 'function')\n throw new Error('Use imported PPTX components, not HTML tags.');\n return component(props);\n}\nexport const jsxs = jsx;\nexport function jsxDEV<P>(\n component: (props: P) => Node,\n props: P,\n key?: string | number,\n _isStaticChildren?: boolean,\n source?: Node['source'],\n): Node {\n const result = jsx(component, props, key);\n return source ? { ...result, source } : result;\n}\nexport function Fragment({ children }: Children): Node {\n return node('Fragment', (context) => visit(children, context));\n}\nexport namespace JSX {\n export type Element = Node;\n export interface ElementChildrenAttribute {\n children: Child;\n }\n export interface IntrinsicAttributes {\n key?: string | number;\n }\n}\n"],"mappings":";AA2BA,SAAgB,KAAK,MAAc,UAAkC;CACnE,OAAO;EAAE;EAAM;CAAS;AAC1B;AACA,eAAsB,MAAM,UAAiB,SAAiC;CAC5E,IAAI,YAAY,QAAQ,OAAO,aAAa,WAAW;CACvD,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UAAU;EAChE,IAAI,OAAO,QAAQ,CAAC,CAAC,KAAK,GAAG,MAAM,IAAI,MAAM,2CAA2C;EACxF;CACF;CACA,IAAI,cAAc,UAChB,IAAI;EACF,MAAM,SAAS,SAAS,OAAO;CACjC,SAAS,OAAO;EACd,IAAI,CAAC,SAAS,QAAQ,MAAM;EAC5B,MAAM,EAAE,UAAU,YAAY,iBAAiB,SAAS;EACxD,MAAM,IAAI,MACR,GAAG,SAAS,GAAG,WAAW,GAAG,aAAa,IAAI,SAAS,KAAK,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KACtH,EAAE,MAAM,CACV;CACF;MAEA,KAAK,MAAM,SAAS,UAAU,MAAM,MAAM,OAAO,OAAO;AAE5D;AACA,SAAgB,aAAa,SAAiC;CAC5D,IAAI,CAAC,QAAQ,SAAS,QAAQ,UAAU,SACtC,MAAM,IAAI,MAAM,wCAAwC;CAC1D,OAAO,QAAQ;AACjB;;AAEA,SAAgB,QAAQ,SAAkB,OAA+C;CACvF,QAAQ,SAAS,KAAK,KAAK;CAC3B,OAAO;AACT;AACA,SAAgB,QAAQ,UAAyB;CAC/C,IAAI,YAAY,QAAQ,OAAO,aAAa,WAAW,OAAO;CAC9D,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UAAU,OAAO,OAAO,QAAQ;CACxF,IAAI,cAAc,UAChB,MAAM,IAAI,MAAM,8DAA8D;CAChF,OAAO,SAAS,IAAI,OAAO,CAAC,CAAC,KAAK,EAAE;AACtC;;AAGA,SAAgB,YAAY,UAAqD;CAC/E,MAAM,WAAmB,CAAC;CAC1B,SAAS,QAAQ,OAAsB;EACrC,IAAI,SAAS,QAAQ,OAAO,UAAU,WAAW,OAAO;EACxD,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;EAC/E,IAAI,cAAc,OAAO;GACvB,SAAS,KAAK,KAAK;GACnB,OAAO;EACT;EACA,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,KAAK,EAAE;CACnC;CACA,OAAO;EAAE,MAAM,QAAQ,QAAQ;EAAG;CAAS;AAC7C;;;AChFA,SAAgB,IAAO,WAA+B,OAAU,MAA8B;CAC5F,IAAI,OAAO,cAAc,YACvB,MAAM,IAAI,MAAM,8CAA8C;CAChE,OAAO,UAAU,KAAK;AACxB;AACA,MAAa,OAAO;AACpB,SAAgB,OACd,WACA,OACA,KACA,mBACA,QACM;CACN,MAAM,SAAS,IAAI,WAAW,OAAO,GAAG;CACxC,OAAO,SAAS;EAAE,GAAG;EAAQ;CAAO,IAAI;AAC1C;AACA,SAAgB,SAAS,EAAE,YAA4B;CACrD,OAAO,KAAK,aAAa,YAAY,MAAM,UAAU,OAAO,CAAC;AAC/D"}
@@ -1,2 +1,2 @@
1
- import { a as jsxs, i as jsxDEV, n as JSX, r as jsx, t as Fragment } from "./jsx-runtime-C-Ggfem1.js";
1
+ import { a as jsxs, i as jsxDEV, n as JSX, r as jsx, t as Fragment } from "./jsx-runtime-D7IpzvWG.js";
2
2
  export { Fragment, JSX, jsx, jsxDEV, jsxs };
@@ -1,2 +1,2 @@
1
- import { i as jsxs, n as jsx, r as jsxDEV, t as Fragment } from "./jsx-runtime-BgfNl42k.js";
1
+ import { i as jsxs, n as jsx, r as jsxDEV, t as Fragment } from "./jsx-runtime-DoUxctgW.js";
2
2
  export { Fragment, jsx, jsxDEV, jsxs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@office-kit/pptx-dsl",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Typed TSX authoring for editable PowerPoint presentations",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,7 +36,7 @@
36
36
  "devDependencies": {
37
37
  "tsdown": "^0.22.2",
38
38
  "typescript": "^6.0.3",
39
- "@office-kit/pptx": "0.17.0"
39
+ "@office-kit/pptx": "0.18.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@office-kit/pptx": ">=0.17.0"
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsx-runtime-BgfNl42k.js","names":[],"sources":["../src/model.ts","../src/jsx-runtime.ts"],"sourcesContent":["import type * as api from '@office-kit/pptx';\n\nexport type Child = Node | string | number | boolean | null | undefined | readonly Child[];\nexport interface Children {\n children?: Child;\n}\nexport interface RawContext {\n presentation: api.PresentationData;\n slide?: api.SlideData;\n shape?: api.SlideShapeData;\n}\nexport interface Context extends RawContext {\n mode: 'compose' | 'edit';\n scope: 'presentation' | 'slide' | 'shape';\n originals: readonly api.SlideData[];\n deferred: Array<() => void | Promise<void>>;\n}\nexport interface Node {\n readonly kind: string;\n readonly source?: { fileName: string; lineNumber: number; columnNumber: number };\n readonly evaluate: (context: Context) => void | Promise<void>;\n}\nexport interface PresentationNode extends Node {\n readonly compile: () => Promise<api.PresentationData>;\n}\nexport function node(kind: string, evaluate: Node['evaluate']): Node {\n return { kind, evaluate };\n}\nexport async function visit(children: Child, context: Context): Promise<void> {\n if (children == null || typeof children === 'boolean') return;\n if (typeof children === 'string' || typeof children === 'number') {\n if (String(children).trim()) throw new Error('Text content must be inside Text or Fill.');\n return;\n }\n if ('evaluate' in children) {\n try {\n await children.evaluate(context);\n } catch (cause) {\n if (!children.source) throw cause;\n const { fileName, lineNumber, columnNumber } = children.source;\n throw new Error(\n `${fileName}:${lineNumber}:${columnNumber} <${children.kind}>: ${cause instanceof Error ? cause.message : String(cause)}`,\n { cause },\n );\n }\n } else {\n for (const child of children) await visit(child, context);\n }\n}\nexport function requireSlide(context: Context): api.SlideData {\n if (!context.slide || context.scope !== 'slide')\n throw new Error('This element must be a child of Slide.');\n return context.slide;\n}\nexport function literal(children: Child): string {\n if (children == null || typeof children === 'boolean') return '';\n if (typeof children === 'string' || typeof children === 'number') return String(children);\n if ('evaluate' in children)\n throw new Error('Use paragraphs for rich text; element children are not text.');\n return children.map(literal).join('');\n}\n\n/** Separate inline text from shape-scoped escape hatches without evaluating them. */\nexport function textContent(children: Child): { text: string; elements: Node[] } {\n const elements: Node[] = [];\n function collect(child: Child): string {\n if (child == null || typeof child === 'boolean') return '';\n if (typeof child === 'string' || typeof child === 'number') return String(child);\n if ('evaluate' in child) {\n elements.push(child);\n return '';\n }\n return child.map(collect).join('');\n }\n return { text: collect(children), elements };\n}\n","import { node, visit, type Child, type Children, type Node } from './model.ts';\n\nexport function jsx<P>(component: (props: P) => Node, props: P, _key?: string | number): Node {\n if (typeof component !== 'function')\n throw new Error('Use imported PPTX components, not HTML tags.');\n return component(props);\n}\nexport const jsxs = jsx;\nexport function jsxDEV<P>(\n component: (props: P) => Node,\n props: P,\n key?: string | number,\n _isStaticChildren?: boolean,\n source?: Node['source'],\n): Node {\n const result = jsx(component, props, key);\n return source ? { ...result, source } : result;\n}\nexport function Fragment({ children }: Children): Node {\n return node('Fragment', (context) => visit(children, context));\n}\nexport namespace JSX {\n export type Element = Node;\n export interface ElementChildrenAttribute {\n children: Child;\n }\n export interface IntrinsicAttributes {\n key?: string | number;\n }\n}\n"],"mappings":";AAyBA,SAAgB,KAAK,MAAc,UAAkC;CACnE,OAAO;EAAE;EAAM;CAAS;AAC1B;AACA,eAAsB,MAAM,UAAiB,SAAiC;CAC5E,IAAI,YAAY,QAAQ,OAAO,aAAa,WAAW;CACvD,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UAAU;EAChE,IAAI,OAAO,QAAQ,CAAC,CAAC,KAAK,GAAG,MAAM,IAAI,MAAM,2CAA2C;EACxF;CACF;CACA,IAAI,cAAc,UAChB,IAAI;EACF,MAAM,SAAS,SAAS,OAAO;CACjC,SAAS,OAAO;EACd,IAAI,CAAC,SAAS,QAAQ,MAAM;EAC5B,MAAM,EAAE,UAAU,YAAY,iBAAiB,SAAS;EACxD,MAAM,IAAI,MACR,GAAG,SAAS,GAAG,WAAW,GAAG,aAAa,IAAI,SAAS,KAAK,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KACtH,EAAE,MAAM,CACV;CACF;MAEA,KAAK,MAAM,SAAS,UAAU,MAAM,MAAM,OAAO,OAAO;AAE5D;AACA,SAAgB,aAAa,SAAiC;CAC5D,IAAI,CAAC,QAAQ,SAAS,QAAQ,UAAU,SACtC,MAAM,IAAI,MAAM,wCAAwC;CAC1D,OAAO,QAAQ;AACjB;AACA,SAAgB,QAAQ,UAAyB;CAC/C,IAAI,YAAY,QAAQ,OAAO,aAAa,WAAW,OAAO;CAC9D,IAAI,OAAO,aAAa,YAAY,OAAO,aAAa,UAAU,OAAO,OAAO,QAAQ;CACxF,IAAI,cAAc,UAChB,MAAM,IAAI,MAAM,8DAA8D;CAChF,OAAO,SAAS,IAAI,OAAO,CAAC,CAAC,KAAK,EAAE;AACtC;;AAGA,SAAgB,YAAY,UAAqD;CAC/E,MAAM,WAAmB,CAAC;CAC1B,SAAS,QAAQ,OAAsB;EACrC,IAAI,SAAS,QAAQ,OAAO,UAAU,WAAW,OAAO;EACxD,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;EAC/E,IAAI,cAAc,OAAO;GACvB,SAAS,KAAK,KAAK;GACnB,OAAO;EACT;EACA,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,KAAK,EAAE;CACnC;CACA,OAAO;EAAE,MAAM,QAAQ,QAAQ;EAAG;CAAS;AAC7C;;;ACzEA,SAAgB,IAAO,WAA+B,OAAU,MAA8B;CAC5F,IAAI,OAAO,cAAc,YACvB,MAAM,IAAI,MAAM,8CAA8C;CAChE,OAAO,UAAU,KAAK;AACxB;AACA,MAAa,OAAO;AACpB,SAAgB,OACd,WACA,OACA,KACA,mBACA,QACM;CACN,MAAM,SAAS,IAAI,WAAW,OAAO,GAAG;CACxC,OAAO,SAAS;EAAE,GAAG;EAAQ;CAAO,IAAI;AAC1C;AACA,SAAgB,SAAS,EAAE,YAA4B;CACrD,OAAO,KAAK,aAAa,YAAY,MAAM,UAAU,OAAO,CAAC;AAC/D"}