Переглянути джерело

feat(api): add `toIpc` method on dpi types, add more constructors

amrbashir 10 місяців тому
батько
коміт
bee00b461a

+ 5 - 0
.changes/api-toIpc.md

@@ -0,0 +1,5 @@
+---
+"@tauri-apps": "patch:feat"
+---
+
+Add to `toIpc`  method on `PhysicalSize`, `PhysicalPosition`, `LogicalSize` and `LogicalPosition` to convert it into IPC-compatible value that can be deserialized correctly on the Rust side into its equivalent struct.

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
crates/tauri/scripts/bundle.global.js


+ 187 - 18
packages/api/src/dpi.ts

@@ -8,20 +8,40 @@
  * @since 2.0.0
  */
 class LogicalSize {
-  type = 'Logical'
+  type = 'Logical' as const
   width: number
   height: number
 
-  constructor(width: number, height: number) {
-    this.width = width
-    this.height = height
+  constructor(width: number, height: number)
+  constructor(objcet: { Logical: { width: number; height: number } })
+  constructor(objcet: { width: number; height: number })
+  constructor(
+    ...args:
+      | [number, number]
+      | [{ width: number; height: number }]
+      | [{ Logical: { width: number; height: number } }]
+  ) {
+    if (args.length === 1) {
+      if ('Logical' in args[0]) {
+        this.width = args[0].Logical.width
+        this.height = args[0].Logical.height
+      } else {
+        this.width = args[0].width
+        this.height = args[0].height
+      }
+    } else {
+      this.width = args[0]
+      this.height = args[1]
+    }
   }
 
   /**
    * Converts the logical size to a physical one.
    * @example
    * ```typescript
+   * import { LogicalSize } from '@tauri-apps/api/dpi';
    * import { getCurrentWindow } from '@tauri-apps/api/window';
+   *
    * const appWindow = getCurrentWindow();
    * const factor = await appWindow.scaleFactor();
    * const size = new LogicalSize(400, 500);
@@ -33,6 +53,29 @@ class LogicalSize {
   toPhysical(scaleFactor: number): PhysicalSize {
     return new PhysicalSize(this.width * scaleFactor, this.height * scaleFactor)
   }
+
+  /**
+   * Converts this size into IPC-compatible value, so it can be
+   * deserialized correctly on the Rust side using `tauri::LogicalSize` struct.
+   * @example
+   * ```typescript
+   * import { LogicalSize } from '@tauri-apps/api/dpi';
+   * import { invoke } from '@tauri-apps/api/core';
+   *
+   * const size = new LogicalSize(400, 500);
+   * await invoke("do_something_with_size", { size: size.toIpc() })
+   * ```
+   *
+   * @since 2.0.0
+   */
+  toIpc(): { Logical: { width: number; height: number } } {
+    return {
+      Logical: {
+        width: this.width,
+        height: this.height
+      }
+    }
+  }
 }
 
 /**
@@ -41,13 +84,31 @@ class LogicalSize {
  * @since 2.0.0
  */
 class PhysicalSize {
-  type = 'Physical'
+  type = 'Physical' as const
   width: number
   height: number
 
-  constructor(width: number, height: number) {
-    this.width = width
-    this.height = height
+  constructor(width: number, height: number)
+  constructor(objcet: { Physical: { width: number; height: number } })
+  constructor(objcet: { width: number; height: number })
+  constructor(
+    ...args:
+      | [number, number]
+      | [{ width: number; height: number }]
+      | [{ Physical: { width: number; height: number } }]
+  ) {
+    if (args.length === 1) {
+      if ('Physical' in args[0]) {
+        this.width = args[0].Physical.width
+        this.height = args[0].Physical.height
+      } else {
+        this.width = args[0].width
+        this.height = args[0].height
+      }
+    } else {
+      this.width = args[0]
+      this.height = args[1]
+    }
   }
 
   /**
@@ -57,13 +118,36 @@ class PhysicalSize {
    * import { getCurrentWindow } from '@tauri-apps/api/window';
    * const appWindow = getCurrentWindow();
    * const factor = await appWindow.scaleFactor();
-   * const size = await appWindow.innerSize();
+   * const size = await appWindow.innerSize(); // PhysicalSize
    * const logical = size.toLogical(factor);
    * ```
    */
   toLogical(scaleFactor: number): LogicalSize {
     return new LogicalSize(this.width / scaleFactor, this.height / scaleFactor)
   }
+
+  /**
+   * Converts this size into IPC-compatible value, so it can be
+   * deserialized correctly on the Rust side using `tauri::PhysicalSize` struct.
+   * @example
+   * ```typescript
+   * import { PhysicalSize } from '@tauri-apps/api/dpi';
+   * import { invoke } from '@tauri-apps/api/core';
+   *
+   * const size = new PhysicalSize(400, 500);
+   * await invoke("do_something_with_size", { size: size.toIpc() })
+   * ```
+   *
+   * @since 2.0.0
+   */
+  toIpc(): { Physical: { width: number; height: number } } {
+    return {
+      Physical: {
+        width: this.width,
+        height: this.height
+      }
+    }
+  }
 }
 
 /**
@@ -72,20 +156,40 @@ class PhysicalSize {
  * @since 2.0.0
  */
 class LogicalPosition {
-  type = 'Logical'
+  type = 'Logical' as const
   x: number
   y: number
 
-  constructor(x: number, y: number) {
-    this.x = x
-    this.y = y
+  constructor(x: number, y: number)
+  constructor(objcet: { Logical: { x: number; y: number } })
+  constructor(objcet: { x: number; y: number })
+  constructor(
+    ...args:
+      | [number, number]
+      | [{ x: number; y: number }]
+      | [{ Logical: { x: number; y: number } }]
+  ) {
+    if (args.length === 1) {
+      if ('Logical' in args[0]) {
+        this.x = args[0].Logical.x
+        this.y = args[0].Logical.y
+      } else {
+        this.x = args[0].x
+        this.y = args[0].y
+      }
+    } else {
+      this.x = args[0]
+      this.y = args[1]
+    }
   }
 
   /**
    * Converts the logical position to a physical one.
    * @example
    * ```typescript
+   * import { LogicalPosition } from '@tauri-apps/api/dpi';
    * import { getCurrentWindow } from '@tauri-apps/api/window';
+   *
    * const appWindow = getCurrentWindow();
    * const factor = await appWindow.scaleFactor();
    * const position = new LogicalPosition(400, 500);
@@ -97,6 +201,29 @@ class LogicalPosition {
   toPhysical(scaleFactor: number): PhysicalPosition {
     return new PhysicalPosition(this.x * scaleFactor, this.x * scaleFactor)
   }
+
+  /**
+   * Converts this position into IPC-compatible value, so it can be
+   * deserialized correctly on the Rust side using `tauri::LogicalPosition` struct.
+   * @example
+   * ```typescript
+   * import { LogicalPosition } from '@tauri-apps/api/dpi';
+   * import { invoke } from '@tauri-apps/api/core';
+   *
+   * const position = new LogicalPosition(400, 500);
+   * await invoke("do_something_with_position", { size: size.toIpc() })
+   * ```
+   *
+   * @since 2.0.0
+   */
+  toIpc(): { Logical: { x: number; y: number } } {
+    return {
+      Logical: {
+        x: this.x,
+        y: this.y
+      }
+    }
+  }
 }
 
 /**
@@ -105,13 +232,31 @@ class LogicalPosition {
  * @since 2.0.0
  */
 class PhysicalPosition {
-  type = 'Physical'
+  type = 'Physical' as const
   x: number
   y: number
 
-  constructor(x: number, y: number) {
-    this.x = x
-    this.y = y
+  constructor(x: number, y: number)
+  constructor(objcet: { Physical: { x: number; y: number } })
+  constructor(objcet: { x: number; y: number })
+  constructor(
+    ...args:
+      | [number, number]
+      | [{ x: number; y: number }]
+      | [{ Physical: { x: number; y: number } }]
+  ) {
+    if (args.length === 1) {
+      if ('Physical' in args[0]) {
+        this.x = args[0].Physical.x
+        this.y = args[0].Physical.y
+      } else {
+        this.x = args[0].x
+        this.y = args[0].y
+      }
+    } else {
+      this.x = args[0]
+      this.y = args[1]
+    }
   }
 
   /**
@@ -119,15 +264,39 @@ class PhysicalPosition {
    * @example
    * ```typescript
    * import { getCurrentWindow } from '@tauri-apps/api/window';
+   *
    * const appWindow = getCurrentWindow();
    * const factor = await appWindow.scaleFactor();
-   * const position = await appWindow.innerPosition();
+   * const position = await appWindow.innerPosition(); // PhysicalPosition
    * const logical = position.toLogical(factor);
    * ```
    */
   toLogical(scaleFactor: number): LogicalPosition {
     return new LogicalPosition(this.x / scaleFactor, this.y / scaleFactor)
   }
+
+  /**
+   * Converts this position into IPC-compatible value, so it can be
+   * deserialized correctly on the Rust side using `tauri::PhysicalPosition` struct.
+   * @example
+   * ```typescript
+   * import { PhysicalPosition } from '@tauri-apps/api/dpi';
+   * import { invoke } from '@tauri-apps/api/core';
+   *
+   * const position = new PhysicalPosition(400, 500);
+   * await invoke("do_something_with_position", { size: size.toIpc() })
+   * ```
+   *
+   * @since 2.0.0
+   */
+  toIpc(): { Physical: { x: number; y: number } } {
+    return {
+      Physical: {
+        x: this.x,
+        y: this.y
+      }
+    }
+  }
 }
 
 export { LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize }

+ 1 - 9
packages/api/src/menu/menu.ts

@@ -243,19 +243,11 @@ export class Menu extends MenuItemBase {
     at?: PhysicalPosition | LogicalPosition,
     window?: Window
   ): Promise<void> {
-    let atValue = null
-    if (at) {
-      atValue = {} as Record<string, unknown>
-      atValue[`${at instanceof PhysicalPosition ? 'Physical' : 'Logical'}`] = {
-        x: at.x,
-        y: at.y
-      }
-    }
     return invoke('plugin:menu|popup', {
       rid: this.rid,
       kind: this.kind,
       window: window?.label ?? null,
-      at: atValue
+      at: at?.toIpc()
     })
   }
 

+ 1 - 9
packages/api/src/menu/submenu.ts

@@ -243,19 +243,11 @@ export class Submenu extends MenuItemBase {
     at?: PhysicalPosition | LogicalPosition,
     window?: Window
   ): Promise<void> {
-    let atValue = null
-    if (at) {
-      atValue = {} as Record<string, unknown>
-      atValue[`${at instanceof PhysicalPosition ? 'Physical' : 'Logical'}`] = {
-        x: at.x,
-        y: at.y
-      }
-    }
     return invoke('plugin:menu|popup', {
       rid: this.rid,
       kind: this.kind,
       window: window?.label ?? null,
-      at: atValue
+      at: at?.toIpc()
     })
   }
 

+ 3 - 10
packages/api/src/tray.ts

@@ -290,16 +290,9 @@ export class TrayIcon extends Resource {
 function mapEvent(e: RustTrayIconEvent): TrayIconEvent {
   const out = e as unknown as TrayIconEvent
 
-  out.position = new PhysicalPosition(e.position.x, e.position.y)
-
-  out.rect.position = new PhysicalPosition(
-    e.rect.position.Physical.x,
-    e.rect.position.Physical.y
-  )
-  out.rect.size = new PhysicalSize(
-    e.rect.size.Physical.width,
-    e.rect.size.Physical.height
-  )
+  out.position = new PhysicalPosition(e.position)
+  out.rect.position = new PhysicalPosition(e.rect.position)
+  out.rect.size = new PhysicalSize(e.rect.size)
 
   return out
 }

+ 10 - 44
packages/api/src/webview.ts

@@ -359,9 +359,9 @@ class Webview {
    * @returns The webview's position.
    */
   async position(): Promise<PhysicalPosition> {
-    return invoke<{ x: number; y: number }>('plugin:webview|webview_position', {
+    return invoke<PhysicalPosition>('plugin:webview|webview_position', {
       label: this.label
-    }).then(({ x, y }) => new PhysicalPosition(x, y))
+    }).then((p) => new PhysicalPosition(p))
   }
 
   /**
@@ -376,12 +376,9 @@ class Webview {
    * @returns The webview's size.
    */
   async size(): Promise<PhysicalSize> {
-    return invoke<{ width: number; height: number }>(
-      'plugin:webview|webview_size',
-      {
-        label: this.label
-      }
-    ).then(({ width, height }) => new PhysicalSize(width, height))
+    return invoke<PhysicalSize>('plugin:webview|webview_size', {
+      label: this.label
+    }).then((s) => new PhysicalSize(s))
   }
 
   // Setters
@@ -414,21 +411,9 @@ class Webview {
    * @returns A promise indicating the success or failure of the operation.
    */
   async setSize(size: LogicalSize | PhysicalSize): Promise<void> {
-    if (!size || (size.type !== 'Logical' && size.type !== 'Physical')) {
-      throw new Error(
-        'the `size` argument must be either a LogicalSize or a PhysicalSize instance'
-      )
-    }
-
-    const value = {} as Record<string, unknown>
-    value[`${size.type}`] = {
-      width: size.width,
-      height: size.height
-    }
-
     return invoke('plugin:webview|set_webview_size', {
       label: this.label,
-      value
+      value: size.toIpc()
     })
   }
 
@@ -446,24 +431,9 @@ class Webview {
   async setPosition(
     position: LogicalPosition | PhysicalPosition
   ): Promise<void> {
-    if (
-      !position ||
-      (position.type !== 'Logical' && position.type !== 'Physical')
-    ) {
-      throw new Error(
-        'the `position` argument must be either a LogicalPosition or a PhysicalPosition instance'
-      )
-    }
-
-    const value = {} as Record<string, unknown>
-    value[`${position.type}`] = {
-      x: position.x,
-      y: position.y
-    }
-
     return invoke('plugin:webview|set_webview_position', {
       label: this.label,
-      value
+      value: position.toIpc()
     })
   }
 
@@ -603,7 +573,7 @@ class Webview {
           payload: {
             type: 'enter',
             paths: event.payload.paths,
-            position: mapPhysicalPosition(event.payload.position)
+            position: new PhysicalPosition(event.payload.position)
           }
         })
       }
@@ -616,7 +586,7 @@ class Webview {
           ...event,
           payload: {
             type: 'over',
-            position: mapPhysicalPosition(event.payload.position)
+            position: new PhysicalPosition(event.payload.position)
           }
         })
       }
@@ -630,7 +600,7 @@ class Webview {
           payload: {
             type: 'drop',
             paths: event.payload.paths,
-            position: mapPhysicalPosition(event.payload.position)
+            position: new PhysicalPosition(event.payload.position)
           }
         })
       }
@@ -652,10 +622,6 @@ class Webview {
   }
 }
 
-function mapPhysicalPosition(m: PhysicalPosition): PhysicalPosition {
-  return new PhysicalPosition(m.x, m.y)
-}
-
 /**
  * Configuration for the webview to create.
  *

+ 23 - 109
packages/api/src/window.ts

@@ -528,9 +528,9 @@ class Window {
    * @returns The window's inner position.
    */
   async innerPosition(): Promise<PhysicalPosition> {
-    return invoke<{ x: number; y: number }>('plugin:window|inner_position', {
+    return invoke<PhysicalPosition>('plugin:window|inner_position', {
       label: this.label
-    }).then(({ x, y }) => new PhysicalPosition(x, y))
+    }).then((p) => new PhysicalPosition(p))
   }
 
   /**
@@ -544,9 +544,9 @@ class Window {
    * @returns The window's outer position.
    */
   async outerPosition(): Promise<PhysicalPosition> {
-    return invoke<{ x: number; y: number }>('plugin:window|outer_position', {
+    return invoke<PhysicalPosition>('plugin:window|outer_position', {
       label: this.label
-    }).then(({ x, y }) => new PhysicalPosition(x, y))
+    }).then((p) => new PhysicalPosition(p))
   }
 
   /**
@@ -561,12 +561,9 @@ class Window {
    * @returns The window's inner size.
    */
   async innerSize(): Promise<PhysicalSize> {
-    return invoke<{ width: number; height: number }>(
-      'plugin:window|inner_size',
-      {
-        label: this.label
-      }
-    ).then(({ width, height }) => new PhysicalSize(width, height))
+    return invoke<PhysicalSize>('plugin:window|inner_size', {
+      label: this.label
+    }).then((s) => new PhysicalSize(s))
   }
 
   /**
@@ -581,12 +578,9 @@ class Window {
    * @returns The window's outer size.
    */
   async outerSize(): Promise<PhysicalSize> {
-    return invoke<{ width: number; height: number }>(
-      'plugin:window|outer_size',
-      {
-        label: this.label
-      }
-    ).then(({ width, height }) => new PhysicalSize(width, height))
+    return invoke<PhysicalSize>('plugin:window|outer_size', {
+      label: this.label
+    }).then((s) => new PhysicalSize(s))
   }
 
   /**
@@ -1269,21 +1263,9 @@ class Window {
    * @returns A promise indicating the success or failure of the operation.
    */
   async setSize(size: LogicalSize | PhysicalSize): Promise<void> {
-    if (!size || (size.type !== 'Logical' && size.type !== 'Physical')) {
-      throw new Error(
-        'the `size` argument must be either a LogicalSize or a PhysicalSize instance'
-      )
-    }
-
-    const value = {} as Record<string, unknown>
-    value[`${size.type}`] = {
-      width: size.width,
-      height: size.height
-    }
-
     return invoke('plugin:window|set_size', {
       label: this.label,
-      value
+      value: size.toIpc()
     })
   }
 
@@ -1301,24 +1283,9 @@ class Window {
   async setMinSize(
     size: LogicalSize | PhysicalSize | null | undefined
   ): Promise<void> {
-    if (size && size.type !== 'Logical' && size.type !== 'Physical') {
-      throw new Error(
-        'the `size` argument must be either a LogicalSize or a PhysicalSize instance'
-      )
-    }
-
-    let value = null as Record<string, unknown> | null
-    if (size) {
-      value = {}
-      value[`${size.type}`] = {
-        width: size.width,
-        height: size.height
-      }
-    }
-
     return invoke('plugin:window|set_min_size', {
       label: this.label,
-      value
+      value: size?.toIpc()
     })
   }
 
@@ -1336,24 +1303,9 @@ class Window {
   async setMaxSize(
     size: LogicalSize | PhysicalSize | null | undefined
   ): Promise<void> {
-    if (size && size.type !== 'Logical' && size.type !== 'Physical') {
-      throw new Error(
-        'the `size` argument must be either a LogicalSize or a PhysicalSize instance'
-      )
-    }
-
-    let value = null as Record<string, unknown> | null
-    if (size) {
-      value = {}
-      value[`${size.type}`] = {
-        width: size.width,
-        height: size.height
-      }
-    }
-
     return invoke('plugin:window|set_max_size', {
       label: this.label,
-      value
+      value: size?.toIpc()
     })
   }
 
@@ -1400,24 +1352,9 @@ class Window {
   async setPosition(
     position: LogicalPosition | PhysicalPosition
   ): Promise<void> {
-    if (
-      !position ||
-      (position.type !== 'Logical' && position.type !== 'Physical')
-    ) {
-      throw new Error(
-        'the `position` argument must be either a LogicalPosition or a PhysicalPosition instance'
-      )
-    }
-
-    const value = {} as Record<string, unknown>
-    value[`${position.type}`] = {
-      x: position.x,
-      y: position.y
-    }
-
     return invoke('plugin:window|set_position', {
       label: this.label,
-      value
+      value: position.toIpc()
     })
   }
 
@@ -1586,24 +1523,9 @@ class Window {
   async setCursorPosition(
     position: LogicalPosition | PhysicalPosition
   ): Promise<void> {
-    if (
-      !position ||
-      (position.type !== 'Logical' && position.type !== 'Physical')
-    ) {
-      throw new Error(
-        'the `position` argument must be either a LogicalPosition or a PhysicalPosition instance'
-      )
-    }
-
-    const value = {} as Record<string, unknown>
-    value[`${position.type}`] = {
-      x: position.x,
-      y: position.y
-    }
-
     return invoke('plugin:window|set_cursor_position', {
       label: this.label,
-      value
+      value: position.toIpc()
     })
   }
 
@@ -1751,7 +1673,7 @@ class Window {
    */
   async onResized(handler: EventCallback<PhysicalSize>): Promise<UnlistenFn> {
     return this.listen<PhysicalSize>(TauriEvent.WINDOW_RESIZED, (e) => {
-      e.payload = mapPhysicalSize(e.payload)
+      e.payload = new PhysicalSize(e.payload)
       handler(e)
     })
   }
@@ -1775,7 +1697,7 @@ class Window {
    */
   async onMoved(handler: EventCallback<PhysicalPosition>): Promise<UnlistenFn> {
     return this.listen<PhysicalPosition>(TauriEvent.WINDOW_MOVED, (e) => {
-      e.payload = mapPhysicalPosition(e.payload)
+      e.payload = new PhysicalPosition(e.payload)
       handler(e)
     })
   }
@@ -1853,7 +1775,7 @@ class Window {
           payload: {
             type: 'enter',
             paths: event.payload.paths,
-            position: mapPhysicalPosition(event.payload.position)
+            position: new PhysicalPosition(event.payload.position)
           }
         })
       }
@@ -1866,7 +1788,7 @@ class Window {
           ...event,
           payload: {
             type: 'over',
-            position: mapPhysicalPosition(event.payload.position)
+            position: new PhysicalPosition(event.payload.position)
           }
         })
       }
@@ -1880,7 +1802,7 @@ class Window {
           payload: {
             type: 'drop',
             paths: event.payload.paths,
-            position: mapPhysicalPosition(event.payload.position)
+            position: new PhysicalPosition(event.payload.position)
           }
         })
       }
@@ -2299,19 +2221,11 @@ function mapMonitor(m: Monitor | null): Monitor | null {
     : {
         name: m.name,
         scaleFactor: m.scaleFactor,
-        position: mapPhysicalPosition(m.position),
-        size: mapPhysicalSize(m.size)
+        position: new PhysicalPosition(m.position),
+        size: new PhysicalSize(m.size)
       }
 }
 
-function mapPhysicalPosition(m: PhysicalPosition): PhysicalPosition {
-  return new PhysicalPosition(m.x, m.y)
-}
-
-function mapPhysicalSize(m: PhysicalSize): PhysicalSize {
-  return new PhysicalSize(m.width, m.height)
-}
-
 /**
  * Returns the monitor on which the window currently resides.
  * Returns `null` if current monitor can't be detected.
@@ -2391,7 +2305,7 @@ async function availableMonitors(): Promise<Monitor[]> {
  */
 async function cursorPosition(): Promise<PhysicalPosition> {
   return invoke<PhysicalPosition>('plugin:window|cursor_position').then(
-    mapPhysicalPosition
+    (v) => new PhysicalPosition(v)
   )
 }
 

Деякі файли не було показано, через те що забагато файлів було змінено