render: honor item self alignment

This commit is contained in:
SGavrl committed 2026-07-23 16:42:19 +00:00
1 parent c333619703
commit ba92928ff5
2 files changed
+96

No files matched your search

+4
View File
@@ -287,6 +287,8 @@ pub struct LayoutStyle {
/// one field for both made `text-align:left` shrink-wrap flex children.
pub text_align: Option<taffy::AlignItems>,
pub align_items: Option<taffy::AlignItems>,
pub align_self: Option<taffy::AlignSelf>,
pub justify_self: Option<taffy::JustifySelf>,
pub flex_direction: Option<taffy::FlexDirection>,
pub flex_wrap: Option<taffy::FlexWrap>,
pub justify_content: Option<taffy::JustifyContent>,
@@ -717,6 +719,8 @@ pub(crate) fn to_taffy_style(style: &LayoutStyle) -> Style {
// `align-items` has no effect on a block formatting context.
s.align_items = None;
}
s.align_self = style.align_self;
s.justify_self = style.justify_self;
if let Some(jc) = style.justify_content {
s.justify_content = Some(jc);
}
+92
View File
@@ -431,6 +431,22 @@ fn apply_value(style: &mut LayoutStyle, name: &str, value: &str) {
_ => {}
}
},
"align-self" => {
if let Some(value) = self_alignment_value(value) {
style.align_self = value;
}
},
"justify-self" => {
if let Some(value) = self_alignment_value(value) {
style.justify_self = value;
}
},
"place-self" => {
if let Some((align, justify)) = self_alignment_pair(value) {
style.align_self = align;
style.justify_self = justify;
}
},
"justify-content" => {
match value {
"center" => style.justify_content = Some(taffy::JustifyContent::CENTER),
@@ -677,6 +693,57 @@ fn apply_value(style: &mut LayoutStyle, name: &str, value: &str) {
}
}
/// Parse the common CSS Box Alignment values that taffy can represent.
///
/// The outer option distinguishes an invalid declaration from `auto`, which
/// resets a preceding declaration to the inherited item-alignment behavior.
fn self_alignment_value(value: &str) -> Option<Option<taffy::AlignSelf>> {
let normalized = value.trim().to_ascii_lowercase();
let alignment = match normalized.as_str() {
"auto" => return Some(None),
"normal" => taffy::AlignSelf::STRETCH,
"start" | "self-start" => taffy::AlignSelf::START,
"end" | "self-end" => taffy::AlignSelf::END,
"flex-start" => taffy::AlignSelf::FLEX_START,
"flex-end" => taffy::AlignSelf::FLEX_END,
"center" => taffy::AlignSelf::CENTER,
"baseline" | "first baseline" => taffy::AlignSelf::BASELINE,
"stretch" => taffy::AlignSelf::STRETCH,
"safe start" | "safe self-start" => taffy::AlignSelf::SAFE_START,
"safe end" | "safe self-end" => taffy::AlignSelf::SAFE_END,
"safe flex-start" => taffy::AlignSelf::SAFE_FLEX_START,
"safe flex-end" => taffy::AlignSelf::SAFE_FLEX_END,
"safe center" => taffy::AlignSelf::SAFE_CENTER,
"unsafe start" | "unsafe self-start" => taffy::AlignSelf::START,
"unsafe end" | "unsafe self-end" => taffy::AlignSelf::END,
"unsafe flex-start" => taffy::AlignSelf::FLEX_START,
"unsafe flex-end" => taffy::AlignSelf::FLEX_END,
"unsafe center" => taffy::AlignSelf::CENTER,
_ => return None,
};
Some(Some(alignment))
}
fn self_alignment_pair(
value: &str,
) -> Option<(Option<taffy::AlignSelf>, Option<taffy::JustifySelf>)> {
if let Some(alignment) = self_alignment_value(value) {
return Some((alignment, alignment));
}
let tokens: Vec<&str> = value.split_whitespace().collect();
for split in 1..tokens.len() {
let align = tokens[..split].join(" ");
let justify = tokens[split..].join(" ");
if let (Some(align), Some(justify)) = (
self_alignment_value(&align),
self_alignment_value(&justify),
) {
return Some((align, justify));
}
}
None
}
/// Parse the subset of `transform` obscura applies at paint time: `translate`,
/// `translateX`, `translateY` (px and %, stored unresolved so % can resolve
/// against the element's own border box later) and `scale`/`scaleX`/`scaleY`.
@@ -2609,6 +2676,31 @@ mod tests {
assert!(invalid.internal_flex_container);
}
#[test]
fn item_self_alignment_parses_and_resets() {
let aligned = compute_style(
"div",
Some("align-self:safe center;justify-self:flex-end"),
);
assert_eq!(aligned.align_self, Some(taffy::AlignSelf::SAFE_CENTER));
assert_eq!(aligned.justify_self, Some(taffy::JustifySelf::FLEX_END));
let reset = compute_style(
"div",
Some("align-self:center;align-self:auto;justify-self:end;justify-self:auto"),
);
assert_eq!(reset.align_self, None);
assert_eq!(reset.justify_self, None);
let normal = compute_style("div", Some("align-self:normal;justify-self:normal"));
assert_eq!(normal.align_self, Some(taffy::AlignSelf::STRETCH));
assert_eq!(normal.justify_self, Some(taffy::JustifySelf::STRETCH));
let shorthand = compute_style("div", Some("place-self:safe center flex-end"));
assert_eq!(shorthand.align_self, Some(taffy::AlignSelf::SAFE_CENTER));
assert_eq!(shorthand.justify_self, Some(taffy::JustifySelf::FLEX_END));
}
#[test]
fn font_shorthand_expands_layout_fields_and_resets_omissions() {
let s = compute_style(