@@ -16,6 +16,7 @@ import type {
1616 DesktopPreviewRecordingArtifact ,
1717 DesktopPreviewRecordingFrame ,
1818 DesktopPreviewScreenshotArtifact ,
19+ DesktopPreviewTabDefaults ,
1920 PreviewAutomationClickInput ,
2021 PreviewAutomationActionEvent ,
2122 PreviewAutomationConsoleEntry ,
@@ -334,6 +335,21 @@ const findZoomStep = (current: number): number => {
334335 return Math . abs ( ZOOM_LEVELS [ index ] ! - current ) < ZOOM_EPSILON ? index : index - 1 ;
335336} ;
336337
338+ /**
339+ * Clamp a client-supplied zoom factor onto the discrete ladder. The setting is
340+ * chosen from the same ladder, but it arrives over IPC from a schema that only
341+ * guarantees a positive number, so an out-of-band value snaps to the nearest
342+ * step rather than leaving the guest at a zoom the zoom controls can't reach.
343+ */
344+ const normalizeZoomFactor = ( value : number | undefined ) : number => {
345+ if ( value === undefined || ! Number . isFinite ( value ) ) return DEFAULT_ZOOM_FACTOR ;
346+ let closest = ZOOM_LEVELS [ 0 ] ! ;
347+ for ( const level of ZOOM_LEVELS ) {
348+ if ( Math . abs ( level - value ) < Math . abs ( closest - value ) ) closest = level ;
349+ }
350+ return closest ;
351+ } ;
352+
337353const nextZoomLevel = ( current : number , direction : "in" | "out" ) : number => {
338354 const step = findZoomStep ( current ) ;
339355 if ( direction === "in" ) {
@@ -1614,6 +1630,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
16141630
16151631 const createTabUnlocked = Effect . fn ( "PreviewManager.createTabUnlocked" ) ( function * (
16161632 tabId : string ,
1633+ defaults ?: DesktopPreviewTabDefaults ,
16171634 ) {
16181635 const updatedAt = yield * currentIso ;
16191636 const result = yield * SynchronizedRef . modify (
@@ -1632,9 +1649,9 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
16321649 navStatus : { kind : "Idle" } ,
16331650 canGoBack : false ,
16341651 canGoForward : false ,
1635- zoomFactor : DEFAULT_ZOOM_FACTOR ,
1652+ zoomFactor : normalizeZoomFactor ( defaults ?. zoomFactor ) ,
16361653 pictureInPicture : false ,
1637- colorScheme : "system" ,
1654+ colorScheme : defaults ?. colorScheme ?? "system" ,
16381655 controller : "none" ,
16391656 updatedAt,
16401657 } ;
@@ -1653,8 +1670,11 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
16531670 return result . state ;
16541671 } ) ;
16551672
1656- const createTab = Effect . fn ( "PreviewManager.createTab" ) ( function * ( tabId : string ) {
1657- return yield * withTabLifecycleLock ( tabId , createTabUnlocked ( tabId ) ) ;
1673+ const createTab = Effect . fn ( "PreviewManager.createTab" ) ( function * (
1674+ tabId : string ,
1675+ defaults ?: DesktopPreviewTabDefaults ,
1676+ ) {
1677+ return yield * withTabLifecycleLock ( tabId , createTabUnlocked ( tabId , defaults ) ) ;
16581678 } ) ;
16591679
16601680 const closeTabUnlocked = Effect . fn ( "PreviewManager.closeTabUnlocked" ) ( function * ( tabId : string ) {
@@ -3802,7 +3822,10 @@ export class PreviewManager extends Context.Service<
38023822 readonly setMainWindow : ( window : BrowserWindow ) => Effect . Effect < void , PreviewManagerError > ;
38033823 readonly getBrowserSession : ( scope ?: string ) => Effect . Effect < Session , PreviewManagerError > ;
38043824 readonly isBrowserPartition : ( partition : string ) => boolean ;
3805- readonly createTab : ( tabId : string ) => Effect . Effect < PreviewTabState , PreviewManagerError > ;
3825+ readonly createTab : (
3826+ tabId : string ,
3827+ defaults ?: DesktopPreviewTabDefaults ,
3828+ ) => Effect . Effect < PreviewTabState , PreviewManagerError > ;
38063829 readonly closeTab : ( tabId : string ) => Effect . Effect < void , PreviewManagerError > ;
38073830 readonly registerWebview : (
38083831 tabId : string ,
0 commit comments