vaniy 0.1.8 → 0.1.10
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 +331 -0
- package/dist/vaniy.es.js +266 -53
- package/dist/vaniy.iife.min.js +1 -1
- package/dist/vaniy.min.js +1 -1
- package/package.json +1 -1
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,334 @@ 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, 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
|
+
**`bindList(target, signal, template, empty?)`**
|
|
410
|
+
|
|
411
|
+
Renders an array signal as a list. Re-renders the entire list on every change.
|
|
412
|
+
|
|
413
|
+
```javascript
|
|
414
|
+
const users = signal([]);
|
|
415
|
+
|
|
416
|
+
const stop = bindList(
|
|
417
|
+
"#user-list",
|
|
418
|
+
users,
|
|
419
|
+
(user) => `<li>${user.name}</li>`,
|
|
420
|
+
"<li>No users found.</li>", // optional fallback for empty/null
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
users.val = [{ name: "Alice" }, { name: "Bob" }];
|
|
424
|
+
// → #user-list innerHTML: <li>Alice</li><li>Bob</li>
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**`bindOptions(target, signal, opts?)`**
|
|
428
|
+
|
|
429
|
+
Populates a `<select>` element from an array signal.
|
|
430
|
+
|
|
431
|
+
```javascript
|
|
432
|
+
const roles = signal([]);
|
|
433
|
+
|
|
434
|
+
bindOptions("#role-select", roles, {
|
|
435
|
+
value: "id", // item property used as <option value> (default: "id")
|
|
436
|
+
label: "name", // item property used as <option> text (default: "name")
|
|
437
|
+
placeholder: "Pick a role", // first empty option text (default: "Select ...")
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
roles.val = [
|
|
441
|
+
{ id: 1, name: "Admin" },
|
|
442
|
+
{ id: 2, name: "Editor" },
|
|
443
|
+
];
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**`bindClass(target, className, signal)`**
|
|
447
|
+
|
|
448
|
+
Adds a class when the signal is truthy, removes it when falsy.
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
const isActive = signal(false);
|
|
452
|
+
|
|
453
|
+
bindClass("#card", "active", isActive);
|
|
454
|
+
|
|
455
|
+
isActive.val = true; // → adds class "active"
|
|
456
|
+
isActive.val = false; // → removes class "active"
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**`bindAttr(target, attr, signal)`**
|
|
460
|
+
|
|
461
|
+
Sets an HTML attribute to the signal's value on every change.
|
|
462
|
+
|
|
463
|
+
```javascript
|
|
464
|
+
const progress = signal(0);
|
|
465
|
+
|
|
466
|
+
bindAttr("#bar", "aria-valuenow", progress);
|
|
467
|
+
|
|
468
|
+
progress.val = 75; // → <div id="bar" aria-valuenow="75">
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Query Cache
|
|
472
|
+
|
|
473
|
+
Async data cache with deduplication, stale-while-revalidate, persistence, and reactive signals.
|
|
474
|
+
|
|
475
|
+
Use `createQuery` to create a fully configured client. `queryClient` is a zero-config default export for quick use.
|
|
476
|
+
|
|
477
|
+
```javascript
|
|
478
|
+
import { createQuery, queryClient } from "vaniy";
|
|
479
|
+
|
|
480
|
+
// Create your own configured client
|
|
481
|
+
const client = createQuery({
|
|
482
|
+
persistKey: "my-app-cache", // localStorage key (default: "query-cache")
|
|
483
|
+
persistedKeys: ["user", "settings"], // cache key prefixes to persist (default: null = none)
|
|
484
|
+
defaultTtl: 60000, // entry lifetime in ms (default: 60000)
|
|
485
|
+
defaultStaleTime: 5000, // freshness window in ms (default: 5000)
|
|
486
|
+
defaultRetries: 3, // retry attempts on failure (default: 3)
|
|
487
|
+
defaultRetryDelay: 1000, // base retry delay in ms, doubles each attempt (default: 1000)
|
|
488
|
+
});
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**Core cache methods:**
|
|
492
|
+
|
|
493
|
+
```javascript
|
|
494
|
+
// Fetch and cache data
|
|
495
|
+
const data = await client.query("users", () => fetch("/api/users").then(r => r.json()));
|
|
496
|
+
|
|
497
|
+
// Per-query overrides
|
|
498
|
+
const data = await client.query("users", fetcher, { ttl: 30000, staleTime: 0 });
|
|
499
|
+
|
|
500
|
+
// Set data manually (e.g. after a mutation)
|
|
501
|
+
client.setQueryData("users", updatedList);
|
|
502
|
+
|
|
503
|
+
// Optimistic update — returns previous value
|
|
504
|
+
const previous = client.mutate("users", (prev) => [...prev, newUser]);
|
|
505
|
+
|
|
506
|
+
// Invalidate (remove from cache)
|
|
507
|
+
client.invalidate("users");
|
|
508
|
+
|
|
509
|
+
// Invalidate and immediately refetch
|
|
510
|
+
client.invalidate("users", { refetch: true, fetcher });
|
|
511
|
+
|
|
512
|
+
// Invalidate all keys matching a pattern
|
|
513
|
+
client.invalidateMatching((key) => key.startsWith("users"));
|
|
514
|
+
|
|
515
|
+
// Prefetch into cache without blocking
|
|
516
|
+
client.prefetch("users", fetcher);
|
|
517
|
+
|
|
518
|
+
// Read cache entry directly
|
|
519
|
+
const entry = client.getEntry("users"); // { data, staleAt, expiry, error, promise }
|
|
520
|
+
|
|
521
|
+
// Subscribe to cache updates for a key
|
|
522
|
+
const unsub = client.subscribe("users", (entry) => console.log(entry?.data));
|
|
523
|
+
|
|
524
|
+
// Clear all cache and storage
|
|
525
|
+
client.clear();
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
**Polling:**
|
|
529
|
+
|
|
530
|
+
```javascript
|
|
531
|
+
// Start polling every 5 seconds — returns a stop function
|
|
532
|
+
const stop = client.startPolling("price", fetcher, 5000);
|
|
533
|
+
|
|
534
|
+
// Stop a specific poll
|
|
535
|
+
client.stopPolling("price");
|
|
536
|
+
|
|
537
|
+
// Stop all active polls
|
|
538
|
+
client.stopAllPolling();
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Reactive signals (`querySignal`):**
|
|
542
|
+
|
|
543
|
+
Wraps a query in reactive signals — ideal for use with Vaniy's reactive system.
|
|
544
|
+
|
|
545
|
+
```javascript
|
|
546
|
+
const { data, loading, error, fetch, refetch, mutate, unsubscribe } =
|
|
547
|
+
client.querySignal("users", () => fetch("/api/users").then(r => r.json()));
|
|
548
|
+
|
|
549
|
+
// data.val, loading.val, error.val update automatically
|
|
550
|
+
console.log(data.val); // fetched array or null
|
|
551
|
+
console.log(loading.val); // true while fetching
|
|
552
|
+
console.log(error.val); // Error instance or null
|
|
553
|
+
|
|
554
|
+
// Skip auto-fetch, call manually
|
|
555
|
+
const qs = client.querySignal("users", fetcher, { enabled: false });
|
|
556
|
+
await qs.fetch();
|
|
557
|
+
|
|
558
|
+
// Refetch (invalidates then fetches)
|
|
559
|
+
await qs.refetch();
|
|
560
|
+
|
|
561
|
+
// Optimistic update
|
|
562
|
+
qs.mutate((prev) => [...prev, newUser]);
|
|
563
|
+
|
|
564
|
+
// Stop listening
|
|
565
|
+
qs.unsubscribe();
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
**Polling signals (`pollingSignal`):**
|
|
569
|
+
|
|
570
|
+
```javascript
|
|
571
|
+
const { data, loading, error, stop } =
|
|
572
|
+
client.pollingSignal("price", fetcher, 5000);
|
|
573
|
+
|
|
574
|
+
// stop polling
|
|
575
|
+
stop();
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**DOM binding (`bindQuery`):**
|
|
579
|
+
|
|
580
|
+
Automatically renders data into a DOM element when the cache updates.
|
|
581
|
+
|
|
582
|
+
```javascript
|
|
583
|
+
client.bindQuery("users", fetcher, {
|
|
584
|
+
target: "#user-list", // CSS selector or element reference
|
|
585
|
+
render: (data) => data.map(u => `<li>${u.name}</li>`).join(""),
|
|
586
|
+
onLoading: (el) => el.innerHTML = "Loading...",
|
|
587
|
+
onError: (err, staleData, el) => el.innerHTML = "Failed to load",
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
// With polling — returns a stop function
|
|
591
|
+
const stop = client.bindQuery("users", fetcher, {
|
|
592
|
+
target: "#user-list",
|
|
593
|
+
render: (data) => data.map(u => `<li>${u.name}</li>`).join(""),
|
|
594
|
+
poll: 10000,
|
|
595
|
+
});
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Query events (via `EVT`):**
|
|
599
|
+
|
|
600
|
+
| Event | Description |
|
|
601
|
+
| ----- | ----------- |
|
|
602
|
+
| `query:fetch` | Fetch started |
|
|
603
|
+
| `query:success` | Fetch succeeded |
|
|
604
|
+
| `query:error` | Fetch failed |
|
|
605
|
+
| `query:retry` | Fetch retrying |
|
|
606
|
+
| `query:mutate` | Cache mutated |
|
|
607
|
+
| `query:set` | Cache set manually |
|
|
608
|
+
| `query:invalidate` | Entry invalidated |
|
|
609
|
+
| `query:hydrated` | Cache loaded from storage |
|
|
610
|
+
| `query:gc` | Expired entries collected |
|
|
611
|
+
| `query:cleared` | All cache cleared |
|
|
612
|
+
|
|
613
|
+
Each event also fires as `query:<key>:<event>` for key-specific subscriptions.
|
|
614
|
+
|
|
284
615
|
### Utilities
|
|
285
616
|
|
|
286
617
|
Additional helper functions.
|
package/dist/vaniy.es.js
CHANGED
|
@@ -75,7 +75,7 @@ const isValidRoutingNumber = (routingNumber) => {
|
|
|
75
75
|
function isNumericLike(value) {
|
|
76
76
|
if (typeof value === "number") return Number.isFinite(value);
|
|
77
77
|
if (typeof value !== "string") return false;
|
|
78
|
-
const s =
|
|
78
|
+
const s = value.trim();
|
|
79
79
|
if (!s) return false;
|
|
80
80
|
return /^-?\d+(\.\d+)?$/.test(s);
|
|
81
81
|
}
|
|
@@ -91,15 +91,15 @@ function parseMinMax(param) {
|
|
|
91
91
|
if (!Number.isFinite(min) || !Number.isFinite(max)) return null;
|
|
92
92
|
return { min, max };
|
|
93
93
|
}
|
|
94
|
-
function isBlank(
|
|
95
|
-
return
|
|
94
|
+
function isBlank(v) {
|
|
95
|
+
return v == null || String(v ?? "").trim() === "";
|
|
96
96
|
}
|
|
97
97
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
98
98
|
function parseByFormat(value, fmt) {
|
|
99
|
-
const
|
|
100
|
-
if (!
|
|
99
|
+
const v = String(value ?? "").trim();
|
|
100
|
+
if (!v) return null;
|
|
101
101
|
if (fmt === "YYYY-MM-DD") {
|
|
102
|
-
const m =
|
|
102
|
+
const m = v.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
103
103
|
if (!m) return null;
|
|
104
104
|
const year = Number(m[1]);
|
|
105
105
|
const month = Number(m[2]);
|
|
@@ -494,6 +494,14 @@ const scan = (rootSelector, options = {}) => {
|
|
|
494
494
|
if (prop === "get") return (k) => cache2[k];
|
|
495
495
|
if (prop === "all")
|
|
496
496
|
return (k) => cache2[k] ? Array.isArray(cache2[k]) ? cache2[k] : [cache2[k]] : [];
|
|
497
|
+
if (prop === "on") {
|
|
498
|
+
return (refName, event, handler) => {
|
|
499
|
+
const els = cache2[refName];
|
|
500
|
+
(Array.isArray(els) ? els : [els]).forEach(
|
|
501
|
+
(el) => el?.on(event, handler)
|
|
502
|
+
);
|
|
503
|
+
};
|
|
504
|
+
}
|
|
497
505
|
if (typeof prop !== "string") return void 0;
|
|
498
506
|
const val = cache2[prop];
|
|
499
507
|
if (!val) {
|
|
@@ -523,6 +531,8 @@ let _base = "";
|
|
|
523
531
|
let _timeout = 8e3;
|
|
524
532
|
let _requestInterceptor = null;
|
|
525
533
|
let _responseInterceptor = null;
|
|
534
|
+
let _bearerTokenFn = null;
|
|
535
|
+
const _statusHandlers = /* @__PURE__ */ new Map();
|
|
526
536
|
const memoryStore = /* @__PURE__ */ new Map();
|
|
527
537
|
const now = () => Date.now();
|
|
528
538
|
function makeStorageAdapter(kind) {
|
|
@@ -600,10 +610,10 @@ function buildFormData({ files, fieldName = "file", fields = {} }) {
|
|
|
600
610
|
const name = list.length > 1 ? `${fieldName}[${i}]` : fieldName;
|
|
601
611
|
fd.append(name, f);
|
|
602
612
|
});
|
|
603
|
-
Object.entries(fields).forEach(([k,
|
|
613
|
+
Object.entries(fields).forEach(([k, v]) => {
|
|
604
614
|
fd.append(
|
|
605
615
|
k,
|
|
606
|
-
|
|
616
|
+
v instanceof Blob || v instanceof File ? v : typeof v === "object" ? JSON.stringify(v) : String(v)
|
|
607
617
|
);
|
|
608
618
|
});
|
|
609
619
|
return fd;
|
|
@@ -632,6 +642,14 @@ async function request(method, url, opts = {}) {
|
|
|
632
642
|
headers,
|
|
633
643
|
signal: controller.signal
|
|
634
644
|
};
|
|
645
|
+
if (_bearerTokenFn) {
|
|
646
|
+
const { token, headerName } = _bearerTokenFn;
|
|
647
|
+
const tokenValue = typeof token === "function" ? token() : token;
|
|
648
|
+
if (tokenValue) {
|
|
649
|
+
const prefix = headerName === "Authorization" ? "Bearer " : "";
|
|
650
|
+
config.headers[headerName] = `${prefix}${tokenValue}`;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
635
653
|
if (body !== void 0) {
|
|
636
654
|
if (body instanceof FormData) {
|
|
637
655
|
config.body = body;
|
|
@@ -645,6 +663,9 @@ async function request(method, url, opts = {}) {
|
|
|
645
663
|
}
|
|
646
664
|
try {
|
|
647
665
|
let res = await fetch(finalUrl, config);
|
|
666
|
+
if (_statusHandlers.has(res.status)) {
|
|
667
|
+
_statusHandlers.get(res.status)(res, { method, url: finalUrl });
|
|
668
|
+
}
|
|
648
669
|
clearTimeout(timeoutId);
|
|
649
670
|
if (_responseInterceptor) {
|
|
650
671
|
res = _responseInterceptor(res) || res;
|
|
@@ -763,7 +784,7 @@ function upload(url, {
|
|
|
763
784
|
method = "POST",
|
|
764
785
|
onProgress,
|
|
765
786
|
// (sentBytes, totalBytes, percent) => void
|
|
766
|
-
signal
|
|
787
|
+
signal: signal2
|
|
767
788
|
// AbortSignal
|
|
768
789
|
} = {}) {
|
|
769
790
|
return new Promise((resolve, reject) => {
|
|
@@ -772,20 +793,28 @@ function upload(url, {
|
|
|
772
793
|
const xhr = new XMLHttpRequest();
|
|
773
794
|
xhr.open(method, finalUrl, true);
|
|
774
795
|
let cfg = { method, headers: { ...headers } };
|
|
796
|
+
if (_bearerTokenFn) {
|
|
797
|
+
const { token, headerName } = _bearerTokenFn;
|
|
798
|
+
const tokenValue = typeof token === "function" ? token() : token;
|
|
799
|
+
if (tokenValue) {
|
|
800
|
+
const prefix = headerName === "Authorization" ? "Bearer " : "";
|
|
801
|
+
cfg.headers[headerName] = `${prefix}${tokenValue}`;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
775
804
|
if (_requestInterceptor) {
|
|
776
805
|
cfg = _requestInterceptor(cfg) || cfg;
|
|
777
806
|
}
|
|
778
|
-
Object.entries(cfg.headers).forEach(([k,
|
|
807
|
+
Object.entries(cfg.headers).forEach(([k, v]) => xhr.setRequestHeader(k, v));
|
|
779
808
|
xhr.timeout = _timeout;
|
|
780
|
-
if (
|
|
809
|
+
if (signal2) {
|
|
781
810
|
const onAbort = () => {
|
|
782
811
|
try {
|
|
783
812
|
xhr.abort();
|
|
784
813
|
} catch {
|
|
785
814
|
}
|
|
786
815
|
};
|
|
787
|
-
if (
|
|
788
|
-
|
|
816
|
+
if (signal2.aborted) onAbort();
|
|
817
|
+
signal2.addEventListener("abort", onAbort, { once: true });
|
|
789
818
|
}
|
|
790
819
|
if (xhr.upload && typeof onProgress === "function") {
|
|
791
820
|
xhr.upload.onprogress = (e) => {
|
|
@@ -872,6 +901,39 @@ const HTTP = {
|
|
|
872
901
|
_timeout = ms;
|
|
873
902
|
return HTTP;
|
|
874
903
|
},
|
|
904
|
+
/**
|
|
905
|
+
* Set bearer token for all requests.
|
|
906
|
+
* @param {string|(() => string|null)} token - Token string or getter function
|
|
907
|
+
* @param {string} [headerName="Authorization"] - Header name
|
|
908
|
+
* @returns {typeof HTTP}
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* // Static token
|
|
912
|
+
* HTTP.bearer("my-token");
|
|
913
|
+
*
|
|
914
|
+
* // From localStorage (re-reads on each request)
|
|
915
|
+
* HTTP.bearer(() => localStorage.getItem("auth_token"));
|
|
916
|
+
*
|
|
917
|
+
* // Custom header name
|
|
918
|
+
* HTTP.bearer(() => localStorage.getItem("api_key"), "X-API-Key");
|
|
919
|
+
*/
|
|
920
|
+
bearer(token, headerName = "Authorization") {
|
|
921
|
+
_bearerTokenFn = { token, headerName };
|
|
922
|
+
return HTTP;
|
|
923
|
+
},
|
|
924
|
+
onStatus(status, fn) {
|
|
925
|
+
_statusHandlers.set(status, fn);
|
|
926
|
+
return HTTP;
|
|
927
|
+
},
|
|
928
|
+
onUnauthorized(fn) {
|
|
929
|
+
return HTTP.onStatus(401, fn);
|
|
930
|
+
},
|
|
931
|
+
onForbidden(fn) {
|
|
932
|
+
return HTTP.onStatus(403, fn);
|
|
933
|
+
},
|
|
934
|
+
onInternalServerError(fn) {
|
|
935
|
+
return HTTP.onStatus(500, fn);
|
|
936
|
+
},
|
|
875
937
|
/**
|
|
876
938
|
* Request interceptor hook.
|
|
877
939
|
* Useful for auth headers, correlation IDs, etc.
|
|
@@ -908,6 +970,123 @@ const HTTP = {
|
|
|
908
970
|
ping: () => console.log("PONG"),
|
|
909
971
|
description: "H is for Http"
|
|
910
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 bindList(target, sig, template, empty = "") {
|
|
1060
|
+
const el = getElement(target);
|
|
1061
|
+
return effect(() => {
|
|
1062
|
+
const items = sig.val;
|
|
1063
|
+
el.html(items?.length ? items.map(template).join("") : empty);
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
function bindOptions(target, sig, opts = {}) {
|
|
1067
|
+
const { value = "id", label = "name", placeholder = "Select ..." } = opts;
|
|
1068
|
+
const el = getElement(target);
|
|
1069
|
+
return effect(() => {
|
|
1070
|
+
const items = sig.val || [];
|
|
1071
|
+
el.html(
|
|
1072
|
+
`<option value="">${placeholder}</option>` + items.map(
|
|
1073
|
+
(item) => `<option value="${item[value]}">${item[label]}</option>`
|
|
1074
|
+
).join("")
|
|
1075
|
+
);
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
function bindClass(target, className, sig) {
|
|
1079
|
+
const el = getElement(target);
|
|
1080
|
+
return effect(() => {
|
|
1081
|
+
sig.val ? el.addClass(className) : el.removeClass(className);
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
function bindAttr(target, attr, sig) {
|
|
1085
|
+
const el = getElement(target);
|
|
1086
|
+
return effect(() => {
|
|
1087
|
+
el.elt.setAttribute(attr, sig.val);
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
911
1090
|
const FormEvents = {
|
|
912
1091
|
STATE_CHANGE: "form:state:change",
|
|
913
1092
|
ERRORS_CHANGE: "form:errors:change",
|
|
@@ -1455,6 +1634,64 @@ const createQuery = (options = {}) => {
|
|
|
1455
1634
|
stopAllPolling();
|
|
1456
1635
|
saveToStorage();
|
|
1457
1636
|
});
|
|
1637
|
+
const querySignal = (key, fetcher, options2 = {}) => {
|
|
1638
|
+
const data = signal(options2.inital ?? null);
|
|
1639
|
+
const loading = signal(false);
|
|
1640
|
+
const error = signal(null);
|
|
1641
|
+
const unsubscribe = subscribe(key, (entry) => {
|
|
1642
|
+
if (entry?.data) data.val = entry.data;
|
|
1643
|
+
if (entry?.error) error.val = entry.error;
|
|
1644
|
+
loading.val = !!entry?.promise && !entry?.data;
|
|
1645
|
+
});
|
|
1646
|
+
const fetch2 = () => {
|
|
1647
|
+
loading.val = true;
|
|
1648
|
+
return query(key, fetcher, options2);
|
|
1649
|
+
};
|
|
1650
|
+
const mutateFn = (updater) => {
|
|
1651
|
+
const prev = mutate(key, updater);
|
|
1652
|
+
data.val = getEntry(key)?.data;
|
|
1653
|
+
return prev;
|
|
1654
|
+
};
|
|
1655
|
+
const refetch = () => {
|
|
1656
|
+
invalidate(key);
|
|
1657
|
+
return fetch2();
|
|
1658
|
+
};
|
|
1659
|
+
if (options2.enabled !== false) fetch2().catch(() => {
|
|
1660
|
+
});
|
|
1661
|
+
return { data, loading, error, fetch: fetch2, refetch, unsubscribe, mutate: mutateFn };
|
|
1662
|
+
};
|
|
1663
|
+
const pollingSignal = (key, fetcher, interval, options2 = {}) => {
|
|
1664
|
+
const qs = querySignal(key, fetcher, { ...options2, enabled: false });
|
|
1665
|
+
const stop = startPolling(key, fetcher, interval, options2);
|
|
1666
|
+
return { ...qs, stop };
|
|
1667
|
+
};
|
|
1668
|
+
const bindQuery = (key, fetcher, options2 = {}) => {
|
|
1669
|
+
const { target, render, onLoading, onError, poll = null, ...queryOptions } = options2;
|
|
1670
|
+
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
1671
|
+
const renderData = (data) => {
|
|
1672
|
+
const html2 = render(data);
|
|
1673
|
+
if (typeof html2 === "string") el.innerHTML = html2;
|
|
1674
|
+
};
|
|
1675
|
+
EVT.sub(`query:${key}:success`, ({ data }) => renderData(data));
|
|
1676
|
+
EVT.sub(`query:${key}:set`, ({ data }) => renderData(data));
|
|
1677
|
+
EVT.sub(`query:${key}:mutate`, ({ data }) => renderData(data));
|
|
1678
|
+
if (onError) {
|
|
1679
|
+
EVT.sub(
|
|
1680
|
+
`query:${key}:error`,
|
|
1681
|
+
({ error, staleData }) => onError(error, staleData, el)
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
if (onLoading) {
|
|
1685
|
+
EVT.sub(`query:${key}:fetch`, ({ hasCache }) => {
|
|
1686
|
+
if (!hasCache) onLoading(el);
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
query(key, fetcher, queryOptions).catch(() => {
|
|
1690
|
+
});
|
|
1691
|
+
if (poll) {
|
|
1692
|
+
return startPolling(key, fetcher, poll, queryOptions);
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1458
1695
|
return {
|
|
1459
1696
|
query,
|
|
1460
1697
|
mutate,
|
|
@@ -1468,6 +1705,9 @@ const createQuery = (options = {}) => {
|
|
|
1468
1705
|
stopAllPolling,
|
|
1469
1706
|
getEntry,
|
|
1470
1707
|
gc,
|
|
1708
|
+
querySignal,
|
|
1709
|
+
pollingSignal,
|
|
1710
|
+
bindQuery,
|
|
1471
1711
|
clear: () => {
|
|
1472
1712
|
cache2.clear();
|
|
1473
1713
|
localStorage.removeItem(persistKey);
|
|
@@ -1475,44 +1715,7 @@ const createQuery = (options = {}) => {
|
|
|
1475
1715
|
}
|
|
1476
1716
|
};
|
|
1477
1717
|
};
|
|
1478
|
-
const queryClient = createQuery(
|
|
1479
|
-
persistKey: "teksoft-cache",
|
|
1480
|
-
persistedKeys: ["user", "settings"]
|
|
1481
|
-
});
|
|
1482
|
-
const bindQuery = (key, fetcher, options = {}) => {
|
|
1483
|
-
const {
|
|
1484
|
-
target,
|
|
1485
|
-
render,
|
|
1486
|
-
onLoading,
|
|
1487
|
-
onError,
|
|
1488
|
-
poll = null,
|
|
1489
|
-
...queryOptions
|
|
1490
|
-
} = options;
|
|
1491
|
-
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
1492
|
-
const renderData = (data) => {
|
|
1493
|
-
const html2 = render(data);
|
|
1494
|
-
if (typeof html2 === "string") el.innerHTML = html2;
|
|
1495
|
-
};
|
|
1496
|
-
EVT.sub(`query:${key}:success`, ({ data }) => renderData(data));
|
|
1497
|
-
EVT.sub(`query:${key}:set`, ({ data }) => renderData(data));
|
|
1498
|
-
EVT.sub(`query:${key}:mutate`, ({ data }) => renderData(data));
|
|
1499
|
-
if (onError) {
|
|
1500
|
-
EVT.sub(
|
|
1501
|
-
`query:${key}:error`,
|
|
1502
|
-
({ error, staleData }) => onError(error, staleData, el)
|
|
1503
|
-
);
|
|
1504
|
-
}
|
|
1505
|
-
if (onLoading) {
|
|
1506
|
-
EVT.sub(`query:${key}:fetch`, ({ hasCache }) => {
|
|
1507
|
-
if (!hasCache) onLoading(el);
|
|
1508
|
-
});
|
|
1509
|
-
}
|
|
1510
|
-
queryClient.query(key, fetcher, queryOptions).catch(() => {
|
|
1511
|
-
});
|
|
1512
|
-
if (poll) {
|
|
1513
|
-
return queryClient.startPolling(key, fetcher, poll, queryOptions);
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1718
|
+
const queryClient = createQuery();
|
|
1516
1719
|
export {
|
|
1517
1720
|
DOM,
|
|
1518
1721
|
EVT,
|
|
@@ -1523,10 +1726,18 @@ export {
|
|
|
1523
1726
|
Q,
|
|
1524
1727
|
V,
|
|
1525
1728
|
all,
|
|
1526
|
-
|
|
1729
|
+
batch,
|
|
1730
|
+
bind,
|
|
1731
|
+
bindAttr,
|
|
1732
|
+
bindClass,
|
|
1733
|
+
bindList,
|
|
1734
|
+
bindOptions,
|
|
1527
1735
|
cache,
|
|
1736
|
+
computed,
|
|
1737
|
+
createQuery,
|
|
1528
1738
|
del,
|
|
1529
1739
|
download,
|
|
1740
|
+
effect,
|
|
1530
1741
|
formatByCountry,
|
|
1531
1742
|
get,
|
|
1532
1743
|
isArray,
|
|
@@ -1544,7 +1755,9 @@ export {
|
|
|
1544
1755
|
raw,
|
|
1545
1756
|
redirect,
|
|
1546
1757
|
request,
|
|
1758
|
+
signal,
|
|
1547
1759
|
toCurrency,
|
|
1548
1760
|
upload,
|
|
1549
|
-
useFormHandler
|
|
1761
|
+
useFormHandler,
|
|
1762
|
+
when
|
|
1550
1763
|
};
|
package/dist/vaniy.iife.min.js
CHANGED
|
@@ -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=v.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},T=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},C=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},D=e=>document.querySelectorAll(e),I={Q:C,$:C,all:D,$$:D,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=C(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("string"!=typeof t)return;const r=s[t];return r||(console.warn(`DOM.scan: ref "${t}" not found`),C(null))}})},make:w,makeId:E,parseHtml:T,onPageLoad:A,onWindowLoad:$,ping:()=>console.log("PONG!"),description:"DOM is for dom manipulation"};let N="",q=8e3,R=null,M=null;const 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 x={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 H(e){return null===e||"object"!=typeof e?String(e):Array.isArray(e)?`[${e.map(H).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${H(e[t])}`).join(",")}}`}const F=(e,t)=>setTimeout(()=>t.abort(),e);async function k(e,t,r={}){const{params:n,body:s,headers:o={},cache:a}=r;let i=N+t;if(n){const e=new URLSearchParams(n).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(q,l),c=!!a,d=a?.strategy,m=a?.ttl??0,f=function(e="memory"){return x[e]||x.memory}(a?.storage),h=a?.key||function(e,t,r,n){return`H|${e}|${t}${r?`?${new URLSearchParams(r).toString()}`:""}${n&&"GET"!==e?`#${H(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};void 0!==s&&(s instanceof FormData?y.body=s:(y.headers["Content-Type"]="application/json",y.body=JSON.stringify(s))),R&&(y=R(y)||y);try{let t,r=await fetch(i,y);clearTimeout(u),M&&(r=M(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=N+e;if(r){const e=new URLSearchParams(r).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(q,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 j(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=`${N}${e}`,m=new XMLHttpRequest;m.open(o,d,!0);let f={method:o,headers:{...s}};if(R&&(f=R(f)||f),Object.entries(f.headers).forEach(([e,t])=>m.setRequestHeader(e,t)),m.timeout=q,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(M){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")};M(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:`${N}${e}`,method:o}),m.ontimeout=()=>u({status:0,data:"Timeout",url:`${N}${e}`,method:o}),m.send(c)})}const _=(e,t)=>k("GET",e,t),V=(e,t,r={})=>k("POST",e,{...r,body:t}),B=(e,t,r={})=>k("PUT",e,{...r,body:t}),G=(e,t={})=>k("DELETE",e,t),J=(e,t)=>fetch(N+e,t),Y={base:e=>(N=e,Y),timeout:e=>(q=e,Y),interceptRequest:e=>(R=e,Y),interceptResponse:e=>(M=e,Y),get:_,post:V,put:B,delete:G,raw:J,download:P,upload:j,ping:()=>console.log("PONG"),description:"H is for Http"},z={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 K{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(z.VALIDATED,{formId:this.formId,isValid:s,errors:o,data:n}),!s)return this.errors=o,this.#o(),void t.pub(z.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(z.SUBMIT_ERROR,{formId:this.formId,errors:{_preSubmit:[e.message]}})}t.pub(z.SUBMIT_SUCCESS,{formId:this.formId,data:n}),this.onSubmit(n)}#s(){t.pub(z.STATE_CHANGE,{formId:this.formId,state:{...this.formState}})}#o(){t.pub(z.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(z.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(z.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 Q{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(z.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(z.ERRORS_CHANGE,this._boundHandleErrors),this.clearAll()}}const W=((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"]});return e.DOM=I,e.EVT=t,e.FormErrorRenderer=Q,e.FormEvents=z,e.FormHandler=K,e.HTTP=Y,e.Q=C,e.V=p,e.all=D,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)}),W.query(e,r,u).catch(()=>{}),l)return W.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=G,e.download=P,e.formatByCountry=(e,t)=>n(e,r[t]??r.US),e.get=_,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=$,e.parseHtml=T,e.post=V,e.put=B,e.queryClient=W,e.raw=J,e.redirect=e=>window.location.href=e,e.request=k,e.toCurrency=n,e.upload=j,e.useFormHandler=function(e,t,r,n){const s=new K(e,t,r,n),o=new Q(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"},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),v=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?(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: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:w,makeId:v,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 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 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);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 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)=>(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: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,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,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 g(e,n)},w=e=>{const t=c.get(e);t&&(clearInterval(t),c.delete(e),d("polling:stop",e,{}))},v=()=>{for(const e of c.keys())w(e)},E=(e,t,r,n={})=>{w(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}),()=>w(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",()=>{v(),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,g(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=b(e,t);return n.val=p(e)?.data,r}}};return{query:g,mutate:b,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||g(e,t,r).catch(()=>{})},startPolling:E,stopPolling:w,stopAllPolling:v,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)}),g(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.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.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=w,e.makeId=v,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=v.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},T=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},C=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},D=e=>document.querySelectorAll(e),I={Q:C,$:C,all:D,$$:D,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=C(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("string"!=typeof t)return;const r=s[t];return r||(console.warn(`DOM.scan: ref "${t}" not found`),C(null))}})},make:w,makeId:E,parseHtml:T,onPageLoad:A,onWindowLoad:$,ping:()=>console.log("PONG!"),description:"DOM is for dom manipulation"};let N="",q=8e3,R=null,M=null;const x=new Map,L=()=>Date.now();function O(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<L()?(t.removeItem(e),null):n.val}catch{return null}},set(e,r,n){const s=n?L()+n:null;t.setItem(e,JSON.stringify({val:r,exp:s}))},del(e){t&&t.removeItem(e)},clear(){t&&t.clear()}}:null}const U={memory:{get(e){const t=x.get(e);return t?t.exp&&t.exp<L()?(x.delete(e),null):t.val:null},set(e,t,r){const n=r?L()+r:null;x.set(e,{val:t,exp:n})},del(e){x.delete(e)},clear(){x.clear()}},local:O("localStorage"),session:O("sessionStorage")};function H(e){return null===e||"object"!=typeof e?String(e):Array.isArray(e)?`[${e.map(H).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${H(e[t])}`).join(",")}}`}const F=(e,t)=>setTimeout(()=>t.abort(),e);async function k(e,t,r={}){const{params:n,body:s,headers:o={},cache:a}=r;let i=N+t;if(n){const e=new URLSearchParams(n).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(q,l),c=!!a,d=a?.strategy,m=a?.ttl??0,f=function(e="memory"){return U[e]||U.memory}(a?.storage),h=a?.key||function(e,t,r,n){return`H|${e}|${t}${r?`?${new URLSearchParams(r).toString()}`:""}${n&&"GET"!==e?`#${H(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};void 0!==s&&(s instanceof FormData?y.body=s:(y.headers["Content-Type"]="application/json",y.body=JSON.stringify(s))),R&&(y=R(y)||y);try{let t,r=await fetch(i,y);clearTimeout(u),M&&(r=M(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=N+e;if(r){const e=new URLSearchParams(r).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(q,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 j(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=`${N}${e}`,m=new XMLHttpRequest;m.open(o,d,!0);let f={method:o,headers:{...s}};if(R&&(f=R(f)||f),Object.entries(f.headers).forEach(([e,t])=>m.setRequestHeader(e,t)),m.timeout=q,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(M){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")};M(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:`${N}${e}`,method:o}),m.ontimeout=()=>u({status:0,data:"Timeout",url:`${N}${e}`,method:o}),m.send(c)})}const _=(e,t)=>k("GET",e,t),V=(e,t,r={})=>k("POST",e,{...r,body:t}),B=(e,t,r={})=>k("PUT",e,{...r,body:t}),G=(e,t={})=>k("DELETE",e,t),J=(e,t)=>fetch(N+e,t),Y={base:e=>(N=e,Y),timeout:e=>(q=e,Y),interceptRequest:e=>(R=e,Y),interceptResponse:e=>(M=e,Y),get:_,post:V,put:B,delete:G,raw:J,download:P,upload:j,ping:()=>console.log("PONG"),description:"H is for Http"},z={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 K{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(z.VALIDATED,{formId:this.formId,isValid:s,errors:o,data:n}),!s)return this.errors=o,this.#o(),void t.pub(z.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(z.SUBMIT_ERROR,{formId:this.formId,errors:{_preSubmit:[e.message]}})}t.pub(z.SUBMIT_SUCCESS,{formId:this.formId,data:n}),this.onSubmit(n)}#s(){t.pub(z.STATE_CHANGE,{formId:this.formId,state:{...this.formState}})}#o(){t.pub(z.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(z.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(z.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 Q{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(z.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(z.ERRORS_CHANGE,this._boundHandleErrors),this.clearAll()}}const W=((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"]});e.DOM=I,e.EVT=t,e.FormErrorRenderer=Q,e.FormEvents=z,e.FormHandler=K,e.HTTP=Y,e.Q=C,e.V=p,e.all=D,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)}),W.query(e,r,u).catch(()=>{}),l)return W.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=G,e.download=P,e.formatByCountry=(e,t)=>n(e,r[t]??r.US),e.get=_,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=$,e.parseHtml=T,e.post=V,e.put=B,e.queryClient=W,e.raw=J,e.redirect=e=>window.location.href=e,e.request=k,e.toCurrency=n,e.upload=j,e.useFormHandler=function(e,t,r,n){const s=new K(e,t,r,n),o=new Q(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"},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),v=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?(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: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:w,makeId:v,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,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,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 g(e,n)},w=e=>{const t=c.get(e);t&&(clearInterval(t),c.delete(e),d("polling:stop",e,{}))},v=()=>{for(const e of c.keys())w(e)},E=(e,t,r,n={})=>{w(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}),()=>w(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",()=>{v(),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,g(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=b(e,t);return n.val=p(e)?.data,r}}};return{query:g,mutate:b,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||g(e,t,r).catch(()=>{})},startPolling:E,stopPolling:w,stopAllPolling:v,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)}),g(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=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.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.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=w,e.makeId=v,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"})});
|