···14141515### Changed
1616- Wired the shared export-feedback helper into silent-failing export paths across every editor: diagrams (SVG, PNG, ASCII with correct `.shapes.size` Map accessor), forms (CSV/XLSX response exports), sheets (CSV, TSV, XLSX, PDF), docs (HTML, Markdown, TXT, PDF, DOCX). Every export now either confirms success with a row/slide/document count or surfaces the real error via toast instead of failing silently. (#686)
1717+- Promoted save-indicator + save-status-ui from sheets-only modules (`src/sheets/save-*.ts`) to shared library modules (`src/lib/save-*.ts`). Docs, slides, forms, diagrams, and calendar now share a single `wireSaveStatus({ provider, ydoc })` helper with consistent "Saved / Saving… / Saved locally / Unsaved changes" feedback — previously only sheets and docs had live autosave state, and docs carried a 50-line inline copy. Slides, forms, diagrams, and calendar HTML upgraded from an empty `<span class="save-status">` to the full indicator DOM (dot + text). Docs main.ts replaces its inline implementation with a one-line call. 8 new jsdom tests pin the wiring contract (saving→saved transitions, dot class flips, offline "Saved locally" fallback, ydoc-origin echo filtering). (#689)
17181819## [0.52.0] — 2026-04-16
1920
···1010import { EncryptedProvider } from '../lib/provider.js';
1111import { installDocGoneHandler } from '../lib/doc-gone-handler.js';
1212import { wireKeyWarningForSession } from '../lib/key-warning.js';
1313+import { wireSaveStatus } from '../lib/save-status-ui.js';
1314import { setupTooltips } from '../lib/tooltips.js';
1415import { mountOfflineIndicator } from '../lib/offline-indicator.js';
1516import { createForm, setTargetSheet, type FormSchema } from './form-builder.js';
···221222 const provider = new EncryptedProvider(ydoc, docId, cryptoKey);
222223 installDocGoneHandler(provider);
223224 wireKeyWarningForSession(docId, document.querySelector<HTMLElement>('.app-topbar'));
225225+ wireSaveStatus({ provider, ydoc });
224226225227 provider.on('sync', () => {
226228 loadFormFromYjs();
+1-1
src/sheets/main.ts
···2525import { wireKeyboardHandler as _wireKeyboardHandler } from './keyboard-handler.js';
2626import { moveSelection as _moveSelection, extendSelection as _extendSelection, moveSelectionTo as _moveSelectionTo, getDataExtent as _getDataExtent, scrollCellIntoView as _scrollCellIntoView, updateSelectionVisuals as _updateSelectionVisuals, clearPrevSelection as _clearPrevSelection, getCellEl as _getCellEl } from './selection-navigation.js';
2727import { deleteSelectedCells as _deleteSelectedCells, copySelection as _copySelection, pasteRowsAtSelection as _pasteRowsAtSelection, pasteAtSelection as _pasteAtSelection, showPasteSpecialDialog as _showPasteSpecialDialogCO, wirePasteListener as _wirePasteListener } from './clipboard-operations.js';
2828-import { wireSaveStatus } from './save-status-ui.js';
2828+import { wireSaveStatus } from '../lib/save-status-ui.js';
2929import { renderGrid as _renderGridGR, scheduleRenderGrid as _scheduleRenderGrid, renderSparklines as _renderSparklines } from './grid-rendering.js';
3030import { onGridTouchStart as _onGridTouchStart, wireTouchDoubleTap as _wireTouchDoubleTap } from './touch-events.js';
3131import { startEditing as _startEditingCE, commitEdit as _commitEditCE, updateFormulaBar as _updateFormulaBarCE, attachCellEditorFormulaUX as _attachCellEditorFormulaUXCE } from './cell-editing.js';