@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 +137 -17
- package/dist/index.d.ts +71 -4
- package/dist/index.js +159 -20
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-C-Ggfem1.d.ts → jsx-runtime-D7IpzvWG.d.ts} +3 -1
- package/dist/{jsx-runtime-BgfNl42k.js → jsx-runtime-DoUxctgW.js} +7 -2
- package/dist/jsx-runtime-DoUxctgW.js.map +1 -0
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/package.json +2 -2
- package/dist/jsx-runtime-BgfNl42k.js.map +0 -1
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
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
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
|
|
70
|
-
text auto-fit
|
|
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
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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((
|
|
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
|
-
...
|
|
273
|
+
...header,
|
|
274
|
+
...striped !== void 0 ? { fill: striped } : {},
|
|
275
|
+
...own,
|
|
203
276
|
format: {
|
|
204
277
|
...props.cellStyle?.format,
|
|
205
|
-
...
|
|
278
|
+
...header?.format,
|
|
279
|
+
...own?.format
|
|
206
280
|
}
|
|
207
281
|
};
|
|
208
282
|
if (appearance.fill) api.setTableCellFill(cell, appearance.fill);
|
|
209
|
-
if (
|
|
210
|
-
|
|
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-
|
|
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 {
|
|
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-
|
|
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"}
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as jsxs, i as jsxDEV, n as JSX, r as jsx, t as Fragment } from "./jsx-runtime-
|
|
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 };
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as jsxs, n as jsx, r as jsxDEV, t as Fragment } from "./jsx-runtime-
|
|
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
|
+
"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.
|
|
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"}
|