diff --git a/Makefile b/Makefile index 651b025..87c74d2 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ NATIVE_MANIFEST = native/Cargo.toml NATIVE_TARGET ?= $(shell $(EMACS_BATCH) -l ebox-native-reflow.el --eval '(princ (ebox-native-reflow--rust-target))') NATIVE_RELEASE_DIR = native/target/$(NATIVE_TARGET)/release -.PHONY: all check ci load compile test checkdoc core-tests grid-tests ebox-commit-tests visual-check-tests package-tests selector-tests examples-tests dsl-tests flex-tests docs-contract-tests ci-contract-tests visual-check native-rust-tests native-build diff-check clean package-lint package-lint-install +.PHONY: all check ci load compile test checkdoc core-tests grid-tests ebox-commit-tests visual-check-tests package-tests selector-tests dsl-tests flex-tests docs-contract-tests ci-contract-tests visual-check native-rust-tests native-build diff-check clean package-lint package-lint-install all: check @@ -21,7 +21,7 @@ compile: rm -f *.elc tests/*.elc scripts/*.elc $(EMACS_BATCH) --eval '(setq byte-compile-error-on-warn t)' -l ebox.el --eval '(ebox-byte-compile)' -test: core-tests grid-tests ebox-commit-tests visual-check-tests package-tests selector-tests examples-tests dsl-tests flex-tests docs-contract-tests ci-contract-tests +test: core-tests grid-tests ebox-commit-tests visual-check-tests package-tests selector-tests dsl-tests flex-tests docs-contract-tests ci-contract-tests core-tests: $(EMACS_BATCH) -l tests/ebox-core-render-tests.el -f ert-run-tests-batch-and-exit @@ -41,9 +41,6 @@ package-tests: selector-tests: $(EMACS_BATCH) -l tests/ebox-selector-tests.el -f ert-run-tests-batch-and-exit -examples-tests: - $(EMACS_BATCH) -L examples -l tests/ebox-examples-tests.el -f ert-run-tests-batch-and-exit - dsl-tests: $(EMACS_BATCH) -l tests/ebox-dsl-tests.el -f ert-run-tests-batch-and-exit diff --git a/docs/maintainer/ebox-current-implementation-reference.en.md b/docs/maintainer/ebox-current-implementation-reference.en.md index 93fd78f..1b2f0a8 100644 --- a/docs/maintainer/ebox-current-implementation-reference.en.md +++ b/docs/maintainer/ebox-current-implementation-reference.en.md @@ -32,7 +32,7 @@ This is the maintainer entry point for the standalone Ebox repository. It descri The package intentionally does not include application Components, UI controls, reactive data, or a playground implementation. Those are sibling-package responsibilities. -The active contract also covers `Makefile`, `.github/workflows/ci.yml`, `examples/ebox-basic-examples.el`, `examples/playground/basic.ebox`, `examples/playground/comprehensive.ebox`, `examples/playground/flex-reference.ebox`, `examples/playground/responsive-reference.ebox`, `tests/ebox-core-render-tests.el`, `tests/ebox-grid-tests.el`, `tests/ebox-commit-tests.el`, `tests/ebox-examples-tests.el`, `tests/ebox-dsl-tests.el`, `tests/ebox-flex-tests.el`, `tests/ebox-selector-tests.el`, `tests/ebox-package-tests.el`, `tests/ebox-visual-check-tests.el`, `tests/ebox-docs-contract-tests.el`, `tests/ebox-ci-contract-tests.el`, `native/Cargo.toml`, `native/Cargo.lock`, `native/build.rs`, `native/vendor/emacs-30/emacs-module.h`, `native/src/lib.rs`, `native/src/layout.rs`, `native/c/ebox_module.c`, `scripts/ebox-package-lint.el`, and `scripts/ebox-visual-check.el`. +The active contract also covers `Makefile`, `.github/workflows/ci.yml`, `tests/ebox-core-render-tests.el`, `tests/ebox-grid-tests.el`, `tests/ebox-commit-tests.el`, `tests/ebox-dsl-tests.el`, `tests/ebox-flex-tests.el`, `tests/ebox-selector-tests.el`, `tests/ebox-package-tests.el`, `tests/ebox-visual-check-tests.el`, `tests/ebox-docs-contract-tests.el`, `tests/ebox-ci-contract-tests.el`, `native/Cargo.toml`, `native/Cargo.lock`, `native/build.rs`, `native/vendor/emacs-30/emacs-module.h`, `native/src/lib.rs`, `native/src/layout.rs`, `native/c/ebox_module.c`, `scripts/ebox-package-lint.el`, and `scripts/ebox-visual-check.el`. ## Runtime model @@ -77,7 +77,7 @@ Grid currently covers fixed and pixel tracks, `auto`, fractional tracks, `minmax ## Active examples and tests -The maintained examples are `examples/ebox-basic-examples.el` and the `.ebox` fixtures under `examples/playground/`. The regression boundary is the ERT files under `tests/` listed in the repository's documentation contract. No test in this package should load the historical full-stack source tree or an application framework. +The standalone package has no bundled playground fixtures. The migrated `.ebox` references and their file runner live in the sibling `ebox-playground` package; this repository tests the DSL and layout primitives directly. The regression boundary is the ERT files under `tests/` listed in the repository's documentation contract. No test in this package should load the historical full-stack source tree or an application framework. ## Verification matrix @@ -91,7 +91,6 @@ make ebox-commit-tests make visual-check-tests make package-tests make selector-tests -make examples-tests make dsl-tests make flex-tests make docs-contract-tests diff --git a/docs/maintainer/ebox-current-implementation-reference.zh.md b/docs/maintainer/ebox-current-implementation-reference.zh.md index d3650d6..6280014 100644 --- a/docs/maintainer/ebox-current-implementation-reference.zh.md +++ b/docs/maintainer/ebox-current-implementation-reference.zh.md @@ -32,6 +32,8 @@ 本包有意不包含应用 Component、UI control、响应式 data 或 playground 实现;它们属于同级包。历史应用性能记录器和 native reflow 评估器也不属于独立 Ebox 的发布边界;Ebox 只保留 native 模块本身、Rust 构建输入和可重复的构建检查。 +active 合同还覆盖 `Makefile`、`.github/workflows/ci.yml`、`tests/ebox-core-render-tests.el`、`tests/ebox-grid-tests.el`、`tests/ebox-commit-tests.el`、`tests/ebox-dsl-tests.el`、`tests/ebox-flex-tests.el`、`tests/ebox-selector-tests.el`、`tests/ebox-package-tests.el`、`tests/ebox-visual-check-tests.el`、`tests/ebox-docs-contract-tests.el`、`tests/ebox-ci-contract-tests.el`、`native/Cargo.toml`、`native/Cargo.lock`、`native/build.rs`、`native/vendor/emacs-30/emacs-module.h`、`native/src/lib.rs`、`native/src/layout.rs`、`native/c/ebox_module.c`、`scripts/ebox-package-lint.el` 和 `scripts/ebox-visual-check.el`。 + ## 运行时模型 正常数据流是: @@ -75,7 +77,7 @@ Source Tree ## Active 示例与测试 -维护中的示例是 `examples/ebox-basic-examples.el` 和 `examples/playground/` 下的 `.ebox` fixture。回归边界是 `tests/` 下由文档合同列出的 ERT 文件。本包测试不得加载历史全栈源码树或应用框架。 +独立 Ebox 包不再内置 playground fixture。迁移后的 `.ebox` 参考文件及其运行器位于同级 `ebox-playground` 包;本仓库直接测试 DSL 与布局原语。回归边界是 `tests/` 下由文档合同列出的 ERT 文件。本包测试不得加载历史全栈源码树或应用框架。 ## 验证矩阵 @@ -87,7 +89,6 @@ make ebox-commit-tests make visual-check-tests make package-tests make selector-tests -make examples-tests make dsl-tests make flex-tests make docs-contract-tests diff --git a/docs/user/ebox-user-guide.en.md b/docs/user/ebox-user-guide.en.md index fe27b0e..23b6bb9 100644 --- a/docs/user/ebox-user-guide.en.md +++ b/docs/user/ebox-user-guide.en.md @@ -64,7 +64,7 @@ Use row and column for simple one-dimensional composition. Use flex when free sp (ebox-create :content "Aside" :grid-column 3 :grid-row 2)) ``` -Grid tracks can be fixed, fractional, `auto`, `minmax`, or repeated. Explicit placement is one-based. Use positive integer spans and let implicit tracks fill omitted positions. +Grid tracks can be fixed, fractional, `auto`, `minmax`, or repeated. Explicit placement is one-based. Use positive integer spans and let implicit tracks fill omitted positions. Multiline items are aligned line by line to their grid rectangle before a wrapper border is painted, keeping a bordered Grid's right edge continuous even when child lines have different natural widths. ## 5. Render text or a buffer @@ -117,7 +117,9 @@ Selectors query the rendered tree and return public handles. They do not edit th (box :content "C"))) ``` -The files under `examples/playground/` are executable fixtures for this syntax. They remain low-level layout examples and do not require the ETAF framework. +Inside a `.ebox` fixture, keep the structural form unquoted. Quote list and symbol constants in property positions (for example, `:gap '(1 (12))` and `:justify-content 'center`), while leaving executable Elisp property expressions unquoted. `ebox-playground` evaluates those property expressions before passing the form to `ebox-build`, matching the `etaf-view` value convention. + +Executable `.ebox` references are maintained by the sibling [`ebox-playground`](../../ebox-playground/README.md) package. Its `examples/` directory contains the migrated Basic, Comprehensive, Flex, Responsive, and complete Grid reference files; they remain low-level layout examples and do not require the ETAF framework. ## 9. Optional native reflow diff --git a/docs/user/ebox-user-guide.zh.md b/docs/user/ebox-user-guide.zh.md index 2e6cf43..ae146f5 100644 --- a/docs/user/ebox-user-guide.zh.md +++ b/docs/user/ebox-user-guide.zh.md @@ -64,7 +64,7 @@ Ebox 是底层的 box、布局和 buffer 渲染包。当应用需要精确几何 (ebox-create :content "Aside" :grid-column 3 :grid-row 2)) ``` -Grid 轨道支持固定值、分数、`auto`、`minmax` 和重复轨道。显式放置从 1 开始;span 使用正整数;省略的位置由隐式轨道补齐。 +Grid 轨道支持固定值、分数、`auto`、`minmax` 和重复轨道。显式放置从 1 开始;span 使用正整数;省略的位置由隐式轨道补齐。多行子项会先逐行对齐到自己的 Grid 矩形,再绘制外层边框;即使子项各行的自然宽度不同,带边框的 Grid 右边缘也会保持连续。 ## 5. 渲染文本或 buffer @@ -117,7 +117,9 @@ Selector 查询已渲染的树并返回公共 handle;它不编辑 buffer,也 (box :content "C"))) ``` -`examples/playground/` 下的文件是该语法的可执行 fixture。它们只演示低层布局,不依赖 ETAF。 +在 `.ebox` fixture 中,结构表单保持不加 quote。属性位置的 list 和 symbol 常量要加 quote,例如 `:gap '(1 (12))`、`:justify-content 'center`;可执行的 Elisp 属性表达式则保持不加 quote。`ebox-playground` 会在把 form 交给 `ebox-build` 之前求值这些属性表达式,这与 `etaf-view` 的属性值约定一致。 + +可执行的 `.ebox` 参考文件由同级 [`ebox-playground`](../../ebox-playground/README.md) 包维护。它的 `examples/` 目录包含迁移后的 Basic、Comprehensive、Flex、Responsive 以及完整 Grid 参考文件;这些文件只演示低层布局,不依赖 ETAF。 ## 9. 可选 native reflow diff --git a/ebox-dsl.el b/ebox-dsl.el index 801dff2..d4853f7 100644 --- a/ebox-dsl.el +++ b/ebox-dsl.el @@ -12,6 +12,30 @@ (require 'ebox-flex) (require 'ebox-grid) +(defun ebox--dsl-unquote-value (value) + "Unquote one static DSL property VALUE when it is quoted data." + (if (and (consp value) + (eq (car value) 'quote) + (null (cddr value))) + (cadr value) + value)) + +(defun ebox--dsl-unquote-properties (items) + "Unquote static property values in top-level DSL ITEMS. +Structural child forms remain untouched; only values immediately following +keyword properties are normalized." + (let (result) + (while items + (let ((item (pop items))) + (if (keywordp item) + (progn + (unless items + (error "ebox-build: missing value for %S" item)) + (push item result) + (push (ebox--dsl-unquote-value (pop items)) result)) + (push item result)))) + (nreverse result))) + (defun ebox--build-split-attrs (items) "Split DSL ITEMS into (PROPS . CHILDREN)." (let (props children) @@ -171,7 +195,7 @@ the child layout in a box using the rendered child layout as content." (error "ebox-build: invalid DSL node %S" dsl)) (t (let ((tag (car dsl)) - (items (cdr dsl))) + (items (ebox--dsl-unquote-properties (cdr dsl)))) (pcase tag ((or 'box 'ebox) (ebox--build-box items)) ('row (ebox--build-layout tag #'ebox-row items)) diff --git a/examples/playground/basic.ebox b/examples/playground/basic.ebox deleted file mode 100644 index 06379f3..0000000 --- a/examples/playground/basic.ebox +++ /dev/null @@ -1,7 +0,0 @@ -(box :content "Playground file" - :box-sizing border-box - :padding (1 (12)) - :border t - :border-color "#2563EB" - :bgcolor "#EFF6FF" - :color "#1E3A8A") diff --git a/examples/playground/comprehensive.ebox b/examples/playground/comprehensive.ebox deleted file mode 100644 index a55b16c..0000000 --- a/examples/playground/comprehensive.ebox +++ /dev/null @@ -1,45 +0,0 @@ -(column - (box :content "Ebox comprehensive DSL showcase\nThe outer sections omit :width so Playground viewport sizing drives the layout." - :padding (1 (16)) :border "#334155" - :bgcolor "#F8FAFC" :color "#0F172A" :text-align center) - - (spacer :height 1) - - (box :content "Width rule in this file\nContainer sections use auto width. Fixed widths remain only where the example demonstrates exact item sizing, basis, min-width, or max-width." - :padding (0 (14)) :border "#64748B" - :bgcolor "#F8FAFC" :color "#111827" :wrap-mode word) - - (spacer :height 1) - - (flex - :margin (1 0 0 1) :padding (1 (8)) - :border "#475569" :bgcolor "#F8FAFC" - :flex-flow (row wrap) - :justify-content space-between :align-items center - :align-content flex-start :row-gap 1 :column-gap (12) - (item - :order -1 :flex-basis (270) :align-self flex-start - (box :content "item order -1\n:flex-basis 270\nalign-self start" - :width (270) :padding (0 (8)) - :border "#BE185D" :bgcolor "#FCE7F3" :color "#831843" - :wrap-mode word)) - (item - :flex (1 1 (220)) - (box :content "item :flex (1 1 220)\ngrow shrink basis" - :width (220) :height 4 - :padding (0 (8)) :border "#1D4ED8" - :bgcolor "#DBEAFE" :color "#111827" :wrap-mode word)) - (item - :flex-grow 2 :flex-shrink 1 :flex-basis (240) - :align-self center - (box :content "item grow 2\nshrink 1\nbasis 240" - :width (240) :height 4 :padding (0 (8)) - :border "#B45309" :bgcolor "#FEF3C7" :color "#78350F" - :wrap-mode word)) - (item :flex-shrink 3 - :flex-basis (190) - :align-self flex-end - (box :content "item shrink 3\nbasis 190\nalign-self flex-end" - :width (190) :height 4 :padding (0 (8)) - :border "#15803D" :bgcolor "#DCFCE7" :color "#14532D" - :wrap-mode word)))) diff --git a/examples/playground/flex-reference.ebox b/examples/playground/flex-reference.ebox deleted file mode 100644 index 63166f3..0000000 --- a/examples/playground/flex-reference.ebox +++ /dev/null @@ -1,463 +0,0 @@ -(column ;; :height (viewport-height) - :width (viewport) - (box :content "Ebox CSS Flex Reference\nA modern, self-explaining DSL gallery for CSS flex container and item properties." - :padding (1 (24)) :border "#2F3437" - :bgcolor "#FAF7F0" :color "#1F2328" :text-align center) - - (spacer :height 1) - - (box :content "Container property: :flex-direction\nMain axis selection. Reverse values swap main-start and main-end while keeping source order intact." - :padding (0 (18)) :border "#D97757" - :bgcolor "#FFF5ED" :color "#3D2B1F") - (flex :flex-flow (row wrap) :row-gap 1 :column-gap (12) :padding (0 (12)) - :border "#D97757" :border-top-p nil - :bgcolor "#FFF8F2" - (column - (box :content "row" :width (220) :padding (0 (10)) :border "#D97757" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :width (220) :height 4 :padding (0 (8)) :border "#D97757" - :border-top-p nil - :bgcolor "#FFF8F2" :flex-direction row :column-gap (10) :align-items center - (item (box :content "A" :width (42) :height 1 :bgcolor "#F7C8B3" :text-align center)) - (item (box :content "B" :width (42) :height 1 :bgcolor "#F0A88F" :text-align center)) - (item (box :content "C" :width (42) :height 1 :bgcolor "#D97757" :color "#FFFFFF" :text-align center)))) - (column - (box :content "row-reverse" :width (220) :padding (0 (10)) :border "#D97757" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :width (220) :height 4 :padding (0 (8)) :border "#D97757" - :border-top-p nil - :bgcolor "#FFF8F2" :flex-direction row-reverse :column-gap (10) :align-items center - (item (box :content "A" :width (42) :height 1 :bgcolor "#F7C8B3" :text-align center)) - (item (box :content "B" :width (42) :height 1 :bgcolor "#F0A88F" :text-align center)) - (item (box :content "C" :width (42) :height 1 :bgcolor "#D97757" :color "#FFFFFF" :text-align center)))) - (column - (box :content "column" :width (220) :padding (0 (10)) :border "#D97757" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :width (220) :height 6 :padding (0 (8)) :border "#D97757" - :border-top-p nil - :bgcolor "#FFF8F2" :flex-direction column :row-gap 1 :align-items stretch - (item (box :content "A" :height 1 :bgcolor "#F7C8B3" :text-align center)) - (item (box :content "B" :height 1 :bgcolor "#F0A88F" :text-align center)) - (item (box :content "C" :height 1 :bgcolor "#D97757" :color "#FFFFFF" :text-align center)))) - (column - (box :content "column-reverse" :width (220) :padding (0 (10)) :border "#D97757" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :width (220) :height 6 :padding (0 (8)) :border "#D97757" - :border-top-p nil - :bgcolor "#FFF8F2" :flex-direction column-reverse :row-gap 1 :align-items stretch - (item (box :content "A" :height 1 :bgcolor "#F7C8B3" :text-align center)) - (item (box :content "B" :height 1 :bgcolor "#F0A88F" :text-align center)) - (item (box :content "C" :height 1 :bgcolor "#D97757" :color "#FFFFFF" :text-align center))))) - - (spacer :height 1) - - (box :content "Container property: :flex-wrap\nLine creation. nowrap keeps one flex line; wrap creates new lines; wrap-reverse stacks lines from the opposite cross side." - :padding (0 (18)) :border "#5E7F6A" - :bgcolor "#F3FAF4" :color "#24352A") - (flex :flex-flow (row wrap) :row-gap 1 :column-gap (12) :padding (0 (12)) - :border "#5E7F6A" :border-top-p nil - :bgcolor "#F8FCF8" - (column - (box :content "nowrap" :max-width (293) :padding (0 (10)) :border "#5E7F6A" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (293) :padding (0 (8)) :border "#5E7F6A" - :border-top-p nil - :bgcolor "#F8FCF8" :flex-wrap nowrap :column-gap (8) :align-items center - (item :flex-shrink 1 (box :content "A" :width (92) :height 1 :bgcolor "#DCEBDD" :text-align center)) - (item :flex-shrink 1 (box :content "B" :width (92) :height 1 :bgcolor "#BFD6C2" :text-align center)) - (item :flex-shrink 1 (box :content "C" :width (92) :height 1 :bgcolor "#8FAF95" :text-align center)))) - (column - (box :content "wrap" :max-width (293) :padding (0 (10)) :border "#5E7F6A" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (293) :padding (0 (8)) :border "#5E7F6A" - :border-top-p nil - :bgcolor "#F8FCF8" :flex-wrap wrap :column-gap (8) :row-gap 1 - (item :flex-shrink 0 (box :content "A 118" :width (118) :height 1 :bgcolor "#DCEBDD" :text-align center)) - (item :flex-shrink 0 (box :content "B 118" :width (118) :height 1 :bgcolor "#BFD6C2" :text-align center)) - (item :flex-shrink 0 (box :content "C 118" :width (118) :height 1 :bgcolor "#8FAF95" :text-align center)))) - (column - (box :content "wrap-reverse" :max-width (293) :padding (0 (10)) :border "#5E7F6A" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (293) :padding (0 (8)) :border "#5E7F6A" - :border-top-p nil - :bgcolor "#F8FCF8" :flex-wrap wrap-reverse :column-gap (8) :row-gap 1 - (item :flex-shrink 0 (box :content "A 118" :width (118) :height 1 :bgcolor "#DCEBDD" :text-align center)) - (item :flex-shrink 0 (box :content "B 118" :width (118) :height 1 :bgcolor "#BFD6C2" :text-align center)) - (item :flex-shrink 0 (box :content "C 118" :width (118) :height 1 :bgcolor "#8FAF95" :text-align center))))) - - (spacer :height 1) - - (box :content "Container property: :flex-flow\nShorthand for direction and wrapping. These examples use one property to set both behaviors." - :padding (0 (18)) :border "#6F6A95" - :bgcolor "#F7F4FC" :color "#2F2B45") - (flex :flex-flow (row wrap) :row-gap 1 :column-gap (12) :padding (0 (12)) - :border "#6F6A95" :border-top-p nil - :bgcolor "#FBF9FF" - (column - (box :content ":flex-flow (row wrap)" :max-width (440) :padding (0 (10)) - :border "#6F6A95" :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (440) :padding (0 (8)) :border "#6F6A95" - :border-top-p nil - :bgcolor "#FBF9FF" :flex-flow (row wrap) :gap (1 (12)) - (item (box :content "A" :width (170) :height 1 :bgcolor "#E4DEF4" :text-align center)) - (item (box :content "B" :width (170) :height 1 :bgcolor "#CBC2E3" :text-align center)) - (item (box :content "C wraps" :width (170) :height 1 :bgcolor "#AFA3D1" :text-align center)))) - (column - (box :content ":flex-flow (column wrap)" :max-width (440) :padding (0 (10)) - :border "#6F6A95" :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (440) :padding (0 (8)) :border "#6F6A95" - :border-top-p nil - :bgcolor "#FBF9FF" :flex-flow (column wrap) :gap (1 (12)) - (item (box :content "A" :width (140) :height 1 :bgcolor "#E4DEF4" :text-align center)) - (item (box :content "B" :width (140) :height 1 :bgcolor "#CBC2E3" :text-align center)) - (item (box :content "C new column" :width (140) :height 1 :bgcolor "#AFA3D1" :text-align center))))) - - (spacer :height 1) - - (box :content "Container property: :justify-content\nMain-axis packing after sizing. Distributed values change the space before, between, and after items." - :padding (0 (18)) :border "#3F6D88" - :bgcolor "#F1F8FB" :color "#20313A") - (flex :flex-flow (row wrap) :row-gap 1 :column-gap (12) :padding (0 (12)) - :border "#3F6D88" :border-top-p nil - :bgcolor "#F6FBFD" - (column - (box :content "flex-start" :width (146) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content flex-start - (item (box :content "A" :width (28) :height 1 :bgcolor "#CAE6F0" :text-align center)) - (item (box :content "B" :width (28) :height 1 :bgcolor "#A8D2E2" :text-align center)))) - (column - (box :content "center" :width (146) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content center - (item (box :content "A" :width (28) :height 1 :bgcolor "#CAE6F0" :text-align center)) - (item (box :content "B" :width (28) :height 1 :bgcolor "#A8D2E2" :text-align center)))) - (column - (box :content "flex-end" :width (146) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content flex-end - (item (box :content "A" :width (28) :height 1 :bgcolor "#CAE6F0" :text-align center)) - (item (box :content "B" :width (28) :height 1 :bgcolor "#A8D2E2" :text-align center)))) - (column - (box :content "space-between" :width (146) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content space-between - (item (box :content "A" :width (28) :height 1 :bgcolor "#CAE6F0" :text-align center)) - (item (box :content "B" :width (28) :height 1 :bgcolor "#A8D2E2" :text-align center)))) - (column - (box :content "space-around" :width (146) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content space-around - (item (box :content "A" :width (28) :height 1 :bgcolor "#CAE6F0" :text-align center)) - (item (box :content "B" :width (28) :height 1 :bgcolor "#A8D2E2" :text-align center)))) - (column - (box :content "space-evenly" :width (146) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content space-evenly - (item (box :content "A" :width (28) :height 1 :bgcolor "#CAE6F0" :text-align center)) - (item (box :content "B" :width (28) :height 1 :bgcolor "#A8D2E2" :text-align center)))) - (column - (box :content "start" :width (176) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content start - (item (box :content "start" :width (70) :height 1 :bgcolor "#CAE6F0" :text-align center)))) - (column - (box :content "end" :width (176) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content end - (item (box :content "end" :width (70) :height 1 :bgcolor "#A8D2E2" :text-align center)))) - (column - (box :content "left" :width (176) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content left - (item (box :content "left" :width (70) :height 1 :bgcolor "#7DB8CE" :text-align center)))) - (column - (box :content "right" :width (176) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content right - (item (box :content "right" :width (70) :height 1 :bgcolor "#5F9CB5" :text-align center)))) - (column - (box :content "normal" :width (176) :padding (0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :border "#3F6D88" :border-top-p nil :bgcolor "#F6FBFD" :justify-content normal - (item (box :content "normal" :width (70) :height 1 :bgcolor "#3F6D88" :color "#FFFFFF" :text-align center))))) - - (spacer :height 1) - - (box :content "Container property: :align-items\nCross-axis alignment inside each flex line. Stretch/normal enlarge auto-sized items; start/end/center move shorter ones." - :padding (0 (18)) :border "#9A6B43" - :bgcolor "#FFF7EE" :color "#3A2A1D") - (flex :flex-flow (row wrap) :row-gap 1 :column-gap (12) :padding (0 (12)) - :border "#9A6B43" :border-top-p nil - :bgcolor "#FFFAF5" - (column - (box :content "flex-start" :width (176) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 5 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items flex-start - (item (box :content "short" :width (68) :height 1 :bgcolor "#F1D0AF" :text-align center)) - (item (box :content "tall\nitem\nsets line" :width (78) :height 3 :bgcolor "#D9AD83" :text-align center)))) - (column - (box :content "center" :width (176) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 5 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items center - (item (box :content "short" :width (68) :height 1 :bgcolor "#F1D0AF" :text-align center)) - (item (box :content "tall\nitem\nsets line" :width (78) :height 3 :bgcolor "#D9AD83" :text-align center)))) - (column - (box :content "flex-end" :width (176) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 5 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items flex-end - (item (box :content "short" :width (68) :height 1 :bgcolor "#F1D0AF" :text-align center)) - (item (box :content "tall\nitem\nsets line" :width (78) :height 3 :bgcolor "#D9AD83" :text-align center)))) - (column - (box :content "stretch" :width (176) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 5 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items stretch - (item (box :content "auto height stretches" :width (72) :bgcolor "#F1D0AF" :text-align center)) - (item (box :content "line height" :width (78) :height 3 :bgcolor "#D9AD83" :text-align center)))) - (column - (box :content "baseline" :width (176) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 5 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items baseline - (item (box :content "baseline" :width (90) :height 1 :bgcolor "#BA8456" :text-align center)))) - (column - (box :content "start" :width (146) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :height 4 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items start - (item (box :content "start" :width (62) :height 1 :bgcolor "#F1D0AF" :text-align center)))) - (column - (box :content "end" :width (146) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :height 4 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items end - (item (box :content "end" :width (62) :height 1 :bgcolor "#D9AD83" :text-align center)))) - (column - (box :content "self-start" :width (146) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :height 4 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items self-start - (item (box :content "self-start" :width (78) :height 1 :bgcolor "#BA8456" :text-align center)))) - (column - (box :content "self-end" :width (146) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :height 4 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items self-end - (item (box :content "self-end" :width (70) :height 1 :bgcolor "#9A6B43" :color "#FFFFFF" :text-align center)))) - (column - (box :content "normal" :width (146) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (flex :width (146) :height 4 :border "#9A6B43" :border-top-p nil :bgcolor "#FFFAF5" :align-items normal - (item (box :content "normal" :width (62) :bgcolor "#7A5132" :color "#FFFFFF" :text-align center)))) - (column - (box :content "stretch note" :width (146) :padding (0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align center) - (box :content "normal behaves stretch-like for auto cross size in this DSL." :width (146) - :height 4 :padding (0 (8)) :border "#9A6B43" :border-top-p nil - :bgcolor "#FFFAF5" :color "#3A2A1D"))) - - (spacer :height 1) - - (box :content "Container property: :align-content\nCross-axis packing between multiple flex lines. It has no visible effect on a nowrap single-line container." - :padding (0 (18)) :border "#7C6A2F" - :bgcolor "#FBF8E8" :color "#362F16") - (flex :flex-flow (row wrap) :row-gap 1 :column-gap (12) :padding (0 (12)) - :border "#7C6A2F" :border-top-p nil - :bgcolor "#FFFDF0" - (column - (box :content "flex-start" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content flex-start :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "center" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content center :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "flex-end" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content flex-end :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "space-between" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content space-between :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "space-around" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content space-around :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "space-evenly" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content space-evenly :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "stretch" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content stretch :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "start" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content start :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "end" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content end :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "baseline" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content baseline :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "normal" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap wrap :align-content normal :row-gap 1 :column-gap (8) - (item (box :content "A" :width (78) :height 1 :bgcolor "#EEE1A8" :text-align center)) - (item (box :content "B" :width (78) :height 1 :bgcolor "#D9C46D" :text-align center)) - (item (box :content "C" :width (78) :height 1 :bgcolor "#B89B3D" :text-align center)))) - (column - (box :content "nowrap note" :width (176) :padding (0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align center) - (flex :width (176) :height 7 :border "#7C6A2F" :border-top-p nil :bgcolor "#FFFDF0" - :flex-wrap nowrap :align-content normal :row-gap 1 :column-gap (8) - (item (box :content "single line" :width (96) :height 1 :bgcolor "#EEE1A8" :text-align center))))) - - (spacer :height 1) - - (box :content "Container properties: :gap, :row-gap, :column-gap\n:gaps define spacing between flex items and flex lines. Explicit row/column values override matching sides." - :padding (0 (18)) :border "#3D7068" - :bgcolor "#F1FAF8" :color "#1D3935") - (flex :flex-flow (row wrap) :row-gap 1 :column-gap (12) :padding (0 (12)) - :border "#3D7068" :border-top-p nil - :bgcolor "#F7FCFB" - (column - (box :content ":gap (1 (14))" :max-width (293) :padding (0 (10)) :border "#3D7068" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (293) - :border "#3D7068" :border-top-p nil :bgcolor "#F7FCFB" - :flex-wrap wrap :gap (1 (14)) - (item (box :content "A" :width (104) :height 1 :bgcolor "#CDEBE5" :text-align center)) - (item (box :content "B" :width (104) :height 1 :bgcolor "#9FD5CB" :text-align center)) - (item (box :content "C" :width (104) :height 1 :bgcolor "#71BDB0" :text-align center)))) - (column - (box :content ":row-gap 2" :max-width (293) :padding (0 (10)) :border "#3D7068" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (293) :border "#3D7068" :border-top-p nil :bgcolor "#F7FCFB" - :flex-wrap wrap :row-gap 2 :column-gap (8) - (item (box :content "A" :width (104) :height 1 :bgcolor "#CDEBE5" :text-align center)) - (item (box :content "B" :width (104) :height 1 :bgcolor "#9FD5CB" :text-align center)) - (item (box :content "C" :width (104) :height 1 :bgcolor "#71BDB0" :text-align center)))) - (column - (box :content ":column-gap (32)" :max-width (293) :padding (0 (10)) :border "#3D7068" - :bgcolor "#FFFDF8" :color "#3D3A35" :text-align center) - (flex :max-width (293) :border "#3D7068" :border-top-p nil :bgcolor "#F7FCFB" - :flex-wrap wrap :row-gap 1 :column-gap (32) - (item (box :content "A" :width (104) :height 1 :bgcolor "#CDEBE5" :text-align center)) - (item (box :content "B" :width (104) :height 1 :bgcolor "#9FD5CB" :text-align center)) - (item (box :content "C" :width (104) :height 1 :bgcolor "#71BDB0" :text-align center))))) - - (spacer :height 1) - - (box :content "Item property: :order\nVisual ordering sorts by :order, then source order. The labels expose both values." - :padding (0 (18)) :border "#8E4A63" - :bgcolor "#FFF4F7" :color "#3A1F2A") - (flex :height 5 :padding (0 (12)) :border "#8E4A63" - :border-top-p nil - :bgcolor "#FFF8FA" :column-gap (12) :align-items center - (item :order 3 (box :content "source 1\n:order 3" :width (150) :height 2 :bgcolor "#F2C4D2" :text-align center)) - (item :order 1 (box :content "source 2\n:order 1" :width (150) :height 2 :bgcolor "#DEA4B7" :text-align center)) - (item :order 2 (box :content "source 3\n:order 2" :width (150) :height 2 :bgcolor "#C87F9A" :text-align center)) - (item :order 1 (box :content "source 4\nsame order" :width (150) :height 2 :bgcolor "#A95F7C" :color "#FFFFFF" :text-align center))) - - (spacer :height 1) - - (box :content "Item sizing: :flex-grow, :flex-shrink, :flex-basis, and child :width\nFlex starts from basis or width/content, then distributes positive or negative space." - :padding (0 (18)) :border "#2F5F7C" - :bgcolor "#F1F8FC" :color "#1C303D") - (column - (box :content "Grow factors: same basis, different growth weights." - :padding (0 (12)) :border "#2F5F7C" :border-top-p nil - :bgcolor "#FFFDF8" :color "#3D3A35") - (flex :padding (0 (12)) :border "#2F5F7C" - :border-top-p nil - :bgcolor "#F8FCFE" :column-gap (10) - (item :flex-grow 1 :flex-basis (120) (box :content "grow 1\nbasis 120" :height 2 :bgcolor "#C7E3F0" :text-align center)) - (item :flex-grow 2 :flex-basis (120) (box :content "grow 2\nbasis 120" :height 2 :bgcolor "#96C7DD" :text-align center)) - (item :flex-grow 3 :flex-basis (120) (box :content "grow 3\nbasis 120" :height 2 :bgcolor "#5FA4C2" :text-align center)))) - (column - (box :content "Shrink factors: overflowing bases lose space by weighted shrink." - :padding (0 (12)) :border "#2F5F7C" :border-top-p nil - :bgcolor "#FFFDF8" :color "#3D3A35") - (flex :padding (0 (12)) :border "#2F5F7C" - :border-top-p nil - :bgcolor "#F8FCFE" :column-gap (10) - (item :flex-shrink 1 :flex-basis (320) (box :content "shrink 1\nbasis 320" :height 2 :bgcolor "#C7E3F0" :text-align center)) - (item :flex-shrink 3 :flex-basis (320) (box :content "shrink 3\nbasis 320" :height 2 :bgcolor "#96C7DD" :text-align center)) - (item :flex-shrink 5 :flex-basis (320) (box :content "shrink 5\nbasis 320" :height 2 :bgcolor "#5FA4C2" :text-align center)))) - (column - (box :content "Basis versus width: explicit basis overrides width; auto basis uses width/content." - :padding (0 (12)) :border "#2F5F7C" :border-top-p nil - :bgcolor "#FFFDF8" :color "#3D3A35") - (flex :padding (0 (12)) :border "#2F5F7C" - :border-top-p nil - :bgcolor "#F8FCFE" :column-gap (10) - (item :flex-basis (120) (box :content "basis 120\nwidth 240" :width (240) :height 2 :bgcolor "#C7E3F0" :text-align center)) - (item :flex-basis auto (box :content "basis auto\nwidth 240" :width (240) :height 2 :bgcolor "#96C7DD" :text-align center)) - (item :flex (1 1 (160)) (box :content "flex tuple\nbasis 160" :width (240) :height 2 :bgcolor "#5FA4C2" :text-align center)))) - (column - (box :content "Intrinsic basis keywords: content, min-content, and max-content derive size from text." - :padding (0 (12)) :border "#2F5F7C" :border-top-p nil - :bgcolor "#FFFDF8" :color "#3D3A35") - (flex :padding (0 (12)) :border "#2F5F7C" - :border-top-p nil - :bgcolor "#F8FCFE" :flex-wrap wrap :row-gap 1 :column-gap (10) - (item :flex-shrink 0 :flex-basis content - (box :content "content\nnatural text" :width (180) :height 2 :bgcolor "#C7E3F0" :text-align center)) - (item :flex-shrink 0 :flex-basis min-content - (box :content "min-content\nwrap choices" :width (180) :height 2 :bgcolor "#96C7DD" :text-align center)) - (item :flex-shrink 0 :flex-basis max-content - (box :content "max-content\nkeeps phrase width" :width (180) :height 2 :bgcolor "#5FA4C2" :text-align center)))) - - (spacer :height 1) - - (box :content "Item property: :flex shorthand\nSupported forms: number, none, auto, initial, and (grow shrink basis). Longhands can override shorthand parts." - :padding (0 (18)) :border "#52612F" - :bgcolor "#F8FAEF" :color "#293116") - (flex :height 7 :padding (0 (12)) :border "#52612F" - :border-top-p nil - :bgcolor "#FCFDF6" :flex-wrap wrap :row-gap 1 :column-gap (8) :align-items center - (item :flex 1 (box :content ":flex 1\n= 1 1 0" :bgcolor "#DDE8B2" :text-align center)) - (item :flex none (box :content ":flex none\n= 0 0 auto" :width (140) :bgcolor "#C5D681" :text-align center)) - (item :flex auto (box :content ":flex auto\n= 1 1 auto" :width (140) :bgcolor "#AABE59" :text-align center)) - (item :flex initial (box :content ":flex initial\n= 0 1 auto" :width (140) :bgcolor "#8D9E3C" :text-align center)) - (item :flex (2 1 (120)) :flex-basis (160) - (box :content ":flex (2 1 120)\nthen basis 160" :bgcolor "#66762D" :color "#FFFFFF" :text-align center))) - - (spacer :height 1) - - (box :content "Item property: :align-self\nPer-item cross-axis override. auto inherits :align-items; other values replace the container setting." - :padding (0 (18)) :border "#7B4D38" - :bgcolor "#FFF6F0" :color "#392319") - (flex :height 7 :padding (0 (12)) :border "#7B4D38" - :border-top-p nil - :bgcolor "#FFFAF7" :align-items flex-start - :flex-wrap wrap :row-gap 1 :column-gap (10) - (item :align-self auto (box :content "auto\ninherits start" :width (118) :height 2 :bgcolor "#EFC7B6" :text-align center)) - (item :align-self flex-start (box :content "flex-start" :width (118) :height 2 :bgcolor "#DBA58D" :text-align center)) - (item :align-self center (box :content "center" :width (118) :height 2 :bgcolor "#BF7F63" :text-align center)) - (item :align-self flex-end (box :content "flex-end" :width (118) :height 2 :bgcolor "#9D6048" :color "#FFFFFF" :text-align center)) - (item :align-self stretch (box :content "stretch\nauto cross" :width (118) :bgcolor "#7B4D38" :color "#FFFFFF" :text-align center)) - (item :align-self normal (box :content "normal\nstretch-like" :width (118) :bgcolor "#5D3929" :color "#FFFFFF" :text-align center))) - (flex :height 6 :padding (0 (12)) :border "#7B4D38" - :border-top-p nil - :bgcolor "#FFFAF7" :align-items flex-start - :flex-wrap wrap :row-gap 1 :column-gap (10) - (item :align-self start (box :content "start" :width (118) :height 2 :bgcolor "#EFC7B6" :text-align center)) - (item :align-self end (box :content "end" :width (118) :height 2 :bgcolor "#DBA58D" :text-align center)) - (item :align-self self-start (box :content "self-start" :width (118) :height 2 :bgcolor "#BF7F63" :text-align center)) - (item :align-self self-end (box :content "self-end" :width (118) :height 2 :bgcolor "#9D6048" :color "#FFFFFF" :text-align center)) - (item :align-self baseline (box :content "baseline" :width (118) :height 2 :bgcolor "#7B4D38" :color "#FFFFFF" :text-align center))) - - (spacer :height 1) - - (box :content "Summary\nUse direction and wrap to create lines, basis/width to choose starting sizes, grow/shrink to distribute space, then justify/align properties to pack items and lines." - :padding (1 (24)) :border "#2F3437" - :bgcolor "#FAF7F0" :color "#1F2328" :text-align center)) diff --git a/examples/playground/responsive-reference.ebox b/examples/playground/responsive-reference.ebox deleted file mode 100644 index 5c58b1f..0000000 --- a/examples/playground/responsive-reference.ebox +++ /dev/null @@ -1,65 +0,0 @@ -(column - :margin-left 1 :margin-top 1 :padding (1 2 1 2) :bgcolor "linen" - (box :content "Ebox Responsive Layout\nDrag the preview window: sections stretch to the current viewport, cards reflow, and text wraps without changing the window layout." - :padding (1 (18)) :border "#334155" :text-align center - :color "#000" :bgcolor "ghost white") - (spacer :height 1) - - (box :content "No explicit viewport width here\nThis page mostly omits :width. The Playground binds the current preview width while rendering, so auto width behaves like a responsive container." - :padding (0 (16)) :border "#0F766E" - :bgcolor "#F0FDFA" :color "#134E4A" :wrap-mode word) - (spacer :height 1) - - (box :content "Adaptive toolbar\nButtons below keep stable sizes. The row packs as many as fit and then wraps." - :padding (0 (16)) :border "#EA580C" :border-bottom-p nil - :bgcolor "#FFF7ED" :color "#431407" :wrap-mode word) - (flex :flex-flow (row wrap) :column-gap (8) :row-gap 1 - :padding (1 (8)) :border "#FDBA74" :bgcolor "#FFFBF5" - (box :content "Render" :width (96) :padding (0 (8)) - :border "#EA580C" :bgcolor "#FED7AA" :color "#111827" - :text-align center) - (box :content "Save" :width (88) :padding (0 (8)) - :border "#D97706" :bgcolor "#FEF3C7" :color "#111827" - :text-align center) - (box :content "Format" :width (96) :padding (0 (8)) - :border "#16A34A" :bgcolor "#DCFCE7" :color "#14532D" - :text-align center) - (box :content "Sample" :width (104) :padding (0 (8)) - :border "#0284C7" :bgcolor "#E0F2FE" :color "#0C4A6E" - :text-align center) - (box :content "Write" :width (88) :padding (0 (8)) - :border "#9333EA" :bgcolor "#F3E8FF" :color "#3B0764" - :text-align center)) - (spacer :height 1) - - (box :content "Responsive cards\nEach card starts from a flex-basis, grows when space is available, and wraps to new rows when the preview becomes narrow." - :padding (0 (16)) :border "#2563EB" :border-bottom-p nil - :bgcolor "#EFF6FF" :color "#1E3A8A" :wrap-mode word) - (flex :flex-flow (row wrap) :column-gap (12) :row-gap 1 - :padding (1 (8)) :border "#93C5FD" :bgcolor "#F8FBFF" - :justify-content center - (item :flex (1 1 (210)) - (box :content "Overview\nThe row uses the current preview width automatically." - :min-width (180) :max-width (280) - :padding (0 (10)) ;; :border "#2563EB" - :bgcolor "#DBEAFE" :color "#111827" :wrap-mode word)) - (item :flex (1 1 (210)) - (box :content "Editor\nDrag slowly or quickly; resize rendering is debounced." - :min-width (180) :max-width (300) - :padding (0 (10)) ;; :border "#4F46E5" - :bgcolor "#E0E7FF" :color "#111827" :wrap-mode word)) - (item :flex (1 1 (210)) - (box :content "Preview\nThe preview buffer rerenders after the viewport settles." - :min-width (180) :max-width (320) - :padding (0 (10)) ;; :border "#7C3AED" - :bgcolor "#EDE9FE" :color "#111827" :wrap-mode word)) - (item :flex (1 1 (210)) - (box :content "Flow\nCards keep readable widths instead of overflowing." - :min-width (180) :max-width (280) - :padding (0 (10)) ;; :border "#0891B2" - :bgcolor "#CFFAFE" :color "#164E63" :wrap-mode word))) - (spacer :height 1) - - (box :content "What to watch\nNarrow preview: cards stack and text wraps. Wide preview: cards share a row and expand up to max-width. The source/preview split is preserved." - :padding (0 (16)) :border "#475569" - :bgcolor "#F8FAFC" :color "#0F172A" :wrap-mode word)) diff --git a/tests/ebox-ci-contract-tests.el b/tests/ebox-ci-contract-tests.el index 3123dfd..3b128e7 100644 --- a/tests/ebox-ci-contract-tests.el +++ b/tests/ebox-ci-contract-tests.el @@ -17,7 +17,7 @@ (let ((source (ebox-ci-test--read "Makefile"))) (dolist (target '("check:" "ci:" "load:" "compile:" "test:" "core-tests:" "grid-tests:" "ebox-commit-tests:" - "examples-tests:" "docs-contract-tests:" + "docs-contract-tests:" "ci-contract-tests:" "native-rust-tests:" "native-build:" "diff-check:")) (should (string-match-p (concat "^" (regexp-quote target)) source))) diff --git a/tests/ebox-docs-contract-tests.el b/tests/ebox-docs-contract-tests.el index 7d7cd83..7866cdf 100644 --- a/tests/ebox-docs-contract-tests.el +++ b/tests/ebox-docs-contract-tests.el @@ -22,13 +22,8 @@ "ebox-layout.el" "ebox-flex.el" "ebox-grid.el" "ebox-buffer-backend.el" "ebox-incremental.el" "ebox-dsl.el" "ebox-selector.el" "ebox-native-reflow.el" - "examples/ebox-basic-examples.el" - "examples/playground/basic.ebox" - "examples/playground/comprehensive.ebox" - "examples/playground/flex-reference.ebox" - "examples/playground/responsive-reference.ebox" "tests/ebox-core-render-tests.el" "tests/ebox-grid-tests.el" - "tests/ebox-commit-tests.el" "tests/ebox-examples-tests.el" + "tests/ebox-commit-tests.el" "tests/ebox-dsl-tests.el" "tests/ebox-flex-tests.el" "tests/ebox-selector-tests.el" "tests/ebox-package-tests.el" "tests/ebox-visual-check-tests.el" "tests/ebox-docs-contract-tests.el" @@ -42,7 +37,7 @@ (defconst ebox-docs-test--targets '("check" "ci" "load" "compile" "core-tests" "grid-tests" "ebox-commit-tests" "visual-check-tests" "package-tests" - "selector-tests" "examples-tests" "dsl-tests" "flex-tests" + "selector-tests" "dsl-tests" "flex-tests" "docs-contract-tests" "ci-contract-tests" "visual-check" "native-rust-tests" "native-build" "package-lint" "diff-check") "Make targets that must be documented and executable.") diff --git a/tests/ebox-dsl-tests.el b/tests/ebox-dsl-tests.el index e76e6a7..d62869e 100644 --- a/tests/ebox-dsl-tests.el +++ b/tests/ebox-dsl-tests.el @@ -90,6 +90,21 @@ :overflow scroll)))) (should (= (length (ebox-string-lines (ebox-render node))) 4)))) +(ert-deftest ebox-build-unquotes-static-list-property-values () + "The DSL should accept quoted list values used by `etaf-view' forms." + (let* ((node (ebox-build + '(grid :width '(120) + :grid-template-columns '((40) 1fr) + :gap '(0 (4)) + (box :content "A") + (box :content "B")))) + (props (plist-get node :raw-props)) + (line (car (ebox-string-lines (ebox-render node))))) + (should (equal (plist-get props :width) '(120))) + (should (equal (plist-get props :grid-template-columns) + '((40) 1fr))) + (should (= (ebox--string-pixel-width line) 120)))) + (ert-deftest ebox-build-composes-fixed-viewport-shell-around-scrollbox () "A fixed viewport shell can reserve chrome while an inner box scrolls." (let* ((ebox-viewport-height 6) diff --git a/tests/ebox-examples-tests.el b/tests/ebox-examples-tests.el deleted file mode 100644 index 709797a..0000000 --- a/tests/ebox-examples-tests.el +++ /dev/null @@ -1,32 +0,0 @@ -;;; ebox-examples-tests.el --- Ebox example contracts -*- lexical-binding: t; -*- - -(require 'ert) -(require 'ebox) -(defconst ebox-examples-test--root - (expand-file-name ".." (file-name-directory (or load-file-name buffer-file-name))) - "Repository root used by example tests.") -(load-file (expand-file-name "examples/ebox-basic-examples.el" - ebox-examples-test--root)) - -(ert-deftest ebox-basic-example-builds-a-public-tree () - "The basic example should build through public constructors." - (let ((node (ebox-basic-examples-build))) - (should (listp node)) - (should (string-match-p "Ebox" - (substring-no-properties (ebox-render node)))))) - -(ert-deftest ebox-dsl-examples-render-without-playground-code () - "The maintained DSL fixtures should render through the Ebox facade." - (dolist (file '("basic.ebox" "comprehensive.ebox" "flex-reference.ebox" - "responsive-reference.ebox")) - (let ((form - (with-temp-buffer - (insert-file-contents - (expand-file-name (concat "examples/playground/" file) - ebox-examples-test--root)) - (read (current-buffer))))) - (should (stringp (ebox-render (ebox-build form))))))) - -(provide 'ebox-examples-tests) - -;;; ebox-examples-tests.el ends here