pptx-vanilla-viewer 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/styles.css CHANGED
@@ -38,7 +38,7 @@
38
38
  .pptxv:focus { outline: none; }
39
39
  .pptxv:focus-visible { outline: 2px solid var(--pptx-ring); outline-offset: -2px; }
40
40
  .pptxv :is(button, a, input, select, textarea, [tabindex]):focus-visible { outline: 2px solid var(--pptx-ring) !important; outline-offset: 2px; }
41
- .pptxv :is(button, [role='button']) { min-width: 24px; min-height: 24px; touch-action: manipulation; }
41
+ .pptxv :is(button, [role='button']):not([role='switch']):not([data-pptx-compact]) { min-width: 24px; min-height: 24px; touch-action: manipulation; }
42
42
  @media (prefers-reduced-motion: reduce) {
43
43
  .pptxv *, .pptxv *::before, .pptxv *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
44
44
  }
@@ -157,6 +157,12 @@
157
157
  flex-direction: column;
158
158
  gap: 8px;
159
159
  }
160
+ /* Virtualized rail: block layout for the absolute-positioned window. :where()
161
+ keeps specificity at one class so the mobile and presenting display:none
162
+ rules below still win (a naked two-class rule, or the inline style this
163
+ replaces, would override them). */
164
+ .pptxv-thumbs:where(.pptxv-thumbs-virtualized) { display: block; }
165
+ .pptxv-thumbs[hidden] { display: none; }
160
166
  .pptxv-thumb {
161
167
  display: flex;
162
168
  align-items: flex-start;
@@ -519,21 +525,104 @@
519
525
  font-size: 12px;
520
526
  }
521
527
  .pptxv-inspector[hidden] { display: none; }
522
- .pptxv-inspector-header {
528
+ /* React-style tab strip: [Elements | Properties | Comments]. */
529
+ .pptxv-inspector-tabs {
523
530
  display: flex;
524
531
  align-items: center;
525
- justify-content: space-between;
532
+ gap: 2px;
533
+ padding: 6px 8px;
534
+ border-bottom: 1px solid var(--pptx-border);
535
+ }
536
+ .pptxv-inspector-tab {
537
+ padding: 4px 8px;
538
+ border: none;
539
+ border-radius: 4px;
540
+ background: var(--pptx-muted);
541
+ color: var(--pptx-muted-foreground);
542
+ font: inherit;
543
+ font-size: 11px;
544
+ cursor: pointer;
545
+ }
546
+ .pptxv-inspector-tab:hover { color: var(--pptx-foreground); background: var(--pptx-accent); }
547
+ .pptxv-inspector-tab.is-active { background: var(--pptx-primary); color: var(--pptx-primary-foreground, #fff); }
548
+ /* Elements tab: layer-order rows. */
549
+ .pptxv-inspector-layer-list { display: flex; flex-direction: column; gap: 2px; }
550
+ .pptxv-inspector-layer-row {
551
+ display: flex;
552
+ align-items: center;
553
+ gap: 8px;
526
554
  width: 100%;
527
- padding: 8px 12px;
555
+ padding: 4px 8px;
528
556
  border: none;
529
- border-bottom: 1px solid var(--pptx-border);
557
+ border-radius: 4px;
530
558
  background: transparent;
531
- color: var(--pptx-foreground);
559
+ color: inherit;
532
560
  font: inherit;
533
- font-weight: 600;
561
+ text-align: left;
562
+ cursor: pointer;
563
+ }
564
+ .pptxv-inspector-layer-row:hover { background: var(--pptx-muted); }
565
+ .pptxv-inspector-layer-row.is-selected { background: color-mix(in srgb, var(--pptx-primary) 25%, transparent); color: var(--pptx-primary); }
566
+ .pptxv-inspector-layer-num { min-width: 16px; color: var(--pptx-muted-foreground); text-align: right; }
567
+ .pptxv-inspector-layer-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
568
+ /* No-selection Properties deck panel + Comments tab. */
569
+ .pptxv-inspector-row-value { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; }
570
+ .pptxv-inspector-deck[hidden] { display: none; }
571
+ .pptxv-inspector-deck-btn {
572
+ width: 100%;
573
+ margin-top: 4px;
574
+ padding: 5px 8px;
575
+ border: 1px solid var(--pptx-border);
576
+ border-radius: var(--pptx-radius);
577
+ background: var(--pptx-muted);
578
+ color: inherit;
579
+ font: inherit;
580
+ font-size: 11px;
581
+ cursor: pointer;
582
+ }
583
+ .pptxv-inspector-deck-btn:hover { background: var(--pptx-accent); }
584
+ .pptxv-inspector-deck-btn:disabled { opacity: 0.5; cursor: default; }
585
+ .pptxv-inspector-deck-btn-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; }
586
+ .pptxv-inspector-theme-select { width: 100%; margin-bottom: 6px; }
587
+ .pptxv-inspector-override-rows { display: flex; flex-direction: column; gap: 5px; margin-top: 6px; }
588
+ .pptxv-inspector-override-row { display: grid; grid-template-columns: minmax(0, 1fr) 14px minmax(0, 1fr); align-items: center; gap: 6px; }
589
+ .pptxv-inspector-override-row .pptxv-inspector-row-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
590
+ .pptxv-inspector-override-swatch {
591
+ width: 14px;
592
+ height: 14px;
593
+ border: 1px solid var(--pptx-border);
594
+ border-radius: 3px;
595
+ flex-shrink: 0;
596
+ }
597
+ .pptxv-inspector-comment { padding: 6px 0; border-bottom: 1px solid color-mix(in srgb, var(--pptx-border) 60%, transparent); }
598
+ .pptxv-inspector-comment.is-resolved { opacity: 0.6; }
599
+ .pptxv-inspector-comment-meta { font-size: 11px; font-weight: 600; }
600
+ .pptxv-inspector-comment-text { margin: 2px 0 4px; }
601
+ .pptxv-inspector-comment-actions { display: flex; gap: 6px; }
602
+ .pptxv-inspector-comment-action {
603
+ padding: 2px 6px;
604
+ border: none;
605
+ border-radius: 4px;
606
+ background: var(--pptx-muted);
607
+ color: var(--pptx-muted-foreground);
608
+ font: inherit;
609
+ font-size: 10px;
534
610
  cursor: pointer;
535
611
  }
536
- .pptxv-inspector-header:hover { background: var(--pptx-accent); color: var(--pptx-accent-foreground); }
612
+ .pptxv-inspector-comment-action:hover { background: var(--pptx-accent); color: var(--pptx-accent-foreground); }
613
+ .pptxv-inspector-comment-add[hidden] { display: none; }
614
+ .pptxv-inspector-comment-input {
615
+ width: 100%;
616
+ margin-top: 6px;
617
+ padding: 6px 8px;
618
+ border: 1px solid var(--pptx-border);
619
+ border-radius: var(--pptx-radius);
620
+ background: var(--pptx-background);
621
+ color: var(--pptx-foreground);
622
+ font: inherit;
623
+ font-size: 12px;
624
+ resize: vertical;
625
+ }
537
626
  .pptxv-inspector-body { padding: 10px 12px; }
538
627
  .pptxv-inspector-body[hidden] { display: none; }
539
628
  .pptxv-inspector-empty { color: var(--pptx-muted-foreground); margin: 0; }
@@ -718,12 +807,16 @@
718
807
  }
719
808
 
720
809
  /* ── Tab content + groups ────────────────────────────────────────────── */
810
+ /* One horizontal row (React: flex flex-nowrap + overflow-x) instead of the
811
+ * old two-row wrap; each group is a column with its label below the buttons. */
721
812
  .pptxv-ribbon-tab-content {
722
813
  display: flex;
723
- flex-wrap: wrap;
724
- align-items: flex-start;
814
+ flex-wrap: nowrap;
815
+ align-items: stretch;
725
816
  gap: 2px;
726
- padding: 6px 8px;
817
+ padding: 4px 8px;
818
+ overflow-x: auto;
819
+ overflow-y: hidden;
727
820
  }
728
821
  .pptxv-ribbon-tab-content[hidden] { display: none; }
729
822
  /* Design tab theme galleries: .pptxv-btn is a fixed 28x28 icon-button
@@ -741,21 +834,33 @@
741
834
  }
742
835
  .pptxv-rgroup {
743
836
  display: flex;
837
+ flex: none;
744
838
  flex-direction: column;
745
839
  align-items: center;
840
+ justify-content: space-between;
746
841
  gap: 2px;
747
842
  padding: 2px 8px;
748
- border-right: 1px solid var(--pptx-border);
843
+ border-right: 1px solid color-mix(in srgb, var(--pptx-border) 40%, transparent);
749
844
  }
750
845
  .pptxv-rgroup:last-child { border-right: none; }
751
- .pptxv-rgroup-row { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; }
846
+ .pptxv-rgroup-row { display: flex; flex-wrap: nowrap; align-items: center; gap: 2px; }
847
+ /* Sentence-case tiny muted label below each group (React: 9px, no uppercase). */
752
848
  .pptxv-rgroup-label {
753
849
  font-size: 9px;
850
+ line-height: 1;
754
851
  color: var(--pptx-muted-foreground);
755
- text-transform: uppercase;
756
- letter-spacing: 0.03em;
757
852
  }
758
853
  .pptxv-rgroup .pptxv-btn.is-active { background: var(--pptx-accent); color: var(--pptx-accent-foreground); }
854
+ /* Labelled pill button (React's pill token): icon + text on a muted chip. */
855
+ .pptxv-btn.pptxv-btn-pill {
856
+ width: auto;
857
+ gap: 6px;
858
+ padding: 0 10px;
859
+ background: var(--pptx-muted);
860
+ font-size: 12px;
861
+ white-space: nowrap;
862
+ }
863
+ .pptxv-btn-label { font-size: 12px; }
759
864
 
760
865
  /* ── Shape insert grid ───────────────────────────────────────────────── */
761
866
  .pptxv-shape-grid {
@@ -904,6 +1009,124 @@
904
1009
  .pptxv-backstage nav button{display:flex;align-items:center;gap:12px;white-space:normal}.pptxv-backstage nav button>span:first-child{display:grid;width:17px;flex:none;place-items:center}
905
1010
 
906
1011
 
1012
+ /* ── Primary-row quick actions ──────────────────────────────────────────── */
1013
+ .pptxv-primary-sep { width: 1px; align-self: stretch; margin: 0 4px; background: color-mix(in srgb, var(--pptx-border) 40%, transparent); }
1014
+ /* React-style "Present" split button + its options dropdown. */
1015
+ .pptxv-present-split { position: relative; display: inline-flex; align-items: stretch; border-left: 1px solid var(--pptx-border); }
1016
+ .pptxv-present-main {
1017
+ padding: 2px 8px;
1018
+ border: none;
1019
+ background: transparent;
1020
+ color: var(--pptx-foreground);
1021
+ font: inherit;
1022
+ font-size: 12px;
1023
+ cursor: pointer;
1024
+ }
1025
+ .pptxv-present-main:hover { background: var(--pptx-accent); }
1026
+ .pptxv-present-caret {
1027
+ display: inline-flex;
1028
+ align-items: center;
1029
+ padding: 0 4px;
1030
+ border: none;
1031
+ border-left: 1px solid var(--pptx-border);
1032
+ background: transparent;
1033
+ color: var(--pptx-foreground);
1034
+ cursor: pointer;
1035
+ }
1036
+ .pptxv-present-caret:hover, .pptxv-present-caret.is-active { background: var(--pptx-accent); }
1037
+ .pptxv-present-caret svg { width: 12px; height: 12px; }
1038
+ /* Right-aligned popover menus (Present options + "..." overflow). */
1039
+ .pptxv-primary-menu {
1040
+ position: absolute;
1041
+ top: calc(100% + 4px);
1042
+ right: 0;
1043
+ z-index: 40;
1044
+ min-width: 190px;
1045
+ max-height: 320px;
1046
+ overflow-y: auto;
1047
+ padding: 4px;
1048
+ border: 1px solid var(--pptx-border);
1049
+ border-radius: var(--pptx-radius);
1050
+ background: var(--pptx-card);
1051
+ color: var(--pptx-card-foreground);
1052
+ box-shadow: 0 6px 20px rgb(0 0 0 / 0.25);
1053
+ }
1054
+ .pptxv-primary-menu[hidden] { display: none; }
1055
+ .pptxv-primary-menu-item {
1056
+ display: block;
1057
+ width: 100%;
1058
+ padding: 6px 8px;
1059
+ border: none;
1060
+ border-radius: 4px;
1061
+ background: transparent;
1062
+ color: inherit;
1063
+ font: inherit;
1064
+ font-size: 12px;
1065
+ text-align: left;
1066
+ white-space: nowrap;
1067
+ cursor: pointer;
1068
+ }
1069
+ .pptxv-primary-menu-item:hover { background: var(--pptx-accent); color: var(--pptx-accent-foreground); }
1070
+ .pptxv-primary-menu-sep { margin: 4px 0; border-top: 1px solid color-mix(in srgb, var(--pptx-border) 60%, transparent); }
1071
+ .pptxv-primary-menu-host { position: relative; display: inline-flex; }
1072
+ /* Custom-shows quick action ("+ Show"). */
1073
+ .pptxv-show-btn {
1074
+ padding: 2px 8px;
1075
+ border: none;
1076
+ border-radius: var(--pptx-radius);
1077
+ background: var(--pptx-muted);
1078
+ color: var(--pptx-foreground);
1079
+ font: inherit;
1080
+ font-size: 11px;
1081
+ white-space: nowrap;
1082
+ cursor: pointer;
1083
+ }
1084
+ .pptxv-show-btn:hover { background: var(--pptx-accent); }
1085
+ /* ── Tab-row right-side actions ── */
1086
+ /* Right side of the tab row: Record + Share, matching React's TabRowActions. */
1087
+ .pptxv-tabrow-spacer { flex: 1; }
1088
+ .pptxv-tabrow-actions { display: inline-flex; align-items: center; gap: 4px; padding-right: 4px; }
1089
+ .pptxv-tabrow-record {
1090
+ display: inline-flex;
1091
+ align-items: center;
1092
+ gap: 5px;
1093
+ padding: 3px 9px;
1094
+ border: none;
1095
+ border-radius: 3px;
1096
+ background: transparent;
1097
+ color: var(--pptx-muted-foreground);
1098
+ font: inherit;
1099
+ font-size: 11px;
1100
+ font-weight: 500;
1101
+ white-space: nowrap;
1102
+ cursor: pointer;
1103
+ }
1104
+ .pptxv-tabrow-record:hover { background: var(--pptx-accent); color: var(--pptx-foreground); }
1105
+ .pptxv-tabrow-record-dot { width: 8px; height: 8px; border-radius: 50%; background: #ef4444; }
1106
+ .pptxv-tabrow-share, .pptxv-tabrow-share.pptxv-btn {
1107
+ display: inline-flex;
1108
+ align-items: center;
1109
+ gap: 4px;
1110
+ width: auto;
1111
+ height: auto;
1112
+ padding: 3px 10px;
1113
+ border: none;
1114
+ border-radius: 3px;
1115
+ background: var(--pptx-primary);
1116
+ color: var(--pptx-primary-foreground, #fff);
1117
+ font: inherit;
1118
+ font-size: 11px;
1119
+ font-weight: 500;
1120
+ white-space: nowrap;
1121
+ cursor: pointer;
1122
+ }
1123
+ .pptxv-tabrow-share:hover, .pptxv-tabrow-share.pptxv-btn:hover:not(:disabled) {
1124
+ background: color-mix(in srgb, var(--pptx-primary) 90%, #000);
1125
+ color: var(--pptx-primary-foreground, #fff);
1126
+ }
1127
+ .pptxv-tabrow-share svg { width: 12px; height: 12px; }
1128
+
1129
+
907
1130
  .pptxv-props-overlay { position:fixed; inset:0; z-index:210; display:grid; place-items:center; background:#0009; }
908
1131
  .pptxv-props-scrim { position:absolute; inset:0; width:100%; height:100%; border:0; background:transparent; }
909
1132
  .pptxv-props-dialog { position:relative; width:min(680px,calc(100vw - 32px)); max-height:calc(100vh - 40px); overflow:auto; border:1px solid var(--pptx-border); border-radius:10px; background:var(--pptx-card); color:var(--pptx-card-foreground); box-shadow:0 24px 80px #0008; }
@@ -1505,6 +1728,111 @@
1505
1728
  }
1506
1729
 
1507
1730
 
1731
+ /* ── Docked Animation panel ──────────────────────────────────────────── */
1732
+ .pptxv-inspector-animation {
1733
+ display: grid;
1734
+ gap: 6px;
1735
+ flex: none;
1736
+ padding: 8px 10px;
1737
+ border-top: 1px solid var(--pptx-border);
1738
+ max-height: 40%;
1739
+ overflow-y: auto;
1740
+ font-size: 11px;
1741
+ }
1742
+ .pptxv-inspector-animation[hidden] { display: none; }
1743
+ .pptxv-anim-header { display: flex; align-items: center; justify-content: space-between; }
1744
+ .pptxv-anim-preview-btn {
1745
+ padding: 2px 6px;
1746
+ border: none;
1747
+ border-radius: var(--pptx-radius);
1748
+ background: transparent;
1749
+ color: var(--pptx-primary);
1750
+ font-size: 10px;
1751
+ cursor: pointer;
1752
+ }
1753
+ .pptxv-anim-preview-btn:hover { background: var(--pptx-accent); }
1754
+ .pptxv-anim-field { display: grid; gap: 2px; font-size: 11px; }
1755
+ .pptxv-anim-field > span { color: var(--pptx-muted-foreground); }
1756
+ .pptxv-anim-field :is(select, input) {
1757
+ min-width: 0;
1758
+ width: 100%;
1759
+ padding: 3px;
1760
+ border: 1px solid var(--pptx-border);
1761
+ border-radius: var(--pptx-radius);
1762
+ background: var(--pptx-muted);
1763
+ color: var(--pptx-foreground);
1764
+ }
1765
+ .pptxv-anim-options { display: grid; gap: 6px; }
1766
+ .pptxv-anim-options[hidden] { display: none; }
1767
+ .pptxv-anim-direction { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
1768
+ .pptxv-anim-direction > span { flex-basis: 100%; }
1769
+ .pptxv-anim-direction-btn {
1770
+ padding: 3px 6px;
1771
+ border: 1px solid var(--pptx-border);
1772
+ border-radius: var(--pptx-radius);
1773
+ background: var(--pptx-muted);
1774
+ color: var(--pptx-muted-foreground);
1775
+ font-size: 10px;
1776
+ cursor: pointer;
1777
+ }
1778
+ .pptxv-anim-direction-btn:hover:not(:disabled) { background: var(--pptx-accent); color: var(--pptx-accent-foreground); }
1779
+ .pptxv-anim-direction-btn.is-active {
1780
+ border-color: var(--pptx-primary);
1781
+ background: color-mix(in srgb, var(--pptx-primary) 20%, transparent);
1782
+ color: var(--pptx-primary);
1783
+ }
1784
+ .pptxv-anim-timeline { display: grid; gap: 4px; }
1785
+ .pptxv-anim-timeline[hidden] { display: none; }
1786
+ .pptxv-anim-bar {
1787
+ position: relative;
1788
+ height: 22px;
1789
+ overflow: hidden;
1790
+ border: 1px solid var(--pptx-border);
1791
+ border-radius: var(--pptx-radius);
1792
+ background: color-mix(in srgb, var(--pptx-muted) 50%, transparent);
1793
+ }
1794
+ .pptxv-anim-bar-seg { position: absolute; top: 2px; bottom: 2px; border-radius: 2px; }
1795
+ .pptxv-anim-bar-seg.is-entrance { background: rgb(34 197 94 / 0.6); }
1796
+ .pptxv-anim-bar-seg.is-emphasis { background: rgb(234 179 8 / 0.6); }
1797
+ .pptxv-anim-bar-seg.is-exit { background: rgb(239 68 68 / 0.6); }
1798
+ .pptxv-anim-bar-seg.is-none { background: color-mix(in srgb, var(--pptx-muted-foreground) 40%, transparent); }
1799
+ .pptxv-anim-bar-seg.is-selected { outline: 1px solid var(--pptx-ring); }
1800
+
1801
+ /* ── Comments tab: threads, replies, edit-in-place ───────────────────── */
1802
+ .pptxv-inspector-comment-badge {
1803
+ margin-left: 6px;
1804
+ padding: 1px 6px;
1805
+ border-radius: 999px;
1806
+ background: rgb(34 197 94 / 0.25);
1807
+ color: rgb(34 197 94);
1808
+ font-size: 9px;
1809
+ font-weight: 500;
1810
+ }
1811
+ .pptxv-inspector-comment.is-reply {
1812
+ border-bottom: none;
1813
+ padding: 4px 0 4px 8px;
1814
+ border-left: 2px solid color-mix(in srgb, var(--pptx-primary) 40%, transparent);
1815
+ }
1816
+ .pptxv-inspector-comment-replies { margin-top: 4px; display: grid; gap: 2px; }
1817
+ .pptxv-inspector-comment-replies-toggle {
1818
+ margin-top: 4px;
1819
+ padding: 0;
1820
+ border: none;
1821
+ background: transparent;
1822
+ color: var(--pptx-muted-foreground);
1823
+ font-size: 10px;
1824
+ text-align: left;
1825
+ cursor: pointer;
1826
+ }
1827
+ .pptxv-inspector-comment-replies-toggle:hover { color: var(--pptx-foreground); }
1828
+ .pptxv-inspector-comment-edit,
1829
+ .pptxv-inspector-comment-reply-form { display: grid; gap: 4px; margin-top: 4px; }
1830
+ .pptxv-inspector-comment-reply-form {
1831
+ padding-left: 8px;
1832
+ border-left: 2px solid color-mix(in srgb, var(--pptx-primary) 40%, transparent);
1833
+ }
1834
+
1835
+
1508
1836
  .pptxv-account { display: flex; flex-direction: column; gap: 28px; max-width: 640px; margin-top: 24px; }
1509
1837
  .pptxv-account-section { padding: 20px; border: 1px solid var(--pptx-border); border-radius: 8px; background: var(--pptx-card); color: var(--pptx-card-foreground); }
1510
1838
  .pptxv-account-section h2 { margin: 0 0 14px; font-size: 14px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-vanilla-viewer",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Zero-framework PowerPoint viewer: render PPTX slides in the browser with plain DOM, no React/Vue/Angular required.",
5
5
  "keywords": [
6
6
  "javascript",
@@ -56,8 +56,10 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "dompurify": "^3.4.12",
59
+ "fast-xml-parser": "^5.10.1",
59
60
  "html2canvas-pro": "^2.2.4",
60
61
  "jspdf": "^4.2.1",
62
+ "jszip": "^3.10.1",
61
63
  "lucide": "^1.25.0"
62
64
  },
63
65
  "devDependencies": {
@@ -71,10 +73,6 @@
71
73
  "y-websocket": "^3.0.0",
72
74
  "yjs": "^13.6.31"
73
75
  },
74
- "peerDependencies": {
75
- "fast-xml-parser": "^5.10.1",
76
- "jszip": "^3.10.1"
77
- },
78
76
  "optionalDependencies": {
79
77
  "y-webrtc": "^10.3.0",
80
78
  "y-websocket": "^3.0.0",