-
Notifications
You must be signed in to change notification settings - Fork 43
feat: expose setZoom and getZoom API on SuperDoc #1498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Add public methods to programmatically control zoom level:
- `setZoom(percent)` - Set zoom level (e.g., 150 for 150%)
- `getZoom()` - Get current zoom level as percentage
This allows developers to implement custom zoom controls
without relying on the toolbar UI.
Usage:
```javascript
// Set zoom to 150%
superdoc.setZoom(150);
// Get current zoom
const zoom = superdoc.getZoom(); // Returns 100, 150, etc.
// Listen for zoom changes
superdoc.on('zoomChange', ({ zoom }) => {
console.log(`Zoom changed to ${zoom}%`);
});
```
Closes superdoc-dev#928
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // Update all presentation editors | ||
| this.superdocStore?.documents?.forEach((doc) => { | ||
| const presentationEditor = typeof doc?.getPresentationEditor === 'function' ? doc.getPresentationEditor() : null; | ||
| if (presentationEditor && typeof presentationEditor.setZoom === 'function') { | ||
| presentationEditor.setZoom(zoomMultiplier); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setZoom bypasses shared activeZoom state
Programmatic zoom changes only call presentationEditor.setZoom for each document (lines shown) and emit an event, but they never update superdocStore.activeZoom. The rest of the UI scales overlays and coordinates from activeZoom (e.g., CommentsLayer.vue uses it to position highlights), and SuperDoc.vue watches it to propagate zoom to PresentationEditor globally. Calling the new setZoom() API will therefore zoom the document content while overlays and hit-testing still assume the previous zoom level, causing misaligned comments/selection after programmatic zoom changes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds programmatic zoom control to SuperDoc by exposing setZoom() and getZoom() public API methods, along with a zoomChange event. This enables developers to implement custom zoom controls (e.g., keyboard shortcuts, custom UI buttons, gesture controls) without relying on the built-in toolbar.
- Adds
getZoom()method to retrieve current zoom level as a percentage - Adds
setZoom(percent)method to programmatically set zoom level for all documents - Emits
zoomChangeevent when zoom is changed programmatically
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
| * Get the current zoom level as a percentage (e.g., 100 for 100%) | ||
| * @returns {number} The current zoom level as a percentage | ||
| * @example | ||
| * const zoom = superdoc.getZoom(); // Returns 100, 150, 200, etc. | ||
| */ | ||
| getZoom() { | ||
| const doc = this.superdocStore?.documents?.[0]; | ||
| const presentationEditor = typeof doc?.getPresentationEditor === 'function' ? doc.getPresentationEditor() : null; | ||
| if (presentationEditor && typeof presentationEditor.zoom === 'number') { | ||
| return Math.round(presentationEditor.zoom * 100); | ||
| } | ||
| // Fallback to 100% if no presentation editor | ||
| return 100; | ||
| } | ||
|
|
||
| /** | ||
| * Set the zoom level for all documents | ||
| * @param {number} percent - The zoom level as a percentage (e.g., 100, 150, 200) | ||
| * @example | ||
| * superdoc.setZoom(150); // Set zoom to 150% | ||
| * superdoc.setZoom(50); // Set zoom to 50% | ||
| */ | ||
| setZoom(percent) { | ||
| if (typeof percent !== 'number' || !Number.isFinite(percent) || percent <= 0) { | ||
| console.warn('[SuperDoc] setZoom expects a positive number representing percentage'); | ||
| return; | ||
| } | ||
|
|
||
| const zoomMultiplier = percent / 100; | ||
|
|
||
| // Update all presentation editors | ||
| this.superdocStore?.documents?.forEach((doc) => { | ||
| const presentationEditor = typeof doc?.getPresentationEditor === 'function' ? doc.getPresentationEditor() : null; | ||
| if (presentationEditor && typeof presentationEditor.setZoom === 'function') { | ||
| presentationEditor.setZoom(zoomMultiplier); | ||
| } | ||
| }); | ||
|
|
||
| // Emit zoom change event | ||
| this.emit('zoomChange', { zoom: percent }); | ||
| } |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new setZoom and getZoom methods lack test coverage. The test file at packages/superdoc/src/SuperDoc.test.js contains comprehensive tests for other SuperDoc methods, and these new public API methods should also be tested.
Consider adding tests that verify:
- setZoom correctly updates all presentation editors with the zoom multiplier
- getZoom returns the correct percentage from the presentation editor
- The zoomChange event is emitted with the correct payload
- Invalid inputs (negative, NaN, zero) are handled gracefully
- Behavior when no presentation editor exists
| presentationEditor.setZoom(zoomMultiplier); | ||
| } | ||
| }); | ||
|
|
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setZoom method emits a 'zoomChange' event but does not update the superdocStore.activeZoom property. This creates an inconsistency because:
- The existing onToolbarCommand method (line 678) sets this.superdocStore.activeZoom when the toolbar zoom is changed
- SuperDoc.vue watches activeZoom (lines 770-777) and calls PresentationEditor.setGlobalZoom when it changes
- By not updating activeZoom, this method bypasses the centralized state management, causing the store to be out of sync with the actual zoom level
The setZoom method should update this.superdocStore.activeZoom = percent before emitting the event, to ensure consistency with the existing zoom management pattern.
| // Update centralized zoom state before emitting event | |
| if (this.superdocStore) { | |
| this.superdocStore.activeZoom = percent; | |
| } |
| }); | ||
|
|
||
| // Emit zoom change event | ||
| this.emit('zoomChange', { zoom: percent }); |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The event name 'zoomChange' is inconsistent with the codebase's event naming convention. Other events in this file use kebab-case (e.g., 'pdf-document-ready', 'sidebar-toggle', 'editor-create', 'editor-destroy'), not camelCase.
This event should be renamed to 'zoom-change' to maintain consistency with the existing event naming pattern throughout the SuperDoc class.
| this.emit('zoomChange', { zoom: percent }); | |
| this.emit('zoom-change', { zoom: percent }); |
| /** | ||
| * Get the current zoom level as a percentage (e.g., 100 for 100%) | ||
| * @returns {number} The current zoom level as a percentage | ||
| * @example | ||
| * const zoom = superdoc.getZoom(); // Returns 100, 150, 200, etc. | ||
| */ | ||
| getZoom() { | ||
| const doc = this.superdocStore?.documents?.[0]; | ||
| const presentationEditor = typeof doc?.getPresentationEditor === 'function' ? doc.getPresentationEditor() : null; | ||
| if (presentationEditor && typeof presentationEditor.zoom === 'number') { | ||
| return Math.round(presentationEditor.zoom * 100); | ||
| } | ||
| // Fallback to 100% if no presentation editor | ||
| return 100; | ||
| } |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The getZoom method only reads from the first document (documents[0]), but setZoom updates all documents. This creates an asymmetry that could cause confusion:
- If you have multiple documents with different zoom levels, getZoom will only return the zoom of the first document
- After calling setZoom, all documents will have the same zoom level
This behavior should be documented in the JSDoc comment, or the implementation should be reconsidered to ensure consistent behavior. Consider adding a note like: "Note: When multiple documents exist, this returns the zoom level of the first document. Use setZoom to apply a zoom level to all documents."
Add 8 test cases covering: - getZoom returns 100 when no presentation editor is available - getZoom returns correct percentage from presentation editor - getZoom rounds to nearest integer - setZoom calls presentation editor with correct multiplier - setZoom emits zoomChange event - setZoom updates all editors in multi-document mode - setZoom handles invalid values gracefully - setZoom handles missing presentation editor
476c981 to
84f915c
Compare
|
@edoversb 🙏🏻 |
84f8ea5 to
2a443d8
Compare
Summary
Add public methods to programmatically control zoom level on SuperDoc instances:
setZoom(percent)- Set zoom level as a percentage (e.g., 150 for 150%)getZoom()- Get current zoom level as percentagezoomChangeevent - Emitted when zoom changesThis allows developers to implement custom zoom controls (e.g., Ctrl+scroll, pinch-to-zoom, custom UI buttons) without relying on the toolbar.
Usage
Test plan
superdoc.setZoom(150)and verify document scales to 150%superdoc.getZoom()and verify it returns correct percentagezoomChangeevent fires when zoom is changedCloses #928