diff --git a/docs/user/ebox-api-reference.en.md b/docs/user/ebox-api-reference.en.md index bda620e..f3c3a33 100644 --- a/docs/user/ebox-api-reference.en.md +++ b/docs/user/ebox-api-reference.en.md @@ -136,9 +136,7 @@ of full browser CSS compatibility. :grid-template-columns '((200) 1fr 1fr) :grid-template-rows '(1 1) :gap '(1 (12)) - (ebox-grid-item - (ebox-create :content "Header") - :grid-column '(1 :span 3)) + (ebox-create :content "Header" :grid-column '(1 :span 3)) (ebox-create :content "Main" :grid-column 1 :grid-row 2) (ebox-create :content "Aside" :grid-column 2 :grid-row 2)) ``` @@ -152,8 +150,8 @@ positions use implicit tracks. `:grid-auto-columns`, `:grid-auto-rows`, and Grid item placement is one-based. `:grid-column` and `:grid-row` accept a positive start integer, `(start :span positive-integer)`, or `(start end)` with `end` greater than `start`. `:grid-column-span` and `:grid-row-span` accept -positive integers. `ebox-grid-item` is a convenience wrapper; placement -properties may also be placed directly on a child node. +positive integers. Placement properties belong directly to the child Box; +Grid item is a parent-child role, not a wrapper or constructor. ## 4. Units, box properties, and text properties @@ -534,15 +532,14 @@ boolean to nil when a host application must avoid background preparation. ## 10. Standalone `.ebox` DSL `ebox-build` compiles a data-oriented list form. Supported tags are `box` and -`ebox`, `row`, `column`, `flex`, `item`, `grid`, `grid-item`, and `spacer`: +`ebox`, `row`, `column`, `flex`, `item`, `grid`, and `spacer`: ```elisp (ebox-build '(grid :width (640) :grid-template-columns ((200) 1fr 1fr) :gap (1 (12)) - (grid-item :grid-column (1 :span 3) - (box :content "Header")) + (box :grid-column (1 :span 3) :content "Header") (box :content "Main"))) ``` @@ -550,7 +547,7 @@ Strings directly under `box` become newline-joined content. Child forms become a default vertical child layout. `row` and `column` can receive box properties around their child layout. `flex` accepts container properties; `item` accepts flex item properties and exactly one or more child forms; -`grid-item` requires exactly one child; `spacer` accepts no children. +`spacer` accepts no children. Inside a `.ebox` file, keep structural forms unquoted. Quote list and symbol constants in property positions when they are data, such as @@ -591,7 +588,7 @@ style-rule functions immediately below are public module-level style APIs. | `ebox-create`, `ebox-build` | Create a legacy node or compile the `.ebox` list DSL during migration. | | `ebox-concat`, `ebox-stack`, `ebox-row`, `ebox-column`, `ebox-spacer` | Compose simple horizontal/vertical layouts and blank boxes. | | `ebox-flex`, `ebox-flex-item` | Build flex containers and item metadata. | -| `ebox-grid`, `ebox-grid-fr`, `ebox-grid-item` | Build Grid layouts, fractional tracks, and placement metadata. | +| `ebox-grid`, `ebox-grid-fr` | Build Grid layouts and fractional tracks; placement metadata belongs to direct child Boxes. | | `ebox-render`, `ebox-render-to-buffer`, `ebox-display-buffer` | Pure materialization, retained mount, and display wrapper. | | `ebox-commit`, `ebox-buffer-update-report`, `ebox-rerender-buffer-with-context`, `ebox-viewport-window-width` | Atomic root commit, report lookup, viewport-context rerender, and the shared display-safe width sampler. | | `ebox-region-ids`, `ebox-region-resolve`, `ebox-region-update` | Region mapping, logical handle lookup, and direct update. | diff --git a/docs/user/ebox-api-reference.zh.md b/docs/user/ebox-api-reference.zh.md index 0e9e866..12ec304 100644 --- a/docs/user/ebox-api-reference.zh.md +++ b/docs/user/ebox-api-reference.zh.md @@ -124,9 +124,7 @@ Flex preferred/min/max size 支持 Ebox 子集:`auto`、`min-content`、 :grid-template-columns '((200) 1fr 1fr) :grid-template-rows '(1 1) :gap '(1 (12)) - (ebox-grid-item - (ebox-create :content "Header") - :grid-column '(1 :span 3)) + (ebox-create :content "Header" :grid-column '(1 :span 3)) (ebox-create :content "Main" :grid-column 1 :grid-row 2) (ebox-create :content "Aside" :grid-column 2 :grid-row 2)) ``` @@ -138,8 +136,8 @@ Flex preferred/min/max size 支持 Ebox 子集:`auto`、`min-content`、 Grid placement 从 1 开始。`:grid-column` 和 `:grid-row` 接受正整数起点、 `(start :span 正整数)`,或 `start` 小于 `end` 的 `(start end)`。 -`:grid-column-span` 与 `:grid-row-span` 接受正整数。`ebox-grid-item` 是便捷 -包装器;placement property 也可以直接放在 child node 上。 +`:grid-column-span` 与 `:grid-row-span` 接受正整数。placement property 直接属于 +child Box;Grid item 是父子参与角色,不是 wrapper 或 constructor。 ## 4. 单位、box property 与文本属性 @@ -484,22 +482,20 @@ Idle prewarm 不会发布 buffer text 或 runtime state。宿主应用不希望 ## 10. 独立 `.ebox` DSL `ebox-build` 编译数据型 list form。支持的 tag 是 `box`/`ebox`、`row`、 -`column`、`flex`、`item`、`grid`、`grid-item` 和 `spacer`: +`column`、`flex`、`item`、`grid` 和 `spacer`: ```elisp (ebox-build '(grid :width (640) :grid-template-columns ((200) 1fr 1fr) :gap (1 (12)) - (grid-item :grid-column (1 :span 3) - (box :content "Header")) + (box :grid-column (1 :span 3) :content "Header") (box :content "Main"))) ``` `box` 下的直接字符串会合并为换行内容;child form 会变成默认纵向 child layout。`row` 与 `column` 可以接收 box property 并包住 child layout;`flex` -接收容器 property;`item` 接收 flex item property;`grid-item` 必须有一个 -child;`spacer` 不能有 child。 +接收容器 property;`item` 接收 flex item property;`spacer` 不能有 child。 在 `.ebox` 文件中,结构 form 保持不加 quote;property 位置的 list 和 symbol 常量要作为 data quote,例如 `:gap '(1 (12))` 或 `:justify-content 'center`; @@ -537,7 +533,7 @@ style API。 | `ebox-create`、`ebox-build` | 迁移期间创建旧节点或编译 `.ebox` list DSL。 | | `ebox-concat`、`ebox-stack`、`ebox-row`、`ebox-column`、`ebox-spacer` | 组合简单横向/纵向布局与空白 box。 | | `ebox-flex`、`ebox-flex-item` | 构建 Flex 容器与 item metadata。 | -| `ebox-grid`、`ebox-grid-fr`、`ebox-grid-item` | 构建 Grid、分数轨道和 placement metadata。 | +| `ebox-grid`、`ebox-grid-fr` | 构建 Grid 与分数轨道;placement metadata 直接属于 child Box。 | | `ebox-render`、`ebox-render-to-buffer`、`ebox-display-buffer` | 纯 materialization、retained mount 与展示包装。 | | `ebox-commit`、`ebox-buffer-update-report`、`ebox-rerender-buffer-with-context`、`ebox-viewport-window-width` | 原子根提交、报告查询、viewport-context rerender 与统一的显示安全宽度采样。 | | `ebox-region-ids`、`ebox-region-resolve`、`ebox-region-update` | Region 映射、logical handle 查询与直接更新。 | diff --git a/ebox-dsl.el b/ebox-dsl.el index bbfce0a..3b784c7 100644 --- a/ebox-dsl.el +++ b/ebox-dsl.el @@ -160,17 +160,6 @@ The first value is string content. The second value is a lazy child node." (plist-put child key (plist-get item-props key)))) (apply #'ebox-flex-item child item-props)))) -(defun ebox--build-grid-item (items) - "Build a grid-item node from DSL ITEMS." - (let* ((split (ebox-grid--split-attrs items)) - (props (car split)) - (children (delq nil (cdr split)))) - (unless (= (length children) 1) - (error "ebox-build: grid-item requires exactly one child node")) - (apply #'ebox-grid-item - (ebox-dsl-build (car children)) - props))) - (defun ebox--build-grid (items) "Build a grid node from DSL ITEMS." (let* ((split (ebox-grid--split-attrs items)) @@ -226,7 +215,7 @@ Supported forms: (row (box :content \"Left\") (spacer :width (16)) (box :content \"Right\")) (column (box :content \"Top\") (box :content \"Bottom\")) (grid :grid-template-columns ((80) (80)) - (grid-item :grid-column (1 :span 2) (box \"Header\"))) + (box :grid-column (1 :span 2) \"Header\")) (flex :width (320) :gap (1 (12)) (item :flex 1 (box \"A\"))) `box' and `ebox' create `ebox-create' nodes. `row', `column', @@ -249,7 +238,6 @@ the child layout in a box using the rendered child layout as content." ('column (ebox--build-layout tag #'ebox-column items)) ('flex (ebox--build-flex items)) ('item (ebox--build-flex-item items)) - ('grid-item (ebox--build-grid-item items)) ('spacer (ebox--build-spacer items)) ('grid (ebox--build-grid items)) (_ (error "ebox-build: unknown DSL tag %S" tag))))))) diff --git a/ebox-grid.el b/ebox-grid.el index 4be06e2..82f355e 100644 --- a/ebox-grid.el +++ b/ebox-grid.el @@ -342,29 +342,6 @@ programmatic port and are therefore rejected here." (error "ebox-grid-fr: FACTOR must be positive: %S" factor)) (list 'fr factor)) -;;;###autoload -(defun ebox-grid-item (node &rest props) - "Return NODE with grid placement PROPS attached. -Supported properties are `:grid-column', `:grid-row', -`:grid-column-span', and `:grid-row-span'." - (unless (and (listp node) (plist-member node :ebox-type)) - (error "ebox-grid-item: NODE is not an Ebox node: %S" node)) - (let ((copy (copy-sequence node)) - (declarations (ebox-style-compile-declarations props t))) - (while props - (let* ((key (pop props)) - (value (progn - (unless props - (error "ebox-grid-item: missing value for %S" key)) - (pop props)))) - (unless (memq key ebox--grid-item-prop-keys) - (error "ebox-grid-item: unsupported property %S" key)) - (plist-put copy key value))) - (plist-put copy :ebox-style-declarations - (append (plist-get copy :ebox-style-declarations) - declarations)) - copy)) - (defun ebox-grid--placement-part (value default) "Return (START SPAN) parsed from placement VALUE and DEFAULT." (cond @@ -895,7 +872,8 @@ Grid properties include `:grid-template-columns', `:grid-template-rows', `:grid-auto-flow', `:gap', `:grid-row-gap', `:grid-column-gap', `:justify-items', `:align-items', `:width', and `:height'. Track sizes use Ebox pixel/line units, `auto', `(fr FACTOR)', or symbols such as `1fr'. -Children may carry `:grid-column' and `:grid-row' placement properties. +Children may carry `:grid-column', `:grid-row', `:grid-column-span', and +`:grid-row-span' placement properties directly. `ebox-grid-fr' is a convenient constructor for fractional tracks." (let* ((split (ebox-grid--split-attrs items)) (raw-props (car split)) diff --git a/ebox.el b/ebox.el index 935ab5e..f8593ac 100644 --- a/ebox.el +++ b/ebox.el @@ -4608,7 +4608,6 @@ through dirty-set and patch-set execution before falling back to root rerender." ebox-grid ebox-grid-fr ebox-grid-layout-create - ebox-grid-item ebox-host-ref-bounds ebox-host-ref-position ebox-native-build @@ -4693,7 +4692,7 @@ and are documented separately in the public API reference.") ;; :padding :margin :border :border-color :bgcolor ;; :text-align :wrap-mode :box-sizing :surface-properties :host-ref ;; ebox-build dsl -;; Compile ETML-style (box/row/column/flex/item/spacer ...) forms into +;; Compile ETML-style (box/row/column/flex/spacer ...) forms into ;; normal ebox layout nodes. ;; ;; ── Layout ──────────────────────────────────────────────────── diff --git a/tests/ebox-docs-contract-tests.el b/tests/ebox-docs-contract-tests.el index ad6fba0..b03196f 100644 --- a/tests/ebox-docs-contract-tests.el +++ b/tests/ebox-docs-contract-tests.el @@ -100,6 +100,16 @@ (should-not (string-match-p "`etaf-[[:alnum:]-]+\\.el`" source)) (should-not (string-match-p "`etaf\\.el`" source))))) +(ert-deftest ebox-docs-do-not-present-removed-grid-item-api () + "Public documentation must expose direct child Grid placement only." + (dolist (file '("docs/user/ebox-api-reference.en.md" + "docs/user/ebox-api-reference.zh.md" + "docs/user/ebox-user-guide.en.md" + "docs/user/ebox-user-guide.zh.md")) + (let ((source (ebox-docs-test--read file))) + (should-not (string-match-p "ebox-grid-item" source)) + (should-not (string-match-p "`grid-item`" source))))) + (provide 'ebox-docs-contract-tests) ;;; ebox-docs-contract-tests.el ends here diff --git a/tests/ebox-grid-tests.el b/tests/ebox-grid-tests.el index b3727be..42a7058 100644 --- a/tests/ebox-grid-tests.el +++ b/tests/ebox-grid-tests.el @@ -161,12 +161,9 @@ (ebox-grid :grid-template-columns '((20) (20)) :grid-template-rows '(1 1) - (ebox-grid-item (ebox-create :content "Header") - :grid-column '(1 :span 2)) - (ebox-grid-item (ebox-create :content "Left") - :grid-row 2 :grid-column 1) - (ebox-grid-item (ebox-create :content "Right") - :grid-row 2 :grid-column 2))))) + (ebox-create :content "Header" :grid-column '(1 :span 2)) + (ebox-create :content "Left" :grid-row 2 :grid-column 1) + (ebox-create :content "Right" :grid-row 2 :grid-column 2))))) (should (string-match-p "Header" plain)) (should (string-match-p "Left.*Right" plain)))) @@ -217,11 +214,11 @@ (should-error (ebox-render (ebox-grid - (ebox-grid-item (ebox-create :content "A") :grid-column-span 0)))) + (ebox-create :content "A" :grid-column-span 0)))) (should-error (ebox-render (ebox-grid - (ebox-grid-item (ebox-create :content "A") :grid-column 0))))) + (ebox-create :content "A" :grid-column 0))))) (ert-deftest ebox-grid-rejects-invalid-ecss-placement-before-layout () "ECSS rules should reject invalid Grid placement before layout runs." @@ -266,13 +263,12 @@ (should (string-match-p "A" (ebox-grid-test--plain node))) (should (string-match-p "B" (ebox-grid-test--plain node))))) -(ert-deftest ebox-build-compiles-grid-item-placement () - "The Ebox DSL should preserve grid-item placement metadata." +(ert-deftest ebox-build-compiles-direct-grid-placement () + "The Ebox DSL should preserve direct child Box placement metadata." (let ((node (ebox-build '(grid :grid-template-columns ((20) (20)) - (grid-item :grid-column (1 :span 2) - (box :content "Header")))))) + (box :grid-column (1 :span 2) :content "Header"))))) (should (string-match-p "Header" (ebox-grid-test--plain node))) (should (equal (plist-get (car (plist-get node :children)) :grid-column) '(1 :span 2))))) diff --git a/tests/ebox-package-tests.el b/tests/ebox-package-tests.el index 3e1ef6d..07ab7f9 100644 --- a/tests/ebox-package-tests.el +++ b/tests/ebox-package-tests.el @@ -170,7 +170,6 @@ ("ebox-flex-item" . "defun") ("ebox-flex" . "defun") ("ebox-grid-fr" . "defun") - ("ebox-grid-item" . "defun") ("ebox-grid" . "defun") ("ebox-grid-layout-create" . "defun") ("ebox-normal-layout-create" . "defun") @@ -230,7 +229,6 @@ ebox-grid ebox-grid-fr ebox-grid-layout-create - ebox-grid-item ebox-host-ref-bounds ebox-host-ref-position ebox-native-build