on master help sign in
Remove @stack

It promised layered children but only set position: relative. Overlays are @in-front and @behind; position relative covers the rest.

commita97bc5822bc82212f76fbf7b4f27a06d0c70322f authoriko <mail@iko.soy> dateSat 26 Sep 2026, 03:38 (2 weeks ago) parenta276f8d
6 files changed+3−24
DESIGN.md−1 crates/htmlang-core/src/ast.rs−1 src/bin/htmlang_lsp/docs.rs−1 tests/snapshots.rs−18 tests/snapshots/new_elements_4.hl+2−2 tests/snapshots/new_elements_4.html+1−1
DESIGN.md−1
@@ -98,7 +98,6 @@ name. Every container lays its children out in a column, except `@row`.
9898| `@row` | div, flex row | Horizontal layout |
9999| `@el` | div, flex column | The container: children laid out top to bottom |
100100| `@grid` | div, grid | Grid container (use `grid-cols`) |
101−| `@stack` | div, position relative | Children layered on top of each other |
102101| `@in-front` / `@behind` | div, absolute | Overlay layers filling the parent (see below) |
103102| `@text` | span | Styled inline text |
104103| `@paragraph` | p | Flowing text with inline elements |
crates/htmlang-core/src/ast.rs−1
@@ -248,7 +248,6 @@ pub static TAGS: &[TagSpec] = &[
248248 TagSpec { name: "audio", html: "audio", arg: TagArg::Attr("src"), ..TagSpec::DEFAULT },
249249 TagSpec { name: "iframe", html: "iframe", arg: TagArg::Attr("src"), container: true, ..TagSpec::DEFAULT },
250250 TagSpec { name: "grid", html: "div", css: "display:grid;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
251− TagSpec { name: "stack", html: "div", css: "position:relative;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
252251 TagSpec { name: "in-front", html: "div", css: "display:flex;flex-direction:column;position:absolute;inset:0;", container: true, ..TagSpec::DEFAULT },
253252 TagSpec { name: "behind", html: "div", css: "display:flex;flex-direction:column;position:absolute;inset:0;z-index:-1;", container: true, ..TagSpec::DEFAULT },
254253];
src/bin/htmlang_lsp/docs.rs−1
@@ -60,7 +60,6 @@ pub(crate) const ELEMENTS: &[Doc] = &[
6060 "@slot header",
6161 ),
6262 doc("grid", "Grid container (`display: grid`).", "@grid [grid-cols 3, spacing 20]"),
63− doc("stack", "Children layered on top of each other (`position: relative`).", "@stack"),
6463 doc(
6564 "in-front",
6665 "Overlay layer filling the parent, painted on top of its content.",
tests/snapshots.rs−18
@@ -2455,16 +2455,6 @@ fn element_grid() {
24552455
24562456// --- Stack element ---
24572457
2458−#[test]
2459−fn element_stack() {
2460− let output = compile("@page T\n@stack [width 200, height 200]\n @el\n @text Layer");
2461− assert!(
2462− output.contains("position:relative"),
2463− "stack should have position:relative: {}",
2464− output
2465− );
2466−}
2467−
24682458// --- @in-front / @behind overlay layers ---
24692459
24702460#[test]
@@ -2773,14 +2763,6 @@ fn no_warning_new_elements() {
27732763 "grid should parse, got: {:?}",
27742764 diags
27752765 );
2776− let diags = parse_diagnostics("@stack\n @text A");
2777− assert!(
2778− !diags
2779− .iter()
2780− .any(|d| d.severity == htmlang::parser::Severity::Error),
2781− "stack should parse, got: {:?}",
2782− diags
2783− );
27842766 let diags = parse_diagnostics("@row\n @spacer");
27852767 assert!(
27862768 !diags
tests/snapshots/new_elements_4.hl+2−2
@@ -9,8 +9,8 @@
99 @el [background #d0d0d0, padding 16]
1010 @text Third
1111
12−-- Stack element (position: relative container)
13−@stack [width 200, height 200]
12+-- Overlays with absolute positioning
13+@el [position relative, width 200, height 200]
1414 @el [position absolute, inset 0, background #3b82f6]
1515 @el [position absolute, bottom 10, right 10]
1616 @text [color white] Overlay
tests/snapshots/new_elements_4.html+1−1
@@ -1 +1 @@
1−<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>New Elements 4</title><style>@layer hl-reset,htmlang;@layer hl-reset{*,*::before,*::after{box-sizing:border-box}body{margin:0;font-family:system-ui,-apple-system,sans-serif}img{display:block}a{text-decoration:none;color:inherit}}@layer htmlang{.a{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;}.b{display:flex;flex-direction:column;background:#f0f0f0;padding:16px;}.c{display:flex;flex-direction:column;background:#e0e0e0;padding:16px;}.d{display:flex;flex-direction:column;background:#d0d0d0;padding:16px;}.e{position:relative;width:200px;height:200px;}.f{display:flex;flex-direction:column;position:absolute;inset:0;background:#3b82f6;}.g{display:flex;flex-direction:column;position:absolute;bottom:10px;right:10px;}.h{color:white;}.i{display:flex;flex-direction:row;height:100px;}.j{display:flex;flex-direction:column;flex:1;}.k{display:flex;flex-direction:row;gap:8px;}.l{display:inline-flex;align-items:center;padding:2px 8px;font-size:0.75rem;font-weight:600;justify-content:center;border-radius:9999px;line-height:1;background:#ef4444;color:white;}.m{display:inline-flex;align-items:center;padding:2px 8px;font-size:0.75rem;font-weight:600;justify-content:center;border-radius:9999px;line-height:1;background:#22c55e;color:white;}.n{display:inline-flex;align-items:center;padding:2px 8px;font-size:0.75rem;font-weight:600;justify-content:center;border-radius:9999px;line-height:1;background:#3b82f6;color:white;}.o{display:flex;flex-direction:row;gap:16px;}.p{position:relative;cursor:help;}.q{text-decoration:underline;}.r{font-weight:bold;}}</style></head><body><div class="a"><div class="b"><span>First</span></div><div class="c"><span>Second</span></div><div class="d"><span>Third</span></div></div><div class="e"><div class="f"></div><div class="g"><span class="h">Overlay</span></div></div><div class="i"><span>Left</span><div class="j"></div><span>Right</span></div><div class="k"><span class="l">3</span><span class="m">New</span><span class="n">Pro</span></div><div class="o"><span class="p" title="Hover me for info">Hover me for info<span class="q">Helpful text</span></span><span class="p" title="This is a tooltip message">This is a tooltip message<span class="r">Important</span></span></div></body></html>
1+<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>New Elements 4</title><style>@layer hl-reset,htmlang;@layer hl-reset{*,*::before,*::after{box-sizing:border-box}body{margin:0;font-family:system-ui,-apple-system,sans-serif}img{display:block}a{text-decoration:none;color:inherit}}@layer htmlang{.a{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;}.b{display:flex;flex-direction:column;background:#f0f0f0;padding:16px;}.c{display:flex;flex-direction:column;background:#e0e0e0;padding:16px;}.d{display:flex;flex-direction:column;background:#d0d0d0;padding:16px;}.e{display:flex;flex-direction:column;position:relative;width:200px;height:200px;}.f{display:flex;flex-direction:column;position:absolute;inset:0;background:#3b82f6;}.g{display:flex;flex-direction:column;position:absolute;bottom:10px;right:10px;}.h{color:white;}.i{display:flex;flex-direction:row;height:100px;}.j{display:flex;flex-direction:column;flex:1;}.k{display:flex;flex-direction:row;gap:8px;}.l{display:inline-flex;align-items:center;padding:2px 8px;font-size:0.75rem;font-weight:600;justify-content:center;border-radius:9999px;line-height:1;background:#ef4444;color:white;}.m{display:inline-flex;align-items:center;padding:2px 8px;font-size:0.75rem;font-weight:600;justify-content:center;border-radius:9999px;line-height:1;background:#22c55e;color:white;}.n{display:inline-flex;align-items:center;padding:2px 8px;font-size:0.75rem;font-weight:600;justify-content:center;border-radius:9999px;line-height:1;background:#3b82f6;color:white;}.o{display:flex;flex-direction:row;gap:16px;}.p{position:relative;cursor:help;}.q{text-decoration:underline;}.r{font-weight:bold;}}</style></head><body><div class="a"><div class="b"><span>First</span></div><div class="c"><span>Second</span></div><div class="d"><span>Third</span></div></div><div class="e"><div class="f"></div><div class="g"><span class="h">Overlay</span></div></div><div class="i"><span>Left</span><div class="j"></div><span>Right</span></div><div class="k"><span class="l">3</span><span class="m">New</span><span class="n">Pro</span></div><div class="o"><span class="p" title="Hover me for info">Hover me for info<span class="q">Helpful text</span></span><span class="p" title="This is a tooltip message">This is a tooltip message<span class="r">Important</span></span></div></body></html>