fix(editor): edgeless can't slider with finger (#15091)

fix bug edgeless can't slider with finger 

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added mobile immersive edgeless mode with dynamic chrome auto-hide and
tap-gesture controls.
  * Added a mobile zoom ruler UI for edgeless.
* **Bug Fixes**
* Improved iOS rendering/zoom by applying low-zoom survival behavior,
gesture-aware refresh deferral, and effective-DPR canvas scaling.
* Fixed iOS webview zoom/bounce and process-termination reload behavior.
  * Improved placeholder styling with theme-aware colors.
* **Chores**
  * Updated local ignore rules and iOS app build/version configuration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: DarkSky <darksky2048@gmail.com>
This commit is contained in:
keepClamDown
2026-06-16 21:19:31 +08:00
committed by GitHub
parent c51bdb74de
commit a77d89bb1a
43 changed files with 4749 additions and 273 deletions
@@ -318,29 +318,71 @@ export class Editor extends Entity {
}
// update scroll position when scrollViewport scroll
const saveScrollPosition = () => {
if (this.mode$.value === 'page' && scrollViewport) {
this.scrollPosition.page = scrollViewport.scrollTop;
this.workbenchView?.setScrollPosition(scrollViewport.scrollTop);
} else if (this.mode$.value === 'edgeless' && gfx) {
const pos = {
centerX: gfx.viewport.centerX,
centerY: gfx.viewport.centerY,
zoom: gfx.viewport.zoom,
};
this.scrollPosition.edgeless = pos;
this.workbenchView?.setScrollPosition(pos);
let edgelessWriteTimer: ReturnType<typeof setTimeout> | null = null;
const flushEdgelessScrollPosition = () => {
if (edgelessWriteTimer) {
clearTimeout(edgelessWriteTimer);
edgelessWriteTimer = null;
}
const pos = this.scrollPosition.edgeless;
if (!pos) {
return;
}
this.workbenchView?.setScrollPosition(pos);
};
scrollViewport?.addEventListener('scroll', saveScrollPosition);
const savePageScrollPosition = () => {
if (!scrollViewport || this.mode$.value !== 'page') {
return;
}
this.scrollPosition.page = scrollViewport.scrollTop;
this.workbenchView?.setScrollPosition(scrollViewport.scrollTop);
};
const saveEdgelessScrollPosition = () => {
if (!gfx || this.mode$.value !== 'edgeless') {
return;
}
this.scrollPosition.edgeless = {
centerX: gfx.viewport.centerX,
centerY: gfx.viewport.centerY,
zoom: gfx.viewport.zoom,
};
if (edgelessWriteTimer) {
clearTimeout(edgelessWriteTimer);
}
edgelessWriteTimer = setTimeout(() => {
flushEdgelessScrollPosition();
}, 160);
};
const handleViewportScroll = () => {
if (this.mode$.value === 'edgeless' && scrollViewport) {
return;
}
savePageScrollPosition();
};
scrollViewport?.addEventListener('scroll', handleViewportScroll);
unsubs.push(() => {
scrollViewport?.removeEventListener('scroll', saveScrollPosition);
scrollViewport?.removeEventListener('scroll', handleViewportScroll);
});
if (gfx) {
const subscription =
gfx.viewport.viewportUpdated.subscribe(saveScrollPosition);
const subscription = gfx.viewport.viewportUpdated.subscribe(() => {
saveEdgelessScrollPosition();
});
unsubs.push(subscription.unsubscribe.bind(subscription));
}
unsubs.push(() => {
flushEdgelessScrollPosition();
});
// update selection when focusAt$ changed
const subscription = this.focusAt$