fix: keep playground references readable

Bind standalone fixture renders to the compact playground viewport, paint reference spacers across the canvas, and give every tinted content box explicit high-contrast ink. Add regression coverage for width, painted separators, and fixture color contracts.
This commit is contained in:
Kinneyzhang 2026-08-05 21:40:32 +08:00
parent 9af3dc9e5f
commit e55a1128bb
8 changed files with 274 additions and 197 deletions

View File

@ -4,6 +4,8 @@
The gallery owns one definite 720 px canvas so its nested Grid examples cannot each reinterpret the surrounding viewport width. It fits a compact GUI Emacs window with at least 760 px of body width. `etaf-playground` remains the separate higher-level Component and Runtime showcase.
Standalone fixture renders use the same compact 720 px default viewport unless the caller dynamically binds `ebox-viewport-width`; viewport-based references therefore stay inside the example canvas.
```elisp
(require 'ebox-playground)
(ebox-playground-open)

View File

@ -4,6 +4,8 @@
画廊统一拥有一个明确的 720 px 画布,因此嵌套 Grid 不会各自重新解释外层视口宽度。只要 GUI Emacs 的正文区域不小于 760 px它就能完整显示。高层 Component/Runtime 展示仍由独立的 `etaf-playground` 提供。
独立 fixture 渲染默认也使用紧凑的 720 px 视口;如果调用方动态绑定了 `ebox-viewport-width`,则保留调用方的值。因此依赖 viewport 的参考例子也会保持在示例画布内。
```elisp
(require 'ebox-playground)
(ebox-playground-open)

View File

@ -51,13 +51,15 @@
(defun ebox-dsl-render ()
"Render the current Ebox DSL buffer into a preview buffer."
(interactive)
(let* ((source (ebox-playground--source-form))
(name (format "*Ebox Preview: %s*"
(or (buffer-file-name) (buffer-name))))
(node (ebox-build source)))
(ebox-display-buffer name node)
(message "Rendered Ebox DSL into %s" name)
(get-buffer name)))
(let ((ebox-viewport-width
(ebox-playground--effective-viewport-width)))
(let* ((source (ebox-playground--source-form))
(name (format "*Ebox Preview: %s*"
(or (buffer-file-name) (buffer-name))))
(node (ebox-build source)))
(ebox-display-buffer name node)
(message "Rendered Ebox DSL into %s" name)
(get-buffer name))))
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.ebox\\'" . ebox-dsl-mode))
@ -77,6 +79,24 @@
:type 'file
:group 'ebox-playground)
(defcustom ebox-playground-default-viewport-width 720
"Viewport width used when a caller does not provide one explicitly."
:type 'positive-integer
:group 'ebox-playground)
(defun ebox-playground--effective-viewport-width ()
"Return the caller's viewport width or the compact playground default."
(if (and (numberp ebox-viewport-width)
(> ebox-viewport-width 0))
(floor ebox-viewport-width)
ebox-playground-default-viewport-width))
(defun ebox-playground--render-node-to-buffer (buffer node)
"Render NODE into BUFFER using the effective playground viewport width."
(let ((ebox-viewport-width
(ebox-playground--effective-viewport-width)))
(ebox-render-to-buffer buffer node)))
(defun ebox-playground--static-value-p (value)
"Return non-nil when VALUE is a literal or explicitly quoted form."
(or (null value) (numberp value) (stringp value) (characterp value)
@ -138,23 +158,26 @@
;;;###autoload
(defun ebox-playground-view (&optional file)
"Build the Ebox DSL form in FILE without buffer side effects."
(ebox-build
(ebox-playground--evaluate-form
(ebox-playground--read-file
(expand-file-name (or file ebox-playground-default-file))))))
(let ((ebox-viewport-width
(ebox-playground--effective-viewport-width)))
(ebox-build
(ebox-playground--evaluate-form
(ebox-playground--read-file
(expand-file-name (or file ebox-playground-default-file)))))))
;;;###autoload
(defun ebox-playground-open (&optional buffer-name)
"Render the default Ebox DSL example into BUFFER-NAME and return its buffer."
(interactive)
(ebox-render-to-buffer (or buffer-name ebox-playground-buffer-name)
(ebox-playground-view)))
(ebox-playground--render-node-to-buffer
(or buffer-name ebox-playground-buffer-name)
(ebox-playground-view)))
;;;###autoload
(defun ebox-playground-open-file (file &optional buffer-name)
"Render Ebox DSL FILE into BUFFER-NAME and return its buffer."
(interactive "fEbox DSL file: ")
(ebox-render-to-buffer
(ebox-playground--render-node-to-buffer
(or buffer-name
(format "*Ebox Preview: %s*" (file-name-nondirectory file)))
(ebox-playground-view file)))

View File

@ -3,13 +3,13 @@
:padding '(1 (16)) :border "#334155"
:bgcolor "#F8FAFC" :color "#0F172A" :text-align 'center)
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#F8FAFC")
(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)
(spacer :width '(viewport) :height 1 :bgcolor "#F8FAFC")
(flex
:margin '(1 0 0 1) :padding '(1 (8))

View File

@ -4,7 +4,7 @@
:padding '(1 (24)) :border "#2F3437"
:bgcolor "#FAF7F0" :color "#1F2328" :text-align 'center)
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -18,38 +18,38 @@
(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))))
(item (box :content "A" :width '(42) :height 1 :bgcolor "#F7C8B3" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(42) :height 1 :bgcolor "#F0A88F" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(42) :height 1 :bgcolor "#D97757" :color "#1F2328" :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))))
(item (box :content "A" :width '(42) :height 1 :bgcolor "#F7C8B3" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(42) :height 1 :bgcolor "#F0A88F" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(42) :height 1 :bgcolor "#D97757" :color "#1F2328" :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))))
(item (box :content "A" :height 1 :bgcolor "#F7C8B3" :color "#1F2328" :text-align 'center))
(item (box :content "B" :height 1 :bgcolor "#F0A88F" :color "#1F2328" :text-align 'center))
(item (box :content "C" :height 1 :bgcolor "#D97757" :color "#1F2328" :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)))))
(item (box :content "A" :height 1 :bgcolor "#F7C8B3" :color "#1F2328" :text-align 'center))
(item (box :content "B" :height 1 :bgcolor "#F0A88F" :color "#1F2328" :text-align 'center))
(item (box :content "C" :height 1 :bgcolor "#D97757" :color "#1F2328" :text-align 'center)))))
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -63,29 +63,29 @@
(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))))
(item :flex-shrink 1 (box :content "A" :width '(92) :height 1 :bgcolor "#DCEBDD" :color "#1F2328" :text-align 'center))
(item :flex-shrink 1 (box :content "B" :width '(92) :height 1 :bgcolor "#BFD6C2" :color "#1F2328" :text-align 'center))
(item :flex-shrink 1 (box :content "C" :width '(92) :height 1 :bgcolor "#8FAF95" :color "#1F2328" :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))))
(item :flex-shrink 0 (box :content "A 118" :width '(118) :height 1 :bgcolor "#DCEBDD" :color "#1F2328" :text-align 'center))
(item :flex-shrink 0 (box :content "B 118" :width '(118) :height 1 :bgcolor "#BFD6C2" :color "#1F2328" :text-align 'center))
(item :flex-shrink 0 (box :content "C 118" :width '(118) :height 1 :bgcolor "#8FAF95" :color "#1F2328" :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)))))
(item :flex-shrink 0 (box :content "A 118" :width '(118) :height 1 :bgcolor "#DCEBDD" :color "#1F2328" :text-align 'center))
(item :flex-shrink 0 (box :content "B 118" :width '(118) :height 1 :bgcolor "#BFD6C2" :color "#1F2328" :text-align 'center))
(item :flex-shrink 0 (box :content "C 118" :width '(118) :height 1 :bgcolor "#8FAF95" :color "#1F2328" :text-align 'center)))))
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -99,20 +99,20 @@
(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))))
(item (box :content "A" :width '(170) :height 1 :bgcolor "#E4DEF4" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(170) :height 1 :bgcolor "#CBC2E3" :color "#1F2328" :text-align 'center))
(item (box :content "C wraps" :width '(170) :height 1 :bgcolor "#AFA3D1" :color "#1F2328" :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)))))
(item (box :content "A" :width '(140) :height 1 :bgcolor "#E4DEF4" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(140) :height 1 :bgcolor "#CBC2E3" :color "#1F2328" :text-align 'center))
(item (box :content "C new column" :width '(140) :height 1 :bgcolor "#AFA3D1" :color "#1F2328" :text-align 'center)))))
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -121,57 +121,57 @@
: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)
(box :content "flex-start" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(28) :height 1 :bgcolor "#CAE6F0" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(28) :height 1 :bgcolor "#A8D2E2" :color "#1F2328" :text-align 'center))))
(column
(box :content "center" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "center" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(28) :height 1 :bgcolor "#CAE6F0" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(28) :height 1 :bgcolor "#A8D2E2" :color "#1F2328" :text-align 'center))))
(column
(box :content "flex-end" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "flex-end" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(28) :height 1 :bgcolor "#CAE6F0" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(28) :height 1 :bgcolor "#A8D2E2" :color "#1F2328" :text-align 'center))))
(column
(box :content "space-between" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "space-between" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(28) :height 1 :bgcolor "#CAE6F0" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(28) :height 1 :bgcolor "#A8D2E2" :color "#1F2328" :text-align 'center))))
(column
(box :content "space-around" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "space-around" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(28) :height 1 :bgcolor "#CAE6F0" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(28) :height 1 :bgcolor "#A8D2E2" :color "#1F2328" :text-align 'center))))
(column
(box :content "space-evenly" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "space-evenly" :width '(146) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(28) :height 1 :bgcolor "#CAE6F0" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(28) :height 1 :bgcolor "#A8D2E2" :color "#1F2328" :text-align 'center))))
(column
(box :content "start" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "start" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "start" :width '(70) :height 1 :bgcolor "#CAE6F0" :color "#1F2328" :text-align 'center))))
(column
(box :content "end" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "end" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "end" :width '(70) :height 1 :bgcolor "#A8D2E2" :color "#1F2328" :text-align 'center))))
(column
(box :content "left" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "left" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "left" :width '(70) :height 1 :bgcolor "#7DB8CE" :color "#1F2328" :text-align 'center))))
(column
(box :content "right" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "right" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "right" :width '(70) :height 1 :bgcolor "#5F9CB5" :color "#1F2328" :text-align 'center))))
(column
(box :content "normal" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "normal" :width '(176) :padding '(0 (4)) :border "#3F6D88" :bgcolor "#FFFDF8" :color "#1F2328" :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)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -180,56 +180,56 @@
: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)
(box :content "flex-start" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "short" :width '(68) :height 1 :bgcolor "#F1D0AF" :color "#1F2328" :text-align 'center))
(item (box :content "tall\nitem\nsets line" :width '(78) :height 3 :bgcolor "#D9AD83" :color "#1F2328" :text-align 'center))))
(column
(box :content "center" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "center" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "short" :width '(68) :height 1 :bgcolor "#F1D0AF" :color "#1F2328" :text-align 'center))
(item (box :content "tall\nitem\nsets line" :width '(78) :height 3 :bgcolor "#D9AD83" :color "#1F2328" :text-align 'center))))
(column
(box :content "flex-end" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "flex-end" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "short" :width '(68) :height 1 :bgcolor "#F1D0AF" :color "#1F2328" :text-align 'center))
(item (box :content "tall\nitem\nsets line" :width '(78) :height 3 :bgcolor "#D9AD83" :color "#1F2328" :text-align 'center))))
(column
(box :content "stretch" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "stretch" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "auto height stretches" :width '(72) :bgcolor "#F1D0AF" :color "#1F2328" :text-align 'center))
(item (box :content "line height" :width '(78) :height 3 :bgcolor "#D9AD83" :color "#1F2328" :text-align 'center))))
(column
(box :content "baseline" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "baseline" :width '(176) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "baseline" :width '(90) :height 1 :bgcolor "#BA8456" :color "#1F2328" :text-align 'center))))
(column
(box :content "start" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "start" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "start" :width '(62) :height 1 :bgcolor "#F1D0AF" :color "#1F2328" :text-align 'center))))
(column
(box :content "end" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "end" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "end" :width '(62) :height 1 :bgcolor "#D9AD83" :color "#1F2328" :text-align 'center))))
(column
(box :content "self-start" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "self-start" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "self-start" :width '(78) :height 1 :bgcolor "#BA8456" :color "#1F2328" :text-align 'center))))
(column
(box :content "self-end" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "self-end" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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)
(box :content "normal" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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 "stretch note" :width '(146) :padding '(0 (4)) :border "#9A6B43" :bgcolor "#FFFDF8" :color "#1F2328" :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)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -238,89 +238,89 @@
: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)
(box :content "flex-start" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "center" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "center" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "flex-end" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "flex-end" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "space-between" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "space-between" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "space-around" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "space-around" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "space-evenly" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "space-evenly" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "stretch" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "stretch" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "start" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "start" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "end" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "end" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "baseline" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "baseline" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "normal" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "normal" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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))))
(item (box :content "A" :width '(78) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(78) :height 1 :bgcolor "#D9C46D" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(78) :height 1 :bgcolor "#B89B3D" :color "#1F2328" :text-align 'center))))
(column
(box :content "nowrap note" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :text-align 'center)
(box :content "nowrap note" :width '(176) :padding '(0 (4)) :border "#7C6A2F" :bgcolor "#FFFDF8" :color "#1F2328" :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)))))
(item (box :content "single line" :width '(96) :height 1 :bgcolor "#EEE1A8" :color "#1F2328" :text-align 'center)))))
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -334,27 +334,27 @@
(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))))
(item (box :content "A" :width '(104) :height 1 :bgcolor "#CDEBE5" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(104) :height 1 :bgcolor "#9FD5CB" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(104) :height 1 :bgcolor "#71BDB0" :color "#1F2328" :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))))
(item (box :content "A" :width '(104) :height 1 :bgcolor "#CDEBE5" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(104) :height 1 :bgcolor "#9FD5CB" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(104) :height 1 :bgcolor "#71BDB0" :color "#1F2328" :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)))))
(item (box :content "A" :width '(104) :height 1 :bgcolor "#CDEBE5" :color "#1F2328" :text-align 'center))
(item (box :content "B" :width '(104) :height 1 :bgcolor "#9FD5CB" :color "#1F2328" :text-align 'center))
(item (box :content "C" :width '(104) :height 1 :bgcolor "#71BDB0" :color "#1F2328" :text-align 'center)))))
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(box :content "Item property: :order\nVisual ordering sorts by :order, then source order. The labels expose both values."
:padding '(0 (18)) :border "#8E4A63"
@ -362,12 +362,12 @@
(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 3 (box :content "source 1\n:order 3" :width '(150) :height 2 :bgcolor "#F2C4D2" :color "#1F2328" :text-align 'center))
(item :order 1 (box :content "source 2\n:order 1" :width '(150) :height 2 :bgcolor "#DEA4B7" :color "#1F2328" :text-align 'center))
(item :order 2 (box :content "source 3\n:order 2" :width '(150) :height 2 :bgcolor "#C87F9A" :color "#1F2328" :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)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -379,9 +379,9 @@
(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))))
(item :flex-grow 1 :flex-basis '(120) (box :content "grow 1\nbasis 120" :height 2 :bgcolor "#C7E3F0" :color "#1F2328" :text-align 'center))
(item :flex-grow 2 :flex-basis '(120) (box :content "grow 2\nbasis 120" :height 2 :bgcolor "#96C7DD" :color "#1F2328" :text-align 'center))
(item :flex-grow 3 :flex-basis '(120) (box :content "grow 3\nbasis 120" :height 2 :bgcolor "#5FA4C2" :color "#1F2328" :text-align 'center))))
(column
(box :content "Shrink factors: overflowing bases lose space by weighted shrink."
:padding '(0 (12)) :border "#2F5F7C" :border-top-p nil
@ -389,9 +389,9 @@
(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))))
(item :flex-shrink 1 :flex-basis '(320) (box :content "shrink 1\nbasis 320" :height 2 :bgcolor "#C7E3F0" :color "#1F2328" :text-align 'center))
(item :flex-shrink 3 :flex-basis '(320) (box :content "shrink 3\nbasis 320" :height 2 :bgcolor "#96C7DD" :color "#1F2328" :text-align 'center))
(item :flex-shrink 5 :flex-basis '(320) (box :content "shrink 5\nbasis 320" :height 2 :bgcolor "#5FA4C2" :color "#1F2328" :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
@ -399,9 +399,9 @@
(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))))
(item :flex-basis '(120) (box :content "basis 120\nwidth 240" :width '(240) :height 2 :bgcolor "#C7E3F0" :color "#1F2328" :text-align 'center))
(item :flex-basis 'auto (box :content "basis auto\nwidth 240" :width '(240) :height 2 :bgcolor "#96C7DD" :color "#1F2328" :text-align 'center))
(item :flex '(1 1 (160)) (box :content "flex tuple\nbasis 160" :width '(240) :height 2 :bgcolor "#5FA4C2" :color "#1F2328" :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
@ -410,13 +410,13 @@
: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))
(box :content "content\nnatural text" :width '(180) :height 2 :bgcolor "#C7E3F0" :color "#1F2328" :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))
(box :content "min-content\nwrap choices" :width '(180) :height 2 :bgcolor "#96C7DD" :color "#1F2328" :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))))
(box :content "max-content\nkeeps phrase width" :width '(180) :height 2 :bgcolor "#5FA4C2" :color "#1F2328" :text-align 'center))))
(spacer :height 1)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -424,14 +424,14 @@
(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 1 (box :content ":flex 1\n= 1 1 0" :bgcolor "#DDE8B2" :color "#1F2328" :text-align 'center))
(item :flex 'none (box :content ":flex none\n= 0 0 auto" :width '(140) :bgcolor "#C5D681" :color "#1F2328" :text-align 'center))
(item :flex 'auto (box :content ":flex auto\n= 1 1 auto" :width '(140) :bgcolor "#AABE59" :color "#1F2328" :text-align 'center))
(item :flex 'initial (box :content ":flex initial\n= 0 1 auto" :width '(140) :bgcolor "#8D9E3C" :color "#1F2328" :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)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"
@ -440,9 +440,9 @@
: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 'auto (box :content "auto\ninherits start" :width '(118) :height 2 :bgcolor "#EFC7B6" :color "#1F2328" :text-align 'center))
(item :align-self 'flex-start (box :content "flex-start" :width '(118) :height 2 :bgcolor "#DBA58D" :color "#1F2328" :text-align 'center))
(item :align-self 'center (box :content "center" :width '(118) :height 2 :bgcolor "#BF7F63" :color "#1F2328" :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)))
@ -450,13 +450,13 @@
: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 'start (box :content "start" :width '(118) :height 2 :bgcolor "#EFC7B6" :color "#1F2328" :text-align 'center))
(item :align-self 'end (box :content "end" :width '(118) :height 2 :bgcolor "#DBA58D" :color "#1F2328" :text-align 'center))
(item :align-self 'self-start (box :content "self-start" :width '(118) :height 2 :bgcolor "#BF7F63" :color "#1F2328" :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)
(spacer :width '(viewport) :height 1 :bgcolor "#FAF7F0")
(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"

View File

@ -7,7 +7,7 @@
:bgcolor "#FFFDF8"
:face 'bold
:text-align 'center)
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "01 TRACK SIZING\nFixed pixels, intrinsic auto tracks, and fractional space share one definite canvas."
:width '(720)
@ -41,7 +41,7 @@
:color "#28485B"
:bgcolor "#D9EAF2"
:text-align 'center))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "02 TRACK FUNCTIONS\n`minmax` protects a readable minimum while `repeat` expands a compact template."
:width '(720)
@ -91,7 +91,7 @@
:color "#26402F"
:bgcolor "#D4E6D7"
:text-align 'center))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "03 IMPLICIT TRACKS + AUTO-FLOW\nDeclared tracks establish the map; auto rows, auto columns, and flow fill the rest."
:width '(720)
@ -124,7 +124,7 @@
(box :content "AUTO ROW 2 / A" :padding '(0 (8)) :color "#203A4A" :bgcolor "#E5F2F7" :text-align 'center)
(box :content "AUTO ROW 2 / B" :padding '(0 (8)) :color "#203A4A" :bgcolor "#D7EAF1" :text-align 'center)
(box :content "AUTO ROW 2 / C" :padding '(0 (8)) :color "#203A4A" :bgcolor "#C8E1EB" :text-align 'center))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "COLUMN FLOW · :grid-auto-columns ((220))"
:width '(720)
:padding '(0 (12))
@ -147,7 +147,7 @@
(box :content "COL 1 / ROW 2" :padding '(0 (8)) :color "#203A4A" :bgcolor "#C3DFEA" :text-align 'center)
(box :content "AUTO COL 2 / ROW 1" :padding '(0 (8)) :color "#203A4A" :bgcolor "#A9D0DE" :text-align 'center)
(box :content "AUTO COL 2 / ROW 2" :padding '(0 (8)) :color "#203A4A" :bgcolor "#E5F2F7" :text-align 'center))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "04 PLACEMENT + SPANS\nGrid items can target one-based rows and columns, span tracks, or fall back to auto-placement."
:width '(720)
@ -183,7 +183,7 @@
:padding '(0 (8)) :color "#332B4B" :bgcolor "#AFA3D1" :text-align 'center))
(box :content "AUTO\nREMAINDER"
:padding '(0 (8)) :color "#332B4B" :bgcolor "#EDE9F6" :text-align 'center))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "05 ITEM ALIGNMENT\n`:justify-items` controls the inline axis; `:align-items` controls the block axis inside each cell."
:width '(720)
@ -226,7 +226,7 @@
(box :content "END" :padding '(0 (8)) :color "#513718" :bgcolor "#F3E4C7" :text-align 'center)
(box :content "INLINE END" :padding '(0 (8)) :color "#513718" :bgcolor "#EAD2A6" :text-align 'center)
(box :content "BLOCK STRETCH" :padding '(0 (8)) :color "#513718" :bgcolor "#E1C18A" :text-align 'center))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "06 CONTENT ALIGNMENT\nWhen tracks do not consume the full canvas, `:justify-content` and `:align-content` distribute the leftover space."
:width '(720)
@ -277,7 +277,7 @@
(box :content "EVEN" :padding '(0 (8)) :color "#1E4148" :bgcolor "#B5DDE0" :text-align 'center)
(box :content "LY" :padding '(0 (8)) :color "#1E4148" :bgcolor "#9ACED2" :text-align 'center)
(box :content "TRACKS" :padding '(0 (8)) :color "#1E4148" :bgcolor "#DDF1F2" :text-align 'center))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "GRID TOOLKIT :grid-template-columns · :grid-template-rows · :grid-auto-columns · :grid-auto-rows · :grid-auto-flow · :gap · :grid-row-gap · :grid-column-gap · :justify-items · :align-items · :justify-content · :align-content · :grid-column · :grid-row · :grid-column-span · :grid-row-span"
:width '(720)

View File

@ -7,7 +7,7 @@
:bgcolor "#FFFDF8"
:face 'bold
:text-align 'center)
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "01 FIXED + FRACTIONAL\nA definite Grid width divides into one exact track and one flexible track."
:width '(720)
:padding '(0 (16))
@ -32,7 +32,7 @@
:grid-column '(1 :span 2) :width '(718) :padding '(1 0)
:color "#663322" :bgcolor "#FFFDF8"
:text-align 'center :wrap-mode 'word))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "02 EXPLICIT PLACEMENT\nSpan columns, target cells, and leave the remaining nodes to auto placement."
:width '(720)
:padding '(0 (16))
@ -60,7 +60,7 @@
:text-align 'center :color "#24422D" :bgcolor "#E3F0E5")
(box :content "STABLE CELLS" :width '(278) :padding '(1 0)
:text-align 'center :color "#24422D" :bgcolor "#D4E6D7"))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "03 PUBLIC COMPOSITION\nColumn, Flex, and Grid share the same public node contract."
:width '(720)
:padding '(0 (16))
@ -88,7 +88,7 @@
:flex-grow 1 :flex-shrink 1 :flex-basis '(200)
:min-width '(180) :padding '(1 (12))
:color "#6B3020" :bgcolor "#F1D4C9"))
(spacer :height 1)
(spacer :width '(720) :height 1 :bgcolor "#FAF7F0")
(box :content "PUBLIC CONTRACT ebox-create · ebox-column · ebox-flex · ebox-grid · ebox-spacer"
:width '(720)
:padding '(0 (16))

View File

@ -17,6 +17,26 @@
"Return a color from executable DSL property code."
"#123456")
(defun ebox-playground-test--boxes (form)
"Return every nested BOX form in FORM."
(when (consp form)
(append (when (eq (car form) 'box)
(list form))
(cl-mapcan #'ebox-playground-test--boxes form))))
(ert-deftest ebox-playground-tinted-content-has-explicit-ink ()
"Every tinted content box in the public fixtures should set its text color."
(dolist (file (append ebox-playground-test--fixtures
'("public-layout-gallery.ebox")))
(let ((form (ebox-playground--read-file
(expand-file-name (concat "examples/" file)
ebox-playground-directory))))
(dolist (box (ebox-playground-test--boxes form))
(let ((properties (cdr box)))
(when (and (memq :content properties)
(memq :bgcolor properties))
(should (memq :color properties))))))))
(ert-deftest ebox-playground-uses-only-public-layout-apis ()
"The example should build and render through the public Ebox entry point."
(let* ((node (ebox-playground-view))
@ -53,6 +73,36 @@
(should (stringp text))
(should (cl-every (lambda (width) (<= width 720)) widths))))))
(ert-deftest ebox-playground-flex-reference-uses-a-compact-default-viewport ()
"The public Flex file entry point should use the compact default viewport."
(let ((path (expand-file-name "examples/flex-reference.ebox"
ebox-playground-directory))
(name " *ebox-playground-flex-viewport-test*"))
(unwind-protect
(progn
(ebox-playground-open-file path name)
(with-current-buffer name
(let ((widths (mapcar #'ebox-string-pixel-width
(ebox-string-lines (buffer-string)))))
(should (cl-every (lambda (width) (<= width 720)) widths)))))
(ebox-playground-close name))))
(ert-deftest ebox-playground-fixed-reference-spacers-paint-the-canvas ()
"Fixed-width reference separators should keep a continuous canvas surface."
(dolist (file '("grid-reference.ebox" "public-layout-gallery.ebox"))
(let* ((path (expand-file-name (concat "examples/" file)
ebox-playground-directory))
(lines (ebox-string-lines
(ebox-render (ebox-playground-view path))))
(separators 0))
(dolist (line lines)
(when (equal (get-text-property 0 'display line)
'(space :width (720)))
(setq separators (1+ separators))
(should (equal (get-text-property 0 'face line)
'(:background "#FAF7F0")))))
(should (> separators 0)))))
(ert-deftest ebox-playground-grid-reference-covers-public-properties ()
"The Grid reference should name every public Grid property in the fixture."
(let ((source (with-temp-buffer