sibujs 1.1.0 → 1.3.0

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.
Files changed (94) hide show
  1. package/README.md +29 -25
  2. package/dist/browser.cjs +804 -2
  3. package/dist/browser.d.cts +591 -1
  4. package/dist/browser.d.ts +591 -1
  5. package/dist/browser.js +50 -8
  6. package/dist/build.cjs +706 -161
  7. package/dist/build.js +21 -12
  8. package/dist/cdn.global.js +188 -7
  9. package/dist/chunk-2BYQDGN3.js +742 -0
  10. package/dist/chunk-32DY64NT.js +282 -0
  11. package/dist/chunk-3AIRKM3B.js +1263 -0
  12. package/dist/chunk-3X2YG6YM.js +505 -0
  13. package/dist/chunk-5X6PP2UK.js +28 -0
  14. package/dist/chunk-77L6NL3X.js +1097 -0
  15. package/dist/chunk-B7SWRFUT.js +332 -0
  16. package/dist/chunk-BGN5ZMP4.js +26 -0
  17. package/dist/chunk-BTU3TJDS.js +365 -0
  18. package/dist/chunk-CHF5OHIA.js +61 -0
  19. package/dist/chunk-CMBFNA7L.js +27 -0
  20. package/dist/chunk-DAHRH4ON.js +331 -0
  21. package/dist/chunk-EBGIRKQY.js +616 -0
  22. package/dist/chunk-EUZND3CB.js +27 -0
  23. package/dist/chunk-F3FA4F32.js +292 -0
  24. package/dist/chunk-GCOK2LC3.js +282 -0
  25. package/dist/chunk-JAKHTMQU.js +1000 -0
  26. package/dist/chunk-JCI5M6U6.js +956 -0
  27. package/dist/chunk-KQPDEVVS.js +398 -0
  28. package/dist/chunk-NEKUBFPT.js +60 -0
  29. package/dist/chunk-NYVAC6P5.js +37 -0
  30. package/dist/chunk-OUZZEE4S.js +365 -0
  31. package/dist/chunk-P6W3STU4.js +2249 -0
  32. package/dist/chunk-PTQJDMRT.js +146 -0
  33. package/dist/chunk-QWZG56ET.js +2744 -0
  34. package/dist/chunk-TSOKIX5Z.js +654 -0
  35. package/dist/chunk-VMVDTCXB.js +712 -0
  36. package/dist/chunk-VRW3FULF.js +725 -0
  37. package/dist/chunk-WZSPOOER.js +84 -0
  38. package/dist/chunk-YT6HQ6AM.js +14 -0
  39. package/dist/chunk-ZD6OAMTH.js +277 -0
  40. package/dist/contracts-DDrwxvJ-.d.cts +245 -0
  41. package/dist/contracts-DDrwxvJ-.d.ts +245 -0
  42. package/dist/data.cjs +35 -2
  43. package/dist/data.d.cts +7 -0
  44. package/dist/data.d.ts +7 -0
  45. package/dist/data.js +9 -8
  46. package/dist/devtools.cjs +122 -0
  47. package/dist/devtools.d.cts +69 -461
  48. package/dist/devtools.d.ts +69 -461
  49. package/dist/devtools.js +127 -6
  50. package/dist/ecosystem.cjs +68 -23
  51. package/dist/ecosystem.d.cts +1 -1
  52. package/dist/ecosystem.d.ts +1 -1
  53. package/dist/ecosystem.js +10 -9
  54. package/dist/extras.cjs +1252 -82
  55. package/dist/extras.d.cts +5 -5
  56. package/dist/extras.d.ts +5 -5
  57. package/dist/extras.js +69 -24
  58. package/dist/index.cjs +708 -161
  59. package/dist/index.d.cts +397 -17
  60. package/dist/index.d.ts +397 -17
  61. package/dist/index.js +39 -17
  62. package/dist/introspect-BumjnBKr.d.cts +477 -0
  63. package/dist/introspect-CZrlcaYy.d.ts +477 -0
  64. package/dist/introspect-Cb0zgpi2.d.cts +477 -0
  65. package/dist/introspect-Y2xNXGSf.d.ts +477 -0
  66. package/dist/motion.js +4 -4
  67. package/dist/patterns.cjs +51 -2
  68. package/dist/patterns.d.cts +18 -8
  69. package/dist/patterns.d.ts +18 -8
  70. package/dist/patterns.js +7 -7
  71. package/dist/performance.js +4 -4
  72. package/dist/plugins.cjs +473 -98
  73. package/dist/plugins.d.cts +27 -4
  74. package/dist/plugins.d.ts +27 -4
  75. package/dist/plugins.js +156 -37
  76. package/dist/ssr-4PBXAOO3.js +40 -0
  77. package/dist/ssr-Do_SiVoL.d.cts +201 -0
  78. package/dist/ssr-Do_SiVoL.d.ts +201 -0
  79. package/dist/ssr.cjs +357 -77
  80. package/dist/ssr.d.cts +10 -1
  81. package/dist/ssr.d.ts +10 -1
  82. package/dist/ssr.js +13 -10
  83. package/dist/tagFactory-DaJ0YWX6.d.cts +47 -0
  84. package/dist/tagFactory-DaJ0YWX6.d.ts +47 -0
  85. package/dist/testing.cjs +233 -2
  86. package/dist/testing.d.cts +42 -1
  87. package/dist/testing.d.ts +42 -1
  88. package/dist/testing.js +129 -2
  89. package/dist/ui.cjs +374 -3
  90. package/dist/ui.d.cts +252 -2
  91. package/dist/ui.d.ts +252 -2
  92. package/dist/ui.js +328 -8
  93. package/dist/widgets.js +7 -7
  94. package/package.json +1 -1
package/dist/testing.js CHANGED
@@ -1,4 +1,9 @@
1
- import "./chunk-MLKGABMK.js";
1
+ import {
2
+ effect
3
+ } from "./chunk-CHF5OHIA.js";
4
+ import "./chunk-EUZND3CB.js";
5
+ import "./chunk-ZD6OAMTH.js";
6
+ import "./chunk-5X6PP2UK.js";
2
7
 
3
8
  // src/testing/a11y.ts
4
9
  var VALID_ARIA_ROLES = /* @__PURE__ */ new Set([
@@ -1389,6 +1394,119 @@ function testComponent(component, options = {}) {
1389
1394
  };
1390
1395
  }
1391
1396
 
1397
+ // src/testing/queries.ts
1398
+ function queryByText(container, text) {
1399
+ const walk = (node) => {
1400
+ if (node.childNodes.length === 1 && node.childNodes[0].nodeType === 3) {
1401
+ if (node.textContent?.includes(text)) return node;
1402
+ }
1403
+ for (const child of Array.from(node.children)) {
1404
+ const found = walk(child);
1405
+ if (found) return found;
1406
+ }
1407
+ return null;
1408
+ };
1409
+ return walk(container);
1410
+ }
1411
+ function queryByTestId(container, testId) {
1412
+ return container.querySelector(`[data-testid="${testId}"]`);
1413
+ }
1414
+ function queryByRole(container, role) {
1415
+ return container.querySelector(`[role="${role}"]`);
1416
+ }
1417
+ function cssEscape(value) {
1418
+ const g = globalThis;
1419
+ if (g.CSS && typeof g.CSS.escape === "function") return g.CSS.escape(value);
1420
+ return value.replace(/[^\w-]/g, (m) => `\\${m.charCodeAt(0).toString(16)} `);
1421
+ }
1422
+ function queryByLabel(container, labelText) {
1423
+ const labels = Array.from(container.querySelectorAll("label"));
1424
+ for (const label of labels) {
1425
+ if (label.textContent?.trim() === labelText) {
1426
+ const forId = label.getAttribute("for");
1427
+ if (forId) {
1428
+ const target = container.querySelector(`#${cssEscape(forId)}`);
1429
+ if (target) return target;
1430
+ }
1431
+ const child = label.querySelector("input, select, textarea, button");
1432
+ if (child) return child;
1433
+ }
1434
+ }
1435
+ return container.querySelector(`[aria-label="${labelText}"]`);
1436
+ }
1437
+ async function pollUntil(fn, timeout, interval, errorIfTimeout) {
1438
+ const start = Date.now();
1439
+ return new Promise((resolve, reject) => {
1440
+ const check = () => {
1441
+ const result = fn();
1442
+ if (result !== null) {
1443
+ resolve(result);
1444
+ return;
1445
+ }
1446
+ if (Date.now() - start >= timeout) {
1447
+ reject(new Error(errorIfTimeout));
1448
+ return;
1449
+ }
1450
+ setTimeout(check, interval);
1451
+ };
1452
+ check();
1453
+ });
1454
+ }
1455
+ function findByText(container, text, options = {}) {
1456
+ return pollUntil(
1457
+ () => queryByText(container, text),
1458
+ options.timeout ?? 1e3,
1459
+ options.interval ?? 50,
1460
+ `findByText: no element with text "${text}" after ${options.timeout ?? 1e3}ms`
1461
+ );
1462
+ }
1463
+ function findByTestId(container, testId, options = {}) {
1464
+ return pollUntil(
1465
+ () => queryByTestId(container, testId),
1466
+ options.timeout ?? 1e3,
1467
+ options.interval ?? 50,
1468
+ `findByTestId: no element with data-testid="${testId}" after ${options.timeout ?? 1e3}ms`
1469
+ );
1470
+ }
1471
+ function findByRole(container, role, options = {}) {
1472
+ return pollUntil(
1473
+ () => queryByRole(container, role),
1474
+ options.timeout ?? 1e3,
1475
+ options.interval ?? 50,
1476
+ `findByRole: no element with role="${role}" after ${options.timeout ?? 1e3}ms`
1477
+ );
1478
+ }
1479
+ function waitForSignal(getter, predicate, options = {}) {
1480
+ const timeoutMs = options.timeout ?? 1e3;
1481
+ return new Promise((resolve, reject) => {
1482
+ let resolved = false;
1483
+ const timer = setTimeout(() => {
1484
+ if (!resolved) {
1485
+ resolved = true;
1486
+ teardown();
1487
+ reject(new Error(`waitForSignal: predicate did not match within ${timeoutMs}ms`));
1488
+ }
1489
+ }, timeoutMs);
1490
+ const teardown = effect(() => {
1491
+ if (resolved) return;
1492
+ const value = getter();
1493
+ if (predicate(value)) {
1494
+ resolved = true;
1495
+ clearTimeout(timer);
1496
+ queueMicrotask(() => teardown());
1497
+ resolve(value);
1498
+ }
1499
+ });
1500
+ });
1501
+ }
1502
+ function type(element, text) {
1503
+ for (const char of text) {
1504
+ element.value += char;
1505
+ element.dispatchEvent(new InputEvent("input", { bubbles: true, data: char }));
1506
+ }
1507
+ element.dispatchEvent(new Event("change", { bubbles: true }));
1508
+ }
1509
+
1392
1510
  // src/testing/snapshot.ts
1393
1511
  function serializeElement2(el, indent) {
1394
1512
  const pad = " ".repeat(indent);
@@ -1851,12 +1969,21 @@ export {
1851
1969
  createTimerMock,
1852
1970
  createUniversalAdapter,
1853
1971
  createVisualSuite,
1972
+ findByRole,
1973
+ findByTestId,
1974
+ findByText,
1854
1975
  fireEvent,
1855
1976
  matchSnapshot,
1856
1977
  mockRouter,
1857
1978
  mockStore,
1979
+ queryByLabel,
1980
+ queryByRole,
1981
+ queryByTestId,
1982
+ queryByText,
1858
1983
  render,
1859
1984
  snapshotComponent,
1860
1985
  testComponent,
1861
- waitFor
1986
+ type,
1987
+ waitFor,
1988
+ waitForSignal
1862
1989
  };
package/dist/ui.cjs CHANGED
@@ -32,7 +32,10 @@ __export(ui_exports, {
32
32
  bindField: () => bindField,
33
33
  composable: () => composable,
34
34
  compose: () => compose,
35
+ createDialogAria: () => createDialogAria,
36
+ createFocusManager: () => createFocusManager,
35
37
  createGuard: () => createGuard,
38
+ createListbox: () => createListbox,
36
39
  createSlots: () => createSlots,
37
40
  creditCardMask: () => creditCardMask,
38
41
  custom: () => custom,
@@ -46,10 +49,13 @@ __export(ui_exports, {
46
49
  eventBus: () => eventBus,
47
50
  focus: () => focus,
48
51
  form: () => form,
52
+ formAction: () => formAction,
49
53
  hotkey: () => hotkey,
54
+ hover: () => hover,
50
55
  infiniteScroll: () => infiniteScroll,
51
56
  inputMask: () => inputMask,
52
57
  intersection: () => intersection,
58
+ interval: () => interval,
53
59
  lazyEffect: () => lazyEffect,
54
60
  lazyLoad: () => lazyLoad,
55
61
  matchesPattern: () => matchesPattern,
@@ -62,9 +68,11 @@ __export(ui_exports, {
62
68
  removeScopedStyle: () => removeScopedStyle,
63
69
  required: () => required,
64
70
  scopedStyle: () => scopedStyle,
71
+ scrollLock: () => scrollLock,
65
72
  ssnMask: () => ssnMask,
66
73
  svgElement: () => svgElement,
67
74
  timeMask: () => timeMask,
75
+ timeout: () => timeout,
68
76
  toast: () => toast,
69
77
  validateProps: () => validateProps,
70
78
  validators: () => validators,
@@ -573,6 +581,41 @@ function form(config) {
573
581
  };
574
582
  }
575
583
 
584
+ // src/ui/formAction.ts
585
+ function formAction(fn) {
586
+ const [pending, setPending] = signal(false);
587
+ const [error, setError] = signal(null);
588
+ const [result, setResult] = signal(null);
589
+ let runId = 0;
590
+ async function run(...args) {
591
+ const currentId = ++runId;
592
+ setPending(true);
593
+ setError(null);
594
+ try {
595
+ const value = await fn(...args);
596
+ if (currentId !== runId) return;
597
+ setResult(value);
598
+ } catch (err) {
599
+ if (currentId !== runId) return;
600
+ setError(err);
601
+ } finally {
602
+ if (currentId === runId) setPending(false);
603
+ }
604
+ }
605
+ function reset() {
606
+ setError(null);
607
+ setResult(null);
608
+ }
609
+ function onSubmit(e) {
610
+ e.preventDefault();
611
+ const formEl = e.currentTarget;
612
+ if (!formEl || typeof FormData === "undefined") return;
613
+ const data = new FormData(formEl);
614
+ run(data);
615
+ }
616
+ return { run, pending, error, result, reset, onSubmit };
617
+ }
618
+
576
619
  // src/core/ssr-context.ts
577
620
  var ssrMode = false;
578
621
  function isSSR() {
@@ -902,10 +945,224 @@ function announce(message, priority = "polite") {
902
945
  });
903
946
  }
904
947
 
948
+ // src/core/rendering/createId.ts
949
+ var idCounter = 0;
950
+ function createId(prefix = "sibu") {
951
+ idCounter++;
952
+ return `${prefix}-${idCounter}`;
953
+ }
954
+
955
+ // src/core/rendering/dispose.ts
956
+ var elementDisposers = /* @__PURE__ */ new WeakMap();
957
+ var _isDev4 = isDev();
958
+ var activeBindingCount = 0;
959
+ function registerDisposer(node, teardown) {
960
+ let disposers = elementDisposers.get(node);
961
+ if (!disposers) {
962
+ disposers = [];
963
+ elementDisposers.set(node, disposers);
964
+ }
965
+ disposers.push(teardown);
966
+ if (_isDev4) activeBindingCount++;
967
+ }
968
+
969
+ // src/ui/a11yPrimitives.ts
970
+ var DEFAULT_FOCUS_SELECTOR = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
971
+ function createFocusManager(container, options = {}) {
972
+ const selector = options.selector ?? DEFAULT_FOCUS_SELECTOR;
973
+ const loop = options.loop ?? true;
974
+ function items() {
975
+ return Array.from(container.querySelectorAll(selector));
976
+ }
977
+ function focusFirst() {
978
+ const all = items();
979
+ if (all.length > 0) all[0].focus();
980
+ }
981
+ function focusLast() {
982
+ const all = items();
983
+ if (all.length > 0) all[all.length - 1].focus();
984
+ }
985
+ function focusNext() {
986
+ const all = items();
987
+ if (all.length === 0) return;
988
+ const idx = all.indexOf(document.activeElement);
989
+ if (idx === -1) {
990
+ all[0].focus();
991
+ return;
992
+ }
993
+ const next = idx + 1;
994
+ if (next >= all.length) {
995
+ if (loop) all[0].focus();
996
+ return;
997
+ }
998
+ all[next].focus();
999
+ }
1000
+ function focusPrev() {
1001
+ const all = items();
1002
+ if (all.length === 0) return;
1003
+ const idx = all.indexOf(document.activeElement);
1004
+ if (idx === -1) {
1005
+ all[all.length - 1].focus();
1006
+ return;
1007
+ }
1008
+ const prev = idx - 1;
1009
+ if (prev < 0) {
1010
+ if (loop) all[all.length - 1].focus();
1011
+ return;
1012
+ }
1013
+ all[prev].focus();
1014
+ }
1015
+ return { focusFirst, focusLast, focusNext, focusPrev, items };
1016
+ }
1017
+ function createListbox(container, options = {}) {
1018
+ const multiple = options.multiple ?? false;
1019
+ const optionSelector = options.optionSelector ?? '[role="option"]';
1020
+ container.setAttribute("role", "listbox");
1021
+ if (multiple) container.setAttribute("aria-multiselectable", "true");
1022
+ if (!container.hasAttribute("tabindex")) container.setAttribute("tabindex", "0");
1023
+ const [activeValue, setActiveValue] = signal(null);
1024
+ const [selectedValue, setSelectedValue] = signal(null);
1025
+ const [activeDescendantId, setActiveDescendantId] = signal(null);
1026
+ function stampIds() {
1027
+ const opts = Array.from(container.querySelectorAll(optionSelector));
1028
+ for (const opt of opts) {
1029
+ if (!opt.id) opt.id = createId("listbox-option");
1030
+ }
1031
+ }
1032
+ stampIds();
1033
+ function getOptions() {
1034
+ return Array.from(container.querySelectorAll(optionSelector));
1035
+ }
1036
+ function setActive(value) {
1037
+ setActiveValue(value);
1038
+ const opts = getOptions();
1039
+ for (const opt of opts) {
1040
+ if (opt.dataset.value === value) {
1041
+ opt.setAttribute("data-highlighted", "");
1042
+ setActiveDescendantId(opt.id || null);
1043
+ container.setAttribute("aria-activedescendant", opt.id || "");
1044
+ } else {
1045
+ opt.removeAttribute("data-highlighted");
1046
+ }
1047
+ }
1048
+ if (value === null) {
1049
+ setActiveDescendantId(null);
1050
+ container.removeAttribute("aria-activedescendant");
1051
+ }
1052
+ }
1053
+ function select(value) {
1054
+ if (multiple) {
1055
+ const current2 = selectedValue();
1056
+ const set = new Set((current2 ?? "").split(",").filter(Boolean));
1057
+ if (set.has(value)) set.delete(value);
1058
+ else set.add(value);
1059
+ setSelectedValue(Array.from(set).join(","));
1060
+ } else {
1061
+ setSelectedValue(value);
1062
+ }
1063
+ options.onSelect?.(value);
1064
+ const opts = getOptions();
1065
+ const current = selectedValue();
1066
+ const selected = new Set((current ?? "").split(",").filter(Boolean));
1067
+ for (const opt of opts) {
1068
+ const ov = opt.dataset.value ?? "";
1069
+ opt.setAttribute("aria-selected", selected.has(ov) ? "true" : "false");
1070
+ }
1071
+ }
1072
+ function moveActive(delta) {
1073
+ const opts = getOptions();
1074
+ if (opts.length === 0) return;
1075
+ const currentIdx = opts.findIndex((o) => o.dataset.value === activeValue());
1076
+ let next = currentIdx + delta;
1077
+ if (next < 0) next = opts.length - 1;
1078
+ if (next >= opts.length) next = 0;
1079
+ const nextValue = opts[next].dataset.value ?? null;
1080
+ setActive(nextValue);
1081
+ if (typeof opts[next].scrollIntoView === "function") {
1082
+ opts[next].scrollIntoView({ block: "nearest" });
1083
+ }
1084
+ }
1085
+ function onKeyDown(e) {
1086
+ switch (e.key) {
1087
+ case "ArrowDown":
1088
+ e.preventDefault();
1089
+ moveActive(1);
1090
+ break;
1091
+ case "ArrowUp":
1092
+ e.preventDefault();
1093
+ moveActive(-1);
1094
+ break;
1095
+ case "Home": {
1096
+ e.preventDefault();
1097
+ const opts = getOptions();
1098
+ if (opts.length > 0) setActive(opts[0].dataset.value ?? null);
1099
+ break;
1100
+ }
1101
+ case "End": {
1102
+ e.preventDefault();
1103
+ const opts = getOptions();
1104
+ if (opts.length > 0) setActive(opts[opts.length - 1].dataset.value ?? null);
1105
+ break;
1106
+ }
1107
+ case "Enter":
1108
+ case " ": {
1109
+ e.preventDefault();
1110
+ const active = activeValue();
1111
+ if (active !== null) select(active);
1112
+ break;
1113
+ }
1114
+ }
1115
+ }
1116
+ function onClick(e) {
1117
+ const target = e.target.closest(optionSelector);
1118
+ if (!target || !container.contains(target)) return;
1119
+ const value = target.dataset.value ?? null;
1120
+ if (value !== null) {
1121
+ setActive(value);
1122
+ select(value);
1123
+ }
1124
+ }
1125
+ container.addEventListener("keydown", onKeyDown);
1126
+ container.addEventListener("click", onClick);
1127
+ function dispose() {
1128
+ container.removeEventListener("keydown", onKeyDown);
1129
+ container.removeEventListener("click", onClick);
1130
+ }
1131
+ registerDisposer(container, dispose);
1132
+ return { activeValue, selectedValue, activeDescendantId, dispose };
1133
+ }
1134
+ function createDialogAria(element, options = {}) {
1135
+ const titleId = options.labelledBy ?? createId("dialog-title");
1136
+ const descriptionId = options.describedBy ?? createId("dialog-desc");
1137
+ element.setAttribute("role", options.alert ? "alertdialog" : "dialog");
1138
+ if (options.modal ?? true) element.setAttribute("aria-modal", "true");
1139
+ element.setAttribute("aria-labelledby", titleId);
1140
+ element.setAttribute("aria-describedby", descriptionId);
1141
+ if (!element.hasAttribute("tabindex")) element.setAttribute("tabindex", "-1");
1142
+ return { titleId, descriptionId };
1143
+ }
1144
+
905
1145
  // src/ui/scopedStyle.ts
906
1146
  var scopeCounter = 0;
1147
+ function decodeCssEscapes(css) {
1148
+ return css.replace(/\\([0-9a-f]{1,6})[ \t\n\r\f]?|\\([^\n])/gi, (_match, hex, ch) => {
1149
+ if (hex) {
1150
+ const code = Number.parseInt(hex, 16);
1151
+ if (Number.isFinite(code) && code > 0 && code <= 1114111) {
1152
+ try {
1153
+ return String.fromCodePoint(code);
1154
+ } catch {
1155
+ return "";
1156
+ }
1157
+ }
1158
+ return "";
1159
+ }
1160
+ return ch || "";
1161
+ });
1162
+ }
907
1163
  function sanitizeCSS(css) {
908
- let sanitized = css.replace(/@import\s+[^;]+;/gi, "/* @import removed */");
1164
+ let sanitized = decodeCssEscapes(css);
1165
+ sanitized = sanitized.replace(/@import\s+[^;]+;/gi, "/* @import removed */");
909
1166
  sanitized = sanitized.replace(/url\s*\(\s*(?:"[^"]*"|'[^']*'|[^)]*)\s*\)/gi, "/* url() removed */");
910
1167
  sanitized = sanitized.replace(/expression\s*\(\s*(?:"[^"]*"|'[^']*'|[^)]*)\s*\)/gi, "/* expression() removed */");
911
1168
  sanitized = sanitized.replace(/-moz-binding\s*:[^;]+;/gi, "/* -moz-binding removed */");
@@ -971,14 +1228,27 @@ function isUrlAttribute(attr) {
971
1228
  }
972
1229
 
973
1230
  // src/reactivity/bindAttribute.ts
974
- var _isDev4 = isDev();
1231
+ var _isDev5 = isDev();
1232
+ function isEventHandlerAttr(name) {
1233
+ if (name.length < 3) return false;
1234
+ const lower = name.toLowerCase();
1235
+ return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
1236
+ }
975
1237
  function bindAttribute(el, attr, getter) {
1238
+ if (isEventHandlerAttr(attr)) {
1239
+ if (_isDev5)
1240
+ devWarn(
1241
+ `bindAttribute: refusing to bind event-handler attribute "${attr}". Use on:{ ${attr.slice(2)}: fn } instead.`
1242
+ );
1243
+ return () => {
1244
+ };
1245
+ }
976
1246
  function commit() {
977
1247
  let value;
978
1248
  try {
979
1249
  value = getter();
980
1250
  } catch (err) {
981
- if (_isDev4)
1251
+ if (_isDev5)
982
1252
  devWarn(`bindAttribute: getter for "${attr}" threw: ${err instanceof Error ? err.message : String(err)}`);
983
1253
  return;
984
1254
  }
@@ -1314,6 +1584,99 @@ function lazyEffect(element, effectFn, options) {
1314
1584
  };
1315
1585
  }
1316
1586
 
1587
+ // src/ui/timers.ts
1588
+ function interval(fn, ms) {
1589
+ let id = null;
1590
+ let running = false;
1591
+ function start() {
1592
+ if (running) return;
1593
+ id = setInterval(fn, ms);
1594
+ running = true;
1595
+ }
1596
+ function stop() {
1597
+ if (id !== null) {
1598
+ clearInterval(id);
1599
+ id = null;
1600
+ }
1601
+ running = false;
1602
+ }
1603
+ start();
1604
+ return {
1605
+ stop,
1606
+ pause: stop,
1607
+ resume: start,
1608
+ isRunning: () => running
1609
+ };
1610
+ }
1611
+ function timeout(fn, ms) {
1612
+ let pending = true;
1613
+ const id = setTimeout(() => {
1614
+ pending = false;
1615
+ fn();
1616
+ }, ms);
1617
+ return {
1618
+ cancel: () => {
1619
+ if (pending) {
1620
+ clearTimeout(id);
1621
+ pending = false;
1622
+ }
1623
+ },
1624
+ isPending: () => pending
1625
+ };
1626
+ }
1627
+
1628
+ // src/ui/hover.ts
1629
+ function hover(target) {
1630
+ const [hovered, setHovered] = signal(false);
1631
+ if (typeof window === "undefined") {
1632
+ return { hovered, dispose: () => {
1633
+ } };
1634
+ }
1635
+ const onEnter = () => setHovered(true);
1636
+ const onLeave = () => setHovered(false);
1637
+ target.addEventListener("pointerenter", onEnter);
1638
+ target.addEventListener("pointerleave", onLeave);
1639
+ function dispose() {
1640
+ target.removeEventListener("pointerenter", onEnter);
1641
+ target.removeEventListener("pointerleave", onLeave);
1642
+ }
1643
+ return { hovered, dispose };
1644
+ }
1645
+
1646
+ // src/ui/scrollLock.ts
1647
+ var lockCount = 0;
1648
+ var savedOverflow = null;
1649
+ var savedPaddingRight = null;
1650
+ function scrollLock() {
1651
+ let owned = false;
1652
+ function lock() {
1653
+ if (owned) return;
1654
+ owned = true;
1655
+ lockCount++;
1656
+ if (lockCount !== 1 || typeof document === "undefined") return;
1657
+ const body = document.body;
1658
+ const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth;
1659
+ savedOverflow = body.style.overflow;
1660
+ savedPaddingRight = body.style.paddingRight;
1661
+ body.style.overflow = "hidden";
1662
+ if (scrollBarWidth > 0) {
1663
+ body.style.paddingRight = `${scrollBarWidth}px`;
1664
+ }
1665
+ }
1666
+ function unlock() {
1667
+ if (!owned) return;
1668
+ owned = false;
1669
+ lockCount = Math.max(0, lockCount - 1);
1670
+ if (lockCount !== 0 || typeof document === "undefined") return;
1671
+ const body = document.body;
1672
+ body.style.overflow = savedOverflow ?? "";
1673
+ body.style.paddingRight = savedPaddingRight ?? "";
1674
+ savedOverflow = null;
1675
+ savedPaddingRight = null;
1676
+ }
1677
+ return { lock, unlock };
1678
+ }
1679
+
1317
1680
  // src/platform/customElement.ts
1318
1681
  function defineElement(name, component, options = {}) {
1319
1682
  if (customElements.get(name)) return;
@@ -1572,7 +1935,10 @@ function createGuard(validator) {
1572
1935
  bindField,
1573
1936
  composable,
1574
1937
  compose,
1938
+ createDialogAria,
1939
+ createFocusManager,
1575
1940
  createGuard,
1941
+ createListbox,
1576
1942
  createSlots,
1577
1943
  creditCardMask,
1578
1944
  custom,
@@ -1586,10 +1952,13 @@ function createGuard(validator) {
1586
1952
  eventBus,
1587
1953
  focus,
1588
1954
  form,
1955
+ formAction,
1589
1956
  hotkey,
1957
+ hover,
1590
1958
  infiniteScroll,
1591
1959
  inputMask,
1592
1960
  intersection,
1961
+ interval,
1593
1962
  lazyEffect,
1594
1963
  lazyLoad,
1595
1964
  matchesPattern,
@@ -1602,9 +1971,11 @@ function createGuard(validator) {
1602
1971
  removeScopedStyle,
1603
1972
  required,
1604
1973
  scopedStyle,
1974
+ scrollLock,
1605
1975
  ssnMask,
1606
1976
  svgElement,
1607
1977
  timeMask,
1978
+ timeout,
1608
1979
  toast,
1609
1980
  validateProps,
1610
1981
  validators,