zenith_core/ast/node/container.rs
1//! Container node structs that own child `Node`s: frame, group, and the table
2//! family (table + column/row/cell).
3
4use std::collections::BTreeMap;
5
6use crate::ast::Span;
7use crate::ast::value::{Dimension, PropertyValue};
8
9use super::common::{Node, UnknownProperty};
10
11/// A `frame` node — a container that CLIPS its children to its rectangular
12/// bounds and renders them in source order (first child = bottom of z-order).
13///
14/// Unlike `group`, a frame has **required** geometry (x, y, w, h): these four
15/// dimensions define the clip rectangle. Children are rendered at their
16/// **absolute** page coordinates — frame does NOT translate children (dx/dy
17/// are unchanged). The frame only clips; it has no fill of its own in v0.
18///
19/// Opacity cascades (multiplies) into all descendant node alphas, exactly as
20/// in `GroupNode`.
21#[derive(Debug, Clone, PartialEq)]
22pub struct FrameNode {
23 pub id: String,
24 pub name: Option<String>,
25 pub role: Option<String>,
26 /// Required: clip-rectangle left edge in page coordinates.
27 pub x: Option<PropertyValue>,
28 /// Required: clip-rectangle top edge in page coordinates.
29 pub y: Option<PropertyValue>,
30 /// Required: clip-rectangle width.
31 pub w: Option<PropertyValue>,
32 /// Required: clip-rectangle height.
33 pub h: Option<PropertyValue>,
34 /// Layout algorithm hint ("absolute"/"flow"/"grid"). `"flow"` activates a
35 /// vertical-stack flow layout (uniform `padding` inset + `gap` between
36 /// children, resolved from the frame's style); `"grid"` tiles children
37 /// row-major into a `columns × rows` grid inside the padded content box with
38 /// uniform `gap` gutters; any other value (including `None` and `"absolute"`)
39 /// keeps the clip-only absolute-positioning model.
40 pub layout: Option<String>,
41 /// Grid column count for `layout="grid"` (ignored otherwise). When the frame
42 /// uses grid layout, children tile row-major into `columns` columns; absent →
43 /// treated as 1 column. KDL: `columns=2`.
44 pub columns: Option<u32>,
45 /// Grid row count for `layout="grid"` (ignored otherwise). Absent → derived as
46 /// `ceil(child_count / columns)` so the grid grows to fit its children. KDL:
47 /// `rows=3`.
48 pub rows: Option<u32>,
49 /// Opacity that cascades (multiplies) into all descendant node alphas.
50 pub opacity: Option<f64>,
51 /// When `Some(false)` the entire subtree (including the clip) is excluded
52 /// from the render.
53 pub visible: Option<bool>,
54 pub locked: Option<bool>,
55 /// Rotation in degrees, applied at render about the node's center (the
56 /// subtree rotates with it; see the compile-site notes for clip limitations).
57 pub rotate: Option<Dimension>,
58 /// Compositing blend mode: `"normal"` (default) or one of the 11 separable
59 /// blends. `None`/`"normal"` render source-over (byte-identical).
60 pub blend_mode: Option<String>,
61 /// Drop shadow / outer glow, as a `(token)` ref to a `shadow` token.
62 pub shadow: Option<PropertyValue>,
63 /// Color/image filter stack, as a `(token)` ref to a `filter` token.
64 pub filter: Option<PropertyValue>,
65 /// Soft reveal mask, as a `(token)` ref to a `mask` token.
66 pub mask: Option<PropertyValue>,
67 /// Gaussian blur radius applied to the node's own rendered ink (sigma in
68 /// the declared unit, resolved to pixels at compile time). `None` / 0 →
69 /// no blur (byte-identical to having no attribute).
70 pub blur: Option<Dimension>,
71 pub style: Option<String>,
72 /// Child nodes in source order.
73 pub children: Vec<Node>,
74 /// Page-relative placement anchor (one of the nine named positions, e.g.
75 /// `"bottom-right"`). When present and recognized, the compile step derives
76 /// the node's x and/or y from the page and node dimensions. An explicitly-
77 /// authored x or y always wins.
78 pub anchor: Option<String>,
79 /// Optional safe-zone reference for the anchor. See [`RectNode::anchor_zone`](super::RectNode::anchor_zone).
80 pub anchor_zone: Option<String>,
81 /// Optional sibling node id for sibling-relative anchor positioning.
82 /// See [`RectNode::anchor_sibling`](super::RectNode::anchor_sibling).
83 pub anchor_sibling: Option<String>,
84 /// Adjacent-placement edge relative to `anchor-sibling`: `above`/`below`/`before`/`after`.
85 /// See [`RectNode::anchor_edge`](super::RectNode::anchor_edge).
86 pub anchor_edge: Option<String>,
87 /// Gap (px) between this node and its `anchor-sibling` edge when `anchor-edge` is set.
88 /// See [`RectNode::anchor_gap`](super::RectNode::anchor_gap).
89 pub anchor_gap: Option<Dimension>,
90 /// Parent-relative anchor toggle. See [`RectNode::anchor_parent`](super::RectNode::anchor_parent).
91 pub anchor_parent: Option<bool>,
92 /// Source declaration span, when available.
93 pub source_span: Option<Span>,
94 /// Unknown properties preserved for forward-compat.
95 pub unknown_props: BTreeMap<String, UnknownProperty>,
96}
97
98/// A named text-safe rectangle declared on a [`GroupNode`] as a
99/// `protected-region` child.
100///
101/// Declared as `protected-region id="…" x=(px)N y=(px)N w=(px)N h=(px)N`
102/// (with an optional `label`). Non-rendering metadata: it is not emitted to
103/// the scene and carries no visual properties of its own. Consumers (e.g.
104/// external layout tools) may consult it to avoid placing text over UI chrome
105/// or other reserved areas.
106#[derive(Debug, Clone, PartialEq)]
107pub struct ProtectedRegion {
108 pub id: String,
109 pub x: Dimension,
110 pub y: Dimension,
111 pub w: Dimension,
112 pub h: Dimension,
113 pub label: Option<String>,
114 pub source_span: Option<Span>,
115}
116
117/// A `group` node — a container that holds child nodes and renders them in
118/// source order (first child = bottom of z-order).
119///
120/// Groups introduce recursive nesting: a group can contain any mix of leaf
121/// nodes and further groups. The group itself emits no scene command; it
122/// only propagates a render context (opacity cascade + translation offset)
123/// to its descendants.
124#[derive(Debug, Clone, PartialEq)]
125pub struct GroupNode {
126 pub id: String,
127 pub name: Option<String>,
128 pub role: Option<String>,
129 /// Advisory x-translation offset applied to the subtree (default 0).
130 pub x: Option<PropertyValue>,
131 /// Advisory y-translation offset applied to the subtree (default 0).
132 pub y: Option<PropertyValue>,
133 /// Advisory bounding width — NOT used to scale children.
134 pub w: Option<PropertyValue>,
135 /// Advisory bounding height — NOT used to scale children.
136 pub h: Option<PropertyValue>,
137 /// Opacity that cascades (multiplies) into all descendant node alphas.
138 pub opacity: Option<f64>,
139 /// When `Some(false)` the entire subtree is excluded from the render.
140 pub visible: Option<bool>,
141 pub locked: Option<bool>,
142 /// Rotation in degrees, applied at render about the node's center (the
143 /// subtree rotates with it; see the compile-site notes for clip limitations).
144 pub rotate: Option<Dimension>,
145 /// Compositing blend mode: `"normal"` (default) or one of the 11 separable
146 /// blends. `None`/`"normal"` render source-over (byte-identical).
147 pub blend_mode: Option<String>,
148 /// Drop shadow / outer glow, as a `(token)` ref to a `shadow` token.
149 pub shadow: Option<PropertyValue>,
150 /// Color/image filter stack, as a `(token)` ref to a `filter` token.
151 pub filter: Option<PropertyValue>,
152 /// Soft reveal mask, as a `(token)` ref to a `mask` token.
153 pub mask: Option<PropertyValue>,
154 /// Gaussian blur radius applied to the node's own rendered ink (sigma in
155 /// the declared unit, resolved to pixels at compile time). `None` / 0 →
156 /// no blur (byte-identical to having no attribute).
157 pub blur: Option<Dimension>,
158 pub style: Option<String>,
159 /// Advisory semantic layer role for external tooling (e.g. `"background"`,
160 /// `"overlay"`). Non-rendering; distinct from the structural `role` field.
161 /// Open-ended string; no value is invalid.
162 pub semantic_role: Option<String>,
163 /// Advisory visual prominence hint in the range `0.0..=1.0`. Non-rendering;
164 /// values outside this range produce a validation warning.
165 pub intensity: Option<f64>,
166 /// Advisory z-ordering hint for external tooling. Non-rendering; all integer
167 /// values are valid.
168 pub layer_priority: Option<i64>,
169 /// Child nodes in source order.
170 pub children: Vec<Node>,
171 /// Advisory text-safe rectangles declared as `protected-region` children.
172 /// Non-rendering metadata; defaults to empty (byte-identical output when absent).
173 pub protected_regions: Vec<ProtectedRegion>,
174 /// Ids of parameters that external tooling is permitted to tweak, declared
175 /// as `editable-param id="…"` children. Non-rendering metadata; defaults to
176 /// empty (byte-identical output when absent).
177 pub editable_param_ids: Vec<String>,
178 /// Page-relative placement anchor (one of the nine named positions, e.g.
179 /// `"bottom-right"`). When present and recognized, the compile step derives
180 /// the node's x and/or y from the page and node dimensions. An explicitly-
181 /// authored x or y always wins.
182 pub anchor: Option<String>,
183 /// Optional safe-zone reference for the anchor. See [`RectNode::anchor_zone`](super::RectNode::anchor_zone).
184 pub anchor_zone: Option<String>,
185 /// Optional sibling node id for sibling-relative anchor positioning.
186 /// See [`RectNode::anchor_sibling`](super::RectNode::anchor_sibling).
187 pub anchor_sibling: Option<String>,
188 /// Adjacent-placement edge relative to `anchor-sibling`: `above`/`below`/`before`/`after`.
189 /// See [`RectNode::anchor_edge`](super::RectNode::anchor_edge).
190 pub anchor_edge: Option<String>,
191 /// Gap (px) between this node and its `anchor-sibling` edge when `anchor-edge` is set.
192 /// See [`RectNode::anchor_gap`](super::RectNode::anchor_gap).
193 pub anchor_gap: Option<Dimension>,
194 /// Parent-relative anchor toggle. See [`RectNode::anchor_parent`](super::RectNode::anchor_parent).
195 pub anchor_parent: Option<bool>,
196 /// Source declaration span, when available.
197 pub source_span: Option<Span>,
198 /// Unknown properties preserved for forward-compat.
199 pub unknown_props: BTreeMap<String, UnknownProperty>,
200}
201
202/// A single column declaration in a [`TableNode`] (a `column` child).
203///
204/// `width` absent means an AUTO column: its width is content-based (the natural
205/// width its cells demand), scaled to fit the table's leftover width.
206#[derive(Debug, Clone, PartialEq)]
207pub struct TableColumn {
208 /// Explicit column width; `None` = auto (content-based width).
209 pub width: Option<Dimension>,
210 /// Source declaration span, when available.
211 pub source_span: Option<Span>,
212 /// Unknown properties preserved for forward-compat.
213 pub unknown_props: BTreeMap<String, UnknownProperty>,
214}
215
216/// A single cell in a [`TableRow`] (a `cell` child).
217///
218/// A cell holds ordinary child nodes (text/rect/image/…) — the same node model
219/// used by `frame`/`group` children — and may span multiple columns/rows via
220/// `colspan`/`rowspan` (HTML-table cell flow).
221#[derive(Debug, Clone, PartialEq)]
222pub struct TableCell {
223 /// Number of columns this cell spans (default 1).
224 pub colspan: u32,
225 /// Number of rows this cell spans (default 1).
226 pub rowspan: u32,
227 /// Cell content — ordinary nodes in source order.
228 pub children: Vec<Node>,
229 /// Per-cell background fill override (token-required color).
230 pub fill: Option<PropertyValue>,
231 /// Per-cell border color override (token-required color).
232 pub border: Option<PropertyValue>,
233 /// Per-cell border width override (token/dimension).
234 pub border_width: Option<PropertyValue>,
235 /// Per-cell horizontal alignment override (`start`/`center`/`end`).
236 pub h_align: Option<String>,
237 /// Per-cell vertical alignment override (`top`/`middle`/`bottom`).
238 pub v_align: Option<String>,
239 /// Source declaration span, when available.
240 pub source_span: Option<Span>,
241 /// Unknown properties preserved for forward-compat.
242 pub unknown_props: BTreeMap<String, UnknownProperty>,
243}
244
245/// A single row in a [`TableNode`] (a `row` child), holding cells left→right.
246#[derive(Debug, Clone, PartialEq)]
247pub struct TableRow {
248 /// Cells in source order (left→right).
249 pub cells: Vec<TableCell>,
250 /// Source declaration span, when available.
251 pub source_span: Option<Span>,
252 /// Unknown properties preserved for forward-compat.
253 pub unknown_props: BTreeMap<String, UnknownProperty>,
254}
255
256/// A `table` node — a grid container of `column`/`row`/`cell` children.
257///
258/// Renders tables with explicit, proportional, or content-based (auto) column
259/// widths; separate or collapsed borders; styled header rows; and multi-page
260/// flow when a table is taller than its page.
261#[derive(Debug, Clone, PartialEq)]
262pub struct TableNode {
263 pub id: String,
264 pub name: Option<String>,
265 pub role: Option<String>,
266 /// Required: table box left edge in page coordinates.
267 pub x: Option<PropertyValue>,
268 /// Required: table box top edge in page coordinates.
269 pub y: Option<PropertyValue>,
270 /// Required: table box width.
271 pub w: Option<PropertyValue>,
272 /// Required: table box height.
273 pub h: Option<PropertyValue>,
274 /// Column declarations, order = left→right.
275 pub columns: Vec<TableColumn>,
276 /// Row declarations, order = top→bottom.
277 pub rows: Vec<TableRow>,
278 /// First N rows are headers: styled via `header_fill`/`header_style` and
279 /// repeated atop each page slice in multi-page flow.
280 pub header_rows: Option<u32>,
281 /// Multi-page flow id. Tables sharing a `flows` id form ONE logical table:
282 /// the FIRST member (page-order, then source-order) is the SOURCE carrying
283 /// all rows + columns; continuation members declare the same id with empty
284 /// rows and receive the body-row slice that fits their box, with header rows
285 /// repeated. Mirrors the text-node `chain` field. `None` = standalone table.
286 pub flows: Option<String>,
287 /// Uniform gutter between cells in px (token or literal).
288 pub gap: Option<PropertyValue>,
289 /// Inset inside each cell in px (token or literal).
290 pub cell_padding: Option<PropertyValue>,
291 /// Border model: `"separate"` (default) or `"collapse"`; both are rendered.
292 pub border_collapse: Option<String>,
293 /// Default cell background (token-required color).
294 pub fill: Option<PropertyValue>,
295 /// Default cell border color (token-required color).
296 pub border: Option<PropertyValue>,
297 /// Default border width (token/dimension).
298 pub border_width: Option<PropertyValue>,
299 /// Header-row background override, applied to header cells (precedence:
300 /// cell.fill > header_fill > table.fill).
301 pub header_fill: Option<PropertyValue>,
302 /// Header text style ref, applied to header-row cell text.
303 pub header_style: Option<String>,
304 /// Default horizontal alignment (`start`(default)/`center`/`end`).
305 pub h_align: Option<String>,
306 /// Default vertical alignment (`top`(default)/`middle`/`bottom`).
307 pub v_align: Option<String>,
308 pub style: Option<String>,
309 pub opacity: Option<f64>,
310 pub visible: Option<bool>,
311 pub locked: Option<bool>,
312 /// Rotation — parsed and preserved but not yet applied at render for tables.
313 pub rotate: Option<Dimension>,
314 /// Page-relative placement anchor (one of the nine named positions, e.g.
315 /// `"bottom-right"`). When present and recognized, the compile step derives
316 /// the node's x and/or y from the page and node dimensions. An explicitly-
317 /// authored x or y always wins.
318 pub anchor: Option<String>,
319 /// Optional safe-zone reference for the anchor. See [`RectNode::anchor_zone`](super::RectNode::anchor_zone).
320 pub anchor_zone: Option<String>,
321 /// Optional sibling node id for sibling-relative anchor positioning.
322 /// See [`RectNode::anchor_sibling`](super::RectNode::anchor_sibling).
323 pub anchor_sibling: Option<String>,
324 /// Adjacent-placement edge relative to `anchor-sibling`: `above`/`below`/`before`/`after`.
325 /// See [`RectNode::anchor_edge`](super::RectNode::anchor_edge).
326 pub anchor_edge: Option<String>,
327 /// Gap (px) between this node and its `anchor-sibling` edge when `anchor-edge` is set.
328 /// See [`RectNode::anchor_gap`](super::RectNode::anchor_gap).
329 pub anchor_gap: Option<Dimension>,
330 /// Parent-relative anchor toggle. See [`RectNode::anchor_parent`](super::RectNode::anchor_parent).
331 pub anchor_parent: Option<bool>,
332 /// Source declaration span, when available.
333 pub source_span: Option<Span>,
334 /// Unknown properties preserved for forward-compat.
335 pub unknown_props: BTreeMap<String, UnknownProperty>,
336}