pptx-angular-viewer 3.17.0 → 3.18.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.17.1](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@3.17.1) - 2026-09-14
11
+
12
+ ### Bug Fixes
13
+
14
+ - **i18n:** Localize inspector and ribbon controls (by @yunfeizhu) ([a657a76](https://github.com/ChristopherVR/pptx-viewer/commit/a657a766d653106f04d50f7b13a94a6c12c77f1e))
15
+
16
+ ## [3.17.0](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@3.17.0) - 2026-09-13
17
+
18
+ ### Features
19
+
20
+ - **shared:** Add configurable viewport fit options (by @Sudhansh6) ([93e3218](https://github.com/ChristopherVR/pptx-viewer/commit/93e3218de54ce8d153761e2fba83f3558fc3051b))
21
+ - **angular:** Add configurable viewport fit options (by @Sudhansh6) ([0125890](https://github.com/ChristopherVR/pptx-viewer/commit/0125890e03830e291b7c00978c2989ad31218f52))
22
+ - **shared:** Expose public element insertion across viewers (by @Sudhansh6) ([2701047](https://github.com/ChristopherVR/pptx-viewer/commit/2701047d5011b5d7ce8408009addc1dc31f6e3f7))
23
+
24
+ ### Bug Fixes
25
+
26
+ - **core:** Preserve empty paragraph insertion formatting (by @Sudhansh6) ([121f6bf](https://github.com/ChristopherVR/pptx-viewer/commit/121f6bf9f64a29ab07e07b5d4f042a4b075d7876))
27
+ - **shared:** Preserve empty paragraph insertion formatting (by @Sudhansh6) ([b34d0f5](https://github.com/ChristopherVR/pptx-viewer/commit/b34d0f5ab9879e02f1de85c0e50b15f3947735c3))
28
+ - **angular:** Preserve empty paragraph insertion formatting (by @Sudhansh6) ([28e4eb2](https://github.com/ChristopherVR/pptx-viewer/commit/28e4eb234641113fd82088c2c3cf9f9a34f03cdb))
29
+ - **vue,angular:** Honor public edit and preview mode switches (by @Sudhansh6) ([97b1e7b](https://github.com/ChristopherVR/pptx-viewer/commit/97b1e7b494d793fae1069583a7db1aa385550329))
30
+ - **shared:** Continue inserted paragraphs from the local list (by @Sudhansh6) ([78b8226](https://github.com/ChristopherVR/pptx-viewer/commit/78b82261a320b93052627ec9e6e460c4845f6f32))
31
+ - **shared:** Leave empty clipboard paste shortcuts unclaimed (by @Sudhansh6) ([aec446f](https://github.com/ChristopherVR/pptx-viewer/commit/aec446f7f36371ad2f9c1cf3e68b7aaeb4f2cc28))
32
+
33
+ ### Other
34
+
35
+ - Retain empty paragraph styles with source alignment (by @Sudhansh6) ([d979cd2](https://github.com/ChristopherVR/pptx-viewer/commit/d979cd25b7c05cef0fc4d4501c39d2bb11e572e0))
36
+ - Integrate semantic list commands with empty paragraph formatting (by @Sudhansh6) ([c5d9a6f](https://github.com/ChristopherVR/pptx-viewer/commit/c5d9a6f4f52c44180111c1f5fca0f10299dce47a))
37
+ - Sync main font and SmartArt fixes (by @Sudhansh6) ([f2066eb](https://github.com/ChristopherVR/pptx-viewer/commit/f2066eb87b62884cadd77593e8b36426398c3312))
38
+ - Sync main paragraph and history fixes (by @Sudhansh6) ([a18a2d7](https://github.com/ChristopherVR/pptx-viewer/commit/a18a2d7fe2bccf7d8c49b72d7a80087d423d1da0))
39
+ - Sync viewport fit changes from main (by @Sudhansh6) ([3c3c0bd](https://github.com/ChristopherVR/pptx-viewer/commit/3c3c0bdb2f88648dd20ffac9b6fd5a691741253d))
40
+ - Sync public insertion with viewport fit API (by @Sudhansh6) ([47df3db](https://github.com/ChristopherVR/pptx-viewer/commit/47df3db6bb7bb6bbee06e36c9ff9565b2fc61252))
41
+ - Sync public insertion with empty paragraph formatting (by @Sudhansh6) ([d1ad9c9](https://github.com/ChristopherVR/pptx-viewer/commit/d1ad9c9562313085cab62f3b9f9fa0abc6d0fa1f))
42
+ - Integrate preview and save-state fixes into insertion (by @Sudhansh6) ([1c33fb5](https://github.com/ChristopherVR/pptx-viewer/commit/1c33fb571634306e6dd989291185313e3cdafb49))
43
+
44
+ ### Documentation
45
+
46
+ - Move viewport fitting into developer guides (by @Sudhansh6) ([60707eb](https://github.com/ChristopherVR/pptx-viewer/commit/60707ebf8f261779b2ebfa41ff0741267a672bd3))
47
+
10
48
  ## [3.16.7](https://github.com/ChristopherVR/pptx-viewer/releases/tag/pptx-angular-viewer@3.16.7) - 2026-09-13
11
49
 
12
50
  ### Bug Fixes
package/README.md CHANGED
@@ -55,7 +55,7 @@ npm install @angular/core @angular/common rxjs @ngx-translate/core
55
55
  ```
56
56
 
57
57
  **Optional peers:** `three` enables interactive GLB/GLTF 3D models and the
58
- `smartArt3D` renderer; `yjs` + `y-websocket` (or `y-webrtc` for serverless
58
+ `smartArt3D` and 3D chart renderers; `yjs` + `y-websocket` (or `y-webrtc` for serverless
59
59
  peer-to-peer) enable real-time collaboration. Without them those features
60
60
  degrade gracefully (poster images, no live session).
61
61
 
@@ -227,28 +227,30 @@ geometry or user zoom. See the [cross-binding defaults](../../docs/guide/viewpor
227
227
 
228
228
  ### Inputs
229
229
 
230
- | Input | Type | Default | Description |
231
- | ------------------ | ------------------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------- |
232
- | `content` | `Uint8Array \| ArrayBuffer \| null` | `null` | The `.pptx` bytes to render. |
233
- | `theme` | `ViewerTheme` | n/a | Color/radius overrides applied as CSS custom properties. Always wins over the File > Options theme picker. |
234
- | `class` | `string` | `''` | Class applied to the root element. |
235
- | `canEdit` | `boolean` | `false` | Enables the editor toolbar, inspector, and drag-and-drop editing. |
236
- | `filePath` | `string` | n/a | Host file path/identifier keying the version-history store. |
237
- | `fileName` | `string` | n/a | Display name of the open document, shown in the title bar. |
238
- | `fonts` | `ViewerFontSource[]` | `[]` | Licensed font sources supplied by the host application. |
239
- | `authorName` | `string` | n/a | Display name for the local user in collaboration/broadcast sessions and presence avatars. |
240
- | `collaboration` | `CollaborationConfig` | n/a | Yjs real-time collaboration config (server URL, room, role). |
241
- | `shareDefaults` | `{ roomId?, userName?, serverUrl? }` | n/a | Seed values for the Share dialog's start form. |
242
- | `onOpenFile` | `() => void` | n/a | Host override for File > Open; bypasses the built-in file picker. |
243
- | `smartArt3D` | `boolean` | `false` | Opt-in Three.js 3D SmartArt renderer (needs the optional `three` peer; falls back to SVG without it). |
244
- | `hiddenActions` | `ToolbarActionId[]` | `[]` | Toolbar buttons/ribbon tabs to hide individually (e.g. `['share', 'broadcast']`), instead of hiding the whole toolbar. |
245
- | `defaultThemeKey` | `string` | n/a | Initial File > Options > Appearance selection when no persisted preference exists. |
246
- | `availableThemes` | `ThemeCatalogEntry[]` | n/a | Theme choices offered by File > Options > Appearance (defaults to the built-in catalog). |
247
- | `onThemeChange` | `(key: string) => void` | n/a | Host hook for the appearance picker; when set, the host owns persisting the choice. |
248
- | `defaultLocale` | `string` | n/a | Initial locale code when no persisted preference exists. |
249
- | `availableLocales` | `LocaleCatalogEntry[]` | n/a | Locale choices offered by File > Options > Language (defaults to the registered `TranslateService` languages). |
250
- | `onLocaleChange` | `(code: string) => void` | n/a | Host hook for the language picker; when set, the host owns applying/persisting the switch. |
251
- | `accountAuth` | `AccountAuthConfig` | n/a | Optional sign-in hook point for File > Account (disabled unless `enabled: true`). |
230
+ | Input | Type | Default | Description |
231
+ | -------------------------------------------------------------------------- | ------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
232
+ | `content` | `Uint8Array \| ArrayBuffer \| null` | `null` | The `.pptx` bytes to render. |
233
+ | `theme` | `ViewerTheme` | n/a | Color/radius overrides applied as CSS custom properties. Always wins over the File > Options theme picker. |
234
+ | `class` | `string` | `''` | Class applied to the root element. |
235
+ | `canEdit` | `boolean` | `false` | Enables the editor toolbar, inspector, and drag-and-drop editing. |
236
+ | `filePath` | `string` | n/a | Host file path/identifier keying the version-history store. |
237
+ | `fileName` | `string` | n/a | Display name of the open document, shown in the title bar. |
238
+ | `fonts` | `ViewerFontSource[]` | `[]` | Licensed font sources supplied by the host application. |
239
+ | `authorName` | `string` | n/a | Display name for the local user in collaboration/broadcast sessions and presence avatars. |
240
+ | `collaboration` | `CollaborationConfig` | n/a | Yjs real-time collaboration config (server URL, room, role). |
241
+ | `shareDefaults` | `{ roomId?, userName?, serverUrl? }` | n/a | Seed values for the Share dialog's start form. |
242
+ | `onOpenFile` | `() => void` | n/a | Host override for File > Open; bypasses the built-in file picker. |
243
+ | `smartArt3D` | `boolean` | `false` | Opt-in Three.js 3D SmartArt renderer (needs the optional `three` peer; falls back to SVG without it). |
244
+ | `surfaceChart3D`, `barChart3D`, `lineChart3D`, `areaChart3D`, `pieChart3D` | `boolean` | `false` | Independently opt in to interactive Three.js renderers for the matching 3D chart kinds; each falls back to SVG when WebGL is unavailable. |
245
+ | `ai` | `PptxAiConfig` | n/a | Optional AI assistant configuration. The SDK peer loads only when its panel is opened. |
246
+ | `hiddenActions` | `ToolbarActionId[]` | `[]` | Toolbar buttons/ribbon tabs to hide individually (e.g. `['share', 'broadcast']`), instead of hiding the whole toolbar. |
247
+ | `defaultThemeKey` | `string` | n/a | Initial File > Options > Appearance selection when no persisted preference exists. |
248
+ | `availableThemes` | `ThemeCatalogEntry[]` | n/a | Theme choices offered by File > Options > Appearance (defaults to the built-in catalog). |
249
+ | `onThemeChange` | `(key: string) => void` | n/a | Host hook for the appearance picker; when set, the host owns persisting the choice. |
250
+ | `defaultLocale` | `string` | n/a | Initial locale code when no persisted preference exists. |
251
+ | `availableLocales` | `LocaleCatalogEntry[]` | n/a | Locale choices offered by File > Options > Language (defaults to the registered `TranslateService` languages). |
252
+ | `onLocaleChange` | `(code: string) => void` | n/a | Host hook for the language picker; when set, the host owns applying/persisting the switch. |
253
+ | `accountAuth` | `AccountAuthConfig` | n/a | Optional sign-in hook point for File > Account (disabled unless `enabled: true`). |
252
254
 
253
255
  ### Outputs
254
256
 
@@ -1,4 +1,4 @@
1
- import { t as toChatSummary } from './pptx-angular-viewer-pptx-angular-viewer-CY2-kaW3.mjs';
1
+ import { t as toChatSummary } from './pptx-angular-viewer-pptx-angular-viewer-B3FNZYVL.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-DjOCNjw-.mjs.map
106
+ //# sourceMappingURL=pptx-angular-viewer-chat-history-idb-BaGfTtS5.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pptx-angular-viewer-chat-history-idb-DjOCNjw-.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-BaGfTtS5.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":";;AAAA;;;;;;;;AAQG;AAKH;AACO,MAAM,UAAU,GAAG;AAC1B;AACA,MAAM,UAAU,GAAG,QAAQ;AAE3B;AACA,SAAS,gBAAgB,CAAI,OAAsB,EAAA;IAClD,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,KAAI;AACzC,QAAA,OAAO,CAAC,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;AACjD,QAAA,OAAO,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AACxF,IAAA,CAAC,CAAC;AACH;AAEA;AACA,SAAS,eAAe,CAAC,EAAkB,EAAA;IAC1C,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,KAAI;QAC5C,EAAE,CAAC,UAAU,GAAG,MAAM,OAAO,EAAE;AAC/B,QAAA,EAAE,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;AACjF,QAAA,EAAE,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;AACnF,IAAA,CAAC,CAAC;AACH;AAEA;;;AAGG;AACG,SAAU,UAAU,CAAC,MAAc,EAAA;AACxC,IAAA,MAAM,GAAG,GAAG,OAAO,SAAS,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS;IACpE,IAAI,CAAC,GAAG,EAAE;AACT,QAAA,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC;IACnE;IACA,OAAO,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,MAAM,KAAI;QACnD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAChC,QAAA,IAAI,CAAC,eAAe,GAAG,MAAK;AAC3B,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM;YACtB,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;AAC9C,gBAAA,MAAM,KAAK,GAAG,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjE,gBAAA,KAAK,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;YAC3D;AACD,QAAA,CAAC;AACD,QAAA,IAAI,CAAC,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;AAC3C,QAAA,IAAI,CAAC,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AACjF,QAAA,IAAI,CAAC,SAAS,GAAG,MAAM,MAAM,CAAC,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;AAC1F,IAAA,CAAC,CAAC;AACH;AAEA;AACA,eAAe,OAAO,CAAC,EAAe,EAAE,MAA0B,EAAA;IACjE,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC;IACjD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC;AACxC,IAAA,MAAM,MAAM,GACX,MAAM,KAAK;AACV,UAAE,KAAK,CAAC,MAAM;AACd,UAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5D,IAAA,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAqB,MAAM,CAAC;AAC/D,IAAA,MAAM,eAAe,CAAC,EAAE,CAAC;AACzB,IAAA,OAAO,IAAI;AACZ;AAEA;AACM,SAAU,gBAAgB,CAAC,EAAe,EAAA;IAC/C,OAAO;QACN,MAAM,IAAI,CAAC,MAA0B,EAAA;YACpC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC;YACtC,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;QACzE,CAAC;QACD,MAAM,IAAI,CAAC,EAAU,EAAA;YACpB,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC;AACjD,YAAA,MAAM,GAAG,GAAG,MAAM,gBAAgB,CACjC,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAClC;AACD,YAAA,MAAM,eAAe,CAAC,EAAE,CAAC;YACzB,OAAO,GAAG,IAAI,IAAI;QACnB,CAAC;QACD,MAAM,IAAI,CAAC,IAAsB,EAAA;YAChC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC;YAClD,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;AACpC,YAAA,MAAM,eAAe,CAAC,EAAE,CAAC;QAC1B,CAAC;QACD,MAAM,MAAM,CAAC,EAAU,EAAA;YACtB,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC;YAClD,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;AACrC,YAAA,MAAM,eAAe,CAAC,EAAE,CAAC;QAC1B,CAAC;QACD,MAAM,KAAK,CAAC,MAA0B,EAAA;YACrC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC;YAClD,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC;AACxC,YAAA,IAAI,MAAM,KAAK,SAAS,EAAE;gBACzB,KAAK,CAAC,KAAK,EAAE;YACd;iBAAO;gBACN,MAAM,GAAG,GAAG,MAAM,gBAAgB,CACjC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAC5D;AACD,gBAAA,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE;AACrB,oBAAA,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBACjB;YACD;AACA,YAAA,MAAM,eAAe,CAAC,EAAE,CAAC;QAC1B,CAAC;KACD;AACF;;"}