feat: lower canonical Box through ETAF runtime
This commit is contained in:
parent
c3ea8aa8ea
commit
c831ca11ca
@ -552,7 +552,7 @@ the ordinary layout lowering path instead."
|
|||||||
(list (apply #'ebox-spacer props)))
|
(list (apply #'ebox-spacer props)))
|
||||||
('fragment
|
('fragment
|
||||||
(etaf--render-value-list children (append path (list :fragment))))
|
(etaf--render-value-list children (append path (list :fragment))))
|
||||||
((or 'row 'column 'container 'stack 'flex 'grid)
|
((or 'box 'row 'column 'container 'stack 'flex 'grid)
|
||||||
(let ((nodes nil)
|
(let ((nodes nil)
|
||||||
(index 0)
|
(index 0)
|
||||||
(range-child-p nil)
|
(range-child-p nil)
|
||||||
@ -624,6 +624,8 @@ the ordinary layout lowering path instead."
|
|||||||
RANGE-CHILD-P records that NODES include nonvisual Range segments."
|
RANGE-CHILD-P records that NODES include nonvisual Range segments."
|
||||||
(let ((node
|
(let ((node
|
||||||
(cond
|
(cond
|
||||||
|
((eq name 'box)
|
||||||
|
(ebox-build (append (list 'box) props nodes)))
|
||||||
((eq name 'row)
|
((eq name 'row)
|
||||||
(if (null props)
|
(if (null props)
|
||||||
(apply #'ebox-row nodes)
|
(apply #'ebox-row nodes)
|
||||||
@ -653,7 +655,7 @@ RANGE-CHILD-P preserves the direct material Range parent."
|
|||||||
(etaf--layout-node 'row props children range-child-p)
|
(etaf--layout-node 'row props children range-child-p)
|
||||||
(apply #'ebox-create :content content props)))
|
(apply #'ebox-create :content content props)))
|
||||||
('spacer (apply #'ebox-spacer props))
|
('spacer (apply #'ebox-spacer props))
|
||||||
((or 'row 'column 'container 'stack 'flex 'grid)
|
((or 'box 'row 'column 'container 'stack 'flex 'grid)
|
||||||
(etaf--layout-node name props children range-child-p))
|
(etaf--layout-node name props children range-child-p))
|
||||||
(_ (signal 'etaf-renderer-error
|
(_ (signal 'etaf-renderer-error
|
||||||
(list (format "Semantic Host requires Step4b lowering: %S"
|
(list (format "Semantic Host requires Step4b lowering: %S"
|
||||||
|
|||||||
@ -1122,7 +1122,8 @@ when the requested boundary is no longer mounted."
|
|||||||
(or (plist-get env :slots)
|
(or (plist-get env :slots)
|
||||||
(and component (etaf--semantic-component-slots component)))))
|
(and component (etaf--semantic-component-slots component)))))
|
||||||
(if (null component-id)
|
(if (null component-id)
|
||||||
(let ((etaf--current-component-instance nil)
|
(let ((etaf--current-runtime runtime)
|
||||||
|
(etaf--current-component-instance nil)
|
||||||
(etaf--current-component-identity nil)
|
(etaf--current-component-identity nil)
|
||||||
(etaf--current-component-semantic-id nil)
|
(etaf--current-component-semantic-id nil)
|
||||||
(etaf--current-component-props nil)
|
(etaf--current-component-props nil)
|
||||||
@ -2991,10 +2992,12 @@ The candidate uses resolved VALUE, DEPS, and NODES."
|
|||||||
(etaf-runtime-candidate-inline-host-ids runtime)
|
(etaf-runtime-candidate-inline-host-ids runtime)
|
||||||
:test #'eql)
|
:test #'eql)
|
||||||
(etaf--runtime-invalidate-semantic-ancestors runtime host-id)
|
(etaf--runtime-invalidate-semantic-ancestors runtime host-id)
|
||||||
(when-let* ((component
|
(when-let* ((component-id
|
||||||
|
(etaf--semantic-inline-range-component-id old))
|
||||||
|
(component
|
||||||
(etaf--pvec-get
|
(etaf--pvec-get
|
||||||
(etaf-generation-semantic-nodes generation)
|
(etaf-generation-semantic-nodes generation)
|
||||||
(etaf--semantic-inline-range-component-id old))))
|
component-id)))
|
||||||
(cl-pushnew (etaf--semantic-component-identity component)
|
(cl-pushnew (etaf--semantic-component-identity component)
|
||||||
(etaf-runtime-candidate-updated-component-identities
|
(etaf-runtime-candidate-updated-component-identities
|
||||||
runtime)
|
runtime)
|
||||||
@ -4456,43 +4459,23 @@ Generation, including its effects and Host contributions."
|
|||||||
|
|
||||||
(defun etaf--runtime-render-dirty-inline-range (runtime effect inline)
|
(defun etaf--runtime-render-dirty-inline-range (runtime effect inline)
|
||||||
"Evaluate RUNTIME dirty INLINE EFFECT and stage its semantic output."
|
"Evaluate RUNTIME dirty INLINE EFFECT and stage its semantic output."
|
||||||
(let* ((generation (etaf-runtime-current-generation runtime))
|
(let (deps context-deps output)
|
||||||
(base-component
|
(etaf--runtime-call-with-component-env
|
||||||
(etaf--pvec-get (etaf-generation-semantic-nodes generation)
|
runtime (etaf--semantic-inline-range-component-id inline)
|
||||||
(etaf--semantic-inline-range-component-id inline)))
|
(lambda ()
|
||||||
(component
|
|
||||||
(or (gethash (etaf--semantic-component-identity base-component)
|
|
||||||
(etaf-runtime-candidate-semantic-nodes runtime))
|
|
||||||
base-component))
|
|
||||||
(instance
|
|
||||||
(gethash (etaf--semantic-component-resource-key component)
|
|
||||||
(etaf-runtime-resource-registry runtime)))
|
|
||||||
deps context-deps output)
|
|
||||||
(let ((etaf--runtime-dependency-collector
|
(let ((etaf--runtime-dependency-collector
|
||||||
(lambda (source) (cl-pushnew source deps :test #'eq)))
|
(lambda (source) (cl-pushnew source deps :test #'eq)))
|
||||||
(etaf--context-inject-recorder
|
(etaf--context-inject-recorder
|
||||||
(lambda (frame key)
|
(lambda (frame key)
|
||||||
(cl-pushnew (cons (etaf-context-owner-id frame) key)
|
(cl-pushnew (cons (etaf-context-owner-id frame) key)
|
||||||
context-deps :test #'equal)))
|
context-deps :test #'equal)))
|
||||||
(etaf--current-runtime runtime)
|
|
||||||
(etaf--current-component-instance instance)
|
|
||||||
(etaf--current-component-identity
|
|
||||||
(etaf--semantic-component-identity component))
|
|
||||||
(etaf--current-component-semantic-id
|
|
||||||
(etaf--semantic-component-semantic-id component))
|
|
||||||
(etaf--current-component-props
|
|
||||||
(etaf--semantic-component-props component))
|
|
||||||
(etaf--current-component-slots
|
|
||||||
(etaf--semantic-component-slots component))
|
|
||||||
(etaf--current-context
|
|
||||||
(etaf--semantic-component-context-frame component))
|
|
||||||
(etaf--active-effect nil)
|
(etaf--active-effect nil)
|
||||||
(etaf--render-phase-p t))
|
(etaf--render-phase-p t))
|
||||||
(setq output
|
(setq output
|
||||||
(etaf--runtime-inline-value-string
|
(etaf--runtime-inline-value-string
|
||||||
(funcall
|
(funcall
|
||||||
(etaf--expr-thunk (etaf--generation-effect-target effect)))
|
(etaf--expr-thunk (etaf--generation-effect-target effect)))
|
||||||
(etaf--semantic-inline-range-surface-properties inline))))
|
(etaf--semantic-inline-range-surface-properties inline))))))
|
||||||
(let ((candidate (copy-sequence inline)))
|
(let ((candidate (copy-sequence inline)))
|
||||||
(setf (etaf--semantic-inline-range-output candidate)
|
(setf (etaf--semantic-inline-range-output candidate)
|
||||||
(copy-sequence output)
|
(copy-sequence output)
|
||||||
@ -4518,11 +4501,13 @@ Generation, including its effects and Host contributions."
|
|||||||
:test #'eql)
|
:test #'eql)
|
||||||
(etaf--runtime-invalidate-semantic-ancestors
|
(etaf--runtime-invalidate-semantic-ancestors
|
||||||
runtime (etaf--semantic-inline-range-parent-id inline))
|
runtime (etaf--semantic-inline-range-parent-id inline))
|
||||||
(when-let* ((component
|
(when-let* ((component-id
|
||||||
|
(etaf--semantic-inline-range-component-id inline))
|
||||||
|
(component
|
||||||
(etaf--pvec-get
|
(etaf--pvec-get
|
||||||
(etaf-generation-semantic-nodes
|
(etaf-generation-semantic-nodes
|
||||||
(etaf-runtime-current-generation runtime))
|
(etaf-runtime-current-generation runtime))
|
||||||
(etaf--semantic-inline-range-component-id inline))))
|
component-id)))
|
||||||
(cl-pushnew (etaf--semantic-component-identity component)
|
(cl-pushnew (etaf--semantic-component-identity component)
|
||||||
(etaf-runtime-candidate-updated-component-identities runtime)
|
(etaf-runtime-candidate-updated-component-identities runtime)
|
||||||
:test #'equal)))
|
:test #'equal)))
|
||||||
@ -4675,11 +4660,13 @@ RENDERED-IDENTITIES names the Component render participants."
|
|||||||
(etaf--pvec-get
|
(etaf--pvec-get
|
||||||
(etaf-generation-semantic-nodes generation)
|
(etaf-generation-semantic-nodes generation)
|
||||||
inline-id))))
|
inline-id))))
|
||||||
|
(component-id
|
||||||
|
(and inline (etaf--semantic-inline-range-component-id inline)))
|
||||||
(component
|
(component
|
||||||
(and inline
|
(and component-id
|
||||||
(etaf--pvec-get
|
(etaf--pvec-get
|
||||||
(etaf-generation-semantic-nodes generation)
|
(etaf-generation-semantic-nodes generation)
|
||||||
(etaf--semantic-inline-range-component-id inline)))))
|
component-id))))
|
||||||
(and component
|
(and component
|
||||||
(member (etaf--semantic-component-identity component)
|
(member (etaf--semantic-component-identity component)
|
||||||
rendered-identities))))
|
rendered-identities))))
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
key-thunk)
|
key-thunk)
|
||||||
|
|
||||||
(defconst etaf--host-names
|
(defconst etaf--host-names
|
||||||
'(text fragment container row column stack flex grid spacer)
|
'(text box fragment container row column stack flex grid spacer)
|
||||||
"Minimal unstyled Hosts implemented by ETAF core.
|
"Minimal unstyled Hosts implemented by ETAF core.
|
||||||
|
|
||||||
Product Components such as Button belong to `etaf-ui'; they are not added to
|
Product Components such as Button belong to `etaf-ui'; they are not added to
|
||||||
|
|||||||
@ -1294,6 +1294,51 @@
|
|||||||
(etaf-test--render-text
|
(etaf-test--render-text
|
||||||
(etaf-view (column (text "A") (text "B")))))))
|
(etaf-view (column (text "A") (text "B")))))))
|
||||||
|
|
||||||
|
(ert-deftest etaf-view-box-lowers-outer-and-layout-to-ebox ()
|
||||||
|
"Lower canonical Box axes through Ebox's public Box DSL."
|
||||||
|
(let ((row
|
||||||
|
(etaf-render
|
||||||
|
(etaf-view
|
||||||
|
(box :outer 'inline :layout 'row
|
||||||
|
(text "A")
|
||||||
|
(text "B")))))
|
||||||
|
(column
|
||||||
|
(etaf-render
|
||||||
|
(etaf-view
|
||||||
|
(box :outer 'block :layout 'column
|
||||||
|
(text "A")
|
||||||
|
(text "B"))))))
|
||||||
|
(should (equal (ebox--computed-display row) '(inline row)))
|
||||||
|
(should (equal (ebox--computed-display column) '(block column)))
|
||||||
|
(should (equal (substring-no-properties (ebox-render row)) "AB"))
|
||||||
|
(should (equal (substring-no-properties (ebox-render column)) "A\nB"))))
|
||||||
|
|
||||||
|
(ert-deftest etaf-view-box-rejects-invalid-layout ()
|
||||||
|
"Reject an invalid canonical Box layout before publication."
|
||||||
|
(should-error
|
||||||
|
(etaf-render (etaf-view (box :layout 'masonry "A")))
|
||||||
|
:type 'error))
|
||||||
|
|
||||||
|
(ert-deftest etaf-runtime-box-retains-child-text-update ()
|
||||||
|
"Mounted canonical Box should retain its layout while Text updates."
|
||||||
|
(let ((buffer-name " *etaf-box-runtime-test*")
|
||||||
|
(source (etaf-ref "A")))
|
||||||
|
(unwind-protect
|
||||||
|
(progn
|
||||||
|
(etaf-mount
|
||||||
|
buffer-name
|
||||||
|
(etaf-view
|
||||||
|
(box :layout 'row
|
||||||
|
(text (expr :value (etaf-value source)))
|
||||||
|
(text "B"))))
|
||||||
|
(should (string-match-p "AB" (etaf-test--buffer-text buffer-name)))
|
||||||
|
(setf (etaf-value source) "C")
|
||||||
|
(should (string-match-p "CB" (etaf-test--buffer-text buffer-name))))
|
||||||
|
(when-let* ((runtime (etaf-runtime-for-buffer buffer-name)))
|
||||||
|
(etaf-unmount runtime))
|
||||||
|
(when-let* ((buffer (get-buffer buffer-name)))
|
||||||
|
(kill-buffer buffer)))))
|
||||||
|
|
||||||
(ert-deftest etaf-view-grid-lowers-to-ebox-grid ()
|
(ert-deftest etaf-view-grid-lowers-to-ebox-grid ()
|
||||||
"Lower the Grid Host through Ebox's two-dimensional layout node."
|
"Lower the Grid Host through Ebox's two-dimensional layout node."
|
||||||
(let ((node (etaf-render
|
(let ((node (etaf-render
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user