@christophervr/pptx-viewer 1.4.0 → 1.4.2
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/CHANGELOG.md +8 -0
- package/dist/index.mjs +155 -36
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ All notable changes to this project are documented here.
|
|
|
4
4
|
This file is generated from [Conventional Commits](https://www.conventionalcommits.org)
|
|
5
5
|
by [git-cliff](https://git-cliff.org); do not edit it by hand.
|
|
6
6
|
|
|
7
|
+
## [1.4.1](https://github.com/ChristopherVR/pptx-viewer/releases/tag/@christophervr/pptx-viewer@1.4.1) - 2026-07-05
|
|
8
|
+
|
|
9
|
+
## [1.4.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/@christophervr/pptx-viewer@1.4.0) - 2026-07-05
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- **core,cli:** Add react, angular, vue to npm keywords (by @ChristopherVR) ([528ec61](https://github.com/ChristopherVR/pptx-viewer/commit/528ec6182bb77c07444dd0e93560b65e604b9524))
|
|
14
|
+
|
|
7
15
|
## [1.3.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/@christophervr/pptx-viewer@1.3.0) - 2026-07-04
|
|
8
16
|
|
|
9
17
|
## [1.2.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/@christophervr/pptx-viewer@1.2.0) - 2026-07-04
|
package/dist/index.mjs
CHANGED
|
@@ -412,6 +412,7 @@ var REACT_APP_TSX = `import { useCallback, useState } from 'react';
|
|
|
412
412
|
import { PptxHandler } from 'pptx-viewer-core';
|
|
413
413
|
import { PowerPointViewer } from 'pptx-react-viewer';
|
|
414
414
|
import 'pptx-react-viewer/styles.css';
|
|
415
|
+
import './i18n';
|
|
415
416
|
|
|
416
417
|
export default function App() {
|
|
417
418
|
const [content, setContent] = useState<Uint8Array | null>(null);
|
|
@@ -439,20 +440,58 @@ export default function App() {
|
|
|
439
440
|
}
|
|
440
441
|
|
|
441
442
|
return (
|
|
442
|
-
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap:
|
|
443
|
-
<
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
443
|
+
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 24, height: '100vh', fontFamily: 'system-ui, sans-serif' }}>
|
|
444
|
+
<h1 style={{ margin: 0, fontSize: 24, fontWeight: 500, color: '#e5e7eb' }}>Open a Presentation</h1>
|
|
445
|
+
<label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '10px 20px', borderRadius: 8, border: '1px solid #4b5563', background: '#1f2937', color: '#f3f4f6', cursor: 'pointer', fontSize: 14, transition: 'background 0.15s' }}>
|
|
446
|
+
Choose .pptx file
|
|
447
|
+
<input
|
|
448
|
+
type="file"
|
|
449
|
+
accept=".pptx"
|
|
450
|
+
style={{ display: 'none' }}
|
|
451
|
+
onChange={(e) => {
|
|
452
|
+
const file = e.target.files?.[0];
|
|
453
|
+
if (file) loadFile(file);
|
|
454
|
+
}}
|
|
455
|
+
/>
|
|
456
|
+
</label>
|
|
457
|
+
<span style={{ color: '#6b7280', fontSize: 13 }}>or</span>
|
|
458
|
+
<button
|
|
459
|
+
onClick={() => void newPresentation()}
|
|
460
|
+
style={{ padding: '10px 20px', borderRadius: 8, border: 'none', background: '#2563eb', color: '#fff', cursor: 'pointer', fontSize: 14, fontWeight: 500 }}
|
|
461
|
+
>
|
|
462
|
+
New Presentation
|
|
463
|
+
</button>
|
|
452
464
|
</div>
|
|
453
465
|
);
|
|
454
466
|
}
|
|
455
467
|
`;
|
|
468
|
+
var REACT_I18N_TS = `import { createInstance } from 'i18next';
|
|
469
|
+
import { translationsEn, keyToLabel } from 'pptx-react-viewer/i18n';
|
|
470
|
+
import { initReactI18next } from 'react-i18next';
|
|
471
|
+
|
|
472
|
+
const i18n = createInstance();
|
|
473
|
+
|
|
474
|
+
i18n.use(initReactI18next).init({
|
|
475
|
+
resources: {
|
|
476
|
+
en: { translation: translationsEn },
|
|
477
|
+
},
|
|
478
|
+
lng: 'en',
|
|
479
|
+
fallbackLng: 'en',
|
|
480
|
+
interpolation: { escapeValue: false },
|
|
481
|
+
parseMissingKeyHandler: (key: string) => keyToLabel(key),
|
|
482
|
+
missingKeyHandler: false,
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
export default i18n;
|
|
486
|
+
`;
|
|
487
|
+
var REACT_INDEX_CSS = `:root {
|
|
488
|
+
color-scheme: light dark;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
body {
|
|
492
|
+
margin: 0;
|
|
493
|
+
}
|
|
494
|
+
`;
|
|
456
495
|
var VUE_APP_VUE = `<script setup lang="ts">
|
|
457
496
|
import { ref } from 'vue';
|
|
458
497
|
import { PptxHandler } from 'pptx-viewer-core';
|
|
@@ -485,12 +524,34 @@ async function newPresentation() {
|
|
|
485
524
|
<div v-if="content" style="height: 100vh">
|
|
486
525
|
<PowerPointViewer :content="content" can-edit style="height: 100%" />
|
|
487
526
|
</div>
|
|
488
|
-
<div v-else style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap:
|
|
489
|
-
<
|
|
490
|
-
<
|
|
527
|
+
<div v-else style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px; height: 100vh; font-family: system-ui, sans-serif">
|
|
528
|
+
<h1 style="margin: 0; font-size: 24px; font-weight: 500; color: #e5e7eb">Open a Presentation</h1>
|
|
529
|
+
<label style="display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; border-radius: 8px; border: 1px solid #4b5563; background: #1f2937; color: #f3f4f6; cursor: pointer; font-size: 14px">
|
|
530
|
+
Choose .pptx file
|
|
531
|
+
<input type="file" accept=".pptx" style="display: none" @change="onPick" />
|
|
532
|
+
</label>
|
|
533
|
+
<span style="color: #6b7280; font-size: 13px">or</span>
|
|
534
|
+
<button style="padding: 10px 20px; border-radius: 8px; border: none; background: #2563eb; color: #fff; cursor: pointer; font-size: 14px; font-weight: 500" @click="newPresentation">New Presentation</button>
|
|
491
535
|
</div>
|
|
492
536
|
</template>
|
|
493
537
|
`;
|
|
538
|
+
var VUE_MAIN_TS = `import { createApp } from 'vue';
|
|
539
|
+
import { createI18n } from 'vue-i18n';
|
|
540
|
+
import { translationsEn, keyToLabel } from 'pptx-vue-viewer/i18n';
|
|
541
|
+
import App from './App.vue';
|
|
542
|
+
|
|
543
|
+
const i18n = createI18n({
|
|
544
|
+
legacy: false,
|
|
545
|
+
locale: 'en',
|
|
546
|
+
fallbackLocale: 'en',
|
|
547
|
+
messages: { en: translationsEn },
|
|
548
|
+
missing: (_locale, key) => keyToLabel(key),
|
|
549
|
+
missingWarn: false,
|
|
550
|
+
fallbackWarn: false,
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
createApp(App).use(i18n).mount('#app');
|
|
554
|
+
`;
|
|
494
555
|
var ANGULAR_APP_TS = `import { Component, signal } from '@angular/core';
|
|
495
556
|
import { PptxHandler } from 'pptx-viewer-core';
|
|
496
557
|
import { PowerPointViewerComponent } from 'pptx-angular-viewer';
|
|
@@ -505,9 +566,14 @@ import { PowerPointViewerComponent } from 'pptx-angular-viewer';
|
|
|
505
566
|
<pptx-power-point-viewer [content]="c" [canEdit]="true" style="height: 100%" />
|
|
506
567
|
</div>
|
|
507
568
|
} @else {
|
|
508
|
-
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap:
|
|
509
|
-
<
|
|
510
|
-
<
|
|
569
|
+
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px; height: 100vh; font-family: system-ui, sans-serif">
|
|
570
|
+
<h1 style="margin: 0; font-size: 24px; font-weight: 500; color: #e5e7eb">Open a Presentation</h1>
|
|
571
|
+
<label style="display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; border-radius: 8px; border: 1px solid #4b5563; background: #1f2937; color: #f3f4f6; cursor: pointer; font-size: 14px">
|
|
572
|
+
Choose .pptx file
|
|
573
|
+
<input type="file" accept=".pptx" style="display: none" (change)="onPick($event)" />
|
|
574
|
+
</label>
|
|
575
|
+
<span style="color: #6b7280; font-size: 13px">or</span>
|
|
576
|
+
<button style="padding: 10px 20px; border-radius: 8px; border: none; background: #2563eb; color: #fff; cursor: pointer; font-size: 14px; font-weight: 500" (click)="newPresentation()">New Presentation</button>
|
|
511
577
|
</div>
|
|
512
578
|
}
|
|
513
579
|
\`,
|
|
@@ -531,6 +597,36 @@ export class App {
|
|
|
531
597
|
}
|
|
532
598
|
}
|
|
533
599
|
`;
|
|
600
|
+
var ANGULAR_MAIN_TS = `import 'zone.js';
|
|
601
|
+
import '@angular/compiler';
|
|
602
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
603
|
+
import { Injectable } from '@angular/core';
|
|
604
|
+
import type { MissingTranslationHandlerParams } from '@ngx-translate/core';
|
|
605
|
+
import { MissingTranslationHandler, provideTranslateService } from '@ngx-translate/core';
|
|
606
|
+
import { keyToLabel } from 'pptx-angular-viewer';
|
|
607
|
+
|
|
608
|
+
import { App } from './app/app.ts';
|
|
609
|
+
|
|
610
|
+
@Injectable()
|
|
611
|
+
class LabelFallbackHandler implements MissingTranslationHandler {
|
|
612
|
+
handle(params: MissingTranslationHandlerParams): string {
|
|
613
|
+
return keyToLabel(params.key);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
bootstrapApplication(App, {
|
|
618
|
+
providers: [
|
|
619
|
+
provideTranslateService({
|
|
620
|
+
lang: 'en',
|
|
621
|
+
fallbackLang: 'en',
|
|
622
|
+
missingTranslationHandler: {
|
|
623
|
+
provide: MissingTranslationHandler,
|
|
624
|
+
useClass: LabelFallbackHandler,
|
|
625
|
+
},
|
|
626
|
+
}),
|
|
627
|
+
],
|
|
628
|
+
}).catch((err) => console.error(err));
|
|
629
|
+
`;
|
|
534
630
|
var TARGETS = [
|
|
535
631
|
{
|
|
536
632
|
id: "react",
|
|
@@ -578,7 +674,11 @@ Docs: https://www.npmjs.com/package/pptx-react-viewer`,
|
|
|
578
674
|
"react-i18next"
|
|
579
675
|
],
|
|
580
676
|
entryCandidates: ["src/App.tsx"],
|
|
581
|
-
entryContent: REACT_APP_TSX
|
|
677
|
+
entryContent: REACT_APP_TSX,
|
|
678
|
+
extraFiles: {
|
|
679
|
+
"src/i18n.ts": REACT_I18N_TS,
|
|
680
|
+
"src/index.css": REACT_INDEX_CSS
|
|
681
|
+
}
|
|
582
682
|
}
|
|
583
683
|
},
|
|
584
684
|
{
|
|
@@ -602,9 +702,16 @@ Docs: https://www.npmjs.com/package/pptx-vue-viewer`,
|
|
|
602
702
|
scaffold: {
|
|
603
703
|
command: "create-vite@latest",
|
|
604
704
|
args: (dir) => [dir, "--template", "vue-ts", "--no-interactive", "--no-immediate"],
|
|
605
|
-
extraPackages: [
|
|
705
|
+
extraPackages: [
|
|
706
|
+
"pptx-vue-viewer",
|
|
707
|
+
"pptx-viewer-core",
|
|
708
|
+
"vue-i18n",
|
|
709
|
+
"jszip",
|
|
710
|
+
"fast-xml-parser"
|
|
711
|
+
],
|
|
606
712
|
entryCandidates: ["src/App.vue"],
|
|
607
|
-
entryContent: VUE_APP_VUE
|
|
713
|
+
entryContent: VUE_APP_VUE,
|
|
714
|
+
extraFiles: { "src/main.ts": VUE_MAIN_TS }
|
|
608
715
|
}
|
|
609
716
|
},
|
|
610
717
|
{
|
|
@@ -636,10 +743,11 @@ Docs: https://www.npmjs.com/package/pptx-angular-viewer`,
|
|
|
636
743
|
"--skip-install",
|
|
637
744
|
"--no-interactive"
|
|
638
745
|
],
|
|
639
|
-
extraPackages: ["pptx-angular-viewer", "pptx-viewer-core"],
|
|
746
|
+
extraPackages: ["pptx-angular-viewer", "pptx-viewer-core", "@ngx-translate/core"],
|
|
640
747
|
// Angular v20+ generates `app.ts`; older schematics generate `app.component.ts`.
|
|
641
748
|
entryCandidates: ["src/app/app.ts", "src/app/app.component.ts"],
|
|
642
|
-
entryContent: ANGULAR_APP_TS
|
|
749
|
+
entryContent: ANGULAR_APP_TS,
|
|
750
|
+
extraFiles: { "src/main.ts": ANGULAR_MAIN_TS }
|
|
643
751
|
}
|
|
644
752
|
},
|
|
645
753
|
{
|
|
@@ -735,18 +843,19 @@ function mergePackages(targets) {
|
|
|
735
843
|
|
|
736
844
|
// src/run-command.ts
|
|
737
845
|
import { spawn } from "child_process";
|
|
738
|
-
function runCommand(command, args, cwd) {
|
|
846
|
+
function runCommand(command, args, cwd, options) {
|
|
739
847
|
return new Promise((resolve, reject) => {
|
|
740
848
|
const isWindows = process.platform === "win32";
|
|
741
|
-
const
|
|
849
|
+
const stdio = options?.silent ? "ignore" : "inherit";
|
|
850
|
+
const child = isWindows ? spawn([command, ...args].join(" "), { cwd, stdio, shell: true }) : spawn(command, args, { cwd, stdio });
|
|
742
851
|
child.on("error", reject);
|
|
743
852
|
child.on("close", (code) => resolve(code ?? 1));
|
|
744
853
|
});
|
|
745
854
|
}
|
|
746
855
|
|
|
747
856
|
// src/scaffold.ts
|
|
748
|
-
import { existsSync as existsSync3, writeFileSync } from "fs";
|
|
749
|
-
import { join as join3 } from "path";
|
|
857
|
+
import { existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
|
|
858
|
+
import { dirname, join as join3 } from "path";
|
|
750
859
|
function sanitizeProjectName(name) {
|
|
751
860
|
const cleaned = name.trim().replace(/[^a-zA-Z0-9._-]+/gu, "-").replace(/-{2,}/gu, "-").replace(/^-+|-+$/gu, "");
|
|
752
861
|
return cleaned || "pptx-viewer-app";
|
|
@@ -763,7 +872,8 @@ async function scaffoldProject(recipe, projectName, pm, cwd) {
|
|
|
763
872
|
const scaffoldExit = await runCommand(
|
|
764
873
|
"npx",
|
|
765
874
|
["--yes", recipe.command, ...recipe.args(projectName)],
|
|
766
|
-
cwd
|
|
875
|
+
cwd,
|
|
876
|
+
{ silent: true }
|
|
767
877
|
);
|
|
768
878
|
if (scaffoldExit !== 0) {
|
|
769
879
|
throw new Error(`${recipe.command} exited with code ${scaffoldExit}`);
|
|
@@ -773,6 +883,13 @@ async function scaffoldProject(recipe, projectName, pm, cwd) {
|
|
|
773
883
|
if (patchedFile) {
|
|
774
884
|
writeFileSync(join3(projectDir, patchedFile), recipe.entryContent);
|
|
775
885
|
}
|
|
886
|
+
if (recipe.extraFiles) {
|
|
887
|
+
for (const [relativePath, content] of Object.entries(recipe.extraFiles)) {
|
|
888
|
+
const fullPath = join3(projectDir, relativePath);
|
|
889
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
890
|
+
writeFileSync(fullPath, content);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
776
893
|
if (recipe.extraPackages.length > 0) {
|
|
777
894
|
const [command, args] = installCommand(pm, recipe.extraPackages);
|
|
778
895
|
const installExit = await runCommand(command, args, projectDir);
|
|
@@ -891,18 +1008,20 @@ ${dim("Skipped.")}`);
|
|
|
891
1008
|
${yellow("Scaffolded the project, but could not find an entry file to wire up automatically.")} See the quick-start snippet below and add it yourself.`
|
|
892
1009
|
);
|
|
893
1010
|
}
|
|
894
|
-
|
|
895
|
-
`
|
|
896
|
-
${
|
|
897
|
-
|
|
1011
|
+
for (const configTarget of configTargets) {
|
|
1012
|
+
console.log(`
|
|
1013
|
+
${configTarget.nextSteps}
|
|
1014
|
+
`);
|
|
1015
|
+
}
|
|
1016
|
+
console.log(`
|
|
1017
|
+
${green("\u2714")} ${bold("Done!")} Starting dev server...
|
|
1018
|
+
`);
|
|
1019
|
+
const projectDir = result.projectDir;
|
|
1020
|
+
const devExit = await runCommand(pm, ["run", "dev"], projectDir);
|
|
1021
|
+
if (devExit !== 0) {
|
|
1022
|
+
console.log(`
|
|
898
1023
|
${cyan(`cd ${projectName}`)}
|
|
899
1024
|
${cyan(`${pm} run dev`)}
|
|
900
|
-
|
|
901
|
-
${target.nextSteps}
|
|
902
|
-
`
|
|
903
|
-
);
|
|
904
|
-
for (const configTarget of configTargets) {
|
|
905
|
-
console.log(`${configTarget.nextSteps}
|
|
906
1025
|
`);
|
|
907
1026
|
}
|
|
908
1027
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@christophervr/pptx-viewer",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Interactive installer for the pptx-viewer family of packages: React, Vue, and Angular viewer components, the framework-agnostic core engine, and the MCP server.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|