//! el-platform — Universal rendering backends for el-ui. //! //! The same component code produces native output for every target platform. //! No bridge. No virtual DOM. Direct platform calls. //! //! The target is chosen in `el.toml`: //! //! ```toml //! [platform] //! target = "web" # web | server | ios | android | macos | linux | windows //! ssr = true //! ``` //! //! All platforms implement the `PlatformBackend` trait. A future agent fills in //! the native API calls for iOS/Android/macOS/Linux/Windows — the architecture //! is correct and complete now. pub mod backends; pub mod config; pub mod node; pub use backends::{ android::AndroidBackend, ios::IosBackend, linux::LinuxBackend, macos::MacosBackend, server::ServerBackend, web::WebBackend, windows::WindowsBackend, }; pub use config::{PlatformConfig, PlatformTarget}; pub use node::{Attribute, EventHandler, PlatformNode, PlatformNodeKind}; use thiserror::Error; #[derive(Debug, Error)] pub enum PlatformError { #[error("render error: {0}")] Render(String), #[error("mount error: {0}")] Mount(String), #[error("unsupported operation on target {target}: {op}")] Unsupported { target: String, op: String }, #[error("event binding error: {0}")] EventBinding(String), } pub type PlatformResult = Result; /// The core trait every platform backend must implement. /// /// All rendering paths go through this interface. Component code is identical /// across targets — only the backend chosen by `el.toml` differs. pub trait PlatformBackend: Send + Sync { /// The platform name (e.g. "web", "server", "ios"). fn name(&self) -> &'static str; /// Create a new element node on this platform. fn create_element(&self, tag: &str) -> PlatformResult; /// Create a text node on this platform. fn create_text(&self, content: &str) -> PlatformResult; /// Set an attribute on a node. fn set_attribute(&self, node: &mut PlatformNode, name: &str, value: &str) -> PlatformResult<()>; /// Remove an attribute from a node. fn remove_attribute(&self, node: &mut PlatformNode, name: &str) -> PlatformResult<()>; /// Append a child node to a parent. fn append_child(&self, parent: &mut PlatformNode, child: PlatformNode) -> PlatformResult<()>; /// Remove a child node from a parent. fn remove_child(&self, parent: &mut PlatformNode, child_index: usize) -> PlatformResult<()>; /// Replace a child node at the given index. fn replace_child( &self, parent: &mut PlatformNode, index: usize, new_child: PlatformNode, ) -> PlatformResult<()>; /// Bind an event handler to a node. fn bind_event( &self, node: &mut PlatformNode, event: &str, handler: EventHandler, ) -> PlatformResult<()>; /// Render a node tree to its platform representation. /// For `server`, this returns an HTML string. /// For `web`, this patches the live DOM. /// For native targets, this calls the appropriate native APIs. fn render_to_string(&self, node: &PlatformNode) -> PlatformResult; /// Mount a node tree into the platform's root container. /// `container_id` is a platform-specific identifier (CSS selector for web, /// view controller ID for iOS, activity ID for Android, etc.). fn mount(&self, root: PlatformNode, container_id: &str) -> PlatformResult<()>; /// Patch an existing mounted tree with a new tree. /// The backend performs the minimal update needed. fn patch(&self, old: &PlatformNode, new: &PlatformNode) -> PlatformResult<()>; /// Whether this backend supports SSR (rendering to HTML string on the server). fn supports_ssr(&self) -> bool { false } } /// Select the backend for a given platform target. pub fn backend_for(target: &PlatformTarget) -> Box { match target { PlatformTarget::Web => Box::new(WebBackend::new()), PlatformTarget::Server => Box::new(ServerBackend::new()), PlatformTarget::Ios => Box::new(IosBackend::new()), PlatformTarget::Android => Box::new(AndroidBackend::new()), PlatformTarget::Macos => Box::new(MacosBackend::new()), PlatformTarget::Linux => Box::new(LinuxBackend::new()), PlatformTarget::Windows => Box::new(WindowsBackend::new()), } }