From 9a69f79861fae1cb80e6f21fa45b73b91a4627ac Mon Sep 17 00:00:00 2001 From: bflatastic Date: Sat, 17 Oct 2026 22:39:10 +0700 Subject: [PATCH] #552: write and read space evenly as SPACE_EVENLY_CSS The format's SPACE_EVENLY is its older name for equal gaps without edge space, so files keep reading it as space between; true space evenly is SPACE_EVENLY_CSS, which the export now writes. --- .../src/fig/auto_layout_sizing_tests.rs | 31 +++++++++++++++++-- crates/format/src/fig/export.rs | 4 +-- crates/format/src/fig/map.rs | 5 +-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/crates/format/src/fig/auto_layout_sizing_tests.rs b/crates/format/src/fig/auto_layout_sizing_tests.rs index 99730f70..29580afb 100644 --- a/crates/format/src/fig/auto_layout_sizing_tests.rs +++ b/crates/format/src/fig/auto_layout_sizing_tests.rs @@ -1,8 +1,8 @@ //! How auto layout frames and text size on import (hug or fixed), on encoded `.fig` files built in //! code and REST file JSON: the sizing a file records, an auto layout frame that records none, and -//! text that hugs by its resize mode. +//! text that hugs by its resize mode. Also how distributed main-axis alignment reads. -use figcraft_doc::{Document, Sizing}; +use figcraft_doc::{Document, MainAlign, Sizing}; use serde_json::{Value, json}; use super::kiwi::{Kv, Schema}; @@ -11,6 +11,7 @@ const SCHEMA: &str = " enum NodeType NONE DOCUMENT CANVAS FRAME TEXT SYMBOL INSTANCE enum StackMode NONE HORIZONTAL VERTICAL enum StackSize FIXED RESIZE_TO_FIT RESIZE_TO_FIT_WITH_IMPLICIT_SIZE +enum StackJustify MIN CENTER MAX SPACE_EVENLY SPACE_BETWEEN SPACE_AROUND SPACE_EVENLY_CSS enum TextAutoResize NONE WIDTH_AND_HEIGHT HEIGHT struct GUID uint sessionID, uint localID struct Vector float x, float y @@ -18,7 +19,7 @@ struct Matrix float m00, float m01, float m02, float m10, float m11, float m12 message ParentIndex GUID guid, string position message TextData string characters message SymbolData GUID symbolID -message NodeChange GUID guid, ParentIndex parentIndex, NodeType type, string name, Vector size, Matrix transform, StackMode stackMode, StackSize stackPrimarySizing, StackSize stackCounterSizing, TextAutoResize textAutoResize, float fontSize, TextData textData, SymbolData symbolData +message NodeChange GUID guid, ParentIndex parentIndex, NodeType type, string name, Vector size, Matrix transform, StackMode stackMode, StackSize stackPrimarySizing, StackSize stackCounterSizing, StackJustify stackPrimaryAlignItems, TextAutoResize textAutoResize, float fontSize, TextData textData, SymbolData symbolData message Message NodeChange[] nodeChanges "; @@ -191,3 +192,27 @@ fn rest_files_read_left_out_sizing_modes_as_hug_and_text_by_its_resize_mode() { assert_eq!(sizing(&doc, name), want, "{name}"); } } + +#[test] +fn distributed_alignment_reads_the_older_evenly_name_as_space_between() { + let rows = [ + ("Between", "SPACE_BETWEEN", MainAlign::SpaceBetween), + ("Older evenly", "SPACE_EVENLY", MainAlign::SpaceBetween), + ("Around", "SPACE_AROUND", MainAlign::SpaceAround), + ("Evenly", "SPACE_EVENLY_CSS", MainAlign::SpaceEvenly), + ]; + let nodes = rows + .iter() + .enumerate() + .flat_map(|(i, (name, align, _))| { + let mut fields = stack("HORIZONTAL", None, None); + fields.push(("stackPrimaryAlignItems", Kv::Enum(align))); + component(10 + 2 * i as u64, 50.0 * i as f64, name, fields, None) + }) + .collect(); + let doc = import(nodes); + for (name, _, want) in rows { + let n = doc.nodes().find(|n| n.name == name).unwrap_or_else(|| panic!("no layer {name}")); + assert_eq!(n.layout.as_ref().map(|l| l.main_align), Some(want), "{name}"); + } +} diff --git a/crates/format/src/fig/export.rs b/crates/format/src/fig/export.rs index ca9e2682..cac29be3 100644 --- a/crates/format/src/fig/export.rs +++ b/crates/format/src/fig/export.rs @@ -73,7 +73,7 @@ enum StrokeJoin MITER=0 BEVEL=1 ROUND=2 enum ConstraintType MIN=0 CENTER=1 MAX=2 STRETCH=3 SCALE=4 enum StackMode NONE=0 HORIZONTAL=1 VERTICAL=2 GRID=3 enum StackAlign MIN=0 CENTER=1 MAX=2 BASELINE=3 -enum StackJustify MIN=0 CENTER=1 MAX=2 SPACE_EVENLY=3 SPACE_BETWEEN=4 SPACE_AROUND=5 +enum StackJustify MIN=0 CENTER=1 MAX=2 SPACE_EVENLY=3 SPACE_BETWEEN=4 SPACE_AROUND=5 SPACE_EVENLY_CSS=6 enum StackCounterAlign MIN=0 CENTER=1 MAX=2 STRETCH=3 AUTO=4 BASELINE=5 enum StackSize FIXED=0 RESIZE_TO_FIT=1 enum StackWrap NO_WRAP=0 WRAP=1 @@ -1371,7 +1371,7 @@ impl<'d> Exporter<'d> { MainAlign::Max => "MAX", MainAlign::SpaceBetween => "SPACE_BETWEEN", MainAlign::SpaceAround => "SPACE_AROUND", - MainAlign::SpaceEvenly => "SPACE_EVENLY", + MainAlign::SpaceEvenly => "SPACE_EVENLY_CSS", }; let cross = match l.cross_align { CrossAlign::Min => "MIN", diff --git a/crates/format/src/fig/map.rs b/crates/format/src/fig/map.rs index a113f902..2ebe1ee9 100644 --- a/crates/format/src/fig/map.rs +++ b/crates/format/src/fig/map.rs @@ -1405,8 +1405,9 @@ impl<'a> Mapper<'a> { Some("CENTER") => "CENTER", Some("MAX") => "MAX", Some("SPACE_AROUND") => "SPACE_AROUND", - Some("SPACE_EVENLY") => "SPACE_EVENLY", - Some("SPACE_BETWEEN" | "SPACE_EVENLY_CSS") => "SPACE_BETWEEN", + // `SPACE_EVENLY` is the format's older name for equal gaps without edge space. + Some("SPACE_EVENLY_CSS") => "SPACE_EVENLY", + Some("SPACE_BETWEEN" | "SPACE_EVENLY") => "SPACE_BETWEEN", _ => "MIN", }; o.insert("primaryAxisAlignItems".into(), json!(main));