// VNode - Cross-platform virtual DOM node
// Windjammer wrapper for Rust VNode FFI
//
// This module provides a type-safe way for Windjammer components to construct
// VNodes that can be rendered to:
// - HTML (for web)
// - egui (for desktop)
//
// Usage:
// use super::vnode::VNode
//
// fn render(&self) -> VNode {
// VNode::div()
// .add_class("container")
// .add_style("padding: 16px")
// .child(VNode::text("Hello, World!".to_string()))
// }
// Import the Rust FFI functions
use crate::vnode_ffi
/// VNode handle - wraps the Rust VNode registry handle
/// This is an opaque wrapper that tracks the VNode in the Rust registry
@auto
pub struct VNode {
handle: u64,
}
impl VNode {
// ========================================================================
// Element constructors
// ========================================================================
/// Create a new div element
pub fn div() -> VNode {
VNode { handle: vnode_ffi::vnode_element("div") }
}
/// Create a new span element
pub fn span() -> VNode {
VNode { handle: vnode_ffi::vnode_element("span") }
}
/// Create a new button element
pub fn button() -> VNode {
VNode { handle: vnode_ffi::vnode_element("button") }
}
/// Create a new input element
pub fn input() -> VNode {
VNode { handle: vnode_ffi::vnode_element("input") }
}
/// Create a new text node
pub fn text(content: string) -> VNode {
VNode { handle: vnode_ffi::vnode_text(content.as_str()) }
}
/// Create any HTML element by tag name
pub fn element(tag: string) -> VNode {
VNode { handle: vnode_ffi::vnode_element(tag.as_str()) }
}
// ========================================================================
// Builder methods (fluent API)
// Use add_* methods which take owned String for flexibility
// ========================================================================
/// Add a CSS class (takes owned String)
pub fn add_class(self, class: string) -> VNode {
vnode_ffi::vnode_class(self.handle, class.as_str())
self
}
/// Add inline style (takes owned String)
pub fn add_style(self, style: string) -> VNode {
vnode_ffi::vnode_style(self.handle, style.as_str())
self
}
/// Add an attribute (takes owned Strings)
pub fn add_attr(self, name: string, value: string) -> VNode {
vnode_ffi::vnode_attr(self.handle, name.as_str(), value.as_str())
self
}
/// Add a child VNode
pub fn child(self, child: VNode) -> VNode {
vnode_ffi::vnode_child(self.handle, child.handle)
self
}
/// Add text content (takes owned String)
pub fn add_text(self, text: string) -> VNode {
let text_node = VNode::text(text)
vnode_ffi::vnode_child(self.handle, text_node.handle)
self
}
// ========================================================================
// Common attribute shortcuts
// ========================================================================
/// Set id attribute
pub fn set_id(self, id: string) -> VNode {
vnode_ffi::vnode_attr(self.handle, "id", id.as_str())
self
}
/// Set placeholder (for inputs)
pub fn set_placeholder(self, text: string) -> VNode {
vnode_ffi::vnode_attr(self.handle, "placeholder", text.as_str())
self
}
/// Set type attribute (for inputs/buttons)
pub fn set_type(self, t: string) -> VNode {
vnode_ffi::vnode_attr(self.handle, "type", t.as_str())
self
}
/// Set value attribute
pub fn set_value(self, v: string) -> VNode {
vnode_ffi::vnode_attr(self.handle, "value", v.as_str())
self
}
/// Set disabled attribute
pub fn set_disabled(self, d: bool) -> VNode {
if d {
vnode_ffi::vnode_attr(self.handle, "disabled", "true")
}
self
}
// ========================================================================
// Access to raw handle (for advanced usage)
// ========================================================================
/// Get the raw handle (for interop with Rust code)
pub fn raw_handle(&self) -> u64 {
self.handle
}
}
// ============================================================================
// Convenience functions for common UI patterns
// ============================================================================
/// Create a container with padding
pub fn container() -> VNode {
VNode::div()
.add_class("wj-container".to_string())
.add_style("padding: 16px".to_string())
}
/// Create a flex row
pub fn row() -> VNode {
VNode::div().add_style("display: flex; flex-direction: row; gap: 8px".to_string())
}
/// Create a flex column
pub fn column() -> VNode {
VNode::div().add_style("display: flex; flex-direction: column; gap: 8px".to_string())
}
/// Create a spacer element
pub fn spacer() -> VNode {
VNode::div().add_style("flex: 1".to_string())
}
/// Create a horizontal divider
pub fn divider() -> VNode {
VNode::element("hr".to_string())
.add_style("border: 0; border-top: 1px solid #333; margin: 8px 0".to_string())
}