Hyperscript examples: add Try it buttons, test stub VM continuation bug
- ~hyperscript/example component: shows "Try it" button with _= attr for all on-click examples, source pre wraps long lines - Added CSS for .active/.light/.dark demo classes with !important to override Tailwind hover states - Added #target div for the "put into" example - Replaced broken examples (items, ~card, js-date-now) with self-contained ones that use available primitives - Repeat example left in with note: continuation after loop pending - New test suite io-suspension-continuation documenting the stub VM bug: outer do continuation lost after suspension/resume completes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -85,3 +85,25 @@
|
||||
(fn () (io "totally-unknown-op-xyz"))
|
||||
(fn (err) (set! caught true)))
|
||||
(assert caught))))
|
||||
|
||||
(defsuite
|
||||
"io-suspension-continuation"
|
||||
(deftest
|
||||
"code after non-suspending call executes"
|
||||
(let
|
||||
((result (list)))
|
||||
(define f (fn () (set! result (append result "a"))))
|
||||
(do (f) (set! result (append result "b")))
|
||||
(assert= result (list "a" "b"))))
|
||||
(deftest
|
||||
"continuation after suspending lambda preserves outer do — BROWSER ONLY"
|
||||
(let
|
||||
((log (list)))
|
||||
(define
|
||||
non-suspending
|
||||
(fn () (set! log (append log "a")) (set! log (append log "b"))))
|
||||
(do (non-suspending) (set! log (append log "after-call")))
|
||||
(assert= log (list "a" "b" "after-call"))
|
||||
(assert
|
||||
true
|
||||
"passes without suspension — browser test needed for full verify: stub VM loses outer do continuation after cek_resume completes"))))
|
||||
|
||||
@@ -2,22 +2,67 @@
|
||||
;; Lives under Applications: /sx/(applications.(hyperscript))
|
||||
|
||||
;; ── Compile result component (server-side rendered) ─────────────
|
||||
sx-serialize
|
||||
(defcomp
|
||||
~hyperscript/compile-result
|
||||
(&key source)
|
||||
(if
|
||||
(or (nil? source) (empty? source))
|
||||
(p
|
||||
(~tw :tokens "text-sm text-gray-400 italic")
|
||||
"Enter some hyperscript and click Compile")
|
||||
(let
|
||||
((compiled (hs-to-sx-from-source source)))
|
||||
(div
|
||||
(~tw :tokens "space-y-4")
|
||||
(div
|
||||
(h4
|
||||
(~tw
|
||||
:tokens "text-xs font-semibold uppercase tracking-wider text-gray-500 mb-2")
|
||||
"Compiled SX")
|
||||
(pre
|
||||
(~tw
|
||||
:tokens "bg-gray-900 text-green-400 p-4 rounded-lg text-sm overflow-x-auto")
|
||||
(sx-serialize compiled)))
|
||||
(div
|
||||
(h4
|
||||
(~tw
|
||||
:tokens "text-xs font-semibold uppercase tracking-wider text-gray-500 mb-2")
|
||||
"Parse Tree")
|
||||
(pre
|
||||
(~tw
|
||||
:tokens "bg-gray-900 text-amber-400 p-4 rounded-lg text-sm overflow-x-auto")
|
||||
(sx-serialize (hs-compile source))))))))
|
||||
|
||||
;; ── Compile handler (POST endpoint) ─────────────────────────────
|
||||
(defcomp
|
||||
~hyperscript/example
|
||||
(&key source description)
|
||||
(div
|
||||
:class "border border-gray-200 rounded-lg p-4 space-y-3"
|
||||
(when description (p :class "text-sm text-gray-600" description))
|
||||
(~tw :tokens "border border-gray-200 rounded-lg p-4 mb-4")
|
||||
(when
|
||||
description
|
||||
(p (~tw :tokens "text-sm text-gray-600 mb-2") description))
|
||||
(div
|
||||
(h4
|
||||
:class "text-xs font-semibold uppercase tracking-wider text-gray-500 mb-1"
|
||||
"Source")
|
||||
(pre
|
||||
:class "bg-gray-50 text-gray-900 p-3 rounded text-sm font-mono"
|
||||
(str "_=\"" source "\"")))
|
||||
(~tw :tokens "flex gap-4 items-start mb-3")
|
||||
(div
|
||||
(~tw :tokens "flex-1")
|
||||
(h4
|
||||
(~tw
|
||||
:tokens "text-xs font-semibold uppercase tracking-wider text-gray-400 mb-1")
|
||||
"Source")
|
||||
(pre
|
||||
(~tw
|
||||
:tokens "bg-gray-50 text-gray-900 p-3 rounded text-sm font-mono whitespace-pre-wrap break-words")
|
||||
(str "_=\"" source "\"")))
|
||||
(when
|
||||
(string-contains? source "on click")
|
||||
(div
|
||||
(~tw :tokens "flex-shrink-0 pt-5")
|
||||
(button
|
||||
(~tw
|
||||
:tokens "px-4 py-2 border border-violet-300 rounded-lg text-sm font-medium text-violet-700 hover:bg-violet-50 transition-colors")
|
||||
:_ source
|
||||
"Try it"))))
|
||||
(~hyperscript/compile-result :source source)))
|
||||
|
||||
;; ── Pipeline example component ──────────────────────────────────
|
||||
@@ -36,7 +81,8 @@ sx-serialize
|
||||
"Hyperscript source")
|
||||
(textarea
|
||||
:name "source"
|
||||
:class "w-full h-24 font-mono text-sm p-3 border border-gray-300 rounded-lg bg-white focus:ring-2 focus:ring-violet-500 focus:border-violet-500"
|
||||
(~tw
|
||||
:tokens "w-full h-24 font-mono text-sm p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-violet-500 focus:border-transparent")
|
||||
"on click add .active to me"))
|
||||
(div
|
||||
(~tw :tokens "mt-2")
|
||||
@@ -54,25 +100,35 @@ sx-serialize
|
||||
~hyperscript/live-demo
|
||||
()
|
||||
(div
|
||||
:class "space-y-4"
|
||||
(~tw :tokens "space-y-4")
|
||||
(style
|
||||
"\n .bg-violet-600 { background-color: rgb(124 58 237); }\n .text-white { color: white; }\n .animate-bounce { animation: bounce 1s infinite; }\n @keyframes bounce {\n 0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8,0,1,1); }\n 50% { transform: none; animation-timing-function: cubic-bezier(0,0,0.2,1); }\n }\n ")
|
||||
(p
|
||||
:class "text-sm text-gray-600"
|
||||
"These buttons have actual hyperscript compiled to SX. Click them to see the behavior.")
|
||||
(~tw :tokens "text-sm text-gray-600")
|
||||
"These buttons have "
|
||||
(code "_=\"...\"")
|
||||
" attributes — hyperscript compiled to SX and activated at boot.")
|
||||
(div
|
||||
:class "flex gap-3 items-center"
|
||||
(~tw :tokens "flex gap-3 items-center")
|
||||
(button
|
||||
:class "px-4 py-2 border border-gray-300 rounded-lg text-sm transition-colors"
|
||||
(~tw
|
||||
:tokens "px-4 py-2 border border-gray-300 rounded-lg text-sm transition-colors")
|
||||
:_ "on click toggle .bg-violet-600 on me then toggle .text-white on me"
|
||||
"Toggle Color")
|
||||
(button
|
||||
:class "px-4 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
(~tw
|
||||
:tokens "px-4 py-2 border border-gray-300 rounded-lg text-sm transition-colors")
|
||||
:_ "on click add .animate-bounce to me then wait 1s then remove .animate-bounce from me"
|
||||
"Bounce")
|
||||
(span :class "text-sm text-gray-500" :id "click-counter" "0 clicks"))
|
||||
(span
|
||||
(~tw :tokens "text-sm text-gray-500")
|
||||
:id "click-counter"
|
||||
"0 clicks"))
|
||||
(div
|
||||
:class "mt-2"
|
||||
(~tw :tokens "mt-2")
|
||||
(button
|
||||
:class "px-4 py-2 border border-gray-300 rounded-lg text-sm"
|
||||
(~tw
|
||||
:tokens "px-4 py-2 border border-gray-300 rounded-lg text-sm transition-colors")
|
||||
:_ "on click increment @data-count on me then set #click-counter's innerHTML to my @data-count"
|
||||
:data-count "0"
|
||||
"Count Clicks"))))
|
||||
@@ -97,6 +153,14 @@ sx-serialize
|
||||
(p
|
||||
"Edit the hyperscript source and click Compile to see the tokenized, parsed, and compiled SX output.")
|
||||
(~hyperscript/playground))
|
||||
(~docs/section
|
||||
:title "Live Demo"
|
||||
:id "live-demo"
|
||||
(p
|
||||
"These buttons have "
|
||||
(code "_=\"...\"")
|
||||
" attributes — hyperscript compiled to SX and activated at boot.")
|
||||
(~hyperscript/live-demo))
|
||||
(~docs/section
|
||||
:title "Pipeline"
|
||||
:id "pipeline"
|
||||
@@ -125,6 +189,8 @@ sx-serialize
|
||||
(~docs/section
|
||||
:title "Examples"
|
||||
:id "examples"
|
||||
(style
|
||||
"\n button.active { background-color: #7c3aed !important; color: white !important; border-color: #7c3aed !important; }\n button.active:hover { background-color: #6d28d9 !important; }\n button.light { background-color: #fef3c7 !important; color: #92400e !important; border-color: #f59e0b !important; }\n button.light:hover { background-color: #fde68a !important; }\n button.dark { background-color: #1e293b !important; color: #e2e8f0 !important; border-color: #475569 !important; }\n button.dark:hover { background-color: #334155 !important; }\n .animate-bounce { animation: bounce 1s; }\n @keyframes bounce {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(-25%); }\n }")
|
||||
(~hyperscript/example
|
||||
:source "on click add .active to me"
|
||||
:description "Event handler: click adds a CSS class")
|
||||
@@ -132,17 +198,22 @@ sx-serialize
|
||||
:source "on click toggle between .light and .dark on me"
|
||||
:description "Toggle between two states")
|
||||
(~hyperscript/example
|
||||
:source "on click set my innerHTML to eval (str \"Clicked at \" (js-date-now))"
|
||||
:description "SX escape: call SX functions from hyperscript, variables flow through")
|
||||
:source "on click set my innerHTML to eval (str \"Hello from \" (+ 2 3) \" worlds\")"
|
||||
:description "SX escape: evaluate SX expressions from hyperscript")
|
||||
(~hyperscript/example
|
||||
:source "on click render ~card :title 'Hello' into #target"
|
||||
:description "Render an SX component directly from a hyperscript handler")
|
||||
:source "on click put \"<b>Rendered!</b>\" into #target"
|
||||
:description "Target another element by CSS selector")
|
||||
(div
|
||||
:id "target"
|
||||
(~tw
|
||||
:tokens "border border-dashed border-gray-300 rounded-lg p-3 min-h-[2rem] text-sm text-gray-400")
|
||||
"← render target")
|
||||
(~hyperscript/example
|
||||
:source "def double(n) return n + n end"
|
||||
:description "Define reusable functions")
|
||||
(~hyperscript/example
|
||||
:source "on click for item in items log item end"
|
||||
:description "Iteration over collections")
|
||||
:source "on click repeat 3 times add .active to me then wait 300ms then remove .active from me then wait 300ms end"
|
||||
:description "Iteration: repeat with timed animation (continuation after loop pending)")
|
||||
(~hyperscript/example
|
||||
:source "behavior Draggable on mousedown add .dragging to me end on mouseup remove .dragging from me end end"
|
||||
:description "Reusable behaviors — install on any element"))))
|
||||
Reference in New Issue
Block a user