Hyperscript: hide/show strategy (opacity/visibility), add/remove query-all
Parser: hide/show handle `with opacity/visibility/display` strategy and properly detect target vs command boundaries. Compiler: emit correct CSS property per strategy, add-class/remove-class use for-each+query-all for class selectors. Runtime: hs-query-all uses dom-body, hs-each helper for collection iteration. Generator: inline run().toEqual() pattern for eval-only tests. 372/831 (45%) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,45 +13,53 @@
|
||||
;; Register an event listener. Returns unlisten function.
|
||||
;; (hs-on target event-name handler) → unlisten-fn
|
||||
(define
|
||||
hs-on
|
||||
(fn (target event-name handler) (dom-listen target event-name handler)))
|
||||
hs-each
|
||||
(fn
|
||||
(target action)
|
||||
(if (list? target) (for-each action target) (action target))))
|
||||
|
||||
;; Register for every occurrence (no queuing — each fires independently).
|
||||
;; Stock hyperscript queues by default; "every" disables queuing.
|
||||
(define
|
||||
hs-on-every
|
||||
hs-on
|
||||
(fn (target event-name handler) (dom-listen target event-name handler)))
|
||||
|
||||
;; Run an initializer function immediately.
|
||||
;; (hs-init thunk) — called at element boot time
|
||||
(define hs-init (fn (thunk) (thunk)))
|
||||
(define
|
||||
hs-on-every
|
||||
(fn (target event-name handler) (dom-listen target event-name handler)))
|
||||
|
||||
;; ── Async / timing ──────────────────────────────────────────────
|
||||
|
||||
;; Wait for a duration in milliseconds.
|
||||
;; In hyperscript, wait is async-transparent — execution pauses.
|
||||
;; Here we use perform/IO suspension for true pause semantics.
|
||||
(define hs-wait (fn (ms) (perform (list (quote io-sleep) ms))))
|
||||
(define hs-init (fn (thunk) (thunk)))
|
||||
|
||||
;; Wait for a DOM event on a target.
|
||||
;; (hs-wait-for target event-name) — suspends until event fires
|
||||
(define hs-wait (fn (ms) (perform (list (quote io-sleep) ms))))
|
||||
|
||||
;; Wait for CSS transitions/animations to settle on an element.
|
||||
(define
|
||||
hs-wait-for
|
||||
(fn
|
||||
(target event-name)
|
||||
(perform (list (quote io-wait-event) target event-name))))
|
||||
|
||||
;; Wait for CSS transitions/animations to settle on an element.
|
||||
(define hs-settle (fn (target) (perform (list (quote io-settle) target))))
|
||||
|
||||
;; ── Class manipulation ──────────────────────────────────────────
|
||||
|
||||
;; Toggle a single class on an element.
|
||||
(define hs-settle (fn (target) (perform (list (quote io-settle) target))))
|
||||
|
||||
;; Toggle between two classes — exactly one is active at a time.
|
||||
(define
|
||||
hs-toggle-class!
|
||||
(fn (target cls) (host-call (host-get target "classList") "toggle" cls)))
|
||||
|
||||
;; Toggle between two classes — exactly one is active at a time.
|
||||
;; Take a class from siblings — add to target, remove from others.
|
||||
;; (hs-take! target cls) — like radio button class behavior
|
||||
(define
|
||||
hs-toggle-between!
|
||||
(fn
|
||||
@@ -61,8 +69,10 @@
|
||||
(do (dom-remove-class target cls1) (dom-add-class target cls2))
|
||||
(do (dom-remove-class target cls2) (dom-add-class target cls1)))))
|
||||
|
||||
;; Take a class from siblings — add to target, remove from others.
|
||||
;; (hs-take! target cls) — like radio button class behavior
|
||||
;; ── DOM insertion ───────────────────────────────────────────────
|
||||
|
||||
;; Put content at a position relative to a target.
|
||||
;; pos: "into" | "before" | "after"
|
||||
(define
|
||||
hs-toggle-style!
|
||||
(fn
|
||||
@@ -86,10 +96,9 @@
|
||||
(dom-set-style target prop "hidden")
|
||||
(dom-set-style target prop "")))))))
|
||||
|
||||
;; ── DOM insertion ───────────────────────────────────────────────
|
||||
;; ── Navigation / traversal ──────────────────────────────────────
|
||||
|
||||
;; Put content at a position relative to a target.
|
||||
;; pos: "into" | "before" | "after"
|
||||
;; Navigate to a URL.
|
||||
(define
|
||||
hs-take!
|
||||
(fn
|
||||
@@ -105,9 +114,7 @@
|
||||
(for-each (fn (el) (dom-remove-attr el name)) els)
|
||||
(dom-set-attr target name "true"))))))
|
||||
|
||||
;; ── Navigation / traversal ──────────────────────────────────────
|
||||
|
||||
;; Navigate to a URL.
|
||||
;; Find next sibling matching a selector (or any sibling).
|
||||
(define
|
||||
hs-put!
|
||||
(fn
|
||||
@@ -120,10 +127,10 @@
|
||||
((= pos "start") (dom-insert-adjacent-html target "afterbegin" value))
|
||||
((= pos "end") (dom-insert-adjacent-html target "beforeend" value)))))
|
||||
|
||||
;; Find next sibling matching a selector (or any sibling).
|
||||
;; Find previous sibling matching a selector.
|
||||
(define hs-navigate! (fn (url) (perform (list (quote io-navigate) url))))
|
||||
|
||||
;; Find previous sibling matching a selector.
|
||||
;; First element matching selector within a scope.
|
||||
(define
|
||||
hs-scroll!
|
||||
(fn
|
||||
@@ -136,7 +143,7 @@
|
||||
((= position "bottom") (dict :block "end"))
|
||||
(true (dict :block "start")))))))
|
||||
|
||||
;; First element matching selector within a scope.
|
||||
;; Last element matching selector.
|
||||
(define
|
||||
hs-halt!
|
||||
(fn
|
||||
@@ -146,12 +153,14 @@
|
||||
(host-call event "preventDefault" (list))
|
||||
(when (= mode "event") (host-call event "stopPropagation" (list))))))
|
||||
|
||||
;; Last element matching selector.
|
||||
;; First/last within a specific scope.
|
||||
(define hs-select! (fn (target) (host-call target "select" (list))))
|
||||
|
||||
;; First/last within a specific scope.
|
||||
(define hs-reset! (fn (target) (host-call target "reset" (list))))
|
||||
|
||||
;; ── Iteration ───────────────────────────────────────────────────
|
||||
|
||||
;; Repeat a thunk N times.
|
||||
(define
|
||||
hs-next
|
||||
(fn
|
||||
@@ -171,9 +180,7 @@
|
||||
(true (find-next (dom-next-sibling el))))))
|
||||
(find-next sibling)))))
|
||||
|
||||
;; ── Iteration ───────────────────────────────────────────────────
|
||||
|
||||
;; Repeat a thunk N times.
|
||||
;; Repeat forever (until break — relies on exception/continuation).
|
||||
(define
|
||||
hs-previous
|
||||
(fn
|
||||
@@ -193,27 +200,24 @@
|
||||
(true (find-prev (dom-get-prop el "previousElementSibling"))))))
|
||||
(find-prev sibling)))))
|
||||
|
||||
;; Repeat forever (until break — relies on exception/continuation).
|
||||
(define
|
||||
hs-query-all
|
||||
(fn
|
||||
(sel)
|
||||
(dom-query-all
|
||||
(host-call (host-global "document") "querySelector" (list "body"))
|
||||
sel)))
|
||||
|
||||
;; ── Fetch ───────────────────────────────────────────────────────
|
||||
|
||||
;; Fetch a URL, parse response according to format.
|
||||
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
||||
(define
|
||||
hs-query-first
|
||||
(fn (sel) (host-call (host-global "document") "querySelector" sel)))
|
||||
(define hs-query-all (fn (sel) (dom-query-all (dom-body) sel)))
|
||||
|
||||
;; ── Type coercion ───────────────────────────────────────────────
|
||||
|
||||
;; Coerce a value to a type by name.
|
||||
;; (hs-coerce value type-name) — type-name is "Int", "Float", "String", etc.
|
||||
(define
|
||||
hs-query-first
|
||||
(fn (sel) (host-call (host-global "document") "querySelector" sel)))
|
||||
|
||||
;; ── Object creation ─────────────────────────────────────────────
|
||||
|
||||
;; Make a new object of a given type.
|
||||
;; (hs-make type-name) — creates empty object/collection
|
||||
(define
|
||||
hs-query-last
|
||||
(fn
|
||||
@@ -222,17 +226,17 @@
|
||||
((all (dom-query-all (dom-body) sel)))
|
||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||
|
||||
;; ── Object creation ─────────────────────────────────────────────
|
||||
|
||||
;; Make a new object of a given type.
|
||||
;; (hs-make type-name) — creates empty object/collection
|
||||
(define hs-first (fn (scope sel) (dom-query-all scope sel)))
|
||||
|
||||
;; ── Behavior installation ───────────────────────────────────────
|
||||
|
||||
;; Install a behavior on an element.
|
||||
;; A behavior is a function that takes (me ...params) and sets up features.
|
||||
;; (hs-install behavior-fn me ...args)
|
||||
(define hs-first (fn (scope sel) (dom-query-all scope sel)))
|
||||
|
||||
;; ── Measurement ─────────────────────────────────────────────────
|
||||
|
||||
;; Measure an element's bounding rect, store as local variables.
|
||||
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
||||
(define
|
||||
hs-last
|
||||
(fn
|
||||
@@ -241,10 +245,10 @@
|
||||
((all (dom-query-all scope sel)))
|
||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||
|
||||
;; ── Measurement ─────────────────────────────────────────────────
|
||||
;; ── Transition ──────────────────────────────────────────────────
|
||||
|
||||
;; Measure an element's bounding rect, store as local variables.
|
||||
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
||||
;; Transition a CSS property to a value, optionally with duration.
|
||||
;; (hs-transition target prop value duration)
|
||||
(define
|
||||
hs-repeat-times
|
||||
(fn
|
||||
@@ -254,10 +258,6 @@
|
||||
(fn (i) (when (< i n) (do (thunk) (do-repeat (+ i 1))))))
|
||||
(do-repeat 0)))
|
||||
|
||||
;; ── Transition ──────────────────────────────────────────────────
|
||||
|
||||
;; Transition a CSS property to a value, optionally with duration.
|
||||
;; (hs-transition target prop value duration)
|
||||
(define
|
||||
hs-repeat-forever
|
||||
(fn
|
||||
@@ -365,14 +365,14 @@
|
||||
(value type-name)
|
||||
(if (nil? value) false (hs-type-check value type-name))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define
|
||||
hs-strict-eq
|
||||
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define
|
||||
hs-falsy?
|
||||
(fn
|
||||
@@ -384,7 +384,8 @@
|
||||
((and (list? v) (= (len v) 0)) true)
|
||||
((= v 0) true)
|
||||
(true false))))
|
||||
|
||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||
;; Property access — dot notation and .length
|
||||
(define
|
||||
hs-matches?
|
||||
(fn
|
||||
@@ -393,8 +394,7 @@
|
||||
(string? target)
|
||||
(if (= pattern ".*") true (string-contains? target pattern))
|
||||
false)))
|
||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||
;; Property access — dot notation and .length
|
||||
;; DOM query stub — sandbox returns empty list
|
||||
(define
|
||||
hs-contains?
|
||||
(fn
|
||||
@@ -414,7 +414,7 @@
|
||||
true
|
||||
(hs-contains? (rest collection) item)))))
|
||||
(true false))))
|
||||
;; DOM query stub — sandbox returns empty list
|
||||
;; Method dispatch — obj.method(args)
|
||||
(define
|
||||
hs-empty?
|
||||
(fn
|
||||
@@ -425,13 +425,13 @@
|
||||
((list? v) (= (len v) 0))
|
||||
((dict? v) (= (len (keys v)) 0))
|
||||
(true false))))
|
||||
;; Method dispatch — obj.method(args)
|
||||
(define hs-first (fn (lst) (first lst)))
|
||||
|
||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||
;; beep! — debug logging, returns value unchanged
|
||||
(define hs-last (fn (lst) (last lst)))
|
||||
(define hs-first (fn (lst) (first lst)))
|
||||
;; Property-based is — check obj.key truthiness
|
||||
(define hs-last (fn (lst) (last lst)))
|
||||
;; Array slicing (inclusive both ends)
|
||||
(define
|
||||
hs-template
|
||||
(fn
|
||||
@@ -517,7 +517,7 @@
|
||||
(set! i (+ i 1))
|
||||
(tpl-loop)))))))
|
||||
(do (tpl-loop) result))))
|
||||
;; Array slicing (inclusive both ends)
|
||||
;; Collection: sorted by
|
||||
(define
|
||||
hs-make-object
|
||||
(fn
|
||||
@@ -529,7 +529,7 @@
|
||||
(fn (pair) (dict-set! d (first pair) (nth pair 1)))
|
||||
pairs)
|
||||
d))))
|
||||
;; Collection: sorted by
|
||||
;; Collection: sorted by descending
|
||||
(define
|
||||
hs-method-call
|
||||
(fn
|
||||
@@ -552,11 +552,11 @@
|
||||
(if (= (first lst) item) i (idx-loop (rest lst) (+ i 1))))))
|
||||
(idx-loop obj 0)))
|
||||
(true nil))))
|
||||
;; Collection: sorted by descending
|
||||
(define hs-beep (fn (v) v))
|
||||
;; Collection: split by
|
||||
(define hs-prop-is (fn (obj key) (not (hs-falsy? (host-get obj key)))))
|
||||
(define hs-beep (fn (v) v))
|
||||
;; Collection: joined by
|
||||
(define hs-prop-is (fn (obj key) (not (hs-falsy? (host-get obj key)))))
|
||||
|
||||
(define
|
||||
hs-slice
|
||||
(fn
|
||||
|
||||
Reference in New Issue
Block a user