Fix keyboard shortcuts + trigger filter + sx-on event mapping
1. parse-trigger-spec: strip [condition] from event names, store as "filter" modifier 2. bind-event: native SX filter for key=='X' patterns (extracts key char and checks event.key + not-input guard) 3. bind-event from: modifier: resolve "body"/"document"/"window" to direct DOM references instead of dom-query 4. sx-platform-2.js: global keyboard dispatch — WASM host-callbacks on document/body don't fire, so keyboard triggers with from:body are handled from JS, calling execute-request via K.eval 5. bind-inline-handlers: map afterSwap/beforeRequest to sx: prefix, eval JS bodies via Function constructor Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -398,6 +398,22 @@
|
||||
"children:", islands[j].children.length);
|
||||
}
|
||||
console.log("[sx] boot done");
|
||||
|
||||
// Global keyboard shortcut dispatch — WASM host-callbacks on
|
||||
// document/body don't fire, so handle from:body keyboard
|
||||
// triggers in JS and call execute-request via the SX engine.
|
||||
document.addEventListener("keyup", function(e) {
|
||||
if (e.target && e.target.matches && e.target.matches("input,textarea,select")) return;
|
||||
var sel = '[sx-trigger*="key==\'' + e.key + '\'"]';
|
||||
var els = document.querySelectorAll(sel);
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
var el = els[i];
|
||||
if (!el.id) el.id = "_sx_kbd_" + Math.random().toString(36).slice(2);
|
||||
try {
|
||||
K.eval('(execute-request (dom-query-by-id "' + el.id + '") nil nil)');
|
||||
} catch(err) { console.warn("[sx] keyboard dispatch error:", err); }
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
1
shared/static/wasm/sx/adapter-dom.sxbc.json
Normal file
1
shared/static/wasm/sx/adapter-dom.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/adapter-html.sxbc.json
Normal file
1
shared/static/wasm/sx/adapter-html.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/adapter-sx.sxbc.json
Normal file
1
shared/static/wasm/sx/adapter-sx.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/boot-helpers.sxbc.json
Normal file
1
shared/static/wasm/sx/boot-helpers.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/boot.sxbc.json
Normal file
1
shared/static/wasm/sx/boot.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/browser.sxbc.json
Normal file
1
shared/static/wasm/sx/browser.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/bytecode.sxbc.json
Normal file
1
shared/static/wasm/sx/bytecode.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/compiler.sxbc.json
Normal file
1
shared/static/wasm/sx/compiler.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/core-signals.sxbc.json
Normal file
1
shared/static/wasm/sx/core-signals.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/cssx.sxbc.json
Normal file
1
shared/static/wasm/sx/cssx.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/deps.sxbc.json
Normal file
1
shared/static/wasm/sx/deps.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/dom.sxbc.json
Normal file
1
shared/static/wasm/sx/dom.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/engine.sxbc.json
Normal file
1
shared/static/wasm/sx/engine.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/freeze.sxbc.json
Normal file
1
shared/static/wasm/sx/freeze.sxbc.json
Normal file
@@ -0,0 +1 @@
|
||||
{"magic":"SXBC","version":1,"hash":"bfa1b3e64a390451","module":{"arity":0,"bytecode":[52,1,0,0,128,0,0,5,51,3,0,128,2,0,5,51,5,0,128,4,0,5,51,7,0,128,6,0,5,51,9,0,128,8,0,5,51,11,0,128,10,0,5,51,13,0,128,12,0,5,51,15,0,128,14,0,5,51,17,0,128,16,0,50],"constants":[{"t":"s","v":"freeze-registry"},{"t":"s","v":"dict"},{"t":"s","v":"freeze-signal"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,1,1,0,2,48,2,17,2,20,2,0,33,62,0,20,4,0,20,2,0,52,3,0,2,6,34,5,0,5,52,5,0,0,17,3,20,6,0,20,7,0,1,9,0,20,9,0,1,10,0,20,11,0,52,8,0,4,48,2,5,20,4,0,20,2,0,20,7,0,52,12,0,3,32,1,0,2,50],"constants":[{"t":"s","v":"context"},{"t":"s","v":"sx-freeze-scope"},{"t":"s","v":"scope-name"},{"t":"s","v":"get"},{"t":"s","v":"freeze-registry"},{"t":"s","v":"list"},{"t":"s","v":"append!"},{"t":"s","v":"entries"},{"t":"s","v":"dict"},{"t":"s","v":"name"},{"t":"s","v":"signal"},{"t":"s","v":"sig"},{"t":"s","v":"dict-set!"}]}},{"t":"s","v":"freeze-scope"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,1,1,0,20,2,0,48,2,5,20,4,0,20,2,0,52,5,0,0,52,3,0,3,5,20,6,0,20,7,0,2,48,2,5,20,8,0,1,1,0,48,1,5,2,50],"constants":[{"t":"s","v":"scope-push!"},{"t":"s","v":"sx-freeze-scope"},{"t":"s","v":"name"},{"t":"s","v":"dict-set!"},{"t":"s","v":"freeze-registry"},{"t":"s","v":"list"},{"t":"s","v":"cek-call"},{"t":"s","v":"body-fn"},{"t":"s","v":"scope-pop!"}]}},{"t":"s","v":"cek-freeze-scope"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,1,0,20,2,0,52,0,0,2,6,34,5,0,5,52,3,0,0,17,1,52,4,0,0,17,2,51,6,0,20,7,0,52,5,0,2,5,1,2,0,20,2,0,1,8,0,20,9,0,52,4,0,4,50],"constants":[{"t":"s","v":"get"},{"t":"s","v":"freeze-registry"},{"t":"s","v":"name"},{"t":"s","v":"list"},{"t":"s","v":"dict"},{"t":"s","v":"for-each"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,1,0,20,3,0,1,4,0,52,2,0,2,20,5,0,20,3,0,1,6,0,52,2,0,2,48,1,52,0,0,3,50],"constants":[{"t":"s","v":"dict-set!"},{"t":"s","v":"signals-dict"},{"t":"s","v":"get"},{"t":"s","v":"entry"},{"t":"s","v":"name"},{"t":"s","v":"signal-value"},{"t":"s","v":"signal"}]}},{"t":"s","v":"entries"},{"t":"s","v":"signals"},{"t":"s","v":"signals-dict"}]}},{"t":"s","v":"cek-freeze-all"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[51,1,0,20,3,0,52,2,0,1,52,0,0,2,50],"constants":[{"t":"s","v":"map"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,49,1,50],"constants":[{"t":"s","v":"cek-freeze-scope"},{"t":"s","v":"name"}]}},{"t":"s","v":"keys"},{"t":"s","v":"freeze-registry"}]}},{"t":"s","v":"cek-thaw-scope"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,1,0,20,2,0,52,0,0,2,6,34,5,0,5,52,3,0,0,17,2,20,4,0,1,5,0,52,0,0,2,17,3,20,6,0,33,13,0,51,8,0,20,9,0,52,7,0,2,32,1,0,2,50],"constants":[{"t":"s","v":"get"},{"t":"s","v":"freeze-registry"},{"t":"s","v":"name"},{"t":"s","v":"list"},{"t":"s","v":"frozen"},{"t":"s","v":"signals"},{"t":"s","v":"values"},{"t":"s","v":"for-each"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,1,0,1,2,0,52,0,0,2,17,1,20,1,0,1,3,0,52,0,0,2,17,2,20,4,0,20,5,0,52,0,0,2,17,3,20,8,0,52,7,0,1,52,6,0,1,33,14,0,20,9,0,20,10,0,20,8,0,49,2,32,1,0,2,50],"constants":[{"t":"s","v":"get"},{"t":"s","v":"entry"},{"t":"s","v":"name"},{"t":"s","v":"signal"},{"t":"s","v":"values"},{"t":"s","v":"sig-name"},{"t":"s","v":"not"},{"t":"s","v":"nil?"},{"t":"s","v":"val"},{"t":"s","v":"reset!"},{"t":"s","v":"sig"}]}},{"t":"s","v":"entries"}]}},{"t":"s","v":"cek-thaw-all"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[51,1,0,20,2,0,52,0,0,2,50],"constants":[{"t":"s","v":"for-each"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,2,0,1,3,0,52,1,0,2,20,2,0,49,2,50],"constants":[{"t":"s","v":"cek-thaw-scope"},{"t":"s","v":"get"},{"t":"s","v":"frozen"},{"t":"s","v":"name"}]}},{"t":"s","v":"frozen-list"}]}},{"t":"s","v":"freeze-to-sx"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,20,2,0,48,1,49,1,50],"constants":[{"t":"s","v":"sx-serialize"},{"t":"s","v":"cek-freeze-scope"},{"t":"s","v":"name"}]}},{"t":"s","v":"thaw-from-sx"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,48,1,17,1,20,4,0,52,3,0,1,52,2,0,1,33,30,0,20,4,0,52,5,0,1,17,2,20,6,0,20,8,0,1,9,0,52,7,0,2,20,8,0,49,2,32,1,0,2,50],"constants":[{"t":"s","v":"sx-parse"},{"t":"s","v":"sx-text"},{"t":"s","v":"not"},{"t":"s","v":"empty?"},{"t":"s","v":"parsed"},{"t":"s","v":"first"},{"t":"s","v":"cek-thaw-scope"},{"t":"s","v":"get"},{"t":"s","v":"frozen"},{"t":"s","v":"name"}]}}]}}
|
||||
1
shared/static/wasm/sx/harness-reactive.sxbc.json
Normal file
1
shared/static/wasm/sx/harness-reactive.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/harness-web.sxbc.json
Normal file
1
shared/static/wasm/sx/harness-web.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/harness.sxbc.json
Normal file
1
shared/static/wasm/sx/harness.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/hypersx.sxbc.json
Normal file
1
shared/static/wasm/sx/hypersx.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
@@ -453,7 +453,18 @@
|
||||
((timer nil)
|
||||
(last-val nil)
|
||||
(listen-target
|
||||
(if (get mods "from") (dom-query (get mods "from")) el)))
|
||||
(let
|
||||
((from-sel (get mods "from")))
|
||||
(cond
|
||||
(nil? from-sel)
|
||||
el
|
||||
(= from-sel "body")
|
||||
(dom-body)
|
||||
(= from-sel "document")
|
||||
(dom-document)
|
||||
(= from-sel "window")
|
||||
(dom-window)
|
||||
:else (dom-query from-sel)))))
|
||||
(when
|
||||
listen-target
|
||||
(dom-add-listener
|
||||
@@ -462,7 +473,7 @@
|
||||
(fn
|
||||
(e)
|
||||
(let
|
||||
((should-fire (if (get mods "filter") (host-call (host-call (dom-window) "Function" "event" (get mods "filter")) "call" el e) true)))
|
||||
((should-fire (if (get mods "filter") (let ((f (get mods "filter"))) (let ((key-match (index-of f "key=='"))) (if (>= key-match 0) (let ((key-char (slice f (+ key-match 5) (+ key-match 6)))) (and (= (host-get e "key") key-char) (not (dom-matches? (host-get e "target") "input,textarea,select")))) true))) true)))
|
||||
(when
|
||||
(get mods "changed")
|
||||
(let
|
||||
@@ -1492,7 +1503,7 @@
|
||||
verb-info
|
||||
(when
|
||||
(not (dom-has-attr? el "sx-disable"))
|
||||
(bind-triggers el verb-info)
|
||||
(do (bind-triggers el verb-info) (bind-preload-for el))
|
||||
(bind-preload-for el))))))
|
||||
|
||||
(define
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/orchestration.sxbc.json
Normal file
1
shared/static/wasm/sx/orchestration.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/page-helpers.sxbc.json
Normal file
1
shared/static/wasm/sx/page-helpers.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/render.sxbc.json
Normal file
1
shared/static/wasm/sx/render.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/router.sxbc.json
Normal file
1
shared/static/wasm/sx/router.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
1
shared/static/wasm/sx/signals.sxbc.json
Normal file
1
shared/static/wasm/sx/signals.sxbc.json
Normal file
@@ -0,0 +1 @@
|
||||
{"magic":"SXBC","version":1,"hash":"5c28976e14b0d85b","module":{"arity":0,"bytecode":[51,1,0,128,0,0,5,51,3,0,128,2,0,5,51,5,0,128,4,0,5,51,7,0,128,6,0,5,51,9,0,128,8,0,5,51,11,0,128,10,0,50],"constants":[{"t":"s","v":"with-marsh-scope"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[52,0,0,0,17,2,20,1,0,51,2,0,20,3,0,48,2,5,20,4,0,20,5,0,1,6,0,20,7,0,49,3,50],"constants":[{"t":"s","v":"list"},{"t":"s","v":"with-island-scope"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,20,2,0,49,2,50],"constants":[{"t":"s","v":"append!"},{"t":"s","v":"disposers"},{"t":"s","v":"d"}]}},{"t":"s","v":"body-fn"},{"t":"s","v":"dom-set-data"},{"t":"s","v":"marsh-el"},{"t":"s","v":"sx-marsh-disposers"},{"t":"s","v":"disposers"}]}},{"t":"s","v":"dispose-marsh-scope"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,1,2,0,48,2,17,1,20,3,0,33,26,0,51,5,0,20,3,0,52,4,0,2,5,20,6,0,20,1,0,1,2,0,2,49,3,32,1,0,2,50],"constants":[{"t":"s","v":"dom-get-data"},{"t":"s","v":"marsh-el"},{"t":"s","v":"sx-marsh-disposers"},{"t":"s","v":"disposers"},{"t":"s","v":"for-each"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,2,49,2,50],"constants":[{"t":"s","v":"cek-call"},{"t":"s","v":"d"}]}},{"t":"s","v":"dom-set-data"}]}},{"t":"s","v":"emit-event"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,20,2,0,20,3,0,49,3,50],"constants":[{"t":"s","v":"dom-dispatch"},{"t":"s","v":"el"},{"t":"s","v":"event-name"},{"t":"s","v":"detail"}]}},{"t":"s","v":"on-event"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,20,2,0,20,3,0,49,3,50],"constants":[{"t":"s","v":"dom-on"},{"t":"s","v":"el"},{"t":"s","v":"event-name"},{"t":"s","v":"handler"}]}},{"t":"s","v":"bridge-event"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,51,1,0,49,1,50],"constants":[{"t":"s","v":"effect"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,20,2,0,51,3,0,48,3,17,0,20,4,0,50],"constants":[{"t":"s","v":"dom-on"},{"t":"s","v":"el"},{"t":"s","v":"event-name"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,48,1,17,1,20,2,0,33,18,0,20,3,0,20,2,0,20,5,0,52,4,0,1,48,2,32,3,0,20,5,0,17,2,20,6,0,20,7,0,20,8,0,49,2,50],"constants":[{"t":"s","v":"event-detail"},{"t":"s","v":"e"},{"t":"s","v":"transform-fn"},{"t":"s","v":"cek-call"},{"t":"s","v":"list"},{"t":"s","v":"detail"},{"t":"s","v":"reset!"},{"t":"s","v":"target-signal"},{"t":"s","v":"new-val"}]}},{"t":"s","v":"remove"}]}}]}},{"t":"s","v":"resource"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,1,2,0,3,1,3,0,2,1,4,0,2,52,1,0,6,48,1,17,1,20,5,0,20,6,0,20,7,0,2,48,2,51,8,0,51,9,0,48,3,5,20,10,0,50],"constants":[{"t":"s","v":"signal"},{"t":"s","v":"dict"},{"t":"s","v":"loading"},{"t":"s","v":"data"},{"t":"s","v":"error"},{"t":"s","v":"promise-then"},{"t":"s","v":"cek-call"},{"t":"s","v":"fetch-fn"},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,1,3,0,4,1,4,0,20,4,0,1,5,0,2,52,2,0,6,49,2,50],"constants":[{"t":"s","v":"reset!"},{"t":"s","v":"state"},{"t":"s","v":"dict"},{"t":"s","v":"loading"},{"t":"s","v":"data"},{"t":"s","v":"error"}]}},{"t":"code","v":{"arity":0,"upvalue-count":0,"bytecode":[20,0,0,20,1,0,1,3,0,4,1,4,0,2,1,5,0,20,6,0,52,2,0,6,49,2,50],"constants":[{"t":"s","v":"reset!"},{"t":"s","v":"state"},{"t":"s","v":"dict"},{"t":"s","v":"loading"},{"t":"s","v":"data"},{"t":"s","v":"error"},{"t":"s","v":"err"}]}},{"t":"s","v":"state"}]}}]}}
|
||||
1
shared/static/wasm/sx/vm.sxbc.json
Normal file
1
shared/static/wasm/sx/vm.sxbc.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
shared/static/wasm/sx_browser.bc.wasm.assets/sx-3b0282d1.wasm
Normal file
BIN
shared/static/wasm/sx_browser.bc.wasm.assets/sx-3b0282d1.wasm
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1792,7 +1792,7 @@
|
||||
blake2_js_for_wasm_create: blake2_js_for_wasm_create};
|
||||
}
|
||||
(globalThis))
|
||||
({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-afdcb8e8",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-8ae21d0a",[2,3,5]],["std_exit-10fb8830",[2]],["start-80fdb768",0]],"generated":(b=>{var
|
||||
({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["sx-3b0282d1",[2]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,4]],["dune__exe__Sx_browser-8ae21d0a",[2,3,5]],["std_exit-10fb8830",[2]],["start-80fdb768",0]],"generated":(b=>{var
|
||||
c=b,a=b?.module?.export||b;return{"env":{"caml_ba_kind_of_typed_array":()=>{throw new
|
||||
Error("caml_ba_kind_of_typed_array not implemented")},"caml_exn_with_js_backtrace":()=>{throw new
|
||||
Error("caml_exn_with_js_backtrace not implemented")},"caml_int64_create_lo_mi_hi":()=>{throw new
|
||||
|
||||
Reference in New Issue
Block a user