@ai-matrx/kit 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/dist/autosave.cjs +92 -0
  5. package/dist/autosave.cjs.map +1 -0
  6. package/dist/autosave.d.cts +17 -0
  7. package/dist/autosave.d.ts +17 -0
  8. package/dist/autosave.js +72 -0
  9. package/dist/autosave.js.map +1 -0
  10. package/dist/clipboard.cjs +152 -0
  11. package/dist/clipboard.cjs.map +1 -0
  12. package/dist/clipboard.d.cts +17 -0
  13. package/dist/clipboard.d.ts +17 -0
  14. package/dist/clipboard.js +132 -0
  15. package/dist/clipboard.js.map +1 -0
  16. package/dist/color-util.cjs +790 -0
  17. package/dist/color-util.cjs.map +1 -0
  18. package/dist/color-util.d.cts +235 -0
  19. package/dist/color-util.d.ts +235 -0
  20. package/dist/color-util.js +767 -0
  21. package/dist/color-util.js.map +1 -0
  22. package/dist/concurrency.cjs +59 -0
  23. package/dist/concurrency.cjs.map +1 -0
  24. package/dist/concurrency.d.cts +19 -0
  25. package/dist/concurrency.d.ts +19 -0
  26. package/dist/concurrency.js +38 -0
  27. package/dist/concurrency.js.map +1 -0
  28. package/dist/confirm.cjs +344 -0
  29. package/dist/confirm.cjs.map +1 -0
  30. package/dist/confirm.d.cts +132 -0
  31. package/dist/confirm.d.ts +132 -0
  32. package/dist/confirm.js +312 -0
  33. package/dist/confirm.js.map +1 -0
  34. package/dist/delimiter-guard.cjs +172 -0
  35. package/dist/delimiter-guard.cjs.map +1 -0
  36. package/dist/delimiter-guard.d.cts +119 -0
  37. package/dist/delimiter-guard.d.ts +119 -0
  38. package/dist/delimiter-guard.js +151 -0
  39. package/dist/delimiter-guard.js.map +1 -0
  40. package/dist/drafts.cjs +223 -0
  41. package/dist/drafts.cjs.map +1 -0
  42. package/dist/drafts.d.cts +62 -0
  43. package/dist/drafts.d.ts +62 -0
  44. package/dist/drafts.js +201 -0
  45. package/dist/drafts.js.map +1 -0
  46. package/dist/idb-store.cjs +178 -0
  47. package/dist/idb-store.cjs.map +1 -0
  48. package/dist/idb-store.d.cts +111 -0
  49. package/dist/idb-store.d.ts +111 -0
  50. package/dist/idb-store.js +155 -0
  51. package/dist/idb-store.js.map +1 -0
  52. package/dist/idle-scheduler.cjs +268 -0
  53. package/dist/idle-scheduler.cjs.map +1 -0
  54. package/dist/idle-scheduler.d.cts +185 -0
  55. package/dist/idle-scheduler.d.ts +185 -0
  56. package/dist/idle-scheduler.js +246 -0
  57. package/dist/idle-scheduler.js.map +1 -0
  58. package/dist/index.cjs +3113 -0
  59. package/dist/index.cjs.map +1 -0
  60. package/dist/index.d.cts +897 -0
  61. package/dist/index.d.ts +897 -0
  62. package/dist/index.js +3088 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/invalidation.cjs +64 -0
  65. package/dist/invalidation.cjs.map +1 -0
  66. package/dist/invalidation.d.cts +52 -0
  67. package/dist/invalidation.d.ts +52 -0
  68. package/dist/invalidation.js +43 -0
  69. package/dist/invalidation.js.map +1 -0
  70. package/dist/json-format.cjs +319 -0
  71. package/dist/json-format.cjs.map +1 -0
  72. package/dist/json-format.d.cts +148 -0
  73. package/dist/json-format.d.ts +148 -0
  74. package/dist/json-format.js +286 -0
  75. package/dist/json-format.js.map +1 -0
  76. package/dist/latest-request.cjs +36 -0
  77. package/dist/latest-request.cjs.map +1 -0
  78. package/dist/latest-request.d.cts +29 -0
  79. package/dist/latest-request.d.ts +29 -0
  80. package/dist/latest-request.js +16 -0
  81. package/dist/latest-request.js.map +1 -0
  82. package/dist/qr.cjs +109 -0
  83. package/dist/qr.cjs.map +1 -0
  84. package/dist/qr.d.cts +47 -0
  85. package/dist/qr.d.ts +47 -0
  86. package/dist/qr.js +78 -0
  87. package/dist/qr.js.map +1 -0
  88. package/dist/react-tree.cjs +69 -0
  89. package/dist/react-tree.cjs.map +1 -0
  90. package/dist/react-tree.d.cts +38 -0
  91. package/dist/react-tree.d.ts +38 -0
  92. package/dist/react-tree.js +38 -0
  93. package/dist/react-tree.js.map +1 -0
  94. package/dist/search-scoring.cjs +116 -0
  95. package/dist/search-scoring.cjs.map +1 -0
  96. package/dist/search-scoring.d.cts +77 -0
  97. package/dist/search-scoring.d.ts +77 -0
  98. package/dist/search-scoring.js +95 -0
  99. package/dist/search-scoring.js.map +1 -0
  100. package/dist/text-case.cjs +313 -0
  101. package/dist/text-case.cjs.map +1 -0
  102. package/dist/text-case.d.cts +53 -0
  103. package/dist/text-case.d.ts +53 -0
  104. package/dist/text-case.js +292 -0
  105. package/dist/text-case.js.map +1 -0
  106. package/dist/toast.cjs +74 -0
  107. package/dist/toast.cjs.map +1 -0
  108. package/dist/toast.d.cts +92 -0
  109. package/dist/toast.d.ts +92 -0
  110. package/dist/toast.js +54 -0
  111. package/dist/toast.js.map +1 -0
  112. package/dist/url-state.cjs +212 -0
  113. package/dist/url-state.cjs.map +1 -0
  114. package/dist/url-state.d.cts +90 -0
  115. package/dist/url-state.d.ts +90 -0
  116. package/dist/url-state.js +199 -0
  117. package/dist/url-state.js.map +1 -0
  118. package/package.json +286 -0
package/dist/index.js ADDED
@@ -0,0 +1,3088 @@
1
+ "use client";
2
+
3
+ // src/autosave.ts
4
+ import { useEffect, useRef, useState } from "react";
5
+ function useAutosave(opts) {
6
+ const { save, debounceMs = 900 } = opts;
7
+ const [status, setStatus] = useState("idle");
8
+ const [lastSavedAt, setLastSavedAt] = useState(null);
9
+ const pendingRef = useRef(null);
10
+ const timerRef = useRef(null);
11
+ const savingRef = useRef(false);
12
+ const saveRef = useRef(save);
13
+ useEffect(() => {
14
+ saveRef.current = save;
15
+ });
16
+ async function saveNow() {
17
+ if (savingRef.current) return;
18
+ const pending = pendingRef.current;
19
+ if (!pending) return;
20
+ pendingRef.current = null;
21
+ savingRef.current = true;
22
+ setStatus("saving");
23
+ let failed = false;
24
+ try {
25
+ const res = await saveRef.current(pending.value);
26
+ if (res.error) {
27
+ failed = true;
28
+ pendingRef.current = pendingRef.current ?? pending;
29
+ setStatus("error");
30
+ } else {
31
+ setLastSavedAt(/* @__PURE__ */ new Date());
32
+ setStatus(pendingRef.current ? "unsaved" : "saved");
33
+ }
34
+ } catch {
35
+ failed = true;
36
+ pendingRef.current = pendingRef.current ?? pending;
37
+ setStatus("error");
38
+ } finally {
39
+ savingRef.current = false;
40
+ if (pendingRef.current && !failed) void saveNow();
41
+ }
42
+ }
43
+ function schedule(value) {
44
+ pendingRef.current = { value };
45
+ setStatus("unsaved");
46
+ if (timerRef.current) clearTimeout(timerRef.current);
47
+ timerRef.current = setTimeout(() => void saveNow(), debounceMs);
48
+ }
49
+ function flush2() {
50
+ if (timerRef.current) {
51
+ clearTimeout(timerRef.current);
52
+ timerRef.current = null;
53
+ }
54
+ void saveNow();
55
+ }
56
+ useEffect(() => {
57
+ return () => {
58
+ if (timerRef.current) clearTimeout(timerRef.current);
59
+ const pending = pendingRef.current;
60
+ if (pending && !savingRef.current) {
61
+ pendingRef.current = null;
62
+ void saveRef.current(pending.value);
63
+ }
64
+ };
65
+ }, []);
66
+ return { status, lastSavedAt, schedule, flush: flush2 };
67
+ }
68
+
69
+ // src/latest-request.ts
70
+ import { useCallback, useRef as useRef2 } from "react";
71
+ function useLatestRequest() {
72
+ const seqRef = useRef2(0);
73
+ return useCallback(() => {
74
+ const mySeq = ++seqRef.current;
75
+ return () => mySeq === seqRef.current;
76
+ }, []);
77
+ }
78
+
79
+ // src/clipboard.ts
80
+ import { useCallback as useCallback2, useState as useState2 } from "react";
81
+ function toError(err, fallback) {
82
+ if (err instanceof Error) return err;
83
+ if (typeof err === "string" && err) return new Error(err);
84
+ return new Error(fallback);
85
+ }
86
+ function useClipboard(options = {}) {
87
+ const { notify } = options;
88
+ const [lastCopied, setLastCopied] = useState2(null);
89
+ const [error, setError] = useState2(null);
90
+ const handleSuccess = (type, successMessage) => {
91
+ setLastCopied(type);
92
+ setError(null);
93
+ notify?.(
94
+ successMessage ?? `${type.charAt(0).toUpperCase() + type.slice(1)} copied to clipboard!`,
95
+ "success"
96
+ );
97
+ };
98
+ const handleError = (err, type) => {
99
+ const message = `Failed to copy ${type}`;
100
+ setError(toError(err, message));
101
+ console.error(message, err);
102
+ notify?.(message, "error");
103
+ };
104
+ const copyText = useCallback2(
105
+ async (text, successMessage) => {
106
+ try {
107
+ await navigator.clipboard.writeText(text);
108
+ handleSuccess("text", successMessage);
109
+ } catch (err) {
110
+ handleError(err, "text");
111
+ }
112
+ },
113
+ [notify]
114
+ );
115
+ const copyImage = useCallback2(
116
+ async (imageSrc, successMessage) => {
117
+ try {
118
+ const response = await fetch(imageSrc);
119
+ if (!response.ok)
120
+ throw new Error(`HTTP error! status: ${response.status}`);
121
+ const blob = await response.blob();
122
+ const canvas = document.createElement("canvas");
123
+ const ctx = canvas.getContext("2d");
124
+ if (!ctx) throw new Error("Failed to get canvas context");
125
+ return new Promise((resolve, reject) => {
126
+ const img = new Image();
127
+ img.onload = () => {
128
+ canvas.width = img.width;
129
+ canvas.height = img.height;
130
+ ctx.drawImage(img, 0, 0);
131
+ canvas.toBlob((pngBlob) => {
132
+ if (pngBlob) {
133
+ const item = new ClipboardItem({ "image/png": pngBlob });
134
+ navigator.clipboard.write([item]).then(
135
+ () => {
136
+ handleSuccess("image", successMessage);
137
+ resolve();
138
+ },
139
+ (err) => reject(
140
+ toError(err, "Failed to write image to clipboard")
141
+ )
142
+ );
143
+ } else {
144
+ reject(new Error("Failed to convert image to PNG"));
145
+ }
146
+ }, "image/png");
147
+ };
148
+ img.onerror = () => reject(new Error("Failed to load image"));
149
+ img.src = URL.createObjectURL(blob);
150
+ });
151
+ } catch (err) {
152
+ handleError(err, "image");
153
+ }
154
+ },
155
+ [notify]
156
+ );
157
+ const copyLink = useCallback2(
158
+ async (link, stripParams = false, successMessage) => {
159
+ try {
160
+ let value = link;
161
+ if (stripParams) {
162
+ const url = new URL(link);
163
+ value = `${url.origin}${url.pathname}`;
164
+ }
165
+ await navigator.clipboard.writeText(value);
166
+ handleSuccess("link", successMessage);
167
+ } catch (err) {
168
+ handleError(err, "link");
169
+ }
170
+ },
171
+ [notify]
172
+ );
173
+ const pasteText = useCallback2(async () => {
174
+ try {
175
+ const text = await navigator.clipboard.readText();
176
+ setError(null);
177
+ return text;
178
+ } catch (err) {
179
+ setError(toError(err, "Failed to paste text"));
180
+ console.error("Failed to paste text: ", err);
181
+ return "";
182
+ }
183
+ }, []);
184
+ const pasteImage = useCallback2(async () => {
185
+ try {
186
+ if (!navigator.clipboard?.read) return null;
187
+ const items = await navigator.clipboard.read();
188
+ for (const item of items) {
189
+ const imageType = item.types.find((type) => type.startsWith("image/"));
190
+ if (imageType) {
191
+ const blob = await item.getType(imageType);
192
+ return new File([blob], "pasted-image.png", { type: imageType });
193
+ }
194
+ }
195
+ return null;
196
+ } catch (err) {
197
+ setError(toError(err, "Failed to paste image"));
198
+ console.error("Failed to paste image: ", err);
199
+ return null;
200
+ }
201
+ }, []);
202
+ return { copyText, copyImage, copyLink, pasteText, pasteImage, lastCopied, error };
203
+ }
204
+
205
+ // src/search-scoring.ts
206
+ var WEIGHT_TABLE = {
207
+ title: { exact: 1e4, startsWith: 5e3, includes: 2e3 },
208
+ subtitle: { exact: 2e3, startsWith: 1e3, includes: 500 },
209
+ body: { exact: 1e3, startsWith: 600, includes: 400 },
210
+ tag: { exact: 500, startsWith: 400, includes: 300 },
211
+ meta: { exact: 200, startsWith: 150, includes: 100 },
212
+ id: { exact: 100, startsWith: 75, includes: 50 }
213
+ };
214
+ var MIN_AUTO_ID_QUERY_LEN = 3;
215
+ function getStringId(item) {
216
+ if (item && typeof item === "object" && "id" in item) {
217
+ const id = item.id;
218
+ if (typeof id === "string" && id.length > 0) return id;
219
+ }
220
+ return null;
221
+ }
222
+ function resolveTiers(field) {
223
+ if (field.weight === "custom" || field.exact != null) {
224
+ return {
225
+ exact: field.exact ?? 0,
226
+ startsWith: field.startsWith ?? 0,
227
+ includes: field.includes ?? 0
228
+ };
229
+ }
230
+ return WEIGHT_TABLE[field.weight ?? "body"];
231
+ }
232
+ function scoreValue(value, q, tiers) {
233
+ if (!value) return 0;
234
+ const v = value.toLowerCase();
235
+ if (v === q) return tiers.exact;
236
+ if (v.startsWith(q)) return tiers.startsWith;
237
+ if (v.includes(q)) return tiers.includes;
238
+ return 0;
239
+ }
240
+ function computeSearchScore(item, query, fields) {
241
+ const trimmed = query.trim();
242
+ if (!trimmed) return 0;
243
+ const q = trimmed.toLowerCase();
244
+ let total = 0;
245
+ fields.forEach((field, idx) => {
246
+ const raw = field.get(item);
247
+ if (raw == null) return;
248
+ const tiers = resolveTiers(field);
249
+ let best = 0;
250
+ if (Array.isArray(raw)) {
251
+ for (const v of raw) {
252
+ if (typeof v !== "string") continue;
253
+ const s = scoreValue(v, q, tiers);
254
+ if (s > best) best = s;
255
+ }
256
+ } else if (typeof raw === "string") {
257
+ best = scoreValue(raw, q, tiers);
258
+ }
259
+ if (best > 0) {
260
+ total += best + (fields.length - idx);
261
+ }
262
+ });
263
+ const hasExplicitId = fields.some((f) => f.weight === "id");
264
+ if (!hasExplicitId && q.length >= MIN_AUTO_ID_QUERY_LEN) {
265
+ const id = getStringId(item);
266
+ if (id) {
267
+ total += scoreValue(id, q, WEIGHT_TABLE.id);
268
+ }
269
+ }
270
+ return total;
271
+ }
272
+ function matchesSearch(item, query, fields) {
273
+ return computeSearchScore(item, query, fields) > 0;
274
+ }
275
+ function idMatchesQuery(item, query) {
276
+ const q = query.trim().toLowerCase();
277
+ if (q.length < MIN_AUTO_ID_QUERY_LEN) return false;
278
+ const id = getStringId(item);
279
+ return id != null && id.toLowerCase().includes(q);
280
+ }
281
+ function filterAndSortBySearch(items, query, fields) {
282
+ const trimmed = query.trim();
283
+ if (!trimmed) return items.slice();
284
+ const scored = [];
285
+ for (let i = 0; i < items.length; i++) {
286
+ const item = items[i];
287
+ const score = computeSearchScore(item, trimmed, fields);
288
+ if (score > 0) scored.push({ item, score, idx: i });
289
+ }
290
+ scored.sort((a, b) => b.score - a.score || a.idx - b.idx);
291
+ return scored.map((s) => s.item);
292
+ }
293
+
294
+ // src/concurrency.ts
295
+ async function runWithConcurrency(items, limit, worker, shouldStart = () => true) {
296
+ if (items.length === 0) {
297
+ return { started: 0, succeeded: 0, failed: 0, failures: [] };
298
+ }
299
+ let cursor = 0;
300
+ let started = 0;
301
+ let succeeded = 0;
302
+ const failures = [];
303
+ const requestedLimit = Number.isFinite(limit) ? Math.floor(limit) : 1;
304
+ const workerCount = Math.max(1, Math.min(requestedLimit, items.length));
305
+ const runners = Array.from({ length: workerCount }, async () => {
306
+ while (shouldStart()) {
307
+ const index = cursor++;
308
+ if (index >= items.length) return;
309
+ started += 1;
310
+ const item = items[index];
311
+ try {
312
+ await worker(item, index);
313
+ succeeded += 1;
314
+ } catch (error) {
315
+ failures.push({ item, index, error });
316
+ }
317
+ }
318
+ });
319
+ await Promise.all(runners);
320
+ failures.sort((left, right) => left.index - right.index);
321
+ return {
322
+ started,
323
+ succeeded,
324
+ failed: failures.length,
325
+ failures
326
+ };
327
+ }
328
+
329
+ // src/text-case.ts
330
+ var DEFAULT_WORD_REPLACEMENTS = {
331
+ // Acronyms & initialisms
332
+ "api": "API",
333
+ "apis": "APIs",
334
+ "ui": "UI",
335
+ "ux": "UX",
336
+ "id": "ID",
337
+ "ids": "IDs",
338
+ "qr": "QR",
339
+ "ssr": "SSR",
340
+ "csr": "CSR",
341
+ "ssg": "SSG",
342
+ "isr": "ISR",
343
+ "spa": "SPA",
344
+ "pwa": "PWA",
345
+ "sdk": "SDK",
346
+ "sdks": "SDKs",
347
+ "cli": "CLI",
348
+ "tty": "TTY",
349
+ "repl": "REPL",
350
+ "ci": "CI",
351
+ "cd": "CD",
352
+ "cpu": "CPU",
353
+ "cpus": "CPUs",
354
+ "gpu": "GPU",
355
+ "gpus": "GPUs",
356
+ "ram": "RAM",
357
+ "rom": "ROM",
358
+ "ssd": "SSD",
359
+ "ssds": "SSDs",
360
+ "hdd": "HDD",
361
+ "hdds": "HDDs",
362
+ "kpi": "KPI",
363
+ "kpis": "KPIs",
364
+ "sla": "SLA",
365
+ "slas": "SLAs",
366
+ "slo": "SLO",
367
+ "slos": "SLOs",
368
+ "sli": "SLI",
369
+ "slis": "SLIs",
370
+ "dom": "DOM",
371
+ // Web, formats, protocols
372
+ "url": "URL",
373
+ "urls": "URLs",
374
+ "uri": "URI",
375
+ "uris": "URIs",
376
+ "http": "HTTP",
377
+ "https": "HTTPS",
378
+ "html": "HTML",
379
+ "css": "CSS",
380
+ "json": "JSON",
381
+ "yaml": "YAML",
382
+ "yml": "YML",
383
+ "toml": "TOML",
384
+ "csv": "CSV",
385
+ "pdf": "PDF",
386
+ "tsv": "TSV",
387
+ "jpg": "JPG",
388
+ "jpeg": "JPEG",
389
+ "png": "PNG",
390
+ "gif": "GIF",
391
+ "webp": "WebP",
392
+ "heic": "HEIC",
393
+ "heif": "HEIF",
394
+ "bmp": "BMP",
395
+ "tiff": "TIFF",
396
+ "ico": "ICO",
397
+ "xml": "XML",
398
+ "sql": "SQL",
399
+ "db": "DB",
400
+ "dbs": "DBs",
401
+ "nosql": "NoSQL",
402
+ "graphql": "GraphQL",
403
+ "grpc": "gRPC",
404
+ "rest": "REST",
405
+ "restful": "RESTful",
406
+ "websocket": "WebSocket",
407
+ "websockets": "WebSockets",
408
+ "webrtc": "WebRTC",
409
+ // Networking
410
+ "ip": "IP",
411
+ "ipv4": "IPv4",
412
+ "ipv6": "IPv6",
413
+ "dns": "DNS",
414
+ "dhcp": "DHCP",
415
+ "nat": "NAT",
416
+ "tcp": "TCP",
417
+ "udp": "UDP",
418
+ "icmp": "ICMP",
419
+ "ttl": "TTL",
420
+ "lan": "LAN",
421
+ "wan": "WAN",
422
+ "vlan": "VLAN",
423
+ "cdn": "CDN",
424
+ "ftp": "FTP",
425
+ "ssh": "SSH",
426
+ "tls": "TLS",
427
+ "ssl": "SSL",
428
+ // Security & crypto
429
+ "jwt": "JWT",
430
+ "jws": "JWS",
431
+ "jwe": "JWE",
432
+ "hmac": "HMAC",
433
+ "rsa": "RSA",
434
+ "ecdsa": "ECDSA",
435
+ "aes": "AES",
436
+ "pbkdf2": "PBKDF2",
437
+ "argon2": "Argon2",
438
+ "scrypt": "scrypt",
439
+ "totp": "TOTP",
440
+ "hotp": "HOTP",
441
+ "mfa": "MFA",
442
+ "2fa": "2FA",
443
+ "csrf": "CSRF",
444
+ "xss": "XSS",
445
+ "ssrf": "SSRF",
446
+ "rce": "RCE",
447
+ "dos": "DoS",
448
+ "ddos": "DDoS",
449
+ "mitm": "MITM",
450
+ "csp": "CSP",
451
+ "cors": "CORS",
452
+ "pii": "PII",
453
+ "phi": "PHI",
454
+ "gdpr": "GDPR",
455
+ "ccpa": "CCPA",
456
+ "hipaa": "HIPAA",
457
+ "rfc": "RFC",
458
+ // Platforms, langs, tools (single-token)
459
+ "javascript": "JavaScript",
460
+ "typescript": "TypeScript",
461
+ "jsx": "JSX",
462
+ "tsx": "TSX",
463
+ "node": "Node",
464
+ // (used when tokenized alone)
465
+ "deno": "Deno",
466
+ "bun": "Bun",
467
+ "react": "React",
468
+ "nextjs": "Next.js",
469
+ // if your tokenizer drops dots, keep this
470
+ "nodejs": "Node.js",
471
+ "postgresql": "PostgreSQL",
472
+ "postgres": "Postgres",
473
+ "mysql": "MySQL",
474
+ "sqlite": "SQLite",
475
+ "redis": "Redis",
476
+ "supabase": "Supabase",
477
+ "docker": "Docker",
478
+ "kubernetes": "Kubernetes",
479
+ "k8s": "Kubernetes",
480
+ "helm": "Helm",
481
+ "npm": "npm",
482
+ "pnpm": "pnpm",
483
+ "yarn": "Yarn",
484
+ "eslint": "ESLint",
485
+ "prettier": "Prettier",
486
+ "vite": "Vite",
487
+ "webpack": "Webpack",
488
+ "babel": "Babel",
489
+ // OS & vendors
490
+ "macos": "macOS",
491
+ "ios": "iOS",
492
+ "ipados": "iPadOS",
493
+ "watchos": "watchOS",
494
+ "tvos": "tvOS",
495
+ "windows": "Windows",
496
+ "linux": "Linux",
497
+ "ubuntu": "Ubuntu",
498
+ "github": "GitHub",
499
+ "gitlab": "GitLab",
500
+ "bitbucket": "Bitbucket",
501
+ // Data & analytics
502
+ "etl": "ETL",
503
+ "elt": "ELT",
504
+ "olap": "OLAP",
505
+ "oltp": "OLTP",
506
+ "bi": "BI",
507
+ // Time & locales
508
+ "utc": "UTC",
509
+ "gmt": "GMT",
510
+ "pst": "PST",
511
+ "pdt": "PDT",
512
+ "pt": "PT",
513
+ // Common “small words” to keep lowercase (unless first/last word)
514
+ "or": "or",
515
+ "and": "and",
516
+ "the": "the",
517
+ "of": "of",
518
+ "in": "in",
519
+ "to": "to",
520
+ "with": "with",
521
+ "as": "as",
522
+ "by": "by",
523
+ "for": "for",
524
+ "on": "on",
525
+ "at": "at",
526
+ "up": "up",
527
+ "a": "a",
528
+ "an": "an",
529
+ "is": "is",
530
+ "are": "are",
531
+ "was": "was",
532
+ "were": "were",
533
+ "be": "be",
534
+ "but": "but",
535
+ "nor": "nor",
536
+ "so": "so",
537
+ "yet": "yet",
538
+ "per": "per",
539
+ "via": "via",
540
+ // Latin abbreviations (tokenized as words in some pipelines)
541
+ "eg": "e.g.",
542
+ "ie": "i.e.",
543
+ "etc": "etc.",
544
+ "aka": "aka",
545
+ "vs": "vs.",
546
+ "v": "v.",
547
+ // Client abbreviations
548
+ "CIC": "CIC",
549
+ "AGR": "AGR",
550
+ "AGER": "AGER",
551
+ "DD": "DD",
552
+ "TS": "TS",
553
+ "TM": "TM",
554
+ "arman": "Arman"
555
+ };
556
+ var DEFAULT_OPTIONS = {
557
+ textCase: "title",
558
+ wordReplacements: DEFAULT_WORD_REPLACEMENTS,
559
+ trim: true
560
+ };
561
+ function formatText(text, options = {}) {
562
+ const opts = { ...DEFAULT_OPTIONS, ...options };
563
+ if (!text) return "";
564
+ let normalized = text.replace(/_/g, " ").replace(/-/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\s+/g, " ");
565
+ if (opts.trim) {
566
+ normalized = normalized.trim();
567
+ }
568
+ let caseTransformed = normalized;
569
+ switch (opts.textCase) {
570
+ case "title":
571
+ caseTransformed = normalized.replace(
572
+ /\w\S*/g,
573
+ (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
574
+ );
575
+ break;
576
+ case "sentence":
577
+ if (normalized.length > 0) {
578
+ caseTransformed = normalized.charAt(0).toUpperCase() + normalized.slice(1).toLowerCase();
579
+ }
580
+ break;
581
+ case "lower":
582
+ caseTransformed = normalized.toLowerCase();
583
+ break;
584
+ case "upper":
585
+ caseTransformed = normalized.toUpperCase();
586
+ break;
587
+ case "normal":
588
+ default:
589
+ break;
590
+ }
591
+ let result = caseTransformed;
592
+ if (opts.wordReplacements) {
593
+ Object.entries(opts.wordReplacements).forEach(([key, value]) => {
594
+ const regex = new RegExp(`\\b${key}\\b`, "gi");
595
+ result = result.replace(regex, value);
596
+ });
597
+ }
598
+ return result;
599
+ }
600
+ function createFormatter(defaultOptions = {}) {
601
+ return (text, overrideOptions = {}) => formatText(text, { ...defaultOptions, ...overrideOptions });
602
+ }
603
+ var formatTitleCase = createFormatter({ textCase: "title" });
604
+ var formatSentenceCase = createFormatter({ textCase: "sentence" });
605
+ var formatNormalCase = createFormatter({ textCase: "normal" });
606
+ var formatUpperCase = createFormatter({ textCase: "upper" });
607
+ var formatLowerCase = createFormatter({ textCase: "lower" });
608
+ var formatWithoutReplacements = createFormatter({ wordReplacements: {} });
609
+
610
+ // src/drafts/use-durable-draft.ts
611
+ import { useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
612
+ var PREFIX = "matrx:durable-draft:";
613
+ var warnedStorageUnavailable = false;
614
+ function storageWrite(storageKey, value) {
615
+ try {
616
+ if (value) window.localStorage.setItem(storageKey, value);
617
+ else window.localStorage.removeItem(storageKey);
618
+ } catch (err) {
619
+ if (!warnedStorageUnavailable) {
620
+ warnedStorageUnavailable = true;
621
+ console.warn(
622
+ "[useDurableDraft] localStorage unavailable \u2014 drafts survive only in memory this session",
623
+ err
624
+ );
625
+ }
626
+ }
627
+ }
628
+ function useDurableDraft(key) {
629
+ const storageKey = PREFIX + key;
630
+ const [draft, setDraftState] = useState3("");
631
+ const touchedKeyRef = useRef3(null);
632
+ useEffect2(() => {
633
+ let saved = null;
634
+ try {
635
+ saved = window.localStorage.getItem(storageKey);
636
+ } catch {
637
+ }
638
+ setDraftState(
639
+ (current) => touchedKeyRef.current === storageKey && current ? current : saved ?? ""
640
+ );
641
+ }, [storageKey]);
642
+ const setDraft = (value) => {
643
+ touchedKeyRef.current = storageKey;
644
+ setDraftState(value);
645
+ storageWrite(storageKey, value);
646
+ };
647
+ const clearDraft = () => {
648
+ touchedKeyRef.current = storageKey;
649
+ setDraftState("");
650
+ storageWrite(storageKey, "");
651
+ };
652
+ return { draft, setDraft, clearDraft };
653
+ }
654
+
655
+ // src/drafts/local-drafts.ts
656
+ var STORAGE_KEY = "matrx.local-drafts.v1";
657
+ var DRAFT_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
658
+ var MAX_DRAFT_CHARS = 4e5;
659
+ var MAX_TOTAL_CHARS = 15e5;
660
+ var TRUNCATION_MARKER = "\n\n[\u2026 truncated by the local draft store \u2014 the note was too large to snapshot in full]";
661
+ var sources = /* @__PURE__ */ new Map();
662
+ var unloadListenerAttached = false;
663
+ var listeners = /* @__PURE__ */ new Set();
664
+ var version = 0;
665
+ function subscribeDrafts(listener) {
666
+ listeners.add(listener);
667
+ return () => {
668
+ listeners.delete(listener);
669
+ };
670
+ }
671
+ function getDraftsVersion() {
672
+ return version;
673
+ }
674
+ function emitDraftsChanged() {
675
+ version += 1;
676
+ for (const listener of listeners) {
677
+ try {
678
+ listener();
679
+ } catch (err) {
680
+ console.error("[LocalDrafts] subscriber threw:", err);
681
+ }
682
+ }
683
+ }
684
+ function registerDraftSource(id, collect) {
685
+ sources.set(id, collect);
686
+ attachUnloadListener();
687
+ return () => {
688
+ if (sources.get(id) === collect) sources.delete(id);
689
+ };
690
+ }
691
+ function attachUnloadListener() {
692
+ if (unloadListenerAttached || typeof window === "undefined") return;
693
+ unloadListenerAttached = true;
694
+ window.addEventListener("pagehide", () => {
695
+ captureDrafts("unload");
696
+ });
697
+ }
698
+ function captureDrafts(reason) {
699
+ if (typeof window === "undefined") return [];
700
+ const collected = [];
701
+ for (const [id, collect] of sources) {
702
+ try {
703
+ collected.push(...collect());
704
+ } catch (err) {
705
+ console.error("[LocalDrafts] draft source failed:", id, err);
706
+ }
707
+ }
708
+ if (collected.length === 0) return [];
709
+ const now = Date.now();
710
+ const written = collected.map((input) => ({
711
+ ...input,
712
+ content: input.content.length > MAX_DRAFT_CHARS ? input.content.slice(0, MAX_DRAFT_CHARS) + TRUNCATION_MARKER : input.content,
713
+ key: draftKey(input.namespace, input.entityId),
714
+ capturedAt: now,
715
+ reason
716
+ }));
717
+ const existing = readAll().filter(
718
+ (d) => !written.some((w) => w.key === d.key)
719
+ );
720
+ writeAll([...written, ...existing]);
721
+ console.warn(
722
+ `[LocalDrafts] snapshotted ${written.length} unsaved item(s) to this browser (reason: ${reason}).`,
723
+ written.map((d) => `${d.key} (${d.content.length} chars)`)
724
+ );
725
+ return written;
726
+ }
727
+ function listDrafts(namespace, ownerId) {
728
+ if (!ownerId) return [];
729
+ return readAll().filter((d) => d.namespace === namespace && d.ownerId === ownerId).sort((a, b) => b.capturedAt - a.capturedAt);
730
+ }
731
+ function getDraft(namespace, entityId, ownerId) {
732
+ if (!ownerId) return null;
733
+ const key = draftKey(namespace, entityId);
734
+ return readAll().find((d) => d.key === key && d.ownerId === ownerId) ?? null;
735
+ }
736
+ function discardDraft(namespace, entityId) {
737
+ const key = draftKey(namespace, entityId);
738
+ const all = readAll();
739
+ const next = all.filter((d) => d.key !== key);
740
+ if (next.length !== all.length) writeAll(next);
741
+ }
742
+ function draftKey(namespace, entityId) {
743
+ return `${namespace}:${entityId}`;
744
+ }
745
+ function readAll() {
746
+ if (typeof window === "undefined") return [];
747
+ let raw = null;
748
+ try {
749
+ raw = window.localStorage.getItem(STORAGE_KEY);
750
+ } catch {
751
+ return [];
752
+ }
753
+ if (!raw) return [];
754
+ try {
755
+ const parsed = JSON.parse(raw);
756
+ if (!Array.isArray(parsed)) return [];
757
+ const cutoff = Date.now() - DRAFT_TTL_MS;
758
+ return parsed.filter(isLocalDraft).filter((d) => d.capturedAt >= cutoff);
759
+ } catch {
760
+ return [];
761
+ }
762
+ }
763
+ function writeAll(drafts) {
764
+ if (typeof window === "undefined") return;
765
+ const cutoff = Date.now() - DRAFT_TTL_MS;
766
+ const fresh = drafts.filter((d) => d.capturedAt >= cutoff).sort((a, b) => b.capturedAt - a.capturedAt);
767
+ const kept = [];
768
+ let total = 0;
769
+ for (const draft of fresh) {
770
+ if (total + draft.content.length > MAX_TOTAL_CHARS && kept.length > 0) {
771
+ console.warn(
772
+ "[LocalDrafts] draft budget exhausted \u2014 dropping older draft",
773
+ draft.key
774
+ );
775
+ continue;
776
+ }
777
+ kept.push(draft);
778
+ total += draft.content.length;
779
+ }
780
+ try {
781
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(kept));
782
+ } catch (err) {
783
+ console.error("[LocalDrafts] failed to persist drafts:", err);
784
+ if (kept.length > 1) {
785
+ try {
786
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify([kept[0]]));
787
+ } catch {
788
+ }
789
+ }
790
+ }
791
+ emitDraftsChanged();
792
+ }
793
+ function isLocalDraft(value) {
794
+ if (typeof value !== "object" || value === null) return false;
795
+ const d = value;
796
+ return typeof d.key === "string" && typeof d.namespace === "string" && typeof d.entityId === "string" && typeof d.content === "string" && typeof d.capturedAt === "number";
797
+ }
798
+
799
+ // src/confirm/opener.ts
800
+ var STATE_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.kit.confirm-opener-state");
801
+ function getState() {
802
+ const holder = globalThis;
803
+ let state = holder[STATE_SLOT];
804
+ if (!state) {
805
+ state = { host: null, queue: [] };
806
+ holder[STATE_SLOT] = state;
807
+ }
808
+ return state;
809
+ }
810
+ function _registerHost(controller) {
811
+ const state = getState();
812
+ state.host = controller;
813
+ while (state.queue.length > 0) {
814
+ const next = state.queue.shift();
815
+ controller.show(next.opts, next.resolve);
816
+ }
817
+ }
818
+ function _unregisterHost(controller) {
819
+ const state = getState();
820
+ if (state.host === controller) state.host = null;
821
+ }
822
+ function confirm(opts) {
823
+ return new Promise((resolve) => {
824
+ const state = getState();
825
+ if (state.host) {
826
+ state.host.show(opts, resolve);
827
+ } else {
828
+ state.queue.push({ opts, resolve });
829
+ }
830
+ });
831
+ }
832
+
833
+ // src/confirm/host.tsx
834
+ import * as React3 from "react";
835
+
836
+ // src/confirm/cn.ts
837
+ import { twMerge } from "tailwind-merge";
838
+ function cn(...values) {
839
+ return twMerge(values.filter(Boolean).join(" "));
840
+ }
841
+
842
+ // src/confirm/alert-dialog.tsx
843
+ import * as React2 from "react";
844
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
845
+
846
+ // src/react-tree.ts
847
+ import * as React from "react";
848
+ var REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal");
849
+ function treeContainsComponent(node, Component) {
850
+ if (node == null || typeof node === "boolean") return false;
851
+ if (Array.isArray(node)) {
852
+ return node.some((child) => treeContainsComponent(child, Component));
853
+ }
854
+ if (React.isValidElement(node)) {
855
+ if (node.type === Component) return true;
856
+ const props = node.props;
857
+ return props.children != null ? treeContainsComponent(props.children, Component) : false;
858
+ }
859
+ if (typeof node === "string" || typeof node === "number") return false;
860
+ if (typeof node === "object" && node.$$typeof === REACT_PORTAL_TYPE) {
861
+ return treeContainsComponent(
862
+ node.children,
863
+ Component
864
+ );
865
+ }
866
+ if (typeof node === "object" && Symbol.iterator in node) {
867
+ return Array.from(node).some(
868
+ (child) => treeContainsComponent(child, Component)
869
+ );
870
+ }
871
+ if (typeof process !== "undefined" && true) {
872
+ const keys = typeof node === "object" ? ` with keys {${Object.keys(node).join(", ")}}` : "";
873
+ console.error(
874
+ `[treeContainsComponent] A non-renderable value${keys} is being passed as a React child. React will throw 'Objects are not valid as a React child' at the real render site. Stringify it (e.g. JSON.stringify) before rendering.`,
875
+ node
876
+ );
877
+ }
878
+ return false;
879
+ }
880
+
881
+ // src/confirm/alert-dialog.tsx
882
+ import { jsx, jsxs } from "react/jsx-runtime";
883
+ var buttonBase = "inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 h-9 px-4 py-2";
884
+ var buttonDefault = "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90";
885
+ var buttonOutline = "border border-border bg-card shadow-sm hover:bg-accent hover:text-accent-foreground";
886
+ var AlertDialog = AlertDialogPrimitive.Root;
887
+ var AlertDialogPortal = AlertDialogPrimitive.Portal;
888
+ var AlertDialogOverlay = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
889
+ AlertDialogPrimitive.Overlay,
890
+ {
891
+ className: cn(
892
+ "fixed inset-0 z-[10000] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
893
+ className
894
+ ),
895
+ ...props,
896
+ ref
897
+ }
898
+ ));
899
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
900
+ var AlertDialogContentPrimitive = React2.forwardRef(({ ...props }, ref) => /* @__PURE__ */ jsx(AlertDialogPrimitive.Content, { ...props, ref, "aria-modal": "true" }));
901
+ AlertDialogContentPrimitive.displayName = "AlertDialogContentPrimitive";
902
+ var AlertDialogDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
903
+ AlertDialogPrimitive.Description,
904
+ {
905
+ ref,
906
+ className: cn("text-sm text-muted-foreground", className),
907
+ ...props
908
+ }
909
+ ));
910
+ AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
911
+ var AlertDialogContent = React2.forwardRef(({ className, children, ...props }, ref) => {
912
+ const hasDescription = treeContainsComponent(children, AlertDialogDescription) || treeContainsComponent(children, AlertDialogPrimitive.Description);
913
+ return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [
914
+ /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
915
+ /* @__PURE__ */ jsxs(
916
+ AlertDialogContentPrimitive,
917
+ {
918
+ ref,
919
+ className: cn(
920
+ "fixed left-[50%] top-[50%] z-[10000] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
921
+ className
922
+ ),
923
+ ...props,
924
+ children: [
925
+ !hasDescription && /* @__PURE__ */ jsx(AlertDialogPrimitive.Description, { className: "sr-only", children: "Please confirm the action described in this dialog." }),
926
+ children
927
+ ]
928
+ }
929
+ )
930
+ ] });
931
+ });
932
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
933
+ var AlertDialogHeader = ({
934
+ className,
935
+ ...props
936
+ }) => /* @__PURE__ */ jsx(
937
+ "div",
938
+ {
939
+ className: cn(
940
+ "flex flex-col space-y-2 text-center sm:text-left",
941
+ className
942
+ ),
943
+ ...props
944
+ }
945
+ );
946
+ AlertDialogHeader.displayName = "AlertDialogHeader";
947
+ var AlertDialogFooter = ({
948
+ className,
949
+ ...props
950
+ }) => /* @__PURE__ */ jsx(
951
+ "div",
952
+ {
953
+ className: cn(
954
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
955
+ className
956
+ ),
957
+ ...props
958
+ }
959
+ );
960
+ AlertDialogFooter.displayName = "AlertDialogFooter";
961
+ var AlertDialogTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
962
+ AlertDialogPrimitive.Title,
963
+ {
964
+ ref,
965
+ className: cn("text-lg font-semibold", className),
966
+ ...props
967
+ }
968
+ ));
969
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
970
+ var AlertDialogAction = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
971
+ AlertDialogPrimitive.Action,
972
+ {
973
+ ref,
974
+ className: cn(buttonBase, buttonDefault, className),
975
+ ...props
976
+ }
977
+ ));
978
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
979
+ var AlertDialogCancel = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
980
+ AlertDialogPrimitive.Cancel,
981
+ {
982
+ ref,
983
+ className: cn(buttonBase, buttonOutline, "mt-2 sm:mt-0", className),
984
+ ...props
985
+ }
986
+ ));
987
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
988
+
989
+ // src/confirm/confirm-dialog.tsx
990
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
991
+ function SpinnerIcon({ className }) {
992
+ return /* @__PURE__ */ jsx2(
993
+ "svg",
994
+ {
995
+ xmlns: "http://www.w3.org/2000/svg",
996
+ width: 24,
997
+ height: 24,
998
+ viewBox: "0 0 24 24",
999
+ fill: "none",
1000
+ stroke: "currentColor",
1001
+ strokeWidth: 2,
1002
+ strokeLinecap: "round",
1003
+ strokeLinejoin: "round",
1004
+ "aria-hidden": "true",
1005
+ className,
1006
+ children: /* @__PURE__ */ jsx2("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
1007
+ }
1008
+ );
1009
+ }
1010
+ function ConfirmDialog({
1011
+ open,
1012
+ onOpenChange,
1013
+ title,
1014
+ description,
1015
+ content,
1016
+ contentClassName,
1017
+ confirmLabel = "Confirm",
1018
+ cancelLabel = "Cancel",
1019
+ variant = "default",
1020
+ busy = false,
1021
+ confirmDisabled = false,
1022
+ onConfirm
1023
+ }) {
1024
+ return /* @__PURE__ */ jsx2(AlertDialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs2(AlertDialogContent, { className: contentClassName, children: [
1025
+ /* @__PURE__ */ jsxs2(AlertDialogHeader, { children: [
1026
+ /* @__PURE__ */ jsx2(AlertDialogTitle, { children: title }),
1027
+ description ? /* @__PURE__ */ jsx2(AlertDialogDescription, { children: description }) : null
1028
+ ] }),
1029
+ content ?? null,
1030
+ /* @__PURE__ */ jsxs2(AlertDialogFooter, { children: [
1031
+ cancelLabel === null ? null : /* @__PURE__ */ jsx2(AlertDialogCancel, { className: "max-lg:min-h-11", disabled: busy, children: cancelLabel }),
1032
+ /* @__PURE__ */ jsxs2(
1033
+ AlertDialogAction,
1034
+ {
1035
+ disabled: busy || confirmDisabled,
1036
+ onClick: (event) => {
1037
+ event.preventDefault();
1038
+ void onConfirm();
1039
+ },
1040
+ className: cn(
1041
+ "max-lg:min-h-11",
1042
+ variant === "destructive" && "bg-destructive text-destructive-foreground hover:bg-destructive/90"
1043
+ ),
1044
+ children: [
1045
+ busy ? /* @__PURE__ */ jsx2(SpinnerIcon, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
1046
+ confirmLabel
1047
+ ]
1048
+ }
1049
+ )
1050
+ ] })
1051
+ ] }) });
1052
+ }
1053
+
1054
+ // src/confirm/host.tsx
1055
+ import { jsx as jsx3 } from "react/jsx-runtime";
1056
+ function ConfirmDialogHost() {
1057
+ const [active, setActive] = React3.useState(null);
1058
+ const [tick, setTick] = React3.useState(0);
1059
+ const queueRef = React3.useRef([]);
1060
+ React3.useEffect(() => {
1061
+ const controller = {
1062
+ show: (opts, resolve) => {
1063
+ queueRef.current.push({ opts, resolve });
1064
+ setTick((n) => n + 1);
1065
+ }
1066
+ };
1067
+ _registerHost(controller);
1068
+ return () => _unregisterHost(controller);
1069
+ }, []);
1070
+ React3.useEffect(() => {
1071
+ if (active === null && queueRef.current.length > 0) {
1072
+ setActive(queueRef.current.shift());
1073
+ }
1074
+ }, [active, tick]);
1075
+ const handleConfirm = React3.useCallback(() => {
1076
+ if (!active) return;
1077
+ active.resolve(true);
1078
+ setActive(null);
1079
+ }, [active]);
1080
+ const handleOpenChange = React3.useCallback(
1081
+ (open) => {
1082
+ if (!open && active) {
1083
+ active.resolve(false);
1084
+ setActive(null);
1085
+ }
1086
+ },
1087
+ [active]
1088
+ );
1089
+ return /* @__PURE__ */ jsx3(
1090
+ ConfirmDialog,
1091
+ {
1092
+ open: !!active,
1093
+ onOpenChange: handleOpenChange,
1094
+ title: active?.opts.title ?? "",
1095
+ description: active?.opts.description,
1096
+ confirmLabel: active?.opts.confirmLabel,
1097
+ cancelLabel: active?.opts.cancelLabel,
1098
+ variant: active?.opts.variant,
1099
+ onConfirm: handleConfirm
1100
+ }
1101
+ );
1102
+ }
1103
+
1104
+ // src/toast.ts
1105
+ function messageText(message, data) {
1106
+ const description = data && typeof data.description === "string" ? data.description : "";
1107
+ const title = typeof message === "string" ? message : "";
1108
+ return [title, description].filter(Boolean).join(" \u2014 ") || "Error toast";
1109
+ }
1110
+ function createMatrxToast({
1111
+ toast: hostToast,
1112
+ capture
1113
+ }) {
1114
+ if (typeof hostToast !== "function") {
1115
+ throw new Error(
1116
+ "createMatrxToast: options.toast must be the sonner `toast` object (or a structural equivalent) \u2014 got " + typeof hostToast
1117
+ );
1118
+ }
1119
+ function captureToast(kind, message, data) {
1120
+ if (!capture) return;
1121
+ try {
1122
+ capture({
1123
+ source: "user-toast",
1124
+ message: `${kind === "warning" ? "[warning] " : ""}${messageText(message, data)}`,
1125
+ userMessage: messageText(message, data),
1126
+ raw: {
1127
+ kind,
1128
+ message: typeof message === "string" ? message : void 0,
1129
+ data
1130
+ }
1131
+ });
1132
+ } catch {
1133
+ }
1134
+ }
1135
+ const error = (message, data) => {
1136
+ captureToast("error", message, data);
1137
+ return hostToast.error(message, data);
1138
+ };
1139
+ const warning = (message, data) => {
1140
+ captureToast("warning", message, data);
1141
+ return hostToast.warning(message, data);
1142
+ };
1143
+ const forward = hostToast;
1144
+ const toast = Object.assign(
1145
+ ((...args) => forward(...args)),
1146
+ hostToast,
1147
+ { error, warning }
1148
+ );
1149
+ const toastErrorAlreadyCaptured = ((message, data) => hostToast.error(message, data));
1150
+ return { toast, toastErrorAlreadyCaptured };
1151
+ }
1152
+
1153
+ // src/invalidation.ts
1154
+ var STATE_SLOT2 = /* @__PURE__ */ Symbol.for("ai-matrx.kit.invalidation-registry");
1155
+ function getCallbacks() {
1156
+ const holder = globalThis;
1157
+ let state = holder[STATE_SLOT2];
1158
+ if (!state) {
1159
+ state = /* @__PURE__ */ new Map();
1160
+ holder[STATE_SLOT2] = state;
1161
+ }
1162
+ return state;
1163
+ }
1164
+ function registerInvalidationCallback(name, callback) {
1165
+ const callbacks = getCallbacks();
1166
+ let set = callbacks.get(name);
1167
+ if (!set) {
1168
+ set = /* @__PURE__ */ new Set();
1169
+ callbacks.set(name, set);
1170
+ }
1171
+ set.add(callback);
1172
+ return () => {
1173
+ set.delete(callback);
1174
+ };
1175
+ }
1176
+ function fireInvalidation(name, detail) {
1177
+ const set = getCallbacks().get(name);
1178
+ if (!set || set.size === 0) return false;
1179
+ for (const callback of set) {
1180
+ try {
1181
+ callback(detail);
1182
+ } catch (error) {
1183
+ console.error(
1184
+ `[invalidation-registry] callback for "${name}" threw`,
1185
+ error
1186
+ );
1187
+ }
1188
+ }
1189
+ return true;
1190
+ }
1191
+
1192
+ // src/delimiter-guard.ts
1193
+ var ZWSP = "\u200B";
1194
+ var ESCAPED_DOLLARS = `${ZWSP}$${ZWSP}$`;
1195
+ var ESCAPED_BRACKET = `${ZWSP}&#91;`;
1196
+ var MAX_MATH_SPAN = 600;
1197
+ var STRUCTURAL_MARKDOWN = /\]\(|https?:\/\/|\*\*|(?:^|\n)[ \t]{0,3}#{1,6}[ \t]|(?:^|\n)[ \t]*[-*+][ \t]+|(?:^|\n)[ \t]*\d+[.)][ \t]/;
1198
+ var LATEX_COMMAND = /\\[a-zA-Z]/;
1199
+ var PROSE_WORD = /[A-Za-z]{3,}/g;
1200
+ var PROSE_WORD_LIMIT = 6;
1201
+ function looksLikeMath(inner) {
1202
+ const s = inner.trim();
1203
+ if (!s) return false;
1204
+ if (STRUCTURAL_MARKDOWN.test(s)) return false;
1205
+ if (s.length > MAX_MATH_SPAN) return false;
1206
+ if (LATEX_COMMAND.test(s)) {
1207
+ return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT * 3;
1208
+ }
1209
+ if (/\n[ \t]*\n/.test(s)) return false;
1210
+ return (s.match(PROSE_WORD) ?? []).length < PROSE_WORD_LIMIT;
1211
+ }
1212
+ function protectedRanges(text) {
1213
+ const ranges = [];
1214
+ const patterns = [/```[\s\S]*?(?:```|$)/g, /~~~[\s\S]*?(?:~~~|$)/g, /`[^`\n]*`/g];
1215
+ for (const re of patterns) {
1216
+ let m;
1217
+ while ((m = re.exec(text)) !== null) {
1218
+ ranges.push([m.index, m.index + m[0].length]);
1219
+ }
1220
+ }
1221
+ return ranges;
1222
+ }
1223
+ function isProtected(index, ranges) {
1224
+ return ranges.some(([start, end]) => index >= start && index < end);
1225
+ }
1226
+ function preview(text, max = 160) {
1227
+ const flat = text.replace(/\s+/g, " ").trim();
1228
+ return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
1229
+ }
1230
+ function guardMathDelimiters(text) {
1231
+ if (!text.includes("$$")) return { text, violations: [] };
1232
+ const ranges = protectedRanges(text);
1233
+ const tokens = [];
1234
+ for (let i = 0; i < text.length - 1; i++) {
1235
+ if (text[i] !== "$" || text[i + 1] !== "$") continue;
1236
+ if (!isProtected(i, ranges)) tokens.push(i);
1237
+ i++;
1238
+ }
1239
+ if (tokens.length === 0) return { text, violations: [] };
1240
+ const violations = [];
1241
+ const escapeAt = [];
1242
+ let j = 0;
1243
+ while (j < tokens.length) {
1244
+ const open = tokens[j];
1245
+ const close = tokens[j + 1];
1246
+ if (close === void 0) {
1247
+ violations.push({
1248
+ reason: "unpaired",
1249
+ index: open,
1250
+ spanLength: 0,
1251
+ // An unpaired `$$` is inert to remark-math (nothing closes it), so it
1252
+ // is reported but NOT escaped — it already renders as literal text.
1253
+ preview: preview(text.slice(open, open + 120))
1254
+ });
1255
+ break;
1256
+ }
1257
+ const inner = text.slice(open + 2, close);
1258
+ if (looksLikeMath(inner)) {
1259
+ j += 2;
1260
+ continue;
1261
+ }
1262
+ escapeAt.push(open);
1263
+ violations.push({
1264
+ reason: "prose-span",
1265
+ index: open,
1266
+ spanLength: inner.length,
1267
+ preview: preview(inner)
1268
+ });
1269
+ j += 1;
1270
+ }
1271
+ let guarded = text;
1272
+ for (const index of [...escapeAt].sort((a, b) => b - a)) {
1273
+ guarded = `${guarded.slice(0, index)}${ESCAPED_DOLLARS}${guarded.slice(index + 2)}`;
1274
+ }
1275
+ return { text: guarded, violations };
1276
+ }
1277
+ var MAX_LINK_LABEL = 200;
1278
+ var LABEL_BLOCK_STRUCTURE = /\n[ \t]*\n|(?:^|\n)[ \t]*[-*+][ \t]+|#{2,6}[ \t]/;
1279
+ function guardRunawayLinks(text) {
1280
+ if (!text.includes("[")) return { text, violations: [] };
1281
+ const ranges = protectedRanges(text);
1282
+ const violations = [];
1283
+ const escapeAt = [];
1284
+ const linkRe = /\[((?:[^[\]]|\\.)*)\]\(([^\s)]*)/g;
1285
+ let m;
1286
+ while ((m = linkRe.exec(text)) !== null) {
1287
+ const open = m.index;
1288
+ if (isProtected(open, ranges)) continue;
1289
+ const label = m[1] ?? "";
1290
+ const runaway = label.length > MAX_LINK_LABEL || LABEL_BLOCK_STRUCTURE.test(label);
1291
+ if (!runaway) continue;
1292
+ escapeAt.push(open);
1293
+ violations.push({
1294
+ reason: "runaway-link",
1295
+ index: open,
1296
+ spanLength: label.length,
1297
+ preview: preview(label)
1298
+ });
1299
+ }
1300
+ let guarded = text;
1301
+ for (const index of [...escapeAt].sort((a, b) => b - a)) {
1302
+ guarded = `${guarded.slice(0, index)}${ESCAPED_BRACKET}${guarded.slice(index + 1)}`;
1303
+ }
1304
+ return { text: guarded, violations };
1305
+ }
1306
+ function guardMarkdownDelimiters(text) {
1307
+ const math = guardMathDelimiters(text);
1308
+ const links = guardRunawayLinks(math.text);
1309
+ return {
1310
+ text: links.text,
1311
+ violations: [...math.violations, ...links.violations]
1312
+ };
1313
+ }
1314
+ function reportDelimiterViolations(violations, context) {
1315
+ if (violations.length === 0) return;
1316
+ try {
1317
+ const worst = violations.find((v) => v.reason !== "unpaired") ?? violations[0];
1318
+ if (!worst) return;
1319
+ const message = worst.reason === "prose-span" ? `Malformed math delimiters: a stray "$$" would have turned ${worst.spanLength} chars of prose into a math span (KaTeX would render it as red error text). Escaped it.` : worst.reason === "runaway-link" ? `Runaway markdown link: an unclosed "[" would have turned ${worst.spanLength} chars into one link label. Escaped it.` : `Malformed math delimiters: an unpaired "$$" reached the renderer.`;
1320
+ console.warn(`[markdown-delimiter-guard] ${message}`, {
1321
+ renderPath: context.renderPath,
1322
+ violations
1323
+ });
1324
+ context.capture?.({
1325
+ source: "markdown-delimiters",
1326
+ message,
1327
+ relation: `markdown:${context.renderPath}`,
1328
+ details: worst.preview,
1329
+ conversationId: context.conversationId,
1330
+ callSite: "guardMarkdownDelimiters",
1331
+ raw: { messageId: context.messageId, violations }
1332
+ });
1333
+ } catch {
1334
+ }
1335
+ }
1336
+
1337
+ // src/json-format/detect.ts
1338
+ import JSON5 from "json5";
1339
+ var FENCE_OPEN = /^([ \t]*)(`{3,}|~{3,})[ \t]*([^\s`~]*)[ \t]*$/;
1340
+ var JSON_FENCE_LANGS = /* @__PURE__ */ new Set(["json", "jsonc", "json5", "geojson", "jsonl"]);
1341
+ function splitFence(text) {
1342
+ const lines = text.split("\n");
1343
+ const openIdx = lines.findIndex((l) => FENCE_OPEN.test(l));
1344
+ if (openIdx === -1) return null;
1345
+ const open = FENCE_OPEN.exec(lines[openIdx] ?? "");
1346
+ if (!open) return null;
1347
+ const [, indent = "", marker = "```", lang = ""] = open;
1348
+ const fenceChar = marker[0] ?? "`";
1349
+ const closeRe = new RegExp(`^[ \\t]*\\${fenceChar}{${marker.length},}[ \\t]*$`);
1350
+ let closeIdx = -1;
1351
+ for (let i = openIdx + 1; i < lines.length; i++) {
1352
+ if (closeRe.test(lines[i] ?? "")) {
1353
+ closeIdx = i;
1354
+ break;
1355
+ }
1356
+ }
1357
+ const afterClose = closeIdx === -1 ? [] : lines.slice(closeIdx + 1);
1358
+ if (afterClose.some((l) => FENCE_OPEN.test(l))) return null;
1359
+ const bodyEnd = closeIdx === -1 ? lines.length : closeIdx;
1360
+ return {
1361
+ leading: openIdx > 0 ? `${lines.slice(0, openIdx).join("\n")}
1362
+ ` : "",
1363
+ payload: lines.slice(openIdx + 1, bodyEnd).join("\n"),
1364
+ trailing: afterClose.length > 0 ? `
1365
+ ${afterClose.join("\n")}` : "",
1366
+ fence: {
1367
+ marker,
1368
+ lang: lang.toLowerCase(),
1369
+ indent,
1370
+ closed: closeIdx !== -1
1371
+ }
1372
+ };
1373
+ }
1374
+ function splitBare(text) {
1375
+ const payload = text.trim();
1376
+ if (payload === "") {
1377
+ return { leading: text, payload: "", trailing: "", fence: null };
1378
+ }
1379
+ const start = text.indexOf(payload);
1380
+ return {
1381
+ leading: text.slice(0, start),
1382
+ payload,
1383
+ trailing: text.slice(start + payload.length),
1384
+ fence: null
1385
+ };
1386
+ }
1387
+ function rootKindOf(value) {
1388
+ if (Array.isArray(value)) return "array";
1389
+ if (typeof value === "object" && value !== null) return "object";
1390
+ return "scalar";
1391
+ }
1392
+ function isBracketShaped(payload) {
1393
+ const first = payload[0];
1394
+ const last = payload[payload.length - 1];
1395
+ if (payload.length < 2) return false;
1396
+ return first === "{" && last === "}" || first === "[" && last === "]";
1397
+ }
1398
+ function errorMessage(err) {
1399
+ return err instanceof Error ? err.message : "Invalid JSON";
1400
+ }
1401
+ function countLines(s) {
1402
+ if (s === "") return 0;
1403
+ let n = 1;
1404
+ for (let i = 0; i < s.length; i++) if (s[i] === "\n") n++;
1405
+ return n;
1406
+ }
1407
+ function detectJson(text) {
1408
+ const split = splitFence(text) ?? splitBare(text);
1409
+ const payload = split.fence ? split.payload.trim() : split.payload;
1410
+ const fenceSaysJson = split.fence !== null && (split.fence.lang === "" || JSON_FENCE_LANGS.has(split.fence.lang));
1411
+ const base = {
1412
+ fence: split.fence,
1413
+ leading: split.leading,
1414
+ trailing: split.trailing,
1415
+ payload,
1416
+ lineCount: countLines(payload),
1417
+ charCount: payload.length
1418
+ };
1419
+ if (payload === "") {
1420
+ return { ...base, ok: false, looksLikeJson: false };
1421
+ }
1422
+ if (split.fence !== null && !fenceSaysJson) {
1423
+ return { ...base, ok: false, looksLikeJson: false };
1424
+ }
1425
+ const shaped = isBracketShaped(payload);
1426
+ let value;
1427
+ let parser;
1428
+ let error;
1429
+ try {
1430
+ value = JSON.parse(payload);
1431
+ parser = "strict";
1432
+ } catch (strictErr) {
1433
+ try {
1434
+ value = JSON5.parse(payload);
1435
+ parser = "tolerant";
1436
+ } catch {
1437
+ error = errorMessage(strictErr);
1438
+ }
1439
+ }
1440
+ if (value === void 0 || parser === void 0) {
1441
+ return { ...base, ok: false, looksLikeJson: shaped, error };
1442
+ }
1443
+ const root = rootKindOf(value);
1444
+ const worthOffering = root !== "scalar" || fenceSaysJson;
1445
+ return { ...base, ok: true, looksLikeJson: worthOffering, value, parser, root };
1446
+ }
1447
+
1448
+ // src/json-format/json-value.ts
1449
+ function isJsonObject(value) {
1450
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1451
+ }
1452
+ function isJsonArray(value) {
1453
+ return Array.isArray(value);
1454
+ }
1455
+ function isJsonPrimitive(value) {
1456
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
1457
+ }
1458
+
1459
+ // src/json-format/format.ts
1460
+ var DEFAULT_JSON_INDENT = 2;
1461
+ var DEFAULT_JSON_WIDTH = 100;
1462
+ function orderedKeys(obj, sortKeys) {
1463
+ const keys = Object.keys(obj).filter((k) => obj[k] !== void 0);
1464
+ return sortKeys ? [...keys].sort((a, b) => a.localeCompare(b)) : keys;
1465
+ }
1466
+ function writeScalar(value) {
1467
+ return JSON.stringify(value) ?? "null";
1468
+ }
1469
+ function flatten(value, cfg) {
1470
+ if (isJsonArray(value)) {
1471
+ if (value.length === 0) return "[]";
1472
+ const parts = value.map((v) => flatten(v ?? null, cfg));
1473
+ return cfg.spaced ? `[${parts.join(", ")}]` : `[${parts.join(",")}]`;
1474
+ }
1475
+ if (isJsonObject(value)) {
1476
+ const keys = orderedKeys(value, cfg.sortKeys);
1477
+ if (keys.length === 0) return "{}";
1478
+ const colon = cfg.spaced ? ": " : ":";
1479
+ const parts = keys.map(
1480
+ (k) => `${JSON.stringify(k)}${colon}${flatten(value[k] ?? null, cfg)}`
1481
+ );
1482
+ return cfg.spaced ? `{ ${parts.join(", ")} }` : `{${parts.join(",")}}`;
1483
+ }
1484
+ return writeScalar(value);
1485
+ }
1486
+ function layoutEntries(entries, pad, cfg) {
1487
+ if (!cfg.pack) return entries.map((e) => pad + e);
1488
+ const lines = [];
1489
+ let current = "";
1490
+ for (let i = 0; i < entries.length; i++) {
1491
+ const entry = entries[i] ?? "";
1492
+ const isLast = i === entries.length - 1;
1493
+ const piece = isLast ? entry : `${entry},`;
1494
+ if (entry.includes("\n")) {
1495
+ if (current !== "") {
1496
+ lines.push(pad + current);
1497
+ current = "";
1498
+ }
1499
+ lines.push(pad + piece);
1500
+ continue;
1501
+ }
1502
+ if (current === "") {
1503
+ current = piece;
1504
+ continue;
1505
+ }
1506
+ const merged = `${current} ${piece}`;
1507
+ if (pad.length + merged.length <= cfg.width) {
1508
+ current = merged;
1509
+ } else {
1510
+ lines.push(pad + current);
1511
+ current = piece;
1512
+ }
1513
+ }
1514
+ if (current !== "") lines.push(pad + current);
1515
+ return lines;
1516
+ }
1517
+ function renderNode(value, level, used, cfg) {
1518
+ const isContainer = isJsonArray(value) || isJsonObject(value);
1519
+ if (!isContainer) return writeScalar(value);
1520
+ const flat = flatten(value, cfg);
1521
+ if (flat === "[]" || flat === "{}") return flat;
1522
+ if (cfg.width >= 0 && used + flat.length <= cfg.width) return flat;
1523
+ const pad = " ".repeat((level + 1) * cfg.indent);
1524
+ const closePad = " ".repeat(level * cfg.indent);
1525
+ if (isJsonArray(value)) {
1526
+ const entries2 = value.map(
1527
+ (v) => renderNode(v ?? null, level + 1, pad.length, cfg)
1528
+ );
1529
+ const body2 = layoutEntries(entries2, pad, cfg);
1530
+ const joined2 = cfg.pack ? body2.join("\n") : body2.join(",\n");
1531
+ return `[
1532
+ ${joined2}
1533
+ ${closePad}]`;
1534
+ }
1535
+ const keys = orderedKeys(value, cfg.sortKeys);
1536
+ const entries = keys.map((k) => {
1537
+ const prefix = `${JSON.stringify(k)}: `;
1538
+ const rendered = renderNode(
1539
+ value[k] ?? null,
1540
+ level + 1,
1541
+ pad.length + prefix.length,
1542
+ cfg
1543
+ );
1544
+ return prefix + rendered;
1545
+ });
1546
+ const body = layoutEntries(entries, pad, cfg);
1547
+ const joined = cfg.pack ? body.join("\n") : body.join(",\n");
1548
+ return `{
1549
+ ${joined}
1550
+ ${closePad}}`;
1551
+ }
1552
+ function stringifyJson(value, options) {
1553
+ const indent = options.indent ?? DEFAULT_JSON_INDENT;
1554
+ const sortKeys = options.sortKeys ?? false;
1555
+ if (options.style === "minify") {
1556
+ return flatten(value, { indent, width: -1, pack: false, spaced: false, sortKeys });
1557
+ }
1558
+ const cfg = {
1559
+ indent,
1560
+ width: options.style === "pretty" ? -1 : options.width ?? DEFAULT_JSON_WIDTH,
1561
+ pack: options.style === "compact",
1562
+ spaced: true,
1563
+ sortKeys
1564
+ };
1565
+ return renderNode(value, 0, 0, cfg);
1566
+ }
1567
+ function sizeOf(text) {
1568
+ let lines = text === "" ? 0 : 1;
1569
+ for (let i = 0; i < text.length; i++) if (text[i] === "\n") lines++;
1570
+ return { lines, chars: text.length };
1571
+ }
1572
+ function reassemble(detection, payload, mode) {
1573
+ const { fence, leading, trailing } = detection;
1574
+ const keepFence = mode === "add" || mode === "preserve" && fence !== null;
1575
+ if (!keepFence) {
1576
+ return leading + payload + trailing;
1577
+ }
1578
+ const marker = fence?.marker ?? "```";
1579
+ const lang = fence?.lang && fence.lang !== "" ? fence.lang : "json";
1580
+ const indent = fence?.indent ?? "";
1581
+ const body = indent ? payload.split("\n").map((l) => l === "" ? l : indent + l).join("\n") : payload;
1582
+ const close = fence !== null && !fence.closed ? "" : `
1583
+ ${indent}${marker}`;
1584
+ return `${leading}${indent}${marker}${lang}
1585
+ ${body}${close}${trailing}`;
1586
+ }
1587
+ function formatJsonText(text, options) {
1588
+ const detection = detectJson(text);
1589
+ const before = sizeOf(text);
1590
+ if (!detection.ok || detection.value === void 0) {
1591
+ return {
1592
+ ok: false,
1593
+ text,
1594
+ error: detection.error ?? "Selection is not JSON.",
1595
+ changed: false,
1596
+ detection,
1597
+ before,
1598
+ after: before
1599
+ };
1600
+ }
1601
+ const payload = stringifyJson(detection.value, options);
1602
+ const next = reassemble(detection, payload, options.fence ?? "preserve");
1603
+ return {
1604
+ ok: true,
1605
+ text: next,
1606
+ changed: next !== text,
1607
+ detection,
1608
+ before,
1609
+ after: sizeOf(next)
1610
+ };
1611
+ }
1612
+
1613
+ // src/idle-scheduler/scheduler.ts
1614
+ var STATE_SLOT3 = /* @__PURE__ */ Symbol.for("ai-matrx.kit.idle-scheduler-state");
1615
+ function getState2() {
1616
+ const holder = globalThis;
1617
+ let state = holder[STATE_SLOT3];
1618
+ if (!state) {
1619
+ state = {
1620
+ queue: /* @__PURE__ */ new Map(),
1621
+ flushState: "idle",
1622
+ cleanupFns: [],
1623
+ flushListeners: /* @__PURE__ */ new Set()
1624
+ };
1625
+ holder[STATE_SLOT3] = state;
1626
+ if (typeof window !== "undefined") {
1627
+ window.__idleSched = getSchedulerState;
1628
+ }
1629
+ }
1630
+ return state;
1631
+ }
1632
+ function registerIdleTask(key, priority, callback) {
1633
+ const state = getState2();
1634
+ if (state.flushState === "done") {
1635
+ scheduleImmediate(callback);
1636
+ return () => {
1637
+ };
1638
+ }
1639
+ state.queue.set(key, { key, priority, callback });
1640
+ if (state.flushState === "idle") {
1641
+ startFlushPipeline(state);
1642
+ }
1643
+ return () => {
1644
+ state.queue.delete(key);
1645
+ };
1646
+ }
1647
+ function onFlushComplete(listener) {
1648
+ const state = getState2();
1649
+ if (state.flushState === "done") {
1650
+ queueMicrotask(listener);
1651
+ return () => {
1652
+ };
1653
+ }
1654
+ state.flushListeners.add(listener);
1655
+ if (state.flushState === "idle") {
1656
+ startFlushPipeline(state);
1657
+ }
1658
+ return () => {
1659
+ state.flushListeners.delete(listener);
1660
+ };
1661
+ }
1662
+ function whenPageIdle(signal) {
1663
+ if (signal?.aborted) return Promise.resolve(false);
1664
+ return new Promise((resolve) => {
1665
+ let settled = false;
1666
+ let unsubscribe = () => {
1667
+ };
1668
+ const finish = (ready) => {
1669
+ if (settled) return;
1670
+ settled = true;
1671
+ unsubscribe();
1672
+ signal?.removeEventListener("abort", onAbort);
1673
+ resolve(ready);
1674
+ };
1675
+ const onAbort = () => finish(false);
1676
+ unsubscribe = onFlushComplete(() => finish(true));
1677
+ signal?.addEventListener("abort", onAbort, { once: true });
1678
+ });
1679
+ }
1680
+ function getSchedulerState() {
1681
+ const state = getState2();
1682
+ return {
1683
+ flushState: state.flushState,
1684
+ pendingCount: state.queue.size,
1685
+ pendingKeys: Array.from(state.queue.keys())
1686
+ };
1687
+ }
1688
+ function resetScheduler() {
1689
+ const state = getState2();
1690
+ state.cleanupFns.forEach((fn) => fn());
1691
+ state.cleanupFns = [];
1692
+ state.queue.clear();
1693
+ state.flushListeners.clear();
1694
+ state.flushState = "idle";
1695
+ }
1696
+ function startFlushPipeline(state) {
1697
+ if (typeof window === "undefined") return;
1698
+ state.flushState = "waiting";
1699
+ const waitForLoad = () => {
1700
+ if (document.readyState === "complete") {
1701
+ waitForPaint();
1702
+ } else {
1703
+ const onLoad = () => waitForPaint();
1704
+ window.addEventListener("load", onLoad, { once: true });
1705
+ state.cleanupFns.push(() => window.removeEventListener("load", onLoad));
1706
+ }
1707
+ };
1708
+ const waitForPaint = () => {
1709
+ let advanced = false;
1710
+ const advance = () => {
1711
+ if (advanced) return;
1712
+ advanced = true;
1713
+ waitForIdle();
1714
+ };
1715
+ const rafId = requestAnimationFrame(advance);
1716
+ const timeoutId = setTimeout(
1717
+ advance,
1718
+ document.visibilityState === "hidden" ? 250 : 1500
1719
+ );
1720
+ state.cleanupFns.push(() => {
1721
+ cancelAnimationFrame(rafId);
1722
+ clearTimeout(timeoutId);
1723
+ });
1724
+ };
1725
+ const waitForIdle = () => {
1726
+ const schedulerGlobal = globalThis.scheduler;
1727
+ if (schedulerGlobal && "postTask" in schedulerGlobal) {
1728
+ schedulerGlobal.postTask(() => void flush(state), { priority: "background" }).catch(() => {
1729
+ });
1730
+ return;
1731
+ }
1732
+ if ("requestIdleCallback" in window) {
1733
+ const idleId = requestIdleCallback(() => void flush(state));
1734
+ state.cleanupFns.push(() => cancelIdleCallback(idleId));
1735
+ return;
1736
+ }
1737
+ const channel = new MessageChannel();
1738
+ channel.port1.onmessage = () => void flush(state);
1739
+ channel.port2.postMessage(void 0);
1740
+ };
1741
+ waitForLoad();
1742
+ }
1743
+ async function flush(state) {
1744
+ if (state.flushState === "done" || state.flushState === "flushing") return;
1745
+ state.flushState = "flushing";
1746
+ const sorted = Array.from(state.queue.values()).sort(
1747
+ (a, b) => a.priority - b.priority
1748
+ );
1749
+ state.queue.clear();
1750
+ for (const task of sorted) {
1751
+ try {
1752
+ await task.callback();
1753
+ } catch (err) {
1754
+ console.error(`[IdleScheduler] Task "${task.key}" failed:`, err);
1755
+ }
1756
+ }
1757
+ state.flushState = "done";
1758
+ if (state.queue.size > 0) {
1759
+ const late = Array.from(state.queue.values()).sort(
1760
+ (a, b) => a.priority - b.priority
1761
+ );
1762
+ state.queue.clear();
1763
+ for (const task of late) scheduleImmediate(task.callback);
1764
+ }
1765
+ state.flushListeners.forEach((listener) => {
1766
+ try {
1767
+ listener();
1768
+ } catch (err) {
1769
+ console.error("[IdleScheduler] Flush listener failed:", err);
1770
+ }
1771
+ });
1772
+ state.flushListeners.clear();
1773
+ }
1774
+ function scheduleImmediate(callback) {
1775
+ requestAnimationFrame(() => {
1776
+ const schedulerGlobal = globalThis.scheduler;
1777
+ if (schedulerGlobal && "postTask" in schedulerGlobal) {
1778
+ schedulerGlobal.postTask(() => void callback(), { priority: "background" }).catch(() => {
1779
+ });
1780
+ return;
1781
+ }
1782
+ if ("requestIdleCallback" in window) {
1783
+ requestIdleCallback(() => void callback());
1784
+ return;
1785
+ }
1786
+ const channel = new MessageChannel();
1787
+ channel.port1.onmessage = () => void callback();
1788
+ channel.port2.postMessage(void 0);
1789
+ });
1790
+ }
1791
+
1792
+ // src/idle-scheduler/hooks.ts
1793
+ import { useEffect as useEffect4, useRef as useRef5, useState as useState5, useCallback as useCallback4 } from "react";
1794
+ function useIdleTask(key, priority, callback) {
1795
+ const callbackRef = useRef5(callback);
1796
+ callbackRef.current = callback;
1797
+ useEffect4(() => {
1798
+ const unregister = registerIdleTask(key, priority, () => {
1799
+ return callbackRef.current();
1800
+ });
1801
+ return unregister;
1802
+ }, [key, priority]);
1803
+ }
1804
+ function useIdleReady() {
1805
+ const [ready, setReady] = useState5(false);
1806
+ useEffect4(() => {
1807
+ const unsubscribe = onFlushComplete(() => {
1808
+ setReady(true);
1809
+ });
1810
+ return unsubscribe;
1811
+ }, []);
1812
+ return ready;
1813
+ }
1814
+ function useIdleGate(key, priority, callback) {
1815
+ const [ready, setReady] = useState5(false);
1816
+ const callbackRef = useRef5(callback);
1817
+ callbackRef.current = callback;
1818
+ useEffect4(() => {
1819
+ const unregister = registerIdleTask(key, priority, async () => {
1820
+ await callbackRef.current();
1821
+ setReady(true);
1822
+ });
1823
+ return unregister;
1824
+ }, [key, priority]);
1825
+ return { ready };
1826
+ }
1827
+ function useIdleRegister() {
1828
+ const unregisterRefs = useRef5(/* @__PURE__ */ new Map());
1829
+ useEffect4(() => {
1830
+ const refs = unregisterRefs.current;
1831
+ return () => {
1832
+ refs.forEach((unregister) => unregister());
1833
+ refs.clear();
1834
+ };
1835
+ }, []);
1836
+ return useCallback4(
1837
+ (key, priority, callback) => {
1838
+ unregisterRefs.current.get(key)?.();
1839
+ const unregister = registerIdleTask(key, priority, callback);
1840
+ unregisterRefs.current.set(key, unregister);
1841
+ },
1842
+ []
1843
+ );
1844
+ }
1845
+
1846
+ // src/url-state.ts
1847
+ import {
1848
+ useCallback as useCallback5,
1849
+ useEffect as useEffect5,
1850
+ useMemo,
1851
+ useRef as useRef6,
1852
+ useState as useState6,
1853
+ useSyncExternalStore
1854
+ } from "react";
1855
+ var URL_STATE_EVENT = "matrx:url-state";
1856
+ var ROUTER_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.kit.url-state-router");
1857
+ function getRouter() {
1858
+ return globalThis[ROUTER_SLOT] ?? null;
1859
+ }
1860
+ function setUrlStateRouter(router) {
1861
+ globalThis[ROUTER_SLOT] = router;
1862
+ }
1863
+ function currentLocation() {
1864
+ const custom = getRouter()?.getLocation;
1865
+ if (custom) return custom();
1866
+ return {
1867
+ pathname: window.location.pathname,
1868
+ search: window.location.search,
1869
+ hash: window.location.hash
1870
+ };
1871
+ }
1872
+ function subscribeToUrl(listener) {
1873
+ window.addEventListener("popstate", listener);
1874
+ window.addEventListener(URL_STATE_EVENT, listener);
1875
+ return () => {
1876
+ window.removeEventListener("popstate", listener);
1877
+ window.removeEventListener(URL_STATE_EVENT, listener);
1878
+ };
1879
+ }
1880
+ function getUrlSnapshot() {
1881
+ return currentLocation().search;
1882
+ }
1883
+ function getServerUrlSnapshot() {
1884
+ return "";
1885
+ }
1886
+ function useUrlSearchParams() {
1887
+ const search = useSyncExternalStore(
1888
+ subscribeToUrl,
1889
+ getUrlSnapshot,
1890
+ getServerUrlSnapshot
1891
+ );
1892
+ return useMemo(() => new URLSearchParams(search), [search]);
1893
+ }
1894
+ function commitUrlParams(patch, history) {
1895
+ const location = currentLocation();
1896
+ const params = new URLSearchParams(location.search);
1897
+ for (const [key, value] of Object.entries(patch)) {
1898
+ if (value === null || value === "") params.delete(key);
1899
+ else params.set(key, value);
1900
+ }
1901
+ const query = params.toString();
1902
+ const next = `${location.pathname}${query ? `?${query}` : ""}${location.hash}`;
1903
+ const current = `${location.pathname}${location.search}${location.hash}`;
1904
+ if (next === current) return;
1905
+ const router = getRouter();
1906
+ if (router) {
1907
+ if (history === "replace") router.replace(next);
1908
+ else router.push(next);
1909
+ } else if (history === "replace") {
1910
+ window.history.replaceState(window.history.state, "", next);
1911
+ } else {
1912
+ window.history.pushState(window.history.state, "", next);
1913
+ }
1914
+ window.dispatchEvent(new Event(URL_STATE_EVENT));
1915
+ }
1916
+ function historyModeForParamChange(current, next, textKeys) {
1917
+ const keys = /* @__PURE__ */ new Set([...current.keys(), ...next.keys()]);
1918
+ const changed = [...keys].filter(
1919
+ (key) => current.get(key) !== next.get(key)
1920
+ );
1921
+ if (changed.length === 0) return "replace";
1922
+ return changed.every((key) => textKeys.includes(key)) ? "replace" : "push";
1923
+ }
1924
+ function useUrlState(key, codec) {
1925
+ const searchParams = useUrlSearchParams();
1926
+ const value = codec.parse(searchParams.get(key));
1927
+ const setValue = (next, options) => {
1928
+ commitUrlParams(
1929
+ { [key]: codec.serialize(next) },
1930
+ options?.history ?? "push"
1931
+ );
1932
+ };
1933
+ return [value, setValue];
1934
+ }
1935
+ function stringUrlCodec(defaultValue = "") {
1936
+ return {
1937
+ defaultValue,
1938
+ parse: (raw) => raw ?? defaultValue,
1939
+ serialize: (value) => value === defaultValue ? null : value
1940
+ };
1941
+ }
1942
+ function enumUrlCodec(values, defaultValue) {
1943
+ const allowed = new Set(values);
1944
+ return {
1945
+ defaultValue,
1946
+ parse: (raw) => raw && allowed.has(raw) ? raw : defaultValue,
1947
+ serialize: (value) => value === defaultValue ? null : value
1948
+ };
1949
+ }
1950
+ function booleanUrlCodec(defaultValue = false) {
1951
+ return {
1952
+ defaultValue,
1953
+ parse: (raw) => raw === null ? defaultValue : raw === "1",
1954
+ serialize: (value) => value === defaultValue ? null : value ? "1" : "0"
1955
+ };
1956
+ }
1957
+ function positiveIntegerUrlCodec(defaultValue) {
1958
+ return {
1959
+ defaultValue,
1960
+ parse: (raw) => {
1961
+ const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
1962
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultValue;
1963
+ },
1964
+ serialize: (value) => value === defaultValue || !Number.isFinite(value) || value <= 0 ? null : String(Math.trunc(value))
1965
+ };
1966
+ }
1967
+ function jsonUrlCodec(defaultValue, isValid) {
1968
+ return {
1969
+ defaultValue,
1970
+ parse: (raw) => {
1971
+ if (!raw) return defaultValue;
1972
+ try {
1973
+ const parsed = JSON.parse(raw);
1974
+ return isValid(parsed) ? parsed : defaultValue;
1975
+ } catch {
1976
+ return defaultValue;
1977
+ }
1978
+ },
1979
+ serialize: (value) => JSON.stringify(value) === JSON.stringify(defaultValue) ? null : JSON.stringify(value)
1980
+ };
1981
+ }
1982
+ function useMirroredUrlState(options) {
1983
+ const { parse, toParams, isSame, textKeys = [], resetKey } = options;
1984
+ const params = useUrlSearchParams();
1985
+ const optionsRef = useRef6(options);
1986
+ optionsRef.current = options;
1987
+ const [value, setValue] = useState6(
1988
+ () => parse(
1989
+ typeof window === "undefined" ? new URLSearchParams() : new URLSearchParams(currentLocation().search)
1990
+ )
1991
+ );
1992
+ useEffect5(() => {
1993
+ if (typeof window === "undefined") return;
1994
+ const current = new URLSearchParams(currentLocation().search);
1995
+ const patch = optionsRef.current.toParams(value);
1996
+ const next = new URLSearchParams(current);
1997
+ for (const [key, v] of Object.entries(patch)) {
1998
+ if (v === null || v === "") next.delete(key);
1999
+ else next.set(key, v);
2000
+ }
2001
+ if (next.toString() === current.toString()) return;
2002
+ commitUrlParams(patch, historyModeForParamChange(current, next, textKeys));
2003
+ }, [value]);
2004
+ useEffect5(() => {
2005
+ const fromUrl = optionsRef.current.parse(
2006
+ new URLSearchParams(currentLocation().search)
2007
+ );
2008
+ setValue((prev) => optionsRef.current.isSame(prev, fromUrl) ? prev : fromUrl);
2009
+ }, [params]);
2010
+ const previousResetKey = useRef6(resetKey);
2011
+ useEffect5(() => {
2012
+ const previous = previousResetKey.current;
2013
+ previousResetKey.current = resetKey;
2014
+ if (previous === resetKey) return;
2015
+ if (previous === void 0 || previous === "") return;
2016
+ if (resetKey === void 0 || resetKey === "") return;
2017
+ const cleared = optionsRef.current.parse(new URLSearchParams());
2018
+ setValue(cleared);
2019
+ commitUrlParams(optionsRef.current.toParams(cleared), "replace");
2020
+ }, [resetKey]);
2021
+ const update = useCallback5((updater) => {
2022
+ setValue(
2023
+ (prev) => typeof updater === "function" ? updater(prev) : updater
2024
+ );
2025
+ }, []);
2026
+ return [value, update];
2027
+ }
2028
+
2029
+ // src/idb-store/store-manager.ts
2030
+ import { openDB } from "idb";
2031
+ var DBStoreManager = class {
2032
+ db = null;
2033
+ dbName;
2034
+ version;
2035
+ constructor(dbName, version2) {
2036
+ this.dbName = dbName;
2037
+ this.version = version2;
2038
+ }
2039
+ async initDB() {
2040
+ if (this.db) return;
2041
+ try {
2042
+ this.db = await openDB(this.dbName, this.version, {
2043
+ upgrade: (db) => {
2044
+ this.setupStores(db);
2045
+ }
2046
+ });
2047
+ } catch (error) {
2048
+ console.error("Failed to initialize database:", error);
2049
+ throw error;
2050
+ }
2051
+ }
2052
+ // `add`/`get` carry their own generic (like `query` below) so a subclass
2053
+ // whose `T` covers one IDB object store (e.g. Recording) can still read/write
2054
+ // a different store's record shape (e.g. RecordingChunk) without a cast —
2055
+ // see the audio store in the original host, which manages both `recordings`
2056
+ // and `chunks` stores.
2057
+ async add(storeName, data) {
2058
+ try {
2059
+ if (!this.db) throw new Error("Database not initialized");
2060
+ const id = await this.db.add(storeName, data);
2061
+ return { data: id.toString(), error: null };
2062
+ } catch (error) {
2063
+ return { data: null, error };
2064
+ }
2065
+ }
2066
+ async get(storeName, id) {
2067
+ try {
2068
+ if (!this.db) throw new Error("Database not initialized");
2069
+ const result = await this.db.get(storeName, id);
2070
+ return { data: result, error: null };
2071
+ } catch (error) {
2072
+ return { data: null, error };
2073
+ }
2074
+ }
2075
+ async getAll(storeName) {
2076
+ try {
2077
+ if (!this.db) throw new Error("Database not initialized");
2078
+ const result = await this.db.getAll(storeName);
2079
+ return { data: result, error: null };
2080
+ } catch (error) {
2081
+ return { data: null, error };
2082
+ }
2083
+ }
2084
+ async update(storeName, id, data) {
2085
+ try {
2086
+ if (!this.db) throw new Error("Database not initialized");
2087
+ const existing = await this.db.get(storeName, id);
2088
+ if (!existing) throw new Error("Record not found");
2089
+ const updated = { ...existing, ...data };
2090
+ await this.db.put(storeName, updated);
2091
+ return { data: true, error: null };
2092
+ } catch (error) {
2093
+ return { data: null, error };
2094
+ }
2095
+ }
2096
+ async delete(storeName, id) {
2097
+ try {
2098
+ if (!this.db) throw new Error("Database not initialized");
2099
+ await this.db.delete(storeName, id);
2100
+ return { data: true, error: null };
2101
+ } catch (error) {
2102
+ return { data: null, error };
2103
+ }
2104
+ }
2105
+ async query(storeName, indexName, query) {
2106
+ try {
2107
+ if (!this.db) throw new Error("Database not initialized");
2108
+ const result = await this.db.getAllFromIndex(storeName, indexName, query);
2109
+ return { data: result, error: null };
2110
+ } catch (error) {
2111
+ return { data: null, error };
2112
+ }
2113
+ }
2114
+ };
2115
+
2116
+ // src/idb-store/store-interface.ts
2117
+ var PublicStoreManager = class extends DBStoreManager {
2118
+ constructor(dbName, version2) {
2119
+ super(dbName, version2);
2120
+ }
2121
+ addItem(storeName, data) {
2122
+ return this.add(storeName, data);
2123
+ }
2124
+ getItem(storeName, id) {
2125
+ return this.get(storeName, id);
2126
+ }
2127
+ getAllItems(storeName) {
2128
+ return this.getAll(storeName);
2129
+ }
2130
+ updateItem(storeName, id, data) {
2131
+ return this.update(storeName, id, data);
2132
+ }
2133
+ deleteItem(storeName, id) {
2134
+ return this.delete(storeName, id);
2135
+ }
2136
+ queryItems(storeName, indexName, query) {
2137
+ return this.query(storeName, indexName, query);
2138
+ }
2139
+ };
2140
+
2141
+ // src/idb-store/feature-store.ts
2142
+ var FeatureStore = class extends PublicStoreManager {
2143
+ storeName;
2144
+ constructor(dbName, version2, storeName) {
2145
+ super(dbName, version2);
2146
+ this.storeName = storeName;
2147
+ this.initDB().catch(() => {
2148
+ });
2149
+ }
2150
+ getStoreName() {
2151
+ return this.storeName;
2152
+ }
2153
+ };
2154
+
2155
+ // src/idb-store/singleton.ts
2156
+ var STATE_SLOT4 = /* @__PURE__ */ Symbol.for("ai-matrx.kit.idb-store-state");
2157
+ function getState3() {
2158
+ const holder = globalThis;
2159
+ let state = holder[STATE_SLOT4];
2160
+ if (!state) {
2161
+ state = { instances: /* @__PURE__ */ new Map() };
2162
+ holder[STATE_SLOT4] = state;
2163
+ }
2164
+ return state;
2165
+ }
2166
+ function getIdbStoreSingleton(key, create) {
2167
+ const state = getState3();
2168
+ if (!state.instances.has(key)) {
2169
+ state.instances.set(key, create());
2170
+ }
2171
+ return state.instances.get(key);
2172
+ }
2173
+ function _resetIdbStoreSingletons() {
2174
+ getState3().instances.clear();
2175
+ }
2176
+
2177
+ // src/color-util/lab-delta.ts
2178
+ function round(value, digits = 0) {
2179
+ const factor = Math.pow(10, digits);
2180
+ return Math.round(factor * value) / factor + 0;
2181
+ }
2182
+ function clamp(value, min = 0, max = 1) {
2183
+ return value > max ? max : value > min ? value : min;
2184
+ }
2185
+ function linearize(channel) {
2186
+ const c = channel / 255;
2187
+ return c < 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
2188
+ }
2189
+ var WHITE_X = 96.422;
2190
+ var WHITE_Y = 100;
2191
+ var WHITE_Z = 82.521;
2192
+ var EPSILON = 216 / 24389;
2193
+ var KAPPA = 24389 / 27;
2194
+ function rgbToXyz(rgb) {
2195
+ const r = linearize(rgb.r);
2196
+ const g = linearize(rgb.g);
2197
+ const b = linearize(rgb.b);
2198
+ const d65 = {
2199
+ x: 100 * (0.4124564 * r + 0.3575761 * g + 0.1804375 * b),
2200
+ y: 100 * (0.2126729 * r + 0.7151522 * g + 0.072175 * b),
2201
+ z: 100 * (0.0193339 * r + 0.119192 * g + 0.9503041 * b)
2202
+ };
2203
+ const d50 = {
2204
+ x: 1.0478112 * d65.x + 0.0228866 * d65.y + -0.050127 * d65.z,
2205
+ y: 0.0295424 * d65.x + 0.9904844 * d65.y + -0.0170491 * d65.z,
2206
+ z: -92345e-7 * d65.x + 0.0150436 * d65.y + 0.7521316 * d65.z
2207
+ };
2208
+ return {
2209
+ x: clamp(d50.x, 0, WHITE_X),
2210
+ y: clamp(d50.y, 0, WHITE_Y),
2211
+ z: clamp(d50.z, 0, WHITE_Z)
2212
+ };
2213
+ }
2214
+ function rgbToLab(rgb) {
2215
+ const xyz = rgbToXyz(rgb);
2216
+ let x = xyz.x / WHITE_X;
2217
+ let y = xyz.y / WHITE_Y;
2218
+ let z = xyz.z / WHITE_Z;
2219
+ x = x > EPSILON ? Math.cbrt(x) : (KAPPA * x + 16) / 116;
2220
+ y = y > EPSILON ? Math.cbrt(y) : (KAPPA * y + 16) / 116;
2221
+ z = z > EPSILON ? Math.cbrt(z) : (KAPPA * z + 16) / 116;
2222
+ return {
2223
+ l: round(116 * y - 16, 2),
2224
+ a: round(500 * (x - y), 2),
2225
+ b: round(200 * (y - z), 2)
2226
+ };
2227
+ }
2228
+ function ciede2000(lab1, lab2) {
2229
+ const { l: l1, a: a1, b: b1 } = lab1;
2230
+ const { l: l2, a: a2, b: b2 } = lab2;
2231
+ const toDeg = 180 / Math.PI;
2232
+ const toRad = Math.PI / 180;
2233
+ const c1 = Math.pow(Math.pow(a1, 2) + Math.pow(b1, 2), 0.5);
2234
+ const c2 = Math.pow(Math.pow(a2, 2) + Math.pow(b2, 2), 0.5);
2235
+ const lBar = (l1 + l2) / 2;
2236
+ const cBar7 = Math.pow((c1 + c2) / 2, 7);
2237
+ const g = 0.5 * (1 - Math.pow(cBar7 / (cBar7 + Math.pow(25, 7)), 0.5));
2238
+ const a1p = a1 * (1 + g);
2239
+ const a2p = a2 * (1 + g);
2240
+ const c1p = Math.pow(Math.pow(a1p, 2) + Math.pow(b1, 2), 0.5);
2241
+ const c2p = Math.pow(Math.pow(a2p, 2) + Math.pow(b2, 2), 0.5);
2242
+ const cBarP = (c1p + c2p) / 2;
2243
+ let h1p = a1p === 0 && b1 === 0 ? 0 : Math.atan2(b1, a1p) * toDeg;
2244
+ let h2p = a2p === 0 && b2 === 0 ? 0 : Math.atan2(b2, a2p) * toDeg;
2245
+ if (h1p < 0) h1p += 360;
2246
+ if (h2p < 0) h2p += 360;
2247
+ let dhp = h2p - h1p;
2248
+ const hAbs = Math.abs(h2p - h1p);
2249
+ if (hAbs > 180 && h2p <= h1p) {
2250
+ dhp += 360;
2251
+ } else if (hAbs > 180 && h2p > h1p) {
2252
+ dhp -= 360;
2253
+ }
2254
+ let hBarP = h1p + h2p;
2255
+ if (hAbs <= 180) {
2256
+ hBarP /= 2;
2257
+ } else {
2258
+ hBarP = (h1p + h2p < 360 ? hBarP + 360 : hBarP - 360) / 2;
2259
+ }
2260
+ const t = 1 - 0.17 * Math.cos(toRad * (hBarP - 30)) + 0.24 * Math.cos(2 * toRad * hBarP) + 0.32 * Math.cos(toRad * (3 * hBarP + 6)) - 0.2 * Math.cos(toRad * (4 * hBarP - 63));
2261
+ const dL = l2 - l1;
2262
+ const dCp = c2p - c1p;
2263
+ const dHp = 2 * Math.sin(toRad * dhp / 2) * Math.pow(c1p * c2p, 0.5);
2264
+ const sl = 1 + 0.015 * Math.pow(lBar - 50, 2) / Math.pow(20 + Math.pow(lBar - 50, 2), 0.5);
2265
+ const sc = 1 + 0.045 * cBarP;
2266
+ const sh = 1 + 0.015 * cBarP * t;
2267
+ const dTheta = 30 * Math.exp(-1 * Math.pow((hBarP - 275) / 25, 2));
2268
+ const cBarP7 = Math.pow(cBarP, 7);
2269
+ const rt = -2 * Math.pow(cBarP7 / (cBarP7 + Math.pow(25, 7)), 0.5) * Math.sin(2 * toRad * dTheta);
2270
+ return Math.pow(
2271
+ Math.pow(dL / 1 / sl, 2) + Math.pow(dCp / 1 / sc, 2) + Math.pow(dHp / 1 / sh, 2) + rt * dCp * dHp / (1 * sc * 1 * sh),
2272
+ 0.5
2273
+ );
2274
+ }
2275
+ function rgbDelta(rgb1, rgb2) {
2276
+ return clamp(round(ciede2000(rgbToLab(rgb1), rgbToLab(rgb2)) / 100, 3));
2277
+ }
2278
+ var HEX_RE = /^#?([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
2279
+ var RGB_FN_RE = /^rgba?\(\s*([+-]?[\d.]+)\s*[,\s]\s*([+-]?[\d.]+)\s*[,\s]\s*([+-]?[\d.]+)(?:\s*[,/]\s*[+-]?[\d.]+%?)?\s*\)$/i;
2280
+ function parseHexOrRgb(input) {
2281
+ const text = input.trim();
2282
+ const hexMatch = text.match(HEX_RE);
2283
+ if (hexMatch) {
2284
+ const hex = hexMatch[1];
2285
+ if (hex.length === 3 || hex.length === 4) {
2286
+ return {
2287
+ r: parseInt(hex[0] + hex[0], 16),
2288
+ g: parseInt(hex[1] + hex[1], 16),
2289
+ b: parseInt(hex[2] + hex[2], 16)
2290
+ };
2291
+ }
2292
+ return {
2293
+ r: parseInt(hex.slice(0, 2), 16),
2294
+ g: parseInt(hex.slice(2, 4), 16),
2295
+ b: parseInt(hex.slice(4, 6), 16)
2296
+ };
2297
+ }
2298
+ const rgbMatch = text.match(RGB_FN_RE);
2299
+ if (rgbMatch) {
2300
+ const r = Number(rgbMatch[1]);
2301
+ const g = Number(rgbMatch[2]);
2302
+ const b = Number(rgbMatch[3]);
2303
+ if ([r, g, b].some((v) => Number.isNaN(v))) return null;
2304
+ return { r: clamp(r, 0, 255), g: clamp(g, 0, 255), b: clamp(b, 0, 255) };
2305
+ }
2306
+ return null;
2307
+ }
2308
+
2309
+ // src/color-util/tailwind-colors.ts
2310
+ var tailwindColors = [
2311
+ {
2312
+ name: "Slate",
2313
+ shades: {
2314
+ "50": "#f8fafc",
2315
+ "100": "#f1f5f9",
2316
+ "200": "#e2e8f0",
2317
+ "300": "#cbd5e1",
2318
+ "400": "#94a3b8",
2319
+ "500": "#64748b",
2320
+ "600": "#475569",
2321
+ "700": "#334155",
2322
+ "800": "#1e293b",
2323
+ "900": "#0f172a",
2324
+ "950": "#020617"
2325
+ }
2326
+ },
2327
+ {
2328
+ name: "Gray",
2329
+ shades: {
2330
+ "50": "#f9fafb",
2331
+ "100": "#f3f4f6",
2332
+ "200": "#e5e7eb",
2333
+ "300": "#d1d5db",
2334
+ "400": "#9ca3af",
2335
+ "500": "#6b7280",
2336
+ "600": "#4b5563",
2337
+ "700": "#374151",
2338
+ "800": "#1f2937",
2339
+ "900": "#111827",
2340
+ "950": "#030712"
2341
+ }
2342
+ },
2343
+ {
2344
+ name: "Zinc",
2345
+ shades: {
2346
+ "50": "#fafafa",
2347
+ "100": "#f4f4f5",
2348
+ "200": "#e4e4e7",
2349
+ "300": "#d4d4d8",
2350
+ "400": "#a1a1aa",
2351
+ "500": "#71717a",
2352
+ "600": "#52525b",
2353
+ "700": "#3f3f46",
2354
+ "800": "#27272a",
2355
+ "900": "#18181b",
2356
+ "950": "#09090b"
2357
+ }
2358
+ },
2359
+ {
2360
+ name: "Neutral",
2361
+ shades: {
2362
+ "50": "#fafafa",
2363
+ "100": "#f5f5f5",
2364
+ "200": "#e5e5e5",
2365
+ "300": "#d4d4d4",
2366
+ "400": "#a3a3a3",
2367
+ "500": "#737373",
2368
+ "600": "#525252",
2369
+ "700": "#404040",
2370
+ "800": "#262626",
2371
+ "900": "#171717",
2372
+ "950": "#0a0a0a"
2373
+ }
2374
+ },
2375
+ {
2376
+ name: "Stone",
2377
+ shades: {
2378
+ "50": "#fafaf9",
2379
+ "100": "#f5f5f4",
2380
+ "200": "#e7e5e4",
2381
+ "300": "#d6d3d1",
2382
+ "400": "#a8a29e",
2383
+ "500": "#78716c",
2384
+ "600": "#57534e",
2385
+ "700": "#44403c",
2386
+ "800": "#292524",
2387
+ "900": "#1c1917",
2388
+ "950": "#0c0a09"
2389
+ }
2390
+ },
2391
+ {
2392
+ name: "Red",
2393
+ shades: {
2394
+ "50": "#fef2f2",
2395
+ "100": "#fee2e2",
2396
+ "200": "#fecaca",
2397
+ "300": "#fca5a5",
2398
+ "400": "#f87171",
2399
+ "500": "#ef4444",
2400
+ "600": "#dc2626",
2401
+ "700": "#b91c1c",
2402
+ "800": "#991b1b",
2403
+ "900": "#7f1d1d",
2404
+ "950": "#450a0a"
2405
+ }
2406
+ },
2407
+ {
2408
+ name: "Orange",
2409
+ shades: {
2410
+ "50": "#fff7ed",
2411
+ "100": "#ffedd5",
2412
+ "200": "#fed7aa",
2413
+ "300": "#fdba74",
2414
+ "400": "#fb923c",
2415
+ "500": "#f97316",
2416
+ "600": "#ea580c",
2417
+ "700": "#c2410c",
2418
+ "800": "#9a3412",
2419
+ "900": "#7c2d12",
2420
+ "950": "#431407"
2421
+ }
2422
+ },
2423
+ {
2424
+ name: "Amber",
2425
+ shades: {
2426
+ "50": "#fffbeb",
2427
+ "100": "#fef3c7",
2428
+ "200": "#fde68a",
2429
+ "300": "#fcd34d",
2430
+ "400": "#fbbf24",
2431
+ "500": "#f59e0b",
2432
+ "600": "#d97706",
2433
+ "700": "#b45309",
2434
+ "800": "#92400e",
2435
+ "900": "#78350f",
2436
+ "950": "#451a03"
2437
+ }
2438
+ },
2439
+ {
2440
+ name: "Yellow",
2441
+ shades: {
2442
+ "50": "#fefce8",
2443
+ "100": "#fef9c3",
2444
+ "200": "#fef08a",
2445
+ "300": "#fde047",
2446
+ "400": "#facc15",
2447
+ "500": "#eab308",
2448
+ "600": "#ca8a04",
2449
+ "700": "#a16207",
2450
+ "800": "#854d0e",
2451
+ "900": "#713f12",
2452
+ "950": "#422006"
2453
+ }
2454
+ },
2455
+ {
2456
+ name: "Lime",
2457
+ shades: {
2458
+ "50": "#f7fee7",
2459
+ "100": "#ecfccb",
2460
+ "200": "#d9f99d",
2461
+ "300": "#bef264",
2462
+ "400": "#a3e635",
2463
+ "500": "#84cc16",
2464
+ "600": "#65a30d",
2465
+ "700": "#4d7c0f",
2466
+ "800": "#3f6212",
2467
+ "900": "#365314",
2468
+ "950": "#1a2e05"
2469
+ }
2470
+ },
2471
+ {
2472
+ name: "Green",
2473
+ shades: {
2474
+ "50": "#f0fdf4",
2475
+ "100": "#dcfce7",
2476
+ "200": "#bbf7d0",
2477
+ "300": "#86efac",
2478
+ "400": "#4ade80",
2479
+ "500": "#22c55e",
2480
+ "600": "#16a34a",
2481
+ "700": "#15803d",
2482
+ "800": "#166534",
2483
+ "900": "#14532d",
2484
+ "950": "#052e16"
2485
+ }
2486
+ },
2487
+ {
2488
+ name: "Emerald",
2489
+ shades: {
2490
+ "50": "#ecfdf5",
2491
+ "100": "#d1fae5",
2492
+ "200": "#a7f3d0",
2493
+ "300": "#6ee7b7",
2494
+ "400": "#34d399",
2495
+ "500": "#10b981",
2496
+ "600": "#059669",
2497
+ "700": "#047857",
2498
+ "800": "#065f46",
2499
+ "900": "#064e3b",
2500
+ "950": "#022c22"
2501
+ }
2502
+ },
2503
+ {
2504
+ name: "Teal",
2505
+ shades: {
2506
+ "50": "#f0fdfa",
2507
+ "100": "#ccfbf1",
2508
+ "200": "#99f6e4",
2509
+ "300": "#5eead4",
2510
+ "400": "#2dd4bf",
2511
+ "500": "#14b8a6",
2512
+ "600": "#0d9488",
2513
+ "700": "#0f766e",
2514
+ "800": "#115e59",
2515
+ "900": "#134e4a",
2516
+ "950": "#042f2e"
2517
+ }
2518
+ },
2519
+ {
2520
+ name: "Cyan",
2521
+ shades: {
2522
+ "50": "#ecfeff",
2523
+ "100": "#cffafe",
2524
+ "200": "#a5f3fc",
2525
+ "300": "#67e8f9",
2526
+ "400": "#22d3ee",
2527
+ "500": "#06b6d4",
2528
+ "600": "#0891b2",
2529
+ "700": "#0e7490",
2530
+ "800": "#155e75",
2531
+ "900": "#164e63",
2532
+ "950": "#083344"
2533
+ }
2534
+ },
2535
+ {
2536
+ name: "Sky",
2537
+ shades: {
2538
+ "50": "#f0f9ff",
2539
+ "100": "#e0f2fe",
2540
+ "200": "#bae6fd",
2541
+ "300": "#7dd3fc",
2542
+ "400": "#38bdf8",
2543
+ "500": "#0ea5e9",
2544
+ "600": "#0284c7",
2545
+ "700": "#0369a1",
2546
+ "800": "#075985",
2547
+ "900": "#0c4a6e",
2548
+ "950": "#082f49"
2549
+ }
2550
+ },
2551
+ {
2552
+ name: "Blue",
2553
+ shades: {
2554
+ "50": "#eff6ff",
2555
+ "100": "#dbeafe",
2556
+ "200": "#bfdbfe",
2557
+ "300": "#93c5fd",
2558
+ "400": "#60a5fa",
2559
+ "500": "#3b82f6",
2560
+ "600": "#2563eb",
2561
+ "700": "#1d4ed8",
2562
+ "800": "#1e40af",
2563
+ "900": "#1e3a8a",
2564
+ "950": "#172554"
2565
+ }
2566
+ },
2567
+ {
2568
+ name: "Indigo",
2569
+ shades: {
2570
+ "50": "#eef2ff",
2571
+ "100": "#e0e7ff",
2572
+ "200": "#c7d2fe",
2573
+ "300": "#a5b4fc",
2574
+ "400": "#818cf8",
2575
+ "500": "#6366f1",
2576
+ "600": "#4f46e5",
2577
+ "700": "#4338ca",
2578
+ "800": "#3730a3",
2579
+ "900": "#312e81",
2580
+ "950": "#1e1b4b"
2581
+ }
2582
+ },
2583
+ {
2584
+ name: "Violet",
2585
+ shades: {
2586
+ "50": "#f5f3ff",
2587
+ "100": "#ede9fe",
2588
+ "200": "#ddd6fe",
2589
+ "300": "#c4b5fd",
2590
+ "400": "#a78bfa",
2591
+ "500": "#8b5cf6",
2592
+ "600": "#7c3aed",
2593
+ "700": "#6d28d9",
2594
+ "800": "#5b21b6",
2595
+ "900": "#4c1d95",
2596
+ "950": "#2e1065"
2597
+ }
2598
+ },
2599
+ {
2600
+ name: "Purple",
2601
+ shades: {
2602
+ "50": "#faf5ff",
2603
+ "100": "#f3e8ff",
2604
+ "200": "#e9d5ff",
2605
+ "300": "#d8b4fe",
2606
+ "400": "#c084fc",
2607
+ "500": "#a855f7",
2608
+ "600": "#9333ea",
2609
+ "700": "#7e22ce",
2610
+ "800": "#6b21a8",
2611
+ "900": "#581c87",
2612
+ "950": "#3b0764"
2613
+ }
2614
+ },
2615
+ {
2616
+ name: "Fuchsia",
2617
+ shades: {
2618
+ "50": "#fdf4ff",
2619
+ "100": "#fae8ff",
2620
+ "200": "#f5d0fe",
2621
+ "300": "#f0abfc",
2622
+ "400": "#e879f9",
2623
+ "500": "#d946ef",
2624
+ "600": "#c026d3",
2625
+ "700": "#a21caf",
2626
+ "800": "#86198f",
2627
+ "900": "#701a75",
2628
+ "950": "#4a044e"
2629
+ }
2630
+ },
2631
+ {
2632
+ name: "Pink",
2633
+ shades: {
2634
+ "50": "#fdf2f8",
2635
+ "100": "#fce7f3",
2636
+ "200": "#fbcfe8",
2637
+ "300": "#f9a8d4",
2638
+ "400": "#f472b6",
2639
+ "500": "#ec4899",
2640
+ "600": "#db2777",
2641
+ "700": "#be185d",
2642
+ "800": "#9d174d",
2643
+ "900": "#831843",
2644
+ "950": "#500724"
2645
+ }
2646
+ },
2647
+ {
2648
+ name: "Rose",
2649
+ shades: {
2650
+ "50": "#fff1f2",
2651
+ "100": "#ffe4e6",
2652
+ "200": "#fecdd3",
2653
+ "300": "#fda4af",
2654
+ "400": "#fb7185",
2655
+ "500": "#f43f5e",
2656
+ "600": "#e11d48",
2657
+ "700": "#be123c",
2658
+ "800": "#9f1239",
2659
+ "900": "#881337",
2660
+ "950": "#4c0519"
2661
+ }
2662
+ }
2663
+ ];
2664
+
2665
+ // src/color-util/tailwind.ts
2666
+ function getColorFromTailwind(tailwindColorString) {
2667
+ const [colorName, shade] = tailwindColorString.split("-");
2668
+ const colorGroup = tailwindColors.find((group) => group.name.toLowerCase() === (colorName ?? "").toLowerCase());
2669
+ if (colorGroup) {
2670
+ const shadeEntry = Object.entries(colorGroup.shades).find(([key]) => key === shade);
2671
+ if (shadeEntry) {
2672
+ return shadeEntry[1];
2673
+ }
2674
+ }
2675
+ return "";
2676
+ }
2677
+ function findNearestTailwindColor(inputColor) {
2678
+ let measure;
2679
+ if (typeof inputColor === "string") {
2680
+ const rgb = parseHexOrRgb(inputColor);
2681
+ if (!rgb) return "";
2682
+ measure = (hexValue) => {
2683
+ const target = parseHexOrRgb(hexValue);
2684
+ return target ? rgbDelta(rgb, target) : Infinity;
2685
+ };
2686
+ } else {
2687
+ measure = (hexValue) => inputColor.delta(hexValue);
2688
+ }
2689
+ let nearestColor = "";
2690
+ let smallestDistance = Infinity;
2691
+ tailwindColors.forEach((colorGroup) => {
2692
+ Object.entries(colorGroup.shades).forEach(([shade, hexValue]) => {
2693
+ const distance = measure(hexValue);
2694
+ if (distance < smallestDistance) {
2695
+ smallestDistance = distance;
2696
+ nearestColor = `${colorGroup.name.toLowerCase()}-${shade}`;
2697
+ }
2698
+ });
2699
+ });
2700
+ return nearestColor;
2701
+ }
2702
+ function formatTailwindColor(tailwindColor) {
2703
+ const tailwindColorNames = [
2704
+ "Slate",
2705
+ "Gray",
2706
+ "Zinc",
2707
+ "Neutral",
2708
+ "Stone",
2709
+ "Red",
2710
+ "Orange",
2711
+ "Amber",
2712
+ "Yellow",
2713
+ "Lime",
2714
+ "Green",
2715
+ "Emerald",
2716
+ "Teal",
2717
+ "Cyan",
2718
+ "Blue",
2719
+ "Indigo",
2720
+ "Violet",
2721
+ "Sky",
2722
+ "Purple",
2723
+ "Fuchsia",
2724
+ "Pink",
2725
+ "Rose"
2726
+ ];
2727
+ const splitIndex = tailwindColor.search(/\d/);
2728
+ if (splitIndex === -1) {
2729
+ const colorName = tailwindColorNames.find((color) => tailwindColor.toLowerCase().includes(color.toLowerCase()));
2730
+ if (colorName) {
2731
+ return getColorFromTailwind(`${colorName.toLowerCase()}-500`);
2732
+ }
2733
+ }
2734
+ if (splitIndex > 0) {
2735
+ const colorNamePart = tailwindColor.slice(0, splitIndex);
2736
+ let shadePart = tailwindColor.slice(splitIndex);
2737
+ const matchedColors = tailwindColorNames.filter((color) => colorNamePart.toLowerCase().includes(color.toLowerCase()));
2738
+ matchedColors.sort((a, b) => colorNamePart.toLowerCase().indexOf(a.toLowerCase()) - colorNamePart.toLowerCase().indexOf(b.toLowerCase()));
2739
+ if (matchedColors.length > 0) {
2740
+ const colorName = matchedColors[0].toLowerCase();
2741
+ let shade = Math.round(parseInt(shadePart) / 100) * 100;
2742
+ const formattedColor = getColorFromTailwind(`${colorName}-${shade.toString()}`);
2743
+ if (formattedColor) {
2744
+ return formattedColor;
2745
+ }
2746
+ }
2747
+ }
2748
+ return "";
2749
+ }
2750
+
2751
+ // src/color-util/formats.ts
2752
+ function formatHex(hex) {
2753
+ return hex.startsWith("#") ? hex : `#${hex}`;
2754
+ }
2755
+ function formatRgbString(rgb) {
2756
+ const rgbValues = rgb.replace(/[^\d,]/g, "").split(",");
2757
+ if (rgbValues.length === 3) {
2758
+ return `rgb(${rgbValues[0].trim()}, ${rgbValues[1].trim()}, ${rgbValues[2].trim()})`;
2759
+ }
2760
+ return "";
2761
+ }
2762
+ function formatRgbObject(rgbObject) {
2763
+ const regex = /["']?r["']?\s*[:=]\s*(\d+)\s*[,]\s*["']?g["']?\s*[:=]\s*(\d+)\s*[,]\s*["']?b["']?\s*[:=]\s*(\d+)(?:\s*[,]\s*["']?a["']?\s*[:=]\s*(\d+))?/i;
2764
+ const match = rgbObject.match(regex);
2765
+ if (match) {
2766
+ const r = match[1], g = match[2], b = match[3], a = match[4] || 1;
2767
+ return `{"r":${r},"g":${g},"b":${b},"a":${a}}`;
2768
+ }
2769
+ return "";
2770
+ }
2771
+ function formatHslObject(hslObject) {
2772
+ const regex = /["']?h["']?\s*[:=]\s*(\d+)\s*,\s*["']?s["']?\s*[:=]\s*(\d+)\s*,\s*["']?l["']?\s*[:=]\s*(\d+)(?:\s*,\s*["']?a["']?\s*[:=]\s*(\d+))?/i;
2773
+ const match = hslObject.match(regex);
2774
+ if (match) {
2775
+ const h = match[1], s = match[2], l = match[3], a = match[4] || 1;
2776
+ return `{"h":${h},"s":${s},"l":${l},"a":${a}}`;
2777
+ }
2778
+ return "";
2779
+ }
2780
+ function formatHslString(hslString) {
2781
+ const hslValues = hslString.replace(/[^\d,%]/g, "").split(/\s*,\s*/);
2782
+ if (hslValues.length === 3) {
2783
+ return `hsl(${hslValues[0]}, ${hslValues[1]}%, ${hslValues[2]}%)`;
2784
+ }
2785
+ return "";
2786
+ }
2787
+ function formatHsvString(hsvString) {
2788
+ const hsvValues = hsvString.replace(/[^\d%\s]/g, "").split(/\s+/).map((value) => parseInt(value.replace("%", ""), 10));
2789
+ if (hsvValues.length === 3 && hsvValues.every((val) => !isNaN(val))) {
2790
+ return `hsv(${hsvValues[0]}, ${hsvValues[1]}%, ${hsvValues[2]}%)`;
2791
+ }
2792
+ return "";
2793
+ }
2794
+ function formatRegularCmykString(cmykString) {
2795
+ const cmykValues = cmykString.replace(/[^\d,]/g, "").split(/\s*,\s*/);
2796
+ if (cmykValues.length === 4 && cmykValues.every((val) => !isNaN(Number(val)))) {
2797
+ return `cmyk(${cmykValues[0]}, ${cmykValues[1]}, ${cmykValues[2]}, ${cmykValues[3]})`;
2798
+ }
2799
+ return "";
2800
+ }
2801
+ function formatCmykObject(cmykObject) {
2802
+ const regex = /["']?c["']?\s*[:=]\s*(\d+)\s*,\s*["']?m["']?\s*[:=]\s*(\d+)\s*,\s*["']?y["']?\s*[:=]\s*(\d+)\s*,\s*["']?k["']?\s*[:=]\s*(\d+)(?:\s*,\s*["']?a["']?\s*[:=]\s*(\d+))?/i;
2803
+ const match = cmykObject.match(regex);
2804
+ if (match) {
2805
+ const c = match[1], m = match[2], y = match[3], k = match[4], a = match[5] || 1;
2806
+ return `{"c":${c},"m":${m},"y":${y},"k":${k},"a":${a}}`;
2807
+ }
2808
+ return "";
2809
+ }
2810
+ function formatCmykString(cmykString) {
2811
+ const cmykValues = cmykString.replace(/[^\d%\s]/g, "").split(/\s+/).map((value) => parseInt(value.replace("%", ""), 10));
2812
+ if (cmykValues.length === 4 && cmykValues.every((val) => !isNaN(val))) {
2813
+ return `device-cmyk(${cmykValues[0]}% ${cmykValues[1]}% ${cmykValues[2]}% ${cmykValues[3]}%)`;
2814
+ }
2815
+ return "";
2816
+ }
2817
+ function isDeviceCmyk(cmykString) {
2818
+ const regex = /device-cmyk\(\s*\d+%\s+\d+%\s+\d+%\s+\d+%\s*\)/;
2819
+ return regex.test(cmykString);
2820
+ }
2821
+ function formatHwbString(hwbString) {
2822
+ const hwbValues = hwbString.replace(/[^\d,%\s]/g, "").split(/\s+/);
2823
+ if (hwbValues.length === 3) {
2824
+ return `hwb(${hwbValues[0]}, ${hwbValues[1]}%, ${hwbValues[2]}%)`;
2825
+ }
2826
+ return "";
2827
+ }
2828
+ function formatLabString(labString) {
2829
+ const match = labString.match(/(?:lab\()?\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)?/i);
2830
+ if (match) {
2831
+ const [, l, a, b] = match;
2832
+ return `lab(${l} ${a} ${b})`;
2833
+ }
2834
+ return "";
2835
+ }
2836
+ function formatLchString(lchString) {
2837
+ const match = lchString.match(/(?:lch\()?\s*(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)\s*\)?/i);
2838
+ if (match) {
2839
+ const [, l, c, h] = match;
2840
+ return `lch(${l} ${c} ${h})`;
2841
+ }
2842
+ return "";
2843
+ }
2844
+ function formatHexWith0x(hex) {
2845
+ if (hex.startsWith("0x")) {
2846
+ return `#${hex.slice(2)}`;
2847
+ }
2848
+ return "";
2849
+ }
2850
+
2851
+ // src/color-util/normalize.ts
2852
+ function createColorNormalizer({ isValid }) {
2853
+ return function normalizeColorInput(colorInput) {
2854
+ if (isValid(colorInput)) {
2855
+ return { value: colorInput, type: "standard" };
2856
+ }
2857
+ if (isDeviceCmyk(colorInput)) {
2858
+ return { value: colorInput, type: "device-cmyk" };
2859
+ }
2860
+ const hex = formatHex(colorInput);
2861
+ if (isValid(hex)) {
2862
+ return { value: hex, type: "hex" };
2863
+ }
2864
+ const rgbString = formatRgbString(colorInput);
2865
+ if (isValid(rgbString)) {
2866
+ return { value: rgbString, type: "rgb" };
2867
+ }
2868
+ const rgbObject = formatRgbObject(colorInput);
2869
+ if (rgbObject !== "") {
2870
+ return { value: rgbObject, type: "rgb-object" };
2871
+ }
2872
+ const hslObject = formatHslObject(colorInput);
2873
+ if (hslObject !== "") {
2874
+ return { value: hslObject, type: "hsl-object" };
2875
+ }
2876
+ const hslString = formatHslString(colorInput);
2877
+ if (isValid(hslString)) {
2878
+ return { value: hslString, type: "hsl" };
2879
+ }
2880
+ const hsvString = formatHsvString(colorInput);
2881
+ if (isValid(hsvString)) {
2882
+ return { value: hsvString, type: "hsv" };
2883
+ }
2884
+ const tailwindColor = formatTailwindColor(colorInput);
2885
+ if (tailwindColor !== "") {
2886
+ return { value: tailwindColor, type: "tailwind" };
2887
+ }
2888
+ const regularCmykString = formatRegularCmykString(colorInput);
2889
+ if (regularCmykString !== "") {
2890
+ return { value: regularCmykString, type: "cmyk" };
2891
+ }
2892
+ const cmykObject = formatCmykObject(colorInput);
2893
+ if (cmykObject !== "") {
2894
+ return { value: cmykObject, type: "cmyk-object" };
2895
+ }
2896
+ const cmykString = formatCmykString(colorInput);
2897
+ if (isValid(cmykString)) {
2898
+ return { value: cmykString, type: "cmyk-percentage" };
2899
+ }
2900
+ const hwbString = formatHwbString(colorInput);
2901
+ if (isValid(hwbString)) {
2902
+ return { value: hwbString, type: "hwb" };
2903
+ }
2904
+ const labString = formatLabString(colorInput);
2905
+ if (labString !== "") {
2906
+ return { value: labString, type: "lab" };
2907
+ }
2908
+ const lchString = formatLchString(colorInput);
2909
+ if (lchString !== "") {
2910
+ return { value: lchString, type: "lch" };
2911
+ }
2912
+ const hexWith0x = formatHexWith0x(colorInput);
2913
+ if (isValid(hexWith0x)) {
2914
+ return { value: hexWith0x, type: "hex-0x" };
2915
+ }
2916
+ return null;
2917
+ };
2918
+ }
2919
+
2920
+ // src/qr.ts
2921
+ var MAX_EDGE = 1600;
2922
+ function nativeDetector() {
2923
+ const ctor = globalThis.BarcodeDetector;
2924
+ return typeof ctor === "function" ? ctor : null;
2925
+ }
2926
+ function hasNativeQrDetector() {
2927
+ return nativeDetector() !== null;
2928
+ }
2929
+ async function decodeNative(source) {
2930
+ const Ctor = nativeDetector();
2931
+ if (!Ctor) return null;
2932
+ try {
2933
+ const detector = new Ctor({ formats: ["qr_code"] });
2934
+ const results = await detector.detect(source);
2935
+ const value = results.find((r) => r.rawValue)?.rawValue;
2936
+ return value ? value : null;
2937
+ } catch {
2938
+ return null;
2939
+ }
2940
+ }
2941
+ async function decodeWithJsQr(frame) {
2942
+ const { default: jsQR } = await import("jsqr");
2943
+ const both = jsQR(frame.data, frame.width, frame.height, {
2944
+ inversionAttempts: "attemptBoth"
2945
+ });
2946
+ return both?.data ? both.data : null;
2947
+ }
2948
+ function toImageData(source, width, height) {
2949
+ if (!width || !height) return null;
2950
+ const scale = Math.min(1, MAX_EDGE / Math.max(width, height));
2951
+ const w = Math.max(1, Math.round(width * scale));
2952
+ const h = Math.max(1, Math.round(height * scale));
2953
+ const canvas = document.createElement("canvas");
2954
+ canvas.width = w;
2955
+ canvas.height = h;
2956
+ const ctx = canvas.getContext("2d", { willReadFrequently: true });
2957
+ if (!ctx) return null;
2958
+ ctx.drawImage(source, 0, 0, w, h);
2959
+ return ctx.getImageData(0, 0, w, h);
2960
+ }
2961
+ async function decodeQrFromImageData(frame) {
2962
+ return await decodeWithJsQr(frame) ?? null;
2963
+ }
2964
+ async function decodeQrFromElement(element) {
2965
+ const width = element instanceof HTMLVideoElement ? element.videoWidth : element.width;
2966
+ const height = element instanceof HTMLVideoElement ? element.videoHeight : element.height;
2967
+ if (!width || !height) return null;
2968
+ const native = await decodeNative(element);
2969
+ if (native) return native;
2970
+ const frame = toImageData(element, width, height);
2971
+ return frame ? decodeQrFromImageData(frame) : null;
2972
+ }
2973
+ async function decodeQrFromImageFile(file) {
2974
+ const direct = await decodeNative(file);
2975
+ if (direct) return direct;
2976
+ let bitmap = null;
2977
+ try {
2978
+ bitmap = await createImageBitmap(file);
2979
+ } catch {
2980
+ throw new Error("That file could not be read as an image.");
2981
+ }
2982
+ try {
2983
+ const viaBitmap = await decodeNative(bitmap);
2984
+ if (viaBitmap) return viaBitmap;
2985
+ const frame = toImageData(bitmap, bitmap.width, bitmap.height);
2986
+ return frame ? decodeQrFromImageData(frame) : null;
2987
+ } finally {
2988
+ bitmap.close();
2989
+ }
2990
+ }
2991
+ export {
2992
+ ConfirmDialog,
2993
+ ConfirmDialogHost,
2994
+ DBStoreManager,
2995
+ DEFAULT_JSON_INDENT,
2996
+ DEFAULT_JSON_WIDTH,
2997
+ DEFAULT_WORD_REPLACEMENTS,
2998
+ FeatureStore,
2999
+ PublicStoreManager,
3000
+ _resetIdbStoreSingletons,
3001
+ booleanUrlCodec,
3002
+ captureDrafts,
3003
+ commitUrlParams,
3004
+ computeSearchScore,
3005
+ confirm,
3006
+ createColorNormalizer,
3007
+ createFormatter,
3008
+ createMatrxToast,
3009
+ decodeQrFromElement,
3010
+ decodeQrFromImageData,
3011
+ decodeQrFromImageFile,
3012
+ detectJson,
3013
+ discardDraft,
3014
+ enumUrlCodec,
3015
+ filterAndSortBySearch,
3016
+ findNearestTailwindColor,
3017
+ fireInvalidation,
3018
+ formatCmykObject,
3019
+ formatCmykString,
3020
+ formatHex,
3021
+ formatHexWith0x,
3022
+ formatHslObject,
3023
+ formatHslString,
3024
+ formatHsvString,
3025
+ formatHwbString,
3026
+ formatJsonText,
3027
+ formatLabString,
3028
+ formatLchString,
3029
+ formatLowerCase,
3030
+ formatNormalCase,
3031
+ formatRegularCmykString,
3032
+ formatRgbObject,
3033
+ formatRgbString,
3034
+ formatSentenceCase,
3035
+ formatTailwindColor,
3036
+ formatText,
3037
+ formatTitleCase,
3038
+ formatUpperCase,
3039
+ formatWithoutReplacements,
3040
+ getColorFromTailwind,
3041
+ getDraft,
3042
+ getDraftsVersion,
3043
+ getIdbStoreSingleton,
3044
+ getSchedulerState,
3045
+ guardMarkdownDelimiters,
3046
+ guardMathDelimiters,
3047
+ guardRunawayLinks,
3048
+ hasNativeQrDetector,
3049
+ historyModeForParamChange,
3050
+ idMatchesQuery,
3051
+ isDeviceCmyk,
3052
+ isJsonArray,
3053
+ isJsonObject,
3054
+ isJsonPrimitive,
3055
+ jsonUrlCodec,
3056
+ listDrafts,
3057
+ matchesSearch,
3058
+ onFlushComplete,
3059
+ parseHexOrRgb,
3060
+ positiveIntegerUrlCodec,
3061
+ registerDraftSource,
3062
+ registerIdleTask,
3063
+ registerInvalidationCallback,
3064
+ reportDelimiterViolations,
3065
+ resetScheduler,
3066
+ rgbDelta,
3067
+ rgbToLab,
3068
+ runWithConcurrency,
3069
+ setUrlStateRouter,
3070
+ stringUrlCodec,
3071
+ stringifyJson,
3072
+ subscribeDrafts,
3073
+ tailwindColors,
3074
+ treeContainsComponent,
3075
+ useAutosave,
3076
+ useClipboard,
3077
+ useDurableDraft,
3078
+ useIdleGate,
3079
+ useIdleReady,
3080
+ useIdleRegister,
3081
+ useIdleTask,
3082
+ useLatestRequest,
3083
+ useMirroredUrlState,
3084
+ useUrlSearchParams,
3085
+ useUrlState,
3086
+ whenPageIdle
3087
+ };
3088
+ //# sourceMappingURL=index.js.map