@pyreon/document 0.13.1 → 0.14.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/lib/analysis/index.js.html +1 -1
- package/lib/{chunk-ErZ26oRB.js → chunk-B4VCYm32.js} +1 -1
- package/lib/{dist-CYL41kqQ.js → dist-dSdlKzJ8.js} +10 -4
- package/lib/{dist-CYL41kqQ.js.map → dist-dSdlKzJ8.js.map} +1 -1
- package/lib/{docx-CcB3jYd3.js → docx-D_wt3a7y.js} +2 -2
- package/lib/{docx-CcB3jYd3.js.map → docx-D_wt3a7y.js.map} +1 -1
- package/lib/{exceljs-BYETsesT.js → exceljs-Bj6LWg5N.js} +56 -42
- package/lib/exceljs-Bj6LWg5N.js.map +1 -0
- package/lib/index.js +10 -10
- package/lib/{pdf-IuBgTb3T.js → pdf-NApJCU6I.js} +4 -4
- package/lib/{pdf-IuBgTb3T.js.map → pdf-NApJCU6I.js.map} +1 -1
- package/lib/{pdfmake-CKMX5URW.js → pdfmake-DPyTSQ91.js} +14 -6
- package/lib/{pdfmake-CKMX5URW.js.map → pdfmake-DPyTSQ91.js.map} +1 -1
- package/lib/{pptx-DXiMiYFM.js → pptx-DLhvPIMn.js} +2 -2
- package/lib/{pptx-DXiMiYFM.js.map → pptx-DLhvPIMn.js.map} +1 -1
- package/lib/{pptxgen.es-FsqHs8mD.js → pptxgen.es-CFrPYgTY.js} +28 -23
- package/lib/{pptxgen.es-FsqHs8mD.js.map → pptxgen.es-CFrPYgTY.js.map} +1 -1
- package/lib/{svg-BKxumy-p.js → svg-uFnPWNCU.js} +2 -3
- package/lib/{svg-BKxumy-p.js.map → svg-uFnPWNCU.js.map} +1 -1
- package/lib/{vfs_fonts-Cap07Jg3.js → vfs_fonts-BSrGAfkk.js} +2 -2
- package/lib/{vfs_fonts-Cap07Jg3.js.map → vfs_fonts-BSrGAfkk.js.map} +1 -1
- package/lib/{xlsx-Cvu4LBNy.js → xlsx-D8XqTBoR.js} +2 -2
- package/lib/{xlsx-Cvu4LBNy.js.map → xlsx-D8XqTBoR.js.map} +1 -1
- package/package.json +5 -5
- package/lib/exceljs-BYETsesT.js.map +0 -1
|
@@ -231,7 +231,7 @@ function processSlide(pageNode, pptx) {
|
|
|
231
231
|
const pptxRenderer = { async render(node, _options) {
|
|
232
232
|
let PptxGenJS;
|
|
233
233
|
try {
|
|
234
|
-
PptxGenJS = await import("./pptxgen.es-
|
|
234
|
+
PptxGenJS = await import("./pptxgen.es-CFrPYgTY.js");
|
|
235
235
|
} catch {
|
|
236
236
|
throw new Error("[@pyreon/document] PPTX renderer requires \"pptxgenjs\" package. Install it: bun add pptxgenjs");
|
|
237
237
|
}
|
|
@@ -256,4 +256,4 @@ const pptxRenderer = { async render(node, _options) {
|
|
|
256
256
|
|
|
257
257
|
//#endregion
|
|
258
258
|
export { pptxRenderer };
|
|
259
|
-
//# sourceMappingURL=pptx-
|
|
259
|
+
//# sourceMappingURL=pptx-DLhvPIMn.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pptx-DXiMiYFM.js","names":[],"sources":["../src/renderers/pptx.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc, sanitizeXmlColor } from '../sanitize'\nimport type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from '../types'\n\n/**\n * PPTX renderer — lazy-loads pptxgenjs on first use.\n * Each `<Page>` becomes a slide. Document nodes map to PPTX elements.\n *\n * @example\n * ```ts\n * import { render, Document, Page, Heading, Text } from '@pyreon/document'\n *\n * const doc = Document({\n * title: 'Presentation',\n * children: [\n * Page({ children: [Heading({ children: 'Slide 1' }), Text({ children: 'Hello' })] }),\n * Page({ children: [Heading({ children: 'Slide 2' })] }),\n * ],\n * })\n * const pptx = await render(doc, 'pptx') // → Uint8Array\n * ```\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === 'string' ? { header: col } : col\n}\n\nfunction getTextContent(children: DocChild[]): string {\n return children\n .map((c) => (typeof c === 'string' ? c : getTextContent((c as DocNode).children)))\n .join('')\n}\n\n/** Vertical position tracker for placing elements on a slide. */\ninterface SlideContext {\n slide: PptxSlide\n y: number\n}\n\n// Duck-typed pptxgenjs interfaces to avoid hard dependency on types\ninterface PptxSlide {\n addText(text: string | PptxTextProps[], opts?: Record<string, unknown>): void\n addImage(opts: Record<string, unknown>): void\n addTable(rows: unknown[][], opts?: Record<string, unknown>): void\n}\n\ninterface PptxTextProps {\n text: string\n options?: Record<string, unknown>\n}\n\ninterface PptxGen {\n addSlide(): PptxSlide\n write(outputType: string): Promise<unknown>\n title: string\n author: string\n subject: string\n}\n\nconst HEADING_SIZES: Record<number, number> = {\n 1: 28,\n 2: 24,\n 3: 20,\n 4: 18,\n 5: 16,\n 6: 14,\n}\n\nconst SLIDE_WIDTH = 10 // inches\nconst CONTENT_MARGIN = 0.5\nconst CONTENT_WIDTH = SLIDE_WIDTH - CONTENT_MARGIN * 2\n\nfunction processNode(node: DocNode, ctx: SlideContext): void {\n const p = node.props\n\n switch (node.type) {\n case 'heading': {\n const level = (p.level as number) ?? 1\n const fontSize = HEADING_SIZES[level] ?? 20\n ctx.slide.addText(getTextContent(node.children), {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.6,\n fontSize,\n bold: true,\n color: sanitizeXmlColor((p.color as string) ?? '#000000'),\n align: (p.align as string) ?? 'left',\n })\n ctx.y += 0.7\n break\n }\n\n case 'text': {\n const text = getTextContent(node.children)\n ctx.slide.addText(text, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.4,\n fontSize: (p.size as number) ?? 14,\n bold: p.bold ?? false,\n italic: p.italic ?? false,\n underline: p.underline ? { style: 'sng' } : undefined,\n strike: p.strikethrough ? 'sngStrike' : undefined,\n color: sanitizeXmlColor((p.color as string) ?? '#333333'),\n align: (p.align as string) ?? 'left',\n })\n ctx.y += 0.5\n break\n }\n\n case 'image': {\n const src = sanitizeImageSrc(p.src as string)\n const w = Math.min(((p.width as number) ?? 400) / 96, CONTENT_WIDTH)\n const h = ((p.height as number) ?? 300) / 96\n\n if (src.startsWith('data:')) {\n ctx.slide.addImage({\n data: src,\n x: CONTENT_MARGIN,\n y: ctx.y,\n w,\n h,\n })\n ctx.y += h + 0.2\n }\n // HTTP URLs and local paths are not supported — skip silently\n break\n }\n\n case 'table': {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)\n const rows = (p.rows ?? []) as (string | number)[][]\n const hs = p.headerStyle as { background?: string; color?: string } | undefined\n\n const headerRow = columns.map((col) => ({\n text: col.header,\n options: {\n bold: true,\n fill: { color: sanitizeXmlColor(hs?.background ?? '#f5f5f5') },\n color: sanitizeXmlColor(hs?.color ?? '#000000'),\n align: col.align ?? 'left',\n fontSize: 12,\n },\n }))\n\n const dataRows = rows.map((row, rowIdx) =>\n columns.map((col, colIdx) => ({\n text: String(row[colIdx] ?? ''),\n options: {\n align: col.align ?? 'left',\n fontSize: 11,\n fill: p.striped && rowIdx % 2 === 1 ? { color: 'F9F9F9' } : undefined,\n },\n })),\n )\n\n const allRows = [headerRow, ...dataRows]\n const rowHeight = 0.35\n const tableHeight = allRows.length * rowHeight\n\n ctx.slide.addTable(allRows, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n border: { pt: 0.5, color: 'DDDDDD' },\n rowH: rowHeight,\n })\n ctx.y += tableHeight + 0.2\n break\n }\n\n case 'list': {\n const items = node.children\n .filter((c): c is DocNode => typeof c !== 'string')\n .map((item) => getTextContent(item.children))\n\n const isOrdered = p.ordered as boolean\n const listText = items.map((item, i) => ({\n text: isOrdered ? `${i + 1}. ${item}\\n` : `\\u2022 ${item}\\n`,\n options: { fontSize: 13, bullet: false },\n }))\n\n ctx.slide.addText(listText, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: items.length * 0.35,\n })\n ctx.y += items.length * 0.35 + 0.1\n break\n }\n\n case 'code': {\n const text = getTextContent(node.children)\n ctx.slide.addText(text, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.5,\n fontSize: 10,\n fontFace: 'Courier New',\n fill: { color: 'F5F5F5' },\n color: '333333',\n })\n ctx.y += 0.6\n break\n }\n\n case 'quote': {\n const text = getTextContent(node.children)\n ctx.slide.addText(text, {\n x: CONTENT_MARGIN + 0.3,\n y: ctx.y,\n w: CONTENT_WIDTH - 0.3,\n h: 0.5,\n fontSize: 13,\n italic: true,\n color: '555555',\n })\n ctx.y += 0.6\n break\n }\n\n case 'link': {\n ctx.slide.addText(getTextContent(node.children), {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.4,\n fontSize: 13,\n color: '4F46E5',\n underline: { style: 'sng' },\n hyperlink: { url: sanitizeHref(p.href as string) },\n })\n ctx.y += 0.5\n break\n }\n\n case 'button': {\n ctx.slide.addText(getTextContent(node.children), {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: 3,\n h: 0.5,\n fontSize: 14,\n bold: true,\n color: sanitizeXmlColor((p.color as string) ?? '#ffffff'),\n fill: {\n color: sanitizeXmlColor((p.background as string) ?? '#4f46e5'),\n },\n align: 'center',\n hyperlink: { url: sanitizeHref(p.href as string) },\n })\n ctx.y += 0.6\n break\n }\n\n case 'spacer': {\n ctx.y += ((p.height as number) ?? 12) / 72\n break\n }\n\n case 'divider': {\n // Render as a thin line using a text element with top border\n ctx.slide.addText('', {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.02,\n fill: { color: sanitizeXmlColor((p.color as string) ?? '#DDDDDD') },\n })\n ctx.y += 0.2\n break\n }\n\n // Container types — recurse into children\n case 'section':\n case 'row':\n case 'column':\n for (const child of node.children) {\n if (typeof child !== 'string') {\n processNode(child, ctx)\n }\n }\n break\n\n default:\n break\n }\n}\n\nfunction processSlide(pageNode: DocNode, pptx: PptxGen): void {\n const slide = pptx.addSlide()\n const ctx: SlideContext = { slide, y: CONTENT_MARGIN }\n\n for (const child of pageNode.children) {\n if (typeof child !== 'string') {\n processNode(child, ctx)\n }\n }\n}\n\nexport const pptxRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<Uint8Array> {\n let PptxGenJS: any\n try {\n PptxGenJS = await import('pptxgenjs')\n } catch {\n throw new Error(\n '[@pyreon/document] PPTX renderer requires \"pptxgenjs\" package. Install it: bun add pptxgenjs',\n )\n }\n const PptxGenClass = PptxGenJS.default ?? PptxGenJS\n\n const pptx = new PptxGenClass() as PptxGen\n\n // Set metadata\n if (node.props.title) pptx.title = node.props.title as string\n if (node.props.author) pptx.author = node.props.author as string\n if (node.props.subject) pptx.subject = node.props.subject as string\n\n // Collect pages — each becomes a slide\n const pages: DocNode[] = []\n for (const child of node.children) {\n if (typeof child !== 'string' && child.type === 'page') {\n pages.push(child)\n }\n }\n\n // If no explicit pages, treat entire document content as one slide\n if (pages.length === 0) {\n const syntheticPage: DocNode = {\n type: 'page',\n props: {},\n children: node.children,\n }\n pages.push(syntheticPage)\n }\n\n for (const page of pages) {\n processSlide(page, pptx)\n }\n\n const output = await pptx.write('arraybuffer')\n return new Uint8Array(output as ArrayBuffer)\n },\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pptx-DLhvPIMn.js","names":[],"sources":["../src/renderers/pptx.ts"],"sourcesContent":["import { sanitizeHref, sanitizeImageSrc, sanitizeXmlColor } from '../sanitize'\nimport type { DocChild, DocNode, DocumentRenderer, RenderOptions, TableColumn } from '../types'\n\n/**\n * PPTX renderer — lazy-loads pptxgenjs on first use.\n * Each `<Page>` becomes a slide. Document nodes map to PPTX elements.\n *\n * @example\n * ```ts\n * import { render, Document, Page, Heading, Text } from '@pyreon/document'\n *\n * const doc = Document({\n * title: 'Presentation',\n * children: [\n * Page({ children: [Heading({ children: 'Slide 1' }), Text({ children: 'Hello' })] }),\n * Page({ children: [Heading({ children: 'Slide 2' })] }),\n * ],\n * })\n * const pptx = await render(doc, 'pptx') // → Uint8Array\n * ```\n */\n\nfunction resolveColumn(col: string | TableColumn): TableColumn {\n return typeof col === 'string' ? { header: col } : col\n}\n\nfunction getTextContent(children: DocChild[]): string {\n return children\n .map((c) => (typeof c === 'string' ? c : getTextContent((c as DocNode).children)))\n .join('')\n}\n\n/** Vertical position tracker for placing elements on a slide. */\ninterface SlideContext {\n slide: PptxSlide\n y: number\n}\n\n// Duck-typed pptxgenjs interfaces to avoid hard dependency on types\ninterface PptxSlide {\n addText(text: string | PptxTextProps[], opts?: Record<string, unknown>): void\n addImage(opts: Record<string, unknown>): void\n addTable(rows: unknown[][], opts?: Record<string, unknown>): void\n}\n\ninterface PptxTextProps {\n text: string\n options?: Record<string, unknown>\n}\n\ninterface PptxGen {\n addSlide(): PptxSlide\n write(outputType: string): Promise<unknown>\n title: string\n author: string\n subject: string\n}\n\nconst HEADING_SIZES: Record<number, number> = {\n 1: 28,\n 2: 24,\n 3: 20,\n 4: 18,\n 5: 16,\n 6: 14,\n}\n\nconst SLIDE_WIDTH = 10 // inches\nconst CONTENT_MARGIN = 0.5\nconst CONTENT_WIDTH = SLIDE_WIDTH - CONTENT_MARGIN * 2\n\nfunction processNode(node: DocNode, ctx: SlideContext): void {\n const p = node.props\n\n switch (node.type) {\n case 'heading': {\n const level = (p.level as number) ?? 1\n const fontSize = HEADING_SIZES[level] ?? 20\n ctx.slide.addText(getTextContent(node.children), {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.6,\n fontSize,\n bold: true,\n color: sanitizeXmlColor((p.color as string) ?? '#000000'),\n align: (p.align as string) ?? 'left',\n })\n ctx.y += 0.7\n break\n }\n\n case 'text': {\n const text = getTextContent(node.children)\n ctx.slide.addText(text, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.4,\n fontSize: (p.size as number) ?? 14,\n bold: p.bold ?? false,\n italic: p.italic ?? false,\n underline: p.underline ? { style: 'sng' } : undefined,\n strike: p.strikethrough ? 'sngStrike' : undefined,\n color: sanitizeXmlColor((p.color as string) ?? '#333333'),\n align: (p.align as string) ?? 'left',\n })\n ctx.y += 0.5\n break\n }\n\n case 'image': {\n const src = sanitizeImageSrc(p.src as string)\n const w = Math.min(((p.width as number) ?? 400) / 96, CONTENT_WIDTH)\n const h = ((p.height as number) ?? 300) / 96\n\n if (src.startsWith('data:')) {\n ctx.slide.addImage({\n data: src,\n x: CONTENT_MARGIN,\n y: ctx.y,\n w,\n h,\n })\n ctx.y += h + 0.2\n }\n // HTTP URLs and local paths are not supported — skip silently\n break\n }\n\n case 'table': {\n const columns = ((p.columns ?? []) as (string | TableColumn)[]).map(resolveColumn)\n const rows = (p.rows ?? []) as (string | number)[][]\n const hs = p.headerStyle as { background?: string; color?: string } | undefined\n\n const headerRow = columns.map((col) => ({\n text: col.header,\n options: {\n bold: true,\n fill: { color: sanitizeXmlColor(hs?.background ?? '#f5f5f5') },\n color: sanitizeXmlColor(hs?.color ?? '#000000'),\n align: col.align ?? 'left',\n fontSize: 12,\n },\n }))\n\n const dataRows = rows.map((row, rowIdx) =>\n columns.map((col, colIdx) => ({\n text: String(row[colIdx] ?? ''),\n options: {\n align: col.align ?? 'left',\n fontSize: 11,\n fill: p.striped && rowIdx % 2 === 1 ? { color: 'F9F9F9' } : undefined,\n },\n })),\n )\n\n const allRows = [headerRow, ...dataRows]\n const rowHeight = 0.35\n const tableHeight = allRows.length * rowHeight\n\n ctx.slide.addTable(allRows, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n border: { pt: 0.5, color: 'DDDDDD' },\n rowH: rowHeight,\n })\n ctx.y += tableHeight + 0.2\n break\n }\n\n case 'list': {\n const items = node.children\n .filter((c): c is DocNode => typeof c !== 'string')\n .map((item) => getTextContent(item.children))\n\n const isOrdered = p.ordered as boolean\n const listText = items.map((item, i) => ({\n text: isOrdered ? `${i + 1}. ${item}\\n` : `\\u2022 ${item}\\n`,\n options: { fontSize: 13, bullet: false },\n }))\n\n ctx.slide.addText(listText, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: items.length * 0.35,\n })\n ctx.y += items.length * 0.35 + 0.1\n break\n }\n\n case 'code': {\n const text = getTextContent(node.children)\n ctx.slide.addText(text, {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.5,\n fontSize: 10,\n fontFace: 'Courier New',\n fill: { color: 'F5F5F5' },\n color: '333333',\n })\n ctx.y += 0.6\n break\n }\n\n case 'quote': {\n const text = getTextContent(node.children)\n ctx.slide.addText(text, {\n x: CONTENT_MARGIN + 0.3,\n y: ctx.y,\n w: CONTENT_WIDTH - 0.3,\n h: 0.5,\n fontSize: 13,\n italic: true,\n color: '555555',\n })\n ctx.y += 0.6\n break\n }\n\n case 'link': {\n ctx.slide.addText(getTextContent(node.children), {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.4,\n fontSize: 13,\n color: '4F46E5',\n underline: { style: 'sng' },\n hyperlink: { url: sanitizeHref(p.href as string) },\n })\n ctx.y += 0.5\n break\n }\n\n case 'button': {\n ctx.slide.addText(getTextContent(node.children), {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: 3,\n h: 0.5,\n fontSize: 14,\n bold: true,\n color: sanitizeXmlColor((p.color as string) ?? '#ffffff'),\n fill: {\n color: sanitizeXmlColor((p.background as string) ?? '#4f46e5'),\n },\n align: 'center',\n hyperlink: { url: sanitizeHref(p.href as string) },\n })\n ctx.y += 0.6\n break\n }\n\n case 'spacer': {\n ctx.y += ((p.height as number) ?? 12) / 72\n break\n }\n\n case 'divider': {\n // Render as a thin line using a text element with top border\n ctx.slide.addText('', {\n x: CONTENT_MARGIN,\n y: ctx.y,\n w: CONTENT_WIDTH,\n h: 0.02,\n fill: { color: sanitizeXmlColor((p.color as string) ?? '#DDDDDD') },\n })\n ctx.y += 0.2\n break\n }\n\n // Container types — recurse into children\n case 'section':\n case 'row':\n case 'column':\n for (const child of node.children) {\n if (typeof child !== 'string') {\n processNode(child, ctx)\n }\n }\n break\n\n default:\n break\n }\n}\n\nfunction processSlide(pageNode: DocNode, pptx: PptxGen): void {\n const slide = pptx.addSlide()\n const ctx: SlideContext = { slide, y: CONTENT_MARGIN }\n\n for (const child of pageNode.children) {\n if (typeof child !== 'string') {\n processNode(child, ctx)\n }\n }\n}\n\nexport const pptxRenderer: DocumentRenderer = {\n async render(node: DocNode, _options?: RenderOptions): Promise<Uint8Array> {\n let PptxGenJS: any\n try {\n PptxGenJS = await import('pptxgenjs')\n } catch {\n throw new Error(\n '[@pyreon/document] PPTX renderer requires \"pptxgenjs\" package. Install it: bun add pptxgenjs',\n )\n }\n const PptxGenClass = PptxGenJS.default ?? PptxGenJS\n\n const pptx = new PptxGenClass() as PptxGen\n\n // Set metadata\n if (node.props.title) pptx.title = node.props.title as string\n if (node.props.author) pptx.author = node.props.author as string\n if (node.props.subject) pptx.subject = node.props.subject as string\n\n // Collect pages — each becomes a slide\n const pages: DocNode[] = []\n for (const child of node.children) {\n if (typeof child !== 'string' && child.type === 'page') {\n pages.push(child)\n }\n }\n\n // If no explicit pages, treat entire document content as one slide\n if (pages.length === 0) {\n const syntheticPage: DocNode = {\n type: 'page',\n props: {},\n children: node.children,\n }\n pages.push(syntheticPage)\n }\n\n for (const page of pages) {\n processSlide(page, pptx)\n }\n\n const output = await pptx.write('arraybuffer')\n return new Uint8Array(output as ArrayBuffer)\n },\n}\n"],"mappings":"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"}
|
|
@@ -2463,10 +2463,11 @@ var Slide = class {
|
|
|
2463
2463
|
* @return {Slide} this Slide
|
|
2464
2464
|
*/
|
|
2465
2465
|
addText(text, options) {
|
|
2466
|
-
|
|
2466
|
+
const textParam = typeof text === "string" || typeof text === "number" ? [{
|
|
2467
2467
|
text,
|
|
2468
2468
|
options
|
|
2469
|
-
}] : text
|
|
2469
|
+
}] : text;
|
|
2470
|
+
addTextDefinition(this, textParam, options, false);
|
|
2470
2471
|
return this;
|
|
2471
2472
|
}
|
|
2472
2473
|
};
|
|
@@ -5443,27 +5444,31 @@ var PptxGenJS = class {
|
|
|
5443
5444
|
}));
|
|
5444
5445
|
}));
|
|
5445
5446
|
});
|
|
5447
|
+
const layout4x3 = {
|
|
5448
|
+
name: "screen4x3",
|
|
5449
|
+
width: 9144e3,
|
|
5450
|
+
height: 6858e3
|
|
5451
|
+
};
|
|
5452
|
+
const layout16x9 = {
|
|
5453
|
+
name: "screen16x9",
|
|
5454
|
+
width: 9144e3,
|
|
5455
|
+
height: 5143500
|
|
5456
|
+
};
|
|
5457
|
+
const layout16x10 = {
|
|
5458
|
+
name: "screen16x10",
|
|
5459
|
+
width: 9144e3,
|
|
5460
|
+
height: 5715e3
|
|
5461
|
+
};
|
|
5462
|
+
const layoutWide = {
|
|
5463
|
+
name: "custom",
|
|
5464
|
+
width: 12192e3,
|
|
5465
|
+
height: 6858e3
|
|
5466
|
+
};
|
|
5446
5467
|
this.LAYOUTS = {
|
|
5447
|
-
LAYOUT_4x3:
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
},
|
|
5452
|
-
LAYOUT_16x9: {
|
|
5453
|
-
name: "screen16x9",
|
|
5454
|
-
width: 9144e3,
|
|
5455
|
-
height: 5143500
|
|
5456
|
-
},
|
|
5457
|
-
LAYOUT_16x10: {
|
|
5458
|
-
name: "screen16x10",
|
|
5459
|
-
width: 9144e3,
|
|
5460
|
-
height: 5715e3
|
|
5461
|
-
},
|
|
5462
|
-
LAYOUT_WIDE: {
|
|
5463
|
-
name: "custom",
|
|
5464
|
-
width: 12192e3,
|
|
5465
|
-
height: 6858e3
|
|
5466
|
-
}
|
|
5468
|
+
LAYOUT_4x3: layout4x3,
|
|
5469
|
+
LAYOUT_16x9: layout16x9,
|
|
5470
|
+
LAYOUT_16x10: layout16x10,
|
|
5471
|
+
LAYOUT_WIDE: layoutWide
|
|
5467
5472
|
};
|
|
5468
5473
|
this._author = "PptxGenJS";
|
|
5469
5474
|
this._company = "PptxGenJS";
|
|
@@ -5691,4 +5696,4 @@ var PptxGenJS = class {
|
|
|
5691
5696
|
|
|
5692
5697
|
//#endregion
|
|
5693
5698
|
export { PptxGenJS as default };
|
|
5694
|
-
//# sourceMappingURL=pptxgen.es-
|
|
5699
|
+
//# sourceMappingURL=pptxgen.es-CFrPYgTY.js.map
|