on master help sign in
HTML names for lists: @ul, @ol, @li
992bdcdiko
DESIGN.md+10−10
@@ -90,8 +90,8 @@ verbatim too (a `--` line in them is not a comment).
90
90
91## Elements
91## Elements
92
92
93−Layout elements set up flexbox; the rest map to the HTML element of the same
93+The layout and text elements come from elm-ui; every other element has its
94−name. Every container lays its children out in a column, except `@row`.
94+HTML name. Every container lays its children out in a column, except `@row`.
95
95
96| Element | Output | Purpose |
96| Element | Output | Purpose |
97|---|---|---|
97|---|---|---|
@@ -110,7 +110,7 @@ Semantic containers, all laid out as columns: `@nav`, `@header`, `@footer`,
110`@details` / `@summary`, `@dialog`, `@figure` / `@figcaption`, `@blockquote` /
110`@details` / `@summary`, `@dialog`, `@figure` / `@figcaption`, `@blockquote` /
111`@cite`, `@fieldset` / `@legend`, `@noscript`.
111`@cite`, `@fieldset` / `@legend`, `@noscript`.
112
112
113−Content: `@list` / `@item` (`@list [ordered]` for `<ol>`), `@dl` / `@dt` /
113+Content: `@ul` / `@ol` / `@li`, `@dl` / `@dt` /
114`@dd`, `@table` / `@thead` / `@tbody` / `@tr` / `@th` / `@td`, `@code`, `@pre`,
114`@dd`, `@table` / `@thead` / `@tbody` / `@tr` / `@th` / `@td`, `@code`, `@pre`,
115`@hr`, `@mark`, `@kbd`, `@abbr`, `@time`, `@progress`, `@meter`, `@output`,
115`@hr`, `@mark`, `@kbd`, `@abbr`, `@time`, `@progress`, `@meter`, `@output`,
116`@canvas`, `@iframe src`, `@video src`, `@audio src`, `@picture` / `@source`,
116`@canvas`, `@iframe src`, `@video src`, `@audio src`, `@picture` / `@source`,
@@ -120,9 +120,9 @@ Form controls: `@input`, `@button`, `@select` / `@option`, `@textarea`,
120`@label`, `@datalist`. `@form URL` sets the form's `action`.
120`@label`, `@datalist`. `@form URL` sets the form's `action`.
121
121
122```
122```
123−@list [ordered]
123+@ol
124− @item First
124+ @li First
125− @item Second
125+ @li Second
126@form [method=post] /subscribe
126@form [method=post] /subscribe
127 @label [for=email] Email
127 @label [for=email] Email
128 @input [type=email, name=email, id=email, required]
128 @input [type=email, name=email, id=email, required]
@@ -162,7 +162,7 @@ Use them like elements; your own `@let` with the same name takes precedence.
162| `@spacer` | Takes up the remaining space in a row or column |
162| `@spacer` | Takes up the remaining space in a row or column |
163| `@tooltip [tip TEXT]` | Text that shows `TEXT` when hovered |
163| `@tooltip [tip TEXT]` | Text that shows `TEXT` when hovered |
164| `@carousel` | Horizontally scrolling row that snaps to each child |
164| `@carousel` | Horizontally scrolling row that snaps to each child |
165−| `@breadcrumb` | Breadcrumb trail of `@item`s |
165+| `@breadcrumb` | Breadcrumb trail of `@li`s |
166| `$skeleton`, `$truncate`, `$no-scrollbar` | Attribute bundles: loading placeholder, one-line ellipsis, hidden scrollbars |
166| `$skeleton`, `$truncate`, `$no-scrollbar` | Attribute bundles: loading placeholder, one-line ellipsis, hidden scrollbars |
167
167
168```
168```
@@ -172,8 +172,8 @@ Use them like elements; your own `@let` with the same name takes precedence.
172 @spacer
172 @spacer
173 @tooltip [tip Opens in a new tab] Help
173 @tooltip [tip Opens in a new tab] Help
174@breadcrumb
174@breadcrumb
175− @item > @link / Home
175+ @li > @link / Home
176− @item Docs
176+ @li Docs
177@el [$skeleton, height 20, width fill]
177@el [$skeleton, height 20, width fill]
178```
178```
179
179
@@ -483,7 +483,7 @@ removed form with its replacement.
483| `@og KEY VALUE` | `@meta og:KEY VALUE` |
483| `@og KEY VALUE` | `@meta og:KEY VALUE` |
484| `@assert`, `@warn`, `@debug`, `@log` | Nothing (the lines are removed) |
484| `@assert`, `@warn`, `@debug`, `@log` | Nothing (the lines are removed) |
485| `@defer` | Its content, directly |
485| `@defer` | Its content, directly |
486−| `@col`, `@p`, `@img`, `@li`, `@btn`, `@ul`, `@divider`, `@opt` | `@el`, `@paragraph`, `@image`, `@item`, `@button`, `@list`, `@hr`, `@option` |
486+| `@col`, `@p`, `@img`, `@li`, `@btn`, `@ul`, `@divider`, `@opt` | `@el`, `@paragraph`, `@image`, `@li`, `@button`, `@ul`, `@hr`, `@option` |
487| `type email`, `id main` (HTML attributes written as styles) | `type=email`, `id=main` |
487| `type email`, `id main` (HTML attributes written as styles) | `type=email`, `id=main` |
488| `skeleton`, `no-scrollbar`, `gradient A B` | `$skeleton`, `$no-scrollbar`, `background linear-gradient(A, B)` |
488| `skeleton`, `no-scrollbar`, `gradient A B` | `$skeleton`, `$no-scrollbar`, `background linear-gradient(A, B)` |
489| `@tooltip TEXT` | `@tooltip [tip TEXT] TEXT` |
489| `@tooltip TEXT` | `@tooltip [tip TEXT] TEXT` |
crates/htmlang-core/src/ast.rs+5−4
@@ -146,7 +146,7 @@ impl ElementKind {
146pub enum TagArg {
146pub enum TagArg {
147 /// Leading text content (`@section Hello`).
147 /// Leading text content (`@section Hello`).
148 Child,
148 Child,
149− /// Printed as the element's text (`@item First`).
149+ /// Printed as the element's text (`@li First`).
150 Text,
150 Text,
151 /// Emitted as this HTML attribute (`@iframe URL` sets `src`).
151 /// Emitted as this HTML attribute (`@iframe URL` sets `src`).
152 Attr(&'static str),
152 Attr(&'static str),
@@ -204,8 +204,9 @@ pub static TAGS: &[TagSpec] = &[
204 TagSpec { name: "blockquote", html: "blockquote", css: "display:flex;flex-direction:column;margin:0;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
204 TagSpec { name: "blockquote", html: "blockquote", css: "display:flex;flex-direction:column;margin:0;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
205 TagSpec { name: "fieldset", html: "fieldset", css: "display:flex;flex-direction:column;border:1px solid currentColor;padding:8px;margin:0;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
205 TagSpec { name: "fieldset", html: "fieldset", css: "display:flex;flex-direction:column;border:1px solid currentColor;padding:8px;margin:0;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
206 TagSpec { name: "datalist", html: "datalist", wraps_text: true, container: true, ..TagSpec::DEFAULT },
206 TagSpec { name: "datalist", html: "datalist", wraps_text: true, container: true, ..TagSpec::DEFAULT },
207− TagSpec { name: "list", html: "ul", css: "margin:0;padding-left:0;list-style:none;", container: true, ..TagSpec::DEFAULT },
207+ TagSpec { name: "ul", html: "ul", css: "margin:0;padding-left:0;list-style:none;", container: true, ..TagSpec::DEFAULT },
208+ TagSpec { name: "ol", html: "ol", css: "margin:0;padding-left:0;list-style:none;", container: true, ..TagSpec::DEFAULT },
208− TagSpec { name: "item", html: "li", css: "display:flex;flex-direction:column;", arg: TagArg::Text, wraps_text: true, container: true, ..TagSpec::DEFAULT },
209+ TagSpec { name: "li", html: "li", css: "display:flex;flex-direction:column;", arg: TagArg::Text, wraps_text: true, container: true, ..TagSpec::DEFAULT },
209 TagSpec { name: "dl", html: "dl", css: "margin:0;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
210 TagSpec { name: "dl", html: "dl", css: "margin:0;", wraps_text: true, container: true, ..TagSpec::DEFAULT },
210 TagSpec { name: "dt", html: "dt", arg: TagArg::Text, container: true, ..TagSpec::DEFAULT },
211 TagSpec { name: "dt", html: "dt", arg: TagArg::Text, container: true, ..TagSpec::DEFAULT },
211 TagSpec { name: "dd", html: "dd", css: "margin:0;display:flex;flex-direction:column;", arg: TagArg::Text, wraps_text: true, container: true, ..TagSpec::DEFAULT },
212 TagSpec { name: "dd", html: "dd", css: "margin:0;display:flex;flex-direction:column;", arg: TagArg::Text, wraps_text: true, container: true, ..TagSpec::DEFAULT },
@@ -253,7 +254,7 @@ pub static TAGS: &[TagSpec] = &[
253];
254];
254
255
255/// Elements that print their argument as their text (`@text Hello`,
256/// Elements that print their argument as their text (`@text Hello`,
256−/// `@item First`).
257+/// `@li First`).
257pub fn renders_argument_as_text(kind: &ElementKind) -> bool {
258pub fn renders_argument_as_text(kind: &ElementKind) -> bool {
258 *kind == ElementKind::Text || kind.spec().is_some_and(|spec| spec.arg == TagArg::Text)
259 *kind == ElementKind::Text || kind.spec().is_some_and(|spec| spec.arg == TagArg::Text)
259}
260}
crates/htmlang-core/src/codegen.rs−5
@@ -1148,11 +1148,6 @@ fn generate_element(
1148 ElementKind::Text => "span",
1148 ElementKind::Text => "span",
1149 ElementKind::Paragraph => "p",
1149 ElementKind::Paragraph => "p",
1150 ElementKind::Link => "a",
1150 ElementKind::Link => "a",
1151− ElementKind::Tag(spec)
1152− if spec.name == "list" && elem.attrs.iter().any(|a| a.key == "ordered") =>
1153− {
1154− "ol"
1155− }
1156 ElementKind::Tag(spec) => spec.html,
1151 ElementKind::Tag(spec) => spec.html,
1157 _ => "",
1152 _ => "",
1158 };
1153 };
crates/htmlang-core/src/parser.rs−16
@@ -1511,9 +1511,7 @@ const REMOVED_SYNTAX: &[(&str, &str)] = &[
1511 ("@col", "use `@el`"),
1511 ("@col", "use `@el`"),
1512 ("@p", "use `@paragraph`"),
1512 ("@p", "use `@paragraph`"),
1513 ("@img", "use `@image`"),
1513 ("@img", "use `@image`"),
1514− ("@li", "use `@item`"),
1515 ("@btn", "use `@button`"),
1514 ("@btn", "use `@button`"),
1516− ("@ul", "use `@list`"),
1517 ("@divider", "use `@hr`"),
1515 ("@divider", "use `@hr`"),
1518 ("@opt", "use `@option`"),
1516 ("@opt", "use `@option`"),
1519];
1517];
@@ -2818,20 +2816,6 @@ fn validate_tree(
2818 });
2816 });
2819 }
2817 }
2820
2818
2821− // 'ordered' only on @list
2822− if base == "ordered" && !elem.kind.is_tag("list") {
2823− diagnostics.push(Diagnostic {
2824− line: elem.line_num,
2825− column: None,
2826− message: format!(
2827− "'ordered' has no effect on {} (only works on @list)",
2828− element_kind_name(&elem.kind)
2829− ),
2830− severity: Severity::Warning,
2831− source_line: None,
2832− });
2833− }
2834−
2835 // Media-specific attributes only on @video/@audio
2819 // Media-specific attributes only on @video/@audio
2836 if matches!(
2820 if matches!(
2837 base,
2821 base,
crates/htmlang-core/src/std.hl+2−2
@@ -37,10 +37,10 @@
37 @row [overflow-x auto, scroll-snap-type x mandatory, scrollbar-width none, children:scroll-snap-align start, children:flex-shrink 0]
37 @row [overflow-x auto, scroll-snap-type x mandatory, scrollbar-width none, children:scroll-snap-align start, children:flex-shrink 0]
38 @children
38 @children
39
39
40−-- Breadcrumb trail: each crumb is an @item.
40+-- Breadcrumb trail: each crumb is an @li.
41@let breadcrumb
41@let breadcrumb
42 @nav [aria-label=breadcrumb]
42 @nav [aria-label=breadcrumb]
43− @list [ordered, display flex, flex-direction row, flex-wrap wrap, gap 8px]
43+ @ol [display flex, flex-direction row, flex-wrap wrap, gap 8px]
44 @children
44 @children
45
45
46-- Loading placeholder: [$skeleton]
46-- Loading placeholder: [$skeleton]
crates/htmlang-core/src/vocab.rs+1−1
@@ -11,7 +11,7 @@
11/// HTML attribute).
11/// HTML attribute).
12pub const HTMLANG_ATTRIBUTES: &[&str] = &[
12pub const HTMLANG_ATTRIBUTES: &[&str] = &[
13 "align-bottom", "align-left", "align-right", "align-top", "center-x", "center-y",
13 "align-bottom", "align-left", "align-right", "align-top", "center-x", "center-y",
14− "col-span", "grid-cols", "grid-rows", "inline", "ordered", "responsive", "row-span",
14+ "col-span", "grid-cols", "grid-rows", "inline", "responsive", "row-span",
15 "spacing", "wrap",
15 "spacing", "wrap",
16];
16];
17
17
editors/vscode/snippets/htmlang.json+3−3
@@ -226,9 +226,9 @@
226 "prefix": "@breadcrumb",
226 "prefix": "@breadcrumb",
227 "body": [
227 "body": [
228 "@breadcrumb",
228 "@breadcrumb",
229− " @item > @link ${1:/} ${2:Home}",
229+ " @li > @link ${1:/} ${2:Home}",
230− " @item > @link ${3:/docs} ${4:Docs}",
230+ " @li > @link ${3:/docs} ${4:Docs}",
231− " @item ${5:Current Page}",
231+ " @li ${5:Current Page}",
232 " $0"
232 " $0"
233 ],
233 ],
234 "description": "Breadcrumb navigation with links"
234 "description": "Breadcrumb navigation with links"
examples/demo.hl+8−8
@@ -244,15 +244,15 @@
244 @row [gap $gap, wrap]
244 @row [gap $gap, wrap]
245 @el [width fill, spacing $base, min-width 240]
245 @el [width fill, spacing $base, min-width 240]
246 @text [font-weight bold] Unordered
246 @text [font-weight bold] Unordered
247− @list [spacing 4, list-style disc, padding-inline-start 20]
247+ @ul [spacing 4, list-style disc, padding-inline-start 20]
248− @item [display list-item] Composable with @each
248+ @li [display list-item] Composable with @each
249− @item [display list-item] Indent to nest children
249+ @li [display list-item] Indent to nest children
250− @item [display list-item] Bold list items work too
250+ @li [display list-item] Bold list items work too
251 @text [font-weight bold] Ordered
251 @text [font-weight bold] Ordered
252− @list [ordered, list-style decimal, padding-inline-start 20]
252+ @ol [list-style decimal, padding-inline-start 20]
253− @item [display list-item] First
253+ @li [display list-item] First
254− @item [display list-item] Second
254+ @li [display list-item] Second
255− @item [display list-item] Third
255+ @li [display list-item] Third
256
256
257 @el [width fill, spacing $base, min-width 240]
257 @el [width fill, spacing $base, min-width 240]
258 @text [font-weight bold] Table
258 @text [font-weight bold] Table
examples/docs.hl+4−4
@@ -66,10 +66,10 @@
66
66
67 @text [font-weight bold, font-size 24, color $ink] Next steps
67 @text [font-weight bold, font-size 24, color $ink] Next steps
68
68
69− @list [spacing 8]
69+ @ul [spacing 8]
70− @item
70+ @li
71 @link [color $primary] /docs/layout Learn the layout model
71 @link [color $primary] /docs/layout Learn the layout model
72− @item
72+ @li
73 @link [color $primary] /docs/styling Customize styling
73 @link [color $primary] /docs/styling Customize styling
74− @item
74+ @li
75 @link [color $primary] /docs/functions Extract reusable components
75 @link [color $primary] /docs/functions Extract reusable components
src/bin/htmlang_lsp/completion.rs+1−1
@@ -413,7 +413,7 @@ fn element_specific_attrs(element: &str) -> &'static [&'static str] {
413 "progress" => &["value", "max"],
413 "progress" => &["value", "max"],
414 "details" => &["open"],
414 "details" => &["open"],
415 "dialog" => &["open"],
415 "dialog" => &["open"],
416− "list" => &["ordered", "type", "start"],
416+ "ol" => &["type", "start", "reversed"],
417 "time" => &["datetime"],
417 "time" => &["datetime"],
418 "abbr" => &["title"],
418 "abbr" => &["title"],
419 "label" => &["for"],
419 "label" => &["for"],
src/bin/htmlang_lsp/docs.rs+4−4
@@ -70,8 +70,9 @@ pub(crate) const ELEMENTS: &[Doc] = &[
70 "Layer filling the parent, painted behind its content.",
70 "Layer filling the parent, painted behind its content.",
71 "@el [padding 40]\n @behind\n @el [background #fef3c7, width fill, height fill]",
71 "@el [padding 40]\n @behind\n @el [background #fef3c7, width fill, height fill]",
72 ),
72 ),
73− doc("list", "List (`<ul>`; `[ordered]` for `<ol>`).", "@list [ordered]\n @item First"),
73+ doc("ul", "Bulleted list.", "@ul\n @li First\n @li Second"),
74+ doc("ol", "Numbered list.", "@ol [list-style decimal]\n @li First"),
74− doc("item", "List item (`<li>`).", "@item First"),
75+ doc("li", "List item.", "@li First"),
75 doc("form", "Form; the argument is its `action`.", "@form [method=post] /subscribe"),
76 doc("form", "Form; the argument is its `action`.", "@form [method=post] /subscribe"),
76 doc("input", "Form input (void element).", "@input [type=email, name=email, required]"),
77 doc("input", "Form input (void element).", "@input [type=email, name=email, required]"),
77 doc("button", "Button.", "@button [type=submit] Send"),
78 doc("button", "Button.", "@button [type=submit] Send"),
@@ -127,7 +128,6 @@ pub(crate) const ATTRIBUTES: &[Doc] = &[
127 doc("col-span", "Columns a grid child spans.", "col-span 2"),
128 doc("col-span", "Columns a grid child spans.", "col-span 2"),
128 doc("row-span", "Rows a grid child spans.", "row-span 2"),
129 doc("row-span", "Rows a grid child spans.", "row-span 2"),
129 doc("line-height", "Line height; integers of 2 or more are px.", "line-height 1.5"),
130 doc("line-height", "Line height; integers of 2 or more are px.", "line-height 1.5"),
130− doc("ordered", "On `@list`: a numbered list (`<ol>`).", "ordered"),
131 doc("inline", "On `@image`: embed the file (SVG markup, or other images as base64) in the page.", "inline"),
131 doc("inline", "On `@image`: embed the file (SVG markup, or other images as base64) in the page.", "inline"),
132 doc("responsive", "On `@image`: widths for a generated `srcset`.", "responsive 400 800 1200"),
132 doc("responsive", "On `@image`: widths for a generated `srcset`.", "responsive 400 800 1200"),
133];
133];
@@ -141,7 +141,7 @@ pub(crate) const COMPONENTS: &[Doc] = &[
141 doc("spacer", "Takes up the remaining space in a row or column.", "@spacer"),
141 doc("spacer", "Takes up the remaining space in a row or column.", "@spacer"),
142 doc("tooltip", "Text that shows `tip` when hovered.", "@tooltip [tip More info] Hover me"),
142 doc("tooltip", "Text that shows `tip` when hovered.", "@tooltip [tip More info] Hover me"),
143 doc("carousel", "Horizontally scrolling row that snaps to each child.", "@carousel [spacing 16]\n @el Slide 1"),
143 doc("carousel", "Horizontally scrolling row that snaps to each child.", "@carousel [spacing 16]\n @el Slide 1"),
144− doc("breadcrumb", "Breadcrumb trail of `@item`s.", "@breadcrumb\n @item > @link / Home\n @item Docs"),
144+ doc("breadcrumb", "Breadcrumb trail of `@li`s.", "@breadcrumb\n @li > @link / Home\n @li Docs"),
145];
145];
146
146
147/// Standard-library attribute bundles, used as `[$name]`.
147/// Standard-library attribute bundles, used as `[$name]`.
src/upgrade.rs+7−10
@@ -18,9 +18,7 @@ const ELEMENT_ALIASES: &[(&str, &str)] = &[
18 ("col", "el"),
18 ("col", "el"),
19 ("p", "paragraph"),
19 ("p", "paragraph"),
20 ("img", "image"),
20 ("img", "image"),
21− ("li", "item"),
22 ("btn", "button"),
21 ("btn", "button"),
23− ("ul", "list"),
24 ("divider", "hr"),
22 ("divider", "hr"),
25 ("opt", "option"),
23 ("opt", "option"),
26];
24];
@@ -518,26 +516,25 @@ fn rewrite_block(
518 return Some(Block { lines: out, end });
516 return Some(Block { lines: out, end });
519 }
517 }
520
518
521− // @breadcrumb: each crumb is now an explicit @item
519+ // @breadcrumb: each crumb is now an explicit @li
522 if (trimmed == "@breadcrumb" || trimmed.starts_with("@breadcrumb "))
520 if (trimmed == "@breadcrumb" || trimmed.starts_with("@breadcrumb "))
523 && !user_defined.contains(&"breadcrumb")
521 && !user_defined.contains(&"breadcrumb")
524 {
522 {
525 let child_indent = body.iter().find(|l| !l.trim().is_empty()).map(|l| indent_of(l));
523 let child_indent = body.iter().find(|l| !l.trim().is_empty()).map(|l| indent_of(l));
524+ let is_item = |t: &str| t == "@li" || t.starts_with("@li ") || t.starts_with("@li[");
526 if body.iter().all(|l| {
525 if body.iter().all(|l| {
527− l.trim().is_empty()
528− || Some(indent_of(l)) != child_indent
526+ l.trim().is_empty() || Some(indent_of(l)) != child_indent || is_item(l.trim())
529− || l.trim().starts_with("@item")
530 }) {
527 }) {
531 return None;
528 return None;
532 }
529 }
533 let mut out = vec![line.to_string()];
530 let mut out = vec![line.to_string()];
534 for l in body {
531 for l in body {
535 let t = l.trim();
532 let t = l.trim();
536− if Some(indent_of(l)) == child_indent && !t.is_empty() && !t.starts_with("@item") {
533+ if Some(indent_of(l)) == child_indent && !t.is_empty() && !is_item(t) {
537 let wrapped = if t.starts_with('@') {
534 let wrapped = if t.starts_with('@') {
538− format!("@item > {}", t)
535+ format!("@li > {}", t)
539 } else {
536 } else {
540− format!("@item {}", t)
537+ format!("@li {}", t)
541 };
538 };
542 out.push(format!("{}{}", " ".repeat(indent_of(l)), wrapped));
539 out.push(format!("{}{}", " ".repeat(indent_of(l)), wrapped));
543 } else {
540 } else {
@@ -1779,7 +1776,7 @@ mod tests {
1779 assert_eq!(up("@tooltip [tip X] Y"), "@tooltip [tip X] Y");
1776 assert_eq!(up("@tooltip [tip X] Y"), "@tooltip [tip X] Y");
1780 assert_eq!(
1777 assert_eq!(
1781 up("@breadcrumb\n @link / Home\n Current"),
1778 up("@breadcrumb\n @link / Home\n Current"),
1782− "@breadcrumb\n @item > @link / Home\n @item Current"
1779+ "@breadcrumb\n @li > @link / Home\n @li Current"
1783 );
1780 );
1784 }
1781 }
1785
1782
tests/snapshots.rs+6−31
@@ -712,15 +712,15 @@ fn semantic_aside_renders_aside_tag() {
712
712
713#[test]
713#[test]
714fn list_renders_ul_by_default() {
714fn list_renders_ul_by_default() {
715− let output = compile("@page T\n@list\n @item Hello");
715+ let output = compile("@page T\n@ul\n @li Hello");
716 assert!(output.contains("<ul"));
716 assert!(output.contains("<ul"));
717 assert!(output.contains("<li"));
717 assert!(output.contains("<li"));
718 assert!(output.contains("Hello"));
718 assert!(output.contains("Hello"));
719}
719}
720
720
721#[test]
721#[test]
722−fn list_renders_ol_with_ordered() {
722+fn ol_renders_ol() {
723− let output = compile("@page T\n@list [ordered]\n @item First\n @item Second");
723+ let output = compile("@page T\n@ol\n @li First\n @li Second");
724 assert!(output.contains("<ol"));
724 assert!(output.contains("<ol"));
725 assert!(output.contains("<li"));
725 assert!(output.contains("<li"));
726}
726}
@@ -728,7 +728,6 @@ fn list_renders_ol_with_ordered() {
728#[test]
728#[test]
729fn removed_aliases_point_to_upgrade() {
729fn removed_aliases_point_to_upgrade() {
730 for (src, replacement) in [
730 for (src, replacement) in [
731− ("@li Works", "@item"),
732 ("@divider", "@hr"),
731 ("@divider", "@hr"),
733 ("@el > @col x", "@el"),
732 ("@el > @col x", "@el"),
734 ("Say {@img a.png}", "@image"),
733 ("Say {@img a.png}", "@image"),
@@ -1093,30 +1092,6 @@ fn comparison_ends_with() {
1093// Feature tests: element-specific attribute validation
1092// Feature tests: element-specific attribute validation
1094// ---------------------------------------------------------------------------
1093// ---------------------------------------------------------------------------
1095
1094
1096−#[test]
1097−fn warning_ordered_on_non_list() {
1098− let diags = parse_diagnostics("@el [ordered]");
1099− assert!(
1100− diags
1101− .iter()
1102− .any(|d| d.message.contains("ordered") && d.message.contains("@list")),
1103− "expected ordered on non-list warning, got: {:?}",
1104− diags
1105− );
1106−}
1107−
1108−#[test]
1109−fn no_warning_ordered_on_list() {
1110− let diags = parse_diagnostics("@list [ordered]\n @item x");
1111− assert!(
1112− !diags
1113− .iter()
1114− .any(|d| d.message.contains("ordered") && d.message.contains("no effect")),
1115− "should not warn about ordered on @list, got: {:?}",
1116− diags
1117− );
1118−}
1119−
1120#[test]
1095#[test]
1121fn warning_controls_on_non_media() {
1096fn warning_controls_on_non_media() {
1122 let diags = parse_diagnostics("@el [controls]");
1097 let diags = parse_diagnostics("@el [controls]");
@@ -1671,7 +1646,7 @@ fn css_caret_color() {
1671
1646
1672#[test]
1647#[test]
1673fn css_list_style() {
1648fn css_list_style() {
1674− let output = compile("@page T\n@list [list-style disc]");
1649+ let output = compile("@page T\n@ul [list-style disc]");
1675 assert!(output.contains("list-style:disc"));
1650 assert!(output.contains("list-style:disc"));
1676}
1651}
1677
1652
@@ -3433,7 +3408,7 @@ fn search_element() {
3433
3408
3434#[test]
3409#[test]
3435fn breadcrumb_generates_nav_ol() {
3410fn breadcrumb_generates_nav_ol() {
3436− let output = compile("@breadcrumb\n @item > @text Home\n @item About");
3411+ let output = compile("@breadcrumb\n @li > @text Home\n @li About");
3437 assert!(output.contains("aria-label=\"breadcrumb\""), "nav: {}", output);
3412 assert!(output.contains("aria-label=\"breadcrumb\""), "nav: {}", output);
3438 assert!(output.contains("<ol class="), "ol: {}", output);
3413 assert!(output.contains("<ol class="), "ol: {}", output);
3439 assert!(output.contains("<li class="), "li: {}", output);
3414 assert!(output.contains("<li class="), "li: {}", output);
@@ -4961,7 +4936,7 @@ fn children_prefix_styles_direct_children() {
4961
4936
4962#[test]
4937#[test]
4963fn standard_library_components_compile_cleanly() {
4938fn standard_library_components_compile_cleanly() {
4964− let src = "@badge [background red] 3\n@tag v2\n@chip Rust\n@avatar\n AB\n@spacer\n@tooltip [tip More] Hover\n@carousel\n @el A\n@breadcrumb\n @item Home\n@el [$skeleton]\n@el [$no-scrollbar]";
4939+ let src = "@badge [background red] 3\n@tag v2\n@chip Rust\n@avatar\n AB\n@spacer\n@tooltip [tip More] Hover\n@carousel\n @el A\n@breadcrumb\n @li Home\n@el [$skeleton]\n@el [$no-scrollbar]";
4965 let diags = parse_diagnostics(src);
4940 let diags = parse_diagnostics(src);
4966 assert!(diags.is_empty(), "standard library produced diagnostics: {:?}", diags);
4941 assert!(diags.is_empty(), "standard library produced diagnostics: {:?}", diags);
4967 let output = compile(src);
4942 let output = compile(src);
tests/snapshots/breadcrumb.hl+3−3
@@ -1,4 +1,4 @@
1@breadcrumb [spacing 10]
1@breadcrumb [spacing 10]
2− @item > @link / Home
2+ @li > @link / Home
3− @item > @link /docs Docs
3+ @li > @link /docs Docs
4− @item > @text Current Page
4+ @li > @text Current Page
tests/snapshots/list_elements.hl+10−10
@@ -1,15 +1,15 @@
1@page List Elements
1@page List Elements
2
2
3−@list [spacing 8]
3+@ul [spacing 8]
4− @item First item
4+ @li First item
5− @item Second item
5+ @li Second item
6− @item Third item
6+ @li Third item
7
7
8−@list [ordered, spacing 4]
8+@ol [spacing 4]
9− @item Step one
9+ @li Step one
10− @item Step two
10+ @li Step two
11− @item Step three
11+ @li Step three
12
12
13−@list
13+@ul
14− @item [padding 10, background #f0f0f0, border-radius 4]
14+ @li [padding 10, background #f0f0f0, border-radius 4]
15 @text [font-weight bold] Styled item
15 @text [font-weight bold] Styled item
tests/snapshots/new_css_properties.hl+3−3
@@ -10,9 +10,9 @@
10
10
11@input [type=text, caret-color red]
11@input [type=text, caret-color red]
12
12
13−@list [list-style disc]
13+@ul [list-style disc]
14− @item One
14+ @li One
15− @item Two
15+ @li Two
16
16
17@table [border-collapse collapse, border-spacing 0]
17@table [border-collapse collapse, border-spacing 0]
18 @tr
18 @tr