victauri_core/snapshot.rs
1use serde::{Deserialize, Serialize};
2
3/// Current state of a Tauri window including geometry, visibility, and loaded URL.
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
5pub struct WindowState {
6 /// Tauri window label (e.g. "main", "notification").
7 pub label: String,
8 /// Window title bar text.
9 pub title: String,
10 /// URL currently loaded in the webview.
11 pub url: String,
12 /// Whether the window is visible on screen.
13 pub visible: bool,
14 /// Whether the window currently has input focus.
15 pub focused: bool,
16 /// Whether the window is maximized.
17 pub maximized: bool,
18 /// Whether the window is minimized.
19 pub minimized: bool,
20 /// Whether the window is in fullscreen mode.
21 pub fullscreen: bool,
22 /// Window position as (x, y) in screen coordinates.
23 pub position: (i32, i32),
24 /// Window dimensions as (width, height) in pixels.
25 pub size: (u32, u32),
26}
27
28/// A point-in-time snapshot of the DOM accessible tree from a specific webview.
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
30pub struct DomSnapshot {
31 /// Label of the webview this snapshot was taken from.
32 pub webview_label: String,
33 /// Top-level accessible elements in the DOM tree.
34 pub elements: Vec<DomElement>,
35 /// Maps ref IDs to CSS selectors for element lookup.
36 pub ref_map: std::collections::HashMap<String, String>,
37}
38
39/// A single element in the accessible DOM tree with semantic metadata and ref handle.
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
41pub struct DomElement {
42 /// Unique ref handle for this element (e.g. "e3"), used to target interactions.
43 pub ref_id: String,
44 /// HTML tag name (e.g. "div", "button").
45 pub tag: String,
46 /// ARIA role if present (e.g. "button", "navigation").
47 pub role: Option<String>,
48 /// Accessible name derived from aria-label, text content, or other heuristics.
49 pub name: Option<String>,
50 /// Visible text content of the element.
51 pub text: Option<String>,
52 /// Form input value, if applicable.
53 pub value: Option<String>,
54 /// Whether the element is interactive (not disabled).
55 pub enabled: bool,
56 /// Whether the element is visible in the viewport.
57 pub visible: bool,
58 /// Whether the element can receive keyboard focus.
59 pub focusable: bool,
60 /// Pixel-level bounding rectangle, if available.
61 pub bounds: Option<ElementBounds>,
62 /// Nested child elements forming the accessible subtree.
63 pub children: Vec<DomElement>,
64 /// Raw HTML attributes on the element.
65 pub attributes: std::collections::HashMap<String, String>,
66}
67
68/// Pixel-level bounding rectangle of a DOM element relative to the viewport.
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
70pub struct ElementBounds {
71 /// Left edge offset from viewport origin.
72 pub x: f64,
73 /// Top edge offset from viewport origin.
74 pub y: f64,
75 /// Element width in CSS pixels.
76 pub width: f64,
77 /// Element height in CSS pixels.
78 pub height: f64,
79}
80
81impl DomSnapshot {
82 /// Renders the snapshot as indented accessible text (roles, names, and ref handles).
83 pub fn to_accessible_text(&self, indent: usize) -> String {
84 let mut output = String::new();
85 for element in &self.elements {
86 Self::format_element(&mut output, element, indent);
87 }
88 output
89 }
90
91 fn format_element(output: &mut String, element: &DomElement, indent: usize) {
92 if !element.visible {
93 return;
94 }
95
96 let prefix = " ".repeat(indent);
97
98 let role_str = element.role.as_deref().unwrap_or(&element.tag);
99 let name_str = element
100 .name
101 .as_ref()
102 .map(|n| format!(" \"{}\"", n))
103 .unwrap_or_default();
104 let ref_str = if element.focusable || element.tag == "button" || element.tag == "input" {
105 format!(" [ref={}]", element.ref_id)
106 } else {
107 String::new()
108 };
109
110 let line = format!("{}- {}{}{}\n", prefix, role_str, name_str, ref_str);
111 output.push_str(&line);
112
113 for child in &element.children {
114 Self::format_element(output, child, indent + 1);
115 }
116 }
117}