@arbidocs/blocks 0.3.142 → 0.3.143

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.
@@ -1,7 +1,7 @@
1
1
  import { create } from 'zustand';
2
2
  import { persist } from 'zustand/middleware';
3
- import { createContext, useState, useEffect, useContext } from 'react';
4
- import { RotateCcw, Palette, ImageIcon, ArrowRight, Quote, ChevronDown, XCircle, AlertTriangle, CheckCircle2, Info, Check, Save } from 'lucide-react';
3
+ import { createContext, useState, useEffect, useMemo, useContext } from 'react';
4
+ import { RotateCcw, Palette, Calendar, X, CalendarDays, GanttChartSquare, ImageIcon, ArrowRight, Quote, ChevronDown, XCircle, AlertTriangle, CheckCircle2, Info, Check, Save } from 'lucide-react';
5
5
  import { Input, Card, CardHeader, CardTitle, CardContent, cn, Button, Avatar, AvatarImage, AvatarFallback, AiMarkdown } from '@arbidocs/react/ui';
6
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
7
 
@@ -585,6 +585,506 @@ function tid(...parts) {
585
585
  (p) => String(p).trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")
586
586
  ).join("-");
587
587
  }
588
+
589
+ // src/timeline/span.ts
590
+ var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
591
+ var MONTH_NAMES = [
592
+ "January",
593
+ "February",
594
+ "March",
595
+ "April",
596
+ "May",
597
+ "June",
598
+ "July",
599
+ "August",
600
+ "September",
601
+ "October",
602
+ "November",
603
+ "December"
604
+ ];
605
+ var WEEKDAY_NAMES = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
606
+ var DAY_MS = 864e5;
607
+ function monthLabel(d) {
608
+ return `${MONTH_NAMES[d.getUTCMonth()]} ${d.getUTCFullYear()}`;
609
+ }
610
+ function utcDay(d) {
611
+ return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
612
+ }
613
+ function dayKey(d) {
614
+ return d.toISOString().slice(0, 10);
615
+ }
616
+ function parseIso2(iso) {
617
+ if (!iso) return null;
618
+ const d = new Date(iso);
619
+ return isNaN(d.getTime()) ? null : d;
620
+ }
621
+ function isMidnight(d) {
622
+ return d.getUTCHours() === 0 && d.getUTCMinutes() === 0 && d.getUTCSeconds() === 0;
623
+ }
624
+ function isEndOfDay(d) {
625
+ return d.getUTCHours() === 23 && d.getUTCMinutes() === 59;
626
+ }
627
+ function lastDayOfMonth(d) {
628
+ return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0)).getUTCDate();
629
+ }
630
+ function day(d) {
631
+ return `${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]} ${d.getUTCFullYear()}`;
632
+ }
633
+ function formatSpan(startIso, endIso) {
634
+ if (!startIso) return "";
635
+ const start = new Date(startIso);
636
+ const end = endIso ? new Date(endIso) : start;
637
+ if (startIso === endIso) {
638
+ const hh = String(start.getUTCHours()).padStart(2, "0");
639
+ const mm = String(start.getUTCMinutes()).padStart(2, "0");
640
+ return `${day(start)}, ${hh}:${mm} UTC`;
641
+ }
642
+ if (isMidnight(start) && isEndOfDay(end)) {
643
+ const sameDay = start.getUTCFullYear() === end.getUTCFullYear() && start.getUTCMonth() === end.getUTCMonth() && start.getUTCDate() === end.getUTCDate();
644
+ if (sameDay) return day(start);
645
+ const firstOfMonth = start.getUTCDate() === 1;
646
+ const endsMonth = end.getUTCDate() === lastDayOfMonth(end);
647
+ const sameMonth = start.getUTCFullYear() === end.getUTCFullYear() && start.getUTCMonth() === end.getUTCMonth();
648
+ if (firstOfMonth && endsMonth && sameMonth) {
649
+ return `${MONTHS[start.getUTCMonth()]} ${start.getUTCFullYear()}`;
650
+ }
651
+ const wholeYear = firstOfMonth && endsMonth && start.getUTCMonth() === 0 && end.getUTCMonth() === 11 && start.getUTCFullYear() === end.getUTCFullYear();
652
+ if (wholeYear) return String(start.getUTCFullYear());
653
+ return `${day(start)} \u2013 ${day(end)}`;
654
+ }
655
+ return `${day(start)} \u2013 ${day(end)}`;
656
+ }
657
+ var DEFAULT_MAX_LANES = 3;
658
+ var MAX_WEEKS = 520;
659
+ function isPrecise(item) {
660
+ if (!item.start || !item.end) return false;
661
+ return item.start.slice(0, 10) === item.end.slice(0, 10);
662
+ }
663
+ function TimelineCalendar({
664
+ items,
665
+ onSelect,
666
+ maxLanes = DEFAULT_MAX_LANES,
667
+ emptyState,
668
+ className,
669
+ testId = "timeline-calendar"
670
+ }) {
671
+ const dated = useMemo(() => items.filter((i) => i.start), [items]);
672
+ const weeks = useMemo(() => {
673
+ if (dated.length === 0) return [];
674
+ const times = dated.flatMap((i) => [
675
+ new Date(i.start).getTime(),
676
+ new Date(i.end ?? i.start).getTime()
677
+ ]);
678
+ const first = utcDay(new Date(Math.min(...times)));
679
+ const last = utcDay(new Date(Math.max(...times)));
680
+ const gridStart = new Date(first);
681
+ gridStart.setUTCDate(first.getUTCDate() - (first.getUTCDay() + 6) % 7);
682
+ const out = [];
683
+ const cursor = new Date(gridStart);
684
+ while (cursor <= last && out.length < MAX_WEEKS) {
685
+ out.push(
686
+ Array.from({ length: 7 }, (_, d) => {
687
+ const day2 = new Date(cursor);
688
+ day2.setUTCDate(cursor.getUTCDate() + d);
689
+ return day2;
690
+ })
691
+ );
692
+ cursor.setUTCDate(cursor.getUTCDate() + 7);
693
+ }
694
+ return out;
695
+ }, [dated]);
696
+ const segmentsByWeek = useMemo(() => {
697
+ return weeks.map((week) => {
698
+ const weekStart = week[0];
699
+ const weekEnd = week[6];
700
+ const overlapping = dated.map((item) => ({
701
+ item,
702
+ start: utcDay(new Date(item.start)),
703
+ end: utcDay(new Date(item.end ?? item.start))
704
+ })).filter(({ start, end }) => start <= weekEnd && end >= weekStart).sort((a, b) => {
705
+ const lenA = b.end.getTime() - b.start.getTime();
706
+ const lenB = a.end.getTime() - a.start.getTime();
707
+ return lenA - lenB || a.start.getTime() - b.start.getTime();
708
+ });
709
+ const laneEnds = [];
710
+ const segments = [];
711
+ let overflow = 0;
712
+ for (const { item, start, end } of overlapping) {
713
+ const from = start < weekStart ? weekStart : start;
714
+ const to = end > weekEnd ? weekEnd : end;
715
+ const startCol = Math.round((from.getTime() - weekStart.getTime()) / DAY_MS);
716
+ const endCol = Math.round((to.getTime() - weekStart.getTime()) / DAY_MS);
717
+ let lane = laneEnds.findIndex((last) => last < startCol);
718
+ if (lane === -1) lane = laneEnds.length;
719
+ if (lane >= maxLanes) {
720
+ overflow += 1;
721
+ continue;
722
+ }
723
+ laneEnds[lane] = endCol;
724
+ segments.push({
725
+ item,
726
+ startCol,
727
+ span: endCol - startCol + 1,
728
+ isStart: start >= weekStart,
729
+ isEnd: end <= weekEnd,
730
+ lane
731
+ });
732
+ }
733
+ return { segments, overflow };
734
+ });
735
+ }, [weeks, dated, maxLanes]);
736
+ if (weeks.length === 0 && emptyState) {
737
+ return /* @__PURE__ */ jsx(Fragment, { children: emptyState });
738
+ }
739
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full", className), "data-testid": testId, children: [
740
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 border-b border-border bg-background", children: WEEKDAY_NAMES.map((d) => /* @__PURE__ */ jsx("div", { className: "px-2 py-1 text-[11px] text-muted-foreground text-center", children: d }, d)) }),
741
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto", "data-testid": `${testId}-scroll`, children: weeks.map((week, wi) => {
742
+ const { segments, overflow } = segmentsByWeek[wi];
743
+ const monthStartDay = week.find((d) => d.getUTCDate() === 1);
744
+ const marker = monthStartDay ?? (wi === 0 ? week[0] : void 0);
745
+ return /* @__PURE__ */ jsxs("div", { children: [
746
+ marker && // Sticky, so the month you are LOOKING at names itself: it
747
+ // pins to the top of the scroller while you are inside it and
748
+ // is pushed up by the next one. No scroll listener needed.
749
+ /* @__PURE__ */ jsx(
750
+ "div",
751
+ {
752
+ className: "sticky top-0 z-10 px-3 py-1 text-xs font-medium text-foreground bg-background/95 backdrop-blur border-y border-border/60",
753
+ "data-testid": `${testId}-month-${marker.getUTCFullYear()}-${String(
754
+ marker.getUTCMonth() + 1
755
+ ).padStart(2, "0")}`,
756
+ children: monthLabel(marker)
757
+ }
758
+ ),
759
+ /* @__PURE__ */ jsxs("div", { className: "border-b border-border/40", children: [
760
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 bg-background", children: week.map((day2) => /* @__PURE__ */ jsx(
761
+ "div",
762
+ {
763
+ "data-testid": `${testId}-day-${dayKey(day2)}`,
764
+ className: cn(
765
+ "px-1 pt-1 text-[11px] border-r border-border/40",
766
+ day2.getUTCDate() === 1 ? "text-foreground font-medium" : "text-muted-foreground/60"
767
+ ),
768
+ children: day2.getUTCDate()
769
+ },
770
+ dayKey(day2)
771
+ )) }),
772
+ /* @__PURE__ */ jsxs(
773
+ "div",
774
+ {
775
+ className: "grid grid-cols-7 gap-y-0.5 px-0.5 pb-1 bg-muted/40",
776
+ style: { gridAutoRows: "minmax(18px, auto)", minHeight: 62 },
777
+ children: [
778
+ segments.map((seg) => /* @__PURE__ */ jsx(
779
+ "button",
780
+ {
781
+ type: "button",
782
+ onClick: () => onSelect?.(seg.item),
783
+ title: `${formatSpan(seg.item.start, seg.item.end)} \u2014 ${seg.item.label}`,
784
+ "data-testid": `${testId}-entry-${seg.item.id}`,
785
+ style: {
786
+ gridColumn: `${seg.startCol + 1} / span ${seg.span}`,
787
+ gridRow: seg.lane + 1
788
+ },
789
+ className: cn(
790
+ "text-left text-[10px] leading-[13px] py-[2px] px-1 min-h-[18px] whitespace-normal break-words line-clamp-3",
791
+ isPrecise(seg.item) ? "bg-primary/20 text-foreground" : "bg-muted text-muted-foreground",
792
+ seg.isStart && "rounded-l",
793
+ seg.isEnd && "rounded-r"
794
+ ),
795
+ children: seg.isStart ? seg.item.label : " "
796
+ },
797
+ `${seg.item.id}-${seg.startCol}`
798
+ )),
799
+ overflow > 0 && /* @__PURE__ */ jsxs(
800
+ "span",
801
+ {
802
+ className: "text-[10px] text-muted-foreground px-1",
803
+ style: { gridColumn: "1 / span 7", gridRow: maxLanes + 1 },
804
+ children: [
805
+ "+",
806
+ overflow,
807
+ " more"
808
+ ]
809
+ }
810
+ )
811
+ ]
812
+ }
813
+ )
814
+ ] })
815
+ ] }, dayKey(week[0]));
816
+ }) })
817
+ ] });
818
+ }
819
+ var BAR_PALETTE = [
820
+ {
821
+ gradient: "linear-gradient(90deg, #6366f1, #818cf8)",
822
+ shadow: "0 2px 6px rgba(99,102,241,.35)"
823
+ },
824
+ {
825
+ gradient: "linear-gradient(90deg, #8b5cf6, #a78bfa)",
826
+ shadow: "0 2px 6px rgba(139,92,246,.35)"
827
+ },
828
+ { gradient: "linear-gradient(90deg, #ef4444, #f87171)", shadow: "0 2px 6px rgba(239,68,68,.35)" },
829
+ {
830
+ gradient: "linear-gradient(90deg, #f59e0b, #fbbf24)",
831
+ shadow: "0 2px 6px rgba(245,158,11,.35)"
832
+ },
833
+ { gradient: "linear-gradient(90deg, #22c55e, #4ade80)", shadow: "0 2px 6px rgba(34,197,94,.35)" },
834
+ { gradient: "linear-gradient(90deg, #06b6d4, #22d3ee)", shadow: "0 2px 6px rgba(6,182,212,.35)" }
835
+ ];
836
+ var WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
837
+ function formatAxisDate(d) {
838
+ return d.toLocaleDateString("en-US", { month: "short", year: "numeric" });
839
+ }
840
+ function formatBarLabel(start, end) {
841
+ const fmt = (d) => d.toLocaleDateString("en-US", { month: "short", year: "2-digit" });
842
+ if (start.getTime() === end.getTime()) return fmt(start);
843
+ return `${fmt(start)} \u2013 ${fmt(end)}`;
844
+ }
845
+ function TimelineGantt({
846
+ items,
847
+ onSelect,
848
+ renderDetail,
849
+ labelWidth = 240,
850
+ emptyMessage = "Nothing dated yet.",
851
+ className,
852
+ testId = "timeline-gantt"
853
+ }) {
854
+ const [activeIndex, setActiveIndex] = useState(null);
855
+ const rows = items.filter((i) => parseIso2(i.start) !== null).slice().sort((a, b) => parseIso2(a.start).getTime() - parseIso2(b.start).getTime());
856
+ if (rows.length === 0) {
857
+ return /* @__PURE__ */ jsxs(
858
+ "div",
859
+ {
860
+ "data-testid": `${testId}-empty-state`,
861
+ className: cn(
862
+ "flex flex-col items-center justify-center py-16 text-muted-foreground",
863
+ className
864
+ ),
865
+ children: [
866
+ /* @__PURE__ */ jsx(Calendar, { className: "w-12 h-12 mb-3 opacity-30" }),
867
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: emptyMessage })
868
+ ]
869
+ }
870
+ );
871
+ }
872
+ const allDates = rows.flatMap((i) => {
873
+ const s = parseIso2(i.start);
874
+ return [s, parseIso2(i.end ?? null) ?? s];
875
+ });
876
+ const minTime = Math.min(...allDates.map((d) => d.getTime()));
877
+ const maxTime = Math.max(...allDates.map((d) => d.getTime()));
878
+ const pad = Math.max((maxTime - minTime) * 0.04, WEEK_MS);
879
+ const axisMin = new Date(minTime - pad);
880
+ const axisMax = new Date(maxTime + pad);
881
+ const axisRange = axisMax.getTime() - axisMin.getTime();
882
+ const toPercent = (d) => Math.min(100, Math.max(0, (d.getTime() - axisMin.getTime()) / axisRange * 100));
883
+ const ticks = Array.from(
884
+ { length: 5 },
885
+ (_, i) => new Date(axisMin.getTime() + axisRange * i / 4)
886
+ );
887
+ const today = /* @__PURE__ */ new Date();
888
+ const todayPct = toPercent(today);
889
+ const showToday = today > axisMin && today < axisMax;
890
+ const activeItem = activeIndex !== null ? rows[activeIndex] : null;
891
+ const detail = activeItem ? renderDetail?.(activeItem) : null;
892
+ const select = (index) => {
893
+ setActiveIndex(index);
894
+ onSelect?.(index === null ? null : rows[index]);
895
+ };
896
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0", className), children: [
897
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 p-5 overflow-x-auto", children: [
898
+ /* @__PURE__ */ jsxs("div", { className: "flex mb-1", children: [
899
+ /* @__PURE__ */ jsx(
900
+ "div",
901
+ {
902
+ style: { width: labelWidth, flexShrink: 0 },
903
+ className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground pb-1",
904
+ children: "Event"
905
+ }
906
+ ),
907
+ /* @__PURE__ */ jsx("div", { className: "flex-1 relative h-6 border-b border-border", children: ticks.map((tick, i) => /* @__PURE__ */ jsx(
908
+ "span",
909
+ {
910
+ style: { left: `${toPercent(tick)}%` },
911
+ className: "absolute bottom-1 text-[10px] text-muted-foreground -translate-x-1/2 whitespace-nowrap select-none",
912
+ children: formatAxisDate(tick)
913
+ },
914
+ i
915
+ )) })
916
+ ] }),
917
+ /* @__PURE__ */ jsxs("div", { className: "relative mt-2", children: [
918
+ showToday && /* @__PURE__ */ jsxs(
919
+ "div",
920
+ {
921
+ className: "absolute top-0 bottom-0 pointer-events-none z-10",
922
+ style: {
923
+ left: `calc(${labelWidth}px + (100% - ${labelWidth}px) * ${todayPct / 100})`
924
+ },
925
+ children: [
926
+ /* @__PURE__ */ jsx("div", { className: "h-full border-l-2 border-dashed border-muted-foreground/50" }),
927
+ /* @__PURE__ */ jsx("span", { className: "absolute -top-5 -translate-x-1/2 text-[9px] text-muted-foreground bg-background border rounded px-1", children: "today" })
928
+ ]
929
+ }
930
+ ),
931
+ rows.map((item, i) => {
932
+ const startDate = parseIso2(item.start);
933
+ const endDate = parseIso2(item.end ?? null) ?? startDate;
934
+ const leftPct = toPercent(startDate);
935
+ const widthPct = Math.max(1, toPercent(endDate) - toPercent(startDate));
936
+ const color = BAR_PALETTE[i % BAR_PALETTE.length];
937
+ const isActive = activeIndex === i;
938
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center mb-2", children: [
939
+ /* @__PURE__ */ jsx(
940
+ "div",
941
+ {
942
+ style: { width: labelWidth, flexShrink: 0 },
943
+ className: "text-xs font-medium text-muted-foreground pr-3 break-words leading-snug",
944
+ children: item.label
945
+ }
946
+ ),
947
+ /* @__PURE__ */ jsx("div", { className: "flex-1 h-7 bg-muted/30 border border-border rounded-md relative overflow-visible", children: /* @__PURE__ */ jsx(
948
+ "button",
949
+ {
950
+ "data-testid": `${testId}-bar-${i}`,
951
+ "aria-label": item.label,
952
+ "aria-pressed": isActive,
953
+ style: {
954
+ left: `${leftPct}%`,
955
+ width: `${widthPct}%`,
956
+ background: color.gradient,
957
+ boxShadow: isActive ? "0 0 0 2px white, 0 0 0 4px #6366f1" : color.shadow
958
+ },
959
+ className: "absolute top-0.5 h-6 rounded text-white text-[9px] font-semibold px-2 overflow-hidden whitespace-nowrap cursor-pointer transition-[filter] hover:brightness-110 focus:outline-none",
960
+ onClick: () => select(isActive ? null : i),
961
+ children: formatBarLabel(startDate, endDate)
962
+ }
963
+ ) })
964
+ ] }, item.id);
965
+ })
966
+ ] })
967
+ ] }),
968
+ /* @__PURE__ */ jsx(
969
+ "div",
970
+ {
971
+ "data-testid": `${testId}-side-panel`,
972
+ className: cn(
973
+ "border-l bg-muted/20 flex flex-col shrink-0 overflow-hidden transition-all duration-300",
974
+ activeItem ? "w-60 open" : "w-0"
975
+ ),
976
+ children: /* @__PURE__ */ jsx(
977
+ "div",
978
+ {
979
+ className: cn(
980
+ "w-60 p-4 flex flex-col gap-3 transition-opacity duration-200",
981
+ activeItem ? "opacity-100" : "opacity-0"
982
+ ),
983
+ children: activeItem && /* @__PURE__ */ jsxs(Fragment, { children: [
984
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
985
+ "button",
986
+ {
987
+ "data-testid": `${testId}-panel-close`,
988
+ className: "w-6 h-6 rounded flex items-center justify-center text-muted-foreground hover:bg-muted",
989
+ onClick: () => select(null),
990
+ "aria-label": "Close panel",
991
+ children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
992
+ }
993
+ ) }),
994
+ /* @__PURE__ */ jsxs("div", { children: [
995
+ /* @__PURE__ */ jsx(
996
+ "div",
997
+ {
998
+ "data-testid": `${testId}-panel-title`,
999
+ className: "text-sm font-semibold text-foreground leading-snug",
1000
+ children: activeItem.label
1001
+ }
1002
+ ),
1003
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 mt-1 text-xs text-muted-foreground", children: [
1004
+ /* @__PURE__ */ jsx(Calendar, { className: "w-3 h-3 shrink-0" }),
1005
+ /* @__PURE__ */ jsx("span", { children: formatSpan(activeItem.start, activeItem.end) || "Date unknown" })
1006
+ ] })
1007
+ ] }),
1008
+ activeItem.description && /* @__PURE__ */ jsxs(Fragment, { children: [
1009
+ /* @__PURE__ */ jsx("hr", { className: "border-border" }),
1010
+ /* @__PURE__ */ jsxs("div", { children: [
1011
+ /* @__PURE__ */ jsx("div", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground mb-1", children: "Summary" }),
1012
+ /* @__PURE__ */ jsx(
1013
+ "p",
1014
+ {
1015
+ "data-testid": `${testId}-panel-desc`,
1016
+ className: "text-xs text-muted-foreground leading-relaxed",
1017
+ children: activeItem.description
1018
+ }
1019
+ )
1020
+ ] })
1021
+ ] }),
1022
+ detail && /* @__PURE__ */ jsxs(Fragment, { children: [
1023
+ /* @__PURE__ */ jsx("hr", { className: "border-border" }),
1024
+ detail
1025
+ ] })
1026
+ ] })
1027
+ }
1028
+ )
1029
+ }
1030
+ )
1031
+ ] });
1032
+ }
1033
+ var TOGGLE = [
1034
+ { mode: "calendar", label: "Calendar", Icon: CalendarDays },
1035
+ { mode: "gantt", label: "Gantt", Icon: GanttChartSquare }
1036
+ ];
1037
+ function Timeline({
1038
+ items,
1039
+ view,
1040
+ defaultView = "calendar",
1041
+ onSelect,
1042
+ renderDetail,
1043
+ emptyMessage,
1044
+ className,
1045
+ testId = "timeline"
1046
+ }) {
1047
+ const [picked, setPicked] = useState(defaultView);
1048
+ const mode = view ?? picked;
1049
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full min-h-0", className), "data-testid": testId, children: [
1050
+ !view && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 p-2 border-b border-border", children: TOGGLE.map(({ mode: m, label, Icon }) => /* @__PURE__ */ jsxs(
1051
+ "button",
1052
+ {
1053
+ type: "button",
1054
+ onClick: () => setPicked(m),
1055
+ "aria-pressed": mode === m,
1056
+ "data-testid": `${testId}-view-${m}`,
1057
+ className: cn(
1058
+ "flex items-center gap-1.5 rounded px-2 py-1 text-xs",
1059
+ mode === m ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"
1060
+ ),
1061
+ children: [
1062
+ /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5" }),
1063
+ label
1064
+ ]
1065
+ },
1066
+ m
1067
+ )) }),
1068
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0", children: mode === "calendar" ? /* @__PURE__ */ jsx(
1069
+ TimelineCalendar,
1070
+ {
1071
+ items,
1072
+ onSelect,
1073
+ testId: `${testId}-calendar`,
1074
+ emptyState: /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center p-8 text-sm text-muted-foreground", children: emptyMessage ?? "Nothing dated yet." })
1075
+ }
1076
+ ) : /* @__PURE__ */ jsx(
1077
+ TimelineGantt,
1078
+ {
1079
+ items,
1080
+ onSelect: (item) => item && onSelect?.(item),
1081
+ renderDetail,
1082
+ emptyMessage,
1083
+ testId: `${testId}-gantt`
1084
+ }
1085
+ ) })
1086
+ ] });
1087
+ }
588
1088
  function SectionHeading({
589
1089
  eyebrow,
590
1090
  title,
@@ -1492,6 +1992,6 @@ function TestimonialGrid({ items, columns = "3", testId }) {
1492
1992
  )) });
1493
1993
  }
1494
1994
 
1495
- export { ASSET_REF_PREFIX, Accordion, AssetResolverProvider, AvatarBlock, Banner, BlockImage, BlockLink, CTABanner, Callout, Columns, ContactForm, Container, FAQ, FONT_PAIRINGS, FeatureGrid, Footer, Gallery, Hero, ListBlock, LogoCloud, MediaText, Navbar, PricingTable, RichTextBlock, SectionHeading, Spacer, Steps, THEME_STYLE_ID, Tabs, TeamGrid, Testimonial, TestimonialGrid, ThemeEditor, VideoEmbed, applyFontVars, applyStoredTheme, applyThemeVars, asAssetRef, assetRefId, clearFontVars, clearThemeVars, createThemeStore, daysUntil, fmtDate, fmtDateTime, fontPackages, formatPageRefs, fromNow, gbp, getFontPairing, hrs, initials, isAssetRef, matchFontPairing, pct, tid, toEmbedUrl, toHslTriplet, useAssetRenderer, useAssetResolverActive };
1496
- //# sourceMappingURL=chunk-ETIYX2MO.js.map
1497
- //# sourceMappingURL=chunk-ETIYX2MO.js.map
1995
+ export { ASSET_REF_PREFIX, Accordion, AssetResolverProvider, AvatarBlock, Banner, BlockImage, BlockLink, CTABanner, Callout, Columns, ContactForm, Container, FAQ, FONT_PAIRINGS, FeatureGrid, Footer, Gallery, Hero, ListBlock, LogoCloud, MediaText, Navbar, PricingTable, RichTextBlock, SectionHeading, Spacer, Steps, THEME_STYLE_ID, Tabs, TeamGrid, Testimonial, TestimonialGrid, ThemeEditor, Timeline, TimelineCalendar, TimelineGantt, VideoEmbed, applyFontVars, applyStoredTheme, applyThemeVars, asAssetRef, assetRefId, clearFontVars, clearThemeVars, createThemeStore, dayKey, daysUntil, fmtDate, fmtDateTime, fontPackages, formatPageRefs, formatSpan, fromNow, gbp, getFontPairing, hrs, initials, isAssetRef, matchFontPairing, monthLabel, parseIso2 as parseIso, pct, tid, toEmbedUrl, toHslTriplet, useAssetRenderer, useAssetResolverActive, utcDay };
1996
+ //# sourceMappingURL=chunk-7ICEOZCE.js.map
1997
+ //# sourceMappingURL=chunk-7ICEOZCE.js.map