package cc.unitmesh.xuiper.ast import cc.unitmesh.xuiper.action.BodyField import cc.unitmesh.xuiper.action.ContentType import cc.unitmesh.xuiper.action.HttpMethod import cc.unitmesh.xuiper.action.NanoAction /** * NanoDSL AST Node - Abstract Syntax Tree representation * * Represents all possible nodes in a NanoDSL component tree. * This sealed class hierarchy enables exhaustive pattern matching. */ sealed class NanoNode { /** * Component definition - the root of a NanoDSL component * Example: `component ProductCard(item: Product):` */ data class Component( val name: String, val params: List = emptyList(), val state: StateBlock? = null, val children: List = emptyList() ) : NanoNode() /** * Component parameter definition */ data class ComponentParam( val name: String, val type: String? = null ) /** * State block containing state variable definitions * Example: `state: count: int = 0` */ data class StateBlock( val variables: List = emptyList() ) /** * State variable definition */ data class StateVariable( val name: String, val type: String, val defaultValue: String? = null ) // ============ Layout Components ============ /** * Vertical stack layout * Example: `VStack(spacing="md"):` */ data class VStack( val spacing: String? = null, val align: String? = null, /** Flex factor when this node is a child of HStack/SplitView etc. */ val flex: Float? = null, val children: List = emptyList() ) : NanoNode() /** * Horizontal stack layout * Example: `HStack(align="center", justify="between"):` */ data class HStack( val spacing: String? = null, val align: String? = null, val justify: String? = null, /** When true, allow children to wrap to the next line on narrow widths. */ val wrap: Boolean? = null, /** Flex factor when this node is a child of another flex container. */ val flex: Float? = null, val children: List = emptyList() ) : NanoNode() // ============ Container Components ============ /** * Card container * Example: `Card: padding: "md"` */ data class Card( val padding: String? = null, val shadow: String? = null, /** Flex factor when this node is a child of HStack/SplitView etc. */ val flex: Float? = null, val children: List = emptyList() ) : NanoNode() // ============ Content Components ============ /** * Text display * Example: `Text("Hello", style="h2")` */ data class Text( val content: String, val style: String? = null, val binding: Binding? = null ) : NanoNode() /** * Image display * Example: `Image(src=item.image, aspect=16/9)` */ data class Image( val src: String, val aspect: String? = null, val radius: String? = null, val width: Int? = null ) : NanoNode() /** * Badge component * Example: `Badge("New", color="green")` */ data class Badge( val text: String, val color: String? = null ) : NanoNode() /** * Icon component * Example: `Icon("flight", size="md", color="blue")` */ data class Icon( val name: String, val size: String? = null, val color: String? = null ) : NanoNode() /** * Divider component */ object Divider : NanoNode() // ============ Input Components ============ /** * Button component * Example: `Button("Add to Cart", intent="primary"): on_click: ...` */ data class Button( val label: String, val intent: String? = null, val icon: String? = null, val disabledIf: String? = null, val onClick: NanoAction? = null ) : NanoNode() /** * Input field * Example: `Input(value := state.email, placeholder="Enter email")` */ data class Input( val value: Binding? = null, val placeholder: String? = null, val type: String? = null ) : NanoNode() /** * Checkbox component * Example: `Checkbox(checked := task.done, label="Accept terms")` */ data class Checkbox( val checked: Binding? = null, val label: String? = null, val onChange: NanoAction? = null ) : NanoNode() // ============ Control Flow ============ /** * Conditional rendering * Example: `if item.is_new: Badge("New")` */ data class Conditional( val condition: String, val thenBranch: List, val elseBranch: List? = null ) : NanoNode() /** * List iteration * Example: `for task in state.tasks: ...` */ data class ForLoop( val variable: String, val iterable: String, val body: List ) : NanoNode() // ============ HTTP Request Components ============ /** * Declarative HTTP request definition * * Example: * ```nanodsl * request login: * url: "/api/login" * method: "POST" * body: * email << state.email * password << state.password * headers: * Content-Type: "application/json" * on_success: * Navigate(to="/dashboard") * on_error: * ShowToast("Login failed") * ``` */ data class HttpRequest( /** Request name (used to invoke: request.login()) */ val name: String, /** Request URL */ val url: String, /** HTTP method */ val method: HttpMethod = HttpMethod.GET, /** Request body fields with bindings */ val body: List = emptyList(), /** Request headers */ val headers: Map = emptyMap(), /** Query parameters */ val params: Map = emptyMap(), /** Content type */ val contentType: ContentType = ContentType.JSON, /** Actions on loading start */ val onLoading: NanoAction? = null, /** Actions on success */ val onSuccess: NanoAction? = null, /** Actions on error */ val onError: NanoAction? = null, /** State path to bind loading status */ val loadingBinding: Binding? = null, /** State path to bind response data */ val responseBinding: Binding? = null, /** State path to bind error message */ val errorBinding: Binding? = null ) : NanoNode() /** * Request body field with optional binding */ data class RequestBodyField( /** Field name in the request body */ val name: String, /** Field value - either literal or state binding */ val value: BodyField ) // ============ Form Components ============ /** * Form container that groups inputs and provides submit handling * * Example: * ```nanodsl * Form(onSubmit=request.login): * Input(name="email", value := state.email) * Input(name="password", type="password", value := state.password) * Button("Submit", type="submit") * ``` */ data class Form( /** Request to invoke on submit */ val onSubmit: String? = null, /** Direct Fetch action on submit */ val onSubmitAction: NanoAction? = null, /** Flex factor when this node is a child of HStack/SplitView etc. */ val flex: Float? = null, /** Child components (inputs, buttons) */ val children: List = emptyList() ) : NanoNode() /** * Select/Dropdown component * Example: `Select(value := state.country, options=countries)` */ data class Select( /** Two-way binding to state */ val value: Binding? = null, /** Options list - can be literal or state binding */ val options: String? = null, /** Placeholder text */ val placeholder: String? = null ) : NanoNode() /** * TextArea component for multi-line input * Example: `TextArea(value := state.bio, rows=4)` */ data class TextArea( /** Two-way binding to state */ val value: Binding? = null, /** Number of rows */ val rows: Int? = null, /** Placeholder text */ val placeholder: String? = null ) : NanoNode() // ============ Tier 1: GenUI Foundation Components ============ /** * SplitView - Split layout (left/right panels) * Example: `SplitView(ratio=0.3): ...` */ data class SplitView( val ratio: Float? = null, /** Flex factor when this node is a child of HStack/SplitView etc. */ val flex: Float? = null, val children: List = emptyList() ) : NanoNode() /** * GenCanvas - Canvas/preview region driven by state * Example: `GenCanvas(bind=state.preview)` */ data class GenCanvas( val bind: Binding? = null, /** Flex factor when this node is a child of HStack/SplitView etc. */ val flex: Float? = null ) : NanoNode() // ============ Tier 2: Structured Input Components ============ /** * SmartTextField - Text input with validation * Example: `SmartTextField("Destination"): label: "Where to go?" bind: state.destination validation: r"^[a-zA-Z\s]+$"` */ data class SmartTextField( val name: String? = null, val label: String? = null, val bind: Binding? = null, val validation: String? = null, val placeholder: String? = null ) : NanoNode() /** * Slider - Range slider input * Example: `Slider("Budget"): label: "Max Budget ($)" bind: state.budget min: 500 max: 10000 step: 100` */ data class Slider( val name: String? = null, val label: String? = null, val bind: Binding? = null, val min: Float? = null, val max: Float? = null, val step: Float? = null, val onChange: NanoAction? = null ) : NanoNode() /** * DateRangePicker - Date range picker * Example: `DateRangePicker("Dates"): bind: state.dates` */ data class DateRangePicker( val name: String? = null, val bind: Binding? = null, val onChange: NanoAction? = null ) : NanoNode() // ============ Tier 3: Data Artifacts ============ /** * DataChart - Data visualization chart * Example: `DataChart("PriceHistory"): type: "line" data: state.flight_prices_history x_axis: "date" y_axis: "price"` */ data class DataChart( val name: String? = null, val type: String? = null, val data: String? = null, val xAxis: String? = null, val yAxis: String? = null, val color: String? = null ) : NanoNode() /** * DataTable - Interactive data table * Example: `DataTable("Flights"): columns: ["Airline", "Time", "Price"] data: state.available_flights` */ data class DataTable( val name: String? = null, val columns: String? = null, val data: String? = null, val onRowClick: NanoAction? = null ) : NanoNode() // ============ P0: Core Form Input Components ============ /** * DatePicker - Single date picker * Example: `DatePicker(bind := state.birthday, format="YYYY-MM-DD")` */ data class DatePicker( val value: Binding? = null, val format: String? = null, val minDate: String? = null, val maxDate: String? = null, val placeholder: String? = null, val onChange: NanoAction? = null ) : NanoNode() /** * Radio - Single radio button * Example: `Radio(bind := state.gender, option="male", label="Male")` */ data class Radio( val value: Binding? = null, val option: String? = null, val label: String? = null, val name: String? = null ) : NanoNode() /** * RadioGroup - Radio button group * Example: `RadioGroup(bind := state.payment, options=["card", "cash", "paypal"])` */ data class RadioGroup( val value: Binding? = null, val options: String? = null, val name: String? = null, val children: List = emptyList() ) : NanoNode() /** * Switch - Toggle switch * Example: `Switch(checked := state.enabled, label="Enable notifications")` */ data class Switch( val checked: Binding? = null, val label: String? = null, val size: String? = null, val onChange: NanoAction? = null ) : NanoNode() /** * NumberInput - Number input with increment/decrement * Example: `NumberInput(bind := state.quantity, min=0, max=100, step=1)` */ data class NumberInput( val value: Binding? = null, val min: Float? = null, val max: Float? = null, val step: Float? = null, val precision: Int? = null, val placeholder: String? = null, val onChange: NanoAction? = null ) : NanoNode() // ============ P0: Feedback Components ============ /** * Modal - Modal dialog * Example: `Modal(open := state.showModal, title="Confirm"): ...` */ data class Modal( val open: Binding? = null, val title: String? = null, val size: String? = null, val closable: Boolean? = null, val onClose: NanoAction? = null, val children: List = emptyList() ) : NanoNode() /** * Alert - Alert notification * Example: `Alert(type="warning", message="Please check your input")` */ data class Alert( val type: String? = null, val message: String? = null, val closable: Boolean? = null, val icon: String? = null, val onClose: NanoAction? = null, val children: List = emptyList() ) : NanoNode() /** * Progress - Progress bar * Example: `Progress(value=state.progress, max=100)` * * Note: value and max can be either literal numbers or state binding expressions * like "state.budget.spent" or "100" */ data class Progress( val value: String? = null, val max: String? = null, val showText: Boolean? = null, val status: String? = null ) : NanoNode() /** * Spinner - Loading spinner * Example: `Spinner(size="md", text="Loading...")` */ data class Spinner( val size: String? = null, val color: String? = null, val text: String? = null ) : NanoNode() }