@constela/runtime 0.19.6 → 1.0.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.
- package/dist/index.d.ts +484 -2
- package/dist/index.js +1929 -22
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -436,6 +436,272 @@ var SAFE_DATE_INSTANCE_METHODS = /* @__PURE__ */ new Set([
|
|
|
436
436
|
"getSeconds",
|
|
437
437
|
"getMilliseconds"
|
|
438
438
|
]);
|
|
439
|
+
function getCalendarDays(year, month) {
|
|
440
|
+
if (typeof year !== "number" || typeof month !== "number") {
|
|
441
|
+
return void 0;
|
|
442
|
+
}
|
|
443
|
+
if (month < 0 || month > 11) {
|
|
444
|
+
return void 0;
|
|
445
|
+
}
|
|
446
|
+
const days = [];
|
|
447
|
+
const firstDayOfMonth = new Date(year, month, 1);
|
|
448
|
+
const dayOfWeek = firstDayOfMonth.getDay();
|
|
449
|
+
const lastDayOfMonth = new Date(year, month + 1, 0);
|
|
450
|
+
const daysInMonth = lastDayOfMonth.getDate();
|
|
451
|
+
const prevMonthDays = dayOfWeek;
|
|
452
|
+
const prevMonthLastDay = new Date(year, month, 0);
|
|
453
|
+
const prevMonthDaysCount = prevMonthLastDay.getDate();
|
|
454
|
+
const prevMonth = month === 0 ? 11 : month - 1;
|
|
455
|
+
const prevYear = month === 0 ? year - 1 : year;
|
|
456
|
+
for (let i = prevMonthDays - 1; i >= 0; i--) {
|
|
457
|
+
days.push({
|
|
458
|
+
date: prevMonthDaysCount - i,
|
|
459
|
+
month: prevMonth,
|
|
460
|
+
year: prevYear,
|
|
461
|
+
isCurrentMonth: false
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
for (let i = 1; i <= daysInMonth; i++) {
|
|
465
|
+
days.push({
|
|
466
|
+
date: i,
|
|
467
|
+
month,
|
|
468
|
+
year,
|
|
469
|
+
isCurrentMonth: true
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
const totalDaysSoFar = days.length;
|
|
473
|
+
const totalWeeksNeeded = Math.ceil(totalDaysSoFar / 7);
|
|
474
|
+
const targetDays = totalWeeksNeeded * 7;
|
|
475
|
+
const nextMonth = month === 11 ? 0 : month + 1;
|
|
476
|
+
const nextYear = month === 11 ? year + 1 : year;
|
|
477
|
+
const nextMonthDaysNeeded = targetDays - totalDaysSoFar;
|
|
478
|
+
for (let i = 1; i <= nextMonthDaysNeeded; i++) {
|
|
479
|
+
days.push({
|
|
480
|
+
date: i,
|
|
481
|
+
month: nextMonth,
|
|
482
|
+
year: nextYear,
|
|
483
|
+
isCurrentMonth: false
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
return days;
|
|
487
|
+
}
|
|
488
|
+
function getWeekDays(locale) {
|
|
489
|
+
const effectiveLocale = typeof locale === "string" ? locale : "en-US";
|
|
490
|
+
const baseSunday = new Date(2024, 0, 7);
|
|
491
|
+
const weekDays = [];
|
|
492
|
+
try {
|
|
493
|
+
const formatter = new Intl.DateTimeFormat(effectiveLocale || "en-US", { weekday: "short" });
|
|
494
|
+
for (let i = 0; i < 7; i++) {
|
|
495
|
+
const date = new Date(baseSunday);
|
|
496
|
+
date.setDate(baseSunday.getDate() + i);
|
|
497
|
+
weekDays.push(formatter.format(date));
|
|
498
|
+
}
|
|
499
|
+
return weekDays;
|
|
500
|
+
} catch {
|
|
501
|
+
const fallbackFormatter = new Intl.DateTimeFormat("en-US", { weekday: "short" });
|
|
502
|
+
for (let i = 0; i < 7; i++) {
|
|
503
|
+
const date = new Date(baseSunday);
|
|
504
|
+
date.setDate(baseSunday.getDate() + i);
|
|
505
|
+
weekDays.push(fallbackFormatter.format(date));
|
|
506
|
+
}
|
|
507
|
+
return weekDays;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
function getMonthName(month, locale) {
|
|
511
|
+
if (typeof month !== "number" || month < 0 || month > 11) {
|
|
512
|
+
return void 0;
|
|
513
|
+
}
|
|
514
|
+
const effectiveLocale = typeof locale === "string" ? locale : "en-US";
|
|
515
|
+
try {
|
|
516
|
+
const date = new Date(2024, month, 1);
|
|
517
|
+
const formatter = new Intl.DateTimeFormat(effectiveLocale, { month: "long" });
|
|
518
|
+
return formatter.format(date);
|
|
519
|
+
} catch {
|
|
520
|
+
const date = new Date(2024, month, 1);
|
|
521
|
+
const formatter = new Intl.DateTimeFormat("en-US", { month: "long" });
|
|
522
|
+
return formatter.format(date);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function formatDateISO(year, month, date) {
|
|
526
|
+
if (typeof year !== "number" || typeof month !== "number" || typeof date !== "number") {
|
|
527
|
+
return void 0;
|
|
528
|
+
}
|
|
529
|
+
const y2 = String(year).padStart(4, "0");
|
|
530
|
+
const m2 = String(month + 1).padStart(2, "0");
|
|
531
|
+
const d2 = String(date).padStart(2, "0");
|
|
532
|
+
return `${y2}-${m2}-${d2}`;
|
|
533
|
+
}
|
|
534
|
+
function sortBy(items, key2, direction) {
|
|
535
|
+
if (!Array.isArray(items)) {
|
|
536
|
+
return void 0;
|
|
537
|
+
}
|
|
538
|
+
if (typeof key2 !== "string") {
|
|
539
|
+
return void 0;
|
|
540
|
+
}
|
|
541
|
+
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
542
|
+
if (forbiddenKeys.has(key2)) {
|
|
543
|
+
return void 0;
|
|
544
|
+
}
|
|
545
|
+
const dir = direction === "desc" ? "desc" : "asc";
|
|
546
|
+
const sorted = [...items];
|
|
547
|
+
sorted.sort((a, b2) => {
|
|
548
|
+
const aVal = a != null && typeof a === "object" ? a[key2] : void 0;
|
|
549
|
+
const bVal = b2 != null && typeof b2 === "object" ? b2[key2] : void 0;
|
|
550
|
+
if (aVal == null && bVal == null) return 0;
|
|
551
|
+
if (aVal == null) return 1;
|
|
552
|
+
if (bVal == null) return -1;
|
|
553
|
+
let comparison = 0;
|
|
554
|
+
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
555
|
+
comparison = aVal - bVal;
|
|
556
|
+
} else {
|
|
557
|
+
comparison = String(aVal).localeCompare(String(bVal));
|
|
558
|
+
}
|
|
559
|
+
return dir === "desc" ? -comparison : comparison;
|
|
560
|
+
});
|
|
561
|
+
return sorted;
|
|
562
|
+
}
|
|
563
|
+
function getPaginatedItems(items, page, pageSize) {
|
|
564
|
+
if (!Array.isArray(items)) {
|
|
565
|
+
return void 0;
|
|
566
|
+
}
|
|
567
|
+
if (typeof page !== "number" || page < 0) {
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
if (typeof pageSize !== "number" || pageSize <= 0) {
|
|
571
|
+
return void 0;
|
|
572
|
+
}
|
|
573
|
+
const start = page * pageSize;
|
|
574
|
+
const end = start + pageSize;
|
|
575
|
+
return items.slice(start, end);
|
|
576
|
+
}
|
|
577
|
+
function getTotalPages(itemCount, pageSize) {
|
|
578
|
+
if (typeof itemCount !== "number" || typeof pageSize !== "number") {
|
|
579
|
+
return 0;
|
|
580
|
+
}
|
|
581
|
+
if (itemCount < 0 || pageSize <= 0) {
|
|
582
|
+
return 0;
|
|
583
|
+
}
|
|
584
|
+
if (itemCount === 0) {
|
|
585
|
+
return 0;
|
|
586
|
+
}
|
|
587
|
+
return Math.ceil(itemCount / pageSize);
|
|
588
|
+
}
|
|
589
|
+
function getPageNumbers(currentPage, totalPages, maxVisible) {
|
|
590
|
+
if (typeof currentPage !== "number" || typeof totalPages !== "number" || typeof maxVisible !== "number") {
|
|
591
|
+
return [];
|
|
592
|
+
}
|
|
593
|
+
if (totalPages <= 0) {
|
|
594
|
+
return [];
|
|
595
|
+
}
|
|
596
|
+
if (currentPage < 0 || currentPage >= totalPages) {
|
|
597
|
+
return [];
|
|
598
|
+
}
|
|
599
|
+
if (totalPages <= maxVisible) {
|
|
600
|
+
return Array.from({ length: totalPages }, (_2, i) => i);
|
|
601
|
+
}
|
|
602
|
+
const result = [];
|
|
603
|
+
const firstPage = 0;
|
|
604
|
+
const lastPage = totalPages - 1;
|
|
605
|
+
result.push(firstPage);
|
|
606
|
+
const middleSlots = maxVisible - 2;
|
|
607
|
+
let middleStart = currentPage - Math.floor((middleSlots - 1) / 2);
|
|
608
|
+
let middleEnd = currentPage + Math.ceil((middleSlots - 1) / 2);
|
|
609
|
+
if (middleStart <= 1) {
|
|
610
|
+
middleStart = 1;
|
|
611
|
+
middleEnd = Math.min(middleSlots, lastPage - 1);
|
|
612
|
+
}
|
|
613
|
+
if (middleEnd >= lastPage - 1) {
|
|
614
|
+
middleEnd = lastPage - 1;
|
|
615
|
+
middleStart = Math.max(1, lastPage - middleSlots);
|
|
616
|
+
}
|
|
617
|
+
if (middleStart > 1) {
|
|
618
|
+
result.push(-1);
|
|
619
|
+
}
|
|
620
|
+
for (let i = middleStart; i <= middleEnd; i++) {
|
|
621
|
+
if (i > firstPage && i < lastPage) {
|
|
622
|
+
result.push(i);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
if (middleEnd < lastPage - 1) {
|
|
626
|
+
result.push(-1);
|
|
627
|
+
}
|
|
628
|
+
result.push(lastPage);
|
|
629
|
+
return result;
|
|
630
|
+
}
|
|
631
|
+
function getVisibleRange(scrollTop, itemHeight, containerHeight, overscan) {
|
|
632
|
+
if (typeof scrollTop !== "number" || typeof itemHeight !== "number" || typeof containerHeight !== "number" || typeof overscan !== "number") {
|
|
633
|
+
return void 0;
|
|
634
|
+
}
|
|
635
|
+
if (scrollTop < 0 || itemHeight <= 0 || containerHeight <= 0) {
|
|
636
|
+
return void 0;
|
|
637
|
+
}
|
|
638
|
+
const firstVisible = Math.floor(scrollTop / itemHeight);
|
|
639
|
+
const visibleCount = Math.ceil(containerHeight / itemHeight);
|
|
640
|
+
const start = Math.max(0, firstVisible - overscan);
|
|
641
|
+
const end = firstVisible + visibleCount + overscan - 1;
|
|
642
|
+
return { start, end };
|
|
643
|
+
}
|
|
644
|
+
function getTotalHeight(itemCount, itemHeight) {
|
|
645
|
+
if (typeof itemCount !== "number" || typeof itemHeight !== "number") {
|
|
646
|
+
return 0;
|
|
647
|
+
}
|
|
648
|
+
if (itemCount < 0 || itemHeight <= 0) {
|
|
649
|
+
return 0;
|
|
650
|
+
}
|
|
651
|
+
return itemCount * itemHeight;
|
|
652
|
+
}
|
|
653
|
+
function formatDate(dateStr, format, locale) {
|
|
654
|
+
if (typeof dateStr !== "string" || !dateStr) {
|
|
655
|
+
return void 0;
|
|
656
|
+
}
|
|
657
|
+
const isoDateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
658
|
+
if (!isoDateRegex.test(dateStr)) {
|
|
659
|
+
return void 0;
|
|
660
|
+
}
|
|
661
|
+
const [yearStr, monthStr, dayStr] = dateStr.split("-");
|
|
662
|
+
const year = parseInt(yearStr, 10);
|
|
663
|
+
const month = parseInt(monthStr, 10) - 1;
|
|
664
|
+
const day = parseInt(dayStr, 10);
|
|
665
|
+
const date = new Date(Date.UTC(year, month, day));
|
|
666
|
+
if (isNaN(date.getTime()) || date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) {
|
|
667
|
+
return void 0;
|
|
668
|
+
}
|
|
669
|
+
const effectiveFormat = typeof format === "string" ? format : "medium";
|
|
670
|
+
const effectiveLocale = typeof locale === "string" ? locale : "en-US";
|
|
671
|
+
if (effectiveFormat === "iso") {
|
|
672
|
+
return dateStr;
|
|
673
|
+
}
|
|
674
|
+
try {
|
|
675
|
+
let options;
|
|
676
|
+
switch (effectiveFormat) {
|
|
677
|
+
case "short":
|
|
678
|
+
if (effectiveLocale.startsWith("ja")) {
|
|
679
|
+
options = { year: "numeric", month: "2-digit", day: "2-digit", timeZone: "UTC" };
|
|
680
|
+
} else {
|
|
681
|
+
options = { year: "2-digit", month: "numeric", day: "numeric", timeZone: "UTC" };
|
|
682
|
+
}
|
|
683
|
+
break;
|
|
684
|
+
case "medium":
|
|
685
|
+
options = { year: "numeric", month: "short", day: "numeric", timeZone: "UTC" };
|
|
686
|
+
break;
|
|
687
|
+
case "long":
|
|
688
|
+
options = { year: "numeric", month: "long", day: "numeric", timeZone: "UTC" };
|
|
689
|
+
break;
|
|
690
|
+
default:
|
|
691
|
+
options = { year: "numeric", month: "short", day: "numeric", timeZone: "UTC" };
|
|
692
|
+
}
|
|
693
|
+
const formatter = new Intl.DateTimeFormat(effectiveLocale, options);
|
|
694
|
+
return formatter.format(date);
|
|
695
|
+
} catch {
|
|
696
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
697
|
+
year: "numeric",
|
|
698
|
+
month: "short",
|
|
699
|
+
day: "numeric",
|
|
700
|
+
timeZone: "UTC"
|
|
701
|
+
});
|
|
702
|
+
return formatter.format(date);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
439
705
|
function createLambdaFunction(lambda, ctx) {
|
|
440
706
|
return (item, index) => {
|
|
441
707
|
const lambdaLocals = {
|
|
@@ -677,6 +943,50 @@ function callDateInstanceMethod(target, method) {
|
|
|
677
943
|
return void 0;
|
|
678
944
|
}
|
|
679
945
|
}
|
|
946
|
+
var GLOBAL_FUNCTIONS = {
|
|
947
|
+
// Date helpers
|
|
948
|
+
getCalendarDays: (year, month) => getCalendarDays(year, month),
|
|
949
|
+
getWeekDays: (locale) => getWeekDays(locale),
|
|
950
|
+
getMonthName: (month, locale) => getMonthName(month, locale),
|
|
951
|
+
formatDate: (dateStr, format, locale) => formatDate(dateStr, format, locale),
|
|
952
|
+
formatDateISO: (year, month, date) => formatDateISO(year, month, date),
|
|
953
|
+
// DataTable helpers
|
|
954
|
+
sortBy: (items, key2, direction) => sortBy(items, key2, direction),
|
|
955
|
+
getPaginatedItems: (items, page, pageSize) => getPaginatedItems(items, page, pageSize),
|
|
956
|
+
getTotalPages: (itemCount, pageSize) => getTotalPages(itemCount, pageSize),
|
|
957
|
+
getPageNumbers: (currentPage, totalPages, maxVisible) => getPageNumbers(currentPage, totalPages, maxVisible),
|
|
958
|
+
// Virtual scroll helpers
|
|
959
|
+
getVisibleRange: (scrollTop, itemHeight, containerHeight, overscan) => getVisibleRange(scrollTop, itemHeight, containerHeight, overscan),
|
|
960
|
+
getTotalHeight: (itemCount, itemHeight) => getTotalHeight(itemCount, itemHeight),
|
|
961
|
+
// Chart helpers - Coordinate calculation
|
|
962
|
+
normalizeValue: (value, min, max) => normalizeValue(value, min, max),
|
|
963
|
+
scaleValue: (value, domainMin, domainMax, rangeMin, rangeMax) => scaleValue(value, domainMin, domainMax, rangeMin, rangeMax),
|
|
964
|
+
getBarDimensions: (data, index, width, height, gap, orientation) => getBarDimensions(data, index, width, height, gap, orientation),
|
|
965
|
+
// Chart helpers - Path generation
|
|
966
|
+
getLinePath: (points, curved) => getLinePath(points, curved),
|
|
967
|
+
getAreaPath: (points, baseline, curved) => getAreaPath(points, baseline, curved),
|
|
968
|
+
getArcPath: (cx, cy, radius, startAngle, endAngle) => getArcPath(cx, cy, radius, startAngle, endAngle),
|
|
969
|
+
// Chart helpers - Pie/Donut
|
|
970
|
+
getPieSlices: (data, valueKey) => getPieSlices(data, valueKey),
|
|
971
|
+
getDonutSlices: (data, valueKey, innerRadius) => getDonutSlices(data, valueKey, innerRadius),
|
|
972
|
+
// Chart helpers - Radar
|
|
973
|
+
getRadarPoints: (data, valueKey, cx, cy, radius, maxValue) => getRadarPoints(data, valueKey, cx, cy, radius, maxValue),
|
|
974
|
+
getRadarAxes: (labels, cx, cy, radius) => getRadarAxes(labels, cx, cy, radius),
|
|
975
|
+
// Chart helpers - Utilities
|
|
976
|
+
getChartBounds: (data, valueKey) => getChartBounds(data, valueKey),
|
|
977
|
+
generateTicks: (min, max, count) => generateTicks(min, max, count),
|
|
978
|
+
// Chart helpers - Data aggregation
|
|
979
|
+
binData: (data, valueKey, binCount) => binData(data, valueKey, binCount),
|
|
980
|
+
aggregateData: (data, groupKey, valueKey, aggregation) => aggregateData(data, groupKey, valueKey, aggregation),
|
|
981
|
+
downsample: (data, targetCount, method) => downsample(data, targetCount, method)
|
|
982
|
+
};
|
|
983
|
+
function callGlobalFunction(method, args) {
|
|
984
|
+
const fn = GLOBAL_FUNCTIONS[method];
|
|
985
|
+
if (!fn) {
|
|
986
|
+
return void 0;
|
|
987
|
+
}
|
|
988
|
+
return fn(...args);
|
|
989
|
+
}
|
|
680
990
|
function evaluate(expr, ctx) {
|
|
681
991
|
switch (expr.expr) {
|
|
682
992
|
case "lit":
|
|
@@ -716,7 +1026,21 @@ function evaluate(expr, ctx) {
|
|
|
716
1026
|
String,
|
|
717
1027
|
Number,
|
|
718
1028
|
Boolean,
|
|
719
|
-
console
|
|
1029
|
+
console,
|
|
1030
|
+
// Date helper functions
|
|
1031
|
+
getCalendarDays,
|
|
1032
|
+
getWeekDays,
|
|
1033
|
+
getMonthName,
|
|
1034
|
+
formatDate,
|
|
1035
|
+
formatDateISO,
|
|
1036
|
+
// DataTable helper functions
|
|
1037
|
+
sortBy,
|
|
1038
|
+
getPaginatedItems,
|
|
1039
|
+
getTotalPages,
|
|
1040
|
+
getPageNumbers,
|
|
1041
|
+
// Virtual scroll helper functions
|
|
1042
|
+
getVisibleRange,
|
|
1043
|
+
getTotalHeight
|
|
720
1044
|
};
|
|
721
1045
|
value = safeGlobals[varName];
|
|
722
1046
|
}
|
|
@@ -727,7 +1051,7 @@ function evaluate(expr, ctx) {
|
|
|
727
1051
|
if (typeof value === "function" && pathParts.length > 0) {
|
|
728
1052
|
let parent = ctx.locals[varName];
|
|
729
1053
|
if (parent === void 0) {
|
|
730
|
-
const safeGlobals = { JSON, Math, Date, Object, Array, String, Number, Boolean, console };
|
|
1054
|
+
const safeGlobals = { JSON, Math, Date, Object, Array, String, Number, Boolean, console, getCalendarDays, getWeekDays, getMonthName, formatDate, formatDateISO, sortBy, getPaginatedItems, getTotalPages, getPageNumbers, getVisibleRange, getTotalHeight };
|
|
731
1055
|
parent = safeGlobals[varName];
|
|
732
1056
|
}
|
|
733
1057
|
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
@@ -823,12 +1147,14 @@ function evaluate(expr, ctx) {
|
|
|
823
1147
|
}
|
|
824
1148
|
case "call": {
|
|
825
1149
|
const callExpr = expr;
|
|
826
|
-
const target = evaluate(callExpr.target, ctx);
|
|
827
|
-
if (target == null) return void 0;
|
|
1150
|
+
const target = callExpr.target != null ? evaluate(callExpr.target, ctx) : null;
|
|
828
1151
|
const args = callExpr.args?.map((arg) => {
|
|
829
1152
|
if (arg.expr === "lambda") return arg;
|
|
830
1153
|
return evaluate(arg, ctx);
|
|
831
1154
|
}) ?? [];
|
|
1155
|
+
if (target === null) {
|
|
1156
|
+
return callGlobalFunction(callExpr.method, args);
|
|
1157
|
+
}
|
|
832
1158
|
if (Array.isArray(target)) {
|
|
833
1159
|
return callArrayMethod(target, callExpr.method, args, ctx, callExpr.args);
|
|
834
1160
|
}
|
|
@@ -844,6 +1170,9 @@ function evaluate(expr, ctx) {
|
|
|
844
1170
|
if (target instanceof Date) {
|
|
845
1171
|
return callDateInstanceMethod(target, callExpr.method);
|
|
846
1172
|
}
|
|
1173
|
+
if (typeof target === "function" && callExpr.method === "call") {
|
|
1174
|
+
return target(...args);
|
|
1175
|
+
}
|
|
847
1176
|
return void 0;
|
|
848
1177
|
}
|
|
849
1178
|
case "lambda":
|
|
@@ -972,6 +1301,528 @@ function evaluateBinary(op, left, right, ctx) {
|
|
|
972
1301
|
throw new Error("Unknown binary operator: " + op);
|
|
973
1302
|
}
|
|
974
1303
|
}
|
|
1304
|
+
function normalizeValue(value, min, max) {
|
|
1305
|
+
if (typeof value !== "number" || typeof min !== "number" || typeof max !== "number") {
|
|
1306
|
+
return void 0;
|
|
1307
|
+
}
|
|
1308
|
+
if (max === min) {
|
|
1309
|
+
return 0;
|
|
1310
|
+
}
|
|
1311
|
+
return (value - min) / (max - min);
|
|
1312
|
+
}
|
|
1313
|
+
function scaleValue(value, domainMin, domainMax, rangeMin, rangeMax) {
|
|
1314
|
+
if (typeof value !== "number" || typeof domainMin !== "number" || typeof domainMax !== "number" || typeof rangeMin !== "number" || typeof rangeMax !== "number") {
|
|
1315
|
+
return void 0;
|
|
1316
|
+
}
|
|
1317
|
+
if (domainMax === domainMin) {
|
|
1318
|
+
return rangeMin;
|
|
1319
|
+
}
|
|
1320
|
+
const normalized = (value - domainMin) / (domainMax - domainMin);
|
|
1321
|
+
return rangeMin + normalized * (rangeMax - rangeMin);
|
|
1322
|
+
}
|
|
1323
|
+
function getBarDimensions(data, index, width, height, gap, orientation) {
|
|
1324
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
1325
|
+
return void 0;
|
|
1326
|
+
}
|
|
1327
|
+
if (typeof index !== "number" || index < 0 || index >= data.length) {
|
|
1328
|
+
return void 0;
|
|
1329
|
+
}
|
|
1330
|
+
if (typeof width !== "number" || typeof height !== "number" || typeof gap !== "number") {
|
|
1331
|
+
return void 0;
|
|
1332
|
+
}
|
|
1333
|
+
const isVertical = orientation === "vertical";
|
|
1334
|
+
const barCount = data.length;
|
|
1335
|
+
const values = data.map((d2) => typeof d2 === "number" ? d2 : 0);
|
|
1336
|
+
const maxValue = Math.max(...values);
|
|
1337
|
+
if (isVertical) {
|
|
1338
|
+
const totalGap = gap * (barCount + 1);
|
|
1339
|
+
const barWidth = (width - totalGap) / barCount;
|
|
1340
|
+
const barX = gap + index * (barWidth + gap);
|
|
1341
|
+
const value = values[index] ?? 0;
|
|
1342
|
+
const barHeight = maxValue > 0 ? value / maxValue * height : 0;
|
|
1343
|
+
const barY = height - barHeight;
|
|
1344
|
+
return {
|
|
1345
|
+
x: barX,
|
|
1346
|
+
y: barY,
|
|
1347
|
+
width: barWidth,
|
|
1348
|
+
height: barHeight
|
|
1349
|
+
};
|
|
1350
|
+
} else {
|
|
1351
|
+
const totalGap = gap * barCount;
|
|
1352
|
+
const barHeight = (height - totalGap) / barCount;
|
|
1353
|
+
const barY = gap + index * (barHeight + gap);
|
|
1354
|
+
const value = values[index] ?? 0;
|
|
1355
|
+
const barWidth = maxValue > 0 ? value / maxValue * width : 0;
|
|
1356
|
+
return {
|
|
1357
|
+
x: 0,
|
|
1358
|
+
y: barY,
|
|
1359
|
+
width: barWidth,
|
|
1360
|
+
height: barHeight
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
function getCurvedPath(points) {
|
|
1365
|
+
if (points.length < 2) {
|
|
1366
|
+
return points.length === 1 ? `M${points[0].x},${points[0].y}` : "";
|
|
1367
|
+
}
|
|
1368
|
+
if (points.length === 2) {
|
|
1369
|
+
return `M${points[0].x},${points[0].y} L${points[1].x},${points[1].y}`;
|
|
1370
|
+
}
|
|
1371
|
+
const pathParts = [`M${points[0].x},${points[0].y}`];
|
|
1372
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
1373
|
+
const p0 = points[Math.max(0, i - 1)];
|
|
1374
|
+
const p1 = points[i];
|
|
1375
|
+
const p2 = points[i + 1];
|
|
1376
|
+
const p3 = points[Math.min(points.length - 1, i + 2)];
|
|
1377
|
+
const cp1x = p1.x + (p2.x - p0.x) / 6;
|
|
1378
|
+
const cp1y = p1.y + (p2.y - p0.y) / 6;
|
|
1379
|
+
const cp2x = p2.x - (p3.x - p1.x) / 6;
|
|
1380
|
+
const cp2y = p2.y - (p3.y - p1.y) / 6;
|
|
1381
|
+
pathParts.push(`C${cp1x},${cp1y} ${cp2x},${cp2y} ${p2.x},${p2.y}`);
|
|
1382
|
+
}
|
|
1383
|
+
return pathParts.join(" ");
|
|
1384
|
+
}
|
|
1385
|
+
function getLinePath(points, curved) {
|
|
1386
|
+
if (!Array.isArray(points)) {
|
|
1387
|
+
return void 0;
|
|
1388
|
+
}
|
|
1389
|
+
if (points.length === 0) {
|
|
1390
|
+
return "";
|
|
1391
|
+
}
|
|
1392
|
+
for (const point of points) {
|
|
1393
|
+
if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
|
|
1394
|
+
return void 0;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
const validPoints = points;
|
|
1398
|
+
if (validPoints.length === 1) {
|
|
1399
|
+
return `M${validPoints[0].x},${validPoints[0].y}`;
|
|
1400
|
+
}
|
|
1401
|
+
if (curved !== true) {
|
|
1402
|
+
const pathParts = validPoints.map((point, i) => {
|
|
1403
|
+
const command = i === 0 ? "M" : "L";
|
|
1404
|
+
return `${command}${point.x},${point.y}`;
|
|
1405
|
+
});
|
|
1406
|
+
return pathParts.join(" ");
|
|
1407
|
+
}
|
|
1408
|
+
return getCurvedPath(validPoints);
|
|
1409
|
+
}
|
|
1410
|
+
function getAreaPath(points, baseline, curved) {
|
|
1411
|
+
if (!Array.isArray(points)) {
|
|
1412
|
+
return void 0;
|
|
1413
|
+
}
|
|
1414
|
+
if (typeof baseline !== "number") {
|
|
1415
|
+
return void 0;
|
|
1416
|
+
}
|
|
1417
|
+
if (points.length === 0) {
|
|
1418
|
+
return "";
|
|
1419
|
+
}
|
|
1420
|
+
for (const point of points) {
|
|
1421
|
+
if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
|
|
1422
|
+
return void 0;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
const validPoints = points;
|
|
1426
|
+
let upperPath;
|
|
1427
|
+
if (curved === true && validPoints.length > 2) {
|
|
1428
|
+
upperPath = getCurvedPath(validPoints);
|
|
1429
|
+
} else {
|
|
1430
|
+
upperPath = validPoints.map((p2, i) => (i === 0 ? "M" : "L") + `${p2.x},${p2.y}`).join(" ");
|
|
1431
|
+
}
|
|
1432
|
+
const lastPoint = validPoints[validPoints.length - 1];
|
|
1433
|
+
const firstPoint = validPoints[0];
|
|
1434
|
+
return `${upperPath} L${lastPoint.x},${baseline} L${firstPoint.x},${baseline} Z`;
|
|
1435
|
+
}
|
|
1436
|
+
function getArcPath(cx, cy, radius, startAngle, endAngle) {
|
|
1437
|
+
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof startAngle !== "number" || typeof endAngle !== "number") {
|
|
1438
|
+
return void 0;
|
|
1439
|
+
}
|
|
1440
|
+
if (radius <= 0) {
|
|
1441
|
+
return void 0;
|
|
1442
|
+
}
|
|
1443
|
+
const x1 = cx + radius * Math.cos(startAngle);
|
|
1444
|
+
const y1 = cy + radius * Math.sin(startAngle);
|
|
1445
|
+
const x2 = cx + radius * Math.cos(endAngle);
|
|
1446
|
+
const y2 = cy + radius * Math.sin(endAngle);
|
|
1447
|
+
const angleDiff = endAngle - startAngle;
|
|
1448
|
+
const largeArcFlag = Math.abs(angleDiff) > Math.PI ? 1 : 0;
|
|
1449
|
+
return `M${x1},${y1} A${radius},${radius} 0 ${largeArcFlag},1 ${x2},${y2}`;
|
|
1450
|
+
}
|
|
1451
|
+
function getPieSlices(data, valueKey) {
|
|
1452
|
+
if (!Array.isArray(data)) {
|
|
1453
|
+
return void 0;
|
|
1454
|
+
}
|
|
1455
|
+
if (typeof valueKey !== "string") {
|
|
1456
|
+
return void 0;
|
|
1457
|
+
}
|
|
1458
|
+
if (data.length === 0) {
|
|
1459
|
+
return [];
|
|
1460
|
+
}
|
|
1461
|
+
const values = data.map((item) => {
|
|
1462
|
+
if (typeof item !== "object" || item === null) return 0;
|
|
1463
|
+
const val = item[valueKey];
|
|
1464
|
+
return typeof val === "number" ? val : 0;
|
|
1465
|
+
});
|
|
1466
|
+
const total = values.reduce((sum, val) => sum + val, 0);
|
|
1467
|
+
const slices = [];
|
|
1468
|
+
let currentAngle = 0;
|
|
1469
|
+
for (let i = 0; i < values.length; i++) {
|
|
1470
|
+
const value = values[i];
|
|
1471
|
+
const percentage = total > 0 ? value / total * 100 : 0;
|
|
1472
|
+
const angleSpan = total > 0 ? value / total * Math.PI * 2 : 0;
|
|
1473
|
+
slices.push({
|
|
1474
|
+
startAngle: currentAngle,
|
|
1475
|
+
endAngle: currentAngle + angleSpan,
|
|
1476
|
+
value,
|
|
1477
|
+
percentage
|
|
1478
|
+
});
|
|
1479
|
+
currentAngle += angleSpan;
|
|
1480
|
+
}
|
|
1481
|
+
return slices;
|
|
1482
|
+
}
|
|
1483
|
+
function getDonutSlices(data, valueKey, innerRadius) {
|
|
1484
|
+
if (typeof innerRadius !== "number" || innerRadius < 0) {
|
|
1485
|
+
return void 0;
|
|
1486
|
+
}
|
|
1487
|
+
const pieSlices = getPieSlices(data, valueKey);
|
|
1488
|
+
if (pieSlices === void 0) {
|
|
1489
|
+
return void 0;
|
|
1490
|
+
}
|
|
1491
|
+
const outerRadius = 100;
|
|
1492
|
+
return pieSlices.map((slice) => ({
|
|
1493
|
+
...slice,
|
|
1494
|
+
outerRadius,
|
|
1495
|
+
innerRadius
|
|
1496
|
+
}));
|
|
1497
|
+
}
|
|
1498
|
+
function getRadarPoints(data, valueKey, cx, cy, radius, maxValue) {
|
|
1499
|
+
if (!Array.isArray(data)) {
|
|
1500
|
+
return void 0;
|
|
1501
|
+
}
|
|
1502
|
+
if (typeof valueKey !== "string") {
|
|
1503
|
+
return void 0;
|
|
1504
|
+
}
|
|
1505
|
+
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof maxValue !== "number") {
|
|
1506
|
+
return void 0;
|
|
1507
|
+
}
|
|
1508
|
+
if (maxValue <= 0) {
|
|
1509
|
+
return void 0;
|
|
1510
|
+
}
|
|
1511
|
+
if (data.length === 0) {
|
|
1512
|
+
return [];
|
|
1513
|
+
}
|
|
1514
|
+
const points = [];
|
|
1515
|
+
const angleStep = Math.PI * 2 / data.length;
|
|
1516
|
+
for (let i = 0; i < data.length; i++) {
|
|
1517
|
+
const item = data[i];
|
|
1518
|
+
const value = typeof item === "object" && item !== null ? item[valueKey] : 0;
|
|
1519
|
+
const numValue = typeof value === "number" ? value : 0;
|
|
1520
|
+
const scaledRadius = numValue / maxValue * radius;
|
|
1521
|
+
const angle = -Math.PI / 2 + i * angleStep;
|
|
1522
|
+
const x2 = cx + scaledRadius * Math.cos(angle);
|
|
1523
|
+
const y2 = cy + scaledRadius * Math.sin(angle);
|
|
1524
|
+
points.push({ x: x2, y: y2 });
|
|
1525
|
+
}
|
|
1526
|
+
return points;
|
|
1527
|
+
}
|
|
1528
|
+
function getRadarAxes(labels, cx, cy, radius) {
|
|
1529
|
+
if (!Array.isArray(labels)) {
|
|
1530
|
+
return void 0;
|
|
1531
|
+
}
|
|
1532
|
+
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number") {
|
|
1533
|
+
return void 0;
|
|
1534
|
+
}
|
|
1535
|
+
if (radius < 0) {
|
|
1536
|
+
return void 0;
|
|
1537
|
+
}
|
|
1538
|
+
if (labels.length === 0) {
|
|
1539
|
+
return [];
|
|
1540
|
+
}
|
|
1541
|
+
const axes = [];
|
|
1542
|
+
const angleStep = Math.PI * 2 / labels.length;
|
|
1543
|
+
for (let i = 0; i < labels.length; i++) {
|
|
1544
|
+
const label = String(labels[i]);
|
|
1545
|
+
const angle = -Math.PI / 2 + i * angleStep;
|
|
1546
|
+
const x2 = cx + radius * Math.cos(angle);
|
|
1547
|
+
const y2 = cy + radius * Math.sin(angle);
|
|
1548
|
+
axes.push({
|
|
1549
|
+
x1: cx,
|
|
1550
|
+
y1: cy,
|
|
1551
|
+
x2,
|
|
1552
|
+
y2,
|
|
1553
|
+
label,
|
|
1554
|
+
angle
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
return axes;
|
|
1558
|
+
}
|
|
1559
|
+
function getChartBounds(data, valueKey) {
|
|
1560
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
1561
|
+
return void 0;
|
|
1562
|
+
}
|
|
1563
|
+
if (typeof valueKey !== "string") {
|
|
1564
|
+
return void 0;
|
|
1565
|
+
}
|
|
1566
|
+
const values = [];
|
|
1567
|
+
for (const item of data) {
|
|
1568
|
+
if (typeof item !== "object" || item === null) {
|
|
1569
|
+
continue;
|
|
1570
|
+
}
|
|
1571
|
+
const val = item[valueKey];
|
|
1572
|
+
if (typeof val === "number") {
|
|
1573
|
+
values.push(val);
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
if (values.length === 0) {
|
|
1577
|
+
return void 0;
|
|
1578
|
+
}
|
|
1579
|
+
return {
|
|
1580
|
+
min: Math.min(...values),
|
|
1581
|
+
max: Math.max(...values)
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
function generateTicks(min, max, count) {
|
|
1585
|
+
if (typeof min !== "number" || typeof max !== "number" || typeof count !== "number") {
|
|
1586
|
+
return [];
|
|
1587
|
+
}
|
|
1588
|
+
if (count <= 0) {
|
|
1589
|
+
return [];
|
|
1590
|
+
}
|
|
1591
|
+
if (min === max) {
|
|
1592
|
+
return [min];
|
|
1593
|
+
}
|
|
1594
|
+
if (count === 1) {
|
|
1595
|
+
return [min];
|
|
1596
|
+
}
|
|
1597
|
+
if (count === 2) {
|
|
1598
|
+
return [min, max];
|
|
1599
|
+
}
|
|
1600
|
+
const range = max - min;
|
|
1601
|
+
const rawStep = range / (count - 1);
|
|
1602
|
+
const niceStep = getNiceStep(rawStep);
|
|
1603
|
+
const niceMin = Math.floor(min / niceStep) * niceStep;
|
|
1604
|
+
const ticks = [];
|
|
1605
|
+
for (let i = 0; i < count; i++) {
|
|
1606
|
+
const tick = niceMin + i * niceStep;
|
|
1607
|
+
ticks.push(Math.round(tick * 1e10) / 1e10);
|
|
1608
|
+
}
|
|
1609
|
+
return ticks;
|
|
1610
|
+
}
|
|
1611
|
+
function getNiceStep(rawStep) {
|
|
1612
|
+
const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
|
|
1613
|
+
const normalized = rawStep / magnitude;
|
|
1614
|
+
let niceNormalized;
|
|
1615
|
+
if (normalized <= 1) {
|
|
1616
|
+
niceNormalized = 1;
|
|
1617
|
+
} else if (normalized <= 2) {
|
|
1618
|
+
niceNormalized = 2;
|
|
1619
|
+
} else if (normalized <= 2.5) {
|
|
1620
|
+
niceNormalized = 2.5;
|
|
1621
|
+
} else if (normalized <= 5) {
|
|
1622
|
+
niceNormalized = 5;
|
|
1623
|
+
} else {
|
|
1624
|
+
niceNormalized = 10;
|
|
1625
|
+
}
|
|
1626
|
+
return niceNormalized * magnitude;
|
|
1627
|
+
}
|
|
1628
|
+
function binData(data, valueKey, binCount) {
|
|
1629
|
+
if (!Array.isArray(data)) {
|
|
1630
|
+
return void 0;
|
|
1631
|
+
}
|
|
1632
|
+
if (typeof valueKey !== "string") {
|
|
1633
|
+
return void 0;
|
|
1634
|
+
}
|
|
1635
|
+
if (typeof binCount !== "number" || binCount <= 0) {
|
|
1636
|
+
return [];
|
|
1637
|
+
}
|
|
1638
|
+
if (data.length === 0) {
|
|
1639
|
+
return [];
|
|
1640
|
+
}
|
|
1641
|
+
const values = [];
|
|
1642
|
+
for (const item of data) {
|
|
1643
|
+
if (typeof item !== "object" || item === null) continue;
|
|
1644
|
+
const val = item[valueKey];
|
|
1645
|
+
if (typeof val === "number") {
|
|
1646
|
+
values.push(val);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
if (values.length === 0) {
|
|
1650
|
+
return [];
|
|
1651
|
+
}
|
|
1652
|
+
const minVal = Math.min(...values);
|
|
1653
|
+
const maxVal = Math.max(...values);
|
|
1654
|
+
const binWidth = maxVal === minVal ? 1 : (maxVal - minVal) / binCount;
|
|
1655
|
+
const bins = [];
|
|
1656
|
+
for (let i = 0; i < binCount; i++) {
|
|
1657
|
+
bins.push({
|
|
1658
|
+
binStart: minVal + i * binWidth,
|
|
1659
|
+
binEnd: minVal + (i + 1) * binWidth,
|
|
1660
|
+
count: 0,
|
|
1661
|
+
values: []
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1664
|
+
for (const val of values) {
|
|
1665
|
+
let binIndex = Math.floor((val - minVal) / binWidth);
|
|
1666
|
+
if (binIndex >= binCount) {
|
|
1667
|
+
binIndex = binCount - 1;
|
|
1668
|
+
}
|
|
1669
|
+
bins[binIndex].count++;
|
|
1670
|
+
bins[binIndex].values.push(val);
|
|
1671
|
+
}
|
|
1672
|
+
return bins;
|
|
1673
|
+
}
|
|
1674
|
+
function aggregateData(data, groupKey, valueKey, aggregation) {
|
|
1675
|
+
if (!Array.isArray(data)) {
|
|
1676
|
+
return void 0;
|
|
1677
|
+
}
|
|
1678
|
+
if (typeof groupKey !== "string" || typeof valueKey !== "string") {
|
|
1679
|
+
return void 0;
|
|
1680
|
+
}
|
|
1681
|
+
const validAggregations = /* @__PURE__ */ new Set(["sum", "avg", "min", "max", "count"]);
|
|
1682
|
+
if (typeof aggregation !== "string" || !validAggregations.has(aggregation)) {
|
|
1683
|
+
return void 0;
|
|
1684
|
+
}
|
|
1685
|
+
if (data.length === 0) {
|
|
1686
|
+
return [];
|
|
1687
|
+
}
|
|
1688
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1689
|
+
for (const item of data) {
|
|
1690
|
+
if (typeof item !== "object" || item === null) continue;
|
|
1691
|
+
const obj = item;
|
|
1692
|
+
const group = String(obj[groupKey] ?? "");
|
|
1693
|
+
const val = obj[valueKey];
|
|
1694
|
+
const numVal = typeof val === "number" ? val : 0;
|
|
1695
|
+
if (!groups.has(group)) {
|
|
1696
|
+
groups.set(group, []);
|
|
1697
|
+
}
|
|
1698
|
+
groups.get(group).push(numVal);
|
|
1699
|
+
}
|
|
1700
|
+
const result = [];
|
|
1701
|
+
for (const [group, values] of groups) {
|
|
1702
|
+
let aggregatedValue;
|
|
1703
|
+
switch (aggregation) {
|
|
1704
|
+
case "sum":
|
|
1705
|
+
aggregatedValue = values.reduce((sum, v2) => sum + v2, 0);
|
|
1706
|
+
break;
|
|
1707
|
+
case "avg":
|
|
1708
|
+
aggregatedValue = values.reduce((sum, v2) => sum + v2, 0) / values.length;
|
|
1709
|
+
break;
|
|
1710
|
+
case "min":
|
|
1711
|
+
aggregatedValue = Math.min(...values);
|
|
1712
|
+
break;
|
|
1713
|
+
case "max":
|
|
1714
|
+
aggregatedValue = Math.max(...values);
|
|
1715
|
+
break;
|
|
1716
|
+
case "count":
|
|
1717
|
+
aggregatedValue = values.length;
|
|
1718
|
+
break;
|
|
1719
|
+
default:
|
|
1720
|
+
aggregatedValue = 0;
|
|
1721
|
+
}
|
|
1722
|
+
result.push({ group, value: aggregatedValue });
|
|
1723
|
+
}
|
|
1724
|
+
return result;
|
|
1725
|
+
}
|
|
1726
|
+
function downsample(data, targetCount, method) {
|
|
1727
|
+
if (!Array.isArray(data)) {
|
|
1728
|
+
return void 0;
|
|
1729
|
+
}
|
|
1730
|
+
if (typeof targetCount !== "number" || targetCount <= 0) {
|
|
1731
|
+
return void 0;
|
|
1732
|
+
}
|
|
1733
|
+
const validMethods = /* @__PURE__ */ new Set(["uniform", "lttb"]);
|
|
1734
|
+
if (typeof method !== "string" || !validMethods.has(method)) {
|
|
1735
|
+
return void 0;
|
|
1736
|
+
}
|
|
1737
|
+
if (data.length === 0) {
|
|
1738
|
+
return [];
|
|
1739
|
+
}
|
|
1740
|
+
if (targetCount >= data.length) {
|
|
1741
|
+
return data;
|
|
1742
|
+
}
|
|
1743
|
+
if (method === "uniform") {
|
|
1744
|
+
return downsampleUniform(data, targetCount);
|
|
1745
|
+
} else {
|
|
1746
|
+
return downsampleLTTB(data, targetCount);
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
function downsampleUniform(data, targetCount) {
|
|
1750
|
+
if (targetCount === 1) {
|
|
1751
|
+
return [data[0]];
|
|
1752
|
+
}
|
|
1753
|
+
if (targetCount === 2) {
|
|
1754
|
+
return [data[0], data[data.length - 1]];
|
|
1755
|
+
}
|
|
1756
|
+
const result = [];
|
|
1757
|
+
const step = (data.length - 1) / (targetCount - 1);
|
|
1758
|
+
for (let i = 0; i < targetCount; i++) {
|
|
1759
|
+
const index = Math.round(i * step);
|
|
1760
|
+
result.push(data[index]);
|
|
1761
|
+
}
|
|
1762
|
+
return result;
|
|
1763
|
+
}
|
|
1764
|
+
function downsampleLTTB(data, targetCount) {
|
|
1765
|
+
if (targetCount === 1) {
|
|
1766
|
+
return [data[0]];
|
|
1767
|
+
}
|
|
1768
|
+
if (targetCount === 2) {
|
|
1769
|
+
return [data[0], data[data.length - 1]];
|
|
1770
|
+
}
|
|
1771
|
+
const getXY = (point) => {
|
|
1772
|
+
if (typeof point !== "object" || point === null) {
|
|
1773
|
+
return { x: 0, y: 0 };
|
|
1774
|
+
}
|
|
1775
|
+
const obj = point;
|
|
1776
|
+
const x2 = typeof obj["x"] === "number" ? obj["x"] : typeof obj["timestamp"] === "number" ? obj["timestamp"] : 0;
|
|
1777
|
+
const y2 = typeof obj["y"] === "number" ? obj["y"] : typeof obj["value"] === "number" ? obj["value"] : 0;
|
|
1778
|
+
return { x: x2, y: y2 };
|
|
1779
|
+
};
|
|
1780
|
+
const result = [];
|
|
1781
|
+
result.push(data[0]);
|
|
1782
|
+
const numBuckets = targetCount - 2;
|
|
1783
|
+
const middleData = data.length - 2;
|
|
1784
|
+
const bucketSize = middleData / numBuckets;
|
|
1785
|
+
let prevSelectedIndex = 0;
|
|
1786
|
+
for (let bucketIndex = 0; bucketIndex < numBuckets; bucketIndex++) {
|
|
1787
|
+
const bucketStart = Math.floor(bucketIndex * bucketSize) + 1;
|
|
1788
|
+
const bucketEnd = Math.floor((bucketIndex + 1) * bucketSize) + 1;
|
|
1789
|
+
const nextBucketStart = bucketEnd;
|
|
1790
|
+
const nextBucketEnd = bucketIndex < numBuckets - 1 ? Math.floor((bucketIndex + 2) * bucketSize) + 1 : data.length;
|
|
1791
|
+
let avgX = 0;
|
|
1792
|
+
let avgY = 0;
|
|
1793
|
+
const nextLen = nextBucketEnd - nextBucketStart;
|
|
1794
|
+
if (nextLen > 0) {
|
|
1795
|
+
for (let j2 = nextBucketStart; j2 < nextBucketEnd; j2++) {
|
|
1796
|
+
const point = getXY(data[j2]);
|
|
1797
|
+
avgX += point.x;
|
|
1798
|
+
avgY += point.y;
|
|
1799
|
+
}
|
|
1800
|
+
avgX /= nextLen;
|
|
1801
|
+
avgY /= nextLen;
|
|
1802
|
+
} else {
|
|
1803
|
+
const lastPoint = getXY(data[data.length - 1]);
|
|
1804
|
+
avgX = lastPoint.x;
|
|
1805
|
+
avgY = lastPoint.y;
|
|
1806
|
+
}
|
|
1807
|
+
const pointA = getXY(data[prevSelectedIndex]);
|
|
1808
|
+
let maxArea = -1;
|
|
1809
|
+
let maxAreaIndex = bucketStart;
|
|
1810
|
+
for (let j2 = bucketStart; j2 < bucketEnd; j2++) {
|
|
1811
|
+
const pointB = getXY(data[j2]);
|
|
1812
|
+
const area = Math.abs(
|
|
1813
|
+
pointA.x * (pointB.y - avgY) + pointB.x * (avgY - pointA.y) + avgX * (pointA.y - pointB.y)
|
|
1814
|
+
);
|
|
1815
|
+
if (area > maxArea) {
|
|
1816
|
+
maxArea = area;
|
|
1817
|
+
maxAreaIndex = j2;
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
result.push(data[maxAreaIndex]);
|
|
1821
|
+
prevSelectedIndex = maxAreaIndex;
|
|
1822
|
+
}
|
|
1823
|
+
result.push(data[data.length - 1]);
|
|
1824
|
+
return result;
|
|
1825
|
+
}
|
|
975
1826
|
function evaluateStyle(expr, ctx) {
|
|
976
1827
|
const preset = ctx.styles?.[expr.name];
|
|
977
1828
|
if (!preset) return void 0;
|
|
@@ -1003,6 +1854,83 @@ function evaluateStyle(expr, ctx) {
|
|
|
1003
1854
|
return classes.trim();
|
|
1004
1855
|
}
|
|
1005
1856
|
|
|
1857
|
+
// src/connection/sse.ts
|
|
1858
|
+
function parseMessageData(data) {
|
|
1859
|
+
try {
|
|
1860
|
+
return JSON.parse(data);
|
|
1861
|
+
} catch {
|
|
1862
|
+
return data;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
function createSSEConnection(url, handlers, eventTypes) {
|
|
1866
|
+
const eventSource = new EventSource(url, void 0);
|
|
1867
|
+
eventSource.onopen = () => {
|
|
1868
|
+
handlers.onOpen?.();
|
|
1869
|
+
};
|
|
1870
|
+
eventSource.onerror = (event) => {
|
|
1871
|
+
handlers.onError?.(event);
|
|
1872
|
+
};
|
|
1873
|
+
eventSource.onmessage = (event) => {
|
|
1874
|
+
const data = parseMessageData(event.data);
|
|
1875
|
+
handlers.onMessage?.(data, "message");
|
|
1876
|
+
};
|
|
1877
|
+
if (eventTypes && eventTypes.length > 0) {
|
|
1878
|
+
for (const eventType of eventTypes) {
|
|
1879
|
+
eventSource.addEventListener(eventType, (event) => {
|
|
1880
|
+
const data = parseMessageData(event.data);
|
|
1881
|
+
handlers.onMessage?.(data, eventType);
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
return {
|
|
1886
|
+
close() {
|
|
1887
|
+
eventSource.close();
|
|
1888
|
+
handlers.onClose?.();
|
|
1889
|
+
},
|
|
1890
|
+
getState() {
|
|
1891
|
+
switch (eventSource.readyState) {
|
|
1892
|
+
case EventSource.CONNECTING:
|
|
1893
|
+
return "connecting";
|
|
1894
|
+
case EventSource.OPEN:
|
|
1895
|
+
return "open";
|
|
1896
|
+
case EventSource.CLOSED:
|
|
1897
|
+
return "closed";
|
|
1898
|
+
default:
|
|
1899
|
+
return "closed";
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
function createSSEConnectionManager() {
|
|
1905
|
+
const connections = /* @__PURE__ */ new Map();
|
|
1906
|
+
return {
|
|
1907
|
+
create(name, url, handlers, eventTypes) {
|
|
1908
|
+
const existing = connections.get(name);
|
|
1909
|
+
if (existing) {
|
|
1910
|
+
existing.close();
|
|
1911
|
+
}
|
|
1912
|
+
const conn = createSSEConnection(url, handlers, eventTypes);
|
|
1913
|
+
connections.set(name, conn);
|
|
1914
|
+
},
|
|
1915
|
+
get(name) {
|
|
1916
|
+
return connections.get(name);
|
|
1917
|
+
},
|
|
1918
|
+
close(name) {
|
|
1919
|
+
const conn = connections.get(name);
|
|
1920
|
+
if (conn) {
|
|
1921
|
+
conn.close();
|
|
1922
|
+
connections.delete(name);
|
|
1923
|
+
}
|
|
1924
|
+
},
|
|
1925
|
+
closeAll() {
|
|
1926
|
+
for (const conn of connections.values()) {
|
|
1927
|
+
conn.close();
|
|
1928
|
+
}
|
|
1929
|
+
connections.clear();
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1006
1934
|
// src/action/executor.ts
|
|
1007
1935
|
function createEvalContext(ctx) {
|
|
1008
1936
|
return {
|
|
@@ -1340,6 +2268,27 @@ async function executeStep(step, ctx) {
|
|
|
1340
2268
|
case "generate":
|
|
1341
2269
|
await executeGenerateStep(step, ctx);
|
|
1342
2270
|
break;
|
|
2271
|
+
case "sseConnect":
|
|
2272
|
+
await executeSSEConnectStep(step, ctx);
|
|
2273
|
+
break;
|
|
2274
|
+
case "sseClose":
|
|
2275
|
+
await executeSSECloseStep(step, ctx);
|
|
2276
|
+
break;
|
|
2277
|
+
case "optimistic":
|
|
2278
|
+
await executeOptimisticStep(step, ctx);
|
|
2279
|
+
break;
|
|
2280
|
+
case "confirm":
|
|
2281
|
+
await executeConfirmStep(step, ctx);
|
|
2282
|
+
break;
|
|
2283
|
+
case "reject":
|
|
2284
|
+
await executeRejectStep(step, ctx);
|
|
2285
|
+
break;
|
|
2286
|
+
case "bind":
|
|
2287
|
+
await executeBindStep(step, ctx);
|
|
2288
|
+
break;
|
|
2289
|
+
case "unbind":
|
|
2290
|
+
await executeUnbindStep(step, ctx);
|
|
2291
|
+
break;
|
|
1343
2292
|
}
|
|
1344
2293
|
}
|
|
1345
2294
|
async function executeSetStep(target, value, ctx) {
|
|
@@ -1879,6 +2828,116 @@ async function executeGenerateStep(step, ctx) {
|
|
|
1879
2828
|
}
|
|
1880
2829
|
}
|
|
1881
2830
|
}
|
|
2831
|
+
function isSSEConnectionManager(obj) {
|
|
2832
|
+
return obj !== null && typeof obj === "object" && typeof obj.create === "function" && typeof obj.close === "function";
|
|
2833
|
+
}
|
|
2834
|
+
function ensureSSEManager(ctx) {
|
|
2835
|
+
if (!isSSEConnectionManager(ctx.sse)) {
|
|
2836
|
+
ctx.sse = createSSEConnectionManager();
|
|
2837
|
+
}
|
|
2838
|
+
return ctx.sse;
|
|
2839
|
+
}
|
|
2840
|
+
async function executeSSEConnectStep(step, ctx) {
|
|
2841
|
+
const evalCtx = createEvalContext(ctx);
|
|
2842
|
+
const url = String(evaluate(step.url, evalCtx));
|
|
2843
|
+
const sseManager = ensureSSEManager(ctx);
|
|
2844
|
+
const handlers = {};
|
|
2845
|
+
if (step.onOpen) {
|
|
2846
|
+
handlers.onOpen = async () => {
|
|
2847
|
+
for (const s of step.onOpen) {
|
|
2848
|
+
await executeStep(s, ctx);
|
|
2849
|
+
}
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
if (step.onMessage) {
|
|
2853
|
+
handlers.onMessage = async (data, eventType) => {
|
|
2854
|
+
ctx.locals["event"] = { data, type: eventType };
|
|
2855
|
+
for (const s of step.onMessage) {
|
|
2856
|
+
await executeStep(s, ctx);
|
|
2857
|
+
}
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
if (step.onError) {
|
|
2861
|
+
handlers.onError = async (error) => {
|
|
2862
|
+
ctx.locals["error"] = error;
|
|
2863
|
+
for (const s of step.onError) {
|
|
2864
|
+
await executeStep(s, ctx);
|
|
2865
|
+
}
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
sseManager.create(step.connection, url, handlers, step.eventTypes);
|
|
2869
|
+
}
|
|
2870
|
+
async function executeSSECloseStep(step, ctx) {
|
|
2871
|
+
if (isSSEConnectionManager(ctx.sse)) {
|
|
2872
|
+
ctx.sse.close(step.connection);
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
async function executeOptimisticStep(step, ctx) {
|
|
2876
|
+
if (!ctx.optimistic) {
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2879
|
+
const evalCtx = createEvalContext(ctx);
|
|
2880
|
+
const value = evaluate(step.value, evalCtx);
|
|
2881
|
+
const path = step.path ? evaluate(step.path, evalCtx) : void 0;
|
|
2882
|
+
if (step.timeout) {
|
|
2883
|
+
ctx.optimistic.setAutoRollbackTimeout(step.timeout);
|
|
2884
|
+
}
|
|
2885
|
+
const updateId = ctx.optimistic.apply(
|
|
2886
|
+
step.target,
|
|
2887
|
+
path,
|
|
2888
|
+
value,
|
|
2889
|
+
(target) => ctx.state.get(target),
|
|
2890
|
+
(target, val) => ctx.state.set(target, val)
|
|
2891
|
+
);
|
|
2892
|
+
if (step.result) {
|
|
2893
|
+
ctx.locals[step.result] = updateId;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
async function executeConfirmStep(step, ctx) {
|
|
2897
|
+
const evalCtx = createEvalContext(ctx);
|
|
2898
|
+
const id = evaluate(step.id, evalCtx);
|
|
2899
|
+
ctx.optimistic?.confirm(String(id));
|
|
2900
|
+
}
|
|
2901
|
+
async function executeRejectStep(step, ctx) {
|
|
2902
|
+
const evalCtx = createEvalContext(ctx);
|
|
2903
|
+
const id = evaluate(step.id, evalCtx);
|
|
2904
|
+
ctx.optimistic?.reject(
|
|
2905
|
+
String(id),
|
|
2906
|
+
(target) => ctx.state.get(target),
|
|
2907
|
+
(target, val) => ctx.state.set(target, val)
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
2910
|
+
async function executeBindStep(step, ctx) {
|
|
2911
|
+
if (!ctx.binding) {
|
|
2912
|
+
return;
|
|
2913
|
+
}
|
|
2914
|
+
const evalCtx = createEvalContext(ctx);
|
|
2915
|
+
const config = {
|
|
2916
|
+
connection: step.connection,
|
|
2917
|
+
target: step.target
|
|
2918
|
+
};
|
|
2919
|
+
if (step.eventType !== void 0) {
|
|
2920
|
+
config.eventType = step.eventType;
|
|
2921
|
+
}
|
|
2922
|
+
if (step.path) {
|
|
2923
|
+
config.path = evaluate(step.path, evalCtx);
|
|
2924
|
+
}
|
|
2925
|
+
if (step.patch !== void 0) {
|
|
2926
|
+
config.patch = step.patch;
|
|
2927
|
+
}
|
|
2928
|
+
ctx.binding.bind(config, (target, value, pathOrOptions) => {
|
|
2929
|
+
if (pathOrOptions && typeof pathOrOptions === "object" && "patch" in pathOrOptions) {
|
|
2930
|
+
ctx.state.set(target, value);
|
|
2931
|
+
} else if (Array.isArray(pathOrOptions)) {
|
|
2932
|
+
ctx.state.setPath(target, pathOrOptions, value);
|
|
2933
|
+
} else {
|
|
2934
|
+
ctx.state.set(target, value);
|
|
2935
|
+
}
|
|
2936
|
+
});
|
|
2937
|
+
}
|
|
2938
|
+
async function executeUnbindStep(step, ctx) {
|
|
2939
|
+
ctx.binding?.unbindByConnection(step.connection);
|
|
2940
|
+
}
|
|
1882
2941
|
|
|
1883
2942
|
// ../../node_modules/.pnpm/marked@17.0.1/node_modules/marked/lib/marked.esm.js
|
|
1884
2943
|
function L() {
|
|
@@ -14623,27 +15682,163 @@ function createApp(program, mount) {
|
|
|
14623
15682
|
void executeAction(onUnmountAction, actionCtx);
|
|
14624
15683
|
}
|
|
14625
15684
|
}
|
|
14626
|
-
for (const cleanup of cleanups) {
|
|
14627
|
-
cleanup();
|
|
14628
|
-
}
|
|
14629
|
-
while (mount.firstChild) {
|
|
14630
|
-
mount.removeChild(mount.firstChild);
|
|
14631
|
-
}
|
|
14632
|
-
},
|
|
14633
|
-
setState(name, value) {
|
|
14634
|
-
if (destroyed) return;
|
|
14635
|
-
state.set(name, value);
|
|
14636
|
-
},
|
|
14637
|
-
getState(name) {
|
|
14638
|
-
return state.get(name);
|
|
15685
|
+
for (const cleanup of cleanups) {
|
|
15686
|
+
cleanup();
|
|
15687
|
+
}
|
|
15688
|
+
while (mount.firstChild) {
|
|
15689
|
+
mount.removeChild(mount.firstChild);
|
|
15690
|
+
}
|
|
15691
|
+
},
|
|
15692
|
+
setState(name, value) {
|
|
15693
|
+
if (destroyed) return;
|
|
15694
|
+
state.set(name, value);
|
|
15695
|
+
},
|
|
15696
|
+
getState(name) {
|
|
15697
|
+
return state.get(name);
|
|
15698
|
+
},
|
|
15699
|
+
subscribe(name, fn) {
|
|
15700
|
+
if (destroyed) return () => {
|
|
15701
|
+
};
|
|
15702
|
+
return state.subscribe(name, fn);
|
|
15703
|
+
}
|
|
15704
|
+
};
|
|
15705
|
+
}
|
|
15706
|
+
|
|
15707
|
+
// src/hydrate-island.ts
|
|
15708
|
+
function hydrateIsland(options) {
|
|
15709
|
+
const { strategy } = options;
|
|
15710
|
+
switch (strategy) {
|
|
15711
|
+
case "load":
|
|
15712
|
+
hydrateImmediately(options);
|
|
15713
|
+
return () => {
|
|
15714
|
+
};
|
|
15715
|
+
case "idle":
|
|
15716
|
+
return hydrateOnIdle(options, options.strategyOptions?.timeout);
|
|
15717
|
+
case "visible":
|
|
15718
|
+
return hydrateOnVisible(options, options.strategyOptions);
|
|
15719
|
+
case "interaction":
|
|
15720
|
+
return hydrateOnInteraction(options);
|
|
15721
|
+
case "media":
|
|
15722
|
+
return hydrateOnMedia(options, options.strategyOptions?.media);
|
|
15723
|
+
case "never":
|
|
15724
|
+
return () => {
|
|
15725
|
+
};
|
|
15726
|
+
// SSR only, no hydration
|
|
15727
|
+
default:
|
|
15728
|
+
hydrateImmediately(options);
|
|
15729
|
+
return () => {
|
|
15730
|
+
};
|
|
15731
|
+
}
|
|
15732
|
+
}
|
|
15733
|
+
function hydrateImmediately(options) {
|
|
15734
|
+
options.element.dataset["islandHydrated"] = "true";
|
|
15735
|
+
}
|
|
15736
|
+
function hydrateOnIdle(options, timeout) {
|
|
15737
|
+
let cancelled = false;
|
|
15738
|
+
let handle2;
|
|
15739
|
+
if ("requestIdleCallback" in window) {
|
|
15740
|
+
handle2 = window.requestIdleCallback(
|
|
15741
|
+
() => {
|
|
15742
|
+
if (!cancelled) hydrateImmediately(options);
|
|
15743
|
+
},
|
|
15744
|
+
timeout ? { timeout } : void 0
|
|
15745
|
+
);
|
|
15746
|
+
return () => {
|
|
15747
|
+
cancelled = true;
|
|
15748
|
+
window.cancelIdleCallback(handle2);
|
|
15749
|
+
};
|
|
15750
|
+
} else {
|
|
15751
|
+
handle2 = setTimeout(() => {
|
|
15752
|
+
if (!cancelled) hydrateImmediately(options);
|
|
15753
|
+
}, timeout ?? 200);
|
|
15754
|
+
return () => {
|
|
15755
|
+
cancelled = true;
|
|
15756
|
+
clearTimeout(handle2);
|
|
15757
|
+
};
|
|
15758
|
+
}
|
|
15759
|
+
}
|
|
15760
|
+
function hydrateOnVisible(options, strategyOptions) {
|
|
15761
|
+
const observer = new IntersectionObserver(
|
|
15762
|
+
(entries2) => {
|
|
15763
|
+
for (const entry of entries2) {
|
|
15764
|
+
if (entry.isIntersecting) {
|
|
15765
|
+
hydrateImmediately(options);
|
|
15766
|
+
observer.disconnect();
|
|
15767
|
+
break;
|
|
15768
|
+
}
|
|
15769
|
+
}
|
|
14639
15770
|
},
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
15771
|
+
{
|
|
15772
|
+
threshold: strategyOptions?.threshold ?? 0,
|
|
15773
|
+
rootMargin: strategyOptions?.rootMargin ?? "0px"
|
|
15774
|
+
}
|
|
15775
|
+
);
|
|
15776
|
+
observer.observe(options.element);
|
|
15777
|
+
return () => observer.disconnect();
|
|
15778
|
+
}
|
|
15779
|
+
function hydrateOnInteraction(options) {
|
|
15780
|
+
const events = ["click", "focusin", "mouseover"];
|
|
15781
|
+
let hydrated = false;
|
|
15782
|
+
const handler = () => {
|
|
15783
|
+
if (hydrated) return;
|
|
15784
|
+
hydrated = true;
|
|
15785
|
+
hydrateImmediately(options);
|
|
15786
|
+
for (const event of events) {
|
|
15787
|
+
options.element.removeEventListener(event, handler);
|
|
15788
|
+
}
|
|
15789
|
+
};
|
|
15790
|
+
for (const event of events) {
|
|
15791
|
+
options.element.addEventListener(event, handler, { passive: true });
|
|
15792
|
+
}
|
|
15793
|
+
return () => {
|
|
15794
|
+
for (const event of events) {
|
|
15795
|
+
options.element.removeEventListener(event, handler);
|
|
14644
15796
|
}
|
|
14645
15797
|
};
|
|
14646
15798
|
}
|
|
15799
|
+
function hydrateOnMedia(options, media) {
|
|
15800
|
+
if (!media) {
|
|
15801
|
+
hydrateImmediately(options);
|
|
15802
|
+
return () => {
|
|
15803
|
+
};
|
|
15804
|
+
}
|
|
15805
|
+
const mql = window.matchMedia(media);
|
|
15806
|
+
if (mql.matches) {
|
|
15807
|
+
hydrateImmediately(options);
|
|
15808
|
+
return () => {
|
|
15809
|
+
};
|
|
15810
|
+
}
|
|
15811
|
+
const handler = (e) => {
|
|
15812
|
+
if (e.matches) {
|
|
15813
|
+
hydrateImmediately(options);
|
|
15814
|
+
mql.removeEventListener("change", handler);
|
|
15815
|
+
}
|
|
15816
|
+
};
|
|
15817
|
+
mql.addEventListener("change", handler);
|
|
15818
|
+
return () => mql.removeEventListener("change", handler);
|
|
15819
|
+
}
|
|
15820
|
+
function detectIslandsInDOM(container) {
|
|
15821
|
+
const islands = [];
|
|
15822
|
+
const elements = container.querySelectorAll("[data-island-id]");
|
|
15823
|
+
for (const element2 of elements) {
|
|
15824
|
+
const id = element2.getAttribute("data-island-id");
|
|
15825
|
+
const strategy = element2.getAttribute(
|
|
15826
|
+
"data-island-strategy"
|
|
15827
|
+
);
|
|
15828
|
+
const optionsJson = element2.getAttribute("data-island-options");
|
|
15829
|
+
const stateJson = element2.getAttribute("data-island-state");
|
|
15830
|
+
if (id && strategy) {
|
|
15831
|
+
islands.push({
|
|
15832
|
+
element: element2,
|
|
15833
|
+
id,
|
|
15834
|
+
strategy,
|
|
15835
|
+
strategyOptions: optionsJson ? JSON.parse(optionsJson) : void 0,
|
|
15836
|
+
state: stateJson ? JSON.parse(stateJson) : void 0
|
|
15837
|
+
});
|
|
15838
|
+
}
|
|
15839
|
+
}
|
|
15840
|
+
return islands;
|
|
15841
|
+
}
|
|
14647
15842
|
|
|
14648
15843
|
// src/hydrate.ts
|
|
14649
15844
|
function createReactiveLocals2(baseLocals, itemSignal, indexSignal, itemName, indexName) {
|
|
@@ -15687,6 +16882,79 @@ function initCopyButtons(container) {
|
|
|
15687
16882
|
});
|
|
15688
16883
|
});
|
|
15689
16884
|
}
|
|
16885
|
+
function hydrateAppWithIslands(program, options) {
|
|
16886
|
+
const container = options?.container ?? document.getElementById("app") ?? document.body;
|
|
16887
|
+
const cleanupFns = [];
|
|
16888
|
+
const islands = detectIslandsInDOM(container);
|
|
16889
|
+
for (const island of islands) {
|
|
16890
|
+
const cleanup = hydrateIsland({
|
|
16891
|
+
...island,
|
|
16892
|
+
program
|
|
16893
|
+
});
|
|
16894
|
+
cleanupFns.push(cleanup);
|
|
16895
|
+
}
|
|
16896
|
+
return () => {
|
|
16897
|
+
for (const cleanup of cleanupFns) {
|
|
16898
|
+
cleanup();
|
|
16899
|
+
}
|
|
16900
|
+
};
|
|
16901
|
+
}
|
|
16902
|
+
|
|
16903
|
+
// src/island-loader.ts
|
|
16904
|
+
function createIslandLoader(options = {}) {
|
|
16905
|
+
const basePath = options.basePath ?? "/_constela/islands/";
|
|
16906
|
+
const cache = /* @__PURE__ */ new Map();
|
|
16907
|
+
const pending = /* @__PURE__ */ new Map();
|
|
16908
|
+
async function load(id) {
|
|
16909
|
+
const cached = cache.get(id);
|
|
16910
|
+
if (cached) {
|
|
16911
|
+
return cached;
|
|
16912
|
+
}
|
|
16913
|
+
const pendingPromise = pending.get(id);
|
|
16914
|
+
if (pendingPromise) {
|
|
16915
|
+
return pendingPromise;
|
|
16916
|
+
}
|
|
16917
|
+
const loadPromise = (async () => {
|
|
16918
|
+
try {
|
|
16919
|
+
const module = await loadModule(id);
|
|
16920
|
+
cache.set(id, module);
|
|
16921
|
+
return module;
|
|
16922
|
+
} finally {
|
|
16923
|
+
pending.delete(id);
|
|
16924
|
+
}
|
|
16925
|
+
})();
|
|
16926
|
+
pending.set(id, loadPromise);
|
|
16927
|
+
return loadPromise;
|
|
16928
|
+
}
|
|
16929
|
+
async function loadModule(id) {
|
|
16930
|
+
const sanitizedId = id.replace(/[\/\\:*?"<>|]/g, "_");
|
|
16931
|
+
const modulePath = `${basePath}${sanitizedId}.js`;
|
|
16932
|
+
try {
|
|
16933
|
+
const module = await import(
|
|
16934
|
+
/* @vite-ignore */
|
|
16935
|
+
modulePath
|
|
16936
|
+
);
|
|
16937
|
+
return module;
|
|
16938
|
+
} catch (error) {
|
|
16939
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16940
|
+
throw new Error(`Failed to load island "${id}" from ${modulePath}: ${message}`);
|
|
16941
|
+
}
|
|
16942
|
+
}
|
|
16943
|
+
function preload(id) {
|
|
16944
|
+
if (cache.has(id)) {
|
|
16945
|
+
return;
|
|
16946
|
+
}
|
|
16947
|
+
if (pending.has(id)) {
|
|
16948
|
+
return;
|
|
16949
|
+
}
|
|
16950
|
+
load(id).catch(() => {
|
|
16951
|
+
});
|
|
16952
|
+
}
|
|
16953
|
+
return {
|
|
16954
|
+
load,
|
|
16955
|
+
preload
|
|
16956
|
+
};
|
|
16957
|
+
}
|
|
15690
16958
|
|
|
15691
16959
|
// src/connection/websocket.ts
|
|
15692
16960
|
function createWebSocketConnection(url, handlers) {
|
|
@@ -15778,6 +17046,380 @@ function createConnectionManager() {
|
|
|
15778
17046
|
};
|
|
15779
17047
|
}
|
|
15780
17048
|
|
|
17049
|
+
// src/connection/reconnect.ts
|
|
17050
|
+
function calculateDelay(strategy, attempt, baseDelay, maxDelay) {
|
|
17051
|
+
let delay;
|
|
17052
|
+
if (strategy === "exponential") {
|
|
17053
|
+
delay = baseDelay * Math.pow(2, attempt);
|
|
17054
|
+
} else if (strategy === "linear") {
|
|
17055
|
+
delay = baseDelay * (attempt + 1);
|
|
17056
|
+
} else {
|
|
17057
|
+
return 0;
|
|
17058
|
+
}
|
|
17059
|
+
return Math.min(delay, maxDelay);
|
|
17060
|
+
}
|
|
17061
|
+
function createReconnectionManager() {
|
|
17062
|
+
const managedConnections = /* @__PURE__ */ new Map();
|
|
17063
|
+
function shouldReconnect(policy) {
|
|
17064
|
+
return policy.enabled && policy.strategy !== "none";
|
|
17065
|
+
}
|
|
17066
|
+
function clearTimer(managed) {
|
|
17067
|
+
if (managed.timerId !== null) {
|
|
17068
|
+
clearTimeout(managed.timerId);
|
|
17069
|
+
managed.timerId = null;
|
|
17070
|
+
}
|
|
17071
|
+
}
|
|
17072
|
+
function scheduleReconnect(managed) {
|
|
17073
|
+
if (managed.isReconnecting) {
|
|
17074
|
+
return;
|
|
17075
|
+
}
|
|
17076
|
+
const { policy, retryCount } = managed;
|
|
17077
|
+
if (retryCount >= policy.maxRetries) {
|
|
17078
|
+
managed.isReconnecting = false;
|
|
17079
|
+
if (!managed.maxRetriesReached) {
|
|
17080
|
+
managed.maxRetriesReached = true;
|
|
17081
|
+
try {
|
|
17082
|
+
managed.onMaxRetriesReached?.();
|
|
17083
|
+
} catch {
|
|
17084
|
+
}
|
|
17085
|
+
}
|
|
17086
|
+
return;
|
|
17087
|
+
}
|
|
17088
|
+
managed.isReconnecting = true;
|
|
17089
|
+
const delay = calculateDelay(
|
|
17090
|
+
policy.strategy,
|
|
17091
|
+
retryCount,
|
|
17092
|
+
policy.baseDelay,
|
|
17093
|
+
policy.maxDelay
|
|
17094
|
+
);
|
|
17095
|
+
managed.timerId = setTimeout(() => {
|
|
17096
|
+
managed.timerId = null;
|
|
17097
|
+
managed.isReconnecting = false;
|
|
17098
|
+
attemptReconnect(managed);
|
|
17099
|
+
}, delay);
|
|
17100
|
+
}
|
|
17101
|
+
function attemptReconnect(managed) {
|
|
17102
|
+
managedConnections.delete(managed.connection);
|
|
17103
|
+
let newConnection;
|
|
17104
|
+
try {
|
|
17105
|
+
newConnection = managed.reconnectFn();
|
|
17106
|
+
} catch {
|
|
17107
|
+
managed.retryCount++;
|
|
17108
|
+
managedConnections.set(managed.connection, managed);
|
|
17109
|
+
scheduleReconnect(managed);
|
|
17110
|
+
return;
|
|
17111
|
+
}
|
|
17112
|
+
managed.retryCount++;
|
|
17113
|
+
managed.connection = newConnection;
|
|
17114
|
+
managedConnections.set(newConnection, managed);
|
|
17115
|
+
if (shouldReconnect(managed.policy)) {
|
|
17116
|
+
monitorConnection(newConnection, () => {
|
|
17117
|
+
handleConnectionError(managed);
|
|
17118
|
+
});
|
|
17119
|
+
}
|
|
17120
|
+
if (newConnection.getState() === "open") {
|
|
17121
|
+
managed.retryCount = 0;
|
|
17122
|
+
managed.maxRetriesReached = false;
|
|
17123
|
+
try {
|
|
17124
|
+
managed.onReconnect?.();
|
|
17125
|
+
} catch {
|
|
17126
|
+
}
|
|
17127
|
+
} else {
|
|
17128
|
+
scheduleReconnect(managed);
|
|
17129
|
+
}
|
|
17130
|
+
}
|
|
17131
|
+
function handleConnectionError(managed) {
|
|
17132
|
+
if (!shouldReconnect(managed.policy)) {
|
|
17133
|
+
return;
|
|
17134
|
+
}
|
|
17135
|
+
scheduleReconnect(managed);
|
|
17136
|
+
}
|
|
17137
|
+
function monitorConnection(connection, onError) {
|
|
17138
|
+
const originalGetState = connection.getState.bind(connection);
|
|
17139
|
+
function checkForError() {
|
|
17140
|
+
const currentState = originalGetState();
|
|
17141
|
+
if (currentState === "closed") {
|
|
17142
|
+
onError();
|
|
17143
|
+
}
|
|
17144
|
+
}
|
|
17145
|
+
const proto = Object.getPrototypeOf(connection);
|
|
17146
|
+
const allKeys = /* @__PURE__ */ new Set([
|
|
17147
|
+
...Object.keys(connection),
|
|
17148
|
+
...proto ? Object.keys(proto) : []
|
|
17149
|
+
]);
|
|
17150
|
+
for (const key2 of allKeys) {
|
|
17151
|
+
const descriptor = Object.getOwnPropertyDescriptor(connection, key2) || Object.getOwnPropertyDescriptor(proto, key2);
|
|
17152
|
+
if (descriptor && typeof descriptor.value === "function" && key2 !== "getState" && key2 !== "close") {
|
|
17153
|
+
const originalMethod = connection[key2];
|
|
17154
|
+
connection[key2] = function(...args) {
|
|
17155
|
+
const result = originalMethod.apply(connection, args);
|
|
17156
|
+
checkForError();
|
|
17157
|
+
return result;
|
|
17158
|
+
};
|
|
17159
|
+
}
|
|
17160
|
+
}
|
|
17161
|
+
}
|
|
17162
|
+
return {
|
|
17163
|
+
wrap(connection, reconnectFn, policy, onReconnect, onMaxRetriesReached) {
|
|
17164
|
+
const managed = {
|
|
17165
|
+
connection,
|
|
17166
|
+
reconnectFn,
|
|
17167
|
+
policy,
|
|
17168
|
+
onReconnect,
|
|
17169
|
+
onMaxRetriesReached,
|
|
17170
|
+
retryCount: 0,
|
|
17171
|
+
timerId: null,
|
|
17172
|
+
isReconnecting: false,
|
|
17173
|
+
maxRetriesReached: false
|
|
17174
|
+
};
|
|
17175
|
+
managedConnections.set(connection, managed);
|
|
17176
|
+
if (shouldReconnect(policy)) {
|
|
17177
|
+
monitorConnection(connection, () => {
|
|
17178
|
+
handleConnectionError(managed);
|
|
17179
|
+
});
|
|
17180
|
+
}
|
|
17181
|
+
return connection;
|
|
17182
|
+
},
|
|
17183
|
+
triggerReconnect(connection) {
|
|
17184
|
+
const managed = managedConnections.get(connection);
|
|
17185
|
+
if (!managed) {
|
|
17186
|
+
return;
|
|
17187
|
+
}
|
|
17188
|
+
clearTimer(managed);
|
|
17189
|
+
managed.isReconnecting = false;
|
|
17190
|
+
managed.retryCount = 0;
|
|
17191
|
+
managed.maxRetriesReached = false;
|
|
17192
|
+
connection.close();
|
|
17193
|
+
attemptReconnect(managed);
|
|
17194
|
+
},
|
|
17195
|
+
dispose(connection) {
|
|
17196
|
+
const managed = managedConnections.get(connection);
|
|
17197
|
+
if (!managed) {
|
|
17198
|
+
return;
|
|
17199
|
+
}
|
|
17200
|
+
clearTimer(managed);
|
|
17201
|
+
managedConnections.delete(connection);
|
|
17202
|
+
},
|
|
17203
|
+
disposeAll() {
|
|
17204
|
+
for (const managed of managedConnections.values()) {
|
|
17205
|
+
clearTimer(managed);
|
|
17206
|
+
}
|
|
17207
|
+
managedConnections.clear();
|
|
17208
|
+
}
|
|
17209
|
+
};
|
|
17210
|
+
}
|
|
17211
|
+
|
|
17212
|
+
// src/optimistic/manager.ts
|
|
17213
|
+
function deepClone(value) {
|
|
17214
|
+
if (value === null || typeof value !== "object") {
|
|
17215
|
+
return value;
|
|
17216
|
+
}
|
|
17217
|
+
if (Array.isArray(value)) {
|
|
17218
|
+
return value.map(deepClone);
|
|
17219
|
+
}
|
|
17220
|
+
const cloned = {};
|
|
17221
|
+
for (const key2 in value) {
|
|
17222
|
+
if (Object.prototype.hasOwnProperty.call(value, key2)) {
|
|
17223
|
+
cloned[key2] = deepClone(value[key2]);
|
|
17224
|
+
}
|
|
17225
|
+
}
|
|
17226
|
+
return cloned;
|
|
17227
|
+
}
|
|
17228
|
+
function getAtPath(obj, path) {
|
|
17229
|
+
let current = obj;
|
|
17230
|
+
for (const key2 of path) {
|
|
17231
|
+
if (current === null || current === void 0) {
|
|
17232
|
+
return void 0;
|
|
17233
|
+
}
|
|
17234
|
+
current = current[key2];
|
|
17235
|
+
}
|
|
17236
|
+
return current;
|
|
17237
|
+
}
|
|
17238
|
+
function setAtPath(obj, path, value) {
|
|
17239
|
+
if (path.length === 0) {
|
|
17240
|
+
return deepClone(value);
|
|
17241
|
+
}
|
|
17242
|
+
const [head2, ...rest] = path;
|
|
17243
|
+
const key2 = head2;
|
|
17244
|
+
const isArray = Array.isArray(obj);
|
|
17245
|
+
const cloned = isArray ? [...obj] : { ...obj };
|
|
17246
|
+
if (rest.length === 0) {
|
|
17247
|
+
cloned[key2] = deepClone(value);
|
|
17248
|
+
} else {
|
|
17249
|
+
cloned[key2] = setAtPath(
|
|
17250
|
+
obj[key2],
|
|
17251
|
+
rest,
|
|
17252
|
+
value
|
|
17253
|
+
);
|
|
17254
|
+
}
|
|
17255
|
+
return cloned;
|
|
17256
|
+
}
|
|
17257
|
+
function createOptimisticManager() {
|
|
17258
|
+
const pendingUpdates = /* @__PURE__ */ new Map();
|
|
17259
|
+
const timers = /* @__PURE__ */ new Map();
|
|
17260
|
+
let autoRollbackTimeout = 0;
|
|
17261
|
+
const stateAccessors = /* @__PURE__ */ new Map();
|
|
17262
|
+
function generateId() {
|
|
17263
|
+
return crypto.randomUUID();
|
|
17264
|
+
}
|
|
17265
|
+
function apply2(target, path, value, getState, setState) {
|
|
17266
|
+
const id = generateId();
|
|
17267
|
+
const currentState = getState(target);
|
|
17268
|
+
const originalValue = path && path.length > 0 ? getAtPath(currentState, path) : currentState;
|
|
17269
|
+
let newState;
|
|
17270
|
+
if (path && path.length > 0) {
|
|
17271
|
+
newState = setAtPath(currentState, path, value);
|
|
17272
|
+
} else {
|
|
17273
|
+
newState = deepClone(value);
|
|
17274
|
+
}
|
|
17275
|
+
setState(target, newState);
|
|
17276
|
+
const pendingUpdate = {
|
|
17277
|
+
id,
|
|
17278
|
+
target,
|
|
17279
|
+
path: path && path.length > 0 ? path : void 0,
|
|
17280
|
+
originalValue,
|
|
17281
|
+
optimisticValue: value,
|
|
17282
|
+
timestamp: Date.now()
|
|
17283
|
+
};
|
|
17284
|
+
pendingUpdates.set(id, pendingUpdate);
|
|
17285
|
+
stateAccessors.set(id, { getState, setState });
|
|
17286
|
+
if (autoRollbackTimeout > 0) {
|
|
17287
|
+
const timer = setTimeout(() => {
|
|
17288
|
+
reject(id, getState, setState);
|
|
17289
|
+
}, autoRollbackTimeout);
|
|
17290
|
+
timers.set(id, timer);
|
|
17291
|
+
}
|
|
17292
|
+
return id;
|
|
17293
|
+
}
|
|
17294
|
+
function confirm(id) {
|
|
17295
|
+
const pending = pendingUpdates.get(id);
|
|
17296
|
+
if (!pending) {
|
|
17297
|
+
return false;
|
|
17298
|
+
}
|
|
17299
|
+
const timer = timers.get(id);
|
|
17300
|
+
if (timer) {
|
|
17301
|
+
clearTimeout(timer);
|
|
17302
|
+
timers.delete(id);
|
|
17303
|
+
}
|
|
17304
|
+
pendingUpdates.delete(id);
|
|
17305
|
+
stateAccessors.delete(id);
|
|
17306
|
+
return true;
|
|
17307
|
+
}
|
|
17308
|
+
function reject(id, getState, setState) {
|
|
17309
|
+
const pending = pendingUpdates.get(id);
|
|
17310
|
+
if (!pending) {
|
|
17311
|
+
return false;
|
|
17312
|
+
}
|
|
17313
|
+
const timer = timers.get(id);
|
|
17314
|
+
if (timer) {
|
|
17315
|
+
clearTimeout(timer);
|
|
17316
|
+
timers.delete(id);
|
|
17317
|
+
}
|
|
17318
|
+
const currentState = getState(pending.target);
|
|
17319
|
+
if (pending.path && pending.path.length > 0) {
|
|
17320
|
+
const restoredState = setAtPath(currentState, pending.path, pending.originalValue);
|
|
17321
|
+
setState(pending.target, restoredState);
|
|
17322
|
+
} else {
|
|
17323
|
+
setState(pending.target, pending.originalValue);
|
|
17324
|
+
}
|
|
17325
|
+
pendingUpdates.delete(id);
|
|
17326
|
+
stateAccessors.delete(id);
|
|
17327
|
+
return true;
|
|
17328
|
+
}
|
|
17329
|
+
function getPending(id) {
|
|
17330
|
+
return pendingUpdates.get(id);
|
|
17331
|
+
}
|
|
17332
|
+
function getAllPending() {
|
|
17333
|
+
return Array.from(pendingUpdates.values());
|
|
17334
|
+
}
|
|
17335
|
+
function setAutoRollbackTimeout(ms) {
|
|
17336
|
+
autoRollbackTimeout = ms;
|
|
17337
|
+
}
|
|
17338
|
+
function dispose() {
|
|
17339
|
+
for (const timer of timers.values()) {
|
|
17340
|
+
clearTimeout(timer);
|
|
17341
|
+
}
|
|
17342
|
+
timers.clear();
|
|
17343
|
+
pendingUpdates.clear();
|
|
17344
|
+
stateAccessors.clear();
|
|
17345
|
+
}
|
|
17346
|
+
return {
|
|
17347
|
+
apply: apply2,
|
|
17348
|
+
confirm,
|
|
17349
|
+
reject,
|
|
17350
|
+
getPending,
|
|
17351
|
+
getAllPending,
|
|
17352
|
+
setAutoRollbackTimeout,
|
|
17353
|
+
dispose
|
|
17354
|
+
};
|
|
17355
|
+
}
|
|
17356
|
+
|
|
17357
|
+
// src/binding/realtime.ts
|
|
17358
|
+
function createBindingManager() {
|
|
17359
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
17360
|
+
function bind(config, setState) {
|
|
17361
|
+
const id = crypto.randomUUID();
|
|
17362
|
+
bindings.set(id, { id, config, setState });
|
|
17363
|
+
return id;
|
|
17364
|
+
}
|
|
17365
|
+
function unbind(id) {
|
|
17366
|
+
return bindings.delete(id);
|
|
17367
|
+
}
|
|
17368
|
+
function unbindByConnection(connection) {
|
|
17369
|
+
for (const [id, binding] of bindings) {
|
|
17370
|
+
if (binding.config.connection === connection) {
|
|
17371
|
+
bindings.delete(id);
|
|
17372
|
+
}
|
|
17373
|
+
}
|
|
17374
|
+
}
|
|
17375
|
+
function unbindByTarget(target) {
|
|
17376
|
+
for (const [id, binding] of bindings) {
|
|
17377
|
+
if (binding.config.target === target) {
|
|
17378
|
+
bindings.delete(id);
|
|
17379
|
+
}
|
|
17380
|
+
}
|
|
17381
|
+
}
|
|
17382
|
+
function handleMessage(connection, data, eventType) {
|
|
17383
|
+
for (const binding of bindings.values()) {
|
|
17384
|
+
const { config, setState } = binding;
|
|
17385
|
+
if (config.connection !== connection) {
|
|
17386
|
+
continue;
|
|
17387
|
+
}
|
|
17388
|
+
if (config.eventType !== void 0) {
|
|
17389
|
+
if (eventType !== config.eventType) {
|
|
17390
|
+
continue;
|
|
17391
|
+
}
|
|
17392
|
+
}
|
|
17393
|
+
let value = data;
|
|
17394
|
+
if (config.transform) {
|
|
17395
|
+
value = config.transform(data);
|
|
17396
|
+
}
|
|
17397
|
+
if (config.patch === true) {
|
|
17398
|
+
setState(config.target, value, { patch: true });
|
|
17399
|
+
} else if (config.path !== void 0) {
|
|
17400
|
+
setState(config.target, value, config.path);
|
|
17401
|
+
} else {
|
|
17402
|
+
setState(config.target, value);
|
|
17403
|
+
}
|
|
17404
|
+
}
|
|
17405
|
+
}
|
|
17406
|
+
function getBindings() {
|
|
17407
|
+
return Array.from(bindings.values()).map((b2) => ({ ...b2.config }));
|
|
17408
|
+
}
|
|
17409
|
+
function dispose() {
|
|
17410
|
+
bindings.clear();
|
|
17411
|
+
}
|
|
17412
|
+
return {
|
|
17413
|
+
bind,
|
|
17414
|
+
unbind,
|
|
17415
|
+
unbindByConnection,
|
|
17416
|
+
unbindByTarget,
|
|
17417
|
+
handleMessage,
|
|
17418
|
+
getBindings,
|
|
17419
|
+
dispose
|
|
17420
|
+
};
|
|
17421
|
+
}
|
|
17422
|
+
|
|
15781
17423
|
// src/hmr/client.ts
|
|
15782
17424
|
var DEFAULT_INITIAL_RECONNECT_DELAY = 1e3;
|
|
15783
17425
|
var DEFAULT_MAX_RECONNECT_DELAY = 3e4;
|
|
@@ -16073,23 +17715,288 @@ function createErrorOverlay() {
|
|
|
16073
17715
|
}
|
|
16074
17716
|
};
|
|
16075
17717
|
}
|
|
17718
|
+
|
|
17719
|
+
// src/theme/provider.ts
|
|
17720
|
+
var DEFAULT_COLORS = {};
|
|
17721
|
+
var DEFAULT_FONTS = {};
|
|
17722
|
+
var DEFAULT_STORAGE_KEY = "constela-theme-mode";
|
|
17723
|
+
function createThemeProvider(options) {
|
|
17724
|
+
const config = options?.config ?? {};
|
|
17725
|
+
const storageKey = options?.storageKey ?? DEFAULT_STORAGE_KEY;
|
|
17726
|
+
const useCookies = options?.useCookies ?? false;
|
|
17727
|
+
const defaultMode = options?.defaultMode ?? "system";
|
|
17728
|
+
let lightColors = { ...DEFAULT_COLORS, ...config.colors };
|
|
17729
|
+
let darkColors = { ...DEFAULT_COLORS, ...config.darkColors };
|
|
17730
|
+
const fonts = { ...DEFAULT_FONTS, ...config.fonts };
|
|
17731
|
+
const cssPrefix = config.cssPrefix ?? "";
|
|
17732
|
+
let selectedMode = loadPersistedMode() ?? config.mode ?? defaultMode;
|
|
17733
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
17734
|
+
let destroyed = false;
|
|
17735
|
+
const mediaQuery = typeof window !== "undefined" ? window.matchMedia("(prefers-color-scheme: dark)") : null;
|
|
17736
|
+
function handleMediaChange(event) {
|
|
17737
|
+
if (destroyed) return;
|
|
17738
|
+
if (selectedMode === "system") {
|
|
17739
|
+
applyTheme();
|
|
17740
|
+
notifySubscribers();
|
|
17741
|
+
}
|
|
17742
|
+
}
|
|
17743
|
+
if (mediaQuery) {
|
|
17744
|
+
mediaQuery.addEventListener("change", handleMediaChange);
|
|
17745
|
+
}
|
|
17746
|
+
function loadPersistedMode() {
|
|
17747
|
+
if (typeof window === "undefined") return null;
|
|
17748
|
+
try {
|
|
17749
|
+
const stored = localStorage.getItem(storageKey);
|
|
17750
|
+
if (stored === "light" || stored === "dark" || stored === "system") {
|
|
17751
|
+
return stored;
|
|
17752
|
+
}
|
|
17753
|
+
} catch {
|
|
17754
|
+
}
|
|
17755
|
+
return null;
|
|
17756
|
+
}
|
|
17757
|
+
function persistMode(mode) {
|
|
17758
|
+
if (typeof window === "undefined") return;
|
|
17759
|
+
try {
|
|
17760
|
+
localStorage.setItem(storageKey, mode);
|
|
17761
|
+
} catch {
|
|
17762
|
+
}
|
|
17763
|
+
if (useCookies && typeof document !== "undefined") {
|
|
17764
|
+
document.cookie = `${storageKey}=${mode}; path=/; max-age=31536000; SameSite=Lax`;
|
|
17765
|
+
}
|
|
17766
|
+
}
|
|
17767
|
+
function resolveMode() {
|
|
17768
|
+
if (selectedMode === "light" || selectedMode === "dark") {
|
|
17769
|
+
return selectedMode;
|
|
17770
|
+
}
|
|
17771
|
+
if (mediaQuery) {
|
|
17772
|
+
return mediaQuery.matches ? "dark" : "light";
|
|
17773
|
+
}
|
|
17774
|
+
return "light";
|
|
17775
|
+
}
|
|
17776
|
+
function getCurrentColors() {
|
|
17777
|
+
const resolved = resolveMode();
|
|
17778
|
+
if (resolved === "dark") {
|
|
17779
|
+
return Object.keys(darkColors).length > 0 ? { ...lightColors, ...darkColors } : lightColors;
|
|
17780
|
+
}
|
|
17781
|
+
return lightColors;
|
|
17782
|
+
}
|
|
17783
|
+
function applyCSSVariables() {
|
|
17784
|
+
if (typeof document === "undefined") return;
|
|
17785
|
+
const root2 = document.documentElement;
|
|
17786
|
+
const colors = getCurrentColors();
|
|
17787
|
+
const prefix = cssPrefix ? `${cssPrefix}-` : "";
|
|
17788
|
+
for (const [key2, value] of Object.entries(colors)) {
|
|
17789
|
+
if (value !== void 0) {
|
|
17790
|
+
root2.style.setProperty(`--${prefix}${key2}`, value);
|
|
17791
|
+
}
|
|
17792
|
+
}
|
|
17793
|
+
for (const [key2, value] of Object.entries(fonts)) {
|
|
17794
|
+
if (value !== void 0) {
|
|
17795
|
+
root2.style.setProperty(`--font-${key2}`, value);
|
|
17796
|
+
}
|
|
17797
|
+
}
|
|
17798
|
+
}
|
|
17799
|
+
function applyDarkClass() {
|
|
17800
|
+
if (typeof document === "undefined") return;
|
|
17801
|
+
const root2 = document.documentElement;
|
|
17802
|
+
if (!root2) return;
|
|
17803
|
+
const resolved = resolveMode();
|
|
17804
|
+
if (resolved === "dark") {
|
|
17805
|
+
root2.classList.add("dark");
|
|
17806
|
+
} else {
|
|
17807
|
+
root2.classList.remove("dark");
|
|
17808
|
+
}
|
|
17809
|
+
}
|
|
17810
|
+
function applyTheme() {
|
|
17811
|
+
applyCSSVariables();
|
|
17812
|
+
applyDarkClass();
|
|
17813
|
+
}
|
|
17814
|
+
function notifySubscribers() {
|
|
17815
|
+
if (destroyed) return;
|
|
17816
|
+
const theme = getTheme();
|
|
17817
|
+
for (const fn of subscribers) {
|
|
17818
|
+
fn(theme);
|
|
17819
|
+
}
|
|
17820
|
+
}
|
|
17821
|
+
function getTheme() {
|
|
17822
|
+
return {
|
|
17823
|
+
resolvedMode: resolveMode(),
|
|
17824
|
+
selectedMode,
|
|
17825
|
+
colors: getCurrentColors(),
|
|
17826
|
+
fonts
|
|
17827
|
+
};
|
|
17828
|
+
}
|
|
17829
|
+
function getMode() {
|
|
17830
|
+
return selectedMode;
|
|
17831
|
+
}
|
|
17832
|
+
function setMode(mode) {
|
|
17833
|
+
if (destroyed) return;
|
|
17834
|
+
if (mode === selectedMode) return;
|
|
17835
|
+
selectedMode = mode;
|
|
17836
|
+
persistMode(mode);
|
|
17837
|
+
applyTheme();
|
|
17838
|
+
notifySubscribers();
|
|
17839
|
+
}
|
|
17840
|
+
function subscribe(fn) {
|
|
17841
|
+
subscribers.add(fn);
|
|
17842
|
+
return () => {
|
|
17843
|
+
subscribers.delete(fn);
|
|
17844
|
+
};
|
|
17845
|
+
}
|
|
17846
|
+
function setColors(colors, mode) {
|
|
17847
|
+
if (destroyed) return;
|
|
17848
|
+
const targetMode = mode ?? "light";
|
|
17849
|
+
if (targetMode === "dark") {
|
|
17850
|
+
darkColors = { ...darkColors, ...colors };
|
|
17851
|
+
} else {
|
|
17852
|
+
lightColors = { ...lightColors, ...colors };
|
|
17853
|
+
}
|
|
17854
|
+
applyTheme();
|
|
17855
|
+
notifySubscribers();
|
|
17856
|
+
}
|
|
17857
|
+
function destroy() {
|
|
17858
|
+
destroyed = true;
|
|
17859
|
+
subscribers.clear();
|
|
17860
|
+
if (mediaQuery) {
|
|
17861
|
+
mediaQuery.removeEventListener("change", handleMediaChange);
|
|
17862
|
+
}
|
|
17863
|
+
}
|
|
17864
|
+
applyTheme();
|
|
17865
|
+
return {
|
|
17866
|
+
getTheme,
|
|
17867
|
+
getMode,
|
|
17868
|
+
setMode,
|
|
17869
|
+
subscribe,
|
|
17870
|
+
setColors,
|
|
17871
|
+
destroy
|
|
17872
|
+
};
|
|
17873
|
+
}
|
|
17874
|
+
|
|
17875
|
+
// src/prefetch.ts
|
|
17876
|
+
var PREFETCH_STRATEGIES = ["hover", "visible", "immediate"];
|
|
17877
|
+
function isPrefetchOptions(value) {
|
|
17878
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
17879
|
+
return false;
|
|
17880
|
+
}
|
|
17881
|
+
const obj = value;
|
|
17882
|
+
if (!PREFETCH_STRATEGIES.includes(obj["strategy"])) {
|
|
17883
|
+
return false;
|
|
17884
|
+
}
|
|
17885
|
+
if ("threshold" in obj && obj["threshold"] !== void 0) {
|
|
17886
|
+
if (typeof obj["threshold"] !== "number") {
|
|
17887
|
+
return false;
|
|
17888
|
+
}
|
|
17889
|
+
}
|
|
17890
|
+
if ("rootMargin" in obj && obj["rootMargin"] !== void 0) {
|
|
17891
|
+
if (typeof obj["rootMargin"] !== "string") {
|
|
17892
|
+
return false;
|
|
17893
|
+
}
|
|
17894
|
+
}
|
|
17895
|
+
return true;
|
|
17896
|
+
}
|
|
17897
|
+
var globalLoader = null;
|
|
17898
|
+
function setGlobalLoader(loader) {
|
|
17899
|
+
globalLoader = loader;
|
|
17900
|
+
}
|
|
17901
|
+
function prefetchIsland(id, options) {
|
|
17902
|
+
if (options !== void 0 && !isPrefetchOptions(options)) {
|
|
17903
|
+
return;
|
|
17904
|
+
}
|
|
17905
|
+
if (globalLoader) {
|
|
17906
|
+
globalLoader.preload(id);
|
|
17907
|
+
}
|
|
17908
|
+
}
|
|
17909
|
+
function createPrefetcher(loader) {
|
|
17910
|
+
const prefetchedIds = /* @__PURE__ */ new Set();
|
|
17911
|
+
function prefetchOnce(id) {
|
|
17912
|
+
if (prefetchedIds.has(id)) {
|
|
17913
|
+
return;
|
|
17914
|
+
}
|
|
17915
|
+
prefetchedIds.add(id);
|
|
17916
|
+
loader.preload(id);
|
|
17917
|
+
}
|
|
17918
|
+
function prefetchOnHover(element2, id) {
|
|
17919
|
+
let cleaned = false;
|
|
17920
|
+
const handler = () => {
|
|
17921
|
+
if (cleaned) return;
|
|
17922
|
+
prefetchOnce(id);
|
|
17923
|
+
};
|
|
17924
|
+
element2.addEventListener("mouseenter", handler, { passive: true });
|
|
17925
|
+
return () => {
|
|
17926
|
+
if (cleaned) return;
|
|
17927
|
+
cleaned = true;
|
|
17928
|
+
element2.removeEventListener("mouseenter", handler, { passive: true });
|
|
17929
|
+
};
|
|
17930
|
+
}
|
|
17931
|
+
function prefetchOnVisible(element2, id, options) {
|
|
17932
|
+
let cleaned = false;
|
|
17933
|
+
let observer = null;
|
|
17934
|
+
const observerOptions = {};
|
|
17935
|
+
if (options?.threshold !== void 0) {
|
|
17936
|
+
observerOptions.threshold = options.threshold;
|
|
17937
|
+
}
|
|
17938
|
+
if (options?.rootMargin !== void 0) {
|
|
17939
|
+
observerOptions.rootMargin = options.rootMargin;
|
|
17940
|
+
}
|
|
17941
|
+
const callback = (entries2) => {
|
|
17942
|
+
for (const entry of entries2) {
|
|
17943
|
+
if (entry.isIntersecting && entry.target === element2) {
|
|
17944
|
+
prefetchOnce(id);
|
|
17945
|
+
if (observer) {
|
|
17946
|
+
observer.unobserve(element2);
|
|
17947
|
+
}
|
|
17948
|
+
break;
|
|
17949
|
+
}
|
|
17950
|
+
}
|
|
17951
|
+
};
|
|
17952
|
+
observer = new IntersectionObserver(callback, observerOptions);
|
|
17953
|
+
observer.observe(element2);
|
|
17954
|
+
return () => {
|
|
17955
|
+
if (cleaned) return;
|
|
17956
|
+
cleaned = true;
|
|
17957
|
+
if (observer) {
|
|
17958
|
+
observer.unobserve(element2);
|
|
17959
|
+
observer = null;
|
|
17960
|
+
}
|
|
17961
|
+
};
|
|
17962
|
+
}
|
|
17963
|
+
return {
|
|
17964
|
+
prefetchOnHover,
|
|
17965
|
+
prefetchOnVisible
|
|
17966
|
+
};
|
|
17967
|
+
}
|
|
16076
17968
|
export {
|
|
17969
|
+
PREFETCH_STRATEGIES,
|
|
16077
17970
|
createApp,
|
|
17971
|
+
createBindingManager,
|
|
16078
17972
|
createComputed,
|
|
16079
17973
|
createConnectionManager,
|
|
16080
17974
|
createEffect,
|
|
16081
17975
|
createErrorOverlay,
|
|
16082
17976
|
createHMRClient,
|
|
16083
17977
|
createHMRHandler,
|
|
17978
|
+
createIslandLoader,
|
|
17979
|
+
createOptimisticManager,
|
|
17980
|
+
createPrefetcher,
|
|
17981
|
+
createReconnectionManager,
|
|
17982
|
+
createSSEConnection,
|
|
17983
|
+
createSSEConnectionManager,
|
|
16084
17984
|
createSignal,
|
|
16085
17985
|
createStateStore,
|
|
17986
|
+
createThemeProvider,
|
|
16086
17987
|
createTypedStateStore,
|
|
16087
17988
|
createWebSocketConnection,
|
|
17989
|
+
detectIslandsInDOM,
|
|
16088
17990
|
evaluate,
|
|
16089
17991
|
evaluateStyle,
|
|
16090
17992
|
executeAction,
|
|
16091
17993
|
hydrateApp,
|
|
16092
|
-
|
|
17994
|
+
hydrateAppWithIslands,
|
|
17995
|
+
hydrateIsland,
|
|
17996
|
+
isPrefetchOptions,
|
|
17997
|
+
prefetchIsland,
|
|
17998
|
+
render,
|
|
17999
|
+
setGlobalLoader
|
|
16093
18000
|
};
|
|
16094
18001
|
/*! Bundled license information:
|
|
16095
18002
|
|