vaniy 0.1.9 → 0.1.11

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/README.md CHANGED
@@ -9,6 +9,9 @@ Vaniy is how we say vanilla in my language.
9
9
  - **HTTP Client** - Full-featured HTTP client with caching, interceptors, and file upload/download
10
10
  - **Event System** - Pub/Sub event emitter for decoupled communication
11
11
  - **Form Handling** - Validation engine with error rendering
12
+ - **Reactivity** - Fine-grained signals, effects, computed values, and batching
13
+ - **DOM Bindings** - Declaratively bind signals to DOM elements
14
+ - **Query Cache** - Configurable async data cache with signals, polling, and DOM bindings
12
15
  - **Zero Dependencies** - Pure vanilla JavaScript
13
16
 
14
17
  ## Installation
@@ -281,6 +284,367 @@ form.destroy();
281
284
  | `form:reset` | Form was reset |
282
285
  | `form:validated` | Validation completed |
283
286
 
287
+ ### Reactivity
288
+
289
+ Fine-grained reactive primitives — signals, effects, computed values, and batching.
290
+
291
+ ```javascript
292
+ import { signal, effect, computed, batch, when } from "vaniy";
293
+ ```
294
+
295
+ **`signal(initial)`**
296
+
297
+ Holds a reactive value. Reading `.val` inside an `effect` tracks the dependency; writing `.val` triggers all dependents.
298
+
299
+ ```javascript
300
+ const count = signal(0);
301
+
302
+ count.val; // read → 0
303
+ count.val = 1; // write → triggers effects
304
+ count.peek(); // read without tracking
305
+ String(count); // "1" (toString)
306
+ count + 0; // 1 (valueOf)
307
+
308
+ // Subscribe manually
309
+ const unsub = count.subscribe(() => console.log(count.val));
310
+ unsub(); // stop
311
+ ```
312
+
313
+ **`effect(fn)`**
314
+
315
+ Runs `fn` immediately and re-runs it whenever any signal read inside it changes.
316
+
317
+ ```javascript
318
+ const name = signal("Alice");
319
+
320
+ effect(() => {
321
+ console.log("Name:", name.val); // runs now and on every change
322
+ });
323
+
324
+ name.val = "Bob"; // → logs "Name: Bob"
325
+ ```
326
+
327
+ **`computed(fn)`**
328
+
329
+ Derives a read-only signal from other signals.
330
+
331
+ ```javascript
332
+ const price = signal(10);
333
+ const qty = signal(3);
334
+ const total = computed(() => price.val * qty.val);
335
+
336
+ console.log(total.val); // 30
337
+
338
+ price.val = 20;
339
+ console.log(total.val); // 60
340
+ ```
341
+
342
+ **`batch(fn)`**
343
+
344
+ Groups multiple signal writes so effects only run once after all updates.
345
+
346
+ ```javascript
347
+ const x = signal(1);
348
+ const y = signal(2);
349
+
350
+ effect(() => console.log(x.val, y.val)); // logs: 1 2
351
+
352
+ batch(() => {
353
+ x.val = 10;
354
+ y.val = 20;
355
+ // effect has not run yet
356
+ });
357
+ // effect runs once here → logs: 10 20
358
+ ```
359
+
360
+ **`when(signal, fn)`**
361
+
362
+ Runs `fn` whenever `signal.val` is truthy, passing the current value.
363
+
364
+ ```javascript
365
+ const user = signal(null);
366
+
367
+ when(user, (u) => console.log("Logged in:", u.name));
368
+
369
+ user.val = { name: "Alice" }; // → logs "Logged in: Alice"
370
+ ```
371
+
372
+ ### DOM Bindings
373
+
374
+ Declaratively bind signals to DOM elements. Each function returns the underlying `effect` — call it to stop the binding.
375
+
376
+ ```javascript
377
+ import { bind, bindText, bindHtml, bindValue, bindList, bindOptions, bindClass, bindAttr } from "vaniy";
378
+ ```
379
+
380
+ All functions accept a CSS selector string or a `Q`-wrapped element as `target`.
381
+
382
+ **`bind(target, prop, signal)`**
383
+
384
+ Syncs a signal to a named property on an element.
385
+
386
+ | `prop` | Behavior |
387
+ | --- | --- |
388
+ | `"text"` | Sets element text content |
389
+ | `"html"` | Sets element inner HTML |
390
+ | `"value"` | Sets input value |
391
+ | `"show"` | Shows element when truthy, hides when falsy |
392
+ | `"hide"` | Hides element when truthy, shows when falsy |
393
+ | `"disabled"` | Sets `disabled` attribute |
394
+ | anything else | Assigned directly as `element[prop]` |
395
+
396
+ ```javascript
397
+ const username = signal("Alice");
398
+ const isAdmin = signal(false);
399
+ const bio = signal("<p>Hello</p>");
400
+
401
+ bind("#name", "text", username);
402
+ bind("#bio", "html", bio);
403
+ bind("#role-badge", "show", isAdmin);
404
+ bind("#submit", "disabled", isAdmin);
405
+
406
+ username.val = "Bob"; // → #name text updates instantly
407
+ ```
408
+
409
+ **`bindText(target, signal)`**
410
+
411
+ Shorthand for `bind(target, "text", signal)`.
412
+
413
+ ```javascript
414
+ const title = signal("Hello");
415
+ bindText("#heading", title);
416
+
417
+ title.val = "World"; // → #heading text content updates
418
+ ```
419
+
420
+ **`bindHtml(target, signal)`**
421
+
422
+ Shorthand for `bind(target, "html", signal)`.
423
+
424
+ ```javascript
425
+ const content = signal("<p>Loading...</p>");
426
+ bindHtml("#panel", content);
427
+
428
+ content.val = "<p>Done</p>"; // → #panel innerHTML updates
429
+ ```
430
+
431
+ **`bindValue(target, signal)`**
432
+
433
+ Shorthand for `bind(target, "value", signal)`.
434
+
435
+ ```javascript
436
+ const query = signal("");
437
+ bindValue("#search", query);
438
+
439
+ query.val = "vaniy"; // → #search input value updates
440
+ ```
441
+
442
+ **`bindList(target, signal, template, empty?)`**
443
+
444
+ Renders an array signal as a list. Re-renders the entire list on every change.
445
+
446
+ ```javascript
447
+ const users = signal([]);
448
+
449
+ const stop = bindList(
450
+ "#user-list",
451
+ users,
452
+ (user) => `<li>${user.name}</li>`,
453
+ "<li>No users found.</li>", // optional fallback for empty/null
454
+ );
455
+
456
+ users.val = [{ name: "Alice" }, { name: "Bob" }];
457
+ // → #user-list innerHTML: <li>Alice</li><li>Bob</li>
458
+ ```
459
+
460
+ **`bindOptions(target, signal, opts?)`**
461
+
462
+ Populates a `<select>` element from an array signal.
463
+
464
+ ```javascript
465
+ const roles = signal([]);
466
+
467
+ bindOptions("#role-select", roles, {
468
+ value: "id", // item property used as <option value> (default: "id")
469
+ label: "name", // item property used as <option> text (default: "name")
470
+ placeholder: "Pick a role", // first empty option text (default: "Select ...")
471
+ });
472
+
473
+ roles.val = [
474
+ { id: 1, name: "Admin" },
475
+ { id: 2, name: "Editor" },
476
+ ];
477
+ ```
478
+
479
+ **`bindClass(target, className, signal)`**
480
+
481
+ Adds a class when the signal is truthy, removes it when falsy.
482
+
483
+ ```javascript
484
+ const isActive = signal(false);
485
+
486
+ bindClass("#card", "active", isActive);
487
+
488
+ isActive.val = true; // → adds class "active"
489
+ isActive.val = false; // → removes class "active"
490
+ ```
491
+
492
+ **`bindAttr(target, attr, signal)`**
493
+
494
+ Sets an HTML attribute to the signal's value on every change.
495
+
496
+ ```javascript
497
+ const progress = signal(0);
498
+
499
+ bindAttr("#bar", "aria-valuenow", progress);
500
+
501
+ progress.val = 75; // → <div id="bar" aria-valuenow="75">
502
+ ```
503
+
504
+ ### Query Cache
505
+
506
+ Async data cache with deduplication, stale-while-revalidate, persistence, and reactive signals.
507
+
508
+ Use `createQuery` to create a fully configured client. `queryClient` is a zero-config default export for quick use.
509
+
510
+ ```javascript
511
+ import { createQuery, queryClient } from "vaniy";
512
+
513
+ // Create your own configured client
514
+ const client = createQuery({
515
+ persistKey: "my-app-cache", // localStorage key (default: "query-cache")
516
+ persistedKeys: ["user", "settings"], // cache key prefixes to persist (default: null = none)
517
+ defaultTtl: 60000, // entry lifetime in ms (default: 60000)
518
+ defaultStaleTime: 5000, // freshness window in ms (default: 5000)
519
+ defaultRetries: 3, // retry attempts on failure (default: 3)
520
+ defaultRetryDelay: 1000, // base retry delay in ms, doubles each attempt (default: 1000)
521
+ });
522
+ ```
523
+
524
+ **Core cache methods:**
525
+
526
+ ```javascript
527
+ // Fetch and cache data
528
+ const data = await client.query("users", () => fetch("/api/users").then(r => r.json()));
529
+
530
+ // Per-query overrides
531
+ const data = await client.query("users", fetcher, { ttl: 30000, staleTime: 0 });
532
+
533
+ // Set data manually (e.g. after a mutation)
534
+ client.setQueryData("users", updatedList);
535
+
536
+ // Optimistic update — returns previous value
537
+ const previous = client.mutate("users", (prev) => [...prev, newUser]);
538
+
539
+ // Invalidate (remove from cache)
540
+ client.invalidate("users");
541
+
542
+ // Invalidate and immediately refetch
543
+ client.invalidate("users", { refetch: true, fetcher });
544
+
545
+ // Invalidate all keys matching a pattern
546
+ client.invalidateMatching((key) => key.startsWith("users"));
547
+
548
+ // Prefetch into cache without blocking
549
+ client.prefetch("users", fetcher);
550
+
551
+ // Read cache entry directly
552
+ const entry = client.getEntry("users"); // { data, staleAt, expiry, error, promise }
553
+
554
+ // Subscribe to cache updates for a key
555
+ const unsub = client.subscribe("users", (entry) => console.log(entry?.data));
556
+
557
+ // Clear all cache and storage
558
+ client.clear();
559
+ ```
560
+
561
+ **Polling:**
562
+
563
+ ```javascript
564
+ // Start polling every 5 seconds — returns a stop function
565
+ const stop = client.startPolling("price", fetcher, 5000);
566
+
567
+ // Stop a specific poll
568
+ client.stopPolling("price");
569
+
570
+ // Stop all active polls
571
+ client.stopAllPolling();
572
+ ```
573
+
574
+ **Reactive signals (`querySignal`):**
575
+
576
+ Wraps a query in reactive signals — ideal for use with Vaniy's reactive system.
577
+
578
+ ```javascript
579
+ const { data, loading, error, fetch, refetch, mutate, unsubscribe } =
580
+ client.querySignal("users", () => fetch("/api/users").then(r => r.json()));
581
+
582
+ // data.val, loading.val, error.val update automatically
583
+ console.log(data.val); // fetched array or null
584
+ console.log(loading.val); // true while fetching
585
+ console.log(error.val); // Error instance or null
586
+
587
+ // Skip auto-fetch, call manually
588
+ const qs = client.querySignal("users", fetcher, { enabled: false });
589
+ await qs.fetch();
590
+
591
+ // Refetch (invalidates then fetches)
592
+ await qs.refetch();
593
+
594
+ // Optimistic update
595
+ qs.mutate((prev) => [...prev, newUser]);
596
+
597
+ // Stop listening
598
+ qs.unsubscribe();
599
+ ```
600
+
601
+ **Polling signals (`pollingSignal`):**
602
+
603
+ ```javascript
604
+ const { data, loading, error, stop } =
605
+ client.pollingSignal("price", fetcher, 5000);
606
+
607
+ // stop polling
608
+ stop();
609
+ ```
610
+
611
+ **DOM binding (`bindQuery`):**
612
+
613
+ Automatically renders data into a DOM element when the cache updates.
614
+
615
+ ```javascript
616
+ client.bindQuery("users", fetcher, {
617
+ target: "#user-list", // CSS selector or element reference
618
+ render: (data) => data.map(u => `<li>${u.name}</li>`).join(""),
619
+ onLoading: (el) => el.innerHTML = "Loading...",
620
+ onError: (err, staleData, el) => el.innerHTML = "Failed to load",
621
+ });
622
+
623
+ // With polling — returns a stop function
624
+ const stop = client.bindQuery("users", fetcher, {
625
+ target: "#user-list",
626
+ render: (data) => data.map(u => `<li>${u.name}</li>`).join(""),
627
+ poll: 10000,
628
+ });
629
+ ```
630
+
631
+ **Query events (via `EVT`):**
632
+
633
+ | Event | Description |
634
+ | ----- | ----------- |
635
+ | `query:fetch` | Fetch started |
636
+ | `query:success` | Fetch succeeded |
637
+ | `query:error` | Fetch failed |
638
+ | `query:retry` | Fetch retrying |
639
+ | `query:mutate` | Cache mutated |
640
+ | `query:set` | Cache set manually |
641
+ | `query:invalidate` | Entry invalidated |
642
+ | `query:hydrated` | Cache loaded from storage |
643
+ | `query:gc` | Expired entries collected |
644
+ | `query:cleared` | All cache cleared |
645
+
646
+ Each event also fires as `query:<key>:<event>` for key-specific subscriptions.
647
+
284
648
  ### Utilities
285
649
 
286
650
  Additional helper functions.
package/dist/vaniy.es.js CHANGED
@@ -970,6 +970,144 @@ const HTTP = {
970
970
  ping: () => console.log("PONG"),
971
971
  description: "H is for Http"
972
972
  };
973
+ let _tracking = null;
974
+ let _pending = /* @__PURE__ */ new Set();
975
+ function signal(initial) {
976
+ let _val = initial;
977
+ const subs = /* @__PURE__ */ new Set();
978
+ const s = {
979
+ get val() {
980
+ if (_tracking) subs.add(_tracking);
981
+ return _val;
982
+ },
983
+ set val(v) {
984
+ if (v === _val) return;
985
+ _val = v;
986
+ for (const fn of subs) fn();
987
+ },
988
+ peek: () => _val,
989
+ subscribe: (fn) => {
990
+ subs.add(fn);
991
+ return () => subs.delete(fn);
992
+ },
993
+ toString: () => String(_val),
994
+ valueOf: () => _val
995
+ };
996
+ return s;
997
+ }
998
+ function effect(fn) {
999
+ const run2 = () => {
1000
+ const prev = _tracking;
1001
+ _tracking = run2;
1002
+ try {
1003
+ fn();
1004
+ } finally {
1005
+ _tracking = prev;
1006
+ }
1007
+ };
1008
+ run2();
1009
+ return run2;
1010
+ }
1011
+ function computed(fn) {
1012
+ const s = signal(void 0);
1013
+ effect(() => {
1014
+ s.val = fn();
1015
+ });
1016
+ return s;
1017
+ }
1018
+ function batch(fn) {
1019
+ fn();
1020
+ _pending.forEach((f) => f());
1021
+ _pending.clear();
1022
+ }
1023
+ function when(sig, fn) {
1024
+ return effect(() => {
1025
+ if (sig.val) fn(sig.val);
1026
+ });
1027
+ }
1028
+ function getElement(target) {
1029
+ return typeof target === "string" ? Q(target) : target;
1030
+ }
1031
+ function bind(target, prop, sig) {
1032
+ const el = getElement(target);
1033
+ return effect(() => {
1034
+ const val = sig.val;
1035
+ switch (prop) {
1036
+ case "text":
1037
+ el.text(val);
1038
+ break;
1039
+ case "html":
1040
+ el.html(val);
1041
+ break;
1042
+ case "value":
1043
+ el.val(val);
1044
+ break;
1045
+ case "show":
1046
+ val ? el.show() : el.hide();
1047
+ break;
1048
+ case "hide":
1049
+ val ? el.hide() : el.show();
1050
+ break;
1051
+ case "disabled":
1052
+ el.elt.disabled = !!val;
1053
+ break;
1054
+ default:
1055
+ el.elt[prop] = val;
1056
+ }
1057
+ });
1058
+ }
1059
+ function bindText(target, sig) {
1060
+ const el = getElement(target);
1061
+ return effect(() => {
1062
+ const val = sig.val;
1063
+ el.text(val);
1064
+ });
1065
+ }
1066
+ function bindHtml(target, sig) {
1067
+ const el = getElement(target);
1068
+ return effect(() => {
1069
+ const val = sig.val;
1070
+ el.html(val);
1071
+ });
1072
+ }
1073
+ function bindValue(target, sig) {
1074
+ const el = getElement(target);
1075
+ return effect(() => {
1076
+ const val = sig.val;
1077
+ el.val(val);
1078
+ });
1079
+ }
1080
+ function bindList(target, sig, template, empty = "") {
1081
+ const el = getElement(target);
1082
+ return effect(() => {
1083
+ const items = sig.val;
1084
+ el.html(items?.length ? items.map(template).join("") : empty);
1085
+ });
1086
+ }
1087
+ function bindOptions(target, sig, opts = {}) {
1088
+ const { value = "id", label = "name", placeholder = "Select ..." } = opts;
1089
+ const el = getElement(target);
1090
+ return effect(() => {
1091
+ const items = sig.val || [];
1092
+ el.html(
1093
+ `<option value="">${placeholder}</option>` + items.map(
1094
+ (item) => `<option value="${item[value]}">${item[label]}</option>`
1095
+ ).join("")
1096
+ );
1097
+ });
1098
+ }
1099
+ function bindClass(target, className, sig) {
1100
+ const el = getElement(target);
1101
+ return effect(() => {
1102
+ sig.val ? el.addClass(className) : el.removeClass(className);
1103
+ });
1104
+ }
1105
+ function bindAttr(target, attr, sig) {
1106
+ const el = getElement(target);
1107
+ return effect(() => {
1108
+ el.elt.setAttribute(attr, sig.val);
1109
+ });
1110
+ }
973
1111
  const FormEvents = {
974
1112
  STATE_CHANGE: "form:state:change",
975
1113
  ERRORS_CHANGE: "form:errors:change",
@@ -1275,28 +1413,6 @@ function parseTTL(str) {
1275
1413
  };
1276
1414
  return num * (map[unit] || 1);
1277
1415
  }
1278
- function signal(initial) {
1279
- let _val = initial;
1280
- const subs = /* @__PURE__ */ new Set();
1281
- const s = {
1282
- get val() {
1283
- return _val;
1284
- },
1285
- set val(v) {
1286
- if (v === _val) return;
1287
- _val = v;
1288
- for (const fn of subs) fn();
1289
- },
1290
- peek: () => _val,
1291
- subscribe: (fn) => {
1292
- subs.add(fn);
1293
- return () => subs.delete(fn);
1294
- },
1295
- toString: () => String(_val),
1296
- valueOf: () => _val
1297
- };
1298
- return s;
1299
- }
1300
1416
  const createQuery = (options = {}) => {
1301
1417
  const {
1302
1418
  persistKey = "query-cache",
@@ -1539,6 +1655,64 @@ const createQuery = (options = {}) => {
1539
1655
  stopAllPolling();
1540
1656
  saveToStorage();
1541
1657
  });
1658
+ const querySignal = (key, fetcher, options2 = {}) => {
1659
+ const data = signal(options2.inital ?? null);
1660
+ const loading = signal(false);
1661
+ const error = signal(null);
1662
+ const unsubscribe = subscribe(key, (entry) => {
1663
+ if (entry?.data) data.val = entry.data;
1664
+ if (entry?.error) error.val = entry.error;
1665
+ loading.val = !!entry?.promise && !entry?.data;
1666
+ });
1667
+ const fetch2 = () => {
1668
+ loading.val = true;
1669
+ return query(key, fetcher, options2);
1670
+ };
1671
+ const mutateFn = (updater) => {
1672
+ const prev = mutate(key, updater);
1673
+ data.val = getEntry(key)?.data;
1674
+ return prev;
1675
+ };
1676
+ const refetch = () => {
1677
+ invalidate(key);
1678
+ return fetch2();
1679
+ };
1680
+ if (options2.enabled !== false) fetch2().catch(() => {
1681
+ });
1682
+ return { data, loading, error, fetch: fetch2, refetch, unsubscribe, mutate: mutateFn };
1683
+ };
1684
+ const pollingSignal = (key, fetcher, interval, options2 = {}) => {
1685
+ const qs = querySignal(key, fetcher, { ...options2, enabled: false });
1686
+ const stop = startPolling(key, fetcher, interval, options2);
1687
+ return { ...qs, stop };
1688
+ };
1689
+ const bindQuery = (key, fetcher, options2 = {}) => {
1690
+ const { target, render, onLoading, onError, poll = null, ...queryOptions } = options2;
1691
+ const el = typeof target === "string" ? document.querySelector(target) : target;
1692
+ const renderData = (data) => {
1693
+ const html2 = render(data);
1694
+ if (typeof html2 === "string") el.innerHTML = html2;
1695
+ };
1696
+ EVT.sub(`query:${key}:success`, ({ data }) => renderData(data));
1697
+ EVT.sub(`query:${key}:set`, ({ data }) => renderData(data));
1698
+ EVT.sub(`query:${key}:mutate`, ({ data }) => renderData(data));
1699
+ if (onError) {
1700
+ EVT.sub(
1701
+ `query:${key}:error`,
1702
+ ({ error, staleData }) => onError(error, staleData, el)
1703
+ );
1704
+ }
1705
+ if (onLoading) {
1706
+ EVT.sub(`query:${key}:fetch`, ({ hasCache }) => {
1707
+ if (!hasCache) onLoading(el);
1708
+ });
1709
+ }
1710
+ query(key, fetcher, queryOptions).catch(() => {
1711
+ });
1712
+ if (poll) {
1713
+ return startPolling(key, fetcher, poll, queryOptions);
1714
+ }
1715
+ };
1542
1716
  return {
1543
1717
  query,
1544
1718
  mutate,
@@ -1552,6 +1726,9 @@ const createQuery = (options = {}) => {
1552
1726
  stopAllPolling,
1553
1727
  getEntry,
1554
1728
  gc,
1729
+ querySignal,
1730
+ pollingSignal,
1731
+ bindQuery,
1555
1732
  clear: () => {
1556
1733
  cache2.clear();
1557
1734
  localStorage.removeItem(persistKey);
@@ -1559,82 +1736,7 @@ const createQuery = (options = {}) => {
1559
1736
  }
1560
1737
  };
1561
1738
  };
1562
- const queryClient = createQuery({
1563
- persistKey: "teksoft-cache",
1564
- persistedKeys: ["user", "settings"]
1565
- });
1566
- const querySignal = (key, fetcher, options = {}) => {
1567
- const data = signal(options.inital ?? null);
1568
- const loading = signal(false);
1569
- const error = signal(null);
1570
- const unsubscribe = queryClient.subscribe(key, (entry) => {
1571
- if (entry?.data) data.val = entry.data;
1572
- if (entry?.error) error.val = entry.error;
1573
- loading.val = !!entry?.promise && !entry?.data;
1574
- });
1575
- const fetch2 = () => {
1576
- loading.val = true;
1577
- return queryClient.query(key, fetcher, options);
1578
- };
1579
- const mutate = (updater) => {
1580
- const prev = queryClient.mutate(key, updater);
1581
- data.val = queryClient.getEntry(key)?.data;
1582
- return prev;
1583
- };
1584
- const refetch = () => {
1585
- queryClient.invalidate(key);
1586
- return fetch2();
1587
- };
1588
- if (options.enabled !== false) fetch2();
1589
- return {
1590
- data,
1591
- loading,
1592
- error,
1593
- fetch: fetch2,
1594
- refetch,
1595
- unsubscribe,
1596
- mutate
1597
- };
1598
- };
1599
- const pollingSignal = (key, fetcher, interval, options = {}) => {
1600
- const qs = querySignal(key, fetcher, { ...options, enabled: false });
1601
- const stop = queryClient.startPolling(key, fetcher, interval, options);
1602
- return { ...qs, stop };
1603
- };
1604
- const bindQuery = (key, fetcher, options = {}) => {
1605
- const {
1606
- target,
1607
- render,
1608
- onLoading,
1609
- onError,
1610
- poll = null,
1611
- ...queryOptions
1612
- } = options;
1613
- const el = typeof target === "string" ? document.querySelector(target) : target;
1614
- const renderData = (data) => {
1615
- const html2 = render(data);
1616
- if (typeof html2 === "string") el.innerHTML = html2;
1617
- };
1618
- EVT.sub(`query:${key}:success`, ({ data }) => renderData(data));
1619
- EVT.sub(`query:${key}:set`, ({ data }) => renderData(data));
1620
- EVT.sub(`query:${key}:mutate`, ({ data }) => renderData(data));
1621
- if (onError) {
1622
- EVT.sub(
1623
- `query:${key}:error`,
1624
- ({ error, staleData }) => onError(error, staleData, el)
1625
- );
1626
- }
1627
- if (onLoading) {
1628
- EVT.sub(`query:${key}:fetch`, ({ hasCache }) => {
1629
- if (!hasCache) onLoading(el);
1630
- });
1631
- }
1632
- queryClient.query(key, fetcher, queryOptions).catch(() => {
1633
- });
1634
- if (poll) {
1635
- return queryClient.startPolling(key, fetcher, poll, queryOptions);
1636
- }
1637
- };
1739
+ const queryClient = createQuery();
1638
1740
  export {
1639
1741
  DOM,
1640
1742
  EVT,
@@ -1645,10 +1747,21 @@ export {
1645
1747
  Q,
1646
1748
  V,
1647
1749
  all,
1648
- bindQuery,
1750
+ batch,
1751
+ bind,
1752
+ bindAttr,
1753
+ bindClass,
1754
+ bindHtml,
1755
+ bindList,
1756
+ bindOptions,
1757
+ bindText,
1758
+ bindValue,
1649
1759
  cache,
1760
+ computed,
1761
+ createQuery,
1650
1762
  del,
1651
1763
  download,
1764
+ effect,
1652
1765
  formatByCountry,
1653
1766
  get,
1654
1767
  isArray,
@@ -1660,15 +1773,15 @@ export {
1660
1773
  onPageLoad,
1661
1774
  onWindowLoad,
1662
1775
  parseHtml,
1663
- pollingSignal,
1664
1776
  post,
1665
1777
  put,
1666
1778
  queryClient,
1667
- querySignal,
1668
1779
  raw,
1669
1780
  redirect,
1670
1781
  request,
1782
+ signal,
1671
1783
  toCurrency,
1672
1784
  upload,
1673
- useFormHandler
1785
+ useFormHandler,
1786
+ when
1674
1787
  };
@@ -1 +1 @@
1
- var vaniy=function(e){"use strict";const t={listeners:new Map,sub:function(e,t){let r=this.listeners.get(e);r||(r=new Set,this.listeners.set(e,r)),r.add(t)},once:function(e,t){const r=(...n)=>{t(...n),this.unsub(e,r)};this.sub(e,r)},unsub:function(e,t){let r=this.listeners.get(e);r&&r.delete(t)},pub:function(e,...t){let r=this.listeners.get(e);r&&r.forEach(r=>{try{r(...t)}catch(t){console.error(`Error in event "${e}" listener: `,t)}})},has:function(e){return this.listeners.has(e)&&this.listeners.get(e).size>0},clear:function(e){e?this.listeners.delete(e):this.listeners.clear()},ping:()=>console.log("PONG!"),description:"EVT is for Event publishing and emitting"},r={US:{locale:"en-US",currency:"USD"},CA:{locale:"en-CA",currency:"CAD"},FR:{locale:"fr-FR",currency:"EUR"},HT:{locale:"ht-HT",currency:"HTG"},GB:{locale:"en-GB",currency:"GBP"},AU:{locale:"en-AU",currency:"AUD"}},n=(e,{locale:t="en-US",currency:r="USD"}={})=>Intl.NumberFormat(t,{style:"currency",currency:r}).format(e);function s(e){return Array.isArray(e)?e.length:function(e){if("number"==typeof e)return Number.isFinite(e);if("string"!=typeof e)return!1;const t=e.trim();return!!t&&/^-?\d+(\.\d+)?$/.test(t)}(e)?Number(String(e).trim()):String(e??"").length}function o(e){const[t,r]=String(e??"").split(",").map(e=>e.trim()),n=Number(t),s=Number(r);return Number.isFinite(n)&&Number.isFinite(s)?{min:n,max:s}:null}const a=e=>new Promise(t=>setTimeout(t,e));function i(e,t){const r=String(e??"").trim();if(!r)return null;if("YYYY-MM-DD"===t){const e=r.match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!e)return null;const t=Number(e[1]),n=Number(e[2]),s=Number(e[3]);return!t||n<1||n>12||s<1||s>31?null:{year:t,month:n,day:s}}return null}function l(e,t,r="en-US"){const n=new Intl.DateTimeFormat(r,{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),s=Object.fromEntries(n.map(e=>[e.type,e.value]));return{year:Number(s.year),month:Number(s.month),day:Number(s.day),hour:Number(s.hour),minute:Number(s.minute),second:Number(s.second)}}function u({year:e,month:t,day:r},n){const s=new Date(Date.UTC(e,t-1,r));return s.setUTCDate(s.getUTCDate()+n),{year:s.getUTCFullYear(),month:s.getUTCMonth()+1,day:s.getUTCDate()}}function c(e,t,r){const{base:n,offsetDays:s}=function(e){const t=String(e).trim().match(/^(.+?)([+-]\d+)?$/);return t?{base:t[1].trim(),offsetDays:t[2]?Number(t[2]):0}:{base:String(e).trim(),offsetDays:0}}(e);let o=function(e,t){const r=new Date,{year:n,month:s,day:o}=l(r,t);return"today"===e?{year:n,month:s,day:o}:"tomorrow"===e?u({year:n,month:s,day:o},1):"yesterday"===e?u({year:n,month:s,day:o},-1):null}(n,r.timezone);if(!o){const e=t?.[n];o=d(e,r)}return o||(o=i(n,r.dateFormat)),o?(s&&(o=u(o,s)),o):null}function d(e,t){if(null==(r=e)||""===String(r??"").trim())return null;var r;const n=String(e).trim();let s=i(n,t.dateFormat);if(s)return s;if(!/^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2})?$/.test(n))return null;const o=new Date(n);if(isNaN(o.getTime()))return null;const a=l(o,t.timezone);return{year:a.year,month:a.month,day:a.day}}function m(e,t,r,n){let s=null;return s="value"===n?d(e,r):c(e,t,r),s?function({year:e,month:t,day:r},n){let s=Date.UTC(e,t-1,r,0,0,0);for(let o=0;o<2;o++){const o=l(new Date(s),n),a=Date.UTC(o.year,o.month-1,o.day,o.hour,o.minute,o.second)-Date.UTC(e,t-1,r,0,0,0);if(0===a)break;s-=a}return s}(s,r.timezone):null}function f(e,t){return{method:t=>(r,n,s)=>{const o=m(r,n,s,"value"),a=m(t,n,s,"target");return null!=o&&null!=a&&e(o,a)},message:t}}const h={required:{method:e=>""!==String(e??"").trim(),message:"This field is required"},requiredIf:{method:e=>(t,r)=>{const[n,s]=String(e).split("="),o=r?.[n];return!(null!=s?String(o??"")===s:""!==String(o??"").trim())||""!==String(t??"").trim()},message:e=>{const[t,r]=String(e).split("=");return null!=r?`This field is requied when ${t} is ${r}`:`This field is required when ${t} has a value`}},email:{method:e=>/\S+@\S+\.\S+/.test(e),message:"Email is invalid"},min:{method:e=>t=>String(t??"").length>=Number(e),message:e=>`Must be at least ${e} characters`},max:{method:e=>t=>String(t??"").length<=Number(e),message:e=>`Must be at most ${e} characters`},date:{method:e=>{if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;const[t,r,n]=e.split("-").map(Number),s=new Date(t,r-1,n);return s.getFullYear()===t&&s.getMonth()===r-1&&s.getDate()===n},message:"Date is invalid. Use the format YYYY-MM-DD."},currency:{method:e=>/^\$?\d{1,3}((,\d{3})*|\d*)(\.\d{2})?$/.test(e),message:"Currency is invalid. Use the format $123,456.78 or 123456.78."},same:{method:e=>(t,r)=>String(t??"")===String(r?.[e]??""),message:e=>`Must match ${e}`},in:{method:e=>t=>(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim()).filter(Boolean)).includes(String(t??"").trim()),message:e=>`Must be one of the following: ${(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim())).filter(Boolean).join(",")}`},before:f((e,t)=>e<t,e=>`Must be before ${e}`),beforeOrEqual:f((e,t)=>e<=t,e=>`Must be before or equal to ${e}`),after:f((e,t)=>e>t,e=>`Must be after ${e}`),afterOrEqual:f((e,t)=>e>=t,e=>`Must be after or equal to ${e}`),between:{method:e=>t=>{const r=o(e);if(!r)return!1;const n=s(t);return r.min<=n&&n<=r.max},message:e=>{const t=o(e);return t?`Must be between ${t.min} and ${t.max}`:"Between rule is invalid. Use between:min,max"}}};function y(e){const t=e.indexOf(":");return-1===t?{name:e,param:void 0}:{name:e.slice(0,t),param:e.slice(t+1)}}const p={run:function(e,t){let r=!0;const n={};for(const s in e){const o=e[s]||[];for(const e of o){const{name:o,param:a}=y(e),i=h[o];if(!i)continue;const l=t?.[s];if(!(void 0!==a?i.method(a)(l,t):i.method(l,t))){r=!1,n[s]||(n[s]=[]);const e="function"==typeof i.message?i.message(a):i.message;n[s].push(e)}}}return{isValid:r,errors:n}},ping:()=>console.log("PONG"),description:"V is for validating forms"},g=e=>({on:(t,r)=>e?.addEventListener(t,r),off:(t,r)=>e?.removeEventListener(t,r)}),b=(e,t)=>{if(!e)return;const r="innerText"in e?"innerText":"textContent";return null!=t&&(e[r]=t),e[r]},S=(e,t)=>{if(e)return null!=t&&(e.innerHTML=t),e.innerHTML},w=e=>document.createElement(e),E=e=>{let t="";const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n<e;n++)t+=r.charAt(Math.floor(62*Math.random()));return t},v=e=>{const t=document.implementation.createHTMLDocument("");return t.body.innerHTML=e,[...t.body.childNodes]},A=e=>{"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)},T=e=>{window.onload=e},$=e=>{const t="string"==typeof e?document.querySelector(e):e,r=e=>(...r)=>{if(t)return e(...r)},n={elt:t,value:t?.value,text:e=>null!=e?(b(t,e),n):b(t),html:e=>null!=e?(S(t,e),n):S(t),val:r(e=>{if(null!=e){if(t.opt&&t.multiple){const r=new Set(Array.isArray(e)?e:[e]);Array.from(t.options).forEach(e=>{e.selected=r.has(e.value)})}else t.value=e;return n.value=t.value,n}return t.options&&t.multiple?Array.from(t.options).filter(e=>e.selected).map(e=>e.value):t.value}),addClass:r(e=>(t.classList.add(e),n)),removeClass:r(e=>(t.classList.remove(e),n)),hasClass:r(e=>t.classList.contains(e)),hide:r(()=>(t.style.display="none",n)),show:r(()=>(t.style.display="",n)),prop:r(e=>t[e]),attr:r(e=>t.getAttribute(e)),removeAttr:e=>{t.removeAttribute(e)},toggle:r(()=>("none"==t.style.display?n.show():n.hide(),n)),css:r(e=>(Object.entries(e).forEach(([e,r])=>{t.style[e]=r}),n)),on:g(t).on,off:g(t).off};return n},C=e=>document.querySelectorAll(e),D={Q:$,$:$,all:C,$$:C,scan:(e,t={})=>{const r=t.refAttr||"v-ref",n="string"==typeof e?document.querySelector(e):e||document;if(!n)throw new Error(`Dom.scan: root "${e}" not found`);const s=Object.create(null);return n.querySelectorAll(`[${r}]`).forEach(e=>{const t=e.getAttribute(r);if(!t)return;const n=$(e);s[t]?Array.isArray(s[t])?s[t].push(n):s[t]=[s[t],n]:s[t]=n}),new Proxy({},{get(e,t){if("_"===t)return s;if("get"===t)return e=>s[e];if("all"===t)return e=>s[e]?Array.isArray(s[e])?s[e]:[s[e]]:[];if("on"===t)return(e,t,r)=>{const n=s[e];(Array.isArray(n)?n:[n]).forEach(e=>e?.on(t,r))};if("string"!=typeof t)return;const r=s[t];return r||(console.warn(`DOM.scan: ref "${t}" not found`),$(null))}})},make:w,makeId:E,parseHtml:v,onPageLoad:A,onWindowLoad:T,ping:()=>console.log("PONG!"),description:"DOM is for dom manipulation"};let I="",N=8e3,q=null,R=null,M=null;const L=new Map,O=new Map,U=()=>Date.now();function x(e){const t="undefined"!=typeof window?window[e]:null;return t?{get(e){const r=t.getItem(e);if(!r)return null;try{const n=JSON.parse(r);return n.exp&&n.exp<U()?(t.removeItem(e),null):n.val}catch{return null}},set(e,r,n){const s=n?U()+n:null;t.setItem(e,JSON.stringify({val:r,exp:s}))},del(e){t&&t.removeItem(e)},clear(){t&&t.clear()}}:null}const H={memory:{get(e){const t=O.get(e);return t?t.exp&&t.exp<U()?(O.delete(e),null):t.val:null},set(e,t,r){const n=r?U()+r:null;O.set(e,{val:t,exp:n})},del(e){O.delete(e)},clear(){O.clear()}},local:x("localStorage"),session:x("sessionStorage")};function k(e){return null===e||"object"!=typeof e?String(e):Array.isArray(e)?`[${e.map(k).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${k(e[t])}`).join(",")}}`}const F=(e,t)=>setTimeout(()=>t.abort(),e);async function P(e,t,r={}){const{params:n,body:s,headers:o={},cache:a}=r;let i=I+t;if(n){const e=new URLSearchParams(n).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c=!!a,d=a?.strategy,m=a?.ttl??0,f=function(e="memory"){return H[e]||H.memory}(a?.storage),h=a?.key||function(e,t,r,n){return`H|${e}|${t}${r?`?${new URLSearchParams(r).toString()}`:""}${n&&"GET"!==e?`#${k(n)}`:""}`}(e,i,n,s);if(c&&!a?.forceRefresh&&"cache-first"===d){const e=f.get(h);if(null!==e)return e}let y={method:e,headers:o,signal:l.signal};if(M){const{token:e,headerName:t}=M,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";y.headers[t]=`${e}${r}`}}void 0!==s&&(s instanceof FormData?y.body=s:(y.headers["Content-Type"]="application/json",y.body=JSON.stringify(s))),q&&(y=q(y)||y);try{let t,r=await fetch(i,y);L.has(r.status)&&L.get(r.status)(r,{method:e,url:i}),clearTimeout(u),R&&(r=R(r)||r);try{t=await r.json()}catch{t=await r.text()}if(!r.ok){const n={status:r.status,data:t,url:i,method:e};if(c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw n}return c&&f.set(h,t,m),t}catch(e){if(clearTimeout(u),c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw e}}async function j(e,{filename:t,params:r,headers:n={},method:s="GET",body:o,onProgress:a}={}){let i=I+e;if(r){const e=new URLSearchParams(r).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c={method:s,headers:{...n},signal:l.signal};void 0!==o&&(o instanceof FormData?c.body=o:(c.headers["Content-Type"]=c.headers["Content-Type"]||"application/json",c.body="string"==typeof o?o:JSON.stringify(o)));const d=await fetch(i,c);if(clearTimeout(u),!d.ok){let e="";try{e=await d.text()}catch{}throw new Error(`Download failed ${d.status}: ${e||d.statusText}`)}if(!t){const e=d.headers.get("Content-Disposition")||"",r=/filename\*=UTF-8''([^;]+)|filename="?([^"]+)"?/i.exec(e);t=decodeURIComponent(r?.[1]||r?.[2]||"download")}let m;if(d.body&&"getReader"in d.body){const e=d.body.getReader(),t=Number(d.headers.get("Content-Length"))||null,r=[];let n=0;for(;;){const{done:s,value:o}=await e.read();if(s)break;if(r.push(o),n+=o.length,"function"==typeof a){a(n,t,t?Math.round(n/t*100):null)}}m=new Blob(r)}else m=await d.blob(),"function"==typeof a&&a(1,1,100);const f=URL.createObjectURL(m),h=document.createElement("a");return h.href=f,h.download=t,h.style.display="none",document.body.appendChild(h),h.click(),document.body.removeChild(h),URL.revokeObjectURL(f),{filename:t,size:m.size,type:m.type}}function _(e,{files:t,fieldName:r="file",fields:n={},headers:s={},method:o="POST",onProgress:a,signal:i}={}){return new Promise((l,u)=>{const c=function({files:e,fieldName:t="file",fields:r={}}){const n=new FormData,s=Array.isArray(e)?e:[e];return s.forEach((e,r)=>{const o=s.length>1?`${t}[${r}]`:t;n.append(o,e)}),Object.entries(r).forEach(([e,t])=>{n.append(e,t instanceof Blob||t instanceof File?t:"object"==typeof t?JSON.stringify(t):String(t))}),n}({files:t,fieldName:r,fields:n}),d=`${I}${e}`,m=new XMLHttpRequest;m.open(o,d,!0);let f={method:o,headers:{...s}};if(M){const{token:e,headerName:t}=M,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";f.headers[t]=`${e}${r}`}}if(q&&(f=q(f)||f),Object.entries(f.headers).forEach(([e,t])=>m.setRequestHeader(e,t)),m.timeout=N,i){const e=()=>{try{m.abort()}catch{}};i.aborted&&e(),i.addEventListener("abort",e,{once:!0})}m.upload&&"function"==typeof a&&(m.upload.onprogress=e=>{if(!e.lengthComputable)return void a(e.loaded,null,null);const t=Math.round(e.loaded/e.total*100);a(e.loaded,e.total,t)}),m.onreadystatechange=async()=>{if(4!==m.readyState)return;if(R){const e={status:m.status,ok:m.status>=200&&m.status<300,headers:new Headers,text:async()=>m.responseText,json:async()=>JSON.parse(m.responseText||"null")};R(e)}const e=(m.getResponseHeader("Content-Type")||"").includes("application/json")?function(e){try{return JSON.parse(e||"null")}catch{return e}}(m.responseText):m.responseText;m.status>=200&&m.status<300?l(e):u({status:m.status,data:e,url:d,method:o})},m.onerror=()=>u({status:0,data:"Network error",url:`${I}${e}`,method:o}),m.ontimeout=()=>u({status:0,data:"Timeout",url:`${I}${e}`,method:o}),m.send(c)})}const B=(e,t)=>P("GET",e,t),V=(e,t,r={})=>P("POST",e,{...r,body:t}),G=(e,t,r={})=>P("PUT",e,{...r,body:t}),z=(e,t={})=>P("DELETE",e,t),J=(e,t)=>fetch(I+e,t),Y={base:e=>(I=e,Y),timeout:e=>(N=e,Y),bearer:(e,t="Authorization")=>(M={token:e,headerName:t},Y),onStatus:(e,t)=>(L.set(e,t),Y),onUnauthorized:e=>Y.onStatus(401,e),onForbidden:e=>Y.onStatus(403,e),onInternalServerError:e=>Y.onStatus(500,e),interceptRequest:e=>(q=e,Y),interceptResponse:e=>(R=e,Y),get:B,post:V,put:G,delete:z,raw:J,download:j,upload:_,ping:()=>console.log("PONG"),description:"H is for Http"},K={STATE_CHANGE:"form:state:change",ERRORS_CHANGE:"form:errors:change",SUBMIT_SUCCESS:"form:submit:success",SUBMIT_ERROR:"form:submit:error",RESET:"form:reset",VALIDATED:"form:validated"};class Q{constructor(e,t,r,n={}){this.formId=e,this.schema=t,this.onSubmit=r,this.preSubmit=n.preSubmit||null,this.form=null,this.formState={},this.errors={},this.initialValues={},this._boundHandleSubmit=this.#e.bind(this),this._boundHandleInput=this.#t.bind(this),this.#r()}#r(){this.form=document.getElementById(this.formId),this.form?(this.#n(),this.form.addEventListener("submit",this._boundHandleSubmit),this.form.addEventListener("input",this._boundHandleInput),this.#s()):console.error(`Form with id ${this.formId} not found`)}#n(){const e=this.form.elements;for(const t of Array.from(e))t.name&&(this.initialValues[t.name]=t.value,this.formState[t.name]=t.value)}#t(e){const{name:t,value:r}=e.target;t&&(this.formState[t]=r,this.#s(),this.errors[t]&&(delete this.errors[t],this.#o()))}async#e(e){e.preventDefault();const r=new FormData(this.form);let n={};r.forEach((e,t)=>{n[t]=e}),this.formState=n,this.#s();const{isValid:s,errors:o}=p.run(this.schema,n);if(t.pub(K.VALIDATED,{formId:this.formId,isValid:s,errors:o,data:n}),!s)return this.errors=o,this.#o(),void t.pub(K.SUBMIT_ERROR,{formId:this.formId,errors:o});if(this.errors={},this.#o(),this.preSubmit)try{n=await this.preSubmit(n)}catch(e){return void t.pub(K.SUBMIT_ERROR,{formId:this.formId,errors:{_preSubmit:[e.message]}})}t.pub(K.SUBMIT_SUCCESS,{formId:this.formId,data:n}),this.onSubmit(n)}#s(){t.pub(K.STATE_CHANGE,{formId:this.formId,state:{...this.formState}})}#o(){t.pub(K.ERRORS_CHANGE,{formId:this.formId,errors:{...this.errors}})}getFormState(){return{...this.formState}}getErrors(){return{...this.errors}}reset(){this.formState={...this.initialValues},this.errors={},this.form&&this.form.reset(),this.#s(),this.#o(),t.pub(K.RESET,{formId:this.formId})}validateNow(){const e=new FormData(this.form),r={};e.forEach((e,t)=>{r[t]=e});const n=p.run(this.schema,r);return this.errors=n.errors,this.#o(),t.pub(K.VALIDATED,{formId:this.formId,isValid:n.isValid,errors:n.errors,data:r}),n}destroy(){this.form&&(this.form.removeEventListener("submit",this._boundHandleSubmit),this.form.removeEventListener("input",this._boundHandleInput))}}class W{constructor(e,r={}){this.formId=e,this.options={containerClass:"form-error-container",errorClass:"text-danger",insertAfterField:!0,...r},this.customContainers={},this._boundHandleErrors=this.#a.bind(this),t.sub(K.ERRORS_CHANGE,this._boundHandleErrors)}#a({formId:e,errors:t}){e===this.formId&&(this.clearAll(),this.renderAll(t))}setContainer(e,t){this.customContainers[e]="string"==typeof t?document.querySelector(t):t}renderAll(e){for(const t in e)this.render(t,e[t])}render(e,t){if(!t||0===t.length)return null;const r=document.createElement("span");r.className=`${this.options.containerClass} ${this.options.errorClass}`,r.dataset.field=e;const n=document.createElement("ul");t.forEach(e=>{const t=document.createElement("li"),r=document.createElement("i");r.textContent=e,t.appendChild(r),n.appendChild(t)}),r.appendChild(n);const s=this.customContainers[e];if(s)s.innerHTML="",s.appendChild(r);else if(this.options.insertAfterField){const t=document.getElementById(this.formId),n=t?.querySelector(`[name="${e}"]`);n&&n.insertAdjacentElement("afterend",r)}return r}clearAll(){const e=document.getElementById(this.formId);if(!e)return;e.querySelectorAll(`.${this.options.containerClass}`).forEach(e=>e.remove());for(const e in this.customContainers)this.customContainers[e]&&(this.customContainers[e].innerHTML="")}destroy(){t.unsub(K.ERRORS_CHANGE,this._boundHandleErrors),this.clearAll()}}function Z(e){let t=e;const r=new Set;return{get val(){return t},set val(e){if(e!==t){t=e;for(const e of r)e()}},peek:()=>t,subscribe:e=>(r.add(e),()=>r.delete(e)),toString:()=>String(t),valueOf:()=>t}}const X=((e={})=>{const{persistKey:r="query-cache",persistedKeys:n=null,defaultTtl:s=6e4,defaultStaleTime:o=5e3,defaultRetries:i=3,defaultRetryDelay:l=1e3}=e,u=new Map,c=new Map,d=(e,r,n)=>{t.pub(`query:${e}`,{key:r,...n}),t.pub(`query:${r}:${e}`,n)},m=()=>{try{const e=localStorage.getItem(r);if(!e)return;const n=JSON.parse(e),s=Date.now();for(const[e,t]of Object.entries(n))s<t.expiry&&u.set(e,{...t,promise:null});t.pub("query:hydrated",{keys:[...u.keys()]})}catch(e){console.warn("Failed to load query cache: ",e)}},f=()=>{try{const e={};for(const[t,r]of u.entries())void 0!==r.data&&(n&&!n.some(e=>t.startsWith(e))||(e[t]={data:r.data,staleAt:r.staleAt,expiry:r.expiry}));localStorage.setItem(r,JSON.stringify(e))}catch(e){console.warn("Failed to persist query cache: ",e)}};let h=null;const y=()=>{h&&clearTimeout(h),h=setTimeout(f,1e3)},p=e=>u.get(e)??null,g=async(e,t,r={})=>{const{ttl:n=s,staleTime:c=o,retries:m=i,retryDelay:f=l}=r,h=Date.now(),g=p(e);if(g&&h<g.staleAt)return d("hit",e,{data:g.data}),g.data;if(g?.promise)return g.promise;const b=g&&h<g.expiry;d("fetch",e,{isStale:b,hasCache:!!g});const S=(async(e,t,r,n)=>{let s;for(let o=0;o<=r;o++)try{return await t()}catch(t){if(s=t,o<r){const s=n*Math.pow(2,o);d("retry",e,{attempt:o+1,maxRetries:r,delay:s,error:t}),await a(s)}}throw s})(e,t,m,f).then(t=>(u.set(e,{data:t,staleAt:Date.now()+c,expiry:Date.now()+n,promise:null,error:null}),d("success",e,{data:t}),y(),t)).catch(t=>{throw u.set(e,{data:g?.data??null,staleAt:g?.staleAt??0,expiry:g?.expiry??0,promise:null,error:t}),d("error",e,{error:t,staleData:g?.data??null}),t});return u.set(e,{...g,promise:S}),b?g.data:S},b=e=>{const t=c.get(e);t&&(clearInterval(t),c.delete(e),d("polling:stop",e,{}))},S=()=>{for(const e of c.keys())b(e)},w=()=>{const e=Date.now(),r=[];for(const[n,s]of u.entries())e>s.expiry&&!t.has(`query:${n}:success`)&&(u.delete(n),r.push(n));r.length&&(y(),t.pub("query:gc",{collected:r}))};return m(),setInterval(w,6e4),window.addEventListener("storage",e=>{if(e.key===r){m();for(const e of u.keys())d("sync",e,{data:u.get(e)?.data})}}),window.addEventListener("beforeunload",()=>{S(),f()}),{query:g,mutate:(e,t)=>{const r=p(e);if(!r)return null;const n=r.data,s="function"==typeof t?t(n):t;return u.set(e,{...r,data:s}),d("mutate",e,{data:s,previous:n}),y(),n},setQueryData:(e,t,r={})=>{const{ttl:n=s,staleTime:a=o}=r,i=Date.now();u.set(e,{data:t,staleAt:i+a,expiry:i+n,promise:null,error:null}),d("set",e,{data:t}),y()},invalidate:(e,t={})=>{const{refetch:r,fetcher:n}=t;if(u.delete(e),d("invalidate",e,{}),y(),r&&n)return g(e,n)},invalidateMatching:e=>{const t=[];for(const r of u.keys())e(r)&&(u.delete(r),t.push(r),d("invalidate",r,{}));return y(),t},subscribe:(e,r)=>{const n=t=>r({...p(e),...t});t.sub(`query:${e}:success`,n),t.sub(`query:${e}:error`,n),t.sub(`query:${e}:mutate`,n),t.sub(`query:${e}:set`,n),t.sub(`query:${e}:invalidate`,()=>r(null));const s=p(e);return s&&r(s),()=>{t.unsub(`query:${e}:success`,n),t.unsub(`query:${e}:error`,n),t.unsub(`query:${e}:mutate`,n),t.unsub(`query:${e}:set`,n),t.unsub(`query:${e}:invalidate`,n)}},prefetch:(e,t,r)=>{const n=p(e);n&&Date.now()<n.staleAt||g(e,t,r).catch(()=>{})},startPolling:(e,t,r,n={})=>{b(e),g(e,t,n).catch(()=>{});const s=setInterval(()=>{const r=p(e);r&&u.set(e,{...r,staleAt:0}),g(e,t,n).catch(()=>{})},r);return c.set(e,s),d("polling:start",e,{interval:r}),()=>b(e)},stopPolling:b,stopAllPolling:S,getEntry:p,gc:w,clear:()=>{u.clear(),localStorage.removeItem(r),t.pub("query:cleared",{})}}})({persistKey:"teksoft-cache",persistedKeys:["user","settings"]}),ee=(e,t,r={})=>{const n=Z(r.inital??null),s=Z(!1),o=Z(null),a=X.subscribe(e,e=>{e?.data&&(n.val=e.data),e?.error&&(o.val=e.error),s.val=!!e?.promise&&!e?.data}),i=()=>(s.val=!0,X.query(e,t,r));return!1!==r.enabled&&i(),{data:n,loading:s,error:o,fetch:i,refetch:()=>(X.invalidate(e),i()),unsubscribe:a,mutate:t=>{const r=X.mutate(e,t);return n.val=X.getEntry(e)?.data,r}}};return e.DOM=D,e.EVT=t,e.FormErrorRenderer=W,e.FormEvents=K,e.FormHandler=Q,e.HTTP=Y,e.Q=$,e.V=p,e.all=C,e.bindQuery=(e,r,n={})=>{const{target:s,render:o,onLoading:a,onError:i,poll:l=null,...u}=n,c="string"==typeof s?document.querySelector(s):s,d=e=>{const t=o(e);"string"==typeof t&&(c.innerHTML=t)};if(t.sub(`query:${e}:success`,({data:e})=>d(e)),t.sub(`query:${e}:set`,({data:e})=>d(e)),t.sub(`query:${e}:mutate`,({data:e})=>d(e)),i&&t.sub(`query:${e}:error`,({error:e,staleData:t})=>i(e,t,c)),a&&t.sub(`query:${e}:fetch`,({hasCache:e})=>{e||a(c)}),X.query(e,r,u).catch(()=>{}),l)return X.startPolling(e,r,l,u)},e.cache=function(e){if(null==e)return{cache:{strategy:"cache-first",storage:"local",ttl:6e4}};if("object"==typeof e)return{cache:e};const t=e.toLowerCase(),r={cfl:{strategy:"cache-first",storage:"local"},cfs:{strategy:"cache-first",storage:"session"},cfm:{strategy:"cache-first",storage:"memory"},nfl:{strategy:"network-first",storage:"local"},nfs:{strategy:"network-first",storage:"session"},nfm:{strategy:"network-first",storage:"memory"}},n=t.match(/cfl|cfs|cfm|nfl|nfs|nfm/),s=n?r[n[0]]:r.cfl,o=t.match(/(\d+)\s*(s|sec|secs|second|seconds|min|m|mins|minute|minutes|h|hr|hours)?/),a=o?function(e){const t=e.replace(/[0-9]/g,"").trim().toLowerCase(),r=parseInt(e,10),n={s:1e3,sec:1e3,secs:1e3,second:1e3,seconds:1e3,m:6e4,min:6e4,mins:6e4,minute:6e4,minutes:6e4,h:36e5,hr:36e5,hrs:36e5,hours:36e5};return r*(n[t]||1)}(o[0]):6e4;return{cache:{strategy:s.strategy,storage:s.storage,ttl:a}}},e.del=z,e.download=j,e.formatByCountry=(e,t)=>n(e,r[t]??r.US),e.get=B,e.isArray=e=>Array.isArray(e),e.isArrayEmpty=e=>!(Array.isArray(e)&&e.length>0),e.isFocus=e=>e==document.activeElement,e.isValidRoutingNumber=e=>{if(!/^\d{9}$/.test(e))return!1;const t=e.split("").map(Number);return(7*(t[0]+t[3]+t[6])+3*(t[1]+t[4]+t[7])+1*(t[2]+t[5]+t[8]))%10==0},e.make=w,e.makeId=E,e.onPageLoad=A,e.onWindowLoad=T,e.parseHtml=v,e.pollingSignal=(e,t,r,n={})=>({...ee(e,t,{...n,enabled:!1}),stop:X.startPolling(e,t,r,n)}),e.post=V,e.put=G,e.queryClient=X,e.querySignal=ee,e.raw=J,e.redirect=e=>window.location.href=e,e.request=P,e.toCurrency=n,e.upload=_,e.useFormHandler=function(e,t,r,n){const s=new Q(e,t,r,n),o=new W(e,n);return{reset:()=>s.reset(),validate:()=>s.validateNow(),destroy:()=>{o.destroy(),s.destroy()},setContainer:(e,t)=>o.setContainer(e,t)}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),e}({});
1
+ var vaniy=function(e){"use strict";const t={listeners:new Map,sub:function(e,t){let r=this.listeners.get(e);r||(r=new Set,this.listeners.set(e,r)),r.add(t)},once:function(e,t){const r=(...n)=>{t(...n),this.unsub(e,r)};this.sub(e,r)},unsub:function(e,t){let r=this.listeners.get(e);r&&r.delete(t)},pub:function(e,...t){let r=this.listeners.get(e);r&&r.forEach(r=>{try{r(...t)}catch(t){console.error(`Error in event "${e}" listener: `,t)}})},has:function(e){return this.listeners.has(e)&&this.listeners.get(e).size>0},clear:function(e){e?this.listeners.delete(e):this.listeners.clear()},ping:()=>console.log("PONG!"),description:"EVT is for Event publishing and emitting"},r={US:{locale:"en-US",currency:"USD"},CA:{locale:"en-CA",currency:"CAD"},FR:{locale:"fr-FR",currency:"EUR"},HT:{locale:"ht-HT",currency:"HTG"},GB:{locale:"en-GB",currency:"GBP"},AU:{locale:"en-AU",currency:"AUD"}},n=(e,{locale:t="en-US",currency:r="USD"}={})=>Intl.NumberFormat(t,{style:"currency",currency:r}).format(e);function s(e){return Array.isArray(e)?e.length:function(e){if("number"==typeof e)return Number.isFinite(e);if("string"!=typeof e)return!1;const t=e.trim();return!!t&&/^-?\d+(\.\d+)?$/.test(t)}(e)?Number(String(e).trim()):String(e??"").length}function o(e){const[t,r]=String(e??"").split(",").map(e=>e.trim()),n=Number(t),s=Number(r);return Number.isFinite(n)&&Number.isFinite(s)?{min:n,max:s}:null}const a=e=>new Promise(t=>setTimeout(t,e));function i(e,t){const r=String(e??"").trim();if(!r)return null;if("YYYY-MM-DD"===t){const e=r.match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!e)return null;const t=Number(e[1]),n=Number(e[2]),s=Number(e[3]);return!t||n<1||n>12||s<1||s>31?null:{year:t,month:n,day:s}}return null}function l(e,t,r="en-US"){const n=new Intl.DateTimeFormat(r,{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),s=Object.fromEntries(n.map(e=>[e.type,e.value]));return{year:Number(s.year),month:Number(s.month),day:Number(s.day),hour:Number(s.hour),minute:Number(s.minute),second:Number(s.second)}}function u({year:e,month:t,day:r},n){const s=new Date(Date.UTC(e,t-1,r));return s.setUTCDate(s.getUTCDate()+n),{year:s.getUTCFullYear(),month:s.getUTCMonth()+1,day:s.getUTCDate()}}function c(e,t,r){const{base:n,offsetDays:s}=function(e){const t=String(e).trim().match(/^(.+?)([+-]\d+)?$/);return t?{base:t[1].trim(),offsetDays:t[2]?Number(t[2]):0}:{base:String(e).trim(),offsetDays:0}}(e);let o=function(e,t){const r=new Date,{year:n,month:s,day:o}=l(r,t);return"today"===e?{year:n,month:s,day:o}:"tomorrow"===e?u({year:n,month:s,day:o},1):"yesterday"===e?u({year:n,month:s,day:o},-1):null}(n,r.timezone);if(!o){const e=t?.[n];o=d(e,r)}return o||(o=i(n,r.dateFormat)),o?(s&&(o=u(o,s)),o):null}function d(e,t){if(null==(r=e)||""===String(r??"").trim())return null;var r;const n=String(e).trim();let s=i(n,t.dateFormat);if(s)return s;if(!/^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2})?$/.test(n))return null;const o=new Date(n);if(isNaN(o.getTime()))return null;const a=l(o,t.timezone);return{year:a.year,month:a.month,day:a.day}}function m(e,t,r,n){let s=null;return s="value"===n?d(e,r):c(e,t,r),s?function({year:e,month:t,day:r},n){let s=Date.UTC(e,t-1,r,0,0,0);for(let o=0;o<2;o++){const o=l(new Date(s),n),a=Date.UTC(o.year,o.month-1,o.day,o.hour,o.minute,o.second)-Date.UTC(e,t-1,r,0,0,0);if(0===a)break;s-=a}return s}(s,r.timezone):null}function f(e,t){return{method:t=>(r,n,s)=>{const o=m(r,n,s,"value"),a=m(t,n,s,"target");return null!=o&&null!=a&&e(o,a)},message:t}}const h={required:{method:e=>""!==String(e??"").trim(),message:"This field is required"},requiredIf:{method:e=>(t,r)=>{const[n,s]=String(e).split("="),o=r?.[n];return!(null!=s?String(o??"")===s:""!==String(o??"").trim())||""!==String(t??"").trim()},message:e=>{const[t,r]=String(e).split("=");return null!=r?`This field is requied when ${t} is ${r}`:`This field is required when ${t} has a value`}},email:{method:e=>/\S+@\S+\.\S+/.test(e),message:"Email is invalid"},min:{method:e=>t=>String(t??"").length>=Number(e),message:e=>`Must be at least ${e} characters`},max:{method:e=>t=>String(t??"").length<=Number(e),message:e=>`Must be at most ${e} characters`},date:{method:e=>{if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;const[t,r,n]=e.split("-").map(Number),s=new Date(t,r-1,n);return s.getFullYear()===t&&s.getMonth()===r-1&&s.getDate()===n},message:"Date is invalid. Use the format YYYY-MM-DD."},currency:{method:e=>/^\$?\d{1,3}((,\d{3})*|\d*)(\.\d{2})?$/.test(e),message:"Currency is invalid. Use the format $123,456.78 or 123456.78."},same:{method:e=>(t,r)=>String(t??"")===String(r?.[e]??""),message:e=>`Must match ${e}`},in:{method:e=>t=>(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim()).filter(Boolean)).includes(String(t??"").trim()),message:e=>`Must be one of the following: ${(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim())).filter(Boolean).join(",")}`},before:f((e,t)=>e<t,e=>`Must be before ${e}`),beforeOrEqual:f((e,t)=>e<=t,e=>`Must be before or equal to ${e}`),after:f((e,t)=>e>t,e=>`Must be after ${e}`),afterOrEqual:f((e,t)=>e>=t,e=>`Must be after or equal to ${e}`),between:{method:e=>t=>{const r=o(e);if(!r)return!1;const n=s(t);return r.min<=n&&n<=r.max},message:e=>{const t=o(e);return t?`Must be between ${t.min} and ${t.max}`:"Between rule is invalid. Use between:min,max"}}};function y(e){const t=e.indexOf(":");return-1===t?{name:e,param:void 0}:{name:e.slice(0,t),param:e.slice(t+1)}}const p={run:function(e,t){let r=!0;const n={};for(const s in e){const o=e[s]||[];for(const e of o){const{name:o,param:a}=y(e),i=h[o];if(!i)continue;const l=t?.[s];if(!(void 0!==a?i.method(a)(l,t):i.method(l,t))){r=!1,n[s]||(n[s]=[]);const e="function"==typeof i.message?i.message(a):i.message;n[s].push(e)}}}return{isValid:r,errors:n}},ping:()=>console.log("PONG"),description:"V is for validating forms"},b=e=>({on:(t,r)=>e?.addEventListener(t,r),off:(t,r)=>e?.removeEventListener(t,r)}),g=(e,t)=>{if(!e)return;const r="innerText"in e?"innerText":"textContent";return null!=t&&(e[r]=t),e[r]},S=(e,t)=>{if(e)return null!=t&&(e.innerHTML=t),e.innerHTML},v=e=>document.createElement(e),w=e=>{let t="";const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n<e;n++)t+=r.charAt(Math.floor(62*Math.random()));return t},E=e=>{const t=document.implementation.createHTMLDocument("");return t.body.innerHTML=e,[...t.body.childNodes]},A=e=>{"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)},$=e=>{window.onload=e},T=e=>{const t="string"==typeof e?document.querySelector(e):e,r=e=>(...r)=>{if(t)return e(...r)},n={elt:t,value:t?.value,text:e=>null!=e?(g(t,e),n):g(t),html:e=>null!=e?(S(t,e),n):S(t),val:r(e=>{if(null!=e){if(t.opt&&t.multiple){const r=new Set(Array.isArray(e)?e:[e]);Array.from(t.options).forEach(e=>{e.selected=r.has(e.value)})}else t.value=e;return n.value=t.value,n}return t.options&&t.multiple?Array.from(t.options).filter(e=>e.selected).map(e=>e.value):t.value}),addClass:r(e=>(t.classList.add(e),n)),removeClass:r(e=>(t.classList.remove(e),n)),hasClass:r(e=>t.classList.contains(e)),hide:r(()=>(t.style.display="none",n)),show:r(()=>(t.style.display="",n)),prop:r(e=>t[e]),attr:r(e=>t.getAttribute(e)),removeAttr:e=>{t.removeAttribute(e)},toggle:r(()=>("none"==t.style.display?n.show():n.hide(),n)),css:r(e=>(Object.entries(e).forEach(([e,r])=>{t.style[e]=r}),n)),on:b(t).on,off:b(t).off};return n},C=e=>document.querySelectorAll(e),D={Q:T,$:T,all:C,$$:C,scan:(e,t={})=>{const r=t.refAttr||"v-ref",n="string"==typeof e?document.querySelector(e):e||document;if(!n)throw new Error(`Dom.scan: root "${e}" not found`);const s=Object.create(null);return n.querySelectorAll(`[${r}]`).forEach(e=>{const t=e.getAttribute(r);if(!t)return;const n=T(e);s[t]?Array.isArray(s[t])?s[t].push(n):s[t]=[s[t],n]:s[t]=n}),new Proxy({},{get(e,t){if("_"===t)return s;if("get"===t)return e=>s[e];if("all"===t)return e=>s[e]?Array.isArray(s[e])?s[e]:[s[e]]:[];if("on"===t)return(e,t,r)=>{const n=s[e];(Array.isArray(n)?n:[n]).forEach(e=>e?.on(t,r))};if("string"!=typeof t)return;const r=s[t];return r||(console.warn(`DOM.scan: ref "${t}" not found`),T(null))}})},make:v,makeId:w,parseHtml:E,onPageLoad:A,onWindowLoad:$,ping:()=>console.log("PONG!"),description:"DOM is for dom manipulation"};let I="",N=8e3,q=null,R=null,M=null;const x=new Map,L=new Map,O=()=>Date.now();function U(e){const t="undefined"!=typeof window?window[e]:null;return t?{get(e){const r=t.getItem(e);if(!r)return null;try{const n=JSON.parse(r);return n.exp&&n.exp<O()?(t.removeItem(e),null):n.val}catch{return null}},set(e,r,n){const s=n?O()+n:null;t.setItem(e,JSON.stringify({val:r,exp:s}))},del(e){t&&t.removeItem(e)},clear(){t&&t.clear()}}:null}const H={memory:{get(e){const t=L.get(e);return t?t.exp&&t.exp<O()?(L.delete(e),null):t.val:null},set(e,t,r){const n=r?O()+r:null;L.set(e,{val:t,exp:n})},del(e){L.delete(e)},clear(){L.clear()}},local:U("localStorage"),session:U("sessionStorage")};function k(e){return null===e||"object"!=typeof e?String(e):Array.isArray(e)?`[${e.map(k).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${k(e[t])}`).join(",")}}`}const F=(e,t)=>setTimeout(()=>t.abort(),e);async function j(e,t,r={}){const{params:n,body:s,headers:o={},cache:a}=r;let i=I+t;if(n){const e=new URLSearchParams(n).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c=!!a,d=a?.strategy,m=a?.ttl??0,f=function(e="memory"){return H[e]||H.memory}(a?.storage),h=a?.key||function(e,t,r,n){return`H|${e}|${t}${r?`?${new URLSearchParams(r).toString()}`:""}${n&&"GET"!==e?`#${k(n)}`:""}`}(e,i,n,s);if(c&&!a?.forceRefresh&&"cache-first"===d){const e=f.get(h);if(null!==e)return e}let y={method:e,headers:o,signal:l.signal};if(M){const{token:e,headerName:t}=M,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";y.headers[t]=`${e}${r}`}}void 0!==s&&(s instanceof FormData?y.body=s:(y.headers["Content-Type"]="application/json",y.body=JSON.stringify(s))),q&&(y=q(y)||y);try{let t,r=await fetch(i,y);x.has(r.status)&&x.get(r.status)(r,{method:e,url:i}),clearTimeout(u),R&&(r=R(r)||r);try{t=await r.json()}catch{t=await r.text()}if(!r.ok){const n={status:r.status,data:t,url:i,method:e};if(c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw n}return c&&f.set(h,t,m),t}catch(e){if(clearTimeout(u),c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw e}}async function P(e,{filename:t,params:r,headers:n={},method:s="GET",body:o,onProgress:a}={}){let i=I+e;if(r){const e=new URLSearchParams(r).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c={method:s,headers:{...n},signal:l.signal};void 0!==o&&(o instanceof FormData?c.body=o:(c.headers["Content-Type"]=c.headers["Content-Type"]||"application/json",c.body="string"==typeof o?o:JSON.stringify(o)));const d=await fetch(i,c);if(clearTimeout(u),!d.ok){let e="";try{e=await d.text()}catch{}throw new Error(`Download failed ${d.status}: ${e||d.statusText}`)}if(!t){const e=d.headers.get("Content-Disposition")||"",r=/filename\*=UTF-8''([^;]+)|filename="?([^"]+)"?/i.exec(e);t=decodeURIComponent(r?.[1]||r?.[2]||"download")}let m;if(d.body&&"getReader"in d.body){const e=d.body.getReader(),t=Number(d.headers.get("Content-Length"))||null,r=[];let n=0;for(;;){const{done:s,value:o}=await e.read();if(s)break;if(r.push(o),n+=o.length,"function"==typeof a){a(n,t,t?Math.round(n/t*100):null)}}m=new Blob(r)}else m=await d.blob(),"function"==typeof a&&a(1,1,100);const f=URL.createObjectURL(m),h=document.createElement("a");return h.href=f,h.download=t,h.style.display="none",document.body.appendChild(h),h.click(),document.body.removeChild(h),URL.revokeObjectURL(f),{filename:t,size:m.size,type:m.type}}function _(e,{files:t,fieldName:r="file",fields:n={},headers:s={},method:o="POST",onProgress:a,signal:i}={}){return new Promise((l,u)=>{const c=function({files:e,fieldName:t="file",fields:r={}}){const n=new FormData,s=Array.isArray(e)?e:[e];return s.forEach((e,r)=>{const o=s.length>1?`${t}[${r}]`:t;n.append(o,e)}),Object.entries(r).forEach(([e,t])=>{n.append(e,t instanceof Blob||t instanceof File?t:"object"==typeof t?JSON.stringify(t):String(t))}),n}({files:t,fieldName:r,fields:n}),d=`${I}${e}`,m=new XMLHttpRequest;m.open(o,d,!0);let f={method:o,headers:{...s}};if(M){const{token:e,headerName:t}=M,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";f.headers[t]=`${e}${r}`}}if(q&&(f=q(f)||f),Object.entries(f.headers).forEach(([e,t])=>m.setRequestHeader(e,t)),m.timeout=N,i){const e=()=>{try{m.abort()}catch{}};i.aborted&&e(),i.addEventListener("abort",e,{once:!0})}m.upload&&"function"==typeof a&&(m.upload.onprogress=e=>{if(!e.lengthComputable)return void a(e.loaded,null,null);const t=Math.round(e.loaded/e.total*100);a(e.loaded,e.total,t)}),m.onreadystatechange=async()=>{if(4!==m.readyState)return;if(R){const e={status:m.status,ok:m.status>=200&&m.status<300,headers:new Headers,text:async()=>m.responseText,json:async()=>JSON.parse(m.responseText||"null")};R(e)}const e=(m.getResponseHeader("Content-Type")||"").includes("application/json")?function(e){try{return JSON.parse(e||"null")}catch{return e}}(m.responseText):m.responseText;m.status>=200&&m.status<300?l(e):u({status:m.status,data:e,url:d,method:o})},m.onerror=()=>u({status:0,data:"Network error",url:`${I}${e}`,method:o}),m.ontimeout=()=>u({status:0,data:"Timeout",url:`${I}${e}`,method:o}),m.send(c)})}const B=(e,t)=>j("GET",e,t),V=(e,t,r={})=>j("POST",e,{...r,body:t}),G=(e,t,r={})=>j("PUT",e,{...r,body:t}),z=(e,t={})=>j("DELETE",e,t),J=(e,t)=>fetch(I+e,t),Y={base:e=>(I=e,Y),timeout:e=>(N=e,Y),bearer:(e,t="Authorization")=>(M={token:e,headerName:t},Y),onStatus:(e,t)=>(x.set(e,t),Y),onUnauthorized:e=>Y.onStatus(401,e),onForbidden:e=>Y.onStatus(403,e),onInternalServerError:e=>Y.onStatus(500,e),interceptRequest:e=>(q=e,Y),interceptResponse:e=>(R=e,Y),get:B,post:V,put:G,delete:z,raw:J,download:P,upload:_,ping:()=>console.log("PONG"),description:"H is for Http"};let Q=null,W=new Set;function K(e){let t=e;const r=new Set;return{get val(){return Q&&r.add(Q),t},set val(e){if(e!==t){t=e;for(const e of r)e()}},peek:()=>t,subscribe:e=>(r.add(e),()=>r.delete(e)),toString:()=>String(t),valueOf:()=>t}}function Z(e){const t=()=>{const r=Q;Q=t;try{e()}finally{Q=r}};return t(),t}function X(e){return"string"==typeof e?T(e):e}const ee={STATE_CHANGE:"form:state:change",ERRORS_CHANGE:"form:errors:change",SUBMIT_SUCCESS:"form:submit:success",SUBMIT_ERROR:"form:submit:error",RESET:"form:reset",VALIDATED:"form:validated"};class te{constructor(e,t,r,n={}){this.formId=e,this.schema=t,this.onSubmit=r,this.preSubmit=n.preSubmit||null,this.form=null,this.formState={},this.errors={},this.initialValues={},this._boundHandleSubmit=this.#e.bind(this),this._boundHandleInput=this.#t.bind(this),this.#r()}#r(){this.form=document.getElementById(this.formId),this.form?(this.#n(),this.form.addEventListener("submit",this._boundHandleSubmit),this.form.addEventListener("input",this._boundHandleInput),this.#s()):console.error(`Form with id ${this.formId} not found`)}#n(){const e=this.form.elements;for(const t of Array.from(e))t.name&&(this.initialValues[t.name]=t.value,this.formState[t.name]=t.value)}#t(e){const{name:t,value:r}=e.target;t&&(this.formState[t]=r,this.#s(),this.errors[t]&&(delete this.errors[t],this.#o()))}async#e(e){e.preventDefault();const r=new FormData(this.form);let n={};r.forEach((e,t)=>{n[t]=e}),this.formState=n,this.#s();const{isValid:s,errors:o}=p.run(this.schema,n);if(t.pub(ee.VALIDATED,{formId:this.formId,isValid:s,errors:o,data:n}),!s)return this.errors=o,this.#o(),void t.pub(ee.SUBMIT_ERROR,{formId:this.formId,errors:o});if(this.errors={},this.#o(),this.preSubmit)try{n=await this.preSubmit(n)}catch(e){return void t.pub(ee.SUBMIT_ERROR,{formId:this.formId,errors:{_preSubmit:[e.message]}})}t.pub(ee.SUBMIT_SUCCESS,{formId:this.formId,data:n}),this.onSubmit(n)}#s(){t.pub(ee.STATE_CHANGE,{formId:this.formId,state:{...this.formState}})}#o(){t.pub(ee.ERRORS_CHANGE,{formId:this.formId,errors:{...this.errors}})}getFormState(){return{...this.formState}}getErrors(){return{...this.errors}}reset(){this.formState={...this.initialValues},this.errors={},this.form&&this.form.reset(),this.#s(),this.#o(),t.pub(ee.RESET,{formId:this.formId})}validateNow(){const e=new FormData(this.form),r={};e.forEach((e,t)=>{r[t]=e});const n=p.run(this.schema,r);return this.errors=n.errors,this.#o(),t.pub(ee.VALIDATED,{formId:this.formId,isValid:n.isValid,errors:n.errors,data:r}),n}destroy(){this.form&&(this.form.removeEventListener("submit",this._boundHandleSubmit),this.form.removeEventListener("input",this._boundHandleInput))}}class re{constructor(e,r={}){this.formId=e,this.options={containerClass:"form-error-container",errorClass:"text-danger",insertAfterField:!0,...r},this.customContainers={},this._boundHandleErrors=this.#a.bind(this),t.sub(ee.ERRORS_CHANGE,this._boundHandleErrors)}#a({formId:e,errors:t}){e===this.formId&&(this.clearAll(),this.renderAll(t))}setContainer(e,t){this.customContainers[e]="string"==typeof t?document.querySelector(t):t}renderAll(e){for(const t in e)this.render(t,e[t])}render(e,t){if(!t||0===t.length)return null;const r=document.createElement("span");r.className=`${this.options.containerClass} ${this.options.errorClass}`,r.dataset.field=e;const n=document.createElement("ul");t.forEach(e=>{const t=document.createElement("li"),r=document.createElement("i");r.textContent=e,t.appendChild(r),n.appendChild(t)}),r.appendChild(n);const s=this.customContainers[e];if(s)s.innerHTML="",s.appendChild(r);else if(this.options.insertAfterField){const t=document.getElementById(this.formId),n=t?.querySelector(`[name="${e}"]`);n&&n.insertAdjacentElement("afterend",r)}return r}clearAll(){const e=document.getElementById(this.formId);if(!e)return;e.querySelectorAll(`.${this.options.containerClass}`).forEach(e=>e.remove());for(const e in this.customContainers)this.customContainers[e]&&(this.customContainers[e].innerHTML="")}destroy(){t.unsub(ee.ERRORS_CHANGE,this._boundHandleErrors),this.clearAll()}}const ne=(e={})=>{const{persistKey:r="query-cache",persistedKeys:n=null,defaultTtl:s=6e4,defaultStaleTime:o=5e3,defaultRetries:i=3,defaultRetryDelay:l=1e3}=e,u=new Map,c=new Map,d=(e,r,n)=>{t.pub(`query:${e}`,{key:r,...n}),t.pub(`query:${r}:${e}`,n)},m=()=>{try{const e=localStorage.getItem(r);if(!e)return;const n=JSON.parse(e),s=Date.now();for(const[e,t]of Object.entries(n))s<t.expiry&&u.set(e,{...t,promise:null});t.pub("query:hydrated",{keys:[...u.keys()]})}catch(e){console.warn("Failed to load query cache: ",e)}},f=()=>{try{const e={};for(const[t,r]of u.entries())void 0!==r.data&&(n&&!n.some(e=>t.startsWith(e))||(e[t]={data:r.data,staleAt:r.staleAt,expiry:r.expiry}));localStorage.setItem(r,JSON.stringify(e))}catch(e){console.warn("Failed to persist query cache: ",e)}};let h=null;const y=()=>{h&&clearTimeout(h),h=setTimeout(f,1e3)},p=e=>u.get(e)??null,b=async(e,t,r={})=>{const{ttl:n=s,staleTime:c=o,retries:m=i,retryDelay:f=l}=r,h=Date.now(),b=p(e);if(b&&h<b.staleAt)return d("hit",e,{data:b.data}),b.data;if(b?.promise)return b.promise;const g=b&&h<b.expiry;d("fetch",e,{isStale:g,hasCache:!!b});const S=(async(e,t,r,n)=>{let s;for(let o=0;o<=r;o++)try{return await t()}catch(t){if(s=t,o<r){const s=n*Math.pow(2,o);d("retry",e,{attempt:o+1,maxRetries:r,delay:s,error:t}),await a(s)}}throw s})(e,t,m,f).then(t=>(u.set(e,{data:t,staleAt:Date.now()+c,expiry:Date.now()+n,promise:null,error:null}),d("success",e,{data:t}),y(),t)).catch(t=>{throw u.set(e,{data:b?.data??null,staleAt:b?.staleAt??0,expiry:b?.expiry??0,promise:null,error:t}),d("error",e,{error:t,staleData:b?.data??null}),t});return u.set(e,{...b,promise:S}),g?b.data:S},g=(e,t)=>{const r=p(e);if(!r)return null;const n=r.data,s="function"==typeof t?t(n):t;return u.set(e,{...r,data:s}),d("mutate",e,{data:s,previous:n}),y(),n},S=(e,t={})=>{const{refetch:r,fetcher:n}=t;if(u.delete(e),d("invalidate",e,{}),y(),r&&n)return b(e,n)},v=e=>{const t=c.get(e);t&&(clearInterval(t),c.delete(e),d("polling:stop",e,{}))},w=()=>{for(const e of c.keys())v(e)},E=(e,t,r,n={})=>{v(e),b(e,t,n).catch(()=>{});const s=setInterval(()=>{const r=p(e);r&&u.set(e,{...r,staleAt:0}),b(e,t,n).catch(()=>{})},r);return c.set(e,s),d("polling:start",e,{interval:r}),()=>v(e)},A=()=>{const e=Date.now(),r=[];for(const[n,s]of u.entries())e>s.expiry&&!t.has(`query:${n}:success`)&&(u.delete(n),r.push(n));r.length&&(y(),t.pub("query:gc",{collected:r}))},$=(e,r)=>{const n=t=>r({...p(e),...t});t.sub(`query:${e}:success`,n),t.sub(`query:${e}:error`,n),t.sub(`query:${e}:mutate`,n),t.sub(`query:${e}:set`,n),t.sub(`query:${e}:invalidate`,()=>r(null));const s=p(e);return s&&r(s),()=>{t.unsub(`query:${e}:success`,n),t.unsub(`query:${e}:error`,n),t.unsub(`query:${e}:mutate`,n),t.unsub(`query:${e}:set`,n),t.unsub(`query:${e}:invalidate`,n)}};m(),setInterval(A,6e4),window.addEventListener("storage",e=>{if(e.key===r){m();for(const e of u.keys())d("sync",e,{data:u.get(e)?.data})}}),window.addEventListener("beforeunload",()=>{w(),f()});const T=(e,t,r={})=>{const n=K(r.inital??null),s=K(!1),o=K(null),a=$(e,e=>{e?.data&&(n.val=e.data),e?.error&&(o.val=e.error),s.val=!!e?.promise&&!e?.data}),i=()=>(s.val=!0,b(e,t,r));return!1!==r.enabled&&i().catch(()=>{}),{data:n,loading:s,error:o,fetch:i,refetch:()=>(S(e),i()),unsubscribe:a,mutate:t=>{const r=g(e,t);return n.val=p(e)?.data,r}}};return{query:b,mutate:g,setQueryData:(e,t,r={})=>{const{ttl:n=s,staleTime:a=o}=r,i=Date.now();u.set(e,{data:t,staleAt:i+a,expiry:i+n,promise:null,error:null}),d("set",e,{data:t}),y()},invalidate:S,invalidateMatching:e=>{const t=[];for(const r of u.keys())e(r)&&(u.delete(r),t.push(r),d("invalidate",r,{}));return y(),t},subscribe:$,prefetch:(e,t,r)=>{const n=p(e);n&&Date.now()<n.staleAt||b(e,t,r).catch(()=>{})},startPolling:E,stopPolling:v,stopAllPolling:w,getEntry:p,gc:A,querySignal:T,pollingSignal:(e,t,r,n={})=>({...T(e,t,{...n,enabled:!1}),stop:E(e,t,r,n)}),bindQuery:(e,r,n={})=>{const{target:s,render:o,onLoading:a,onError:i,poll:l=null,...u}=n,c="string"==typeof s?document.querySelector(s):s,d=e=>{const t=o(e);"string"==typeof t&&(c.innerHTML=t)};if(t.sub(`query:${e}:success`,({data:e})=>d(e)),t.sub(`query:${e}:set`,({data:e})=>d(e)),t.sub(`query:${e}:mutate`,({data:e})=>d(e)),i&&t.sub(`query:${e}:error`,({error:e,staleData:t})=>i(e,t,c)),a&&t.sub(`query:${e}:fetch`,({hasCache:e})=>{e||a(c)}),b(e,r,u).catch(()=>{}),l)return E(e,r,l,u)},clear:()=>{u.clear(),localStorage.removeItem(r),t.pub("query:cleared",{})}}},se=ne();return e.DOM=D,e.EVT=t,e.FormErrorRenderer=re,e.FormEvents=ee,e.FormHandler=te,e.HTTP=Y,e.Q=T,e.V=p,e.all=C,e.batch=function(e){e(),W.forEach(e=>e()),W.clear()},e.bind=function(e,t,r){const n=X(e);return Z(()=>{const e=r.val;switch(t){case"text":n.text(e);break;case"html":n.html(e);break;case"value":n.val(e);break;case"show":e?n.show():n.hide();break;case"hide":e?n.hide():n.show();break;case"disabled":n.elt.disabled=!!e;break;default:n.elt[t]=e}})},e.bindAttr=function(e,t,r){const n=X(e);return Z(()=>{n.elt.setAttribute(t,r.val)})},e.bindClass=function(e,t,r){const n=X(e);return Z(()=>{r.val?n.addClass(t):n.removeClass(t)})},e.bindHtml=function(e,t){const r=X(e);return Z(()=>{const e=t.val;r.html(e)})},e.bindList=function(e,t,r,n=""){const s=X(e);return Z(()=>{const e=t.val;s.html(e?.length?e.map(r).join(""):n)})},e.bindOptions=function(e,t,r={}){const{value:n="id",label:s="name",placeholder:o="Select ..."}=r,a=X(e);return Z(()=>{const e=t.val||[];a.html(`<option value="">${o}</option>`+e.map(e=>`<option value="${e[n]}">${e[s]}</option>`).join(""))})},e.bindText=function(e,t){const r=X(e);return Z(()=>{const e=t.val;r.text(e)})},e.bindValue=function(e,t){const r=X(e);return Z(()=>{const e=t.val;r.val(e)})},e.cache=function(e){if(null==e)return{cache:{strategy:"cache-first",storage:"local",ttl:6e4}};if("object"==typeof e)return{cache:e};const t=e.toLowerCase(),r={cfl:{strategy:"cache-first",storage:"local"},cfs:{strategy:"cache-first",storage:"session"},cfm:{strategy:"cache-first",storage:"memory"},nfl:{strategy:"network-first",storage:"local"},nfs:{strategy:"network-first",storage:"session"},nfm:{strategy:"network-first",storage:"memory"}},n=t.match(/cfl|cfs|cfm|nfl|nfs|nfm/),s=n?r[n[0]]:r.cfl,o=t.match(/(\d+)\s*(s|sec|secs|second|seconds|min|m|mins|minute|minutes|h|hr|hours)?/),a=o?function(e){const t=e.replace(/[0-9]/g,"").trim().toLowerCase(),r=parseInt(e,10),n={s:1e3,sec:1e3,secs:1e3,second:1e3,seconds:1e3,m:6e4,min:6e4,mins:6e4,minute:6e4,minutes:6e4,h:36e5,hr:36e5,hrs:36e5,hours:36e5};return r*(n[t]||1)}(o[0]):6e4;return{cache:{strategy:s.strategy,storage:s.storage,ttl:a}}},e.computed=function(e){const t=K(void 0);return Z(()=>{t.val=e()}),t},e.createQuery=ne,e.del=z,e.download=P,e.effect=Z,e.formatByCountry=(e,t)=>n(e,r[t]??r.US),e.get=B,e.isArray=e=>Array.isArray(e),e.isArrayEmpty=e=>!(Array.isArray(e)&&e.length>0),e.isFocus=e=>e==document.activeElement,e.isValidRoutingNumber=e=>{if(!/^\d{9}$/.test(e))return!1;const t=e.split("").map(Number);return(7*(t[0]+t[3]+t[6])+3*(t[1]+t[4]+t[7])+1*(t[2]+t[5]+t[8]))%10==0},e.make=v,e.makeId=w,e.onPageLoad=A,e.onWindowLoad=$,e.parseHtml=E,e.post=V,e.put=G,e.queryClient=se,e.raw=J,e.redirect=e=>window.location.href=e,e.request=j,e.signal=K,e.toCurrency=n,e.upload=_,e.useFormHandler=function(e,t,r,n){const s=new te(e,t,r,n),o=new re(e,n);return{reset:()=>s.reset(),validate:()=>s.validateNow(),destroy:()=>{o.destroy(),s.destroy()},setContainer:(e,t)=>o.setContainer(e,t)}},e.when=function(e,t){return Z(()=>{e.val&&t(e.val)})},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),e}({});
package/dist/vaniy.min.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).vaniy={})}(this,function(e){"use strict";const t={listeners:new Map,sub:function(e,t){let r=this.listeners.get(e);r||(r=new Set,this.listeners.set(e,r)),r.add(t)},once:function(e,t){const r=(...n)=>{t(...n),this.unsub(e,r)};this.sub(e,r)},unsub:function(e,t){let r=this.listeners.get(e);r&&r.delete(t)},pub:function(e,...t){let r=this.listeners.get(e);r&&r.forEach(r=>{try{r(...t)}catch(t){console.error(`Error in event "${e}" listener: `,t)}})},has:function(e){return this.listeners.has(e)&&this.listeners.get(e).size>0},clear:function(e){e?this.listeners.delete(e):this.listeners.clear()},ping:()=>console.log("PONG!"),description:"EVT is for Event publishing and emitting"},r={US:{locale:"en-US",currency:"USD"},CA:{locale:"en-CA",currency:"CAD"},FR:{locale:"fr-FR",currency:"EUR"},HT:{locale:"ht-HT",currency:"HTG"},GB:{locale:"en-GB",currency:"GBP"},AU:{locale:"en-AU",currency:"AUD"}},n=(e,{locale:t="en-US",currency:r="USD"}={})=>Intl.NumberFormat(t,{style:"currency",currency:r}).format(e);function s(e){return Array.isArray(e)?e.length:function(e){if("number"==typeof e)return Number.isFinite(e);if("string"!=typeof e)return!1;const t=e.trim();return!!t&&/^-?\d+(\.\d+)?$/.test(t)}(e)?Number(String(e).trim()):String(e??"").length}function o(e){const[t,r]=String(e??"").split(",").map(e=>e.trim()),n=Number(t),s=Number(r);return Number.isFinite(n)&&Number.isFinite(s)?{min:n,max:s}:null}const a=e=>new Promise(t=>setTimeout(t,e));function i(e,t){const r=String(e??"").trim();if(!r)return null;if("YYYY-MM-DD"===t){const e=r.match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!e)return null;const t=Number(e[1]),n=Number(e[2]),s=Number(e[3]);return!t||n<1||n>12||s<1||s>31?null:{year:t,month:n,day:s}}return null}function l(e,t,r="en-US"){const n=new Intl.DateTimeFormat(r,{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),s=Object.fromEntries(n.map(e=>[e.type,e.value]));return{year:Number(s.year),month:Number(s.month),day:Number(s.day),hour:Number(s.hour),minute:Number(s.minute),second:Number(s.second)}}function u({year:e,month:t,day:r},n){const s=new Date(Date.UTC(e,t-1,r));return s.setUTCDate(s.getUTCDate()+n),{year:s.getUTCFullYear(),month:s.getUTCMonth()+1,day:s.getUTCDate()}}function c(e,t,r){const{base:n,offsetDays:s}=function(e){const t=String(e).trim().match(/^(.+?)([+-]\d+)?$/);return t?{base:t[1].trim(),offsetDays:t[2]?Number(t[2]):0}:{base:String(e).trim(),offsetDays:0}}(e);let o=function(e,t){const r=new Date,{year:n,month:s,day:o}=l(r,t);return"today"===e?{year:n,month:s,day:o}:"tomorrow"===e?u({year:n,month:s,day:o},1):"yesterday"===e?u({year:n,month:s,day:o},-1):null}(n,r.timezone);if(!o){const e=t?.[n];o=d(e,r)}return o||(o=i(n,r.dateFormat)),o?(s&&(o=u(o,s)),o):null}function d(e,t){if(null==(r=e)||""===String(r??"").trim())return null;var r;const n=String(e).trim();let s=i(n,t.dateFormat);if(s)return s;if(!/^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2})?$/.test(n))return null;const o=new Date(n);if(isNaN(o.getTime()))return null;const a=l(o,t.timezone);return{year:a.year,month:a.month,day:a.day}}function m(e,t,r,n){let s=null;return s="value"===n?d(e,r):c(e,t,r),s?function({year:e,month:t,day:r},n){let s=Date.UTC(e,t-1,r,0,0,0);for(let o=0;o<2;o++){const o=l(new Date(s),n),a=Date.UTC(o.year,o.month-1,o.day,o.hour,o.minute,o.second)-Date.UTC(e,t-1,r,0,0,0);if(0===a)break;s-=a}return s}(s,r.timezone):null}function f(e,t){return{method:t=>(r,n,s)=>{const o=m(r,n,s,"value"),a=m(t,n,s,"target");return null!=o&&null!=a&&e(o,a)},message:t}}const h={required:{method:e=>""!==String(e??"").trim(),message:"This field is required"},requiredIf:{method:e=>(t,r)=>{const[n,s]=String(e).split("="),o=r?.[n];return!(null!=s?String(o??"")===s:""!==String(o??"").trim())||""!==String(t??"").trim()},message:e=>{const[t,r]=String(e).split("=");return null!=r?`This field is requied when ${t} is ${r}`:`This field is required when ${t} has a value`}},email:{method:e=>/\S+@\S+\.\S+/.test(e),message:"Email is invalid"},min:{method:e=>t=>String(t??"").length>=Number(e),message:e=>`Must be at least ${e} characters`},max:{method:e=>t=>String(t??"").length<=Number(e),message:e=>`Must be at most ${e} characters`},date:{method:e=>{if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;const[t,r,n]=e.split("-").map(Number),s=new Date(t,r-1,n);return s.getFullYear()===t&&s.getMonth()===r-1&&s.getDate()===n},message:"Date is invalid. Use the format YYYY-MM-DD."},currency:{method:e=>/^\$?\d{1,3}((,\d{3})*|\d*)(\.\d{2})?$/.test(e),message:"Currency is invalid. Use the format $123,456.78 or 123456.78."},same:{method:e=>(t,r)=>String(t??"")===String(r?.[e]??""),message:e=>`Must match ${e}`},in:{method:e=>t=>(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim()).filter(Boolean)).includes(String(t??"").trim()),message:e=>`Must be one of the following: ${(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim())).filter(Boolean).join(",")}`},before:f((e,t)=>e<t,e=>`Must be before ${e}`),beforeOrEqual:f((e,t)=>e<=t,e=>`Must be before or equal to ${e}`),after:f((e,t)=>e>t,e=>`Must be after ${e}`),afterOrEqual:f((e,t)=>e>=t,e=>`Must be after or equal to ${e}`),between:{method:e=>t=>{const r=o(e);if(!r)return!1;const n=s(t);return r.min<=n&&n<=r.max},message:e=>{const t=o(e);return t?`Must be between ${t.min} and ${t.max}`:"Between rule is invalid. Use between:min,max"}}};function y(e){const t=e.indexOf(":");return-1===t?{name:e,param:void 0}:{name:e.slice(0,t),param:e.slice(t+1)}}const p={run:function(e,t){let r=!0;const n={};for(const s in e){const o=e[s]||[];for(const e of o){const{name:o,param:a}=y(e),i=h[o];if(!i)continue;const l=t?.[s];if(!(void 0!==a?i.method(a)(l,t):i.method(l,t))){r=!1,n[s]||(n[s]=[]);const e="function"==typeof i.message?i.message(a):i.message;n[s].push(e)}}}return{isValid:r,errors:n}},ping:()=>console.log("PONG"),description:"V is for validating forms"},g=e=>({on:(t,r)=>e?.addEventListener(t,r),off:(t,r)=>e?.removeEventListener(t,r)}),b=(e,t)=>{if(!e)return;const r="innerText"in e?"innerText":"textContent";return null!=t&&(e[r]=t),e[r]},S=(e,t)=>{if(e)return null!=t&&(e.innerHTML=t),e.innerHTML},w=e=>document.createElement(e),E=e=>{let t="";const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n<e;n++)t+=r.charAt(Math.floor(62*Math.random()));return t},v=e=>{const t=document.implementation.createHTMLDocument("");return t.body.innerHTML=e,[...t.body.childNodes]},A=e=>{"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)},T=e=>{window.onload=e},$=e=>{const t="string"==typeof e?document.querySelector(e):e,r=e=>(...r)=>{if(t)return e(...r)},n={elt:t,value:t?.value,text:e=>null!=e?(b(t,e),n):b(t),html:e=>null!=e?(S(t,e),n):S(t),val:r(e=>{if(null!=e){if(t.opt&&t.multiple){const r=new Set(Array.isArray(e)?e:[e]);Array.from(t.options).forEach(e=>{e.selected=r.has(e.value)})}else t.value=e;return n.value=t.value,n}return t.options&&t.multiple?Array.from(t.options).filter(e=>e.selected).map(e=>e.value):t.value}),addClass:r(e=>(t.classList.add(e),n)),removeClass:r(e=>(t.classList.remove(e),n)),hasClass:r(e=>t.classList.contains(e)),hide:r(()=>(t.style.display="none",n)),show:r(()=>(t.style.display="",n)),prop:r(e=>t[e]),attr:r(e=>t.getAttribute(e)),removeAttr:e=>{t.removeAttribute(e)},toggle:r(()=>("none"==t.style.display?n.show():n.hide(),n)),css:r(e=>(Object.entries(e).forEach(([e,r])=>{t.style[e]=r}),n)),on:g(t).on,off:g(t).off};return n},C=e=>document.querySelectorAll(e),D={Q:$,$:$,all:C,$$:C,scan:(e,t={})=>{const r=t.refAttr||"v-ref",n="string"==typeof e?document.querySelector(e):e||document;if(!n)throw new Error(`Dom.scan: root "${e}" not found`);const s=Object.create(null);return n.querySelectorAll(`[${r}]`).forEach(e=>{const t=e.getAttribute(r);if(!t)return;const n=$(e);s[t]?Array.isArray(s[t])?s[t].push(n):s[t]=[s[t],n]:s[t]=n}),new Proxy({},{get(e,t){if("_"===t)return s;if("get"===t)return e=>s[e];if("all"===t)return e=>s[e]?Array.isArray(s[e])?s[e]:[s[e]]:[];if("on"===t)return(e,t,r)=>{const n=s[e];(Array.isArray(n)?n:[n]).forEach(e=>e?.on(t,r))};if("string"!=typeof t)return;const r=s[t];return r||(console.warn(`DOM.scan: ref "${t}" not found`),$(null))}})},make:w,makeId:E,parseHtml:v,onPageLoad:A,onWindowLoad:T,ping:()=>console.log("PONG!"),description:"DOM is for dom manipulation"};let I="",N=8e3,q=null,R=null,M=null;const x=new Map,L=new Map,O=()=>Date.now();function U(e){const t="undefined"!=typeof window?window[e]:null;return t?{get(e){const r=t.getItem(e);if(!r)return null;try{const n=JSON.parse(r);return n.exp&&n.exp<O()?(t.removeItem(e),null):n.val}catch{return null}},set(e,r,n){const s=n?O()+n:null;t.setItem(e,JSON.stringify({val:r,exp:s}))},del(e){t&&t.removeItem(e)},clear(){t&&t.clear()}}:null}const H={memory:{get(e){const t=L.get(e);return t?t.exp&&t.exp<O()?(L.delete(e),null):t.val:null},set(e,t,r){const n=r?O()+r:null;L.set(e,{val:t,exp:n})},del(e){L.delete(e)},clear(){L.clear()}},local:U("localStorage"),session:U("sessionStorage")};function k(e){return null===e||"object"!=typeof e?String(e):Array.isArray(e)?`[${e.map(k).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${k(e[t])}`).join(",")}}`}const F=(e,t)=>setTimeout(()=>t.abort(),e);async function P(e,t,r={}){const{params:n,body:s,headers:o={},cache:a}=r;let i=I+t;if(n){const e=new URLSearchParams(n).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c=!!a,d=a?.strategy,m=a?.ttl??0,f=function(e="memory"){return H[e]||H.memory}(a?.storage),h=a?.key||function(e,t,r,n){return`H|${e}|${t}${r?`?${new URLSearchParams(r).toString()}`:""}${n&&"GET"!==e?`#${k(n)}`:""}`}(e,i,n,s);if(c&&!a?.forceRefresh&&"cache-first"===d){const e=f.get(h);if(null!==e)return e}let y={method:e,headers:o,signal:l.signal};if(M){const{token:e,headerName:t}=M,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";y.headers[t]=`${e}${r}`}}void 0!==s&&(s instanceof FormData?y.body=s:(y.headers["Content-Type"]="application/json",y.body=JSON.stringify(s))),q&&(y=q(y)||y);try{let t,r=await fetch(i,y);x.has(r.status)&&x.get(r.status)(r,{method:e,url:i}),clearTimeout(u),R&&(r=R(r)||r);try{t=await r.json()}catch{t=await r.text()}if(!r.ok){const n={status:r.status,data:t,url:i,method:e};if(c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw n}return c&&f.set(h,t,m),t}catch(e){if(clearTimeout(u),c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw e}}async function j(e,{filename:t,params:r,headers:n={},method:s="GET",body:o,onProgress:a}={}){let i=I+e;if(r){const e=new URLSearchParams(r).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c={method:s,headers:{...n},signal:l.signal};void 0!==o&&(o instanceof FormData?c.body=o:(c.headers["Content-Type"]=c.headers["Content-Type"]||"application/json",c.body="string"==typeof o?o:JSON.stringify(o)));const d=await fetch(i,c);if(clearTimeout(u),!d.ok){let e="";try{e=await d.text()}catch{}throw new Error(`Download failed ${d.status}: ${e||d.statusText}`)}if(!t){const e=d.headers.get("Content-Disposition")||"",r=/filename\*=UTF-8''([^;]+)|filename="?([^"]+)"?/i.exec(e);t=decodeURIComponent(r?.[1]||r?.[2]||"download")}let m;if(d.body&&"getReader"in d.body){const e=d.body.getReader(),t=Number(d.headers.get("Content-Length"))||null,r=[];let n=0;for(;;){const{done:s,value:o}=await e.read();if(s)break;if(r.push(o),n+=o.length,"function"==typeof a){a(n,t,t?Math.round(n/t*100):null)}}m=new Blob(r)}else m=await d.blob(),"function"==typeof a&&a(1,1,100);const f=URL.createObjectURL(m),h=document.createElement("a");return h.href=f,h.download=t,h.style.display="none",document.body.appendChild(h),h.click(),document.body.removeChild(h),URL.revokeObjectURL(f),{filename:t,size:m.size,type:m.type}}function _(e,{files:t,fieldName:r="file",fields:n={},headers:s={},method:o="POST",onProgress:a,signal:i}={}){return new Promise((l,u)=>{const c=function({files:e,fieldName:t="file",fields:r={}}){const n=new FormData,s=Array.isArray(e)?e:[e];return s.forEach((e,r)=>{const o=s.length>1?`${t}[${r}]`:t;n.append(o,e)}),Object.entries(r).forEach(([e,t])=>{n.append(e,t instanceof Blob||t instanceof File?t:"object"==typeof t?JSON.stringify(t):String(t))}),n}({files:t,fieldName:r,fields:n}),d=`${I}${e}`,m=new XMLHttpRequest;m.open(o,d,!0);let f={method:o,headers:{...s}};if(M){const{token:e,headerName:t}=M,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";f.headers[t]=`${e}${r}`}}if(q&&(f=q(f)||f),Object.entries(f.headers).forEach(([e,t])=>m.setRequestHeader(e,t)),m.timeout=N,i){const e=()=>{try{m.abort()}catch{}};i.aborted&&e(),i.addEventListener("abort",e,{once:!0})}m.upload&&"function"==typeof a&&(m.upload.onprogress=e=>{if(!e.lengthComputable)return void a(e.loaded,null,null);const t=Math.round(e.loaded/e.total*100);a(e.loaded,e.total,t)}),m.onreadystatechange=async()=>{if(4!==m.readyState)return;if(R){const e={status:m.status,ok:m.status>=200&&m.status<300,headers:new Headers,text:async()=>m.responseText,json:async()=>JSON.parse(m.responseText||"null")};R(e)}const e=(m.getResponseHeader("Content-Type")||"").includes("application/json")?function(e){try{return JSON.parse(e||"null")}catch{return e}}(m.responseText):m.responseText;m.status>=200&&m.status<300?l(e):u({status:m.status,data:e,url:d,method:o})},m.onerror=()=>u({status:0,data:"Network error",url:`${I}${e}`,method:o}),m.ontimeout=()=>u({status:0,data:"Timeout",url:`${I}${e}`,method:o}),m.send(c)})}const B=(e,t)=>P("GET",e,t),V=(e,t,r={})=>P("POST",e,{...r,body:t}),G=(e,t,r={})=>P("PUT",e,{...r,body:t}),z=(e,t={})=>P("DELETE",e,t),J=(e,t)=>fetch(I+e,t),Y={base:e=>(I=e,Y),timeout:e=>(N=e,Y),bearer:(e,t="Authorization")=>(M={token:e,headerName:t},Y),onStatus:(e,t)=>(x.set(e,t),Y),onUnauthorized:e=>Y.onStatus(401,e),onForbidden:e=>Y.onStatus(403,e),onInternalServerError:e=>Y.onStatus(500,e),interceptRequest:e=>(q=e,Y),interceptResponse:e=>(R=e,Y),get:B,post:V,put:G,delete:z,raw:J,download:j,upload:_,ping:()=>console.log("PONG"),description:"H is for Http"},K={STATE_CHANGE:"form:state:change",ERRORS_CHANGE:"form:errors:change",SUBMIT_SUCCESS:"form:submit:success",SUBMIT_ERROR:"form:submit:error",RESET:"form:reset",VALIDATED:"form:validated"};class Q{constructor(e,t,r,n={}){this.formId=e,this.schema=t,this.onSubmit=r,this.preSubmit=n.preSubmit||null,this.form=null,this.formState={},this.errors={},this.initialValues={},this._boundHandleSubmit=this.#e.bind(this),this._boundHandleInput=this.#t.bind(this),this.#r()}#r(){this.form=document.getElementById(this.formId),this.form?(this.#n(),this.form.addEventListener("submit",this._boundHandleSubmit),this.form.addEventListener("input",this._boundHandleInput),this.#s()):console.error(`Form with id ${this.formId} not found`)}#n(){const e=this.form.elements;for(const t of Array.from(e))t.name&&(this.initialValues[t.name]=t.value,this.formState[t.name]=t.value)}#t(e){const{name:t,value:r}=e.target;t&&(this.formState[t]=r,this.#s(),this.errors[t]&&(delete this.errors[t],this.#o()))}async#e(e){e.preventDefault();const r=new FormData(this.form);let n={};r.forEach((e,t)=>{n[t]=e}),this.formState=n,this.#s();const{isValid:s,errors:o}=p.run(this.schema,n);if(t.pub(K.VALIDATED,{formId:this.formId,isValid:s,errors:o,data:n}),!s)return this.errors=o,this.#o(),void t.pub(K.SUBMIT_ERROR,{formId:this.formId,errors:o});if(this.errors={},this.#o(),this.preSubmit)try{n=await this.preSubmit(n)}catch(e){return void t.pub(K.SUBMIT_ERROR,{formId:this.formId,errors:{_preSubmit:[e.message]}})}t.pub(K.SUBMIT_SUCCESS,{formId:this.formId,data:n}),this.onSubmit(n)}#s(){t.pub(K.STATE_CHANGE,{formId:this.formId,state:{...this.formState}})}#o(){t.pub(K.ERRORS_CHANGE,{formId:this.formId,errors:{...this.errors}})}getFormState(){return{...this.formState}}getErrors(){return{...this.errors}}reset(){this.formState={...this.initialValues},this.errors={},this.form&&this.form.reset(),this.#s(),this.#o(),t.pub(K.RESET,{formId:this.formId})}validateNow(){const e=new FormData(this.form),r={};e.forEach((e,t)=>{r[t]=e});const n=p.run(this.schema,r);return this.errors=n.errors,this.#o(),t.pub(K.VALIDATED,{formId:this.formId,isValid:n.isValid,errors:n.errors,data:r}),n}destroy(){this.form&&(this.form.removeEventListener("submit",this._boundHandleSubmit),this.form.removeEventListener("input",this._boundHandleInput))}}class W{constructor(e,r={}){this.formId=e,this.options={containerClass:"form-error-container",errorClass:"text-danger",insertAfterField:!0,...r},this.customContainers={},this._boundHandleErrors=this.#a.bind(this),t.sub(K.ERRORS_CHANGE,this._boundHandleErrors)}#a({formId:e,errors:t}){e===this.formId&&(this.clearAll(),this.renderAll(t))}setContainer(e,t){this.customContainers[e]="string"==typeof t?document.querySelector(t):t}renderAll(e){for(const t in e)this.render(t,e[t])}render(e,t){if(!t||0===t.length)return null;const r=document.createElement("span");r.className=`${this.options.containerClass} ${this.options.errorClass}`,r.dataset.field=e;const n=document.createElement("ul");t.forEach(e=>{const t=document.createElement("li"),r=document.createElement("i");r.textContent=e,t.appendChild(r),n.appendChild(t)}),r.appendChild(n);const s=this.customContainers[e];if(s)s.innerHTML="",s.appendChild(r);else if(this.options.insertAfterField){const t=document.getElementById(this.formId),n=t?.querySelector(`[name="${e}"]`);n&&n.insertAdjacentElement("afterend",r)}return r}clearAll(){const e=document.getElementById(this.formId);if(!e)return;e.querySelectorAll(`.${this.options.containerClass}`).forEach(e=>e.remove());for(const e in this.customContainers)this.customContainers[e]&&(this.customContainers[e].innerHTML="")}destroy(){t.unsub(K.ERRORS_CHANGE,this._boundHandleErrors),this.clearAll()}}function Z(e){let t=e;const r=new Set;return{get val(){return t},set val(e){if(e!==t){t=e;for(const e of r)e()}},peek:()=>t,subscribe:e=>(r.add(e),()=>r.delete(e)),toString:()=>String(t),valueOf:()=>t}}const X=((e={})=>{const{persistKey:r="query-cache",persistedKeys:n=null,defaultTtl:s=6e4,defaultStaleTime:o=5e3,defaultRetries:i=3,defaultRetryDelay:l=1e3}=e,u=new Map,c=new Map,d=(e,r,n)=>{t.pub(`query:${e}`,{key:r,...n}),t.pub(`query:${r}:${e}`,n)},m=()=>{try{const e=localStorage.getItem(r);if(!e)return;const n=JSON.parse(e),s=Date.now();for(const[e,t]of Object.entries(n))s<t.expiry&&u.set(e,{...t,promise:null});t.pub("query:hydrated",{keys:[...u.keys()]})}catch(e){console.warn("Failed to load query cache: ",e)}},f=()=>{try{const e={};for(const[t,r]of u.entries())void 0!==r.data&&(n&&!n.some(e=>t.startsWith(e))||(e[t]={data:r.data,staleAt:r.staleAt,expiry:r.expiry}));localStorage.setItem(r,JSON.stringify(e))}catch(e){console.warn("Failed to persist query cache: ",e)}};let h=null;const y=()=>{h&&clearTimeout(h),h=setTimeout(f,1e3)},p=e=>u.get(e)??null,g=async(e,t,r={})=>{const{ttl:n=s,staleTime:c=o,retries:m=i,retryDelay:f=l}=r,h=Date.now(),g=p(e);if(g&&h<g.staleAt)return d("hit",e,{data:g.data}),g.data;if(g?.promise)return g.promise;const b=g&&h<g.expiry;d("fetch",e,{isStale:b,hasCache:!!g});const S=(async(e,t,r,n)=>{let s;for(let o=0;o<=r;o++)try{return await t()}catch(t){if(s=t,o<r){const s=n*Math.pow(2,o);d("retry",e,{attempt:o+1,maxRetries:r,delay:s,error:t}),await a(s)}}throw s})(e,t,m,f).then(t=>(u.set(e,{data:t,staleAt:Date.now()+c,expiry:Date.now()+n,promise:null,error:null}),d("success",e,{data:t}),y(),t)).catch(t=>{throw u.set(e,{data:g?.data??null,staleAt:g?.staleAt??0,expiry:g?.expiry??0,promise:null,error:t}),d("error",e,{error:t,staleData:g?.data??null}),t});return u.set(e,{...g,promise:S}),b?g.data:S},b=e=>{const t=c.get(e);t&&(clearInterval(t),c.delete(e),d("polling:stop",e,{}))},S=()=>{for(const e of c.keys())b(e)},w=()=>{const e=Date.now(),r=[];for(const[n,s]of u.entries())e>s.expiry&&!t.has(`query:${n}:success`)&&(u.delete(n),r.push(n));r.length&&(y(),t.pub("query:gc",{collected:r}))};return m(),setInterval(w,6e4),window.addEventListener("storage",e=>{if(e.key===r){m();for(const e of u.keys())d("sync",e,{data:u.get(e)?.data})}}),window.addEventListener("beforeunload",()=>{S(),f()}),{query:g,mutate:(e,t)=>{const r=p(e);if(!r)return null;const n=r.data,s="function"==typeof t?t(n):t;return u.set(e,{...r,data:s}),d("mutate",e,{data:s,previous:n}),y(),n},setQueryData:(e,t,r={})=>{const{ttl:n=s,staleTime:a=o}=r,i=Date.now();u.set(e,{data:t,staleAt:i+a,expiry:i+n,promise:null,error:null}),d("set",e,{data:t}),y()},invalidate:(e,t={})=>{const{refetch:r,fetcher:n}=t;if(u.delete(e),d("invalidate",e,{}),y(),r&&n)return g(e,n)},invalidateMatching:e=>{const t=[];for(const r of u.keys())e(r)&&(u.delete(r),t.push(r),d("invalidate",r,{}));return y(),t},subscribe:(e,r)=>{const n=t=>r({...p(e),...t});t.sub(`query:${e}:success`,n),t.sub(`query:${e}:error`,n),t.sub(`query:${e}:mutate`,n),t.sub(`query:${e}:set`,n),t.sub(`query:${e}:invalidate`,()=>r(null));const s=p(e);return s&&r(s),()=>{t.unsub(`query:${e}:success`,n),t.unsub(`query:${e}:error`,n),t.unsub(`query:${e}:mutate`,n),t.unsub(`query:${e}:set`,n),t.unsub(`query:${e}:invalidate`,n)}},prefetch:(e,t,r)=>{const n=p(e);n&&Date.now()<n.staleAt||g(e,t,r).catch(()=>{})},startPolling:(e,t,r,n={})=>{b(e),g(e,t,n).catch(()=>{});const s=setInterval(()=>{const r=p(e);r&&u.set(e,{...r,staleAt:0}),g(e,t,n).catch(()=>{})},r);return c.set(e,s),d("polling:start",e,{interval:r}),()=>b(e)},stopPolling:b,stopAllPolling:S,getEntry:p,gc:w,clear:()=>{u.clear(),localStorage.removeItem(r),t.pub("query:cleared",{})}}})({persistKey:"teksoft-cache",persistedKeys:["user","settings"]}),ee=(e,t,r={})=>{const n=Z(r.inital??null),s=Z(!1),o=Z(null),a=X.subscribe(e,e=>{e?.data&&(n.val=e.data),e?.error&&(o.val=e.error),s.val=!!e?.promise&&!e?.data}),i=()=>(s.val=!0,X.query(e,t,r));return!1!==r.enabled&&i(),{data:n,loading:s,error:o,fetch:i,refetch:()=>(X.invalidate(e),i()),unsubscribe:a,mutate:t=>{const r=X.mutate(e,t);return n.val=X.getEntry(e)?.data,r}}};e.DOM=D,e.EVT=t,e.FormErrorRenderer=W,e.FormEvents=K,e.FormHandler=Q,e.HTTP=Y,e.Q=$,e.V=p,e.all=C,e.bindQuery=(e,r,n={})=>{const{target:s,render:o,onLoading:a,onError:i,poll:l=null,...u}=n,c="string"==typeof s?document.querySelector(s):s,d=e=>{const t=o(e);"string"==typeof t&&(c.innerHTML=t)};if(t.sub(`query:${e}:success`,({data:e})=>d(e)),t.sub(`query:${e}:set`,({data:e})=>d(e)),t.sub(`query:${e}:mutate`,({data:e})=>d(e)),i&&t.sub(`query:${e}:error`,({error:e,staleData:t})=>i(e,t,c)),a&&t.sub(`query:${e}:fetch`,({hasCache:e})=>{e||a(c)}),X.query(e,r,u).catch(()=>{}),l)return X.startPolling(e,r,l,u)},e.cache=function(e){if(null==e)return{cache:{strategy:"cache-first",storage:"local",ttl:6e4}};if("object"==typeof e)return{cache:e};const t=e.toLowerCase(),r={cfl:{strategy:"cache-first",storage:"local"},cfs:{strategy:"cache-first",storage:"session"},cfm:{strategy:"cache-first",storage:"memory"},nfl:{strategy:"network-first",storage:"local"},nfs:{strategy:"network-first",storage:"session"},nfm:{strategy:"network-first",storage:"memory"}},n=t.match(/cfl|cfs|cfm|nfl|nfs|nfm/),s=n?r[n[0]]:r.cfl,o=t.match(/(\d+)\s*(s|sec|secs|second|seconds|min|m|mins|minute|minutes|h|hr|hours)?/),a=o?function(e){const t=e.replace(/[0-9]/g,"").trim().toLowerCase(),r=parseInt(e,10),n={s:1e3,sec:1e3,secs:1e3,second:1e3,seconds:1e3,m:6e4,min:6e4,mins:6e4,minute:6e4,minutes:6e4,h:36e5,hr:36e5,hrs:36e5,hours:36e5};return r*(n[t]||1)}(o[0]):6e4;return{cache:{strategy:s.strategy,storage:s.storage,ttl:a}}},e.del=z,e.download=j,e.formatByCountry=(e,t)=>n(e,r[t]??r.US),e.get=B,e.isArray=e=>Array.isArray(e),e.isArrayEmpty=e=>!(Array.isArray(e)&&e.length>0),e.isFocus=e=>e==document.activeElement,e.isValidRoutingNumber=e=>{if(!/^\d{9}$/.test(e))return!1;const t=e.split("").map(Number);return(7*(t[0]+t[3]+t[6])+3*(t[1]+t[4]+t[7])+1*(t[2]+t[5]+t[8]))%10==0},e.make=w,e.makeId=E,e.onPageLoad=A,e.onWindowLoad=T,e.parseHtml=v,e.pollingSignal=(e,t,r,n={})=>({...ee(e,t,{...n,enabled:!1}),stop:X.startPolling(e,t,r,n)}),e.post=V,e.put=G,e.queryClient=X,e.querySignal=ee,e.raw=J,e.redirect=e=>window.location.href=e,e.request=P,e.toCurrency=n,e.upload=_,e.useFormHandler=function(e,t,r,n){const s=new Q(e,t,r,n),o=new W(e,n);return{reset:()=>s.reset(),validate:()=>s.validateNow(),destroy:()=>{o.destroy(),s.destroy()},setContainer:(e,t)=>o.setContainer(e,t)}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).vaniy={})}(this,function(e){"use strict";const t={listeners:new Map,sub:function(e,t){let r=this.listeners.get(e);r||(r=new Set,this.listeners.set(e,r)),r.add(t)},once:function(e,t){const r=(...n)=>{t(...n),this.unsub(e,r)};this.sub(e,r)},unsub:function(e,t){let r=this.listeners.get(e);r&&r.delete(t)},pub:function(e,...t){let r=this.listeners.get(e);r&&r.forEach(r=>{try{r(...t)}catch(t){console.error(`Error in event "${e}" listener: `,t)}})},has:function(e){return this.listeners.has(e)&&this.listeners.get(e).size>0},clear:function(e){e?this.listeners.delete(e):this.listeners.clear()},ping:()=>console.log("PONG!"),description:"EVT is for Event publishing and emitting"},r={US:{locale:"en-US",currency:"USD"},CA:{locale:"en-CA",currency:"CAD"},FR:{locale:"fr-FR",currency:"EUR"},HT:{locale:"ht-HT",currency:"HTG"},GB:{locale:"en-GB",currency:"GBP"},AU:{locale:"en-AU",currency:"AUD"}},n=(e,{locale:t="en-US",currency:r="USD"}={})=>Intl.NumberFormat(t,{style:"currency",currency:r}).format(e);function s(e){return Array.isArray(e)?e.length:function(e){if("number"==typeof e)return Number.isFinite(e);if("string"!=typeof e)return!1;const t=e.trim();return!!t&&/^-?\d+(\.\d+)?$/.test(t)}(e)?Number(String(e).trim()):String(e??"").length}function o(e){const[t,r]=String(e??"").split(",").map(e=>e.trim()),n=Number(t),s=Number(r);return Number.isFinite(n)&&Number.isFinite(s)?{min:n,max:s}:null}const a=e=>new Promise(t=>setTimeout(t,e));function i(e,t){const r=String(e??"").trim();if(!r)return null;if("YYYY-MM-DD"===t){const e=r.match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!e)return null;const t=Number(e[1]),n=Number(e[2]),s=Number(e[3]);return!t||n<1||n>12||s<1||s>31?null:{year:t,month:n,day:s}}return null}function l(e,t,r="en-US"){const n=new Intl.DateTimeFormat(r,{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),s=Object.fromEntries(n.map(e=>[e.type,e.value]));return{year:Number(s.year),month:Number(s.month),day:Number(s.day),hour:Number(s.hour),minute:Number(s.minute),second:Number(s.second)}}function u({year:e,month:t,day:r},n){const s=new Date(Date.UTC(e,t-1,r));return s.setUTCDate(s.getUTCDate()+n),{year:s.getUTCFullYear(),month:s.getUTCMonth()+1,day:s.getUTCDate()}}function c(e,t,r){const{base:n,offsetDays:s}=function(e){const t=String(e).trim().match(/^(.+?)([+-]\d+)?$/);return t?{base:t[1].trim(),offsetDays:t[2]?Number(t[2]):0}:{base:String(e).trim(),offsetDays:0}}(e);let o=function(e,t){const r=new Date,{year:n,month:s,day:o}=l(r,t);return"today"===e?{year:n,month:s,day:o}:"tomorrow"===e?u({year:n,month:s,day:o},1):"yesterday"===e?u({year:n,month:s,day:o},-1):null}(n,r.timezone);if(!o){const e=t?.[n];o=d(e,r)}return o||(o=i(n,r.dateFormat)),o?(s&&(o=u(o,s)),o):null}function d(e,t){if(null==(r=e)||""===String(r??"").trim())return null;var r;const n=String(e).trim();let s=i(n,t.dateFormat);if(s)return s;if(!/^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2})?$/.test(n))return null;const o=new Date(n);if(isNaN(o.getTime()))return null;const a=l(o,t.timezone);return{year:a.year,month:a.month,day:a.day}}function m(e,t,r,n){let s=null;return s="value"===n?d(e,r):c(e,t,r),s?function({year:e,month:t,day:r},n){let s=Date.UTC(e,t-1,r,0,0,0);for(let o=0;o<2;o++){const o=l(new Date(s),n),a=Date.UTC(o.year,o.month-1,o.day,o.hour,o.minute,o.second)-Date.UTC(e,t-1,r,0,0,0);if(0===a)break;s-=a}return s}(s,r.timezone):null}function f(e,t){return{method:t=>(r,n,s)=>{const o=m(r,n,s,"value"),a=m(t,n,s,"target");return null!=o&&null!=a&&e(o,a)},message:t}}const h={required:{method:e=>""!==String(e??"").trim(),message:"This field is required"},requiredIf:{method:e=>(t,r)=>{const[n,s]=String(e).split("="),o=r?.[n];return!(null!=s?String(o??"")===s:""!==String(o??"").trim())||""!==String(t??"").trim()},message:e=>{const[t,r]=String(e).split("=");return null!=r?`This field is requied when ${t} is ${r}`:`This field is required when ${t} has a value`}},email:{method:e=>/\S+@\S+\.\S+/.test(e),message:"Email is invalid"},min:{method:e=>t=>String(t??"").length>=Number(e),message:e=>`Must be at least ${e} characters`},max:{method:e=>t=>String(t??"").length<=Number(e),message:e=>`Must be at most ${e} characters`},date:{method:e=>{if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;const[t,r,n]=e.split("-").map(Number),s=new Date(t,r-1,n);return s.getFullYear()===t&&s.getMonth()===r-1&&s.getDate()===n},message:"Date is invalid. Use the format YYYY-MM-DD."},currency:{method:e=>/^\$?\d{1,3}((,\d{3})*|\d*)(\.\d{2})?$/.test(e),message:"Currency is invalid. Use the format $123,456.78 or 123456.78."},same:{method:e=>(t,r)=>String(t??"")===String(r?.[e]??""),message:e=>`Must match ${e}`},in:{method:e=>t=>(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim()).filter(Boolean)).includes(String(t??"").trim()),message:e=>`Must be one of the following: ${(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim())).filter(Boolean).join(",")}`},before:f((e,t)=>e<t,e=>`Must be before ${e}`),beforeOrEqual:f((e,t)=>e<=t,e=>`Must be before or equal to ${e}`),after:f((e,t)=>e>t,e=>`Must be after ${e}`),afterOrEqual:f((e,t)=>e>=t,e=>`Must be after or equal to ${e}`),between:{method:e=>t=>{const r=o(e);if(!r)return!1;const n=s(t);return r.min<=n&&n<=r.max},message:e=>{const t=o(e);return t?`Must be between ${t.min} and ${t.max}`:"Between rule is invalid. Use between:min,max"}}};function y(e){const t=e.indexOf(":");return-1===t?{name:e,param:void 0}:{name:e.slice(0,t),param:e.slice(t+1)}}const p={run:function(e,t){let r=!0;const n={};for(const s in e){const o=e[s]||[];for(const e of o){const{name:o,param:a}=y(e),i=h[o];if(!i)continue;const l=t?.[s];if(!(void 0!==a?i.method(a)(l,t):i.method(l,t))){r=!1,n[s]||(n[s]=[]);const e="function"==typeof i.message?i.message(a):i.message;n[s].push(e)}}}return{isValid:r,errors:n}},ping:()=>console.log("PONG"),description:"V is for validating forms"},b=e=>({on:(t,r)=>e?.addEventListener(t,r),off:(t,r)=>e?.removeEventListener(t,r)}),g=(e,t)=>{if(!e)return;const r="innerText"in e?"innerText":"textContent";return null!=t&&(e[r]=t),e[r]},S=(e,t)=>{if(e)return null!=t&&(e.innerHTML=t),e.innerHTML},v=e=>document.createElement(e),w=e=>{let t="";const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n<e;n++)t+=r.charAt(Math.floor(62*Math.random()));return t},E=e=>{const t=document.implementation.createHTMLDocument("");return t.body.innerHTML=e,[...t.body.childNodes]},A=e=>{"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)},T=e=>{window.onload=e},$=e=>{const t="string"==typeof e?document.querySelector(e):e,r=e=>(...r)=>{if(t)return e(...r)},n={elt:t,value:t?.value,text:e=>null!=e?(g(t,e),n):g(t),html:e=>null!=e?(S(t,e),n):S(t),val:r(e=>{if(null!=e){if(t.opt&&t.multiple){const r=new Set(Array.isArray(e)?e:[e]);Array.from(t.options).forEach(e=>{e.selected=r.has(e.value)})}else t.value=e;return n.value=t.value,n}return t.options&&t.multiple?Array.from(t.options).filter(e=>e.selected).map(e=>e.value):t.value}),addClass:r(e=>(t.classList.add(e),n)),removeClass:r(e=>(t.classList.remove(e),n)),hasClass:r(e=>t.classList.contains(e)),hide:r(()=>(t.style.display="none",n)),show:r(()=>(t.style.display="",n)),prop:r(e=>t[e]),attr:r(e=>t.getAttribute(e)),removeAttr:e=>{t.removeAttribute(e)},toggle:r(()=>("none"==t.style.display?n.show():n.hide(),n)),css:r(e=>(Object.entries(e).forEach(([e,r])=>{t.style[e]=r}),n)),on:b(t).on,off:b(t).off};return n},C=e=>document.querySelectorAll(e),D={Q:$,$:$,all:C,$$:C,scan:(e,t={})=>{const r=t.refAttr||"v-ref",n="string"==typeof e?document.querySelector(e):e||document;if(!n)throw new Error(`Dom.scan: root "${e}" not found`);const s=Object.create(null);return n.querySelectorAll(`[${r}]`).forEach(e=>{const t=e.getAttribute(r);if(!t)return;const n=$(e);s[t]?Array.isArray(s[t])?s[t].push(n):s[t]=[s[t],n]:s[t]=n}),new Proxy({},{get(e,t){if("_"===t)return s;if("get"===t)return e=>s[e];if("all"===t)return e=>s[e]?Array.isArray(s[e])?s[e]:[s[e]]:[];if("on"===t)return(e,t,r)=>{const n=s[e];(Array.isArray(n)?n:[n]).forEach(e=>e?.on(t,r))};if("string"!=typeof t)return;const r=s[t];return r||(console.warn(`DOM.scan: ref "${t}" not found`),$(null))}})},make:v,makeId:w,parseHtml:E,onPageLoad:A,onWindowLoad:T,ping:()=>console.log("PONG!"),description:"DOM is for dom manipulation"};let I="",N=8e3,q=null,R=null,x=null;const M=new Map,L=new Map,O=()=>Date.now();function U(e){const t="undefined"!=typeof window?window[e]:null;return t?{get(e){const r=t.getItem(e);if(!r)return null;try{const n=JSON.parse(r);return n.exp&&n.exp<O()?(t.removeItem(e),null):n.val}catch{return null}},set(e,r,n){const s=n?O()+n:null;t.setItem(e,JSON.stringify({val:r,exp:s}))},del(e){t&&t.removeItem(e)},clear(){t&&t.clear()}}:null}const H={memory:{get(e){const t=L.get(e);return t?t.exp&&t.exp<O()?(L.delete(e),null):t.val:null},set(e,t,r){const n=r?O()+r:null;L.set(e,{val:t,exp:n})},del(e){L.delete(e)},clear(){L.clear()}},local:U("localStorage"),session:U("sessionStorage")};function k(e){return null===e||"object"!=typeof e?String(e):Array.isArray(e)?`[${e.map(k).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${k(e[t])}`).join(",")}}`}const F=(e,t)=>setTimeout(()=>t.abort(),e);async function j(e,t,r={}){const{params:n,body:s,headers:o={},cache:a}=r;let i=I+t;if(n){const e=new URLSearchParams(n).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c=!!a,d=a?.strategy,m=a?.ttl??0,f=function(e="memory"){return H[e]||H.memory}(a?.storage),h=a?.key||function(e,t,r,n){return`H|${e}|${t}${r?`?${new URLSearchParams(r).toString()}`:""}${n&&"GET"!==e?`#${k(n)}`:""}`}(e,i,n,s);if(c&&!a?.forceRefresh&&"cache-first"===d){const e=f.get(h);if(null!==e)return e}let y={method:e,headers:o,signal:l.signal};if(x){const{token:e,headerName:t}=x,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";y.headers[t]=`${e}${r}`}}void 0!==s&&(s instanceof FormData?y.body=s:(y.headers["Content-Type"]="application/json",y.body=JSON.stringify(s))),q&&(y=q(y)||y);try{let t,r=await fetch(i,y);M.has(r.status)&&M.get(r.status)(r,{method:e,url:i}),clearTimeout(u),R&&(r=R(r)||r);try{t=await r.json()}catch{t=await r.text()}if(!r.ok){const n={status:r.status,data:t,url:i,method:e};if(c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw n}return c&&f.set(h,t,m),t}catch(e){if(clearTimeout(u),c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw e}}async function P(e,{filename:t,params:r,headers:n={},method:s="GET",body:o,onProgress:a}={}){let i=I+e;if(r){const e=new URLSearchParams(r).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(N,l),c={method:s,headers:{...n},signal:l.signal};void 0!==o&&(o instanceof FormData?c.body=o:(c.headers["Content-Type"]=c.headers["Content-Type"]||"application/json",c.body="string"==typeof o?o:JSON.stringify(o)));const d=await fetch(i,c);if(clearTimeout(u),!d.ok){let e="";try{e=await d.text()}catch{}throw new Error(`Download failed ${d.status}: ${e||d.statusText}`)}if(!t){const e=d.headers.get("Content-Disposition")||"",r=/filename\*=UTF-8''([^;]+)|filename="?([^"]+)"?/i.exec(e);t=decodeURIComponent(r?.[1]||r?.[2]||"download")}let m;if(d.body&&"getReader"in d.body){const e=d.body.getReader(),t=Number(d.headers.get("Content-Length"))||null,r=[];let n=0;for(;;){const{done:s,value:o}=await e.read();if(s)break;if(r.push(o),n+=o.length,"function"==typeof a){a(n,t,t?Math.round(n/t*100):null)}}m=new Blob(r)}else m=await d.blob(),"function"==typeof a&&a(1,1,100);const f=URL.createObjectURL(m),h=document.createElement("a");return h.href=f,h.download=t,h.style.display="none",document.body.appendChild(h),h.click(),document.body.removeChild(h),URL.revokeObjectURL(f),{filename:t,size:m.size,type:m.type}}function _(e,{files:t,fieldName:r="file",fields:n={},headers:s={},method:o="POST",onProgress:a,signal:i}={}){return new Promise((l,u)=>{const c=function({files:e,fieldName:t="file",fields:r={}}){const n=new FormData,s=Array.isArray(e)?e:[e];return s.forEach((e,r)=>{const o=s.length>1?`${t}[${r}]`:t;n.append(o,e)}),Object.entries(r).forEach(([e,t])=>{n.append(e,t instanceof Blob||t instanceof File?t:"object"==typeof t?JSON.stringify(t):String(t))}),n}({files:t,fieldName:r,fields:n}),d=`${I}${e}`,m=new XMLHttpRequest;m.open(o,d,!0);let f={method:o,headers:{...s}};if(x){const{token:e,headerName:t}=x,r="function"==typeof e?e():e;if(r){const e="Authorization"===t?"Bearer ":"";f.headers[t]=`${e}${r}`}}if(q&&(f=q(f)||f),Object.entries(f.headers).forEach(([e,t])=>m.setRequestHeader(e,t)),m.timeout=N,i){const e=()=>{try{m.abort()}catch{}};i.aborted&&e(),i.addEventListener("abort",e,{once:!0})}m.upload&&"function"==typeof a&&(m.upload.onprogress=e=>{if(!e.lengthComputable)return void a(e.loaded,null,null);const t=Math.round(e.loaded/e.total*100);a(e.loaded,e.total,t)}),m.onreadystatechange=async()=>{if(4!==m.readyState)return;if(R){const e={status:m.status,ok:m.status>=200&&m.status<300,headers:new Headers,text:async()=>m.responseText,json:async()=>JSON.parse(m.responseText||"null")};R(e)}const e=(m.getResponseHeader("Content-Type")||"").includes("application/json")?function(e){try{return JSON.parse(e||"null")}catch{return e}}(m.responseText):m.responseText;m.status>=200&&m.status<300?l(e):u({status:m.status,data:e,url:d,method:o})},m.onerror=()=>u({status:0,data:"Network error",url:`${I}${e}`,method:o}),m.ontimeout=()=>u({status:0,data:"Timeout",url:`${I}${e}`,method:o}),m.send(c)})}const B=(e,t)=>j("GET",e,t),V=(e,t,r={})=>j("POST",e,{...r,body:t}),G=(e,t,r={})=>j("PUT",e,{...r,body:t}),z=(e,t={})=>j("DELETE",e,t),J=(e,t)=>fetch(I+e,t),Y={base:e=>(I=e,Y),timeout:e=>(N=e,Y),bearer:(e,t="Authorization")=>(x={token:e,headerName:t},Y),onStatus:(e,t)=>(M.set(e,t),Y),onUnauthorized:e=>Y.onStatus(401,e),onForbidden:e=>Y.onStatus(403,e),onInternalServerError:e=>Y.onStatus(500,e),interceptRequest:e=>(q=e,Y),interceptResponse:e=>(R=e,Y),get:B,post:V,put:G,delete:z,raw:J,download:P,upload:_,ping:()=>console.log("PONG"),description:"H is for Http"};let Q=null,W=new Set;function K(e){let t=e;const r=new Set;return{get val(){return Q&&r.add(Q),t},set val(e){if(e!==t){t=e;for(const e of r)e()}},peek:()=>t,subscribe:e=>(r.add(e),()=>r.delete(e)),toString:()=>String(t),valueOf:()=>t}}function Z(e){const t=()=>{const r=Q;Q=t;try{e()}finally{Q=r}};return t(),t}function X(e){return"string"==typeof e?$(e):e}const ee={STATE_CHANGE:"form:state:change",ERRORS_CHANGE:"form:errors:change",SUBMIT_SUCCESS:"form:submit:success",SUBMIT_ERROR:"form:submit:error",RESET:"form:reset",VALIDATED:"form:validated"};class te{constructor(e,t,r,n={}){this.formId=e,this.schema=t,this.onSubmit=r,this.preSubmit=n.preSubmit||null,this.form=null,this.formState={},this.errors={},this.initialValues={},this._boundHandleSubmit=this.#e.bind(this),this._boundHandleInput=this.#t.bind(this),this.#r()}#r(){this.form=document.getElementById(this.formId),this.form?(this.#n(),this.form.addEventListener("submit",this._boundHandleSubmit),this.form.addEventListener("input",this._boundHandleInput),this.#s()):console.error(`Form with id ${this.formId} not found`)}#n(){const e=this.form.elements;for(const t of Array.from(e))t.name&&(this.initialValues[t.name]=t.value,this.formState[t.name]=t.value)}#t(e){const{name:t,value:r}=e.target;t&&(this.formState[t]=r,this.#s(),this.errors[t]&&(delete this.errors[t],this.#o()))}async#e(e){e.preventDefault();const r=new FormData(this.form);let n={};r.forEach((e,t)=>{n[t]=e}),this.formState=n,this.#s();const{isValid:s,errors:o}=p.run(this.schema,n);if(t.pub(ee.VALIDATED,{formId:this.formId,isValid:s,errors:o,data:n}),!s)return this.errors=o,this.#o(),void t.pub(ee.SUBMIT_ERROR,{formId:this.formId,errors:o});if(this.errors={},this.#o(),this.preSubmit)try{n=await this.preSubmit(n)}catch(e){return void t.pub(ee.SUBMIT_ERROR,{formId:this.formId,errors:{_preSubmit:[e.message]}})}t.pub(ee.SUBMIT_SUCCESS,{formId:this.formId,data:n}),this.onSubmit(n)}#s(){t.pub(ee.STATE_CHANGE,{formId:this.formId,state:{...this.formState}})}#o(){t.pub(ee.ERRORS_CHANGE,{formId:this.formId,errors:{...this.errors}})}getFormState(){return{...this.formState}}getErrors(){return{...this.errors}}reset(){this.formState={...this.initialValues},this.errors={},this.form&&this.form.reset(),this.#s(),this.#o(),t.pub(ee.RESET,{formId:this.formId})}validateNow(){const e=new FormData(this.form),r={};e.forEach((e,t)=>{r[t]=e});const n=p.run(this.schema,r);return this.errors=n.errors,this.#o(),t.pub(ee.VALIDATED,{formId:this.formId,isValid:n.isValid,errors:n.errors,data:r}),n}destroy(){this.form&&(this.form.removeEventListener("submit",this._boundHandleSubmit),this.form.removeEventListener("input",this._boundHandleInput))}}class re{constructor(e,r={}){this.formId=e,this.options={containerClass:"form-error-container",errorClass:"text-danger",insertAfterField:!0,...r},this.customContainers={},this._boundHandleErrors=this.#a.bind(this),t.sub(ee.ERRORS_CHANGE,this._boundHandleErrors)}#a({formId:e,errors:t}){e===this.formId&&(this.clearAll(),this.renderAll(t))}setContainer(e,t){this.customContainers[e]="string"==typeof t?document.querySelector(t):t}renderAll(e){for(const t in e)this.render(t,e[t])}render(e,t){if(!t||0===t.length)return null;const r=document.createElement("span");r.className=`${this.options.containerClass} ${this.options.errorClass}`,r.dataset.field=e;const n=document.createElement("ul");t.forEach(e=>{const t=document.createElement("li"),r=document.createElement("i");r.textContent=e,t.appendChild(r),n.appendChild(t)}),r.appendChild(n);const s=this.customContainers[e];if(s)s.innerHTML="",s.appendChild(r);else if(this.options.insertAfterField){const t=document.getElementById(this.formId),n=t?.querySelector(`[name="${e}"]`);n&&n.insertAdjacentElement("afterend",r)}return r}clearAll(){const e=document.getElementById(this.formId);if(!e)return;e.querySelectorAll(`.${this.options.containerClass}`).forEach(e=>e.remove());for(const e in this.customContainers)this.customContainers[e]&&(this.customContainers[e].innerHTML="")}destroy(){t.unsub(ee.ERRORS_CHANGE,this._boundHandleErrors),this.clearAll()}}const ne=(e={})=>{const{persistKey:r="query-cache",persistedKeys:n=null,defaultTtl:s=6e4,defaultStaleTime:o=5e3,defaultRetries:i=3,defaultRetryDelay:l=1e3}=e,u=new Map,c=new Map,d=(e,r,n)=>{t.pub(`query:${e}`,{key:r,...n}),t.pub(`query:${r}:${e}`,n)},m=()=>{try{const e=localStorage.getItem(r);if(!e)return;const n=JSON.parse(e),s=Date.now();for(const[e,t]of Object.entries(n))s<t.expiry&&u.set(e,{...t,promise:null});t.pub("query:hydrated",{keys:[...u.keys()]})}catch(e){console.warn("Failed to load query cache: ",e)}},f=()=>{try{const e={};for(const[t,r]of u.entries())void 0!==r.data&&(n&&!n.some(e=>t.startsWith(e))||(e[t]={data:r.data,staleAt:r.staleAt,expiry:r.expiry}));localStorage.setItem(r,JSON.stringify(e))}catch(e){console.warn("Failed to persist query cache: ",e)}};let h=null;const y=()=>{h&&clearTimeout(h),h=setTimeout(f,1e3)},p=e=>u.get(e)??null,b=async(e,t,r={})=>{const{ttl:n=s,staleTime:c=o,retries:m=i,retryDelay:f=l}=r,h=Date.now(),b=p(e);if(b&&h<b.staleAt)return d("hit",e,{data:b.data}),b.data;if(b?.promise)return b.promise;const g=b&&h<b.expiry;d("fetch",e,{isStale:g,hasCache:!!b});const S=(async(e,t,r,n)=>{let s;for(let o=0;o<=r;o++)try{return await t()}catch(t){if(s=t,o<r){const s=n*Math.pow(2,o);d("retry",e,{attempt:o+1,maxRetries:r,delay:s,error:t}),await a(s)}}throw s})(e,t,m,f).then(t=>(u.set(e,{data:t,staleAt:Date.now()+c,expiry:Date.now()+n,promise:null,error:null}),d("success",e,{data:t}),y(),t)).catch(t=>{throw u.set(e,{data:b?.data??null,staleAt:b?.staleAt??0,expiry:b?.expiry??0,promise:null,error:t}),d("error",e,{error:t,staleData:b?.data??null}),t});return u.set(e,{...b,promise:S}),g?b.data:S},g=(e,t)=>{const r=p(e);if(!r)return null;const n=r.data,s="function"==typeof t?t(n):t;return u.set(e,{...r,data:s}),d("mutate",e,{data:s,previous:n}),y(),n},S=(e,t={})=>{const{refetch:r,fetcher:n}=t;if(u.delete(e),d("invalidate",e,{}),y(),r&&n)return b(e,n)},v=e=>{const t=c.get(e);t&&(clearInterval(t),c.delete(e),d("polling:stop",e,{}))},w=()=>{for(const e of c.keys())v(e)},E=(e,t,r,n={})=>{v(e),b(e,t,n).catch(()=>{});const s=setInterval(()=>{const r=p(e);r&&u.set(e,{...r,staleAt:0}),b(e,t,n).catch(()=>{})},r);return c.set(e,s),d("polling:start",e,{interval:r}),()=>v(e)},A=()=>{const e=Date.now(),r=[];for(const[n,s]of u.entries())e>s.expiry&&!t.has(`query:${n}:success`)&&(u.delete(n),r.push(n));r.length&&(y(),t.pub("query:gc",{collected:r}))},T=(e,r)=>{const n=t=>r({...p(e),...t});t.sub(`query:${e}:success`,n),t.sub(`query:${e}:error`,n),t.sub(`query:${e}:mutate`,n),t.sub(`query:${e}:set`,n),t.sub(`query:${e}:invalidate`,()=>r(null));const s=p(e);return s&&r(s),()=>{t.unsub(`query:${e}:success`,n),t.unsub(`query:${e}:error`,n),t.unsub(`query:${e}:mutate`,n),t.unsub(`query:${e}:set`,n),t.unsub(`query:${e}:invalidate`,n)}};m(),setInterval(A,6e4),window.addEventListener("storage",e=>{if(e.key===r){m();for(const e of u.keys())d("sync",e,{data:u.get(e)?.data})}}),window.addEventListener("beforeunload",()=>{w(),f()});const $=(e,t,r={})=>{const n=K(r.inital??null),s=K(!1),o=K(null),a=T(e,e=>{e?.data&&(n.val=e.data),e?.error&&(o.val=e.error),s.val=!!e?.promise&&!e?.data}),i=()=>(s.val=!0,b(e,t,r));return!1!==r.enabled&&i().catch(()=>{}),{data:n,loading:s,error:o,fetch:i,refetch:()=>(S(e),i()),unsubscribe:a,mutate:t=>{const r=g(e,t);return n.val=p(e)?.data,r}}};return{query:b,mutate:g,setQueryData:(e,t,r={})=>{const{ttl:n=s,staleTime:a=o}=r,i=Date.now();u.set(e,{data:t,staleAt:i+a,expiry:i+n,promise:null,error:null}),d("set",e,{data:t}),y()},invalidate:S,invalidateMatching:e=>{const t=[];for(const r of u.keys())e(r)&&(u.delete(r),t.push(r),d("invalidate",r,{}));return y(),t},subscribe:T,prefetch:(e,t,r)=>{const n=p(e);n&&Date.now()<n.staleAt||b(e,t,r).catch(()=>{})},startPolling:E,stopPolling:v,stopAllPolling:w,getEntry:p,gc:A,querySignal:$,pollingSignal:(e,t,r,n={})=>({...$(e,t,{...n,enabled:!1}),stop:E(e,t,r,n)}),bindQuery:(e,r,n={})=>{const{target:s,render:o,onLoading:a,onError:i,poll:l=null,...u}=n,c="string"==typeof s?document.querySelector(s):s,d=e=>{const t=o(e);"string"==typeof t&&(c.innerHTML=t)};if(t.sub(`query:${e}:success`,({data:e})=>d(e)),t.sub(`query:${e}:set`,({data:e})=>d(e)),t.sub(`query:${e}:mutate`,({data:e})=>d(e)),i&&t.sub(`query:${e}:error`,({error:e,staleData:t})=>i(e,t,c)),a&&t.sub(`query:${e}:fetch`,({hasCache:e})=>{e||a(c)}),b(e,r,u).catch(()=>{}),l)return E(e,r,l,u)},clear:()=>{u.clear(),localStorage.removeItem(r),t.pub("query:cleared",{})}}},se=ne();e.DOM=D,e.EVT=t,e.FormErrorRenderer=re,e.FormEvents=ee,e.FormHandler=te,e.HTTP=Y,e.Q=$,e.V=p,e.all=C,e.batch=function(e){e(),W.forEach(e=>e()),W.clear()},e.bind=function(e,t,r){const n=X(e);return Z(()=>{const e=r.val;switch(t){case"text":n.text(e);break;case"html":n.html(e);break;case"value":n.val(e);break;case"show":e?n.show():n.hide();break;case"hide":e?n.hide():n.show();break;case"disabled":n.elt.disabled=!!e;break;default:n.elt[t]=e}})},e.bindAttr=function(e,t,r){const n=X(e);return Z(()=>{n.elt.setAttribute(t,r.val)})},e.bindClass=function(e,t,r){const n=X(e);return Z(()=>{r.val?n.addClass(t):n.removeClass(t)})},e.bindHtml=function(e,t){const r=X(e);return Z(()=>{const e=t.val;r.html(e)})},e.bindList=function(e,t,r,n=""){const s=X(e);return Z(()=>{const e=t.val;s.html(e?.length?e.map(r).join(""):n)})},e.bindOptions=function(e,t,r={}){const{value:n="id",label:s="name",placeholder:o="Select ..."}=r,a=X(e);return Z(()=>{const e=t.val||[];a.html(`<option value="">${o}</option>`+e.map(e=>`<option value="${e[n]}">${e[s]}</option>`).join(""))})},e.bindText=function(e,t){const r=X(e);return Z(()=>{const e=t.val;r.text(e)})},e.bindValue=function(e,t){const r=X(e);return Z(()=>{const e=t.val;r.val(e)})},e.cache=function(e){if(null==e)return{cache:{strategy:"cache-first",storage:"local",ttl:6e4}};if("object"==typeof e)return{cache:e};const t=e.toLowerCase(),r={cfl:{strategy:"cache-first",storage:"local"},cfs:{strategy:"cache-first",storage:"session"},cfm:{strategy:"cache-first",storage:"memory"},nfl:{strategy:"network-first",storage:"local"},nfs:{strategy:"network-first",storage:"session"},nfm:{strategy:"network-first",storage:"memory"}},n=t.match(/cfl|cfs|cfm|nfl|nfs|nfm/),s=n?r[n[0]]:r.cfl,o=t.match(/(\d+)\s*(s|sec|secs|second|seconds|min|m|mins|minute|minutes|h|hr|hours)?/),a=o?function(e){const t=e.replace(/[0-9]/g,"").trim().toLowerCase(),r=parseInt(e,10),n={s:1e3,sec:1e3,secs:1e3,second:1e3,seconds:1e3,m:6e4,min:6e4,mins:6e4,minute:6e4,minutes:6e4,h:36e5,hr:36e5,hrs:36e5,hours:36e5};return r*(n[t]||1)}(o[0]):6e4;return{cache:{strategy:s.strategy,storage:s.storage,ttl:a}}},e.computed=function(e){const t=K(void 0);return Z(()=>{t.val=e()}),t},e.createQuery=ne,e.del=z,e.download=P,e.effect=Z,e.formatByCountry=(e,t)=>n(e,r[t]??r.US),e.get=B,e.isArray=e=>Array.isArray(e),e.isArrayEmpty=e=>!(Array.isArray(e)&&e.length>0),e.isFocus=e=>e==document.activeElement,e.isValidRoutingNumber=e=>{if(!/^\d{9}$/.test(e))return!1;const t=e.split("").map(Number);return(7*(t[0]+t[3]+t[6])+3*(t[1]+t[4]+t[7])+1*(t[2]+t[5]+t[8]))%10==0},e.make=v,e.makeId=w,e.onPageLoad=A,e.onWindowLoad=T,e.parseHtml=E,e.post=V,e.put=G,e.queryClient=se,e.raw=J,e.redirect=e=>window.location.href=e,e.request=j,e.signal=K,e.toCurrency=n,e.upload=_,e.useFormHandler=function(e,t,r,n){const s=new te(e,t,r,n),o=new re(e,n);return{reset:()=>s.reset(),validate:()=>s.validateNow(),destroy:()=>{o.destroy(),s.destroy()},setContainer:(e,t)=>o.setContainer(e,t)}},e.when=function(e,t){return Z(()=>{e.val&&t(e.val)})},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaniy",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "A lightweight, modular JavaScript utility library for common web development tasks.",
5
5
  "type": "module",
6
6
  "sideEffects": false,