@filens/core 0.0.0-stage → 0.1.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +215 -2
  3. package/dist/archive-volumes.d.ts +2 -0
  4. package/dist/archive-volumes.js +46 -0
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +14 -0
  7. package/dist/index.js +15113 -0
  8. package/dist/parser/archive-volumes.d.ts +18 -0
  9. package/dist/parser/archive.d.ts +13 -0
  10. package/dist/parser/attachments.d.ts +8 -0
  11. package/dist/parser/load-pptx.d.ts +3 -0
  12. package/dist/parser/load-source.d.ts +6 -0
  13. package/dist/parser/ordered-xml.d.ts +2 -0
  14. package/dist/parser/xml.d.ts +5 -0
  15. package/dist/parser/zip-reader.d.ts +17 -0
  16. package/dist/parser/zip.d.ts +4 -0
  17. package/dist/preview/attachment-session.d.ts +4 -0
  18. package/dist/preview/audio-lyrics.d.ts +15 -0
  19. package/dist/preview/audio-player.d.ts +40 -0
  20. package/dist/preview/containers.d.ts +12 -0
  21. package/dist/preview/font-loading.d.ts +11 -0
  22. package/dist/preview/font-matching.d.ts +17 -0
  23. package/dist/preview/font-metadata.d.ts +9 -0
  24. package/dist/preview/font-packs.d.ts +5 -0
  25. package/dist/preview/font-panose.d.ts +4 -0
  26. package/dist/preview/font-scenes.d.ts +8 -0
  27. package/dist/preview/fonts.d.ts +14 -0
  28. package/dist/preview/formats.d.ts +52 -0
  29. package/dist/preview/index.d.ts +17 -0
  30. package/dist/preview/native-drivers.d.ts +85 -0
  31. package/dist/preview/password.d.ts +7 -0
  32. package/dist/preview/pptx-driver.d.ts +29 -0
  33. package/dist/preview/previewer.d.ts +66 -0
  34. package/dist/preview/registry.d.ts +23 -0
  35. package/dist/preview/resource-resolver.d.ts +17 -0
  36. package/dist/preview/touch-gestures.d.ts +14 -0
  37. package/dist/preview/types.d.ts +571 -0
  38. package/dist/preview/video-controls.d.ts +28 -0
  39. package/dist/preview/video-player.d.ts +2 -0
  40. package/dist/render/dom.d.ts +17 -0
  41. package/dist/render/geometry.d.ts +138 -0
  42. package/dist/render/preset-definitions.d.ts +60 -0
  43. package/dist/render/preset-geometry.d.ts +17 -0
  44. package/dist/types.d.ts +380 -0
  45. package/dist/utils/colors.d.ts +8 -0
  46. package/dist/utils/common.d.ts +8 -0
  47. package/dist/utils/fonts.d.ts +2 -0
  48. package/dist/utils/units.d.ts +4 -0
  49. package/dist/viewer.d.ts +61 -0
  50. package/dist/zip-DI3roeYk.js +190 -0
  51. package/dist/zip.d.ts +3 -0
  52. package/dist/zip.js +5 -0
  53. package/package.json +61 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FiLens contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,216 @@
1
- # Temporary Holding Version
1
+ # @filens/core
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ESM PPTX parsing and preview core for browser applications.
4
+
5
+ ## What It Exposes
6
+
7
+ - `init(container, options)`
8
+ - `createViewer(container, options)`
9
+ - `loadPptx(source)`
10
+ - `renderSlideToElement(slide, presentation, options)`
11
+
12
+ The package also exports the core runtime types.
13
+
14
+ Workers can import `openZipArchive` and the `ZipEntry` type from
15
+ `@filens/core/zip`. This entry loads ZIP parsing without viewer code or CSS.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @filens/core
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```ts
26
+ import { init } from '@filens/core';
27
+ import '@filens/core/style.css';
28
+
29
+ const mount = document.getElementById('mount');
30
+ if (!mount) {
31
+ throw new Error('Missing mount element.');
32
+ }
33
+
34
+ const viewer = init(mount, {
35
+ fit: 'contain',
36
+ initialScale: 1,
37
+ minScale: 0.4,
38
+ maxScale: 4,
39
+ virtual: true
40
+ });
41
+
42
+ await viewer.preview('/samples/sample-deck.pptx');
43
+ ```
44
+
45
+ ## Source Types
46
+
47
+ `preview()` and `loadPptx()` support:
48
+
49
+ - `string`
50
+ - `ArrayBuffer`
51
+ - `Uint8Array`
52
+ - `Blob`
53
+ - `File`
54
+
55
+ For multi-format previews, `createPreviewer()` coordinates registered drivers and
56
+ converters. Opening another file or calling `destroy()` settles superseded
57
+ `preview()` calls, aborts their load signals, and ignores late results and events.
58
+ The signal remains active after the initial load for background resource work.
59
+ Custom drivers must release their own DOM and resources on destruction; work that
60
+ ignores cancellation may still finish. Rejected loads release their sessions and
61
+ expose the error through `getState()` and the `error` event.
62
+
63
+ Password-protected PDF and Office documents can be opened through `createPreviewer()`.
64
+ Register the Office drivers and configure the WASM converter for encrypted Office
65
+ packages. Set `requestPassword` to an async callback that receives `{ name, reason,
66
+ attempt, signal }` and returns a password or `null` to cancel. `reason` is
67
+ `password_required` or `password_invalid`; respect the signal when a file is replaced.
68
+ A known password can be supplied per load with
69
+ `previewer.preview(source, { name: 'document.docx', password })`.
70
+ Passwords retain spaces and Unicode, are not included in preview state, and are
71
+ not reused for subsequent documents. Stable `password_cancelled`, `password_required`
72
+ and `password_invalid` errors can be recognized with `previewPasswordErrorCode()`.
73
+
74
+ With `@filens/archive` registered, encrypted ZIP entries use the same password
75
+ callback. ZIP directories are listed without decrypting their files; a password
76
+ is requested when an encrypted entry is opened. Both ZipCrypto and AES ZIPs are
77
+ supported, including entries with different passwords. A cancelled entry returns
78
+ to the archive. Low-level callers can pass `{ password, signal }` as the second
79
+ argument to `openZipArchive()`, or supply a password to `entry.bytes(password)`.
80
+
81
+ DOCX, XLSX and PPTX previews expose files in their package's `embeddings` directory
82
+ in an **Attachments** panel. PDF drivers expose PDF attachments through the same
83
+ panel. Opening one reuses the registered drivers and converter, so a document can
84
+ contain an encrypted ZIP/RAR/7z, another document, or further attachments. OLE Package
85
+ objects are unwrapped to their original filename and payload; native OLE Office
86
+ objects are identified as DOC/XLS/PPT. Unsupported payloads can be downloaded.
87
+ Returning keeps the parent renderer and scroll position. The default nested
88
+ previewer shares the parent's registry and converter; custom `previewerFactory`
89
+ implementations must forward `containerContext`, `requestPassword`, and other
90
+ received options. Custom document drivers may implement `getAttachments()`.
91
+
92
+ Nested previews share limits of 8 levels, 20,000 entries per container, 128 MiB
93
+ per expanded entry, and 512 MiB of expanded data per top-level preview. Office
94
+ payloads are read on demand; PDF.js supplies PDF attachment contents when the
95
+ attachment list is requested. Linked external objects are not fetched as
96
+ attachments. Legacy Office conversion only exposes attachments preserved in its
97
+ OpenXML output. RAR 4/5 and 7z use a lazy-loaded 7-Zip WASM worker, including
98
+ encrypted filenames, encrypted entries and solid archives. Header passwords are
99
+ requested before listing; entry passwords are requested on opening. Cancelling
100
+ or exceeding the 60-second operation limit terminates the worker. Multi-volume
101
+ archives support RAR `.part01.rar` / `.rar` + `.r00`, 7z `.7z.001`,
102
+ byte-split ZIP `.zip.001`, and traditional ZIP `.z01` + `.zip` naming.
103
+ The demo and standalone picker accept all parts together in any order; nested
104
+ archives automatically find companion volumes in the same directory. Document
105
+ attachments can also collect companion parts, including OLE-wrapped parts.
106
+ Missing first/intermediate parts identify the missing filename; the WASM engine
107
+ validates the final volume. Each set is limited to 256 volumes and 512 MiB of
108
+ compressed input, in addition to the expanded-byte limits above.
109
+
110
+ Hosts can supply companions directly on a source descriptor:
111
+
112
+ ```ts
113
+ await previewer.preview({
114
+ source: firstFile, name: 'bundle.7z.001',
115
+ archiveVolumes: [{ name: 'bundle.7z.002', source: secondFile }]
116
+ });
117
+ ```
118
+
119
+ `selectArchiveVolumes(name, files)` is exported by `@filens/archive` and the
120
+ CSS-free `@filens/core/archive-volumes` entry for custom file pickers. It keeps
121
+ different families/directories separate and returns the primary part first.
122
+ Encrypted ZIP directory metadata is not supported. Corrupt embedded
123
+ OLE objects retain an original-byte download even when their preview fails.
124
+
125
+ PPTX and participating optional drivers also expose `PreviewItemState.fonts`
126
+ through the generic runtime. This includes discovered font references,
127
+ best-effort availability, application mappings, and layout-drift warnings.
128
+ Set `fontLoading: true` on `createPreviewer()` to load optional Latin/CJK webfonts
129
+ in the background and refresh layouts after loading. Custom packs and
130
+ `fontResolver` URL/byte assets support self-hosting and authorization; adaptive
131
+ mirrors and bounded backoff retain local fallback when loading fails.
132
+ See [font diagnostics and loading](../../docs/fonts.md) for supported formats,
133
+ configuration, helper APIs, provenance semantics, and detection limits.
134
+
135
+ ## Viewer Options
136
+
137
+ ```ts
138
+ interface ViewerOptions {
139
+ width?: number;
140
+ height?: number;
141
+ fit?: 'contain' | 'width' | 'none';
142
+ initialScale?: number;
143
+ minScale?: number;
144
+ maxScale?: number;
145
+ virtual?: boolean;
146
+ }
147
+ ```
148
+
149
+ ## Viewer API
150
+
151
+ ```ts
152
+ interface ViewerInstance {
153
+ preview(source: PptxSource): Promise<void>;
154
+ destroy(): void;
155
+ setScale(scale: number): void;
156
+ fit(mode?: FitMode): void;
157
+ goToSlide(index: number): void;
158
+ next(): void;
159
+ prev(): void;
160
+ getState(): ViewerState;
161
+ on(event, handler): () => void;
162
+ }
163
+ ```
164
+
165
+ ## Events
166
+
167
+ - `rendered`
168
+ - `error`
169
+ - `slidechange`
170
+ - `scalechange`
171
+ - `warnings`
172
+
173
+ ## Rendering Strategy
174
+
175
+ The current implementation uses HTML + SVG:
176
+
177
+ - text, images, and tables render through DOM/CSS
178
+ - preset shapes, lines, and connectors render through SVG
179
+ - thumbnails reuse the same rendering pipeline as the main viewer
180
+
181
+ ## Current Coverage
182
+
183
+ Good coverage today:
184
+
185
+ - common text boxes and placeholders
186
+ - images
187
+ - grouped shapes
188
+ - tables
189
+ - theme colors and fonts
190
+ - master/layout inheritance
191
+ - common preset arrows and polygon shapes
192
+ - slide links and external hyperlinks
193
+ - cached 2D column and pie charts, with titles and legends
194
+
195
+ Still limited:
196
+
197
+ - animations
198
+ - other chart types and advanced chart formatting
199
+ - SmartArt
200
+ - media playback objects
201
+ - embedded fonts
202
+ - some long-tail shape formulas
203
+
204
+ ## Dist Output
205
+
206
+ Build output:
207
+
208
+ - `dist/index.js`
209
+ - `dist/index.css`
210
+ - `dist/index.d.ts`
211
+
212
+ Import CSS with:
213
+
214
+ ```ts
215
+ import '@filens/core/style.css';
216
+ ```
@@ -0,0 +1,2 @@
1
+ export { ARCHIVE_VOLUME_LIMITS, isArchiveVolumeName, selectArchiveVolumes } from './parser/archive-volumes';
2
+ export type { ArchiveVolumeSet } from './parser/archive-volumes';
@@ -0,0 +1,46 @@
1
+ const l = { maxVolumes: 256, maxBytes: 536870912 };
2
+ function d(r) {
3
+ let e = /^(.*\.part)(\d+)(\.rar)$/i.exec(r);
4
+ if (e) return { format: "rar", kind: "rar-part", key: `${e[1]}*.rar`.toLowerCase(), base: e[1], index: Number(e[2]) - 1, width: e[2].length };
5
+ if (e = /^(.*\.(7z|zip))\.(\d{3,})$/i.exec(r), e) return { format: e[2].toLowerCase(), kind: "numbered", key: `${e[1]}.*`.toLowerCase(), base: e[1], index: Number(e[3]) - 1, width: e[3].length };
6
+ if (e = /^(.*)\.([r-y])(\d{2})$/i.exec(r), e) return { format: "rar", kind: "rar-old", key: `${e[1]}.rar`.toLowerCase(), base: e[1], index: (e[2].toLowerCase().charCodeAt(0) - 114) * 100 + Number(e[3]) + 1, width: 2 };
7
+ if (e = /^(.*)\.rar$/i.exec(r), e) return { format: "rar", kind: "rar-old", key: r.toLowerCase(), base: e[1], index: 0, width: 2 };
8
+ if (e = /^(.*)\.z(\d{2,})$/i.exec(r), e) return { format: "zip", kind: "zip", key: `${e[1]}.zip`.toLowerCase(), base: e[1], index: Number(e[2]) - 1, width: e[2].length };
9
+ if (e = /^(.*)\.zip$/i.exec(r), e) return { format: "zip", kind: "zip", key: r.toLowerCase(), base: e[1], index: 1 / 0, width: 2 };
10
+ }
11
+ function f(r) {
12
+ const e = d(r);
13
+ return !!(e && (e.kind === "numbered" || e.kind === "rar-part" || !/\.(rar|zip)$/i.test(r)));
14
+ }
15
+ function c(r, e) {
16
+ const n = d(r);
17
+ if (!n) return;
18
+ const i = e.flatMap((t) => {
19
+ const a = d(t.name);
20
+ return (a == null ? void 0 : a.key) === n.key && a.kind === n.kind ? [{ file: t, info: a }] : [];
21
+ }).sort((t, a) => t.info.index - a.info.index);
22
+ if (!i.length || i.length === 1 && !f(r)) return;
23
+ if (i.length > l.maxVolumes) throw new Error("Archive contains too many volumes.");
24
+ const s = /* @__PURE__ */ new Set();
25
+ for (const { info: t } of i) {
26
+ if (s.has(t.index)) throw new Error("Duplicate archive volume numbers.");
27
+ if (t.index < 0 || !Number.isSafeInteger(t.index) && !(t.kind === "zip" && t.index === 1 / 0)) throw new Error("Invalid archive volume number.");
28
+ s.add(t.index);
29
+ }
30
+ const u = i.filter((t) => t.info.index !== 1 / 0);
31
+ for (let t = 0; t < u.length; t++)
32
+ if (u[t].info.index !== t)
33
+ throw new Error(`Missing archive volume: ${h(n, t)}. Select all parts of the archive.`);
34
+ if (n.kind === "zip" && !i.some((t) => t.info.index === 1 / 0))
35
+ throw new Error(`Missing archive volume: ${n.base}.zip. Select all parts of the archive.`);
36
+ const o = n.kind === "zip" ? i[i.length - 1].file : i[0].file;
37
+ return { format: n.format, primary: o, files: [o, ...i.map((t) => t.file).filter((t) => t !== o)] };
38
+ }
39
+ function h(r, e) {
40
+ return r.kind === "rar-part" ? `${r.base}${String(e + 1).padStart(r.width, "0")}.rar` : r.kind === "numbered" ? `${r.base}.${String(e + 1).padStart(r.width, "0")}` : r.kind === "zip" ? `${r.base}.z${String(e + 1).padStart(r.width, "0")}` : e === 0 ? `${r.base}.rar` : `${r.base}.${String.fromCharCode(114 + Math.floor((e - 1) / 100))}${String((e - 1) % 100).padStart(2, "0")}`;
41
+ }
42
+ export {
43
+ l as ARCHIVE_VOLUME_LIMITS,
44
+ f as isArchiveVolumeName,
45
+ c as selectArchiveVolumes
46
+ };
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ .pptxv-viewer{position:relative;display:flex;width:100%;height:100%;min-height:320px;background:#e6e9ef;overflow:hidden}.pptxv-scroll-area{flex:1;overflow:auto;padding:12px;scroll-behavior:smooth;scroll-padding:12px;scroll-snap-type:y proximity}.pptxv-loading{display:flex;align-items:center;justify-content:center;min-height:240px;color:#395170;font:600 15px/1.4 system-ui,sans-serif}.pptxv-loading--error{color:#8a1f1f}.pptxv-slide-shell{position:relative;contain:layout style;margin:0 auto 18px;scroll-snap-align:start}.pptxv-slide-stage{position:relative;border-radius:0;box-shadow:none;overflow:hidden}.pptxv-slide{position:relative;overflow:hidden;font-family:system-ui,sans-serif}.pptxv-slide--thumbnail{box-shadow:none}.pptxv-item{box-sizing:border-box}.pptxv-item--table,.pptxv-item--chart,.pptxv-item--unsupported{overflow:hidden}.pptxv-item--shape,.pptxv-item--media{overflow:visible}.pptxv-shape-svg{display:block;overflow:visible}.pptxv-text-frame{display:flex;flex-direction:column;width:100%;height:100%;box-sizing:border-box}.pptxv-shape-text{display:block;width:auto;height:auto;box-sizing:border-box}.pptxv-paragraph{margin:0;line-height:1;word-break:normal;overflow-wrap:break-word}.pptxv-run{white-space:pre-wrap}.pptxv-run--tab{display:inline-block;white-space:pre;min-width:4px}.pptxv-run--link{color:inherit;text-decoration-line:underline;text-decoration-color:currentcolor;text-underline-offset:.08em}.pptxv-item-link{cursor:pointer}.pptxv-item-link:focus-visible{outline:none;box-shadow:inset 0 0 0 2px #2f6bffd1,inset 0 0 0 4px #ffffffc2}.pptxv-run--bullet{display:inline-block;min-width:1.2em}.pptxv-run--bullet-auto{min-width:2.4em}.pptxv-image{display:block;-webkit-user-select:none;user-select:none}.pptxv-media-stage{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;background:transparent}.pptxv-media-poster-frame{position:absolute}.pptxv-media-poster,.pptxv-media-player{display:block}.pptxv-media-poster{-webkit-user-select:none;user-select:none;pointer-events:none}.pptxv-media-player--video{background:transparent}.pptxv-media-player--audio{min-width:220px}.pptxv-table{width:100%;height:100%;border-collapse:collapse;table-layout:fixed;background:transparent}.pptxv-table-cell{border:0 solid transparent;vertical-align:top;padding:0}.pptxv-chart-svg{display:block;width:100%;height:100%;overflow:hidden;font-family:Aptos,Calibri,Segoe UI,sans-serif}.pptxv-chart-title,.pptxv-chart-axis-label,.pptxv-chart-category-label,.pptxv-chart-legend{fill:#595959;font-weight:400}.pptxv-chart-gridline{stroke:#bfbfbf;stroke-width:1}.pptxv-chart-axis{stroke:#000;stroke-width:1.25}.pptxv-item--unsupported{display:flex;align-items:center;justify-content:center;border:1px dashed rgba(57,81,112,.35);background:#ffffffb8;color:#395170;font:600 12px/1.3 system-ui,sans-serif}.pptxv-native-preview{box-sizing:border-box;width:100%;height:100%;min-height:280px;font-family:system-ui,sans-serif}.pptxv-native-preview--image,.pptxv-native-preview--video,.pptxv-native-preview--audio{display:flex;align-items:center;justify-content:center;overflow:auto;padding:16px;background:#151923}.pptxv-native-preview--image{cursor:grab;touch-action:none}.pptxv-native-preview--image.is-panning{cursor:grabbing}.pptxv-native-preview--audio{background:radial-gradient(ellipse at 12% 10%,#e3eadd,transparent 65%),#f2f0eb;flex-direction:column;padding:clamp(16px,4%,48px);justify-content:safe center;container-type:inline-size}.pptxv-native-image{display:block;width:auto;height:auto;transform-origin:center center;-webkit-user-select:none;user-select:none}.pptxv-native-media{display:block;max-width:100%}.pptxv-native-media--video{max-height:100%;background:#000}.pptxv-has-video-controls{position:relative;container-type:inline-size;outline:none}.pptxv-native-preview--video.pptxv-has-video-controls{overflow:hidden;padding:0 0 110px;background:#11151c}.pptxv-has-video-controls:fullscreen{width:100%;height:100%}.pptxv-video-controls{position:absolute;right:12px;bottom:max(12px,env(safe-area-inset-bottom));left:12px;z-index:3;box-sizing:border-box;max-width:880px;margin:0 auto;padding:10px 14px 8px;border:1px solid rgba(255,255,255,.18);border-radius:20px;background:#141821e0;color:#f8fafc;font:13px/1.4 system-ui,sans-serif;-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);box-shadow:0 6px 24px #0003}.pptxv-video-control-row{display:flex;align-items:center;gap:4px;min-width:0}.pptxv-video-controls button,.panoramav-view-controls button{display:inline-flex;align-items:center;justify-content:center;flex:0 0 36px;box-sizing:border-box;width:36px;height:36px;padding:7px;border:0;border-radius:50%;background:transparent;color:#f8fafc;cursor:pointer;touch-action:manipulation}.pptxv-video-controls button:hover,.panoramav-view-controls button:hover{background:#ffffff24}.pptxv-video-controls button:disabled,.panoramav-view-controls button:disabled{opacity:.4;cursor:default}.pptxv-video-controls :focus-visible,.panoramav-view-controls button:focus-visible,.pptxv-has-video-controls:focus-visible{outline:2px solid #9ec5ff;outline-offset:2px}.pptxv-video-time{flex-shrink:0;margin-left:5px;color:#e5e7eb;font:inherit;font-variant-numeric:tabular-nums;white-space:nowrap}.pptxv-video-control-spacer{flex:1}.pptxv-video-controls input[type=range]{min-width:0;padding:0;border:0;border-radius:2px;accent-color:#f8fafc;cursor:pointer;touch-action:pan-y}.pptxv-video-controls .pptxv-video-timeline{display:block;width:100%;height:18px;margin:0 0 4px;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent}.pptxv-video-timeline::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:linear-gradient(to right,#f8fafc var(--pptxv-video-progress, 0%),#ffffff40 var(--pptxv-video-progress, 0%))}.pptxv-video-timeline::-webkit-slider-thumb{width:12px;height:12px;margin-top:-4px;border-radius:50%;background:#fff;-webkit-appearance:none;-moz-appearance:none;appearance:none}.pptxv-video-timeline::-moz-range-track{height:4px;border-radius:2px;background:#ffffff40}.pptxv-video-timeline::-moz-range-progress{height:4px;background:#f8fafc}.pptxv-video-timeline::-moz-range-thumb{width:12px;height:12px;border:0;border-radius:50%;background:#fff}.pptxv-video-volume{display:flex;align-items:center;gap:4px}.pptxv-video-volume input{width:68px}.pptxv-video-rate{height:36px;padding:0 4px;border:0;border-radius:8px;background:transparent;color:#f8fafc;font:inherit;cursor:pointer}.pptxv-video-rate option{background:#202632;color:#f8fafc}.pptxv-video-captions{max-width:84px}.pptxv-video-controls [hidden]{display:none}@container (max-width: 540px){.pptxv-video-volume input{display:none}}@container (max-width: 420px){.pptxv-video-controls{right:8px;left:8px;padding:8px;border-radius:16px}.pptxv-video-controls .pptxv-video-skip,.pptxv-video-controls .pptxv-video-pip{display:none}.pptxv-video-captions{max-width:44px}.pptxv-video-control-row{gap:2px}.pptxv-video-time{margin-left:0;font-size:11px}}.pptxv-native-media--audio{width:min(640px,100%)}.pptxv-native-audio-cover{display:block;position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;width:100%;height:100%;object-fit:cover;border-radius:inherit}.pptxv-audio-player{--audio-accent: #40634c;box-sizing:border-box;width:min(880px,100%);flex-shrink:0;margin:auto;color:#283c32;background:#fffefa;border:1px solid #d7dbd0;border-radius:22px;box-shadow:0 16px 56px #243b2c0c;font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;overflow:hidden}.pptxv-audio-player button,.pptxv-audio-player select{font:inherit;cursor:pointer;color:inherit}.pptxv-audio-player button:focus-visible,.pptxv-audio-player select:focus-visible,.pptxv-audio-lyrics:focus-visible{outline:2px solid var(--audio-accent);outline-offset:3px}.pptxv-audio-body{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);gap:clamp(24px,5%,56px);padding:clamp(24px,5%,44px)}.pptxv-audio-album{min-width:0}.pptxv-audio-artwork{position:relative;aspect-ratio:1;width:100%;max-width:280px;margin-bottom:26px;border-radius:14px;background:#45644e;box-shadow:0 10px 24px #223b3026;isolation:isolate}.pptxv-audio-placeholder{display:grid;place-items:center;height:100%;overflow:hidden;border-radius:inherit;background:radial-gradient(circle at 25% 15%,#9cab7c,transparent 50%),linear-gradient(145deg,#526c53,#1f3c37)}.pptxv-audio-placeholder span{display:grid;place-items:center;width:66%;aspect-ratio:1;border:1px solid #ffffff30;border-radius:50%;box-shadow:0 0 0 15px #ffffff06,0 0 0 30px #ffffff06;color:#e8e8cd;font-size:52px}.pptxv-audio-play{position:absolute;z-index:2;right:14px;bottom:14px;display:grid;place-items:center;width:48px;height:48px;padding:0;border:1px solid #ffffffa0;border-radius:50%;color:#293f32!important;background:#fffef4ee;box-shadow:0 4px 16px #0002}.pptxv-audio-play:hover{background:#fff;transform:scale(1.04)}.pptxv-audio-eyebrow{margin:0 0 10px;color:#697c63;font-size:10px;letter-spacing:.16em}.pptxv-audio-eyebrow:before{content:"";display:inline-block;width:6px;height:6px;margin-right:7px;border-radius:50%;background:#a7b19b}.is-playing .pptxv-audio-eyebrow:before{background:#52835b;box-shadow:0 0 0 4px #52835b18}.pptxv-audio-title{margin:0 0 8px;font-size:clamp(19px,2.4cqw,25px);font-weight:600;line-height:1.4;overflow-wrap:anywhere}.pptxv-audio-details{margin:0 0 18px;color:#6c756b;font-size:12px;line-height:1.6;overflow-wrap:anywhere}.pptxv-audio-import{padding:6px 10px;border:1px solid #dce0d4;border-radius:6px;background:transparent;font-size:11px!important}.pptxv-audio-import:hover{border-color:#95a48c;background:#f3f5ed}.pptxv-audio-lyric-panel{min-width:0;display:flex;flex-direction:column}.pptxv-audio-lyric-header{display:flex;justify-content:space-between;align-items:center;gap:12px;padding-bottom:14px;border-bottom:1px solid #e8e9e1}.pptxv-audio-lyric-header h3{margin:0;color:#6c756b;font-size:12px;font-weight:500;letter-spacing:.06em}.pptxv-audio-lyrics{position:relative;flex:1 0 auto;height:280px;max-height:340px;overflow:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:#cbd1c3 transparent;margin-top:12px;padding:40px 0;box-sizing:border-box}.pptxv-audio-lyrics.is-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:#7b8375;gap:12px}.pptxv-audio-empty-icon{font-size:42px;color:#a0ae93}.pptxv-audio-lyrics.is-empty p{margin:0;font-size:14px}.pptxv-audio-lyrics.is-empty small{color:#7b8375;font-size:11px;line-height:1.7}.pptxv-audio-lyric{display:block;width:100%;padding:12px 10px;margin:0;border:0;border-left:2px solid transparent;border-radius:0 6px 6px 0;background:transparent;color:#7c8378!important;text-align:left;font-size:14px!important;line-height:1.8;white-space:pre-line;overflow-wrap:anywhere;transition:color .18s,background .18s}.pptxv-audio-lyric:hover{color:#40634c!important;background:#f4f5ee}.pptxv-audio-lyric.is-active{border-left-color:var(--audio-accent);color:#304e39!important;background:#eff3e9;font-weight:600}.pptxv-audio-timing{display:flex;justify-content:flex-end;align-items:center;gap:10px;margin-top:12px;color:#6c756b;font-size:10px}.pptxv-audio-timing[hidden]{display:none}.pptxv-audio-timing button{padding:4px 7px;border:1px solid #e0e3d8;border-radius:4px;background:transparent}.pptxv-audio-timing output{min-width:38px;text-align:center;font-variant-numeric:tabular-nums}.pptxv-audio-status{margin:10px 0 0;color:#707969;font-size:11px;line-height:1.6}.pptxv-audio-status:empty{display:none}.pptxv-audio-footer{display:flex;align-items:center;gap:14px;padding:16px 24px;background:#f3f5ee;border-top:1px solid #e2e6d9}.pptxv-audio-footer audio{width:100%;min-width:0;height:44px;flex:1}.pptxv-audio-extras{display:flex;align-items:center;gap:10px}.pptxv-audio-repeat{width:30px;height:30px;border:1px solid transparent;border-radius:50%;background:transparent;font-size:22px!important}.pptxv-audio-repeat[aria-pressed=true]{color:#355d3e;border-color:#cad7bf;background:#e1ead7}.pptxv-audio-speed{max-width:68px;padding:4px;border:0;border-radius:4px;background:transparent;font-size:12px!important}@container (max-width: 560px){.pptxv-audio-body{grid-template-columns:minmax(0,1fr);gap:24px;padding:24px}.pptxv-audio-album{display:grid;grid-template-columns:112px minmax(0,1fr);column-gap:18px;align-content:center}.pptxv-audio-artwork{width:112px;grid-row:span 4;margin:0}.pptxv-audio-eyebrow{margin-bottom:6px;font-size:9px}.pptxv-audio-title{font-size:18px}.pptxv-audio-details{margin-bottom:10px;font-size:11px}.pptxv-audio-play{width:36px;height:36px;right:8px;bottom:8px}.pptxv-audio-placeholder span{font-size:28px}.pptxv-audio-lyrics{flex:none;height:230px}.pptxv-audio-footer{flex-wrap:wrap;gap:6px;padding:12px}.pptxv-audio-footer audio{flex-basis:100%}.pptxv-audio-extras{margin-left:auto}}@media (prefers-reduced-motion: reduce){.pptxv-audio-player *{transition:none!important}}.pptxv-native-preview--text{overflow:auto;background:#f8fafc}.pptxv-native-preview--html{overflow:hidden;background:#fff}.pptxv-native-html-frame{display:block;width:100%;height:100%;min-height:inherit;border:0;background:#fff}.pptxv-native-text-shell{box-sizing:border-box;min-width:100%;min-height:100%;padding:18px}.pptxv-native-text-body{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:start;min-width:max-content}.pptxv-native-text-gutter{box-sizing:border-box;position:sticky;left:0;z-index:1;white-space:pre;min-width:3.25rem;padding-right:14px;color:#64748b;background:#f8fafc;border-right:1px solid rgba(100,116,139,.2);font:13px/1.55 Consolas,SFMono-Regular,Liberation Mono,Menlo,monospace;text-align:right;-webkit-user-select:none;user-select:none}.pptxv-native-text{box-sizing:border-box;min-width:100%;margin:0;padding-left:14px;color:#1f2937;font:13px/1.55 Consolas,SFMono-Regular,Liberation Mono,Menlo,monospace;-moz-tab-size:2;tab-size:2;white-space:pre-wrap;overflow-wrap:anywhere}.pptxv-native-text[data-wrap=false]{white-space:pre;overflow-wrap:normal}.pptxv-native-text-shell[data-family=code]{color-scheme:dark;background:#0b1220}.pptxv-native-text-shell[data-family=code] .pptxv-native-text-gutter{color:#607089;background:#0b1220;border-right-color:#94a3b82e}.pptxv-native-text[data-family=code]{color:#d7e0ec}.pptxv-token--comment{color:#6f8f72;font-style:italic}.pptxv-token--keyword{color:#f08fc5}.pptxv-token--literal{color:#79b8ff}.pptxv-token--string{color:#e7a873}.pptxv-token--number{color:#a8d58d}.pptxv-token--property{color:#8bd5ff}.pptxv-token--tag,.pptxv-token--type{color:#67d4c0}.pptxv-token--function{color:#e8d17a}.pptxv-token--operator{color:#b9c5d6}.filens-attachments-shell,.filens-attachment-panel{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;overflow:hidden}.filens-attachments-document,.filens-attachment-preview{flex:1;min-height:0;overflow:hidden}.filens-attachments-shell [hidden]{display:none!important}.filens-attachments,.filens-attachment-navigation{flex-shrink:0;box-sizing:border-box;padding:10px 14px;border-bottom:1px solid #d7dee8;background:#f8fafc;color:#1f2937;font:14px/1.4 system-ui,sans-serif}.filens-attachments summary{cursor:pointer}.filens-attachments ul{max-height:180px;overflow:auto;margin:8px 0 0;padding:0;list-style:none}.filens-attachments li,.filens-attachment-navigation{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.filens-attachment-navigation span{overflow-wrap:anywhere;flex:1}.filens-attachments button,.filens-attachment-navigation button{font:inherit;color:inherit;padding:5px 10px;border:1px solid #cbd5e1;border-radius:4px;background:#fff;cursor:pointer}.filens-attachments li button:first-child{text-align:left;overflow-wrap:anywhere}.filens-attachment-status{margin:12px 16px;font:14px/1.5 system-ui,sans-serif}.filens-attachment-status[role=alert]{color:#b91c1c}
@@ -0,0 +1,14 @@
1
+ export { createViewer, init, PptxViewer } from './viewer';
2
+ export { loadPptx } from './parser/load-pptx';
3
+ export { openZipArchive } from './parser/zip';
4
+ export type { ZipEntry, ZipArchiveOptions } from './parser/zip';
5
+ export { attachmentFilename, readOfficeAttachments, unwrapOfficeAttachment } from './parser/attachments';
6
+ export * from './archive-volumes';
7
+ export { MediaRegistry, renderSlideToElement } from './render/dom';
8
+ export type { MediaResolver, RenderSlideOptions } from './render/dom';
9
+ export * from './preview';
10
+ export { bindPreviewTouchGestures, type PreviewTouchGestureOptions } from './preview/touch-gestures';
11
+ export { createVideoPlaybackControls, type VideoPlaybackActions, type VideoPlaybackState } from './preview/video-controls';
12
+ export { createVideoPreviewPlayer } from './preview/video-player';
13
+ export type { Model3dPreviewNode, Model3dPreviewState, PreviewDisplayMode, PreviewFontResolveRequest, PreviewFontResolveResult, PreviewFontResolver, PreviewMaterialInfo, PreviewSnapshotBackground, PreviewSectionInfo, PreviewerInstance, PreviewResourceResolveRequest, PreviewResourceResolveResult, PreviewResourceResolver, PreviewerFactory, PreviewSession } from './preview/types';
14
+ export type * from './types';