pptx-custom 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # pptx-custom
2
2
 
3
- Utilities to customize PPTX JSON templates in two stages:
3
+ [中文文档](./README.zh-CN.md)
4
4
 
5
- - `applyCustomContent`: replace default slide content from backend JSON text.
6
- - `applyCustomTheme`: apply user theme settings (palette/font/background).
7
- - `parseCustomContent`: parse custom content to slide data
5
+ Utilities for customizing `json2pptx` JSON decks in two stages:
6
+
7
+ - Content stage: map backend slide content into a template deck.
8
+ - Theme stage: replace theme colors/font/background and apply scoped media.
8
9
 
9
10
  ## Install
10
11
 
@@ -12,31 +13,85 @@ Utilities to customize PPTX JSON templates in two stages:
12
13
  npm i pptx-custom
13
14
  ```
14
15
 
15
- ## Usage
16
+ ## Exports
17
+
18
+ - `applyCustomContent(template, input)`
19
+ - `parseCustomContent(raw)`
20
+ - `applyCustomContentToTemplate(template, slides)`
21
+ - `applyCustomTheme(deck, themeInput)`
22
+
23
+ Types are also exported, including:
24
+ `CustomSlide`, `Deck`, `PptxCustomContentInput`, `PptxCustomThemeInput`,
25
+ `PptxCustomOptions`, `TemplateJson`, `TemplateJsonSlide`, `TemplateJsonElement`,
26
+ `TemplateJsonTheme`.
27
+
28
+ ## Quick Start
16
29
 
17
30
  ```ts
18
31
  import {
19
32
  applyCustomContent,
20
33
  applyCustomTheme,
21
34
  parseCustomContent,
35
+ applyCustomContentToTemplate
22
36
  } from 'pptx-custom'
23
37
 
24
- const deckWithContent = applyCustomContent(templateDeck, backendText)
38
+ const withContent = applyCustomContent(templateDeck, backendText)
25
39
 
26
- const deckWithTheme = applyCustomTheme(deckWithContent, {
40
+ const withTheme = applyCustomTheme(withContent, {
27
41
  themeColors: ['#111111', '#333333', '#555555', '#777777', '#999999', '#BBBBBB'],
28
42
  fontColor: '#222222',
29
- backgroundColor: '#FFFFFF'
43
+ backgroundColor: '#FFFFFF',
44
+ backgroundImage: {
45
+ src: 'https://example.com/background.png',
46
+ scope: {
47
+ cover: false,
48
+ contents: true,
49
+ transition: true,
50
+ content: true,
51
+ end: false
52
+ }
53
+ },
54
+ logoImage: {
55
+ src: 'https://example.com/logo.png',
56
+ position: 'right',
57
+ scope: {
58
+ cover: true,
59
+ contents: true,
60
+ transition: true,
61
+ content: true,
62
+ end: true
63
+ }
64
+ }
30
65
  })
31
66
 
32
67
  const slides = parseCustomContent(backendText)
33
- const deckFromSlides = applyCustomContentToTemplate(templateDeck, slides)
34
-
68
+ const withContentDirect = applyCustomContentToTemplate(templateDeck, slides)
35
69
  ```
36
70
 
37
- ## Custom Content Format
71
+ ## Custom Content Input
72
+
73
+ `parseCustomContent` and `applyCustomContent` support:
74
+
75
+ 1. NDJSON (one slide per line)
76
+ 2. JSON array of slides
77
+ 3. JSON object with a `slides` array
78
+ 4. JSON object containing a single slide (with `type`)
79
+
80
+ Supported slide types:
38
81
 
39
- `applyCustomContent` and `parseCustomContent` accept NDJSON-style lines or JSON arrays/objects of slides:
82
+ - `cover`
83
+ - `contents`
84
+ - `transition`
85
+ - `content`
86
+ - `end`
87
+
88
+ Legacy aliases accepted in input:
89
+
90
+ - `agenda` -> `contents`
91
+ - `section` -> `transition`
92
+ - `ending` -> `end`
93
+
94
+ Example NDJSON:
40
95
 
41
96
  ```json
42
97
  {"type":"cover","data":{"title":"Title","text":"Subtitle"}}
@@ -46,8 +101,31 @@ const deckFromSlides = applyCustomContentToTemplate(templateDeck, slides)
46
101
  {"type":"end"}
47
102
  ```
48
103
 
49
- ## Exported APIs
104
+ ## Theme Input
50
105
 
51
- - `applyCustomContent(template, input)`
52
- - `parseCustomContent(raw)`
53
- - `applyCustomTheme(deck, themeUpdate)`
106
+ `applyCustomTheme` accepts `PptxCustomThemeInput`:
107
+
108
+ - `themeColors: string[]` (uses first 6)
109
+ - `fontColor: string`
110
+ - `backgroundColor?: string`
111
+ - `backgroundImage?: { src, scope, width?, height? }`
112
+ - `logoImage?: { src, scope, position, width?, height? }`
113
+ - `clearBackgroundImage?: boolean`
114
+ - `clearLogoImage?: boolean`
115
+
116
+ `scope` keys:
117
+ `cover | contents | transition | content | end`
118
+
119
+ ## Behavior Notes
120
+
121
+ - Both `applyCustomContent` and `applyCustomTheme` run through `json2pptx-schema`
122
+ parsing/normalization before returning.
123
+ - `applyCustomContent` selects template slides by `type`, and for `contents/content`
124
+ prefers layouts with the closest capacity to the requested item count.
125
+ - `applyCustomContent` normalizes logo elements (`imageType: "logo"`) to stay within
126
+ top margins and removes logo clipping.
127
+ - `applyCustomTheme` inserts scoped background images as slide elements with
128
+ `imageType: "background"` and logo images with `imageType: "logo"`.
129
+ - When both `backgroundImage` and `backgroundColor` are provided, background color is
130
+ applied as a 50% alpha overlay color on targeted slides.
131
+ - `clearBackgroundImage` also clears logo images in current behavior.
@@ -0,0 +1,131 @@
1
+ # pptx-custom
2
+
3
+ [English](./README.md)
4
+
5
+ 用于对 `json2pptx` JSON deck 进行两阶段定制:
6
+
7
+ - 内容阶段:将后端内容映射到模板 deck。
8
+ - 主题阶段:替换主题色/字体/背景,并按范围应用媒体资源。
9
+
10
+ ## 安装
11
+
12
+ ```bash
13
+ npm i pptx-custom
14
+ ```
15
+
16
+ ## 导出 API
17
+
18
+ - `applyCustomContent(template, input)`
19
+ - `parseCustomContent(raw)`
20
+ - `applyCustomContentToTemplate(template, slides)`
21
+ - `applyCustomTheme(deck, themeInput)`
22
+
23
+ 同时导出类型,包括:
24
+ `CustomSlide`、`Deck`、`PptxCustomContentInput`、`PptxCustomThemeInput`、
25
+ `PptxCustomOptions`、`TemplateJson`、`TemplateJsonSlide`、`TemplateJsonElement`、
26
+ `TemplateJsonTheme`。
27
+
28
+ ## 快速开始
29
+
30
+ ```ts
31
+ import {
32
+ applyCustomContent,
33
+ applyCustomTheme,
34
+ parseCustomContent,
35
+ applyCustomContentToTemplate
36
+ } from 'pptx-custom'
37
+
38
+ const withContent = applyCustomContent(templateDeck, backendText)
39
+
40
+ const withTheme = applyCustomTheme(withContent, {
41
+ themeColors: ['#111111', '#333333', '#555555', '#777777', '#999999', '#BBBBBB'],
42
+ fontColor: '#222222',
43
+ backgroundColor: '#FFFFFF',
44
+ backgroundImage: {
45
+ src: 'https://example.com/background.png',
46
+ scope: {
47
+ cover: false,
48
+ contents: true,
49
+ transition: true,
50
+ content: true,
51
+ end: false
52
+ }
53
+ },
54
+ logoImage: {
55
+ src: 'https://example.com/logo.png',
56
+ position: 'right',
57
+ scope: {
58
+ cover: true,
59
+ contents: true,
60
+ transition: true,
61
+ content: true,
62
+ end: true
63
+ }
64
+ }
65
+ })
66
+
67
+ const slides = parseCustomContent(backendText)
68
+ const withContentDirect = applyCustomContentToTemplate(templateDeck, slides)
69
+ ```
70
+
71
+ ## 自定义内容输入格式
72
+
73
+ `parseCustomContent` 和 `applyCustomContent` 支持:
74
+
75
+ 1. NDJSON(每行一个 slide)
76
+ 2. JSON slide 数组
77
+ 3. 带 `slides` 字段的 JSON 对象
78
+ 4. 单个 slide JSON 对象(包含 `type`)
79
+
80
+ 支持的 slide 类型:
81
+
82
+ - `cover`
83
+ - `contents`
84
+ - `transition`
85
+ - `content`
86
+ - `end`
87
+
88
+ 兼容的历史别名:
89
+
90
+ - `agenda` -> `contents`
91
+ - `section` -> `transition`
92
+ - `ending` -> `end`
93
+
94
+ NDJSON 示例:
95
+
96
+ ```json
97
+ {"type":"cover","data":{"title":"Title","text":"Subtitle"}}
98
+ {"type":"contents","data":{"items":["Part A","Part B"]}}
99
+ {"type":"transition","data":{"title":"Part A","text":"Section intro"}}
100
+ {"type":"content","data":{"title":"Topic","items":[{"title":"Point","text":"Detail"}]}}
101
+ {"type":"end"}
102
+ ```
103
+
104
+ ## 主题输入
105
+
106
+ `applyCustomTheme` 接收 `PptxCustomThemeInput`:
107
+
108
+ - `themeColors: string[]`(最多使用前 6 个)
109
+ - `fontColor: string`
110
+ - `backgroundColor?: string`
111
+ - `backgroundImage?: { src, scope, width?, height? }`
112
+ - `logoImage?: { src, scope, position, width?, height? }`
113
+ - `clearBackgroundImage?: boolean`
114
+ - `clearLogoImage?: boolean`
115
+
116
+ `scope` 可选键:
117
+ `cover | contents | transition | content | end`
118
+
119
+ ## 行为说明
120
+
121
+ - `applyCustomContent` 与 `applyCustomTheme` 都会在返回前经过
122
+ `json2pptx-schema` 的解析与规范化。
123
+ - `applyCustomContent` 按 `type` 选模板页;对 `contents/content` 会优先选择
124
+ 与输入条目数容量最接近的布局。
125
+ - `applyCustomContent` 会规范化 logo 元素(`imageType: "logo"`):
126
+ 保持在顶部边距内,并移除 logo 裁剪配置。
127
+ - `applyCustomTheme` 会将背景图以元素形式写入(`imageType: "background"`),
128
+ 并将 logo 以 `imageType: "logo"` 写入。
129
+ - 当同时提供 `backgroundImage` 与 `backgroundColor` 时,会在目标页应用
130
+ 50% 透明度的背景色叠加效果。
131
+ - 当前行为下,`clearBackgroundImage` 也会同时清除 logo 图片。
package/dist/index.d.mts CHANGED
@@ -102,6 +102,7 @@ type SlideElement = {
102
102
  type: string;
103
103
  id?: string;
104
104
  groupId?: string;
105
+ lock?: boolean;
105
106
  left?: number;
106
107
  top?: number;
107
108
  width?: number;
@@ -248,10 +249,30 @@ type CustomSlide = {
248
249
  data?: undefined;
249
250
  };
250
251
  type PptxCustomContentInput = string | CustomSlide[];
252
+ type ThemeScopeKey = 'cover' | 'contents' | 'transition' | 'content' | 'end';
253
+ type ThemeScope = Record<ThemeScopeKey, boolean>;
254
+ type ThemeBackgroundImageInput = {
255
+ src: string;
256
+ scope: ThemeScope;
257
+ width?: number;
258
+ height?: number;
259
+ };
260
+ type ThemeLogoPosition = 'left' | 'right';
261
+ type ThemeLogoImageInput = {
262
+ src: string;
263
+ scope: ThemeScope;
264
+ position: ThemeLogoPosition;
265
+ width?: number;
266
+ height?: number;
267
+ };
251
268
  type PptxCustomThemeInput = {
252
269
  themeColors: string[];
253
270
  fontColor: string;
254
271
  backgroundColor?: string;
272
+ backgroundImage?: ThemeBackgroundImageInput;
273
+ logoImage?: ThemeLogoImageInput;
274
+ clearBackgroundImage?: boolean;
275
+ clearLogoImage?: boolean;
255
276
  };
256
277
  type PptxCustomOptions = {
257
278
  customContent?: PptxCustomContentInput;
package/dist/index.d.ts CHANGED
@@ -102,6 +102,7 @@ type SlideElement = {
102
102
  type: string;
103
103
  id?: string;
104
104
  groupId?: string;
105
+ lock?: boolean;
105
106
  left?: number;
106
107
  top?: number;
107
108
  width?: number;
@@ -248,10 +249,30 @@ type CustomSlide = {
248
249
  data?: undefined;
249
250
  };
250
251
  type PptxCustomContentInput = string | CustomSlide[];
252
+ type ThemeScopeKey = 'cover' | 'contents' | 'transition' | 'content' | 'end';
253
+ type ThemeScope = Record<ThemeScopeKey, boolean>;
254
+ type ThemeBackgroundImageInput = {
255
+ src: string;
256
+ scope: ThemeScope;
257
+ width?: number;
258
+ height?: number;
259
+ };
260
+ type ThemeLogoPosition = 'left' | 'right';
261
+ type ThemeLogoImageInput = {
262
+ src: string;
263
+ scope: ThemeScope;
264
+ position: ThemeLogoPosition;
265
+ width?: number;
266
+ height?: number;
267
+ };
251
268
  type PptxCustomThemeInput = {
252
269
  themeColors: string[];
253
270
  fontColor: string;
254
271
  backgroundColor?: string;
272
+ backgroundImage?: ThemeBackgroundImageInput;
273
+ logoImage?: ThemeLogoImageInput;
274
+ clearBackgroundImage?: boolean;
275
+ clearLogoImage?: boolean;
255
276
  };
256
277
  type PptxCustomOptions = {
257
278
  customContent?: PptxCustomContentInput;
package/dist/index.js CHANGED
@@ -306,11 +306,63 @@ var applyCustomContentToTemplate = (template, CustomSlides) => {
306
306
  };
307
307
 
308
308
  // src/custom-content/index.ts
309
+ var FALLBACK_SLIDE_WIDTH = 1e3;
310
+ var FALLBACK_SLIDE_HEIGHT = 562.5;
311
+ var LOGO_MARGIN_X = 24;
312
+ var LOGO_MARGIN_Y = 18;
313
+ var LOGO_MAX_WIDTH_RATIO = 0.34;
314
+ var LOGO_MAX_HEIGHT_RATIO = 0.16;
315
+ function isLogoImageElement(element) {
316
+ return element.type === "image" && element.imageType === "logo";
317
+ }
318
+ function fitSize(width, height, maxWidth, maxHeight) {
319
+ const safeWidth = width > 0 ? width : maxWidth;
320
+ const safeHeight = height > 0 ? height : maxHeight;
321
+ const scale = Math.min(maxWidth / safeWidth, maxHeight / safeHeight);
322
+ return {
323
+ width: safeWidth * scale,
324
+ height: safeHeight * scale
325
+ };
326
+ }
327
+ function normalizeLogoElements(deck) {
328
+ const slideWidth = deck.width || FALLBACK_SLIDE_WIDTH;
329
+ const slideHeight = deck.height || FALLBACK_SLIDE_HEIGHT;
330
+ const logoMaxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO;
331
+ const logoMaxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO;
332
+ const slides = deck.slides.map((slide) => {
333
+ let changed = false;
334
+ const elements = slide.elements.map((element) => {
335
+ if (!isLogoImageElement(element)) return element;
336
+ const size = fitSize(
337
+ element.width ?? logoMaxWidth,
338
+ element.height ?? logoMaxHeight,
339
+ logoMaxWidth,
340
+ logoMaxHeight
341
+ );
342
+ const isLeft = (element.left ?? 0) < slideWidth / 2;
343
+ const left = isLeft ? LOGO_MARGIN_X : Math.max(LOGO_MARGIN_X, slideWidth - size.width - LOGO_MARGIN_X);
344
+ const top = LOGO_MARGIN_Y;
345
+ const { clip: _clip, ...rest } = element;
346
+ changed = true;
347
+ return {
348
+ ...rest,
349
+ left,
350
+ top,
351
+ width: size.width,
352
+ height: size.height,
353
+ fixedRatio: true
354
+ };
355
+ });
356
+ return changed ? { ...slide, elements } : slide;
357
+ });
358
+ return { ...deck, slides };
359
+ }
309
360
  function applyCustomContent(template, input) {
310
361
  const normalizedTemplate = (0, import_json2pptx_schema.parseDocument)(template);
311
362
  const CustomSlides = typeof input === "string" ? parseCustomContent(input) : input;
312
363
  const updated = applyCustomContentToTemplate(normalizedTemplate, CustomSlides);
313
- return (0, import_json2pptx_schema.parseDocument)(updated);
364
+ const withNormalizedLogo = normalizeLogoElements(updated);
365
+ return (0, import_json2pptx_schema.parseDocument)(withNormalizedLogo);
314
366
  }
315
367
 
316
368
  // src/custom-theme/index.ts
@@ -579,10 +631,178 @@ function applyTheme2Json(deck, update) {
579
631
  }
580
632
 
581
633
  // src/custom-theme/index.ts
634
+ var FALLBACK_SLIDE_WIDTH2 = 1e3;
635
+ var FALLBACK_SLIDE_HEIGHT2 = 562.5;
636
+ var LOGO_MARGIN_X2 = 24;
637
+ var LOGO_MARGIN_Y2 = 18;
638
+ var LOGO_MAX_WIDTH_RATIO2 = 0.34;
639
+ var LOGO_MAX_HEIGHT_RATIO2 = 0.16;
640
+ var DEFAULT_LOGO_ASPECT_RATIO = 3.2;
641
+ function mapSlideTypeToScopeKey(type) {
642
+ const normalized = type?.trim().toLowerCase();
643
+ if (!normalized) return null;
644
+ if (normalized === "cover") return "cover";
645
+ if (normalized === "contents" || normalized === "agenda") return "contents";
646
+ if (normalized === "transition" || normalized === "section") return "transition";
647
+ if (normalized === "content") return "content";
648
+ if (normalized === "end" || normalized === "ending") return "end";
649
+ return null;
650
+ }
651
+ function isSlideInScope(slide, scope) {
652
+ const key = mapSlideTypeToScopeKey(slide.type);
653
+ if (!key) return false;
654
+ return Boolean(scope[key]);
655
+ }
656
+ function createElementId(prefix, slideIndex) {
657
+ const random = Math.random().toString(36).slice(2, 10);
658
+ return `${prefix}-${slideIndex}-${random}`;
659
+ }
660
+ function toHalfOpacityColor(value) {
661
+ const rgb = parseColorToRgb(value);
662
+ if (!rgb) return value;
663
+ return `rgba(${rgb.r},${rgb.g},${rgb.b},0.5)`;
664
+ }
665
+ function buildBackgroundElement(src, slideWidth, slideHeight, slideIndex) {
666
+ return {
667
+ type: "image",
668
+ id: createElementId("background", slideIndex),
669
+ src,
670
+ width: slideWidth,
671
+ height: slideHeight,
672
+ left: 0,
673
+ top: 0,
674
+ fixedRatio: true,
675
+ rotate: 0,
676
+ imageType: "background",
677
+ filters: {
678
+ opacity: "100%"
679
+ }
680
+ };
681
+ }
682
+ function buildLogoElement(src, slideWidth, slideHeight, position, slideIndex, logoWidth, logoHeight) {
683
+ const aspectRatio = resolveLogoAspectRatio(logoWidth, logoHeight);
684
+ const maxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO2;
685
+ const maxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO2;
686
+ let width = maxWidth;
687
+ let height = width / aspectRatio;
688
+ if (height > maxHeight) {
689
+ height = maxHeight;
690
+ width = height * aspectRatio;
691
+ }
692
+ const left = position === "left" ? LOGO_MARGIN_X2 : Math.max(LOGO_MARGIN_X2, slideWidth - width - LOGO_MARGIN_X2);
693
+ return {
694
+ type: "image",
695
+ id: createElementId("logo", slideIndex),
696
+ src,
697
+ width,
698
+ height,
699
+ left,
700
+ top: LOGO_MARGIN_Y2,
701
+ fixedRatio: true,
702
+ rotate: 0,
703
+ imageType: "logo"
704
+ };
705
+ }
706
+ function resolveLogoAspectRatio(width, height) {
707
+ if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
708
+ return width / height;
709
+ }
710
+ return DEFAULT_LOGO_ASPECT_RATIO;
711
+ }
712
+ function replaceScopedMedia(deck, input) {
713
+ if (!deck.slides?.length) return deck;
714
+ const slideWidth = deck.width ?? FALLBACK_SLIDE_WIDTH2;
715
+ const slideHeight = deck.height ?? FALLBACK_SLIDE_HEIGHT2;
716
+ const backgroundInput = input.backgroundImage;
717
+ const logoInput = input.logoImage;
718
+ const shouldClearBackground = Boolean(input.clearBackgroundImage);
719
+ const shouldClearLogo = Boolean(input.clearLogoImage || shouldClearBackground);
720
+ if (!backgroundInput?.src && !logoInput?.src && !shouldClearBackground && !shouldClearLogo) {
721
+ return deck;
722
+ }
723
+ const slides = deck.slides.map((slide, slideIndex) => {
724
+ let nextElements = slide.elements ? [...slide.elements] : [];
725
+ let nextBackground = slide.background;
726
+ let changed = false;
727
+ if (shouldClearBackground) {
728
+ const before = nextElements.length;
729
+ nextElements = nextElements.filter(
730
+ (element) => !(element.type === "image" && element.imageType === "background")
731
+ );
732
+ if (nextElements.length !== before) {
733
+ changed = true;
734
+ if (input.backgroundColor) {
735
+ nextBackground = {
736
+ ...nextBackground ?? {},
737
+ type: "solid",
738
+ color: input.backgroundColor
739
+ };
740
+ }
741
+ }
742
+ }
743
+ if (shouldClearLogo) {
744
+ const before = nextElements.length;
745
+ nextElements = nextElements.filter(
746
+ (element) => !(element.type === "image" && element.imageType === "logo")
747
+ );
748
+ if (nextElements.length !== before) {
749
+ changed = true;
750
+ }
751
+ }
752
+ if (backgroundInput?.src && isSlideInScope(slide, backgroundInput.scope)) {
753
+ const withoutBackground = nextElements.filter(
754
+ (element) => !(element.type === "image" && element.imageType === "background")
755
+ );
756
+ nextElements = [
757
+ buildBackgroundElement(
758
+ backgroundInput.src,
759
+ slideWidth,
760
+ slideHeight,
761
+ slideIndex
762
+ ),
763
+ ...withoutBackground
764
+ ];
765
+ changed = true;
766
+ if (input.backgroundColor) {
767
+ nextBackground = {
768
+ ...nextBackground ?? {},
769
+ type: "solid",
770
+ color: toHalfOpacityColor(input.backgroundColor)
771
+ };
772
+ }
773
+ }
774
+ if (logoInput?.src && isSlideInScope(slide, logoInput.scope)) {
775
+ const withoutLogo = nextElements.filter(
776
+ (element) => !(element.type === "image" && element.imageType === "logo")
777
+ );
778
+ nextElements = [
779
+ ...withoutLogo,
780
+ buildLogoElement(
781
+ logoInput.src,
782
+ slideWidth,
783
+ slideHeight,
784
+ logoInput.position,
785
+ slideIndex,
786
+ logoInput.width,
787
+ logoInput.height
788
+ )
789
+ ];
790
+ changed = true;
791
+ }
792
+ if (!changed && nextBackground === slide.background) return slide;
793
+ return {
794
+ ...slide,
795
+ ...changed ? { elements: nextElements } : {},
796
+ ...nextBackground ? { background: nextBackground } : {}
797
+ };
798
+ });
799
+ return { ...deck, slides };
800
+ }
582
801
  function applyCustomTheme(deck, input) {
583
802
  const normalizedDeck = (0, import_json2pptx_schema2.parseDocument)(deck);
584
- const updated = applyTheme2Json(normalizedDeck, input);
585
- return (0, import_json2pptx_schema2.parseDocument)(updated);
803
+ const withColors = applyTheme2Json(normalizedDeck, input);
804
+ const withMedia = replaceScopedMedia(withColors, input);
805
+ return (0, import_json2pptx_schema2.parseDocument)(withMedia);
586
806
  }
587
807
  // Annotate the CommonJS export names for ESM import in node:
588
808
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/custom-content/index.ts","../src/custom-content/parser.ts","../src/custom-content/html.ts","../src/custom-content/slide-appliers.ts","../src/custom-content/template-builder.ts","../src/custom-theme/index.ts","../src/custom-theme/color-utils.ts","../src/custom-theme/mappings.ts","../src/custom-theme/replacers.ts","../src/custom-theme/theme-applier.ts"],"sourcesContent":["import { applyCustomContent, parseCustomContent, applyCustomContentToTemplate } from './custom-content/index'\nimport { applyCustomTheme } from './custom-theme/index'\n\nexport {\n parseCustomContent,\n applyCustomContent,\n applyCustomContentToTemplate,\n\n applyCustomTheme,\n}\n\nexport type {\n CustomSlide,\n Deck,\n PptxCustomContentInput,\n PptxCustomOptions,\n PptxCustomThemeInput,\n TemplateJson,\n TemplateJsonElement,\n TemplateJsonSlide,\n TemplateJsonTheme\n} from './types'\n","import { parseDocument } from 'json2pptx-schema'\nimport type { PptxCustomContentInput, TemplateJson } from '../types'\nimport { parseCustomContent } from './parser'\nimport { applyCustomContentToTemplate } from './template-builder'\n\nexport function applyCustomContent (\n template: TemplateJson,\n input: PptxCustomContentInput\n): TemplateJson {\n const normalizedTemplate = parseDocument(template) as unknown as TemplateJson\n const CustomSlides = typeof input === 'string' ? parseCustomContent(input) : input\n const updated = applyCustomContentToTemplate(normalizedTemplate, CustomSlides)\n return parseDocument(updated) as unknown as TemplateJson\n}\n\nexport { parseCustomContent, applyCustomContentToTemplate }\n","import type { BackendContentItem, CustomSlide } from '../types'\n\ntype UnknownRecord = Record<string, unknown>\n\nconst isRecord = (value: unknown): value is UnknownRecord =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst asString = (value: unknown): string | null =>\n typeof value === 'string' ? value : null\n\nconst asStringArray = (value: unknown): string[] | null => {\n if (!Array.isArray(value)) return null\n const normalized = value\n .map(item => asString(item))\n .filter((item): item is string => item !== null)\n return normalized.length === value.length ? normalized : null\n}\n\nconst normalizeType = (value: unknown): CustomSlide['type'] | null => {\n const raw = asString(value)?.trim().toLowerCase()\n if (!raw) return null\n if (raw === 'agenda') return 'contents'\n if (raw === 'section') return 'transition'\n if (raw === 'ending') return 'end'\n if (\n raw === 'cover' ||\n raw === 'contents' ||\n raw === 'transition' ||\n raw === 'content' ||\n raw === 'end'\n ) {\n return raw\n }\n return null\n}\n\nconst normalizeContentItems = (value: unknown): BackendContentItem[] | null => {\n if (!Array.isArray(value)) return null\n const normalized: BackendContentItem[] = []\n for (const item of value) {\n if (!isRecord(item)) return null\n const title = asString(item.title)\n const text = asString(item.text)\n if (title == null || text == null) return null\n normalized.push({ title, text })\n }\n return normalized\n}\n\nconst normalizeSlide = (value: unknown): CustomSlide | null => {\n if (!isRecord(value)) return null\n const type = normalizeType(value.type)\n if (!type) return null\n\n const rawData = isRecord(value.data) ? value.data : {}\n\n if (type === 'cover') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'contents') {\n const items = asStringArray(rawData.items)\n if (!items) return null\n return { type, data: { items } }\n }\n\n if (type === 'transition') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'content') {\n const title = asString(rawData.title)\n const items = normalizeContentItems(rawData.items)\n if (title == null || !items) return null\n return { type, data: { title, items } }\n }\n\n return { type }\n}\n\nconst parseNdJsonSlides = (raw: string): unknown[] =>\n raw\n .split(/\\r?\\n/)\n .map(line => line.trim())\n .filter(Boolean)\n .map(line => JSON.parse(line) as unknown)\n\nconst parseStructuredSlides = (raw: string): unknown[] | null => {\n const trimmed = raw.trim()\n if (!trimmed) return []\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return null\n\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed) as unknown\n } catch {\n return null\n }\n if (Array.isArray(parsed)) return parsed\n if (!isRecord(parsed)) return null\n if (Array.isArray(parsed.slides)) return parsed.slides\n if ('type' in parsed) return [parsed]\n return null\n}\n\nexport const parseCustomContent = (raw: string): CustomSlide[] => {\n const candidates = parseStructuredSlides(raw) ?? parseNdJsonSlides(raw)\n const slides = candidates\n .map(item => normalizeSlide(item))\n .filter((item): item is CustomSlide => item !== null)\n\n if (slides.length !== candidates.length) {\n throw new Error('Invalid custom content format')\n }\n return slides\n}\n","import type { TemplateJsonElement } from '../types'\n\nexport const updateHtmlContent = (html: string, text: string) => {\n if (typeof DOMParser === 'undefined') {\n return `<p>${text}</p>`\n }\n const parser = new DOMParser()\n const doc = parser.parseFromString(html, 'text/html')\n const spans = Array.from(doc.querySelectorAll('span'))\n if (spans.length > 0) {\n spans.forEach((span, index) => {\n span.textContent = index === 0 ? text : ''\n })\n } else {\n const paragraph = doc.querySelector('p')\n if (paragraph) {\n paragraph.textContent = text\n } else {\n doc.body.textContent = text\n }\n }\n return doc.body.innerHTML\n}\n\nexport const setElementText = (element: TemplateJsonElement, text: string) => {\n if (element.type !== 'text') return\n element.content = updateHtmlContent(element.content, text)\n}\n","import type {\n BackendContentData,\n BackendContentsData,\n BackendCoverData,\n BackendTransitionData,\n TemplateJsonSlide\n} from '../types'\nimport { setElementText, updateHtmlContent } from './html'\n\nfunction setShapeTextByType (\n slide: TemplateJsonSlide,\n textType: string,\n text: string\n): boolean {\n const shape = slide.elements.find((element) => {\n if (element.type !== 'shape') return false\n const maybeShape = element as unknown as {\n text?: { type?: string; content?: string }\n }\n return maybeShape.text?.type === textType\n })\n\n if (!shape) return false\n\n const shapeWithText = shape as unknown as {\n text?: { type?: string; content?: string }\n }\n if (!shapeWithText.text || typeof shapeWithText.text.content !== 'string') {\n return false\n }\n\n shapeWithText.text.content = updateHtmlContent(shapeWithText.text.content, text)\n return true\n}\n\nexport const applyCoverData = (slide: TemplateJsonSlide, data: BackendCoverData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n}\n\nexport const applyContentsData = (\n slide: TemplateJsonSlide,\n data: BackendContentsData\n) => {\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n items.forEach((element, index) => {\n const text = data.items[index]\n if (text) setElementText(element, text)\n })\n}\n\nexport const applyTransitionData = (\n slide: TemplateJsonSlide,\n data: BackendTransitionData,\n sectionIndex: number\n) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n const partNumber = slide.elements.find(\n element => element.type === 'text' && element.textType === 'partNumber'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n const formattedSectionIndex = `${sectionIndex}`.padStart(2, '0')\n if (partNumber) {\n setElementText(partNumber, formattedSectionIndex)\n } else {\n setShapeTextByType(slide, 'partNumber', formattedSectionIndex)\n }\n}\n\nexport const applyContentData = (slide: TemplateJsonSlide, data: BackendContentData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n if (title) setElementText(title, data.title)\n\n const itemTitles = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'itemTitle'\n )\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n\n data.items.forEach((item, index) => {\n const titleEl = itemTitles[index]\n const textEl = items[index]\n if (titleEl) setElementText(titleEl, item.title)\n if (textEl) setElementText(textEl, item.text)\n })\n}\n","import type { CustomSlide, TemplateJson, TemplateJsonSlide } from '../types'\nimport {\n applyContentData,\n applyContentsData,\n applyCoverData,\n applyTransitionData\n} from './slide-appliers'\n\nconst cloneSlide = (slide: TemplateJsonSlide): TemplateJsonSlide =>\n JSON.parse(JSON.stringify(slide)) as TemplateJsonSlide\n\nfunction normalizeLabel (value: string): string {\n return value\n .replace(/\\s+/g, ' ')\n .replace(/[,。、“”‘’:;!?【】()《》〈〉·,.:;!?()[\\]{}\"'`~\\-_/\\\\]/g, '')\n .trim()\n .toLowerCase()\n}\n\nfunction resolveTransitionIndex (\n customSlides: CustomSlide[],\n currentSlideIndex: number,\n transitionTitle: string,\n fallbackIndex: number\n): number {\n const normalizedTitle = normalizeLabel(transitionTitle)\n if (!normalizedTitle) return fallbackIndex\n\n const contentsItems = customSlides\n .slice(0, currentSlideIndex + 1)\n .filter((slide): slide is Extract<CustomSlide, { type: 'contents' }> => slide.type === 'contents')\n .flatMap(slide => slide.data.items)\n\n for (let index = 0; index < contentsItems.length; index += 1) {\n const normalizedItem = normalizeLabel(contentsItems[index])\n if (!normalizedItem) continue\n if (\n normalizedItem === normalizedTitle ||\n normalizedItem.includes(normalizedTitle) ||\n normalizedTitle.includes(normalizedItem)\n ) {\n return index + 1\n }\n }\n\n return fallbackIndex\n}\n\nexport const applyCustomContentToTemplate = (\n template: TemplateJson,\n CustomSlides: CustomSlide[]\n): TemplateJson => {\n const grouped = template.slides.reduce<Record<string, TemplateJsonSlide[]>>(\n (acc, slide) => {\n const key = slide.type || 'default'\n if (!acc[key]) acc[key] = []\n acc[key].push(slide)\n return acc\n },\n {}\n )\n\n const usage = new Map<string, number>()\n const getTextTypeCount = (slide: TemplateJsonSlide, textType: string) =>\n slide.elements.filter(\n element => element.type === 'text' && element.textType === textType\n ).length\n\n const getContentCapacity = (slide: TemplateJsonSlide) => {\n const titleSlots = getTextTypeCount(slide, 'itemTitle')\n const itemSlots = getTextTypeCount(slide, 'item')\n return Math.min(titleSlots, itemSlots)\n }\n\n const pickFromPool = (key: string, pool: TemplateJsonSlide[]) => {\n const index = usage.get(key) ?? 0\n usage.set(key, index + 1)\n return cloneSlide(pool[index % pool.length])\n }\n\n const pickSlide = (type: string, desiredCount?: number) => {\n const pool = grouped[type] || grouped.default || template.slides\n if (desiredCount == null || pool.length === 1) {\n return pickFromPool(type, pool)\n }\n\n const scored = pool.map(slide => {\n const capacity =\n type === 'content'\n ? getContentCapacity(slide)\n : getTextTypeCount(slide, 'item')\n return { slide, capacity }\n })\n const eligible = scored.filter(item => item.capacity >= desiredCount)\n if (eligible.length > 0) {\n const minCapacity = Math.min(...eligible.map(item => item.capacity))\n const best = eligible\n .filter(item => item.capacity === minCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, best)\n }\n const maxCapacity = Math.max(...scored.map(item => item.capacity))\n const fallback = scored\n .filter(item => item.capacity === maxCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, fallback)\n }\n\n let transitionIndex = 0\n const slides = CustomSlides.map((item, index) => {\n const desiredCount =\n item.type === 'contents'\n ? item.data.items.length\n : item.type === 'content'\n ? item.data.items.length\n : undefined\n const slide = pickSlide(item.type, desiredCount)\n if (item.type === 'cover') {\n applyCoverData(slide, item.data)\n } else if (item.type === 'contents') {\n applyContentsData(slide, item.data)\n } else if (item.type === 'transition') {\n transitionIndex += 1\n const partNumber = resolveTransitionIndex(\n CustomSlides,\n index,\n item.data.title,\n transitionIndex\n )\n applyTransitionData(slide, item.data, partNumber)\n } else if (item.type === 'content') {\n applyContentData(slide, item.data)\n }\n return slide\n })\n\n return {\n ...template,\n slides\n }\n}\n","import { parseDocument } from 'json2pptx-schema'\nimport type { Deck, PptxCustomThemeInput } from '../types'\nimport { applyTheme2Json } from './theme-applier'\n\nexport function applyCustomTheme (\n deck: Deck,\n input: PptxCustomThemeInput\n): Deck {\n const normalizedDeck = parseDocument(deck) as unknown as Deck\n const updated = applyTheme2Json(normalizedDeck, input)\n return parseDocument(updated) as unknown as Deck\n}\n\nexport { applyTheme2Json }\n","import type { ColorMapping, RGB } from './types'\n\nexport function normalizeHexColor (value: string): string | null {\n const raw = value.trim()\n const withHash = raw.startsWith('#') ? raw.slice(1) : raw\n if (withHash.length !== 3 && withHash.length !== 6) return null\n if (!/^[0-9a-fA-F]+$/.test(withHash)) return null\n const expanded =\n withHash.length === 3\n ? withHash\n .split('')\n .map((char) => char + char)\n .join('')\n : withHash\n return `#${expanded.toUpperCase()}`\n}\n\nexport function parseColorToRgb (\n value: string\n): (RGB & { alpha?: number }) | null {\n const hex = normalizeHexColor(value)\n if (hex) {\n const raw = hex.slice(1)\n const r = Number.parseInt(raw.slice(0, 2), 16)\n const g = Number.parseInt(raw.slice(2, 4), 16)\n const b = Number.parseInt(raw.slice(4, 6), 16)\n return { r, g, b }\n }\n\n const match = value.match(\n /rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)/i\n )\n if (!match) return null\n const r = Math.round(Number(match[1]))\n const g = Math.round(Number(match[2]))\n const b = Math.round(Number(match[3]))\n const alpha = match[4] !== undefined ? Number(match[4]) : undefined\n return {\n r,\n g,\n b,\n ...(Number.isFinite(alpha) ? { alpha } : {})\n }\n}\n\nexport function normalizeThemeColor (value: string): string | null {\n const hex = normalizeHexColor(value)\n if (hex) return hex\n const parsed = parseColorToRgb(value)\n if (!parsed) return null\n if (parsed.alpha !== undefined) {\n return `rgba(${parsed.r},${parsed.g},${parsed.b},${parsed.alpha})`\n }\n return `rgb(${parsed.r},${parsed.g},${parsed.b})`\n}\n\nexport function isPureColorString (value: string): boolean {\n const trimmed = value.trim()\n if (!trimmed) return false\n if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(trimmed)) return true\n return /^rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)$/i.test(\n trimmed\n )\n}\n\nfunction normalizeColorKey (value?: string): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = parseColorToRgb(trimmed)\n if (parsed) {\n return `${parsed.r},${parsed.g},${parsed.b},${parsed.alpha ?? 'none'}`\n }\n const hex = normalizeHexColor(trimmed)\n if (hex) return hex\n return trimmed.toLowerCase()\n}\n\nexport function colorsEqual (a: string, b: string): boolean {\n const aKey = normalizeColorKey(a)\n const bKey = normalizeColorKey(b)\n if (!aKey || !bKey) return false\n return aKey === bKey\n}\n\nexport function isWhiteColor (value?: string): boolean {\n const key = normalizeColorKey(value)\n if (!key) return false\n return (\n key === '#FFFFFF' ||\n key === '255,255,255,none' ||\n key === '255,255,255,1'\n )\n}\n\nexport function rgbToString (rgb: RGB): string {\n return `rgb(${rgb.r},${rgb.g},${rgb.b})`\n}\n\nexport function findMappingForColor (\n value: string,\n mappings: ColorMapping[]\n): ColorMapping | undefined {\n const parsed = parseColorToRgb(value)\n if (!parsed) return undefined\n return mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n}\n","import { normalizeHexColor, parseColorToRgb } from './color-utils'\nimport type { ColorMapping } from './types'\n\nexport function buildColorMappings (\n previous: string[],\n next: string[]\n): ColorMapping[] {\n const mappings: ColorMapping[] = []\n const length = Math.min(previous.length, next.length)\n for (let i = 0; i < length; i += 1) {\n const fromParsed = parseColorToRgb(previous[i])\n const toParsed = parseColorToRgb(next[i])\n if (!fromParsed || !toParsed) continue\n const toHex = normalizeHexColor(next[i]) ?? undefined\n mappings.push({\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n })\n }\n return mappings\n}\n\nexport function buildSingleMapping (\n from?: string,\n to?: string\n): ColorMapping | null {\n if (!from || !to) return null\n const fromParsed = parseColorToRgb(from)\n const toParsed = parseColorToRgb(to)\n if (!fromParsed || !toParsed) return null\n const toHex = normalizeHexColor(to) ?? undefined\n return {\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n }\n}\n","import type { Slide, SlideElement } from '../types'\nimport {\n findMappingForColor,\n isPureColorString,\n normalizeThemeColor,\n parseColorToRgb,\n rgbToString\n} from './color-utils'\nimport type { ColorMapping } from './types'\n\nfunction applyFontColorToHtml (value: string, fontColor: string): string {\n if (!value || !fontColor) return value\n const normalized = normalizeThemeColor(fontColor) ?? fontColor\n const hasStyleColor = /\\bcolor\\s*:/i.test(value)\n if (hasStyleColor) {\n return value.replace(/color\\s*:\\s*([^;\"']+)/gi, () => `color: ${normalized}`)\n }\n return value.replace(\n /(<[^>]+style\\s*=\\s*[\"'])([^\"']*)([\"'])/gi,\n (_match, start, styles, end) => {\n if (/\\bcolor\\s*:/i.test(styles)) return _match\n const nextStyles = styles.trim()\n ? `${styles.trim()}; color: ${normalized}`\n : `color: ${normalized}`\n return `${start}${nextStyles}${end}`\n }\n )\n}\n\nfunction replaceColorValue (value: string, mappings: ColorMapping[]): string {\n const mapping = findMappingForColor(value, mappings)\n if (!mapping) return value\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n if (parsed.alpha !== undefined) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceRgbaString (value: string, mappings: ColorMapping[]): string {\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n const mapping = mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n if (!mapping) return value\n if (parsed.alpha !== undefined || value.toLowerCase().startsWith('rgba')) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha ?? 1})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceColorsInText (value: string, mappings: ColorMapping[]): string {\n let next = value\n next = next.replace(/#([0-9a-f]{3}|[0-9a-f]{6})/gi, (match) => {\n const mapping = findMappingForColor(match, mappings)\n if (!mapping) return match\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n })\n next = next.replace(/rgba?\\([^)]*\\)/gi, (match) =>\n replaceRgbaString(match, mappings)\n )\n return next\n}\n\nfunction replaceColorsDeep (value: unknown, mappings: ColorMapping[]): unknown {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n const pureColor = isPureColorString(trimmed)\n if (pureColor) {\n const replaced = replaceColorValue(trimmed, mappings)\n return value === trimmed ? replaced : value.replace(trimmed, replaced)\n }\n return replaceColorsInText(value, mappings)\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => replaceColorsDeep(item, mappings))\n }\n\n if (value && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n const next: Record<string, unknown> = {}\n for (const [key, item] of entries) {\n next[key] = replaceColorsDeep(item, mappings)\n }\n return next\n }\n\n return value\n}\n\nfunction replaceTextElementColors (\n element: SlideElement,\n fontMappings: ColorMapping[],\n fontColor: string\n): SlideElement {\n const next = replaceColorsDeep(element, fontMappings) as SlideElement\n const normalizedFontColor = normalizeThemeColor(fontColor) ?? fontColor\n const withDefault =\n normalizedFontColor && 'defaultColor' in next\n ? { ...next, defaultColor: normalizedFontColor }\n : next\n if (!('content' in withDefault) || typeof withDefault.content !== 'string') {\n return withDefault\n }\n return {\n ...withDefault,\n content: applyFontColorToHtml(withDefault.content, normalizedFontColor)\n }\n}\n\nexport function replaceSlideColors (\n slide: Slide,\n themeMappings: ColorMapping[],\n fontMappings: ColorMapping[],\n fontColor: string\n): Slide {\n const { elements, ...rest } = slide\n const nextSlide = replaceColorsDeep(rest, themeMappings) as Slide\n if (!elements) return nextSlide\n\n const nextElements: SlideElement[] = elements.map((element) => {\n if (element && typeof element === 'object' && element.type === 'text') {\n return replaceTextElementColors(element, fontMappings, fontColor)\n }\n return replaceColorsDeep(element, themeMappings) as SlideElement\n })\n\n return { ...nextSlide, elements: nextElements }\n}\n","import type { Deck, PptxCustomThemeInput } from '../types'\nimport { colorsEqual, isWhiteColor } from './color-utils'\nimport { buildColorMappings, buildSingleMapping } from './mappings'\nimport { replaceSlideColors } from './replacers'\n\nexport function applyTheme2Json (deck: Deck, update: PptxCustomThemeInput): Deck {\n const previousTheme = deck.theme ?? {}\n const themeColors = update.themeColors.slice(0, 6)\n const themeMappings = buildColorMappings(\n previousTheme.themeColors ?? [],\n themeColors\n )\n const fontMapping = buildSingleMapping(\n previousTheme.fontColor,\n update.fontColor\n )\n const fontMappings = fontMapping ? [fontMapping] : []\n\n const nextBackground = update.backgroundColor ?? previousTheme.backgroundColor\n const prevBackground = previousTheme.backgroundColor\n const slides = deck.slides?.map((slide) => {\n const nextSlide = replaceSlideColors(\n slide,\n themeMappings,\n fontMappings,\n update.fontColor\n )\n if (!nextBackground) return nextSlide\n const currentColor = nextSlide.background?.color\n const shouldUpdate =\n !currentColor ||\n (prevBackground && colorsEqual(currentColor, prevBackground)) ||\n (!prevBackground && isWhiteColor(currentColor))\n if (!shouldUpdate) return nextSlide\n return {\n ...nextSlide,\n background: {\n ...(nextSlide.background ?? {}),\n type: nextSlide.background?.type ?? 'solid',\n color: nextBackground\n }\n }\n })\n\n return {\n ...deck,\n theme: {\n ...previousTheme,\n themeColors,\n fontColor: update.fontColor,\n backgroundColor: update.backgroundColor ?? previousTheme.backgroundColor\n },\n slides\n }\n}\n"],"mappings":"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","names":["import_json2pptx_schema","r","g","b"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/custom-content/index.ts","../src/custom-content/parser.ts","../src/custom-content/html.ts","../src/custom-content/slide-appliers.ts","../src/custom-content/template-builder.ts","../src/custom-theme/index.ts","../src/custom-theme/color-utils.ts","../src/custom-theme/mappings.ts","../src/custom-theme/replacers.ts","../src/custom-theme/theme-applier.ts"],"sourcesContent":["import { applyCustomContent, parseCustomContent, applyCustomContentToTemplate } from './custom-content/index'\nimport { applyCustomTheme } from './custom-theme/index'\n\nexport {\n parseCustomContent,\n applyCustomContent,\n applyCustomContentToTemplate,\n\n applyCustomTheme,\n}\n\nexport type {\n CustomSlide,\n Deck,\n PptxCustomContentInput,\n PptxCustomOptions,\n PptxCustomThemeInput,\n TemplateJson,\n TemplateJsonElement,\n TemplateJsonSlide,\n TemplateJsonTheme\n} from './types'\n","import { parseDocument } from 'json2pptx-schema'\nimport type {\n PptxCustomContentInput,\n TemplateJson,\n TemplateJsonElement,\n TemplateJsonImage\n} from '../types'\nimport { parseCustomContent } from './parser'\nimport { applyCustomContentToTemplate } from './template-builder'\n\nconst FALLBACK_SLIDE_WIDTH = 1000\nconst FALLBACK_SLIDE_HEIGHT = 562.5\nconst LOGO_MARGIN_X = 24\nconst LOGO_MARGIN_Y = 18\nconst LOGO_MAX_WIDTH_RATIO = 0.34\nconst LOGO_MAX_HEIGHT_RATIO = 0.16\n\nfunction isLogoImageElement (\n element: TemplateJsonElement\n): element is TemplateJsonImage {\n return element.type === 'image' && element.imageType === 'logo'\n}\n\nfunction fitSize (\n width: number,\n height: number,\n maxWidth: number,\n maxHeight: number\n): { width: number; height: number } {\n const safeWidth = width > 0 ? width : maxWidth\n const safeHeight = height > 0 ? height : maxHeight\n const scale = Math.min(maxWidth / safeWidth, maxHeight / safeHeight)\n return {\n width: safeWidth * scale,\n height: safeHeight * scale\n }\n}\n\nfunction normalizeLogoElements (deck: TemplateJson): TemplateJson {\n const slideWidth = deck.width || FALLBACK_SLIDE_WIDTH\n const slideHeight = deck.height || FALLBACK_SLIDE_HEIGHT\n const logoMaxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO\n const logoMaxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO\n\n const slides = deck.slides.map(slide => {\n let changed = false\n const elements = slide.elements.map(element => {\n if (!isLogoImageElement(element)) return element\n\n const size = fitSize(\n element.width ?? logoMaxWidth,\n element.height ?? logoMaxHeight,\n logoMaxWidth,\n logoMaxHeight\n )\n const isLeft = (element.left ?? 0) < slideWidth / 2\n const left = isLeft\n ? LOGO_MARGIN_X\n : Math.max(LOGO_MARGIN_X, slideWidth - size.width - LOGO_MARGIN_X)\n const top = LOGO_MARGIN_Y\n const { clip: _clip, ...rest } = element\n\n changed = true\n return {\n ...rest,\n left,\n top,\n width: size.width,\n height: size.height,\n fixedRatio: true\n }\n })\n\n return changed ? { ...slide, elements } : slide\n })\n\n return { ...deck, slides }\n}\n\nexport function applyCustomContent (\n template: TemplateJson,\n input: PptxCustomContentInput\n): TemplateJson {\n const normalizedTemplate = parseDocument(template) as unknown as TemplateJson\n const CustomSlides = typeof input === 'string' ? parseCustomContent(input) : input\n const updated = applyCustomContentToTemplate(normalizedTemplate, CustomSlides)\n const withNormalizedLogo = normalizeLogoElements(updated)\n return parseDocument(withNormalizedLogo) as unknown as TemplateJson\n}\n\nexport { parseCustomContent, applyCustomContentToTemplate }\n","import type { BackendContentItem, CustomSlide } from '../types'\n\ntype UnknownRecord = Record<string, unknown>\n\nconst isRecord = (value: unknown): value is UnknownRecord =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst asString = (value: unknown): string | null =>\n typeof value === 'string' ? value : null\n\nconst asStringArray = (value: unknown): string[] | null => {\n if (!Array.isArray(value)) return null\n const normalized = value\n .map(item => asString(item))\n .filter((item): item is string => item !== null)\n return normalized.length === value.length ? normalized : null\n}\n\nconst normalizeType = (value: unknown): CustomSlide['type'] | null => {\n const raw = asString(value)?.trim().toLowerCase()\n if (!raw) return null\n if (raw === 'agenda') return 'contents'\n if (raw === 'section') return 'transition'\n if (raw === 'ending') return 'end'\n if (\n raw === 'cover' ||\n raw === 'contents' ||\n raw === 'transition' ||\n raw === 'content' ||\n raw === 'end'\n ) {\n return raw\n }\n return null\n}\n\nconst normalizeContentItems = (value: unknown): BackendContentItem[] | null => {\n if (!Array.isArray(value)) return null\n const normalized: BackendContentItem[] = []\n for (const item of value) {\n if (!isRecord(item)) return null\n const title = asString(item.title)\n const text = asString(item.text)\n if (title == null || text == null) return null\n normalized.push({ title, text })\n }\n return normalized\n}\n\nconst normalizeSlide = (value: unknown): CustomSlide | null => {\n if (!isRecord(value)) return null\n const type = normalizeType(value.type)\n if (!type) return null\n\n const rawData = isRecord(value.data) ? value.data : {}\n\n if (type === 'cover') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'contents') {\n const items = asStringArray(rawData.items)\n if (!items) return null\n return { type, data: { items } }\n }\n\n if (type === 'transition') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'content') {\n const title = asString(rawData.title)\n const items = normalizeContentItems(rawData.items)\n if (title == null || !items) return null\n return { type, data: { title, items } }\n }\n\n return { type }\n}\n\nconst parseNdJsonSlides = (raw: string): unknown[] =>\n raw\n .split(/\\r?\\n/)\n .map(line => line.trim())\n .filter(Boolean)\n .map(line => JSON.parse(line) as unknown)\n\nconst parseStructuredSlides = (raw: string): unknown[] | null => {\n const trimmed = raw.trim()\n if (!trimmed) return []\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return null\n\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed) as unknown\n } catch {\n return null\n }\n if (Array.isArray(parsed)) return parsed\n if (!isRecord(parsed)) return null\n if (Array.isArray(parsed.slides)) return parsed.slides\n if ('type' in parsed) return [parsed]\n return null\n}\n\nexport const parseCustomContent = (raw: string): CustomSlide[] => {\n const candidates = parseStructuredSlides(raw) ?? parseNdJsonSlides(raw)\n const slides = candidates\n .map(item => normalizeSlide(item))\n .filter((item): item is CustomSlide => item !== null)\n\n if (slides.length !== candidates.length) {\n throw new Error('Invalid custom content format')\n }\n return slides\n}\n","import type { TemplateJsonElement } from '../types'\n\nexport const updateHtmlContent = (html: string, text: string) => {\n if (typeof DOMParser === 'undefined') {\n return `<p>${text}</p>`\n }\n const parser = new DOMParser()\n const doc = parser.parseFromString(html, 'text/html')\n const spans = Array.from(doc.querySelectorAll('span'))\n if (spans.length > 0) {\n spans.forEach((span, index) => {\n span.textContent = index === 0 ? text : ''\n })\n } else {\n const paragraph = doc.querySelector('p')\n if (paragraph) {\n paragraph.textContent = text\n } else {\n doc.body.textContent = text\n }\n }\n return doc.body.innerHTML\n}\n\nexport const setElementText = (element: TemplateJsonElement, text: string) => {\n if (element.type !== 'text') return\n element.content = updateHtmlContent(element.content, text)\n}\n","import type {\n BackendContentData,\n BackendContentsData,\n BackendCoverData,\n BackendTransitionData,\n TemplateJsonSlide\n} from '../types'\nimport { setElementText, updateHtmlContent } from './html'\n\nfunction setShapeTextByType (\n slide: TemplateJsonSlide,\n textType: string,\n text: string\n): boolean {\n const shape = slide.elements.find((element) => {\n if (element.type !== 'shape') return false\n const maybeShape = element as unknown as {\n text?: { type?: string; content?: string }\n }\n return maybeShape.text?.type === textType\n })\n\n if (!shape) return false\n\n const shapeWithText = shape as unknown as {\n text?: { type?: string; content?: string }\n }\n if (!shapeWithText.text || typeof shapeWithText.text.content !== 'string') {\n return false\n }\n\n shapeWithText.text.content = updateHtmlContent(shapeWithText.text.content, text)\n return true\n}\n\nexport const applyCoverData = (slide: TemplateJsonSlide, data: BackendCoverData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n}\n\nexport const applyContentsData = (\n slide: TemplateJsonSlide,\n data: BackendContentsData\n) => {\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n items.forEach((element, index) => {\n const text = data.items[index]\n if (text) setElementText(element, text)\n })\n}\n\nexport const applyTransitionData = (\n slide: TemplateJsonSlide,\n data: BackendTransitionData,\n sectionIndex: number\n) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n const partNumber = slide.elements.find(\n element => element.type === 'text' && element.textType === 'partNumber'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n const formattedSectionIndex = `${sectionIndex}`.padStart(2, '0')\n if (partNumber) {\n setElementText(partNumber, formattedSectionIndex)\n } else {\n setShapeTextByType(slide, 'partNumber', formattedSectionIndex)\n }\n}\n\nexport const applyContentData = (slide: TemplateJsonSlide, data: BackendContentData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n if (title) setElementText(title, data.title)\n\n const itemTitles = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'itemTitle'\n )\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n\n data.items.forEach((item, index) => {\n const titleEl = itemTitles[index]\n const textEl = items[index]\n if (titleEl) setElementText(titleEl, item.title)\n if (textEl) setElementText(textEl, item.text)\n })\n}\n","import type { CustomSlide, TemplateJson, TemplateJsonSlide } from '../types'\nimport {\n applyContentData,\n applyContentsData,\n applyCoverData,\n applyTransitionData\n} from './slide-appliers'\n\nconst cloneSlide = (slide: TemplateJsonSlide): TemplateJsonSlide =>\n JSON.parse(JSON.stringify(slide)) as TemplateJsonSlide\n\nfunction normalizeLabel (value: string): string {\n return value\n .replace(/\\s+/g, ' ')\n .replace(/[,。、“”‘’:;!?【】()《》〈〉·,.:;!?()[\\]{}\"'`~\\-_/\\\\]/g, '')\n .trim()\n .toLowerCase()\n}\n\nfunction resolveTransitionIndex (\n customSlides: CustomSlide[],\n currentSlideIndex: number,\n transitionTitle: string,\n fallbackIndex: number\n): number {\n const normalizedTitle = normalizeLabel(transitionTitle)\n if (!normalizedTitle) return fallbackIndex\n\n const contentsItems = customSlides\n .slice(0, currentSlideIndex + 1)\n .filter((slide): slide is Extract<CustomSlide, { type: 'contents' }> => slide.type === 'contents')\n .flatMap(slide => slide.data.items)\n\n for (let index = 0; index < contentsItems.length; index += 1) {\n const normalizedItem = normalizeLabel(contentsItems[index])\n if (!normalizedItem) continue\n if (\n normalizedItem === normalizedTitle ||\n normalizedItem.includes(normalizedTitle) ||\n normalizedTitle.includes(normalizedItem)\n ) {\n return index + 1\n }\n }\n\n return fallbackIndex\n}\n\nexport const applyCustomContentToTemplate = (\n template: TemplateJson,\n CustomSlides: CustomSlide[]\n): TemplateJson => {\n const grouped = template.slides.reduce<Record<string, TemplateJsonSlide[]>>(\n (acc, slide) => {\n const key = slide.type || 'default'\n if (!acc[key]) acc[key] = []\n acc[key].push(slide)\n return acc\n },\n {}\n )\n\n const usage = new Map<string, number>()\n const getTextTypeCount = (slide: TemplateJsonSlide, textType: string) =>\n slide.elements.filter(\n element => element.type === 'text' && element.textType === textType\n ).length\n\n const getContentCapacity = (slide: TemplateJsonSlide) => {\n const titleSlots = getTextTypeCount(slide, 'itemTitle')\n const itemSlots = getTextTypeCount(slide, 'item')\n return Math.min(titleSlots, itemSlots)\n }\n\n const pickFromPool = (key: string, pool: TemplateJsonSlide[]) => {\n const index = usage.get(key) ?? 0\n usage.set(key, index + 1)\n return cloneSlide(pool[index % pool.length])\n }\n\n const pickSlide = (type: string, desiredCount?: number) => {\n const pool = grouped[type] || grouped.default || template.slides\n if (desiredCount == null || pool.length === 1) {\n return pickFromPool(type, pool)\n }\n\n const scored = pool.map(slide => {\n const capacity =\n type === 'content'\n ? getContentCapacity(slide)\n : getTextTypeCount(slide, 'item')\n return { slide, capacity }\n })\n const eligible = scored.filter(item => item.capacity >= desiredCount)\n if (eligible.length > 0) {\n const minCapacity = Math.min(...eligible.map(item => item.capacity))\n const best = eligible\n .filter(item => item.capacity === minCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, best)\n }\n const maxCapacity = Math.max(...scored.map(item => item.capacity))\n const fallback = scored\n .filter(item => item.capacity === maxCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, fallback)\n }\n\n let transitionIndex = 0\n const slides = CustomSlides.map((item, index) => {\n const desiredCount =\n item.type === 'contents'\n ? item.data.items.length\n : item.type === 'content'\n ? item.data.items.length\n : undefined\n const slide = pickSlide(item.type, desiredCount)\n if (item.type === 'cover') {\n applyCoverData(slide, item.data)\n } else if (item.type === 'contents') {\n applyContentsData(slide, item.data)\n } else if (item.type === 'transition') {\n transitionIndex += 1\n const partNumber = resolveTransitionIndex(\n CustomSlides,\n index,\n item.data.title,\n transitionIndex\n )\n applyTransitionData(slide, item.data, partNumber)\n } else if (item.type === 'content') {\n applyContentData(slide, item.data)\n }\n return slide\n })\n\n return {\n ...template,\n slides\n }\n}\n","import { parseDocument } from 'json2pptx-schema'\nimport type {\n Deck,\n PptxCustomThemeInput,\n Slide,\n SlideElement,\n ThemeLogoPosition,\n ThemeScope,\n ThemeScopeKey\n} from '../types'\nimport { parseColorToRgb } from './color-utils'\nimport { applyTheme2Json } from './theme-applier'\n\nconst FALLBACK_SLIDE_WIDTH = 1000\nconst FALLBACK_SLIDE_HEIGHT = 562.5\nconst LOGO_MARGIN_X = 24\nconst LOGO_MARGIN_Y = 18\nconst LOGO_MAX_WIDTH_RATIO = 0.34\nconst LOGO_MAX_HEIGHT_RATIO = 0.16\nconst DEFAULT_LOGO_ASPECT_RATIO = 3.2\n\nfunction mapSlideTypeToScopeKey (type?: string): ThemeScopeKey | null {\n const normalized = type?.trim().toLowerCase()\n if (!normalized) return null\n\n if (normalized === 'cover') return 'cover'\n if (normalized === 'contents' || normalized === 'agenda') return 'contents'\n if (normalized === 'transition' || normalized === 'section') return 'transition'\n if (normalized === 'content') return 'content'\n if (normalized === 'end' || normalized === 'ending') return 'end'\n\n return null\n}\n\nfunction isSlideInScope (slide: Slide, scope: ThemeScope): boolean {\n const key = mapSlideTypeToScopeKey(slide.type)\n if (!key) return false\n return Boolean(scope[key])\n}\n\nfunction createElementId (prefix: string, slideIndex: number): string {\n const random = Math.random().toString(36).slice(2, 10)\n return `${prefix}-${slideIndex}-${random}`\n}\n\nfunction toHalfOpacityColor (value: string): string {\n const rgb = parseColorToRgb(value)\n if (!rgb) return value\n return `rgba(${rgb.r},${rgb.g},${rgb.b},0.5)`\n}\n\nfunction buildBackgroundElement (\n src: string,\n slideWidth: number,\n slideHeight: number,\n slideIndex: number\n): SlideElement {\n return {\n type: 'image',\n id: createElementId('background', slideIndex),\n src,\n width: slideWidth,\n height: slideHeight,\n left: 0,\n top: 0,\n fixedRatio: true,\n rotate: 0,\n imageType: 'background',\n filters: {\n opacity: '100%'\n }\n }\n}\n\nfunction buildLogoElement (\n src: string,\n slideWidth: number,\n slideHeight: number,\n position: ThemeLogoPosition,\n slideIndex: number,\n logoWidth?: number,\n logoHeight?: number\n): SlideElement {\n const aspectRatio = resolveLogoAspectRatio(logoWidth, logoHeight)\n const maxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO\n const maxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO\n let width = maxWidth\n let height = width / aspectRatio\n if (height > maxHeight) {\n height = maxHeight\n width = height * aspectRatio\n }\n const left =\n position === 'left'\n ? LOGO_MARGIN_X\n : Math.max(LOGO_MARGIN_X, slideWidth - width - LOGO_MARGIN_X)\n\n return {\n type: 'image',\n id: createElementId('logo', slideIndex),\n src,\n width,\n height,\n left,\n top: LOGO_MARGIN_Y,\n fixedRatio: true,\n rotate: 0,\n imageType: 'logo'\n }\n}\n\nfunction resolveLogoAspectRatio (\n width?: number,\n height?: number\n): number {\n if (\n typeof width === 'number' &&\n typeof height === 'number' &&\n width > 0 &&\n height > 0\n ) {\n return width / height\n }\n return DEFAULT_LOGO_ASPECT_RATIO\n}\n\nfunction replaceScopedMedia (deck: Deck, input: PptxCustomThemeInput): Deck {\n if (!deck.slides?.length) return deck\n\n const slideWidth = deck.width ?? FALLBACK_SLIDE_WIDTH\n const slideHeight = deck.height ?? FALLBACK_SLIDE_HEIGHT\n const backgroundInput = input.backgroundImage\n const logoInput = input.logoImage\n const shouldClearBackground = Boolean(input.clearBackgroundImage)\n const shouldClearLogo = Boolean(input.clearLogoImage || shouldClearBackground)\n\n if (\n !backgroundInput?.src &&\n !logoInput?.src &&\n !shouldClearBackground &&\n !shouldClearLogo\n ) {\n return deck\n }\n\n const slides = deck.slides.map((slide, slideIndex) => {\n let nextElements = slide.elements ? [...slide.elements] : []\n let nextBackground = slide.background\n let changed = false\n\n if (shouldClearBackground) {\n const before = nextElements.length\n nextElements = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'background')\n )\n if (nextElements.length !== before) {\n changed = true\n if (input.backgroundColor) {\n nextBackground = {\n ...(nextBackground ?? {}),\n type: 'solid',\n color: input.backgroundColor\n }\n }\n }\n }\n\n if (shouldClearLogo) {\n const before = nextElements.length\n nextElements = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'logo')\n )\n if (nextElements.length !== before) {\n changed = true\n }\n }\n\n if (backgroundInput?.src && isSlideInScope(slide, backgroundInput.scope)) {\n const withoutBackground = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'background')\n )\n nextElements = [\n buildBackgroundElement(\n backgroundInput.src,\n slideWidth,\n slideHeight,\n slideIndex\n ),\n ...withoutBackground\n ]\n changed = true\n\n if (input.backgroundColor) {\n nextBackground = {\n ...(nextBackground ?? {}),\n type: 'solid',\n color: toHalfOpacityColor(input.backgroundColor)\n }\n }\n }\n\n if (logoInput?.src && isSlideInScope(slide, logoInput.scope)) {\n const withoutLogo = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'logo')\n )\n nextElements = [\n ...withoutLogo,\n buildLogoElement(\n logoInput.src,\n slideWidth,\n slideHeight,\n logoInput.position,\n slideIndex,\n logoInput.width,\n logoInput.height\n )\n ]\n changed = true\n }\n\n if (!changed && nextBackground === slide.background) return slide\n\n return {\n ...slide,\n ...(changed ? { elements: nextElements } : {}),\n ...(nextBackground ? { background: nextBackground } : {})\n }\n })\n\n return { ...deck, slides }\n}\n\nexport function applyCustomTheme (\n deck: Deck,\n input: PptxCustomThemeInput\n): Deck {\n const normalizedDeck = parseDocument(deck) as unknown as Deck\n const withColors = applyTheme2Json(normalizedDeck, input)\n const withMedia = replaceScopedMedia(withColors, input)\n return parseDocument(withMedia) as unknown as Deck\n}\n\nexport { applyTheme2Json }\n","import type { ColorMapping, RGB } from './types'\n\nexport function normalizeHexColor (value: string): string | null {\n const raw = value.trim()\n const withHash = raw.startsWith('#') ? raw.slice(1) : raw\n if (withHash.length !== 3 && withHash.length !== 6) return null\n if (!/^[0-9a-fA-F]+$/.test(withHash)) return null\n const expanded =\n withHash.length === 3\n ? withHash\n .split('')\n .map((char) => char + char)\n .join('')\n : withHash\n return `#${expanded.toUpperCase()}`\n}\n\nexport function parseColorToRgb (\n value: string\n): (RGB & { alpha?: number }) | null {\n const hex = normalizeHexColor(value)\n if (hex) {\n const raw = hex.slice(1)\n const r = Number.parseInt(raw.slice(0, 2), 16)\n const g = Number.parseInt(raw.slice(2, 4), 16)\n const b = Number.parseInt(raw.slice(4, 6), 16)\n return { r, g, b }\n }\n\n const match = value.match(\n /rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)/i\n )\n if (!match) return null\n const r = Math.round(Number(match[1]))\n const g = Math.round(Number(match[2]))\n const b = Math.round(Number(match[3]))\n const alpha = match[4] !== undefined ? Number(match[4]) : undefined\n return {\n r,\n g,\n b,\n ...(Number.isFinite(alpha) ? { alpha } : {})\n }\n}\n\nexport function normalizeThemeColor (value: string): string | null {\n const hex = normalizeHexColor(value)\n if (hex) return hex\n const parsed = parseColorToRgb(value)\n if (!parsed) return null\n if (parsed.alpha !== undefined) {\n return `rgba(${parsed.r},${parsed.g},${parsed.b},${parsed.alpha})`\n }\n return `rgb(${parsed.r},${parsed.g},${parsed.b})`\n}\n\nexport function isPureColorString (value: string): boolean {\n const trimmed = value.trim()\n if (!trimmed) return false\n if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(trimmed)) return true\n return /^rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)$/i.test(\n trimmed\n )\n}\n\nfunction normalizeColorKey (value?: string): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = parseColorToRgb(trimmed)\n if (parsed) {\n return `${parsed.r},${parsed.g},${parsed.b},${parsed.alpha ?? 'none'}`\n }\n const hex = normalizeHexColor(trimmed)\n if (hex) return hex\n return trimmed.toLowerCase()\n}\n\nexport function colorsEqual (a: string, b: string): boolean {\n const aKey = normalizeColorKey(a)\n const bKey = normalizeColorKey(b)\n if (!aKey || !bKey) return false\n return aKey === bKey\n}\n\nexport function isWhiteColor (value?: string): boolean {\n const key = normalizeColorKey(value)\n if (!key) return false\n return (\n key === '#FFFFFF' ||\n key === '255,255,255,none' ||\n key === '255,255,255,1'\n )\n}\n\nexport function rgbToString (rgb: RGB): string {\n return `rgb(${rgb.r},${rgb.g},${rgb.b})`\n}\n\nexport function findMappingForColor (\n value: string,\n mappings: ColorMapping[]\n): ColorMapping | undefined {\n const parsed = parseColorToRgb(value)\n if (!parsed) return undefined\n return mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n}\n","import { normalizeHexColor, parseColorToRgb } from './color-utils'\nimport type { ColorMapping } from './types'\n\nexport function buildColorMappings (\n previous: string[],\n next: string[]\n): ColorMapping[] {\n const mappings: ColorMapping[] = []\n const length = Math.min(previous.length, next.length)\n for (let i = 0; i < length; i += 1) {\n const fromParsed = parseColorToRgb(previous[i])\n const toParsed = parseColorToRgb(next[i])\n if (!fromParsed || !toParsed) continue\n const toHex = normalizeHexColor(next[i]) ?? undefined\n mappings.push({\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n })\n }\n return mappings\n}\n\nexport function buildSingleMapping (\n from?: string,\n to?: string\n): ColorMapping | null {\n if (!from || !to) return null\n const fromParsed = parseColorToRgb(from)\n const toParsed = parseColorToRgb(to)\n if (!fromParsed || !toParsed) return null\n const toHex = normalizeHexColor(to) ?? undefined\n return {\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n }\n}\n","import type { Slide, SlideElement } from '../types'\nimport {\n findMappingForColor,\n isPureColorString,\n normalizeThemeColor,\n parseColorToRgb,\n rgbToString\n} from './color-utils'\nimport type { ColorMapping } from './types'\n\nfunction applyFontColorToHtml (value: string, fontColor: string): string {\n if (!value || !fontColor) return value\n const normalized = normalizeThemeColor(fontColor) ?? fontColor\n const hasStyleColor = /\\bcolor\\s*:/i.test(value)\n if (hasStyleColor) {\n return value.replace(/color\\s*:\\s*([^;\"']+)/gi, () => `color: ${normalized}`)\n }\n return value.replace(\n /(<[^>]+style\\s*=\\s*[\"'])([^\"']*)([\"'])/gi,\n (_match, start, styles, end) => {\n if (/\\bcolor\\s*:/i.test(styles)) return _match\n const nextStyles = styles.trim()\n ? `${styles.trim()}; color: ${normalized}`\n : `color: ${normalized}`\n return `${start}${nextStyles}${end}`\n }\n )\n}\n\nfunction replaceColorValue (value: string, mappings: ColorMapping[]): string {\n const mapping = findMappingForColor(value, mappings)\n if (!mapping) return value\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n if (parsed.alpha !== undefined) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceRgbaString (value: string, mappings: ColorMapping[]): string {\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n const mapping = mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n if (!mapping) return value\n if (parsed.alpha !== undefined || value.toLowerCase().startsWith('rgba')) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha ?? 1})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceColorsInText (value: string, mappings: ColorMapping[]): string {\n let next = value\n next = next.replace(/#([0-9a-f]{3}|[0-9a-f]{6})/gi, (match) => {\n const mapping = findMappingForColor(match, mappings)\n if (!mapping) return match\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n })\n next = next.replace(/rgba?\\([^)]*\\)/gi, (match) =>\n replaceRgbaString(match, mappings)\n )\n return next\n}\n\nfunction replaceColorsDeep (value: unknown, mappings: ColorMapping[]): unknown {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n const pureColor = isPureColorString(trimmed)\n if (pureColor) {\n const replaced = replaceColorValue(trimmed, mappings)\n return value === trimmed ? replaced : value.replace(trimmed, replaced)\n }\n return replaceColorsInText(value, mappings)\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => replaceColorsDeep(item, mappings))\n }\n\n if (value && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n const next: Record<string, unknown> = {}\n for (const [key, item] of entries) {\n next[key] = replaceColorsDeep(item, mappings)\n }\n return next\n }\n\n return value\n}\n\nfunction replaceTextElementColors (\n element: SlideElement,\n fontMappings: ColorMapping[],\n fontColor: string\n): SlideElement {\n const next = replaceColorsDeep(element, fontMappings) as SlideElement\n const normalizedFontColor = normalizeThemeColor(fontColor) ?? fontColor\n const withDefault =\n normalizedFontColor && 'defaultColor' in next\n ? { ...next, defaultColor: normalizedFontColor }\n : next\n if (!('content' in withDefault) || typeof withDefault.content !== 'string') {\n return withDefault\n }\n return {\n ...withDefault,\n content: applyFontColorToHtml(withDefault.content, normalizedFontColor)\n }\n}\n\nexport function replaceSlideColors (\n slide: Slide,\n themeMappings: ColorMapping[],\n fontMappings: ColorMapping[],\n fontColor: string\n): Slide {\n const { elements, ...rest } = slide\n const nextSlide = replaceColorsDeep(rest, themeMappings) as Slide\n if (!elements) return nextSlide\n\n const nextElements: SlideElement[] = elements.map((element) => {\n if (element && typeof element === 'object' && element.type === 'text') {\n return replaceTextElementColors(element, fontMappings, fontColor)\n }\n return replaceColorsDeep(element, themeMappings) as SlideElement\n })\n\n return { ...nextSlide, elements: nextElements }\n}\n","import type { Deck, PptxCustomThemeInput } from '../types'\nimport { colorsEqual, isWhiteColor } from './color-utils'\nimport { buildColorMappings, buildSingleMapping } from './mappings'\nimport { replaceSlideColors } from './replacers'\n\nexport function applyTheme2Json (deck: Deck, update: PptxCustomThemeInput): Deck {\n const previousTheme = deck.theme ?? {}\n const themeColors = update.themeColors.slice(0, 6)\n const themeMappings = buildColorMappings(\n previousTheme.themeColors ?? [],\n themeColors\n )\n const fontMapping = buildSingleMapping(\n previousTheme.fontColor,\n update.fontColor\n )\n const fontMappings = fontMapping ? [fontMapping] : []\n\n const nextBackground = update.backgroundColor ?? previousTheme.backgroundColor\n const prevBackground = previousTheme.backgroundColor\n const slides = deck.slides?.map((slide) => {\n const nextSlide = replaceSlideColors(\n slide,\n themeMappings,\n fontMappings,\n update.fontColor\n )\n if (!nextBackground) return nextSlide\n const currentColor = nextSlide.background?.color\n const shouldUpdate =\n !currentColor ||\n (prevBackground && colorsEqual(currentColor, prevBackground)) ||\n (!prevBackground && isWhiteColor(currentColor))\n if (!shouldUpdate) return nextSlide\n return {\n ...nextSlide,\n background: {\n ...(nextSlide.background ?? {}),\n type: nextSlide.background?.type ?? 'solid',\n color: nextBackground\n }\n }\n })\n\n return {\n ...deck,\n theme: {\n ...previousTheme,\n themeColors,\n fontColor: update.fontColor,\n backgroundColor: update.backgroundColor ?? previousTheme.backgroundColor\n },\n slides\n }\n}\n"],"mappings":"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","names":["import_json2pptx_schema","r","g","b","FALLBACK_SLIDE_WIDTH","FALLBACK_SLIDE_HEIGHT","LOGO_MARGIN_X","LOGO_MARGIN_Y","LOGO_MAX_WIDTH_RATIO","LOGO_MAX_HEIGHT_RATIO"]}
package/dist/index.mjs CHANGED
@@ -277,11 +277,63 @@ var applyCustomContentToTemplate = (template, CustomSlides) => {
277
277
  };
278
278
 
279
279
  // src/custom-content/index.ts
280
+ var FALLBACK_SLIDE_WIDTH = 1e3;
281
+ var FALLBACK_SLIDE_HEIGHT = 562.5;
282
+ var LOGO_MARGIN_X = 24;
283
+ var LOGO_MARGIN_Y = 18;
284
+ var LOGO_MAX_WIDTH_RATIO = 0.34;
285
+ var LOGO_MAX_HEIGHT_RATIO = 0.16;
286
+ function isLogoImageElement(element) {
287
+ return element.type === "image" && element.imageType === "logo";
288
+ }
289
+ function fitSize(width, height, maxWidth, maxHeight) {
290
+ const safeWidth = width > 0 ? width : maxWidth;
291
+ const safeHeight = height > 0 ? height : maxHeight;
292
+ const scale = Math.min(maxWidth / safeWidth, maxHeight / safeHeight);
293
+ return {
294
+ width: safeWidth * scale,
295
+ height: safeHeight * scale
296
+ };
297
+ }
298
+ function normalizeLogoElements(deck) {
299
+ const slideWidth = deck.width || FALLBACK_SLIDE_WIDTH;
300
+ const slideHeight = deck.height || FALLBACK_SLIDE_HEIGHT;
301
+ const logoMaxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO;
302
+ const logoMaxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO;
303
+ const slides = deck.slides.map((slide) => {
304
+ let changed = false;
305
+ const elements = slide.elements.map((element) => {
306
+ if (!isLogoImageElement(element)) return element;
307
+ const size = fitSize(
308
+ element.width ?? logoMaxWidth,
309
+ element.height ?? logoMaxHeight,
310
+ logoMaxWidth,
311
+ logoMaxHeight
312
+ );
313
+ const isLeft = (element.left ?? 0) < slideWidth / 2;
314
+ const left = isLeft ? LOGO_MARGIN_X : Math.max(LOGO_MARGIN_X, slideWidth - size.width - LOGO_MARGIN_X);
315
+ const top = LOGO_MARGIN_Y;
316
+ const { clip: _clip, ...rest } = element;
317
+ changed = true;
318
+ return {
319
+ ...rest,
320
+ left,
321
+ top,
322
+ width: size.width,
323
+ height: size.height,
324
+ fixedRatio: true
325
+ };
326
+ });
327
+ return changed ? { ...slide, elements } : slide;
328
+ });
329
+ return { ...deck, slides };
330
+ }
280
331
  function applyCustomContent(template, input) {
281
332
  const normalizedTemplate = parseDocument(template);
282
333
  const CustomSlides = typeof input === "string" ? parseCustomContent(input) : input;
283
334
  const updated = applyCustomContentToTemplate(normalizedTemplate, CustomSlides);
284
- return parseDocument(updated);
335
+ const withNormalizedLogo = normalizeLogoElements(updated);
336
+ return parseDocument(withNormalizedLogo);
285
337
  }
286
338
 
287
339
  // src/custom-theme/index.ts
@@ -550,10 +602,178 @@ function applyTheme2Json(deck, update) {
550
602
  }
551
603
 
552
604
  // src/custom-theme/index.ts
605
+ var FALLBACK_SLIDE_WIDTH2 = 1e3;
606
+ var FALLBACK_SLIDE_HEIGHT2 = 562.5;
607
+ var LOGO_MARGIN_X2 = 24;
608
+ var LOGO_MARGIN_Y2 = 18;
609
+ var LOGO_MAX_WIDTH_RATIO2 = 0.34;
610
+ var LOGO_MAX_HEIGHT_RATIO2 = 0.16;
611
+ var DEFAULT_LOGO_ASPECT_RATIO = 3.2;
612
+ function mapSlideTypeToScopeKey(type) {
613
+ const normalized = type?.trim().toLowerCase();
614
+ if (!normalized) return null;
615
+ if (normalized === "cover") return "cover";
616
+ if (normalized === "contents" || normalized === "agenda") return "contents";
617
+ if (normalized === "transition" || normalized === "section") return "transition";
618
+ if (normalized === "content") return "content";
619
+ if (normalized === "end" || normalized === "ending") return "end";
620
+ return null;
621
+ }
622
+ function isSlideInScope(slide, scope) {
623
+ const key = mapSlideTypeToScopeKey(slide.type);
624
+ if (!key) return false;
625
+ return Boolean(scope[key]);
626
+ }
627
+ function createElementId(prefix, slideIndex) {
628
+ const random = Math.random().toString(36).slice(2, 10);
629
+ return `${prefix}-${slideIndex}-${random}`;
630
+ }
631
+ function toHalfOpacityColor(value) {
632
+ const rgb = parseColorToRgb(value);
633
+ if (!rgb) return value;
634
+ return `rgba(${rgb.r},${rgb.g},${rgb.b},0.5)`;
635
+ }
636
+ function buildBackgroundElement(src, slideWidth, slideHeight, slideIndex) {
637
+ return {
638
+ type: "image",
639
+ id: createElementId("background", slideIndex),
640
+ src,
641
+ width: slideWidth,
642
+ height: slideHeight,
643
+ left: 0,
644
+ top: 0,
645
+ fixedRatio: true,
646
+ rotate: 0,
647
+ imageType: "background",
648
+ filters: {
649
+ opacity: "100%"
650
+ }
651
+ };
652
+ }
653
+ function buildLogoElement(src, slideWidth, slideHeight, position, slideIndex, logoWidth, logoHeight) {
654
+ const aspectRatio = resolveLogoAspectRatio(logoWidth, logoHeight);
655
+ const maxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO2;
656
+ const maxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO2;
657
+ let width = maxWidth;
658
+ let height = width / aspectRatio;
659
+ if (height > maxHeight) {
660
+ height = maxHeight;
661
+ width = height * aspectRatio;
662
+ }
663
+ const left = position === "left" ? LOGO_MARGIN_X2 : Math.max(LOGO_MARGIN_X2, slideWidth - width - LOGO_MARGIN_X2);
664
+ return {
665
+ type: "image",
666
+ id: createElementId("logo", slideIndex),
667
+ src,
668
+ width,
669
+ height,
670
+ left,
671
+ top: LOGO_MARGIN_Y2,
672
+ fixedRatio: true,
673
+ rotate: 0,
674
+ imageType: "logo"
675
+ };
676
+ }
677
+ function resolveLogoAspectRatio(width, height) {
678
+ if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
679
+ return width / height;
680
+ }
681
+ return DEFAULT_LOGO_ASPECT_RATIO;
682
+ }
683
+ function replaceScopedMedia(deck, input) {
684
+ if (!deck.slides?.length) return deck;
685
+ const slideWidth = deck.width ?? FALLBACK_SLIDE_WIDTH2;
686
+ const slideHeight = deck.height ?? FALLBACK_SLIDE_HEIGHT2;
687
+ const backgroundInput = input.backgroundImage;
688
+ const logoInput = input.logoImage;
689
+ const shouldClearBackground = Boolean(input.clearBackgroundImage);
690
+ const shouldClearLogo = Boolean(input.clearLogoImage || shouldClearBackground);
691
+ if (!backgroundInput?.src && !logoInput?.src && !shouldClearBackground && !shouldClearLogo) {
692
+ return deck;
693
+ }
694
+ const slides = deck.slides.map((slide, slideIndex) => {
695
+ let nextElements = slide.elements ? [...slide.elements] : [];
696
+ let nextBackground = slide.background;
697
+ let changed = false;
698
+ if (shouldClearBackground) {
699
+ const before = nextElements.length;
700
+ nextElements = nextElements.filter(
701
+ (element) => !(element.type === "image" && element.imageType === "background")
702
+ );
703
+ if (nextElements.length !== before) {
704
+ changed = true;
705
+ if (input.backgroundColor) {
706
+ nextBackground = {
707
+ ...nextBackground ?? {},
708
+ type: "solid",
709
+ color: input.backgroundColor
710
+ };
711
+ }
712
+ }
713
+ }
714
+ if (shouldClearLogo) {
715
+ const before = nextElements.length;
716
+ nextElements = nextElements.filter(
717
+ (element) => !(element.type === "image" && element.imageType === "logo")
718
+ );
719
+ if (nextElements.length !== before) {
720
+ changed = true;
721
+ }
722
+ }
723
+ if (backgroundInput?.src && isSlideInScope(slide, backgroundInput.scope)) {
724
+ const withoutBackground = nextElements.filter(
725
+ (element) => !(element.type === "image" && element.imageType === "background")
726
+ );
727
+ nextElements = [
728
+ buildBackgroundElement(
729
+ backgroundInput.src,
730
+ slideWidth,
731
+ slideHeight,
732
+ slideIndex
733
+ ),
734
+ ...withoutBackground
735
+ ];
736
+ changed = true;
737
+ if (input.backgroundColor) {
738
+ nextBackground = {
739
+ ...nextBackground ?? {},
740
+ type: "solid",
741
+ color: toHalfOpacityColor(input.backgroundColor)
742
+ };
743
+ }
744
+ }
745
+ if (logoInput?.src && isSlideInScope(slide, logoInput.scope)) {
746
+ const withoutLogo = nextElements.filter(
747
+ (element) => !(element.type === "image" && element.imageType === "logo")
748
+ );
749
+ nextElements = [
750
+ ...withoutLogo,
751
+ buildLogoElement(
752
+ logoInput.src,
753
+ slideWidth,
754
+ slideHeight,
755
+ logoInput.position,
756
+ slideIndex,
757
+ logoInput.width,
758
+ logoInput.height
759
+ )
760
+ ];
761
+ changed = true;
762
+ }
763
+ if (!changed && nextBackground === slide.background) return slide;
764
+ return {
765
+ ...slide,
766
+ ...changed ? { elements: nextElements } : {},
767
+ ...nextBackground ? { background: nextBackground } : {}
768
+ };
769
+ });
770
+ return { ...deck, slides };
771
+ }
553
772
  function applyCustomTheme(deck, input) {
554
773
  const normalizedDeck = parseDocument2(deck);
555
- const updated = applyTheme2Json(normalizedDeck, input);
556
- return parseDocument2(updated);
774
+ const withColors = applyTheme2Json(normalizedDeck, input);
775
+ const withMedia = replaceScopedMedia(withColors, input);
776
+ return parseDocument2(withMedia);
557
777
  }
558
778
  export {
559
779
  applyCustomContent,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/custom-content/index.ts","../src/custom-content/parser.ts","../src/custom-content/html.ts","../src/custom-content/slide-appliers.ts","../src/custom-content/template-builder.ts","../src/custom-theme/index.ts","../src/custom-theme/color-utils.ts","../src/custom-theme/mappings.ts","../src/custom-theme/replacers.ts","../src/custom-theme/theme-applier.ts"],"sourcesContent":["import { parseDocument } from 'json2pptx-schema'\nimport type { PptxCustomContentInput, TemplateJson } from '../types'\nimport { parseCustomContent } from './parser'\nimport { applyCustomContentToTemplate } from './template-builder'\n\nexport function applyCustomContent (\n template: TemplateJson,\n input: PptxCustomContentInput\n): TemplateJson {\n const normalizedTemplate = parseDocument(template) as unknown as TemplateJson\n const CustomSlides = typeof input === 'string' ? parseCustomContent(input) : input\n const updated = applyCustomContentToTemplate(normalizedTemplate, CustomSlides)\n return parseDocument(updated) as unknown as TemplateJson\n}\n\nexport { parseCustomContent, applyCustomContentToTemplate }\n","import type { BackendContentItem, CustomSlide } from '../types'\n\ntype UnknownRecord = Record<string, unknown>\n\nconst isRecord = (value: unknown): value is UnknownRecord =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst asString = (value: unknown): string | null =>\n typeof value === 'string' ? value : null\n\nconst asStringArray = (value: unknown): string[] | null => {\n if (!Array.isArray(value)) return null\n const normalized = value\n .map(item => asString(item))\n .filter((item): item is string => item !== null)\n return normalized.length === value.length ? normalized : null\n}\n\nconst normalizeType = (value: unknown): CustomSlide['type'] | null => {\n const raw = asString(value)?.trim().toLowerCase()\n if (!raw) return null\n if (raw === 'agenda') return 'contents'\n if (raw === 'section') return 'transition'\n if (raw === 'ending') return 'end'\n if (\n raw === 'cover' ||\n raw === 'contents' ||\n raw === 'transition' ||\n raw === 'content' ||\n raw === 'end'\n ) {\n return raw\n }\n return null\n}\n\nconst normalizeContentItems = (value: unknown): BackendContentItem[] | null => {\n if (!Array.isArray(value)) return null\n const normalized: BackendContentItem[] = []\n for (const item of value) {\n if (!isRecord(item)) return null\n const title = asString(item.title)\n const text = asString(item.text)\n if (title == null || text == null) return null\n normalized.push({ title, text })\n }\n return normalized\n}\n\nconst normalizeSlide = (value: unknown): CustomSlide | null => {\n if (!isRecord(value)) return null\n const type = normalizeType(value.type)\n if (!type) return null\n\n const rawData = isRecord(value.data) ? value.data : {}\n\n if (type === 'cover') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'contents') {\n const items = asStringArray(rawData.items)\n if (!items) return null\n return { type, data: { items } }\n }\n\n if (type === 'transition') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'content') {\n const title = asString(rawData.title)\n const items = normalizeContentItems(rawData.items)\n if (title == null || !items) return null\n return { type, data: { title, items } }\n }\n\n return { type }\n}\n\nconst parseNdJsonSlides = (raw: string): unknown[] =>\n raw\n .split(/\\r?\\n/)\n .map(line => line.trim())\n .filter(Boolean)\n .map(line => JSON.parse(line) as unknown)\n\nconst parseStructuredSlides = (raw: string): unknown[] | null => {\n const trimmed = raw.trim()\n if (!trimmed) return []\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return null\n\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed) as unknown\n } catch {\n return null\n }\n if (Array.isArray(parsed)) return parsed\n if (!isRecord(parsed)) return null\n if (Array.isArray(parsed.slides)) return parsed.slides\n if ('type' in parsed) return [parsed]\n return null\n}\n\nexport const parseCustomContent = (raw: string): CustomSlide[] => {\n const candidates = parseStructuredSlides(raw) ?? parseNdJsonSlides(raw)\n const slides = candidates\n .map(item => normalizeSlide(item))\n .filter((item): item is CustomSlide => item !== null)\n\n if (slides.length !== candidates.length) {\n throw new Error('Invalid custom content format')\n }\n return slides\n}\n","import type { TemplateJsonElement } from '../types'\n\nexport const updateHtmlContent = (html: string, text: string) => {\n if (typeof DOMParser === 'undefined') {\n return `<p>${text}</p>`\n }\n const parser = new DOMParser()\n const doc = parser.parseFromString(html, 'text/html')\n const spans = Array.from(doc.querySelectorAll('span'))\n if (spans.length > 0) {\n spans.forEach((span, index) => {\n span.textContent = index === 0 ? text : ''\n })\n } else {\n const paragraph = doc.querySelector('p')\n if (paragraph) {\n paragraph.textContent = text\n } else {\n doc.body.textContent = text\n }\n }\n return doc.body.innerHTML\n}\n\nexport const setElementText = (element: TemplateJsonElement, text: string) => {\n if (element.type !== 'text') return\n element.content = updateHtmlContent(element.content, text)\n}\n","import type {\n BackendContentData,\n BackendContentsData,\n BackendCoverData,\n BackendTransitionData,\n TemplateJsonSlide\n} from '../types'\nimport { setElementText, updateHtmlContent } from './html'\n\nfunction setShapeTextByType (\n slide: TemplateJsonSlide,\n textType: string,\n text: string\n): boolean {\n const shape = slide.elements.find((element) => {\n if (element.type !== 'shape') return false\n const maybeShape = element as unknown as {\n text?: { type?: string; content?: string }\n }\n return maybeShape.text?.type === textType\n })\n\n if (!shape) return false\n\n const shapeWithText = shape as unknown as {\n text?: { type?: string; content?: string }\n }\n if (!shapeWithText.text || typeof shapeWithText.text.content !== 'string') {\n return false\n }\n\n shapeWithText.text.content = updateHtmlContent(shapeWithText.text.content, text)\n return true\n}\n\nexport const applyCoverData = (slide: TemplateJsonSlide, data: BackendCoverData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n}\n\nexport const applyContentsData = (\n slide: TemplateJsonSlide,\n data: BackendContentsData\n) => {\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n items.forEach((element, index) => {\n const text = data.items[index]\n if (text) setElementText(element, text)\n })\n}\n\nexport const applyTransitionData = (\n slide: TemplateJsonSlide,\n data: BackendTransitionData,\n sectionIndex: number\n) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n const partNumber = slide.elements.find(\n element => element.type === 'text' && element.textType === 'partNumber'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n const formattedSectionIndex = `${sectionIndex}`.padStart(2, '0')\n if (partNumber) {\n setElementText(partNumber, formattedSectionIndex)\n } else {\n setShapeTextByType(slide, 'partNumber', formattedSectionIndex)\n }\n}\n\nexport const applyContentData = (slide: TemplateJsonSlide, data: BackendContentData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n if (title) setElementText(title, data.title)\n\n const itemTitles = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'itemTitle'\n )\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n\n data.items.forEach((item, index) => {\n const titleEl = itemTitles[index]\n const textEl = items[index]\n if (titleEl) setElementText(titleEl, item.title)\n if (textEl) setElementText(textEl, item.text)\n })\n}\n","import type { CustomSlide, TemplateJson, TemplateJsonSlide } from '../types'\nimport {\n applyContentData,\n applyContentsData,\n applyCoverData,\n applyTransitionData\n} from './slide-appliers'\n\nconst cloneSlide = (slide: TemplateJsonSlide): TemplateJsonSlide =>\n JSON.parse(JSON.stringify(slide)) as TemplateJsonSlide\n\nfunction normalizeLabel (value: string): string {\n return value\n .replace(/\\s+/g, ' ')\n .replace(/[,。、“”‘’:;!?【】()《》〈〉·,.:;!?()[\\]{}\"'`~\\-_/\\\\]/g, '')\n .trim()\n .toLowerCase()\n}\n\nfunction resolveTransitionIndex (\n customSlides: CustomSlide[],\n currentSlideIndex: number,\n transitionTitle: string,\n fallbackIndex: number\n): number {\n const normalizedTitle = normalizeLabel(transitionTitle)\n if (!normalizedTitle) return fallbackIndex\n\n const contentsItems = customSlides\n .slice(0, currentSlideIndex + 1)\n .filter((slide): slide is Extract<CustomSlide, { type: 'contents' }> => slide.type === 'contents')\n .flatMap(slide => slide.data.items)\n\n for (let index = 0; index < contentsItems.length; index += 1) {\n const normalizedItem = normalizeLabel(contentsItems[index])\n if (!normalizedItem) continue\n if (\n normalizedItem === normalizedTitle ||\n normalizedItem.includes(normalizedTitle) ||\n normalizedTitle.includes(normalizedItem)\n ) {\n return index + 1\n }\n }\n\n return fallbackIndex\n}\n\nexport const applyCustomContentToTemplate = (\n template: TemplateJson,\n CustomSlides: CustomSlide[]\n): TemplateJson => {\n const grouped = template.slides.reduce<Record<string, TemplateJsonSlide[]>>(\n (acc, slide) => {\n const key = slide.type || 'default'\n if (!acc[key]) acc[key] = []\n acc[key].push(slide)\n return acc\n },\n {}\n )\n\n const usage = new Map<string, number>()\n const getTextTypeCount = (slide: TemplateJsonSlide, textType: string) =>\n slide.elements.filter(\n element => element.type === 'text' && element.textType === textType\n ).length\n\n const getContentCapacity = (slide: TemplateJsonSlide) => {\n const titleSlots = getTextTypeCount(slide, 'itemTitle')\n const itemSlots = getTextTypeCount(slide, 'item')\n return Math.min(titleSlots, itemSlots)\n }\n\n const pickFromPool = (key: string, pool: TemplateJsonSlide[]) => {\n const index = usage.get(key) ?? 0\n usage.set(key, index + 1)\n return cloneSlide(pool[index % pool.length])\n }\n\n const pickSlide = (type: string, desiredCount?: number) => {\n const pool = grouped[type] || grouped.default || template.slides\n if (desiredCount == null || pool.length === 1) {\n return pickFromPool(type, pool)\n }\n\n const scored = pool.map(slide => {\n const capacity =\n type === 'content'\n ? getContentCapacity(slide)\n : getTextTypeCount(slide, 'item')\n return { slide, capacity }\n })\n const eligible = scored.filter(item => item.capacity >= desiredCount)\n if (eligible.length > 0) {\n const minCapacity = Math.min(...eligible.map(item => item.capacity))\n const best = eligible\n .filter(item => item.capacity === minCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, best)\n }\n const maxCapacity = Math.max(...scored.map(item => item.capacity))\n const fallback = scored\n .filter(item => item.capacity === maxCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, fallback)\n }\n\n let transitionIndex = 0\n const slides = CustomSlides.map((item, index) => {\n const desiredCount =\n item.type === 'contents'\n ? item.data.items.length\n : item.type === 'content'\n ? item.data.items.length\n : undefined\n const slide = pickSlide(item.type, desiredCount)\n if (item.type === 'cover') {\n applyCoverData(slide, item.data)\n } else if (item.type === 'contents') {\n applyContentsData(slide, item.data)\n } else if (item.type === 'transition') {\n transitionIndex += 1\n const partNumber = resolveTransitionIndex(\n CustomSlides,\n index,\n item.data.title,\n transitionIndex\n )\n applyTransitionData(slide, item.data, partNumber)\n } else if (item.type === 'content') {\n applyContentData(slide, item.data)\n }\n return slide\n })\n\n return {\n ...template,\n slides\n }\n}\n","import { parseDocument } from 'json2pptx-schema'\nimport type { Deck, PptxCustomThemeInput } from '../types'\nimport { applyTheme2Json } from './theme-applier'\n\nexport function applyCustomTheme (\n deck: Deck,\n input: PptxCustomThemeInput\n): Deck {\n const normalizedDeck = parseDocument(deck) as unknown as Deck\n const updated = applyTheme2Json(normalizedDeck, input)\n return parseDocument(updated) as unknown as Deck\n}\n\nexport { applyTheme2Json }\n","import type { ColorMapping, RGB } from './types'\n\nexport function normalizeHexColor (value: string): string | null {\n const raw = value.trim()\n const withHash = raw.startsWith('#') ? raw.slice(1) : raw\n if (withHash.length !== 3 && withHash.length !== 6) return null\n if (!/^[0-9a-fA-F]+$/.test(withHash)) return null\n const expanded =\n withHash.length === 3\n ? withHash\n .split('')\n .map((char) => char + char)\n .join('')\n : withHash\n return `#${expanded.toUpperCase()}`\n}\n\nexport function parseColorToRgb (\n value: string\n): (RGB & { alpha?: number }) | null {\n const hex = normalizeHexColor(value)\n if (hex) {\n const raw = hex.slice(1)\n const r = Number.parseInt(raw.slice(0, 2), 16)\n const g = Number.parseInt(raw.slice(2, 4), 16)\n const b = Number.parseInt(raw.slice(4, 6), 16)\n return { r, g, b }\n }\n\n const match = value.match(\n /rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)/i\n )\n if (!match) return null\n const r = Math.round(Number(match[1]))\n const g = Math.round(Number(match[2]))\n const b = Math.round(Number(match[3]))\n const alpha = match[4] !== undefined ? Number(match[4]) : undefined\n return {\n r,\n g,\n b,\n ...(Number.isFinite(alpha) ? { alpha } : {})\n }\n}\n\nexport function normalizeThemeColor (value: string): string | null {\n const hex = normalizeHexColor(value)\n if (hex) return hex\n const parsed = parseColorToRgb(value)\n if (!parsed) return null\n if (parsed.alpha !== undefined) {\n return `rgba(${parsed.r},${parsed.g},${parsed.b},${parsed.alpha})`\n }\n return `rgb(${parsed.r},${parsed.g},${parsed.b})`\n}\n\nexport function isPureColorString (value: string): boolean {\n const trimmed = value.trim()\n if (!trimmed) return false\n if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(trimmed)) return true\n return /^rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)$/i.test(\n trimmed\n )\n}\n\nfunction normalizeColorKey (value?: string): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = parseColorToRgb(trimmed)\n if (parsed) {\n return `${parsed.r},${parsed.g},${parsed.b},${parsed.alpha ?? 'none'}`\n }\n const hex = normalizeHexColor(trimmed)\n if (hex) return hex\n return trimmed.toLowerCase()\n}\n\nexport function colorsEqual (a: string, b: string): boolean {\n const aKey = normalizeColorKey(a)\n const bKey = normalizeColorKey(b)\n if (!aKey || !bKey) return false\n return aKey === bKey\n}\n\nexport function isWhiteColor (value?: string): boolean {\n const key = normalizeColorKey(value)\n if (!key) return false\n return (\n key === '#FFFFFF' ||\n key === '255,255,255,none' ||\n key === '255,255,255,1'\n )\n}\n\nexport function rgbToString (rgb: RGB): string {\n return `rgb(${rgb.r},${rgb.g},${rgb.b})`\n}\n\nexport function findMappingForColor (\n value: string,\n mappings: ColorMapping[]\n): ColorMapping | undefined {\n const parsed = parseColorToRgb(value)\n if (!parsed) return undefined\n return mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n}\n","import { normalizeHexColor, parseColorToRgb } from './color-utils'\nimport type { ColorMapping } from './types'\n\nexport function buildColorMappings (\n previous: string[],\n next: string[]\n): ColorMapping[] {\n const mappings: ColorMapping[] = []\n const length = Math.min(previous.length, next.length)\n for (let i = 0; i < length; i += 1) {\n const fromParsed = parseColorToRgb(previous[i])\n const toParsed = parseColorToRgb(next[i])\n if (!fromParsed || !toParsed) continue\n const toHex = normalizeHexColor(next[i]) ?? undefined\n mappings.push({\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n })\n }\n return mappings\n}\n\nexport function buildSingleMapping (\n from?: string,\n to?: string\n): ColorMapping | null {\n if (!from || !to) return null\n const fromParsed = parseColorToRgb(from)\n const toParsed = parseColorToRgb(to)\n if (!fromParsed || !toParsed) return null\n const toHex = normalizeHexColor(to) ?? undefined\n return {\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n }\n}\n","import type { Slide, SlideElement } from '../types'\nimport {\n findMappingForColor,\n isPureColorString,\n normalizeThemeColor,\n parseColorToRgb,\n rgbToString\n} from './color-utils'\nimport type { ColorMapping } from './types'\n\nfunction applyFontColorToHtml (value: string, fontColor: string): string {\n if (!value || !fontColor) return value\n const normalized = normalizeThemeColor(fontColor) ?? fontColor\n const hasStyleColor = /\\bcolor\\s*:/i.test(value)\n if (hasStyleColor) {\n return value.replace(/color\\s*:\\s*([^;\"']+)/gi, () => `color: ${normalized}`)\n }\n return value.replace(\n /(<[^>]+style\\s*=\\s*[\"'])([^\"']*)([\"'])/gi,\n (_match, start, styles, end) => {\n if (/\\bcolor\\s*:/i.test(styles)) return _match\n const nextStyles = styles.trim()\n ? `${styles.trim()}; color: ${normalized}`\n : `color: ${normalized}`\n return `${start}${nextStyles}${end}`\n }\n )\n}\n\nfunction replaceColorValue (value: string, mappings: ColorMapping[]): string {\n const mapping = findMappingForColor(value, mappings)\n if (!mapping) return value\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n if (parsed.alpha !== undefined) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceRgbaString (value: string, mappings: ColorMapping[]): string {\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n const mapping = mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n if (!mapping) return value\n if (parsed.alpha !== undefined || value.toLowerCase().startsWith('rgba')) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha ?? 1})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceColorsInText (value: string, mappings: ColorMapping[]): string {\n let next = value\n next = next.replace(/#([0-9a-f]{3}|[0-9a-f]{6})/gi, (match) => {\n const mapping = findMappingForColor(match, mappings)\n if (!mapping) return match\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n })\n next = next.replace(/rgba?\\([^)]*\\)/gi, (match) =>\n replaceRgbaString(match, mappings)\n )\n return next\n}\n\nfunction replaceColorsDeep (value: unknown, mappings: ColorMapping[]): unknown {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n const pureColor = isPureColorString(trimmed)\n if (pureColor) {\n const replaced = replaceColorValue(trimmed, mappings)\n return value === trimmed ? replaced : value.replace(trimmed, replaced)\n }\n return replaceColorsInText(value, mappings)\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => replaceColorsDeep(item, mappings))\n }\n\n if (value && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n const next: Record<string, unknown> = {}\n for (const [key, item] of entries) {\n next[key] = replaceColorsDeep(item, mappings)\n }\n return next\n }\n\n return value\n}\n\nfunction replaceTextElementColors (\n element: SlideElement,\n fontMappings: ColorMapping[],\n fontColor: string\n): SlideElement {\n const next = replaceColorsDeep(element, fontMappings) as SlideElement\n const normalizedFontColor = normalizeThemeColor(fontColor) ?? fontColor\n const withDefault =\n normalizedFontColor && 'defaultColor' in next\n ? { ...next, defaultColor: normalizedFontColor }\n : next\n if (!('content' in withDefault) || typeof withDefault.content !== 'string') {\n return withDefault\n }\n return {\n ...withDefault,\n content: applyFontColorToHtml(withDefault.content, normalizedFontColor)\n }\n}\n\nexport function replaceSlideColors (\n slide: Slide,\n themeMappings: ColorMapping[],\n fontMappings: ColorMapping[],\n fontColor: string\n): Slide {\n const { elements, ...rest } = slide\n const nextSlide = replaceColorsDeep(rest, themeMappings) as Slide\n if (!elements) return nextSlide\n\n const nextElements: SlideElement[] = elements.map((element) => {\n if (element && typeof element === 'object' && element.type === 'text') {\n return replaceTextElementColors(element, fontMappings, fontColor)\n }\n return replaceColorsDeep(element, themeMappings) as SlideElement\n })\n\n return { ...nextSlide, elements: nextElements }\n}\n","import type { Deck, PptxCustomThemeInput } from '../types'\nimport { colorsEqual, isWhiteColor } from './color-utils'\nimport { buildColorMappings, buildSingleMapping } from './mappings'\nimport { replaceSlideColors } from './replacers'\n\nexport function applyTheme2Json (deck: Deck, update: PptxCustomThemeInput): Deck {\n const previousTheme = deck.theme ?? {}\n const themeColors = update.themeColors.slice(0, 6)\n const themeMappings = buildColorMappings(\n previousTheme.themeColors ?? [],\n themeColors\n )\n const fontMapping = buildSingleMapping(\n previousTheme.fontColor,\n update.fontColor\n )\n const fontMappings = fontMapping ? [fontMapping] : []\n\n const nextBackground = update.backgroundColor ?? previousTheme.backgroundColor\n const prevBackground = previousTheme.backgroundColor\n const slides = deck.slides?.map((slide) => {\n const nextSlide = replaceSlideColors(\n slide,\n themeMappings,\n fontMappings,\n update.fontColor\n )\n if (!nextBackground) return nextSlide\n const currentColor = nextSlide.background?.color\n const shouldUpdate =\n !currentColor ||\n (prevBackground && colorsEqual(currentColor, prevBackground)) ||\n (!prevBackground && isWhiteColor(currentColor))\n if (!shouldUpdate) return nextSlide\n return {\n ...nextSlide,\n background: {\n ...(nextSlide.background ?? {}),\n type: nextSlide.background?.type ?? 'solid',\n color: nextBackground\n }\n }\n })\n\n return {\n ...deck,\n theme: {\n ...previousTheme,\n themeColors,\n fontColor: update.fontColor,\n backgroundColor: update.backgroundColor ?? previousTheme.backgroundColor\n },\n slides\n }\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;;;ACI9B,IAAM,WAAW,CAAC,UAChB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,IAAM,WAAW,CAAC,UAChB,OAAO,UAAU,WAAW,QAAQ;AAEtC,IAAM,gBAAgB,CAAC,UAAoC;AACzD,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,QAAM,aAAa,MAChB,IAAI,UAAQ,SAAS,IAAI,CAAC,EAC1B,OAAO,CAAC,SAAyB,SAAS,IAAI;AACjD,SAAO,WAAW,WAAW,MAAM,SAAS,aAAa;AAC3D;AAEA,IAAM,gBAAgB,CAAC,UAA+C;AACpE,QAAM,MAAM,SAAS,KAAK,GAAG,KAAK,EAAE,YAAY;AAChD,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,QAAQ,SAAU,QAAO;AAC7B,MAAI,QAAQ,UAAW,QAAO;AAC9B,MAAI,QAAQ,SAAU,QAAO;AAC7B,MACE,QAAQ,WACR,QAAQ,cACR,QAAQ,gBACR,QAAQ,aACR,QAAQ,OACR;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,IAAM,wBAAwB,CAAC,UAAgD;AAC7E,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,QAAM,aAAmC,CAAC;AAC1C,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,UAAM,QAAQ,SAAS,KAAK,KAAK;AACjC,UAAM,OAAO,SAAS,KAAK,IAAI;AAC/B,QAAI,SAAS,QAAQ,QAAQ,KAAM,QAAO;AAC1C,eAAW,KAAK,EAAE,OAAO,KAAK,CAAC;AAAA,EACjC;AACA,SAAO;AACT;AAEA,IAAM,iBAAiB,CAAC,UAAuC;AAC7D,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAC7B,QAAM,OAAO,cAAc,MAAM,IAAI;AACrC,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,UAAU,SAAS,MAAM,IAAI,IAAI,MAAM,OAAO,CAAC;AAErD,MAAI,SAAS,SAAS;AACpB,UAAM,QAAQ,SAAS,QAAQ,KAAK;AACpC,UAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,QAAI,SAAS,QAAQ,QAAQ,KAAM,QAAO;AAC1C,WAAO,EAAE,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE;AAAA,EACvC;AAEA,MAAI,SAAS,YAAY;AACvB,UAAM,QAAQ,cAAc,QAAQ,KAAK;AACzC,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,EAAE,MAAM,MAAM,EAAE,MAAM,EAAE;AAAA,EACjC;AAEA,MAAI,SAAS,cAAc;AACzB,UAAM,QAAQ,SAAS,QAAQ,KAAK;AACpC,UAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,QAAI,SAAS,QAAQ,QAAQ,KAAM,QAAO;AAC1C,WAAO,EAAE,MAAM,MAAM,EAAE,OAAO,KAAK,EAAE;AAAA,EACvC;AAEA,MAAI,SAAS,WAAW;AACtB,UAAM,QAAQ,SAAS,QAAQ,KAAK;AACpC,UAAM,QAAQ,sBAAsB,QAAQ,KAAK;AACjD,QAAI,SAAS,QAAQ,CAAC,MAAO,QAAO;AACpC,WAAO,EAAE,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE;AAAA,EACxC;AAEA,SAAO,EAAE,KAAK;AAChB;AAEA,IAAM,oBAAoB,CAAC,QACzB,IACG,MAAM,OAAO,EACb,IAAI,UAAQ,KAAK,KAAK,CAAC,EACvB,OAAO,OAAO,EACd,IAAI,UAAQ,KAAK,MAAM,IAAI,CAAY;AAE5C,IAAM,wBAAwB,CAAC,QAAkC;AAC/D,QAAM,UAAU,IAAI,KAAK;AACzB,MAAI,CAAC,QAAS,QAAO,CAAC;AACtB,MAAI,CAAC,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,WAAW,GAAG,EAAG,QAAO;AAEjE,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO;AAAA,EAC7B,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,MAAM,EAAG,QAAO;AAClC,MAAI,CAAC,SAAS,MAAM,EAAG,QAAO;AAC9B,MAAI,MAAM,QAAQ,OAAO,MAAM,EAAG,QAAO,OAAO;AAChD,MAAI,UAAU,OAAQ,QAAO,CAAC,MAAM;AACpC,SAAO;AACT;AAEO,IAAM,qBAAqB,CAAC,QAA+B;AAChE,QAAM,aAAa,sBAAsB,GAAG,KAAK,kBAAkB,GAAG;AACtE,QAAM,SAAS,WACZ,IAAI,UAAQ,eAAe,IAAI,CAAC,EAChC,OAAO,CAAC,SAA8B,SAAS,IAAI;AAEtD,MAAI,OAAO,WAAW,WAAW,QAAQ;AACvC,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AACA,SAAO;AACT;;;ACvHO,IAAM,oBAAoB,CAAC,MAAc,SAAiB;AAC/D,MAAI,OAAO,cAAc,aAAa;AACpC,WAAO,MAAM,IAAI;AAAA,EACnB;AACA,QAAM,SAAS,IAAI,UAAU;AAC7B,QAAM,MAAM,OAAO,gBAAgB,MAAM,WAAW;AACpD,QAAM,QAAQ,MAAM,KAAK,IAAI,iBAAiB,MAAM,CAAC;AACrD,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,WAAK,cAAc,UAAU,IAAI,OAAO;AAAA,IAC1C,CAAC;AAAA,EACH,OAAO;AACL,UAAM,YAAY,IAAI,cAAc,GAAG;AACvC,QAAI,WAAW;AACb,gBAAU,cAAc;AAAA,IAC1B,OAAO;AACL,UAAI,KAAK,cAAc;AAAA,IACzB;AAAA,EACF;AACA,SAAO,IAAI,KAAK;AAClB;AAEO,IAAM,iBAAiB,CAAC,SAA8B,SAAiB;AAC5E,MAAI,QAAQ,SAAS,OAAQ;AAC7B,UAAQ,UAAU,kBAAkB,QAAQ,SAAS,IAAI;AAC3D;;;AClBA,SAAS,mBACP,OACA,UACA,MACS;AACT,QAAM,QAAQ,MAAM,SAAS,KAAK,CAAC,YAAY;AAC7C,QAAI,QAAQ,SAAS,QAAS,QAAO;AACrC,UAAM,aAAa;AAGnB,WAAO,WAAW,MAAM,SAAS;AAAA,EACnC,CAAC;AAED,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,gBAAgB;AAGtB,MAAI,CAAC,cAAc,QAAQ,OAAO,cAAc,KAAK,YAAY,UAAU;AACzE,WAAO;AAAA,EACT;AAEA,gBAAc,KAAK,UAAU,kBAAkB,cAAc,KAAK,SAAS,IAAI;AAC/E,SAAO;AACT;AAEO,IAAM,iBAAiB,CAAC,OAA0B,SAA2B;AAClF,QAAM,QAAQ,MAAM,SAAS;AAAA,IAC3B,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,QAAM,UAAU,MAAM,SAAS;AAAA,IAC7B,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,MAAI,MAAO,gBAAe,OAAO,KAAK,KAAK;AAC3C,MAAI,QAAS,gBAAe,SAAS,KAAK,IAAI;AAChD;AAEO,IAAM,oBAAoB,CAC/B,OACA,SACG;AACH,QAAM,QAAQ,MAAM,SAAS;AAAA,IAC3B,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,QAAM,QAAQ,CAAC,SAAS,UAAU;AAChC,UAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,QAAI,KAAM,gBAAe,SAAS,IAAI;AAAA,EACxC,CAAC;AACH;AAEO,IAAM,sBAAsB,CACjC,OACA,MACA,iBACG;AACH,QAAM,QAAQ,MAAM,SAAS;AAAA,IAC3B,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,QAAM,UAAU,MAAM,SAAS;AAAA,IAC7B,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,QAAM,aAAa,MAAM,SAAS;AAAA,IAChC,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,MAAI,MAAO,gBAAe,OAAO,KAAK,KAAK;AAC3C,MAAI,QAAS,gBAAe,SAAS,KAAK,IAAI;AAC9C,QAAM,wBAAwB,GAAG,YAAY,GAAG,SAAS,GAAG,GAAG;AAC/D,MAAI,YAAY;AACd,mBAAe,YAAY,qBAAqB;AAAA,EAClD,OAAO;AACL,uBAAmB,OAAO,cAAc,qBAAqB;AAAA,EAC/D;AACF;AAEO,IAAM,mBAAmB,CAAC,OAA0B,SAA6B;AACtF,QAAM,QAAQ,MAAM,SAAS;AAAA,IAC3B,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,MAAI,MAAO,gBAAe,OAAO,KAAK,KAAK;AAE3C,QAAM,aAAa,MAAM,SAAS;AAAA,IAChC,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AACA,QAAM,QAAQ,MAAM,SAAS;AAAA,IAC3B,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D;AAEA,OAAK,MAAM,QAAQ,CAAC,MAAM,UAAU;AAClC,UAAM,UAAU,WAAW,KAAK;AAChC,UAAM,SAAS,MAAM,KAAK;AAC1B,QAAI,QAAS,gBAAe,SAAS,KAAK,KAAK;AAC/C,QAAI,OAAQ,gBAAe,QAAQ,KAAK,IAAI;AAAA,EAC9C,CAAC;AACH;;;AC9FA,IAAM,aAAa,CAAC,UAClB,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AAElC,SAAS,eAAgB,OAAuB;AAC9C,SAAO,MACJ,QAAQ,QAAQ,GAAG,EACnB,QAAQ,kDAAkD,EAAE,EAC5D,KAAK,EACL,YAAY;AACjB;AAEA,SAAS,uBACP,cACA,mBACA,iBACA,eACQ;AACR,QAAM,kBAAkB,eAAe,eAAe;AACtD,MAAI,CAAC,gBAAiB,QAAO;AAE7B,QAAM,gBAAgB,aACnB,MAAM,GAAG,oBAAoB,CAAC,EAC9B,OAAO,CAAC,UAA+D,MAAM,SAAS,UAAU,EAChG,QAAQ,WAAS,MAAM,KAAK,KAAK;AAEpC,WAAS,QAAQ,GAAG,QAAQ,cAAc,QAAQ,SAAS,GAAG;AAC5D,UAAM,iBAAiB,eAAe,cAAc,KAAK,CAAC;AAC1D,QAAI,CAAC,eAAgB;AACrB,QACE,mBAAmB,mBACnB,eAAe,SAAS,eAAe,KACvC,gBAAgB,SAAS,cAAc,GACvC;AACA,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,+BAA+B,CAC1C,UACA,iBACiB;AACjB,QAAM,UAAU,SAAS,OAAO;AAAA,IAC9B,CAAC,KAAK,UAAU;AACd,YAAM,MAAM,MAAM,QAAQ;AAC1B,UAAI,CAAC,IAAI,GAAG,EAAG,KAAI,GAAG,IAAI,CAAC;AAC3B,UAAI,GAAG,EAAE,KAAK,KAAK;AACnB,aAAO;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,QAAQ,oBAAI,IAAoB;AACtC,QAAM,mBAAmB,CAAC,OAA0B,aAClD,MAAM,SAAS;AAAA,IACb,aAAW,QAAQ,SAAS,UAAU,QAAQ,aAAa;AAAA,EAC7D,EAAE;AAEJ,QAAM,qBAAqB,CAAC,UAA6B;AACvD,UAAM,aAAa,iBAAiB,OAAO,WAAW;AACtD,UAAM,YAAY,iBAAiB,OAAO,MAAM;AAChD,WAAO,KAAK,IAAI,YAAY,SAAS;AAAA,EACvC;AAEA,QAAM,eAAe,CAAC,KAAa,SAA8B;AAC/D,UAAM,QAAQ,MAAM,IAAI,GAAG,KAAK;AAChC,UAAM,IAAI,KAAK,QAAQ,CAAC;AACxB,WAAO,WAAW,KAAK,QAAQ,KAAK,MAAM,CAAC;AAAA,EAC7C;AAEA,QAAM,YAAY,CAAC,MAAc,iBAA0B;AACzD,UAAM,OAAO,QAAQ,IAAI,KAAK,QAAQ,WAAW,SAAS;AAC1D,QAAI,gBAAgB,QAAQ,KAAK,WAAW,GAAG;AAC7C,aAAO,aAAa,MAAM,IAAI;AAAA,IAChC;AAEA,UAAM,SAAS,KAAK,IAAI,WAAS;AAC/B,YAAM,WACJ,SAAS,YACL,mBAAmB,KAAK,IACxB,iBAAiB,OAAO,MAAM;AACpC,aAAO,EAAE,OAAO,SAAS;AAAA,IAC3B,CAAC;AACD,UAAM,WAAW,OAAO,OAAO,UAAQ,KAAK,YAAY,YAAY;AACpE,QAAI,SAAS,SAAS,GAAG;AACvB,YAAM,cAAc,KAAK,IAAI,GAAG,SAAS,IAAI,UAAQ,KAAK,QAAQ,CAAC;AACnE,YAAM,OAAO,SACV,OAAO,UAAQ,KAAK,aAAa,WAAW,EAC5C,IAAI,UAAQ,KAAK,KAAK;AACzB,aAAO,aAAa,GAAG,IAAI,IAAI,YAAY,IAAI,IAAI;AAAA,IACrD;AACA,UAAM,cAAc,KAAK,IAAI,GAAG,OAAO,IAAI,UAAQ,KAAK,QAAQ,CAAC;AACjE,UAAM,WAAW,OACd,OAAO,UAAQ,KAAK,aAAa,WAAW,EAC5C,IAAI,UAAQ,KAAK,KAAK;AACzB,WAAO,aAAa,GAAG,IAAI,IAAI,YAAY,IAAI,QAAQ;AAAA,EACzD;AAEA,MAAI,kBAAkB;AACtB,QAAM,SAAS,aAAa,IAAI,CAAC,MAAM,UAAU;AAC/C,UAAM,eACJ,KAAK,SAAS,aACV,KAAK,KAAK,MAAM,SAChB,KAAK,SAAS,YACd,KAAK,KAAK,MAAM,SAChB;AACN,UAAM,QAAQ,UAAU,KAAK,MAAM,YAAY;AAC/C,QAAI,KAAK,SAAS,SAAS;AACzB,qBAAe,OAAO,KAAK,IAAI;AAAA,IACjC,WAAW,KAAK,SAAS,YAAY;AACnC,wBAAkB,OAAO,KAAK,IAAI;AAAA,IACpC,WAAW,KAAK,SAAS,cAAc;AACrC,yBAAmB;AACnB,YAAM,aAAa;AAAA,QACjB;AAAA,QACA;AAAA,QACA,KAAK,KAAK;AAAA,QACV;AAAA,MACF;AACA,0BAAoB,OAAO,KAAK,MAAM,UAAU;AAAA,IAClD,WAAW,KAAK,SAAS,WAAW;AAClC,uBAAiB,OAAO,KAAK,IAAI;AAAA,IACnC;AACA,WAAO;AAAA,EACT,CAAC;AAED,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EACF;AACF;;;AJvIO,SAAS,mBACd,UACA,OACc;AACd,QAAM,qBAAqB,cAAc,QAAQ;AACjD,QAAM,eAAe,OAAO,UAAU,WAAW,mBAAmB,KAAK,IAAI;AAC7E,QAAM,UAAU,6BAA6B,oBAAoB,YAAY;AAC7E,SAAO,cAAc,OAAO;AAC9B;;;AKbA,SAAS,iBAAAA,sBAAqB;;;ACEvB,SAAS,kBAAmB,OAA8B;AAC/D,QAAM,MAAM,MAAM,KAAK;AACvB,QAAM,WAAW,IAAI,WAAW,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI;AACtD,MAAI,SAAS,WAAW,KAAK,SAAS,WAAW,EAAG,QAAO;AAC3D,MAAI,CAAC,iBAAiB,KAAK,QAAQ,EAAG,QAAO;AAC7C,QAAM,WACJ,SAAS,WAAW,IAChB,SACG,MAAM,EAAE,EACR,IAAI,CAAC,SAAS,OAAO,IAAI,EACzB,KAAK,EAAE,IACV;AACN,SAAO,IAAI,SAAS,YAAY,CAAC;AACnC;AAEO,SAAS,gBACd,OACmC;AACnC,QAAM,MAAM,kBAAkB,KAAK;AACnC,MAAI,KAAK;AACP,UAAM,MAAM,IAAI,MAAM,CAAC;AACvB,UAAMC,KAAI,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;AAC7C,UAAMC,KAAI,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;AAC7C,UAAMC,KAAI,OAAO,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;AAC7C,WAAO,EAAE,GAAAF,IAAG,GAAAC,IAAG,GAAAC,GAAE;AAAA,EACnB;AAEA,QAAM,QAAQ,MAAM;AAAA,IAClB;AAAA,EACF;AACA,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC,CAAC;AACrC,QAAM,IAAI,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC,CAAC;AACrC,QAAM,IAAI,KAAK,MAAM,OAAO,MAAM,CAAC,CAAC,CAAC;AACrC,QAAM,QAAQ,MAAM,CAAC,MAAM,SAAY,OAAO,MAAM,CAAC,CAAC,IAAI;AAC1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,OAAO,SAAS,KAAK,IAAI,EAAE,MAAM,IAAI,CAAC;AAAA,EAC5C;AACF;AAEO,SAAS,oBAAqB,OAA8B;AACjE,QAAM,MAAM,kBAAkB,KAAK;AACnC,MAAI,IAAK,QAAO;AAChB,QAAM,SAAS,gBAAgB,KAAK;AACpC,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,UAAU,QAAW;AAC9B,WAAO,QAAQ,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,OAAO,KAAK;AAAA,EACjE;AACA,SAAO,OAAO,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,OAAO,CAAC;AAChD;AAEO,SAAS,kBAAmB,OAAwB;AACzD,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,gCAAgC,KAAK,OAAO,EAAG,QAAO;AAC1D,SAAO,mFAAmF;AAAA,IACxF;AAAA,EACF;AACF;AAEA,SAAS,kBAAmB,OAA+B;AACzD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,SAAS,gBAAgB,OAAO;AACtC,MAAI,QAAQ;AACV,WAAO,GAAG,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,OAAO,SAAS,MAAM;AAAA,EACtE;AACA,QAAM,MAAM,kBAAkB,OAAO;AACrC,MAAI,IAAK,QAAO;AAChB,SAAO,QAAQ,YAAY;AAC7B;AAEO,SAAS,YAAa,GAAW,GAAoB;AAC1D,QAAM,OAAO,kBAAkB,CAAC;AAChC,QAAM,OAAO,kBAAkB,CAAC;AAChC,MAAI,CAAC,QAAQ,CAAC,KAAM,QAAO;AAC3B,SAAO,SAAS;AAClB;AAEO,SAAS,aAAc,OAAyB;AACrD,QAAM,MAAM,kBAAkB,KAAK;AACnC,MAAI,CAAC,IAAK,QAAO;AACjB,SACE,QAAQ,aACR,QAAQ,sBACR,QAAQ;AAEZ;AAEO,SAAS,YAAa,KAAkB;AAC7C,SAAO,OAAO,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC;AACvC;AAEO,SAAS,oBACd,OACA,UAC0B;AAC1B,QAAM,SAAS,gBAAgB,KAAK;AACpC,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,SAAS;AAAA,IACd,CAAC,SACC,KAAK,QAAQ,MAAM,OAAO,KAC1B,KAAK,QAAQ,MAAM,OAAO,KAC1B,KAAK,QAAQ,MAAM,OAAO;AAAA,EAC9B;AACF;;;AC5GO,SAAS,mBACd,UACA,MACgB;AAChB,QAAM,WAA2B,CAAC;AAClC,QAAM,SAAS,KAAK,IAAI,SAAS,QAAQ,KAAK,MAAM;AACpD,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,UAAM,aAAa,gBAAgB,SAAS,CAAC,CAAC;AAC9C,UAAM,WAAW,gBAAgB,KAAK,CAAC,CAAC;AACxC,QAAI,CAAC,cAAc,CAAC,SAAU;AAC9B,UAAM,QAAQ,kBAAkB,KAAK,CAAC,CAAC,KAAK;AAC5C,aAAS,KAAK;AAAA,MACZ,SAAS,EAAE,GAAG,WAAW,GAAG,GAAG,WAAW,GAAG,GAAG,WAAW,EAAE;AAAA,MAC7D,OAAO,EAAE,GAAG,SAAS,GAAG,GAAG,SAAS,GAAG,GAAG,SAAS,EAAE;AAAA,MACrD;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,SAAS,mBACd,MACA,IACqB;AACrB,MAAI,CAAC,QAAQ,CAAC,GAAI,QAAO;AACzB,QAAM,aAAa,gBAAgB,IAAI;AACvC,QAAM,WAAW,gBAAgB,EAAE;AACnC,MAAI,CAAC,cAAc,CAAC,SAAU,QAAO;AACrC,QAAM,QAAQ,kBAAkB,EAAE,KAAK;AACvC,SAAO;AAAA,IACL,SAAS,EAAE,GAAG,WAAW,GAAG,GAAG,WAAW,GAAG,GAAG,WAAW,EAAE;AAAA,IAC7D,OAAO,EAAE,GAAG,SAAS,GAAG,GAAG,SAAS,GAAG,GAAG,SAAS,EAAE;AAAA,IACrD;AAAA,EACF;AACF;;;AC3BA,SAAS,qBAAsB,OAAe,WAA2B;AACvE,MAAI,CAAC,SAAS,CAAC,UAAW,QAAO;AACjC,QAAM,aAAa,oBAAoB,SAAS,KAAK;AACrD,QAAM,gBAAgB,eAAe,KAAK,KAAK;AAC/C,MAAI,eAAe;AACjB,WAAO,MAAM,QAAQ,2BAA2B,MAAM,UAAU,UAAU,EAAE;AAAA,EAC9E;AACA,SAAO,MAAM;AAAA,IACX;AAAA,IACA,CAAC,QAAQ,OAAO,QAAQ,QAAQ;AAC9B,UAAI,eAAe,KAAK,MAAM,EAAG,QAAO;AACxC,YAAM,aAAa,OAAO,KAAK,IAC3B,GAAG,OAAO,KAAK,CAAC,YAAY,UAAU,KACtC,UAAU,UAAU;AACxB,aAAO,GAAG,KAAK,GAAG,UAAU,GAAG,GAAG;AAAA,IACpC;AAAA,EACF;AACF;AAEA,SAAS,kBAAmB,OAAe,UAAkC;AAC3E,QAAM,UAAU,oBAAoB,OAAO,QAAQ;AACnD,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,SAAS,gBAAgB,KAAK;AACpC,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,UAAU,QAAW;AAC9B,WAAO,QAAQ,QAAQ,MAAM,CAAC,IAAI,QAAQ,MAAM,CAAC,IAAI,QAAQ,MAAM,CAAC,IAAI,OAAO,KAAK;AAAA,EACtF;AACA,SAAO,QAAQ,SAAS,YAAY,QAAQ,KAAK;AACnD;AAEA,SAAS,kBAAmB,OAAe,UAAkC;AAC3E,QAAM,SAAS,gBAAgB,KAAK;AACpC,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,UAAU,SAAS;AAAA,IACvB,CAAC,SACC,KAAK,QAAQ,MAAM,OAAO,KAC1B,KAAK,QAAQ,MAAM,OAAO,KAC1B,KAAK,QAAQ,MAAM,OAAO;AAAA,EAC9B;AACA,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,OAAO,UAAU,UAAa,MAAM,YAAY,EAAE,WAAW,MAAM,GAAG;AACxE,WAAO,QAAQ,QAAQ,MAAM,CAAC,IAAI,QAAQ,MAAM,CAAC,IAAI,QAAQ,MAAM,CAAC,IAAI,OAAO,SAAS,CAAC;AAAA,EAC3F;AACA,SAAO,QAAQ,SAAS,YAAY,QAAQ,KAAK;AACnD;AAEA,SAAS,oBAAqB,OAAe,UAAkC;AAC7E,MAAI,OAAO;AACX,SAAO,KAAK,QAAQ,gCAAgC,CAAC,UAAU;AAC7D,UAAM,UAAU,oBAAoB,OAAO,QAAQ;AACnD,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,QAAQ,SAAS,YAAY,QAAQ,KAAK;AAAA,EACnD,CAAC;AACD,SAAO,KAAK;AAAA,IAAQ;AAAA,IAAoB,CAAC,UACvC,kBAAkB,OAAO,QAAQ;AAAA,EACnC;AACA,SAAO;AACT;AAEA,SAAS,kBAAmB,OAAgB,UAAmC;AAC7E,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,UAAM,YAAY,kBAAkB,OAAO;AAC3C,QAAI,WAAW;AACb,YAAM,WAAW,kBAAkB,SAAS,QAAQ;AACpD,aAAO,UAAU,UAAU,WAAW,MAAM,QAAQ,SAAS,QAAQ;AAAA,IACvE;AACA,WAAO,oBAAoB,OAAO,QAAQ;AAAA,EAC5C;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,SAAS,kBAAkB,MAAM,QAAQ,CAAC;AAAA,EAC9D;AAEA,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,UAAU,OAAO,QAAQ,KAAgC;AAC/D,UAAM,OAAgC,CAAC;AACvC,eAAW,CAAC,KAAK,IAAI,KAAK,SAAS;AACjC,WAAK,GAAG,IAAI,kBAAkB,MAAM,QAAQ;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,yBACP,SACA,cACA,WACc;AACd,QAAM,OAAO,kBAAkB,SAAS,YAAY;AACpD,QAAM,sBAAsB,oBAAoB,SAAS,KAAK;AAC9D,QAAM,cACJ,uBAAuB,kBAAkB,OACrC,EAAE,GAAG,MAAM,cAAc,oBAAoB,IAC7C;AACN,MAAI,EAAE,aAAa,gBAAgB,OAAO,YAAY,YAAY,UAAU;AAC1E,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,qBAAqB,YAAY,SAAS,mBAAmB;AAAA,EACxE;AACF;AAEO,SAAS,mBACd,OACA,eACA,cACA,WACO;AACP,QAAM,EAAE,UAAU,GAAG,KAAK,IAAI;AAC9B,QAAM,YAAY,kBAAkB,MAAM,aAAa;AACvD,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,eAA+B,SAAS,IAAI,CAAC,YAAY;AAC7D,QAAI,WAAW,OAAO,YAAY,YAAY,QAAQ,SAAS,QAAQ;AACrE,aAAO,yBAAyB,SAAS,cAAc,SAAS;AAAA,IAClE;AACA,WAAO,kBAAkB,SAAS,aAAa;AAAA,EACjD,CAAC;AAED,SAAO,EAAE,GAAG,WAAW,UAAU,aAAa;AAChD;;;ACjIO,SAAS,gBAAiB,MAAY,QAAoC;AAC/E,QAAM,gBAAgB,KAAK,SAAS,CAAC;AACrC,QAAM,cAAc,OAAO,YAAY,MAAM,GAAG,CAAC;AACjD,QAAM,gBAAgB;AAAA,IACpB,cAAc,eAAe,CAAC;AAAA,IAC9B;AAAA,EACF;AACA,QAAM,cAAc;AAAA,IAClB,cAAc;AAAA,IACd,OAAO;AAAA,EACT;AACA,QAAM,eAAe,cAAc,CAAC,WAAW,IAAI,CAAC;AAEpD,QAAM,iBAAiB,OAAO,mBAAmB,cAAc;AAC/D,QAAM,iBAAiB,cAAc;AACrC,QAAM,SAAS,KAAK,QAAQ,IAAI,CAAC,UAAU;AACzC,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AACA,QAAI,CAAC,eAAgB,QAAO;AAC5B,UAAM,eAAe,UAAU,YAAY;AAC3C,UAAM,eACJ,CAAC,gBACA,kBAAkB,YAAY,cAAc,cAAc,KAC1D,CAAC,kBAAkB,aAAa,YAAY;AAC/C,QAAI,CAAC,aAAc,QAAO;AAC1B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,YAAY;AAAA,QACV,GAAI,UAAU,cAAc,CAAC;AAAA,QAC7B,MAAM,UAAU,YAAY,QAAQ;AAAA,QACpC,OAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,WAAW,OAAO;AAAA,MAClB,iBAAiB,OAAO,mBAAmB,cAAc;AAAA,IAC3D;AAAA,IACA;AAAA,EACF;AACF;;;AJlDO,SAAS,iBACd,MACA,OACM;AACN,QAAM,iBAAiBC,eAAc,IAAI;AACzC,QAAM,UAAU,gBAAgB,gBAAgB,KAAK;AACrD,SAAOA,eAAc,OAAO;AAC9B;","names":["parseDocument","r","g","b","parseDocument"]}
1
+ {"version":3,"sources":["../src/custom-content/index.ts","../src/custom-content/parser.ts","../src/custom-content/html.ts","../src/custom-content/slide-appliers.ts","../src/custom-content/template-builder.ts","../src/custom-theme/index.ts","../src/custom-theme/color-utils.ts","../src/custom-theme/mappings.ts","../src/custom-theme/replacers.ts","../src/custom-theme/theme-applier.ts"],"sourcesContent":["import { parseDocument } from 'json2pptx-schema'\nimport type {\n PptxCustomContentInput,\n TemplateJson,\n TemplateJsonElement,\n TemplateJsonImage\n} from '../types'\nimport { parseCustomContent } from './parser'\nimport { applyCustomContentToTemplate } from './template-builder'\n\nconst FALLBACK_SLIDE_WIDTH = 1000\nconst FALLBACK_SLIDE_HEIGHT = 562.5\nconst LOGO_MARGIN_X = 24\nconst LOGO_MARGIN_Y = 18\nconst LOGO_MAX_WIDTH_RATIO = 0.34\nconst LOGO_MAX_HEIGHT_RATIO = 0.16\n\nfunction isLogoImageElement (\n element: TemplateJsonElement\n): element is TemplateJsonImage {\n return element.type === 'image' && element.imageType === 'logo'\n}\n\nfunction fitSize (\n width: number,\n height: number,\n maxWidth: number,\n maxHeight: number\n): { width: number; height: number } {\n const safeWidth = width > 0 ? width : maxWidth\n const safeHeight = height > 0 ? height : maxHeight\n const scale = Math.min(maxWidth / safeWidth, maxHeight / safeHeight)\n return {\n width: safeWidth * scale,\n height: safeHeight * scale\n }\n}\n\nfunction normalizeLogoElements (deck: TemplateJson): TemplateJson {\n const slideWidth = deck.width || FALLBACK_SLIDE_WIDTH\n const slideHeight = deck.height || FALLBACK_SLIDE_HEIGHT\n const logoMaxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO\n const logoMaxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO\n\n const slides = deck.slides.map(slide => {\n let changed = false\n const elements = slide.elements.map(element => {\n if (!isLogoImageElement(element)) return element\n\n const size = fitSize(\n element.width ?? logoMaxWidth,\n element.height ?? logoMaxHeight,\n logoMaxWidth,\n logoMaxHeight\n )\n const isLeft = (element.left ?? 0) < slideWidth / 2\n const left = isLeft\n ? LOGO_MARGIN_X\n : Math.max(LOGO_MARGIN_X, slideWidth - size.width - LOGO_MARGIN_X)\n const top = LOGO_MARGIN_Y\n const { clip: _clip, ...rest } = element\n\n changed = true\n return {\n ...rest,\n left,\n top,\n width: size.width,\n height: size.height,\n fixedRatio: true\n }\n })\n\n return changed ? { ...slide, elements } : slide\n })\n\n return { ...deck, slides }\n}\n\nexport function applyCustomContent (\n template: TemplateJson,\n input: PptxCustomContentInput\n): TemplateJson {\n const normalizedTemplate = parseDocument(template) as unknown as TemplateJson\n const CustomSlides = typeof input === 'string' ? parseCustomContent(input) : input\n const updated = applyCustomContentToTemplate(normalizedTemplate, CustomSlides)\n const withNormalizedLogo = normalizeLogoElements(updated)\n return parseDocument(withNormalizedLogo) as unknown as TemplateJson\n}\n\nexport { parseCustomContent, applyCustomContentToTemplate }\n","import type { BackendContentItem, CustomSlide } from '../types'\n\ntype UnknownRecord = Record<string, unknown>\n\nconst isRecord = (value: unknown): value is UnknownRecord =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst asString = (value: unknown): string | null =>\n typeof value === 'string' ? value : null\n\nconst asStringArray = (value: unknown): string[] | null => {\n if (!Array.isArray(value)) return null\n const normalized = value\n .map(item => asString(item))\n .filter((item): item is string => item !== null)\n return normalized.length === value.length ? normalized : null\n}\n\nconst normalizeType = (value: unknown): CustomSlide['type'] | null => {\n const raw = asString(value)?.trim().toLowerCase()\n if (!raw) return null\n if (raw === 'agenda') return 'contents'\n if (raw === 'section') return 'transition'\n if (raw === 'ending') return 'end'\n if (\n raw === 'cover' ||\n raw === 'contents' ||\n raw === 'transition' ||\n raw === 'content' ||\n raw === 'end'\n ) {\n return raw\n }\n return null\n}\n\nconst normalizeContentItems = (value: unknown): BackendContentItem[] | null => {\n if (!Array.isArray(value)) return null\n const normalized: BackendContentItem[] = []\n for (const item of value) {\n if (!isRecord(item)) return null\n const title = asString(item.title)\n const text = asString(item.text)\n if (title == null || text == null) return null\n normalized.push({ title, text })\n }\n return normalized\n}\n\nconst normalizeSlide = (value: unknown): CustomSlide | null => {\n if (!isRecord(value)) return null\n const type = normalizeType(value.type)\n if (!type) return null\n\n const rawData = isRecord(value.data) ? value.data : {}\n\n if (type === 'cover') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'contents') {\n const items = asStringArray(rawData.items)\n if (!items) return null\n return { type, data: { items } }\n }\n\n if (type === 'transition') {\n const title = asString(rawData.title)\n const text = asString(rawData.text)\n if (title == null || text == null) return null\n return { type, data: { title, text } }\n }\n\n if (type === 'content') {\n const title = asString(rawData.title)\n const items = normalizeContentItems(rawData.items)\n if (title == null || !items) return null\n return { type, data: { title, items } }\n }\n\n return { type }\n}\n\nconst parseNdJsonSlides = (raw: string): unknown[] =>\n raw\n .split(/\\r?\\n/)\n .map(line => line.trim())\n .filter(Boolean)\n .map(line => JSON.parse(line) as unknown)\n\nconst parseStructuredSlides = (raw: string): unknown[] | null => {\n const trimmed = raw.trim()\n if (!trimmed) return []\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return null\n\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed) as unknown\n } catch {\n return null\n }\n if (Array.isArray(parsed)) return parsed\n if (!isRecord(parsed)) return null\n if (Array.isArray(parsed.slides)) return parsed.slides\n if ('type' in parsed) return [parsed]\n return null\n}\n\nexport const parseCustomContent = (raw: string): CustomSlide[] => {\n const candidates = parseStructuredSlides(raw) ?? parseNdJsonSlides(raw)\n const slides = candidates\n .map(item => normalizeSlide(item))\n .filter((item): item is CustomSlide => item !== null)\n\n if (slides.length !== candidates.length) {\n throw new Error('Invalid custom content format')\n }\n return slides\n}\n","import type { TemplateJsonElement } from '../types'\n\nexport const updateHtmlContent = (html: string, text: string) => {\n if (typeof DOMParser === 'undefined') {\n return `<p>${text}</p>`\n }\n const parser = new DOMParser()\n const doc = parser.parseFromString(html, 'text/html')\n const spans = Array.from(doc.querySelectorAll('span'))\n if (spans.length > 0) {\n spans.forEach((span, index) => {\n span.textContent = index === 0 ? text : ''\n })\n } else {\n const paragraph = doc.querySelector('p')\n if (paragraph) {\n paragraph.textContent = text\n } else {\n doc.body.textContent = text\n }\n }\n return doc.body.innerHTML\n}\n\nexport const setElementText = (element: TemplateJsonElement, text: string) => {\n if (element.type !== 'text') return\n element.content = updateHtmlContent(element.content, text)\n}\n","import type {\n BackendContentData,\n BackendContentsData,\n BackendCoverData,\n BackendTransitionData,\n TemplateJsonSlide\n} from '../types'\nimport { setElementText, updateHtmlContent } from './html'\n\nfunction setShapeTextByType (\n slide: TemplateJsonSlide,\n textType: string,\n text: string\n): boolean {\n const shape = slide.elements.find((element) => {\n if (element.type !== 'shape') return false\n const maybeShape = element as unknown as {\n text?: { type?: string; content?: string }\n }\n return maybeShape.text?.type === textType\n })\n\n if (!shape) return false\n\n const shapeWithText = shape as unknown as {\n text?: { type?: string; content?: string }\n }\n if (!shapeWithText.text || typeof shapeWithText.text.content !== 'string') {\n return false\n }\n\n shapeWithText.text.content = updateHtmlContent(shapeWithText.text.content, text)\n return true\n}\n\nexport const applyCoverData = (slide: TemplateJsonSlide, data: BackendCoverData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n}\n\nexport const applyContentsData = (\n slide: TemplateJsonSlide,\n data: BackendContentsData\n) => {\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n items.forEach((element, index) => {\n const text = data.items[index]\n if (text) setElementText(element, text)\n })\n}\n\nexport const applyTransitionData = (\n slide: TemplateJsonSlide,\n data: BackendTransitionData,\n sectionIndex: number\n) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n const content = slide.elements.find(\n element => element.type === 'text' && element.textType === 'content'\n )\n const partNumber = slide.elements.find(\n element => element.type === 'text' && element.textType === 'partNumber'\n )\n if (title) setElementText(title, data.title)\n if (content) setElementText(content, data.text)\n const formattedSectionIndex = `${sectionIndex}`.padStart(2, '0')\n if (partNumber) {\n setElementText(partNumber, formattedSectionIndex)\n } else {\n setShapeTextByType(slide, 'partNumber', formattedSectionIndex)\n }\n}\n\nexport const applyContentData = (slide: TemplateJsonSlide, data: BackendContentData) => {\n const title = slide.elements.find(\n element => element.type === 'text' && element.textType === 'title'\n )\n if (title) setElementText(title, data.title)\n\n const itemTitles = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'itemTitle'\n )\n const items = slide.elements.filter(\n element => element.type === 'text' && element.textType === 'item'\n )\n\n data.items.forEach((item, index) => {\n const titleEl = itemTitles[index]\n const textEl = items[index]\n if (titleEl) setElementText(titleEl, item.title)\n if (textEl) setElementText(textEl, item.text)\n })\n}\n","import type { CustomSlide, TemplateJson, TemplateJsonSlide } from '../types'\nimport {\n applyContentData,\n applyContentsData,\n applyCoverData,\n applyTransitionData\n} from './slide-appliers'\n\nconst cloneSlide = (slide: TemplateJsonSlide): TemplateJsonSlide =>\n JSON.parse(JSON.stringify(slide)) as TemplateJsonSlide\n\nfunction normalizeLabel (value: string): string {\n return value\n .replace(/\\s+/g, ' ')\n .replace(/[,。、“”‘’:;!?【】()《》〈〉·,.:;!?()[\\]{}\"'`~\\-_/\\\\]/g, '')\n .trim()\n .toLowerCase()\n}\n\nfunction resolveTransitionIndex (\n customSlides: CustomSlide[],\n currentSlideIndex: number,\n transitionTitle: string,\n fallbackIndex: number\n): number {\n const normalizedTitle = normalizeLabel(transitionTitle)\n if (!normalizedTitle) return fallbackIndex\n\n const contentsItems = customSlides\n .slice(0, currentSlideIndex + 1)\n .filter((slide): slide is Extract<CustomSlide, { type: 'contents' }> => slide.type === 'contents')\n .flatMap(slide => slide.data.items)\n\n for (let index = 0; index < contentsItems.length; index += 1) {\n const normalizedItem = normalizeLabel(contentsItems[index])\n if (!normalizedItem) continue\n if (\n normalizedItem === normalizedTitle ||\n normalizedItem.includes(normalizedTitle) ||\n normalizedTitle.includes(normalizedItem)\n ) {\n return index + 1\n }\n }\n\n return fallbackIndex\n}\n\nexport const applyCustomContentToTemplate = (\n template: TemplateJson,\n CustomSlides: CustomSlide[]\n): TemplateJson => {\n const grouped = template.slides.reduce<Record<string, TemplateJsonSlide[]>>(\n (acc, slide) => {\n const key = slide.type || 'default'\n if (!acc[key]) acc[key] = []\n acc[key].push(slide)\n return acc\n },\n {}\n )\n\n const usage = new Map<string, number>()\n const getTextTypeCount = (slide: TemplateJsonSlide, textType: string) =>\n slide.elements.filter(\n element => element.type === 'text' && element.textType === textType\n ).length\n\n const getContentCapacity = (slide: TemplateJsonSlide) => {\n const titleSlots = getTextTypeCount(slide, 'itemTitle')\n const itemSlots = getTextTypeCount(slide, 'item')\n return Math.min(titleSlots, itemSlots)\n }\n\n const pickFromPool = (key: string, pool: TemplateJsonSlide[]) => {\n const index = usage.get(key) ?? 0\n usage.set(key, index + 1)\n return cloneSlide(pool[index % pool.length])\n }\n\n const pickSlide = (type: string, desiredCount?: number) => {\n const pool = grouped[type] || grouped.default || template.slides\n if (desiredCount == null || pool.length === 1) {\n return pickFromPool(type, pool)\n }\n\n const scored = pool.map(slide => {\n const capacity =\n type === 'content'\n ? getContentCapacity(slide)\n : getTextTypeCount(slide, 'item')\n return { slide, capacity }\n })\n const eligible = scored.filter(item => item.capacity >= desiredCount)\n if (eligible.length > 0) {\n const minCapacity = Math.min(...eligible.map(item => item.capacity))\n const best = eligible\n .filter(item => item.capacity === minCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, best)\n }\n const maxCapacity = Math.max(...scored.map(item => item.capacity))\n const fallback = scored\n .filter(item => item.capacity === maxCapacity)\n .map(item => item.slide)\n return pickFromPool(`${type}:${desiredCount}`, fallback)\n }\n\n let transitionIndex = 0\n const slides = CustomSlides.map((item, index) => {\n const desiredCount =\n item.type === 'contents'\n ? item.data.items.length\n : item.type === 'content'\n ? item.data.items.length\n : undefined\n const slide = pickSlide(item.type, desiredCount)\n if (item.type === 'cover') {\n applyCoverData(slide, item.data)\n } else if (item.type === 'contents') {\n applyContentsData(slide, item.data)\n } else if (item.type === 'transition') {\n transitionIndex += 1\n const partNumber = resolveTransitionIndex(\n CustomSlides,\n index,\n item.data.title,\n transitionIndex\n )\n applyTransitionData(slide, item.data, partNumber)\n } else if (item.type === 'content') {\n applyContentData(slide, item.data)\n }\n return slide\n })\n\n return {\n ...template,\n slides\n }\n}\n","import { parseDocument } from 'json2pptx-schema'\nimport type {\n Deck,\n PptxCustomThemeInput,\n Slide,\n SlideElement,\n ThemeLogoPosition,\n ThemeScope,\n ThemeScopeKey\n} from '../types'\nimport { parseColorToRgb } from './color-utils'\nimport { applyTheme2Json } from './theme-applier'\n\nconst FALLBACK_SLIDE_WIDTH = 1000\nconst FALLBACK_SLIDE_HEIGHT = 562.5\nconst LOGO_MARGIN_X = 24\nconst LOGO_MARGIN_Y = 18\nconst LOGO_MAX_WIDTH_RATIO = 0.34\nconst LOGO_MAX_HEIGHT_RATIO = 0.16\nconst DEFAULT_LOGO_ASPECT_RATIO = 3.2\n\nfunction mapSlideTypeToScopeKey (type?: string): ThemeScopeKey | null {\n const normalized = type?.trim().toLowerCase()\n if (!normalized) return null\n\n if (normalized === 'cover') return 'cover'\n if (normalized === 'contents' || normalized === 'agenda') return 'contents'\n if (normalized === 'transition' || normalized === 'section') return 'transition'\n if (normalized === 'content') return 'content'\n if (normalized === 'end' || normalized === 'ending') return 'end'\n\n return null\n}\n\nfunction isSlideInScope (slide: Slide, scope: ThemeScope): boolean {\n const key = mapSlideTypeToScopeKey(slide.type)\n if (!key) return false\n return Boolean(scope[key])\n}\n\nfunction createElementId (prefix: string, slideIndex: number): string {\n const random = Math.random().toString(36).slice(2, 10)\n return `${prefix}-${slideIndex}-${random}`\n}\n\nfunction toHalfOpacityColor (value: string): string {\n const rgb = parseColorToRgb(value)\n if (!rgb) return value\n return `rgba(${rgb.r},${rgb.g},${rgb.b},0.5)`\n}\n\nfunction buildBackgroundElement (\n src: string,\n slideWidth: number,\n slideHeight: number,\n slideIndex: number\n): SlideElement {\n return {\n type: 'image',\n id: createElementId('background', slideIndex),\n src,\n width: slideWidth,\n height: slideHeight,\n left: 0,\n top: 0,\n fixedRatio: true,\n rotate: 0,\n imageType: 'background',\n filters: {\n opacity: '100%'\n }\n }\n}\n\nfunction buildLogoElement (\n src: string,\n slideWidth: number,\n slideHeight: number,\n position: ThemeLogoPosition,\n slideIndex: number,\n logoWidth?: number,\n logoHeight?: number\n): SlideElement {\n const aspectRatio = resolveLogoAspectRatio(logoWidth, logoHeight)\n const maxWidth = slideWidth * LOGO_MAX_WIDTH_RATIO\n const maxHeight = slideHeight * LOGO_MAX_HEIGHT_RATIO\n let width = maxWidth\n let height = width / aspectRatio\n if (height > maxHeight) {\n height = maxHeight\n width = height * aspectRatio\n }\n const left =\n position === 'left'\n ? LOGO_MARGIN_X\n : Math.max(LOGO_MARGIN_X, slideWidth - width - LOGO_MARGIN_X)\n\n return {\n type: 'image',\n id: createElementId('logo', slideIndex),\n src,\n width,\n height,\n left,\n top: LOGO_MARGIN_Y,\n fixedRatio: true,\n rotate: 0,\n imageType: 'logo'\n }\n}\n\nfunction resolveLogoAspectRatio (\n width?: number,\n height?: number\n): number {\n if (\n typeof width === 'number' &&\n typeof height === 'number' &&\n width > 0 &&\n height > 0\n ) {\n return width / height\n }\n return DEFAULT_LOGO_ASPECT_RATIO\n}\n\nfunction replaceScopedMedia (deck: Deck, input: PptxCustomThemeInput): Deck {\n if (!deck.slides?.length) return deck\n\n const slideWidth = deck.width ?? FALLBACK_SLIDE_WIDTH\n const slideHeight = deck.height ?? FALLBACK_SLIDE_HEIGHT\n const backgroundInput = input.backgroundImage\n const logoInput = input.logoImage\n const shouldClearBackground = Boolean(input.clearBackgroundImage)\n const shouldClearLogo = Boolean(input.clearLogoImage || shouldClearBackground)\n\n if (\n !backgroundInput?.src &&\n !logoInput?.src &&\n !shouldClearBackground &&\n !shouldClearLogo\n ) {\n return deck\n }\n\n const slides = deck.slides.map((slide, slideIndex) => {\n let nextElements = slide.elements ? [...slide.elements] : []\n let nextBackground = slide.background\n let changed = false\n\n if (shouldClearBackground) {\n const before = nextElements.length\n nextElements = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'background')\n )\n if (nextElements.length !== before) {\n changed = true\n if (input.backgroundColor) {\n nextBackground = {\n ...(nextBackground ?? {}),\n type: 'solid',\n color: input.backgroundColor\n }\n }\n }\n }\n\n if (shouldClearLogo) {\n const before = nextElements.length\n nextElements = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'logo')\n )\n if (nextElements.length !== before) {\n changed = true\n }\n }\n\n if (backgroundInput?.src && isSlideInScope(slide, backgroundInput.scope)) {\n const withoutBackground = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'background')\n )\n nextElements = [\n buildBackgroundElement(\n backgroundInput.src,\n slideWidth,\n slideHeight,\n slideIndex\n ),\n ...withoutBackground\n ]\n changed = true\n\n if (input.backgroundColor) {\n nextBackground = {\n ...(nextBackground ?? {}),\n type: 'solid',\n color: toHalfOpacityColor(input.backgroundColor)\n }\n }\n }\n\n if (logoInput?.src && isSlideInScope(slide, logoInput.scope)) {\n const withoutLogo = nextElements.filter(\n element => !(element.type === 'image' && element.imageType === 'logo')\n )\n nextElements = [\n ...withoutLogo,\n buildLogoElement(\n logoInput.src,\n slideWidth,\n slideHeight,\n logoInput.position,\n slideIndex,\n logoInput.width,\n logoInput.height\n )\n ]\n changed = true\n }\n\n if (!changed && nextBackground === slide.background) return slide\n\n return {\n ...slide,\n ...(changed ? { elements: nextElements } : {}),\n ...(nextBackground ? { background: nextBackground } : {})\n }\n })\n\n return { ...deck, slides }\n}\n\nexport function applyCustomTheme (\n deck: Deck,\n input: PptxCustomThemeInput\n): Deck {\n const normalizedDeck = parseDocument(deck) as unknown as Deck\n const withColors = applyTheme2Json(normalizedDeck, input)\n const withMedia = replaceScopedMedia(withColors, input)\n return parseDocument(withMedia) as unknown as Deck\n}\n\nexport { applyTheme2Json }\n","import type { ColorMapping, RGB } from './types'\n\nexport function normalizeHexColor (value: string): string | null {\n const raw = value.trim()\n const withHash = raw.startsWith('#') ? raw.slice(1) : raw\n if (withHash.length !== 3 && withHash.length !== 6) return null\n if (!/^[0-9a-fA-F]+$/.test(withHash)) return null\n const expanded =\n withHash.length === 3\n ? withHash\n .split('')\n .map((char) => char + char)\n .join('')\n : withHash\n return `#${expanded.toUpperCase()}`\n}\n\nexport function parseColorToRgb (\n value: string\n): (RGB & { alpha?: number }) | null {\n const hex = normalizeHexColor(value)\n if (hex) {\n const raw = hex.slice(1)\n const r = Number.parseInt(raw.slice(0, 2), 16)\n const g = Number.parseInt(raw.slice(2, 4), 16)\n const b = Number.parseInt(raw.slice(4, 6), 16)\n return { r, g, b }\n }\n\n const match = value.match(\n /rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)/i\n )\n if (!match) return null\n const r = Math.round(Number(match[1]))\n const g = Math.round(Number(match[2]))\n const b = Math.round(Number(match[3]))\n const alpha = match[4] !== undefined ? Number(match[4]) : undefined\n return {\n r,\n g,\n b,\n ...(Number.isFinite(alpha) ? { alpha } : {})\n }\n}\n\nexport function normalizeThemeColor (value: string): string | null {\n const hex = normalizeHexColor(value)\n if (hex) return hex\n const parsed = parseColorToRgb(value)\n if (!parsed) return null\n if (parsed.alpha !== undefined) {\n return `rgba(${parsed.r},${parsed.g},${parsed.b},${parsed.alpha})`\n }\n return `rgb(${parsed.r},${parsed.g},${parsed.b})`\n}\n\nexport function isPureColorString (value: string): boolean {\n const trimmed = value.trim()\n if (!trimmed) return false\n if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(trimmed)) return true\n return /^rgba?\\(\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*,\\s*([0-9.]+)\\s*(?:,\\s*([0-9.]+)\\s*)?\\)$/i.test(\n trimmed\n )\n}\n\nfunction normalizeColorKey (value?: string): string | null {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = parseColorToRgb(trimmed)\n if (parsed) {\n return `${parsed.r},${parsed.g},${parsed.b},${parsed.alpha ?? 'none'}`\n }\n const hex = normalizeHexColor(trimmed)\n if (hex) return hex\n return trimmed.toLowerCase()\n}\n\nexport function colorsEqual (a: string, b: string): boolean {\n const aKey = normalizeColorKey(a)\n const bKey = normalizeColorKey(b)\n if (!aKey || !bKey) return false\n return aKey === bKey\n}\n\nexport function isWhiteColor (value?: string): boolean {\n const key = normalizeColorKey(value)\n if (!key) return false\n return (\n key === '#FFFFFF' ||\n key === '255,255,255,none' ||\n key === '255,255,255,1'\n )\n}\n\nexport function rgbToString (rgb: RGB): string {\n return `rgb(${rgb.r},${rgb.g},${rgb.b})`\n}\n\nexport function findMappingForColor (\n value: string,\n mappings: ColorMapping[]\n): ColorMapping | undefined {\n const parsed = parseColorToRgb(value)\n if (!parsed) return undefined\n return mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n}\n","import { normalizeHexColor, parseColorToRgb } from './color-utils'\nimport type { ColorMapping } from './types'\n\nexport function buildColorMappings (\n previous: string[],\n next: string[]\n): ColorMapping[] {\n const mappings: ColorMapping[] = []\n const length = Math.min(previous.length, next.length)\n for (let i = 0; i < length; i += 1) {\n const fromParsed = parseColorToRgb(previous[i])\n const toParsed = parseColorToRgb(next[i])\n if (!fromParsed || !toParsed) continue\n const toHex = normalizeHexColor(next[i]) ?? undefined\n mappings.push({\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n })\n }\n return mappings\n}\n\nexport function buildSingleMapping (\n from?: string,\n to?: string\n): ColorMapping | null {\n if (!from || !to) return null\n const fromParsed = parseColorToRgb(from)\n const toParsed = parseColorToRgb(to)\n if (!fromParsed || !toParsed) return null\n const toHex = normalizeHexColor(to) ?? undefined\n return {\n fromRgb: { r: fromParsed.r, g: fromParsed.g, b: fromParsed.b },\n toRgb: { r: toParsed.r, g: toParsed.g, b: toParsed.b },\n toHex\n }\n}\n","import type { Slide, SlideElement } from '../types'\nimport {\n findMappingForColor,\n isPureColorString,\n normalizeThemeColor,\n parseColorToRgb,\n rgbToString\n} from './color-utils'\nimport type { ColorMapping } from './types'\n\nfunction applyFontColorToHtml (value: string, fontColor: string): string {\n if (!value || !fontColor) return value\n const normalized = normalizeThemeColor(fontColor) ?? fontColor\n const hasStyleColor = /\\bcolor\\s*:/i.test(value)\n if (hasStyleColor) {\n return value.replace(/color\\s*:\\s*([^;\"']+)/gi, () => `color: ${normalized}`)\n }\n return value.replace(\n /(<[^>]+style\\s*=\\s*[\"'])([^\"']*)([\"'])/gi,\n (_match, start, styles, end) => {\n if (/\\bcolor\\s*:/i.test(styles)) return _match\n const nextStyles = styles.trim()\n ? `${styles.trim()}; color: ${normalized}`\n : `color: ${normalized}`\n return `${start}${nextStyles}${end}`\n }\n )\n}\n\nfunction replaceColorValue (value: string, mappings: ColorMapping[]): string {\n const mapping = findMappingForColor(value, mappings)\n if (!mapping) return value\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n if (parsed.alpha !== undefined) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceRgbaString (value: string, mappings: ColorMapping[]): string {\n const parsed = parseColorToRgb(value)\n if (!parsed) return value\n const mapping = mappings.find(\n (item) =>\n item.fromRgb.r === parsed.r &&\n item.fromRgb.g === parsed.g &&\n item.fromRgb.b === parsed.b\n )\n if (!mapping) return value\n if (parsed.alpha !== undefined || value.toLowerCase().startsWith('rgba')) {\n return `rgba(${mapping.toRgb.r},${mapping.toRgb.g},${mapping.toRgb.b},${parsed.alpha ?? 1})`\n }\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n}\n\nfunction replaceColorsInText (value: string, mappings: ColorMapping[]): string {\n let next = value\n next = next.replace(/#([0-9a-f]{3}|[0-9a-f]{6})/gi, (match) => {\n const mapping = findMappingForColor(match, mappings)\n if (!mapping) return match\n return mapping.toHex ?? rgbToString(mapping.toRgb)\n })\n next = next.replace(/rgba?\\([^)]*\\)/gi, (match) =>\n replaceRgbaString(match, mappings)\n )\n return next\n}\n\nfunction replaceColorsDeep (value: unknown, mappings: ColorMapping[]): unknown {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n const pureColor = isPureColorString(trimmed)\n if (pureColor) {\n const replaced = replaceColorValue(trimmed, mappings)\n return value === trimmed ? replaced : value.replace(trimmed, replaced)\n }\n return replaceColorsInText(value, mappings)\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => replaceColorsDeep(item, mappings))\n }\n\n if (value && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n const next: Record<string, unknown> = {}\n for (const [key, item] of entries) {\n next[key] = replaceColorsDeep(item, mappings)\n }\n return next\n }\n\n return value\n}\n\nfunction replaceTextElementColors (\n element: SlideElement,\n fontMappings: ColorMapping[],\n fontColor: string\n): SlideElement {\n const next = replaceColorsDeep(element, fontMappings) as SlideElement\n const normalizedFontColor = normalizeThemeColor(fontColor) ?? fontColor\n const withDefault =\n normalizedFontColor && 'defaultColor' in next\n ? { ...next, defaultColor: normalizedFontColor }\n : next\n if (!('content' in withDefault) || typeof withDefault.content !== 'string') {\n return withDefault\n }\n return {\n ...withDefault,\n content: applyFontColorToHtml(withDefault.content, normalizedFontColor)\n }\n}\n\nexport function replaceSlideColors (\n slide: Slide,\n themeMappings: ColorMapping[],\n fontMappings: ColorMapping[],\n fontColor: string\n): Slide {\n const { elements, ...rest } = slide\n const nextSlide = replaceColorsDeep(rest, themeMappings) as Slide\n if (!elements) return nextSlide\n\n const nextElements: SlideElement[] = elements.map((element) => {\n if (element && typeof element === 'object' && element.type === 'text') {\n return replaceTextElementColors(element, fontMappings, fontColor)\n }\n return replaceColorsDeep(element, themeMappings) as SlideElement\n })\n\n return { ...nextSlide, elements: nextElements }\n}\n","import type { Deck, PptxCustomThemeInput } from '../types'\nimport { colorsEqual, isWhiteColor } from './color-utils'\nimport { buildColorMappings, buildSingleMapping } from './mappings'\nimport { replaceSlideColors } from './replacers'\n\nexport function applyTheme2Json (deck: Deck, update: PptxCustomThemeInput): Deck {\n const previousTheme = deck.theme ?? {}\n const themeColors = update.themeColors.slice(0, 6)\n const themeMappings = buildColorMappings(\n previousTheme.themeColors ?? [],\n themeColors\n )\n const fontMapping = buildSingleMapping(\n previousTheme.fontColor,\n update.fontColor\n )\n const fontMappings = fontMapping ? [fontMapping] : []\n\n const nextBackground = update.backgroundColor ?? previousTheme.backgroundColor\n const prevBackground = previousTheme.backgroundColor\n const slides = deck.slides?.map((slide) => {\n const nextSlide = replaceSlideColors(\n slide,\n themeMappings,\n fontMappings,\n update.fontColor\n )\n if (!nextBackground) return nextSlide\n const currentColor = nextSlide.background?.color\n const shouldUpdate =\n !currentColor ||\n (prevBackground && colorsEqual(currentColor, prevBackground)) ||\n (!prevBackground && isWhiteColor(currentColor))\n if (!shouldUpdate) return nextSlide\n return {\n ...nextSlide,\n background: {\n ...(nextSlide.background ?? {}),\n type: nextSlide.background?.type ?? 'solid',\n color: nextBackground\n }\n }\n })\n\n return {\n ...deck,\n theme: {\n ...previousTheme,\n themeColors,\n fontColor: update.fontColor,\n backgroundColor: update.backgroundColor ?? previousTheme.backgroundColor\n },\n slides\n }\n}\n"],"mappings":"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","names":["parseDocument","r","g","b","FALLBACK_SLIDE_WIDTH","FALLBACK_SLIDE_HEIGHT","LOGO_MARGIN_X","LOGO_MARGIN_Y","LOGO_MAX_WIDTH_RATIO","LOGO_MAX_HEIGHT_RATIO","parseDocument"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-custom",
3
- "version": "0.2.2",
3
+ "version": "0.3.1",
4
4
  "description": "Custom content and theme utilities for PPTX JSON templates.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.cjs",