feat(runtime): support slhx drag drops

req: htmx_equivalents/002

req: dx/008

req: list/003

req: examples/001
This commit is contained in:
slhx agent
2026-05-11 07:59:32 +02:00
parent ad8806c187
commit 816552e735
6 changed files with 39 additions and 38 deletions
+19 -3
View File
@@ -10,6 +10,7 @@
const timers = new WeakMap();
const sseSources = new WeakMap();
const atomStores = new WeakMap();
const dragKeys = new WeakMap();
function roots() {
return Array.from(document.querySelectorAll(`[${ROOT}]`));
@@ -51,11 +52,13 @@
}
}
function formDataFor(el) {
function formDataFor(el, eventName) {
const form = el.tagName === "FORM" ? el : el.closest("form");
const data = form ? new FormData(form) : new FormData();
const id = handleId(el) || (form && handleId(form));
if (id && !data.has("__h")) data.set("__h", id);
const dragKey = eventName === "drop" && dragKeys.get(rootOf(el));
if (dragKey && !data.has("work_id")) data.set("work_id", dragKey);
for (const { name, value } of Array.from(el.attributes || [])) {
if (name.startsWith("data-") && !name.startsWith("data-slhx-") && name !== HID && name !== SID) {
data.set(name.slice(5).replace(/-/g, "_"), value);
@@ -85,7 +88,7 @@
async function send(el, eventName) {
if (el.getAttribute("data-slhx-confirm") && !confirm(el.getAttribute("data-slhx-confirm"))) return;
const { form, data, multipart } = formDataFor(el);
const { form, data, multipart } = formDataFor(el, eventName);
const target = form || el;
const policy = requestPolicy(target, eventName);
const active = pending.get(target);
@@ -386,8 +389,21 @@
}
function bindRoot(root) {
["click", "submit", "input", "change"].forEach((name) => {
["click", "submit", "input", "change", "dragstart", "dragover", "drop"].forEach((name) => {
root.addEventListener(name, (event) => {
if (name === "dragstart") {
const item = closestInRoot(event.target, root, "[data-key]");
if (item) {
dragKeys.set(root, item.getAttribute("data-key"));
if (event.dataTransfer) event.dataTransfer.setData("text/plain", item.getAttribute("data-key"));
}
return;
}
if (name === "dragover") {
const drop = closestInRoot(event.target, root, `[${HID}][data-slhx-on="drop"]`);
if (drop) event.preventDefault();
return;
}
const nav = closestInRoot(event.target, root, "a[data-slhx-nav], [data-slhx-boost] a[href]");
if (name === "click" && nav && sameOriginNav(event, nav)) {
event.preventDefault();
+12
View File
@@ -27,6 +27,18 @@ fn runtime_clicking_submitter_schedules_form_submit() {
assert!(source.contains("schedule(form, \"submit\")"));
}
#[test]
fn runtime_supports_drag_drop_params_without_user_js() {
// req: htmx_equivalents/002, req: dx/008
let source = slhx_js::RUNTIME_JS;
assert!(source.contains("const dragKeys = new WeakMap()"));
assert!(source.contains("dragstart"));
assert!(source.contains("dragover"));
assert!(source.contains("eventName === \"drop\""));
assert!(source.contains("data.set(\"work_id\", dragKey)"));
}
#[test]
fn runtime_supports_queued_request_policy() {
let source = slhx_js::RUNTIME_JS;