HS: transition query-ref + multi-prop (+2 tests)
Three parts: (a) parser `collect-transitions` recognises `style`
tokens (`*prop`) as a continuation, so
`transition *width from A to B *height from A to B` chains both
transitions instead of dropping the second. (b) Mock `El` class gets
`nextSibling`/`previousSibling` (plus `*ElementSibling` aliases) so
`transition *W of the next <span/>` can resolve the next-sibling
target via host-get. (c) Generator pattern for
`const X = await evaluate(() => { const el = document.querySelector(SEL);
el.dispatchEvent(new Event(NAME, ...)); return ... })`; optionally
prefixed by a destructuring assignment and allowing trailing
`expect(...).toBe(...)` junk because `_body_statements` only splits on
`;` at depth 0.
Remaining `can use initial to transition to original value` needs
`on click N` count-filtered events (same mock-sync block as cluster 13).
Suite hs-upstream-transition: 13/17 → 15/17. Smoke 0-195: 162/195
unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1618,8 +1618,11 @@
|
|||||||
(if
|
(if
|
||||||
(and
|
(and
|
||||||
(not (at-end?))
|
(not (at-end?))
|
||||||
(= (tp-type) "ident")
|
(or
|
||||||
(not (hs-keyword? (tp-val))))
|
(= (tp-type) "style")
|
||||||
|
(and
|
||||||
|
(= (tp-type) "ident")
|
||||||
|
(not (hs-keyword? (tp-val))))))
|
||||||
(collect-transitions
|
(collect-transitions
|
||||||
(append acc (list (parse-one-transition))))
|
(append acc (list (parse-one-transition))))
|
||||||
acc)))
|
acc)))
|
||||||
|
|||||||
@@ -1618,8 +1618,11 @@
|
|||||||
(if
|
(if
|
||||||
(and
|
(and
|
||||||
(not (at-end?))
|
(not (at-end?))
|
||||||
(= (tp-type) "ident")
|
(or
|
||||||
(not (hs-keyword? (tp-val))))
|
(= (tp-type) "style")
|
||||||
|
(and
|
||||||
|
(= (tp-type) "ident")
|
||||||
|
(not (hs-keyword? (tp-val))))))
|
||||||
(collect-transitions
|
(collect-transitions
|
||||||
(append acc (list (parse-one-transition))))
|
(append acc (list (parse-one-transition))))
|
||||||
acc)))
|
acc)))
|
||||||
|
|||||||
@@ -12798,6 +12798,7 @@ end")
|
|||||||
(dom-set-attr _el-div "_" "on click transition *width from 0px to 100px *height from 0px to 100px")
|
(dom-set-attr _el-div "_" "on click transition *width from 0px to 100px *height from 0px to 100px")
|
||||||
(dom-append (dom-body) _el-div)
|
(dom-append (dom-body) _el-div)
|
||||||
(hs-activate! _el-div)
|
(hs-activate! _el-div)
|
||||||
|
(dom-dispatch _el-div "click" nil)
|
||||||
(assert= (dom-get-style _el-div "width") "100px")
|
(assert= (dom-get-style _el-div "width") "100px")
|
||||||
(assert= (dom-get-style _el-div "height") "100px")
|
(assert= (dom-get-style _el-div "height") "100px")
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ class El {
|
|||||||
contains(o) { if(o===this)return true; for(const c of this.children)if(c===o||c.contains(o))return true; return false; }
|
contains(o) { if(o===this)return true; for(const c of this.children)if(c===o||c.contains(o))return true; return false; }
|
||||||
cloneNode(d) { const e=new El(this.tagName.toLowerCase()); Object.assign(e.attributes,this.attributes); e.id=this.id; e.className=this.className; e.classList._sync(this.className); for(const k of Object.keys(this.style)){if(typeof this.style[k]!=='function')e.style[k]=this.style[k];} e.textContent=this.textContent; e.innerHTML=this.innerHTML; e.value=this.value; if(d)for(const c of this.children)e.appendChild(c.cloneNode(true)); return e; }
|
cloneNode(d) { const e=new El(this.tagName.toLowerCase()); Object.assign(e.attributes,this.attributes); e.id=this.id; e.className=this.className; e.classList._sync(this.className); for(const k of Object.keys(this.style)){if(typeof this.style[k]!=='function')e.style[k]=this.style[k];} e.textContent=this.textContent; e.innerHTML=this.innerHTML; e.value=this.value; if(d)for(const c of this.children)e.appendChild(c.cloneNode(true)); return e; }
|
||||||
focus(){} blur(){} click(){this.dispatchEvent(new Ev('click',{bubbles:true}));} remove(){if(this.parentElement)this.parentElement.removeChild(this);}
|
focus(){} blur(){} click(){this.dispatchEvent(new Ev('click',{bubbles:true}));} remove(){if(this.parentElement)this.parentElement.removeChild(this);}
|
||||||
|
get nextSibling(){const p=this.parentElement;if(!p)return null;const i=p.children.indexOf(this);return i>=0&&i<p.children.length-1?p.children[i+1]:null;}
|
||||||
|
get nextElementSibling(){return this.nextSibling;}
|
||||||
|
get previousSibling(){const p=this.parentElement;if(!p)return null;const i=p.children.indexOf(this);return i>0?p.children[i-1]:null;}
|
||||||
|
get previousElementSibling(){return this.previousSibling;}
|
||||||
reset(){
|
reset(){
|
||||||
// Form reset: walk descendants, restore defaultValue / defaultChecked /
|
// Form reset: walk descendants, restore defaultValue / defaultChecked /
|
||||||
// defaultSelected.
|
// defaultSelected.
|
||||||
|
|||||||
@@ -1071,6 +1071,26 @@ def parse_dev_body(body, elements, var_names):
|
|||||||
ops.append(f'(dom-dispatch {target} "{m.group(3)}" {detail_expr})')
|
ops.append(f'(dom-dispatch {target} "{m.group(3)}" {detail_expr})')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# [const X = await ]evaluate(() => { const el = document.querySelector(SEL); el.dispatchEvent(new Event(NAME, ...)); return ... })
|
||||||
|
# Dispatches an event on a queried element and ignores the return value.
|
||||||
|
# Stmt may have trailing un-split junk (`expect(...).toBe(...)`) since
|
||||||
|
# body splitter only breaks on `;` and `})` doesn't always have one.
|
||||||
|
m = re.match(
|
||||||
|
r"(?:const\s+\w+\s*=\s*(?:await\s+)?)?"
|
||||||
|
r"evaluate\(\s*\(\)\s*=>\s*\{\s*"
|
||||||
|
r"const\s+(\w+)\s*=\s*document\.querySelector\(\s*(['\"])([^'\"]+)\2\s*\)\s*;?\s*"
|
||||||
|
r"\1\.dispatchEvent\(\s*new\s+(?:Custom)?Event\(\s*(['\"])([^'\"]+)\4"
|
||||||
|
r"(\s*,\s*\{[^}]*\})?\s*\)\s*\)\s*;?",
|
||||||
|
stmt_na, re.DOTALL,
|
||||||
|
)
|
||||||
|
if m and seen_html:
|
||||||
|
sel = re.sub(r'^#work-area\s+', '', m.group(3))
|
||||||
|
target = selector_to_sx(sel, elements, var_names)
|
||||||
|
opts = m.group(6) or ''
|
||||||
|
detail_expr = _extract_detail_expr(opts)
|
||||||
|
ops.append(f'(dom-dispatch {target} "{m.group(5)}" {detail_expr})')
|
||||||
|
continue
|
||||||
|
|
||||||
# evaluate(() => document.getElementById(ID).METHOD()) — generic
|
# evaluate(() => document.getElementById(ID).METHOD()) — generic
|
||||||
# method dispatch (showModal, close, click, focus, blur, reset…).
|
# method dispatch (showModal, close, click, focus, blur, reset…).
|
||||||
m = re.match(
|
m = re.match(
|
||||||
|
|||||||
Reference in New Issue
Block a user