@jsswift/core 1.0.51 → 1.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cms.js +172 -161
- package/dist/cms.min.js +1 -1
- package/dist/min-cms.js +1 -1
- package/package.json +1 -1
- package/src/10-overlay.js +3 -4
- package/src/31-rod-model.js +169 -157
package/dist/cms.js
CHANGED
|
@@ -661,8 +661,7 @@
|
|
|
661
661
|
const schedulePosition = () => {
|
|
662
662
|
if (!opts.anchorEl) return;
|
|
663
663
|
const raf = globalThis.requestAnimationFrame || ((fn) => setTimeout(() => fn(Date.now()), 0));
|
|
664
|
-
|
|
665
|
-
if (entry._positionFrame != null) caf(entry._positionFrame);
|
|
664
|
+
if (entry._positionFrame != null) return;
|
|
666
665
|
entry._positionFrame = raf(() => {
|
|
667
666
|
entry._positionFrame = null;
|
|
668
667
|
position();
|
|
@@ -673,13 +672,13 @@
|
|
|
673
672
|
if (opts.anchorEl) {
|
|
674
673
|
position();
|
|
675
674
|
schedulePosition();
|
|
676
|
-
const onResize =
|
|
675
|
+
const onResize = schedulePosition;
|
|
677
676
|
window.addEventListener("resize", onResize);
|
|
678
677
|
window.addEventListener("scroll", onResize, true);
|
|
679
678
|
window.visualViewport?.addEventListener?.("resize", onResize);
|
|
680
679
|
window.visualViewport?.addEventListener?.("scroll", onResize);
|
|
681
680
|
if (typeof ResizeObserver === "function") {
|
|
682
|
-
const panelResizeObserver = new ResizeObserver(
|
|
681
|
+
const panelResizeObserver = new ResizeObserver(schedulePosition);
|
|
683
682
|
panelResizeObserver.observe(panel);
|
|
684
683
|
entry._panelResizeObserver = panelResizeObserver;
|
|
685
684
|
}
|
|
@@ -2340,163 +2339,175 @@ _.dynamic = function (renderFn) {
|
|
|
2340
2339
|
|
|
2341
2340
|
return r;
|
|
2342
2341
|
};
|
|
2343
|
-
// ===============================
|
|
2344
|
-
// Two-way binding: input <-> rod
|
|
2345
|
-
// ===============================
|
|
2346
|
-
// ===============================
|
|
2347
|
-
// Two-way binding avanzato
|
|
2348
|
-
// input / checkbox / radio / select
|
|
2349
|
-
// ===============================
|
|
2350
|
-
|
|
2351
|
-
function getInputKind(el) {
|
|
2352
|
-
if (!el || !el.tagName) return null;
|
|
2353
|
-
|
|
2354
|
-
const tag = el.tagName.toLowerCase();
|
|
2355
|
-
|
|
2356
|
-
if (tag === "input") {
|
|
2357
|
-
const type = (el.type || "text").toLowerCase();
|
|
2358
|
-
if (type === "checkbox") return "checkbox";
|
|
2359
|
-
if (type === "radio") return "radio";
|
|
2360
|
-
if (type === "number") return "number";
|
|
2361
|
-
return "text";
|
|
2362
|
-
}
|
|
2363
|
-
|
|
2364
|
-
if (tag === "select") {
|
|
2365
|
-
return el.multiple ? "select-multiple" : "select";
|
|
2366
|
-
}
|
|
2367
|
-
|
|
2368
|
-
return null;
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
|
-
JSswift.rodModel = function (target, rodObj, opts = {}) {
|
|
2372
|
-
if (!rodObj || rodObj.type !== "rod") {
|
|
2373
|
-
throw new Error("[JSswift.rodModel] rodObj deve essere un rod");
|
|
2374
|
-
}
|
|
2375
|
-
|
|
2376
|
-
// Supporta singolo elemento o lista (radio)
|
|
2377
|
-
const elements = Array.isArray(target) || target instanceof NodeList
|
|
2378
|
-
? Array.from(target)
|
|
2379
|
-
: [target];
|
|
2380
|
-
|
|
2381
|
-
const eventName = opts.event ?? "change";
|
|
2382
|
-
const parse = opts.parse ?? (v => v);
|
|
2383
|
-
const format = opts.format ?? (v => v);
|
|
2384
|
-
|
|
2385
|
-
let syncing = false;
|
|
2386
|
-
const disposers = [];
|
|
2387
|
-
|
|
2388
|
-
// === ROD → DOM ===
|
|
2389
|
-
const updateDOM = (value) => {
|
|
2390
|
-
for (const el of elements) {
|
|
2391
|
-
if (!el) continue;
|
|
2392
|
-
const kind = getInputKind(el);
|
|
2393
|
-
|
|
2394
|
-
switch (kind) {
|
|
2395
|
-
case "checkbox":
|
|
2396
|
-
el.checked = !!value;
|
|
2397
|
-
break;
|
|
2398
|
-
|
|
2399
|
-
case "radio":
|
|
2400
|
-
el.checked = el.value == value;
|
|
2401
|
-
break;
|
|
2402
|
-
|
|
2403
|
-
case "select":
|
|
2404
|
-
el.value = value ?? "";
|
|
2405
|
-
break;
|
|
2406
|
-
|
|
2407
|
-
case "select-multiple":
|
|
2408
|
-
const arr = Array.isArray(value) ? value.map(String) : [];
|
|
2409
|
-
for (const opt of el.options) {
|
|
2410
|
-
opt.selected = arr.includes(opt.value);
|
|
2411
|
-
}
|
|
2412
|
-
break;
|
|
2413
|
-
|
|
2414
|
-
case "number":
|
|
2415
|
-
case "text":
|
|
2416
|
-
default:
|
|
2417
|
-
el.value = value ?? "";
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
};
|
|
2421
|
-
|
|
2422
|
-
// bind rod → DOM (usa rod.action)
|
|
2423
|
-
|
|
2424
|
-
if (syncing) return;
|
|
2425
|
-
syncing = true;
|
|
2426
|
-
try {
|
|
2427
|
-
updateDOM(format(v));
|
|
2428
|
-
} finally {
|
|
2429
|
-
syncing = false;
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2342
|
+
// ===============================
|
|
2343
|
+
// Two-way binding: input <-> rod
|
|
2344
|
+
// ===============================
|
|
2345
|
+
// ===============================
|
|
2346
|
+
// Two-way binding avanzato
|
|
2347
|
+
// input / checkbox / radio / select
|
|
2348
|
+
// ===============================
|
|
2349
|
+
|
|
2350
|
+
function getInputKind(el) {
|
|
2351
|
+
if (!el || !el.tagName) return null;
|
|
2352
|
+
|
|
2353
|
+
const tag = el.tagName.toLowerCase();
|
|
2354
|
+
|
|
2355
|
+
if (tag === "input") {
|
|
2356
|
+
const type = (el.type || "text").toLowerCase();
|
|
2357
|
+
if (type === "checkbox") return "checkbox";
|
|
2358
|
+
if (type === "radio") return "radio";
|
|
2359
|
+
if (type === "number") return "number";
|
|
2360
|
+
return "text";
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
if (tag === "select") {
|
|
2364
|
+
return el.multiple ? "select-multiple" : "select";
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
return null;
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
JSswift.rodModel = function (target, rodObj, opts = {}) {
|
|
2371
|
+
if (!rodObj || rodObj.type !== "rod") {
|
|
2372
|
+
throw new Error("[JSswift.rodModel] rodObj deve essere un rod");
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
// Supporta singolo elemento o lista (radio)
|
|
2376
|
+
const elements = Array.isArray(target) || target instanceof NodeList
|
|
2377
|
+
? Array.from(target)
|
|
2378
|
+
: [target];
|
|
2379
|
+
|
|
2380
|
+
const eventName = opts.event ?? "change";
|
|
2381
|
+
const parse = opts.parse ?? (v => v);
|
|
2382
|
+
const format = opts.format ?? (v => v);
|
|
2383
|
+
|
|
2384
|
+
let syncing = false;
|
|
2385
|
+
const disposers = [];
|
|
2386
|
+
|
|
2387
|
+
// === ROD → DOM ===
|
|
2388
|
+
const updateDOM = (value) => {
|
|
2389
|
+
for (const el of elements) {
|
|
2390
|
+
if (!el) continue;
|
|
2391
|
+
const kind = getInputKind(el);
|
|
2392
|
+
|
|
2393
|
+
switch (kind) {
|
|
2394
|
+
case "checkbox":
|
|
2395
|
+
el.checked = !!value;
|
|
2396
|
+
break;
|
|
2397
|
+
|
|
2398
|
+
case "radio":
|
|
2399
|
+
el.checked = el.value == value;
|
|
2400
|
+
break;
|
|
2401
|
+
|
|
2402
|
+
case "select":
|
|
2403
|
+
el.value = value ?? "";
|
|
2404
|
+
break;
|
|
2405
|
+
|
|
2406
|
+
case "select-multiple":
|
|
2407
|
+
const arr = Array.isArray(value) ? value.map(String) : [];
|
|
2408
|
+
for (const opt of el.options) {
|
|
2409
|
+
opt.selected = arr.includes(opt.value);
|
|
2410
|
+
}
|
|
2411
|
+
break;
|
|
2412
|
+
|
|
2413
|
+
case "number":
|
|
2414
|
+
case "text":
|
|
2415
|
+
default:
|
|
2416
|
+
el.value = value ?? "";
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2420
|
+
|
|
2421
|
+
// bind rod → DOM (usa rod.action)
|
|
2422
|
+
const onValue = (v) => {
|
|
2423
|
+
if (syncing) return;
|
|
2424
|
+
syncing = true;
|
|
2425
|
+
try {
|
|
2426
|
+
updateDOM(format(v));
|
|
2427
|
+
} finally {
|
|
2428
|
+
syncing = false;
|
|
2429
|
+
}
|
|
2430
|
+
};
|
|
2431
|
+
rodObj.action(onValue);
|
|
2432
|
+
|
|
2433
|
+
// sync iniziale
|
|
2434
|
+
updateDOM(format(rodObj.value));
|
|
2435
|
+
|
|
2436
|
+
// === DOM → ROD ===
|
|
2437
|
+
for (const el of elements) {
|
|
2438
|
+
if (!el) continue;
|
|
2439
|
+
|
|
2440
|
+
const kind = getInputKind(el);
|
|
2441
|
+
|
|
2442
|
+
const handler = () => {
|
|
2443
|
+
if (syncing) return;
|
|
2444
|
+
|
|
2445
|
+
let next;
|
|
2446
|
+
|
|
2447
|
+
switch (kind) {
|
|
2448
|
+
case "checkbox":
|
|
2449
|
+
next = el.checked;
|
|
2450
|
+
break;
|
|
2451
|
+
|
|
2452
|
+
case "radio":
|
|
2453
|
+
if (!el.checked) return;
|
|
2454
|
+
next = el.value;
|
|
2455
|
+
break;
|
|
2456
|
+
|
|
2457
|
+
case "select":
|
|
2458
|
+
next = el.value;
|
|
2459
|
+
break;
|
|
2460
|
+
|
|
2461
|
+
case "select-multiple":
|
|
2462
|
+
next = Array.from(el.selectedOptions).map(o => o.value);
|
|
2463
|
+
break;
|
|
2464
|
+
|
|
2465
|
+
case "number":
|
|
2466
|
+
next = parse(el.value === "" ? null : Number(el.value));
|
|
2467
|
+
break;
|
|
2468
|
+
|
|
2469
|
+
case "text":
|
|
2470
|
+
default:
|
|
2471
|
+
next = parse(el.value);
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
syncing = true;
|
|
2475
|
+
try {
|
|
2476
|
+
if (rodObj.value !== next) rodObj.value = next;
|
|
2477
|
+
} finally {
|
|
2478
|
+
syncing = false;
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
|
|
2482
|
+
el.addEventListener(eventName, handler);
|
|
2483
|
+
disposers.push(() => el.removeEventListener(eventName, handler));
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
// Release both directions without disposing the caller-owned rod.
|
|
2487
|
+
let disposed = false;
|
|
2488
|
+
const dispose = () => {
|
|
2489
|
+
if (disposed) return;
|
|
2490
|
+
disposed = true;
|
|
2491
|
+
disposers.splice(0).forEach(fn => fn());
|
|
2492
|
+
const actionIndex = rodObj._actions?.indexOf(onValue) ?? -1;
|
|
2493
|
+
if (actionIndex >= 0) rodObj._actions.splice(actionIndex, 1);
|
|
2494
|
+
const hookIndex = rodObj._disposeHooks?.indexOf(dispose) ?? -1;
|
|
2495
|
+
if (hookIndex >= 0 && !rodObj._disposed) rodObj._disposeHooks.splice(hookIndex, 1);
|
|
2496
|
+
};
|
|
2497
|
+
if (typeof rodObj.onDispose === "function") rodObj.onDispose(dispose);
|
|
2498
|
+
return dispose;
|
|
2499
|
+
};
|
|
2500
|
+
|
|
2501
|
+
|
|
2502
|
+
// input <-> signal (sugar)
|
|
2503
|
+
JSswift.signalModel = function (inputEl, get, set, opts = {}) {
|
|
2504
|
+
const r = JSswift.rodFromSignal(get, set);
|
|
2505
|
+
const stopBinding = JSswift.rodModel(inputEl, r, opts);
|
|
2506
|
+
return () => {
|
|
2507
|
+
stopBinding();
|
|
2508
|
+
r.dispose();
|
|
2509
|
+
};
|
|
2510
|
+
};
|
|
2500
2511
|
// ===============================
|
|
2501
2512
|
// Lifecycle helpers
|
|
2502
2513
|
// ===============================
|