""" Typed dataclasses returned by the BrowserCLI Python API. Each object is bound to a BrowserCLI instance so you can call actions directly on it: tabs = b.tabs_list() tabs[0].close() tabs[0].move(forward=True) groups = b.group_list() groups[0].tabs() groups[0].add_tab("https://example.com") """ from __future__ import annotations from dataclasses import dataclass, field from typing import TYPE_CHECKING if TYPE_CHECKING: from browser_cli import BrowserCLI # ── Tab ─────────────────────────────────────────────────────────────────────── @dataclass class Tab: """A browser tab.""" id: int window_id: int active: bool title: str url: str group_id: int | None = None browser: str | None = None _browser: BrowserCLI | None = field(default=None, repr=False, compare=False, init=False) def _b(self) -> BrowserCLI: if self._browser is None: raise RuntimeError("Tab is not bound to a BrowserCLI instance") return self._browser def close(self) -> None: """Close this tab.""" self._b()._cmd("tabs.close", {"tabId": self.id}) def activate(self) -> None: """Switch browser focus to this tab.""" self._b()._cmd("tabs.active", {"tabId": self.id}) def reload(self) -> None: """Reload this tab.""" self._b()._cmd("navigate.reload", {"tabId": self.id}) def hard_reload(self) -> None: """Hard-reload this tab (bypass cache).""" self._b()._cmd("navigate.hard_reload", {"tabId": self.id}) def move( self, *, forward: bool = False, backward: bool = False, group_id: int | None = None, window_id: int | None = None, index: int | None = None, ) -> None: """Move this tab. Args: forward: Move one position to the right within the window. backward: Move one position to the left within the window. group_id: Move into the tab group with this ID. window_id: Move to the window with this ID. index: Absolute position index in the target window. """ self._b()._cmd("tabs.move", { "tabId": self.id, "forward": forward, "backward": backward, "groupId": group_id, "windowId": window_id, "index": index, }) def html(self) -> str: """Return the full HTML source of this tab.""" return self._b()._cmd("tabs.html", {"tabId": self.id}) def open(self, url: str, *, background: bool = False) -> None: """Navigate this tab to *url*.""" # Re-uses navigate.open which opens a new tab; for in-place navigation # we target by tabId via the focus then navigate approach. For now we # open a new tab in the same window as a convenience. self._b()._cmd("navigate.open", {"url": url, "background": background}) # ── Group ───────────────────────────────────────────────────────────────────── @dataclass class Group: """A browser tab group.""" id: int title: str color: str collapsed: bool tab_count: int browser: str | None = None _browser: BrowserCLI | None = field(default=None, repr=False, compare=False, init=False) def _b(self) -> BrowserCLI: if self._browser is None: raise RuntimeError("Group is not bound to a BrowserCLI instance") return self._browser def close(self) -> None: """Ungroup (and close) this tab group.""" self._b()._cmd("group.close", {"groupId": self.id}) def tabs(self) -> list[Tab]: """Return all tabs inside this group.""" return self._b().group_tabs(self.id) def move(self, *, forward: bool = False, backward: bool = False) -> None: """Move this group forward or backward among groups.""" self._b()._cmd("group.move", { "group": str(self.id), "forward": forward, "backward": backward, }) def add_tab(self, url: str | None = None) -> int | None: """Open a new tab inside this group. Returns the new tab ID.""" return self._b().group_add_tab(self.id, url)