Skip to content

Commit 3ba59a9

Browse files
committed
feat: implement positioned component
1 parent 4704851 commit 3ba59a9

4 files changed

Lines changed: 37 additions & 19 deletions

File tree

.claude/skills/rustmotion/SKILL.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,22 @@ Animated number counter. See Rule 4: must be standalone.
685685

686686
Style: `font-size` (48.0), `color` (#FFFFFF), `font-family` (Inter), `font-weight`, `text-align`, `letter-spacing`, `text-shadow`, `stroke`
687687

688-
### 10. `card` / `flex`
688+
### 10. `positioned`
689+
690+
Container that places children at fixed absolute coordinates (like Flutter's `Stack`/`Positioned`). Each child uses `position: {x, y}` relative to the container's top-left.
691+
692+
```json
693+
{
694+
"type": "positioned",
695+
"position": { "x": 100, "y": 200 },
696+
"children": [
697+
{ "type": "shape", "shape": "rect", "position": { "x": 0, "y": 0 }, "size": { "width": 400, "height": 300 }, "style": { "fill": "#1E293B", "border-radius": 16 } },
698+
{ "type": "icon", "icon": "lucide:phone-off", "position": { "x": 170, "y": 120 }, "style": { "size": 64, "color": "#FFFFFF" } }
699+
]
700+
}
701+
```
702+
703+
### 11. `card` / `flex`
689704

690705
Visual container with CSS-like flex & grid layout. `flex` is an alias for `card`. See Rule 8.
691706

src/components/mod.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub mod image;
1010
pub mod progress;
1111
pub mod qrcode;
1212
pub mod shape;
13-
pub mod stack;
13+
pub mod positioned;
1414
pub mod svg;
1515
pub mod text;
1616
pub mod video;
@@ -30,7 +30,7 @@ pub use grid::Grid;
3030
pub use icon::Icon;
3131
pub use image::Image;
3232
pub use shape::Shape;
33-
pub use stack::Stack;
33+
pub use positioned::Positioned;
3434
pub use svg::Svg;
3535
pub use text::Text;
3636
pub use video::Video;
@@ -107,7 +107,7 @@ pub enum Component {
107107
Caption(Caption),
108108
Codeblock(Codeblock),
109109
// Container components
110-
Stack(Stack),
110+
Positioned(Positioned),
111111
Flex(Flex),
112112
Grid(Grid),
113113
/// Backward-compatible card container (supports both flex and grid display modes).
@@ -130,7 +130,7 @@ impl Component {
130130
Component::Counter(c) => c,
131131
Component::Caption(c) => c,
132132
Component::Codeblock(c) => c,
133-
Component::Stack(c) => c,
133+
Component::Positioned(c) => c,
134134
Component::Flex(c) => c,
135135
Component::Grid(c) => c,
136136
Component::Card(c) => c,
@@ -153,7 +153,7 @@ impl Component {
153153
Component::Flex(c) => Some(c),
154154
Component::Grid(c) => Some(c),
155155
Component::Card(c) => Some(c),
156-
Component::Stack(_) => None,
156+
Component::Positioned(_) => None,
157157
}
158158
}
159159

@@ -172,7 +172,7 @@ impl Component {
172172
Component::Flex(c) => Some(c),
173173
Component::Grid(c) => Some(c),
174174
Component::Card(c) => Some(c),
175-
Component::Caption(_) | Component::Stack(_) => None,
175+
Component::Caption(_) | Component::Positioned(_) => None,
176176
}
177177
}
178178

@@ -189,7 +189,7 @@ impl Component {
189189
Component::Counter(c) => c,
190190
Component::Caption(c) => c,
191191
Component::Codeblock(c) => c,
192-
Component::Stack(c) => c,
192+
Component::Positioned(c) => c,
193193
Component::Flex(c) => c,
194194
Component::Grid(c) => c,
195195
Component::Card(c) => c,
@@ -200,7 +200,7 @@ impl Component {
200200
#[allow(dead_code)]
201201
pub fn as_container(&self) -> Option<&dyn Container> {
202202
match self {
203-
Component::Stack(c) => Some(c),
203+
Component::Positioned(c) => Some(c),
204204
Component::Flex(c) => Some(c),
205205
Component::Grid(c) => Some(c),
206206
Component::Card(c) => Some(c),
@@ -211,7 +211,7 @@ impl Component {
211211
/// Returns a mutable reference to this component's children, if it has any.
212212
pub fn children_mut(&mut self) -> Option<&mut Vec<ChildComponent>> {
213213
match self {
214-
Component::Stack(c) => Some(&mut c.children),
214+
Component::Positioned(c) => Some(&mut c.children),
215215
Component::Flex(c) => Some(&mut c.children),
216216
Component::Grid(c) => Some(&mut c.children),
217217
Component::Card(c) => Some(&mut c.children),
Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,31 @@ use crate::traits::{Container, RenderContext, Widget};
99

1010
use super::ChildComponent;
1111

12-
/// Stack container — children are positioned absolutely (like CSS `position: absolute`).
13-
/// Replaces the old `Group` layer.
12+
/// Positioned container — children are placed at fixed absolute coordinates.
13+
/// Like Flutter's Stack/Positioned: each child uses its `position: {x, y}` field.
1414
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
15-
pub struct Stack {
15+
pub struct Positioned {
1616
#[serde(default)]
1717
pub children: Vec<ChildComponent>,
1818
#[serde(default)]
1919
pub style: LayerStyle,
2020
}
2121

22-
crate::impl_traits!(Stack {
22+
crate::impl_traits!(Positioned {
2323
Styled => style,
2424
});
2525

26-
impl Container for Stack {
26+
impl Container for Positioned {
2727
fn children(&self) -> &[ChildComponent] {
2828
&self.children
2929
}
3030
}
3131

32-
impl Widget for Stack {
32+
impl Widget for Positioned {
33+
fn layout(&self, constraints: &Constraints) -> LayoutNode {
34+
crate::layout::stack::layout_stack(self, constraints)
35+
}
36+
3337
fn render(&self, canvas: &Canvas, layout: &LayoutNode, ctx: &RenderContext, _props: &crate::engine::animator::AnimatedProperties) -> Result<()> {
3438
crate::engine::render_v2::render_children(canvas, &self.children, layout, ctx)?;
3539
Ok(())

src/layout/stack.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#![allow(dead_code)]
21
use crate::components::ChildComponent;
32
use crate::traits::{Container, Styled};
43

@@ -74,7 +73,7 @@ fn measure_child(child: &ChildComponent, constraints: &Constraints) -> (f32, f32
7473
mod tests {
7574
use super::*;
7675
use crate::components::shape::Shape;
77-
use crate::components::stack::Stack;
76+
use crate::components::positioned::Positioned;
7877
use crate::components::{ChildComponent, Component, PositionMode};
7978
use crate::schema::{LayerStyle, ShapeType, Size};
8079

@@ -96,7 +95,7 @@ mod tests {
9695

9796
#[test]
9897
fn test_stack_2_children() {
99-
let stack = Stack {
98+
let stack = Positioned {
10099
children: vec![
101100
shape_child_at(100.0, 100.0, 0.0, 0.0),
102101
shape_child_at(50.0, 50.0, 200.0, 150.0),

0 commit comments

Comments
 (0)