pptx-angular-viewer 3.20.0 → 3.21.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/CHANGELOG.md CHANGED
@@ -7,6 +7,44 @@ A release listed with no entries carried no Conventional Commit in this package'
7
7
  scope: scripts/release-plan.mjs re-releases a package whenever any of its files
8
8
  change, not only on conventional ones.
9
9
 
10
+ ## [3.20.1](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@3.20.1) - 2026-09-17
11
+
12
+ ### Bug Fixes
13
+
14
+ - **i18n:** Translate recording and editor control labels (by @yunfeizhu) ([7be4498](https://github.com/ChristopherVR/pptx-viewer/commit/7be44985707067b5e11fcac257e52186d7159349))
15
+ - **core:** Embed real images in CLI export-md/export-svg output (by @ChristopherVR) ([6617c92](https://github.com/ChristopherVR/pptx-viewer/commit/6617c92a2ee2ea673c35e4a58cc60dc7cc32def5))
16
+ - **shared:** Keep chart axis interval count off a manual plot layout (by @ChristopherVR) ([d39b2b0](https://github.com/ChristopherVR/pptx-viewer/commit/d39b2b06925c8bd02e64b39c8b5b1a4476537010))
17
+
18
+ ### Testing
19
+
20
+ - **i18n:** Cover translated editor controls across bindings (by @yunfeizhu) ([fe99e2b](https://github.com/ChristopherVR/pptx-viewer/commit/fe99e2b866a66bd3874707ae506416fd03bf8f1e))
21
+ - **core:** Remove duplicate chart-stacked-line-markers manifest entry (by @ChristopherVR) ([5c60b11](https://github.com/ChristopherVR/pptx-viewer/commit/5c60b1170223c3c74bd5815e8ebad28a233656a4))
22
+
23
+ ## [3.20.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@3.20.0) - 2026-09-17
24
+
25
+ ### Features
26
+
27
+ - **shared:** Chart quick-actions descriptor (Elements/Styles/Filters) (by @ChristopherVR) ([90ea1ff](https://github.com/ChristopherVR/pptx-viewer/commit/90ea1ffeff956f7401c6edd2123d92e5f3065e2d))
28
+ - **react,shared:** Chart quick-action icons (Elements/Styles/Filters) (by @ChristopherVR) ([4c9f9e7](https://github.com/ChristopherVR/pptx-viewer/commit/4c9f9e79a20f92ca77fd40208007a0b8f1ecc044))
29
+ - **angular:** Chart quick-action icons (Elements/Styles/Filters) (by @ChristopherVR) ([4acdcd8](https://github.com/ChristopherVR/pptx-viewer/commit/4acdcd8c4239b5e796b457c92cb1fa68b6833e88))
30
+
31
+ ### Bug Fixes
32
+
33
+ - **shared:** Scale chart auto axis bounds by plot height, not a fixed constant (by @ChristopherVR) ([fc56a8a](https://github.com/ChristopherVR/pptx-viewer/commit/fc56a8afc70f7e0109be712b19b0d7e34a3b31a1))
34
+ - **shared:** Cycle PowerPoint's automatic marker-symbol sequence per series idx (by @ChristopherVR) ([f55afb4](https://github.com/ChristopherVR/pptx-viewer/commit/f55afb45ad0533a5370bff27f0ba80e33e22eff2))
35
+ - **shared:** Honor a chart-level default legend text style (by @ChristopherVR) ([1807bd3](https://github.com/ChristopherVR/pptx-viewer/commit/1807bd30d2f1961f8ad58478cf8066cabfd11d31))
36
+ - **core:** Treat a bare c:majorGridlines/minorGridlines as present (by @ChristopherVR) ([2e06cee](https://github.com/ChristopherVR/pptx-viewer/commit/2e06ceeb007873d7960c982e3454267b9e530173))
37
+ - **shared:** Clear per-series colour overrides when applying a chart style preset (by @ChristopherVR) ([1417f28](https://github.com/ChristopherVR/pptx-viewer/commit/1417f28060858b7a490f9bc33773fa3eb4e1e462))
38
+ - **react,vue,angular,svelte,vanilla:** Use opaque colours for chart quick-action buttons (by @ChristopherVR) ([9d1df11](https://github.com/ChristopherVR/pptx-viewer/commit/9d1df116b2e8959fe97ad12865f694e1c5f8316d))
39
+ - **shared:** Stop the Chart Filters list and series order reshuffling on toggle (by @ChristopherVR) ([4a9546f](https://github.com/ChristopherVR/pptx-viewer/commit/4a9546fa6b17a7d8952cde345ad38d67ad54f509))
40
+ - **core,shared:** Preserve series formatting across a Chart Filters hide/restore round trip (by @ChristopherVR) ([6555181](https://github.com/ChristopherVR/pptx-viewer/commit/6555181fea70e6c80fa079c1866c6aa8c8ec97cb))
41
+ - **core:** Make editor ids collision-free within a process (by @ChristopherVR) ([04a61a0](https://github.com/ChristopherVR/pptx-viewer/commit/04a61a096b48fee63c433fac5b5d6690734cbc44))
42
+
43
+ ### Testing
44
+
45
+ - **core:** Register the missing chart-stacked-line-markers fixture in the corpus manifest (by @ChristopherVR) ([2d7c886](https://github.com/ChristopherVR/pptx-viewer/commit/2d7c88618042dac64e60c09c827b73b409976f1f))
46
+ - **core:** Register the stacked line marker fixture (by @Sudhansh6) ([87a8423](https://github.com/ChristopherVR/pptx-viewer/commit/87a8423047db0df204b8db2d8c155624bb190d26))
47
+
10
48
  ## [3.19.2](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@3.19.2) - 2026-09-17
11
49
 
12
50
  ### Bug Fixes
@@ -1,4 +1,4 @@
1
- import { t as toChatSummary } from './pptx-angular-viewer-pptx-angular-viewer-DP0uS-ib.mjs';
1
+ import { t as toChatSummary } from './pptx-angular-viewer-pptx-angular-viewer-vihD7wHf.mjs';
2
2
 
3
3
  /**
4
4
  * IndexedDB backend for {@link createChatHistoryStore}. Kept in its own module
@@ -103,4 +103,4 @@ function createIdbBackend(db) {
103
103
  }
104
104
 
105
105
  export { CHAT_STORE, createIdbBackend, openChatDb };
106
- //# sourceMappingURL=pptx-angular-viewer-chat-history-idb-amzrYVHP.mjs.map
106
+ //# sourceMappingURL=pptx-angular-viewer-chat-history-idb-DewzErjQ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pptx-angular-viewer-chat-history-idb-amzrYVHP.mjs","sources":["../../src/internal/shared-src/ai/chat-history-idb.ts"],"sourcesContent":["/**\n * IndexedDB backend for {@link createChatHistoryStore}. Kept in its own module\n * so the localStorage fallback and the public factory stay within the per-file\n * size budget. Uses the raw IndexedDB API with tiny promise wrappers so no new\n * runtime dependency is pulled in.\n *\n * Every browser global is touched lazily from inside a function, never at module\n * load, so importing this file in a non-DOM environment (Node, SSR) never throws.\n */\n\nimport type { ChatBackend, PptxAiChatSummary, PptxAiStoredChat } from './chat-history-store';\nimport { toChatSummary } from './chat-history-store';\n\n/** Object store holding one record per chat, keyed by `id`. */\nexport const CHAT_STORE = 'chats';\n/** Index over the optional `deckId` key path, used for per-deck filtering. */\nconst DECK_INDEX = 'deckId';\n\n/** Resolve an `IDBRequest` to a promise. */\nfunction requestToPromise<T>(request: IDBRequest<T>): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error ?? new Error('IndexedDB request failed.'));\n\t});\n}\n\n/** Resolve when a transaction commits (or reject on error/abort). */\nfunction transactionDone(tx: IDBTransaction): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\ttx.oncomplete = () => resolve();\n\t\ttx.onerror = () => reject(tx.error ?? new Error('IndexedDB transaction failed.'));\n\t\ttx.onabort = () => reject(tx.error ?? new Error('IndexedDB transaction aborted.'));\n\t});\n}\n\n/**\n * Open (and if needed create/upgrade) the chat database. Throws when there is no\n * `indexedDB` global so the caller can transparently fall back to localStorage.\n */\nexport function openChatDb(dbName: string): Promise<IDBDatabase> {\n\tconst idb = typeof indexedDB !== 'undefined' ? indexedDB : undefined;\n\tif (!idb) {\n\t\tthrow new Error('IndexedDB is not available in this environment.');\n\t}\n\treturn new Promise<IDBDatabase>((resolve, reject) => {\n\t\tconst open = idb.open(dbName, 1);\n\t\topen.onupgradeneeded = () => {\n\t\t\tconst db = open.result;\n\t\t\tif (!db.objectStoreNames.contains(CHAT_STORE)) {\n\t\t\t\tconst store = db.createObjectStore(CHAT_STORE, { keyPath: 'id' });\n\t\t\t\tstore.createIndex(DECK_INDEX, 'deckId', { unique: false });\n\t\t\t}\n\t\t};\n\t\topen.onsuccess = () => resolve(open.result);\n\t\topen.onerror = () => reject(open.error ?? new Error('Failed to open IndexedDB.'));\n\t\topen.onblocked = () => reject(new Error('IndexedDB open blocked by another connection.'));\n\t});\n}\n\n/** Read every stored chat (newest-first ordering is applied by the caller). */\nasync function readAll(db: IDBDatabase, deckId: string | undefined): Promise<PptxAiStoredChat[]> {\n\tconst tx = db.transaction(CHAT_STORE, 'readonly');\n\tconst store = tx.objectStore(CHAT_STORE);\n\tconst source =\n\t\tdeckId === undefined\n\t\t\t? store.getAll()\n\t\t\t: store.index(DECK_INDEX).getAll(IDBKeyRange.only(deckId));\n\tconst rows = await requestToPromise<PptxAiStoredChat[]>(source);\n\tawait transactionDone(tx);\n\treturn rows;\n}\n\n/** Create an IndexedDB-backed {@link ChatBackend}. */\nexport function createIdbBackend(db: IDBDatabase): ChatBackend {\n\treturn {\n\t\tasync list(deckId: string | undefined): Promise<PptxAiChatSummary[]> {\n\t\t\tconst rows = await readAll(db, deckId);\n\t\t\treturn rows.map(toChatSummary).sort((a, b) => b.updatedAt - a.updatedAt);\n\t\t},\n\t\tasync load(id: string): Promise<PptxAiStoredChat | null> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readonly');\n\t\t\tconst row = await requestToPromise<PptxAiStoredChat | undefined>(\n\t\t\t\ttx.objectStore(CHAT_STORE).get(id),\n\t\t\t);\n\t\t\tawait transactionDone(tx);\n\t\t\treturn row ?? null;\n\t\t},\n\t\tasync save(chat: PptxAiStoredChat): Promise<void> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readwrite');\n\t\t\ttx.objectStore(CHAT_STORE).put(chat);\n\t\t\tawait transactionDone(tx);\n\t\t},\n\t\tasync remove(id: string): Promise<void> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readwrite');\n\t\t\ttx.objectStore(CHAT_STORE).delete(id);\n\t\t\tawait transactionDone(tx);\n\t\t},\n\t\tasync clear(deckId: string | undefined): Promise<void> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readwrite');\n\t\t\tconst store = tx.objectStore(CHAT_STORE);\n\t\t\tif (deckId === undefined) {\n\t\t\t\tstore.clear();\n\t\t\t} else {\n\t\t\t\tconst ids = await requestToPromise<IDBValidKey[]>(\n\t\t\t\t\tstore.index(DECK_INDEX).getAllKeys(IDBKeyRange.only(deckId)),\n\t\t\t\t);\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tstore.delete(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait transactionDone(tx);\n\t\t},\n\t};\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pptx-angular-viewer-chat-history-idb-DewzErjQ.mjs","sources":["../../src/internal/shared-src/ai/chat-history-idb.ts"],"sourcesContent":["/**\n * IndexedDB backend for {@link createChatHistoryStore}. Kept in its own module\n * so the localStorage fallback and the public factory stay within the per-file\n * size budget. Uses the raw IndexedDB API with tiny promise wrappers so no new\n * runtime dependency is pulled in.\n *\n * Every browser global is touched lazily from inside a function, never at module\n * load, so importing this file in a non-DOM environment (Node, SSR) never throws.\n */\n\nimport type { ChatBackend, PptxAiChatSummary, PptxAiStoredChat } from './chat-history-store';\nimport { toChatSummary } from './chat-history-store';\n\n/** Object store holding one record per chat, keyed by `id`. */\nexport const CHAT_STORE = 'chats';\n/** Index over the optional `deckId` key path, used for per-deck filtering. */\nconst DECK_INDEX = 'deckId';\n\n/** Resolve an `IDBRequest` to a promise. */\nfunction requestToPromise<T>(request: IDBRequest<T>): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error ?? new Error('IndexedDB request failed.'));\n\t});\n}\n\n/** Resolve when a transaction commits (or reject on error/abort). */\nfunction transactionDone(tx: IDBTransaction): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\ttx.oncomplete = () => resolve();\n\t\ttx.onerror = () => reject(tx.error ?? new Error('IndexedDB transaction failed.'));\n\t\ttx.onabort = () => reject(tx.error ?? new Error('IndexedDB transaction aborted.'));\n\t});\n}\n\n/**\n * Open (and if needed create/upgrade) the chat database. Throws when there is no\n * `indexedDB` global so the caller can transparently fall back to localStorage.\n */\nexport function openChatDb(dbName: string): Promise<IDBDatabase> {\n\tconst idb = typeof indexedDB !== 'undefined' ? indexedDB : undefined;\n\tif (!idb) {\n\t\tthrow new Error('IndexedDB is not available in this environment.');\n\t}\n\treturn new Promise<IDBDatabase>((resolve, reject) => {\n\t\tconst open = idb.open(dbName, 1);\n\t\topen.onupgradeneeded = () => {\n\t\t\tconst db = open.result;\n\t\t\tif (!db.objectStoreNames.contains(CHAT_STORE)) {\n\t\t\t\tconst store = db.createObjectStore(CHAT_STORE, { keyPath: 'id' });\n\t\t\t\tstore.createIndex(DECK_INDEX, 'deckId', { unique: false });\n\t\t\t}\n\t\t};\n\t\topen.onsuccess = () => resolve(open.result);\n\t\topen.onerror = () => reject(open.error ?? new Error('Failed to open IndexedDB.'));\n\t\topen.onblocked = () => reject(new Error('IndexedDB open blocked by another connection.'));\n\t});\n}\n\n/** Read every stored chat (newest-first ordering is applied by the caller). */\nasync function readAll(db: IDBDatabase, deckId: string | undefined): Promise<PptxAiStoredChat[]> {\n\tconst tx = db.transaction(CHAT_STORE, 'readonly');\n\tconst store = tx.objectStore(CHAT_STORE);\n\tconst source =\n\t\tdeckId === undefined\n\t\t\t? store.getAll()\n\t\t\t: store.index(DECK_INDEX).getAll(IDBKeyRange.only(deckId));\n\tconst rows = await requestToPromise<PptxAiStoredChat[]>(source);\n\tawait transactionDone(tx);\n\treturn rows;\n}\n\n/** Create an IndexedDB-backed {@link ChatBackend}. */\nexport function createIdbBackend(db: IDBDatabase): ChatBackend {\n\treturn {\n\t\tasync list(deckId: string | undefined): Promise<PptxAiChatSummary[]> {\n\t\t\tconst rows = await readAll(db, deckId);\n\t\t\treturn rows.map(toChatSummary).sort((a, b) => b.updatedAt - a.updatedAt);\n\t\t},\n\t\tasync load(id: string): Promise<PptxAiStoredChat | null> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readonly');\n\t\t\tconst row = await requestToPromise<PptxAiStoredChat | undefined>(\n\t\t\t\ttx.objectStore(CHAT_STORE).get(id),\n\t\t\t);\n\t\t\tawait transactionDone(tx);\n\t\t\treturn row ?? null;\n\t\t},\n\t\tasync save(chat: PptxAiStoredChat): Promise<void> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readwrite');\n\t\t\ttx.objectStore(CHAT_STORE).put(chat);\n\t\t\tawait transactionDone(tx);\n\t\t},\n\t\tasync remove(id: string): Promise<void> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readwrite');\n\t\t\ttx.objectStore(CHAT_STORE).delete(id);\n\t\t\tawait transactionDone(tx);\n\t\t},\n\t\tasync clear(deckId: string | undefined): Promise<void> {\n\t\t\tconst tx = db.transaction(CHAT_STORE, 'readwrite');\n\t\t\tconst store = tx.objectStore(CHAT_STORE);\n\t\t\tif (deckId === undefined) {\n\t\t\t\tstore.clear();\n\t\t\t} else {\n\t\t\t\tconst ids = await requestToPromise<IDBValidKey[]>(\n\t\t\t\t\tstore.index(DECK_INDEX).getAllKeys(IDBKeyRange.only(deckId)),\n\t\t\t\t);\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tstore.delete(id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait transactionDone(tx);\n\t\t},\n\t};\n}\n"],"names":[],"mappings":"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"}