@jsamuel1/pptxgenjs 4.1.3 → 4.1.4

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.
@@ -0,0 +1,148 @@
1
+ /* PptxGenJS 4.1.4 @ 2026-06-08T05:10:40.789Z */
2
+ 'use strict';
3
+
4
+ /**
5
+ * PptxGenJS — Theme Extraction utility (docs/feature-theme-extraction.md)
6
+ *
7
+ * Parses CSS `:root { --var: value; }` custom properties and maps known variable-name
8
+ * patterns to a theme palette (background/accent/text/font + an extended colour set).
9
+ * Pure, dependency-free, regex-based parsing — no DOM and no browser required, so it runs
10
+ * in Node.js. This is an OPTIONAL utility (imported from `@jsamuel1/pptxgenjs/utils`), not
11
+ * part of the main `PptxGenJS` class, keeping the core library focused on OOXML generation.
12
+ */
13
+ /** Built-in dark preset (matches docs/feature-theme-extraction.md). */
14
+ const DARK_PRESET = {
15
+ bg: '121218',
16
+ bgSecondary: '1A1A24',
17
+ accent: '7C3AED',
18
+ accentSoft: 'A78BFA',
19
+ text: 'E4E4ED',
20
+ textSecondary: '8A8A9A',
21
+ font: 'Inter',
22
+ sky: '38BDF8',
23
+ green: '10B981',
24
+ orange: 'FF9900',
25
+ red: 'EF4444',
26
+ };
27
+ /** Built-in light preset. */
28
+ const LIGHT_PRESET = {
29
+ bg: 'FFFFFF',
30
+ bgSecondary: 'F4F4F7',
31
+ accent: '7C3AED',
32
+ accentSoft: 'A78BFA',
33
+ text: '121218',
34
+ textSecondary: '5A5A6A',
35
+ font: 'Inter',
36
+ sky: '0EA5E9',
37
+ green: '059669',
38
+ orange: 'EA580C',
39
+ red: 'DC2626',
40
+ };
41
+ /**
42
+ * Exact CSS-variable-name → theme-slot map. Names are matched exactly (NOT by substring) so
43
+ * `--bg` and `--bg-card` resolve to different slots. Mirrors the table in the feature spec.
44
+ */
45
+ const VAR_TO_SLOT = {
46
+ // bg
47
+ bg: 'bg', 'color-bg': 'bg', background: 'bg', 'bg-deep': 'bg',
48
+ // bgSecondary
49
+ 'bg-card': 'bgSecondary', card: 'bgSecondary', 'color-bg-secondary': 'bgSecondary', 'bg-surface': 'bgSecondary',
50
+ // accent
51
+ purple: 'accent', accent: 'accent', 'color-primary': 'accent', primary: 'accent',
52
+ // accentSoft
53
+ 'purple-soft': 'accentSoft', 'accent-soft': 'accentSoft', 'color-primary-light': 'accentSoft',
54
+ // text
55
+ white: 'text', text: 'text', 'color-text': 'text', foreground: 'text',
56
+ // textSecondary
57
+ gray: 'textSecondary', muted: 'textSecondary', 'color-text-secondary': 'textSecondary',
58
+ // sky
59
+ sky: 'sky', blue: 'sky', info: 'sky',
60
+ // green
61
+ green: 'green', success: 'green',
62
+ // orange
63
+ orange: 'orange', warning: 'orange',
64
+ // red
65
+ red: 'red', error: 'red', danger: 'red',
66
+ // font
67
+ font: 'font', 'font-family': 'font',
68
+ };
69
+ /** Slots whose value is a colour (vs. a font family) — used to decide value normalisation. */
70
+ const COLOR_SLOTS = new Set(['bg', 'bgSecondary', 'accent', 'accentSoft', 'text', 'textSecondary', 'sky', 'green', 'orange', 'red']);
71
+ /** Normalise a colour value to a 6-digit hex (no `#`). 3-digit hex is expanded; non-hex returned as-is. */
72
+ function normalizeColor(raw) {
73
+ let v = raw.trim().replace(/^#/, '');
74
+ // Expand 3-digit shorthand (#abc -> AABBCC)
75
+ if (/^[0-9a-fA-F]{3}$/.test(v))
76
+ v = v.split('').map(c => c + c).join('');
77
+ // Uppercase 6/8-digit hex for consistency with the rest of the library
78
+ if (/^[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/.test(v))
79
+ return v.toUpperCase();
80
+ // rgb()/hsl()/named colours are returned trimmed but unconverted (documented limitation)
81
+ return v;
82
+ }
83
+ /** Normalise a font-family value: strip surrounding quotes and take the first family. */
84
+ function normalizeFont(raw) {
85
+ const first = raw.split(',')[0].trim();
86
+ return first.replace(/^['"]/, '').replace(/['"]$/, '').trim();
87
+ }
88
+ /**
89
+ * Extract `--name: value;` custom-property declarations from CSS text.
90
+ * Prefers declarations inside `:root { … }` blocks; if none are found, falls back to scanning
91
+ * the entire string (covers inline/style-block custom props without a `:root` selector).
92
+ * @returns map of bare variable name (no leading `--`) -> value
93
+ */
94
+ function parseCssVars(css) {
95
+ const out = {};
96
+ const declRegex = /--([\w-]+)\s*:\s*([^;]+);/g;
97
+ const collect = (text) => {
98
+ let m;
99
+ while ((m = declRegex.exec(text)) !== null) {
100
+ out[m[1].trim().toLowerCase()] = m[2].trim();
101
+ }
102
+ };
103
+ // 1) :root blocks (there can be more than one)
104
+ const rootRegex = /:root\s*\{([^}]*)\}/g;
105
+ let rootMatch;
106
+ let foundRoot = false;
107
+ while ((rootMatch = rootRegex.exec(css)) !== null) {
108
+ foundRoot = true;
109
+ declRegex.lastIndex = 0;
110
+ collect(rootMatch[1]);
111
+ }
112
+ // 2) Fallback: no :root vars — scan the whole CSS for custom-prop declarations
113
+ if (!foundRoot) {
114
+ declRegex.lastIndex = 0;
115
+ collect(css);
116
+ }
117
+ return out;
118
+ }
119
+ /**
120
+ * Parse CSS `:root` custom properties into a theme palette, falling back to a preset for any
121
+ * slot not present in the CSS.
122
+ * @param {string} css - CSS text (or any text containing `--name: value;` declarations)
123
+ * @param {ExtractThemeOptions} [options] - presets + which preset to fall back to
124
+ * @returns {ThemePalette} the resolved palette (always complete — preset fills the gaps)
125
+ * @example
126
+ * const theme = extractThemeFromCSS(':root{ --bg:#121218; --purple:#7C3AED; }')
127
+ * // => { bg: '121218', accent: '7C3AED', ... }
128
+ */
129
+ function extractThemeFromCSS(css, options = {}) {
130
+ const presets = Object.assign({ dark: DARK_PRESET, light: LIGHT_PRESET }, (options.presets || {}));
131
+ const presetName = options.defaultPreset || 'dark';
132
+ const base = presets[presetName] || DARK_PRESET;
133
+ // Start from a complete palette (dark) then layer the chosen preset so the result is always whole
134
+ const theme = Object.assign(Object.assign({}, DARK_PRESET), base);
135
+ if (typeof css === 'string' && css.length > 0) {
136
+ const vars = parseCssVars(css);
137
+ Object.keys(vars).forEach(name => {
138
+ const slot = VAR_TO_SLOT[name];
139
+ if (!slot)
140
+ return;
141
+ const value = vars[name];
142
+ theme[slot] = slot === 'font' || !COLOR_SLOTS.has(slot) ? normalizeFont(value) : normalizeColor(value);
143
+ });
144
+ }
145
+ return theme;
146
+ }
147
+
148
+ exports.extractThemeFromCSS = extractThemeFromCSS;
@@ -0,0 +1,146 @@
1
+ /* PptxGenJS 4.1.4 @ 2026-06-08T05:10:40.789Z */
2
+ /**
3
+ * PptxGenJS — Theme Extraction utility (docs/feature-theme-extraction.md)
4
+ *
5
+ * Parses CSS `:root { --var: value; }` custom properties and maps known variable-name
6
+ * patterns to a theme palette (background/accent/text/font + an extended colour set).
7
+ * Pure, dependency-free, regex-based parsing — no DOM and no browser required, so it runs
8
+ * in Node.js. This is an OPTIONAL utility (imported from `@jsamuel1/pptxgenjs/utils`), not
9
+ * part of the main `PptxGenJS` class, keeping the core library focused on OOXML generation.
10
+ */
11
+ /** Built-in dark preset (matches docs/feature-theme-extraction.md). */
12
+ const DARK_PRESET = {
13
+ bg: '121218',
14
+ bgSecondary: '1A1A24',
15
+ accent: '7C3AED',
16
+ accentSoft: 'A78BFA',
17
+ text: 'E4E4ED',
18
+ textSecondary: '8A8A9A',
19
+ font: 'Inter',
20
+ sky: '38BDF8',
21
+ green: '10B981',
22
+ orange: 'FF9900',
23
+ red: 'EF4444',
24
+ };
25
+ /** Built-in light preset. */
26
+ const LIGHT_PRESET = {
27
+ bg: 'FFFFFF',
28
+ bgSecondary: 'F4F4F7',
29
+ accent: '7C3AED',
30
+ accentSoft: 'A78BFA',
31
+ text: '121218',
32
+ textSecondary: '5A5A6A',
33
+ font: 'Inter',
34
+ sky: '0EA5E9',
35
+ green: '059669',
36
+ orange: 'EA580C',
37
+ red: 'DC2626',
38
+ };
39
+ /**
40
+ * Exact CSS-variable-name → theme-slot map. Names are matched exactly (NOT by substring) so
41
+ * `--bg` and `--bg-card` resolve to different slots. Mirrors the table in the feature spec.
42
+ */
43
+ const VAR_TO_SLOT = {
44
+ // bg
45
+ bg: 'bg', 'color-bg': 'bg', background: 'bg', 'bg-deep': 'bg',
46
+ // bgSecondary
47
+ 'bg-card': 'bgSecondary', card: 'bgSecondary', 'color-bg-secondary': 'bgSecondary', 'bg-surface': 'bgSecondary',
48
+ // accent
49
+ purple: 'accent', accent: 'accent', 'color-primary': 'accent', primary: 'accent',
50
+ // accentSoft
51
+ 'purple-soft': 'accentSoft', 'accent-soft': 'accentSoft', 'color-primary-light': 'accentSoft',
52
+ // text
53
+ white: 'text', text: 'text', 'color-text': 'text', foreground: 'text',
54
+ // textSecondary
55
+ gray: 'textSecondary', muted: 'textSecondary', 'color-text-secondary': 'textSecondary',
56
+ // sky
57
+ sky: 'sky', blue: 'sky', info: 'sky',
58
+ // green
59
+ green: 'green', success: 'green',
60
+ // orange
61
+ orange: 'orange', warning: 'orange',
62
+ // red
63
+ red: 'red', error: 'red', danger: 'red',
64
+ // font
65
+ font: 'font', 'font-family': 'font',
66
+ };
67
+ /** Slots whose value is a colour (vs. a font family) — used to decide value normalisation. */
68
+ const COLOR_SLOTS = new Set(['bg', 'bgSecondary', 'accent', 'accentSoft', 'text', 'textSecondary', 'sky', 'green', 'orange', 'red']);
69
+ /** Normalise a colour value to a 6-digit hex (no `#`). 3-digit hex is expanded; non-hex returned as-is. */
70
+ function normalizeColor(raw) {
71
+ let v = raw.trim().replace(/^#/, '');
72
+ // Expand 3-digit shorthand (#abc -> AABBCC)
73
+ if (/^[0-9a-fA-F]{3}$/.test(v))
74
+ v = v.split('').map(c => c + c).join('');
75
+ // Uppercase 6/8-digit hex for consistency with the rest of the library
76
+ if (/^[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/.test(v))
77
+ return v.toUpperCase();
78
+ // rgb()/hsl()/named colours are returned trimmed but unconverted (documented limitation)
79
+ return v;
80
+ }
81
+ /** Normalise a font-family value: strip surrounding quotes and take the first family. */
82
+ function normalizeFont(raw) {
83
+ const first = raw.split(',')[0].trim();
84
+ return first.replace(/^['"]/, '').replace(/['"]$/, '').trim();
85
+ }
86
+ /**
87
+ * Extract `--name: value;` custom-property declarations from CSS text.
88
+ * Prefers declarations inside `:root { … }` blocks; if none are found, falls back to scanning
89
+ * the entire string (covers inline/style-block custom props without a `:root` selector).
90
+ * @returns map of bare variable name (no leading `--`) -> value
91
+ */
92
+ function parseCssVars(css) {
93
+ const out = {};
94
+ const declRegex = /--([\w-]+)\s*:\s*([^;]+);/g;
95
+ const collect = (text) => {
96
+ let m;
97
+ while ((m = declRegex.exec(text)) !== null) {
98
+ out[m[1].trim().toLowerCase()] = m[2].trim();
99
+ }
100
+ };
101
+ // 1) :root blocks (there can be more than one)
102
+ const rootRegex = /:root\s*\{([^}]*)\}/g;
103
+ let rootMatch;
104
+ let foundRoot = false;
105
+ while ((rootMatch = rootRegex.exec(css)) !== null) {
106
+ foundRoot = true;
107
+ declRegex.lastIndex = 0;
108
+ collect(rootMatch[1]);
109
+ }
110
+ // 2) Fallback: no :root vars — scan the whole CSS for custom-prop declarations
111
+ if (!foundRoot) {
112
+ declRegex.lastIndex = 0;
113
+ collect(css);
114
+ }
115
+ return out;
116
+ }
117
+ /**
118
+ * Parse CSS `:root` custom properties into a theme palette, falling back to a preset for any
119
+ * slot not present in the CSS.
120
+ * @param {string} css - CSS text (or any text containing `--name: value;` declarations)
121
+ * @param {ExtractThemeOptions} [options] - presets + which preset to fall back to
122
+ * @returns {ThemePalette} the resolved palette (always complete — preset fills the gaps)
123
+ * @example
124
+ * const theme = extractThemeFromCSS(':root{ --bg:#121218; --purple:#7C3AED; }')
125
+ * // => { bg: '121218', accent: '7C3AED', ... }
126
+ */
127
+ function extractThemeFromCSS(css, options = {}) {
128
+ const presets = Object.assign({ dark: DARK_PRESET, light: LIGHT_PRESET }, (options.presets || {}));
129
+ const presetName = options.defaultPreset || 'dark';
130
+ const base = presets[presetName] || DARK_PRESET;
131
+ // Start from a complete palette (dark) then layer the chosen preset so the result is always whole
132
+ const theme = Object.assign(Object.assign({}, DARK_PRESET), base);
133
+ if (typeof css === 'string' && css.length > 0) {
134
+ const vars = parseCssVars(css);
135
+ Object.keys(vars).forEach(name => {
136
+ const slot = VAR_TO_SLOT[name];
137
+ if (!slot)
138
+ return;
139
+ const value = vars[name];
140
+ theme[slot] = slot === 'font' || !COLOR_SLOTS.has(slot) ? normalizeFont(value) : normalizeColor(value);
141
+ });
142
+ }
143
+ return theme;
144
+ }
145
+
146
+ export { extractThemeFromCSS };
package/dist/utils.js ADDED
@@ -0,0 +1,148 @@
1
+ /* PptxGenJS 4.1.4 @ 2026-06-08T05:10:40.789Z */
2
+ 'use strict';
3
+
4
+ /**
5
+ * PptxGenJS — Theme Extraction utility (docs/feature-theme-extraction.md)
6
+ *
7
+ * Parses CSS `:root { --var: value; }` custom properties and maps known variable-name
8
+ * patterns to a theme palette (background/accent/text/font + an extended colour set).
9
+ * Pure, dependency-free, regex-based parsing — no DOM and no browser required, so it runs
10
+ * in Node.js. This is an OPTIONAL utility (imported from `@jsamuel1/pptxgenjs/utils`), not
11
+ * part of the main `PptxGenJS` class, keeping the core library focused on OOXML generation.
12
+ */
13
+ /** Built-in dark preset (matches docs/feature-theme-extraction.md). */
14
+ const DARK_PRESET = {
15
+ bg: '121218',
16
+ bgSecondary: '1A1A24',
17
+ accent: '7C3AED',
18
+ accentSoft: 'A78BFA',
19
+ text: 'E4E4ED',
20
+ textSecondary: '8A8A9A',
21
+ font: 'Inter',
22
+ sky: '38BDF8',
23
+ green: '10B981',
24
+ orange: 'FF9900',
25
+ red: 'EF4444',
26
+ };
27
+ /** Built-in light preset. */
28
+ const LIGHT_PRESET = {
29
+ bg: 'FFFFFF',
30
+ bgSecondary: 'F4F4F7',
31
+ accent: '7C3AED',
32
+ accentSoft: 'A78BFA',
33
+ text: '121218',
34
+ textSecondary: '5A5A6A',
35
+ font: 'Inter',
36
+ sky: '0EA5E9',
37
+ green: '059669',
38
+ orange: 'EA580C',
39
+ red: 'DC2626',
40
+ };
41
+ /**
42
+ * Exact CSS-variable-name → theme-slot map. Names are matched exactly (NOT by substring) so
43
+ * `--bg` and `--bg-card` resolve to different slots. Mirrors the table in the feature spec.
44
+ */
45
+ const VAR_TO_SLOT = {
46
+ // bg
47
+ bg: 'bg', 'color-bg': 'bg', background: 'bg', 'bg-deep': 'bg',
48
+ // bgSecondary
49
+ 'bg-card': 'bgSecondary', card: 'bgSecondary', 'color-bg-secondary': 'bgSecondary', 'bg-surface': 'bgSecondary',
50
+ // accent
51
+ purple: 'accent', accent: 'accent', 'color-primary': 'accent', primary: 'accent',
52
+ // accentSoft
53
+ 'purple-soft': 'accentSoft', 'accent-soft': 'accentSoft', 'color-primary-light': 'accentSoft',
54
+ // text
55
+ white: 'text', text: 'text', 'color-text': 'text', foreground: 'text',
56
+ // textSecondary
57
+ gray: 'textSecondary', muted: 'textSecondary', 'color-text-secondary': 'textSecondary',
58
+ // sky
59
+ sky: 'sky', blue: 'sky', info: 'sky',
60
+ // green
61
+ green: 'green', success: 'green',
62
+ // orange
63
+ orange: 'orange', warning: 'orange',
64
+ // red
65
+ red: 'red', error: 'red', danger: 'red',
66
+ // font
67
+ font: 'font', 'font-family': 'font',
68
+ };
69
+ /** Slots whose value is a colour (vs. a font family) — used to decide value normalisation. */
70
+ const COLOR_SLOTS = new Set(['bg', 'bgSecondary', 'accent', 'accentSoft', 'text', 'textSecondary', 'sky', 'green', 'orange', 'red']);
71
+ /** Normalise a colour value to a 6-digit hex (no `#`). 3-digit hex is expanded; non-hex returned as-is. */
72
+ function normalizeColor(raw) {
73
+ let v = raw.trim().replace(/^#/, '');
74
+ // Expand 3-digit shorthand (#abc -> AABBCC)
75
+ if (/^[0-9a-fA-F]{3}$/.test(v))
76
+ v = v.split('').map(c => c + c).join('');
77
+ // Uppercase 6/8-digit hex for consistency with the rest of the library
78
+ if (/^[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/.test(v))
79
+ return v.toUpperCase();
80
+ // rgb()/hsl()/named colours are returned trimmed but unconverted (documented limitation)
81
+ return v;
82
+ }
83
+ /** Normalise a font-family value: strip surrounding quotes and take the first family. */
84
+ function normalizeFont(raw) {
85
+ const first = raw.split(',')[0].trim();
86
+ return first.replace(/^['"]/, '').replace(/['"]$/, '').trim();
87
+ }
88
+ /**
89
+ * Extract `--name: value;` custom-property declarations from CSS text.
90
+ * Prefers declarations inside `:root { … }` blocks; if none are found, falls back to scanning
91
+ * the entire string (covers inline/style-block custom props without a `:root` selector).
92
+ * @returns map of bare variable name (no leading `--`) -> value
93
+ */
94
+ function parseCssVars(css) {
95
+ const out = {};
96
+ const declRegex = /--([\w-]+)\s*:\s*([^;]+);/g;
97
+ const collect = (text) => {
98
+ let m;
99
+ while ((m = declRegex.exec(text)) !== null) {
100
+ out[m[1].trim().toLowerCase()] = m[2].trim();
101
+ }
102
+ };
103
+ // 1) :root blocks (there can be more than one)
104
+ const rootRegex = /:root\s*\{([^}]*)\}/g;
105
+ let rootMatch;
106
+ let foundRoot = false;
107
+ while ((rootMatch = rootRegex.exec(css)) !== null) {
108
+ foundRoot = true;
109
+ declRegex.lastIndex = 0;
110
+ collect(rootMatch[1]);
111
+ }
112
+ // 2) Fallback: no :root vars — scan the whole CSS for custom-prop declarations
113
+ if (!foundRoot) {
114
+ declRegex.lastIndex = 0;
115
+ collect(css);
116
+ }
117
+ return out;
118
+ }
119
+ /**
120
+ * Parse CSS `:root` custom properties into a theme palette, falling back to a preset for any
121
+ * slot not present in the CSS.
122
+ * @param {string} css - CSS text (or any text containing `--name: value;` declarations)
123
+ * @param {ExtractThemeOptions} [options] - presets + which preset to fall back to
124
+ * @returns {ThemePalette} the resolved palette (always complete — preset fills the gaps)
125
+ * @example
126
+ * const theme = extractThemeFromCSS(':root{ --bg:#121218; --purple:#7C3AED; }')
127
+ * // => { bg: '121218', accent: '7C3AED', ... }
128
+ */
129
+ function extractThemeFromCSS(css, options = {}) {
130
+ const presets = Object.assign({ dark: DARK_PRESET, light: LIGHT_PRESET }, (options.presets || {}));
131
+ const presetName = options.defaultPreset || 'dark';
132
+ const base = presets[presetName] || DARK_PRESET;
133
+ // Start from a complete palette (dark) then layer the chosen preset so the result is always whole
134
+ const theme = Object.assign(Object.assign({}, DARK_PRESET), base);
135
+ if (typeof css === 'string' && css.length > 0) {
136
+ const vars = parseCssVars(css);
137
+ Object.keys(vars).forEach(name => {
138
+ const slot = VAR_TO_SLOT[name];
139
+ if (!slot)
140
+ return;
141
+ const value = vars[name];
142
+ theme[slot] = slot === 'font' || !COLOR_SLOTS.has(slot) ? normalizeFont(value) : normalizeColor(value);
143
+ });
144
+ }
145
+ return theme;
146
+ }
147
+
148
+ exports.extractThemeFromCSS = extractThemeFromCSS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsamuel1/pptxgenjs",
3
- "version": "4.1.3",
3
+ "version": "4.1.4",
4
4
  "author": {
5
5
  "name": "Joshua Samuel",
6
6
  "url": "https://github.com/jsamuel1/"
@@ -15,22 +15,31 @@
15
15
  "homepage": "https://github.com/jsamuel1/PptxGenJS#readme",
16
16
  "license": "MIT",
17
17
  "exports": {
18
- "types": "./types/index.d.ts",
19
- "import": "./dist/pptxgen.es.js",
20
- "require": "./dist/pptxgen.cjs.js"
18
+ ".": {
19
+ "types": "./types/index.d.ts",
20
+ "import": "./dist/pptxgen.es.js",
21
+ "require": "./dist/pptxgen.cjs.js"
22
+ },
23
+ "./utils": {
24
+ "types": "./types/utils.d.ts",
25
+ "import": "./dist/utils.es.js",
26
+ "require": "./dist/utils.cjs.js"
27
+ }
21
28
  },
22
29
  "main": "dist/pptxgen.cjs.js",
23
30
  "module": "dist/pptxgen.es.js",
31
+ "sideEffects": false,
24
32
  "files": [
25
33
  "dist",
26
34
  "types"
27
35
  ],
28
36
  "types": "types",
29
37
  "scripts": {
30
- "build": "rollup -c --bundleConfigAsCjs",
31
- "start": "gulp",
32
- "ship": "gulp ship",
33
- "defs": "gulp reactTestDefs",
38
+ "build": "rollup -c",
39
+ "lint": "eslint src",
40
+ "lint:fix": "eslint src --fix",
41
+ "ship": "SHIP=1 rollup -c && node tools/build/copy-demo-artifacts.mjs",
42
+ "prepublishOnly": "SHIP=1 rollup -c",
34
43
  "watch": "rollup -cw",
35
44
  "pretest": "npm run build",
36
45
  "test": "node test/run.js && node test/run-schema.js",
@@ -41,41 +50,31 @@
41
50
  "browser": {
42
51
  "express": false,
43
52
  "fs": false,
44
- "https": false,
45
- "image-size": false,
46
53
  "node:fs": false,
47
54
  "node:https": false,
48
55
  "os": false,
49
56
  "path": false
50
57
  },
51
58
  "dependencies": {
52
- "@types/node": "^22.19.20",
53
- "https": "^1.0.0",
54
- "image-size": "^2.0.2",
55
59
  "jszip": "^3.10.1"
56
60
  },
57
61
  "devDependencies": {
58
- "@eslint/js": "^9.39.4",
62
+ "@eslint/js": "^10.0.1",
59
63
  "@rollup/plugin-commonjs": "^29.0.3",
60
64
  "@rollup/plugin-node-resolve": "^16.0.3",
65
+ "@rollup/plugin-terser": "^1.0.0",
61
66
  "@stylistic/eslint-plugin": "^5.10.0",
67
+ "@types/node": "^25.9.2",
62
68
  "@typescript-eslint/eslint-plugin": "^8.60.1",
63
69
  "@typescript-eslint/parser": "^8.60.1",
64
- "eslint": "^9.39.4",
70
+ "eslint": "^10.4.1",
65
71
  "express": "^5.2.1",
66
- "gulp": "^5.0.1",
67
- "gulp-concat": "^2.6.1",
68
- "gulp-delete-lines": "0.0.7",
69
- "gulp-ignore": "^3.0.0",
70
- "gulp-insert": "^0.5.0",
71
- "gulp-sourcemaps": "^3.0.0",
72
- "gulp-uglify": "^3.0.2",
72
+ "playwright": "^1.60.0",
73
73
  "rollup": "^4.61.1",
74
74
  "rollup-plugin-typescript2": "^0.37.0",
75
- "tslib": "^2.8.0",
76
- "typescript": "^5.9.3",
77
- "typescript-eslint": "^8.60.1",
78
- "playwright": "^1.60.0"
75
+ "tslib": "^2.8.1",
76
+ "typescript": "^6.0.3",
77
+ "typescript-eslint": "^8.60.1"
79
78
  },
80
79
  "repository": {
81
80
  "type": "git",
package/types/index.d.ts CHANGED
@@ -124,6 +124,14 @@ declare class PptxGenJS {
124
124
  * @deprecated use `addSlide(IAddSlideOptions)`
125
125
  */
126
126
  addSlide(masterName?: string): PptxGenJS.Slide
127
+ /**
128
+ * Compute evenly-spaced grid cell positions within a bounding area.
129
+ * - Pure layout helper: returns one `{ x, y, w, h }` (inches) per item; emits no slide content.
130
+ * @param {LayoutGridProps} props grid options
131
+ * @returns {LayoutGridResult} array of `{ x, y, w, h }` cells (inches), one per item
132
+ * @example const grid = pptx.layoutGrid({ items: 6, columns: 3, area: { x: 0.5, y: 2, w: 12, h: 4 }, gap: 0.2 })
133
+ */
134
+ layoutGrid(props: PptxGenJS.LayoutGridProps): PptxGenJS.LayoutGridResult
127
135
  /**
128
136
  * Create a custom Slide Layout in any size
129
137
  * @param {PresLayout} layout an object with user-defined w/h
@@ -845,6 +853,39 @@ declare namespace PptxGenJS {
845
853
  * @example '75%' // coordinate as percentage of slide size
846
854
  */
847
855
  export type Coord = number | `${number}%`
856
+ export interface LayoutGridArea {
857
+ x: number
858
+ y: number
859
+ w: number
860
+ h: number
861
+ }
862
+ export interface LayoutGridProps {
863
+ /** Number of items (cells) to position */
864
+ items: number
865
+ /** Items per row (rows are auto-calculated) */
866
+ columns: number
867
+ /** Bounding box (inches) to lay the grid out within */
868
+ area: LayoutGridArea
869
+ /** Gap between cells (inches) - used for both axes unless overridden @default 0.2 */
870
+ gap?: number
871
+ /** Horizontal gap override (inches) */
872
+ gapX?: number
873
+ /** Vertical gap override (inches) */
874
+ gapY?: number
875
+ /** Inner padding per cell (inches) - insets each returned cell box @default 0 */
876
+ padding?: number
877
+ /** Horizontal alignment of a partial last row @default 'start' */
878
+ align?: 'start' | 'center' | 'stretch'
879
+ /** Vertical alignment (reserved) @default 'start' */
880
+ valign?: 'start' | 'center' | 'stretch'
881
+ }
882
+ export interface LayoutGridCell {
883
+ x: number
884
+ y: number
885
+ w: number
886
+ h: number
887
+ }
888
+ export type LayoutGridResult = LayoutGridCell[]
848
889
  export interface PositionProps {
849
890
  /**
850
891
  * Horizontal position
@@ -0,0 +1,40 @@
1
+ // Type definitions for @jsamuel1/pptxgenjs/utils
2
+ // Optional, format-agnostic helpers (not part of the main PptxGenJS class).
3
+
4
+ /** A resolved theme palette. All colours are 6-digit hex strings (no leading `#`). */
5
+ export interface ThemePalette {
6
+ /** Background colour. */
7
+ bg: string
8
+ /** Card/surface (secondary background) colour. */
9
+ bgSecondary: string
10
+ /** Primary accent colour. */
11
+ accent: string
12
+ /** Lighter accent colour. */
13
+ accentSoft: string
14
+ /** Primary text colour. */
15
+ text: string
16
+ /** Muted/secondary text colour. */
17
+ textSecondary: string
18
+ /** Font family. */
19
+ font: string
20
+ /** Extended palette — informational/utility colours. */
21
+ sky: string
22
+ green: string
23
+ orange: string
24
+ red: string
25
+ [key: string]: string
26
+ }
27
+
28
+ /** Options for `extractThemeFromCSS`. */
29
+ export interface ExtractThemeOptions {
30
+ /** Named fallback presets; merged over the built-ins (`dark`, `light`). */
31
+ presets?: Record<string, Partial<ThemePalette>>
32
+ /** Which preset to use as the base/fallback. @default 'dark' */
33
+ defaultPreset?: string
34
+ }
35
+
36
+ /**
37
+ * Parse CSS `:root` custom properties into a theme palette, falling back to a preset for any
38
+ * slot not present in the CSS.
39
+ */
40
+ export function extractThemeFromCSS(css: string, options?: ExtractThemeOptions): ThemePalette