@almadar/ui 6.25.0 → 6.27.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.
@@ -34818,6 +34818,247 @@ var init_WizardNavigation = __esm({
34818
34818
  WizardNavigation.displayName = "WizardNavigation";
34819
34819
  }
34820
34820
  });
34821
+ function parseDay(value) {
34822
+ if (value === void 0 || value === null || value === "") return null;
34823
+ const d = value instanceof Date ? new Date(value.getTime()) : new Date(value);
34824
+ if (Number.isNaN(d.getTime())) return null;
34825
+ d.setHours(0, 0, 0, 0);
34826
+ return d;
34827
+ }
34828
+ function Gantt({
34829
+ tasks = [],
34830
+ links = [],
34831
+ titleField = "title",
34832
+ startField = "start",
34833
+ endField = "end",
34834
+ durationField,
34835
+ statusField = "status",
34836
+ groupField = "",
34837
+ rangeStart,
34838
+ rangeEnd,
34839
+ showToday = true,
34840
+ dayWidth = 28,
34841
+ barClickEvent,
34842
+ className,
34843
+ isLoading = false,
34844
+ error = null
34845
+ }) {
34846
+ const { t } = hooks.useTranslate();
34847
+ const placed = React96.useMemo(() => {
34848
+ const rows = Array.isArray(tasks) ? tasks : tasks ? [tasks] : [];
34849
+ const out = [];
34850
+ rows.forEach((row, idx) => {
34851
+ const start = parseDay(core.getNestedValue(row, startField));
34852
+ if (!start) return;
34853
+ let end = parseDay(core.getNestedValue(row, endField));
34854
+ if (!end && durationField) {
34855
+ const days2 = Number(core.getNestedValue(row, durationField));
34856
+ if (Number.isFinite(days2) && days2 > 0) {
34857
+ end = new Date(start.getTime() + days2 * DAY_MS);
34858
+ }
34859
+ }
34860
+ if (!end || end.getTime() < start.getTime()) end = new Date(start.getTime() + DAY_MS);
34861
+ out.push({
34862
+ row,
34863
+ id: String(row.id ?? idx),
34864
+ label: String(core.getNestedValue(row, titleField) ?? ""),
34865
+ status: String(core.getNestedValue(row, statusField) ?? "").toLowerCase(),
34866
+ group: groupField ? String(core.getNestedValue(row, groupField) ?? "") : "",
34867
+ start,
34868
+ end
34869
+ });
34870
+ });
34871
+ return out;
34872
+ }, [tasks, titleField, startField, endField, durationField, statusField, groupField]);
34873
+ const [axisStart, axisEnd] = React96.useMemo(() => {
34874
+ const lo = parseDay(rangeStart) ?? (placed.length ? new Date(Math.min(...placed.map((p) => p.start.getTime())) - 2 * DAY_MS) : new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)));
34875
+ const hi = parseDay(rangeEnd) ?? (placed.length ? new Date(Math.max(...placed.map((p) => p.end.getTime())) + 2 * DAY_MS) : new Date(lo.getTime() + 30 * DAY_MS));
34876
+ return hi.getTime() > lo.getTime() ? [lo, hi] : [lo, new Date(lo.getTime() + DAY_MS)];
34877
+ }, [rangeStart, rangeEnd, placed]);
34878
+ const totalDays = Math.round((axisEnd.getTime() - axisStart.getTime()) / DAY_MS);
34879
+ const chartWidth = totalDays * dayWidth;
34880
+ const dayOffset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
34881
+ const displayItems = React96.useMemo(() => {
34882
+ if (!groupField) return placed.map((task) => ({ kind: "task", task }));
34883
+ const items = [];
34884
+ const seen = /* @__PURE__ */ new Set();
34885
+ for (const task of placed) {
34886
+ if (!seen.has(task.group)) {
34887
+ seen.add(task.group);
34888
+ items.push({ kind: "group", label: task.group || "\u2014" });
34889
+ }
34890
+ items.push({ kind: "task", task });
34891
+ }
34892
+ return items;
34893
+ }, [placed, groupField]);
34894
+ const barGeometry = React96.useMemo(() => {
34895
+ const offset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
34896
+ const map = /* @__PURE__ */ new Map();
34897
+ displayItems.forEach((item, idx) => {
34898
+ if (item.kind !== "task") return;
34899
+ const x0 = offset(item.task.start);
34900
+ const x1 = Math.max(offset(item.task.end), x0 + dayWidth / 2);
34901
+ map.set(item.task.id, { x0, x1, y: HEADER_HEIGHT + idx * ROW_HEIGHT + ROW_HEIGHT / 2 });
34902
+ });
34903
+ return map;
34904
+ }, [displayItems, axisStart, dayWidth]);
34905
+ const days = React96.useMemo(() => {
34906
+ const out = [];
34907
+ for (let i = 0; i < totalDays; i++) out.push(new Date(axisStart.getTime() + i * DAY_MS));
34908
+ return out;
34909
+ }, [axisStart, totalDays]);
34910
+ const todayOffset = React96.useMemo(() => {
34911
+ const today = parseDay(/* @__PURE__ */ new Date());
34912
+ if (!today || today < axisStart || today > axisEnd) return null;
34913
+ return (today.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
34914
+ }, [axisStart, axisEnd, dayWidth]);
34915
+ if (isLoading) {
34916
+ return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
34917
+ }
34918
+ if (error) {
34919
+ return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-4", className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", color: "error", children: error.message }) });
34920
+ }
34921
+ if (placed.length === 0) {
34922
+ return /* @__PURE__ */ jsxRuntime.jsx(
34923
+ EmptyState,
34924
+ {
34925
+ title: t("empty.noData"),
34926
+ className
34927
+ }
34928
+ );
34929
+ }
34930
+ return /* @__PURE__ */ jsxRuntime.jsx(
34931
+ Box,
34932
+ {
34933
+ className: cn("w-full overflow-auto rounded-md border border-border bg-card", className),
34934
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "relative", style: { width: LABEL_WIDTH + chartWidth, minWidth: "100%" }, children: [
34935
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "none", className: "sticky top-0 z-20 bg-card border-b border-border", style: { height: HEADER_HEIGHT }, children: [
34936
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card border-r border-border", style: { width: LABEL_WIDTH, height: HEADER_HEIGHT } }),
34937
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "relative", style: { width: chartWidth, height: HEADER_HEIGHT }, children: days.map((day, i) => /* @__PURE__ */ jsxRuntime.jsx(
34938
+ Box,
34939
+ {
34940
+ className: cn(
34941
+ "absolute top-0 bottom-0 border-l border-border/50 flex items-end justify-center pb-1",
34942
+ day.getDay() === 0 || day.getDay() === 6 ? "bg-muted/40" : void 0
34943
+ ),
34944
+ style: { left: i * dayWidth, width: dayWidth },
34945
+ children: dayWidth >= 20 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: day.getDate() })
34946
+ },
34947
+ i
34948
+ )) })
34949
+ ] }),
34950
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "relative", children: [
34951
+ displayItems.map(
34952
+ (item, idx) => item.kind === "group" ? /* @__PURE__ */ jsxRuntime.jsxs(
34953
+ HStack,
34954
+ {
34955
+ gap: "none",
34956
+ className: "border-b border-border bg-muted/30",
34957
+ style: { height: ROW_HEIGHT },
34958
+ children: [
34959
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-muted/30 px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", weight: "semibold", children: item.label }) }),
34960
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { style: { width: chartWidth, height: ROW_HEIGHT } })
34961
+ ]
34962
+ },
34963
+ `g-${idx}`
34964
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
34965
+ HStack,
34966
+ {
34967
+ gap: "none",
34968
+ className: "border-b border-border/50",
34969
+ style: { height: ROW_HEIGHT },
34970
+ children: [
34971
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "truncate", children: item.task.label }) }),
34972
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "relative", style: { width: chartWidth, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsxRuntime.jsx(
34973
+ Box,
34974
+ {
34975
+ className: cn(
34976
+ "absolute top-1/2 -translate-y-1/2 h-4 rounded-sm transition-colors",
34977
+ STATUS_BAR[item.task.status] ?? "bg-primary/80 hover:bg-primary",
34978
+ barClickEvent ? "cursor-pointer" : void 0
34979
+ ),
34980
+ style: {
34981
+ left: dayOffset(item.task.start),
34982
+ width: Math.max(dayOffset(item.task.end) - dayOffset(item.task.start), dayWidth / 2)
34983
+ },
34984
+ action: barClickEvent,
34985
+ actionPayload: { id: item.task.id }
34986
+ }
34987
+ ) })
34988
+ ]
34989
+ },
34990
+ item.task.id
34991
+ )
34992
+ ),
34993
+ links.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
34994
+ "svg",
34995
+ {
34996
+ className: "absolute pointer-events-none",
34997
+ style: { left: LABEL_WIDTH, top: 0 },
34998
+ width: chartWidth,
34999
+ height: HEADER_HEIGHT + displayItems.length * ROW_HEIGHT,
35000
+ children: [
35001
+ /* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx("marker", { id: "gantt-arrow", markerWidth: "8", markerHeight: "8", refX: "7", refY: "4", orient: "auto", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M0,0 L8,4 L0,8 z", fill: "var(--muted-foreground, currentColor)" }) }) }),
35002
+ links.map((link, i) => {
35003
+ const from = barGeometry.get(link.from);
35004
+ const to = barGeometry.get(link.to);
35005
+ if (!from || !to) return null;
35006
+ const midX = from.x1 + Math.max(8, (to.x0 - from.x1) / 2);
35007
+ return /* @__PURE__ */ jsxRuntime.jsx(
35008
+ "path",
35009
+ {
35010
+ d: `M ${from.x1} ${from.y} L ${midX} ${from.y} L ${midX} ${to.y} L ${to.x0} ${to.y}`,
35011
+ fill: "none",
35012
+ stroke: "var(--muted-foreground, currentColor)",
35013
+ strokeWidth: 1.5,
35014
+ markerEnd: "url(#gantt-arrow)"
35015
+ },
35016
+ i
35017
+ );
35018
+ })
35019
+ ]
35020
+ }
35021
+ ),
35022
+ showToday && todayOffset !== null && /* @__PURE__ */ jsxRuntime.jsx(
35023
+ Box,
35024
+ {
35025
+ className: "absolute top-0 bottom-0 w-0.5 bg-error/70 pointer-events-none",
35026
+ style: { left: LABEL_WIDTH + todayOffset }
35027
+ }
35028
+ )
35029
+ ] })
35030
+ ] })
35031
+ }
35032
+ );
35033
+ }
35034
+ var DAY_MS, ROW_HEIGHT, HEADER_HEIGHT, LABEL_WIDTH, STATUS_BAR;
35035
+ var init_Gantt = __esm({
35036
+ "components/core/molecules/Gantt.tsx"() {
35037
+ "use client";
35038
+ init_cn();
35039
+ init_getNestedValue();
35040
+ init_Box();
35041
+ init_Stack();
35042
+ init_Typography();
35043
+ init_LoadingState();
35044
+ init_EmptyState();
35045
+ DAY_MS = 24 * 60 * 60 * 1e3;
35046
+ ROW_HEIGHT = 36;
35047
+ HEADER_HEIGHT = 44;
35048
+ LABEL_WIDTH = 192;
35049
+ STATUS_BAR = {
35050
+ complete: "bg-success/80 hover:bg-success",
35051
+ done: "bg-success/80 hover:bg-success",
35052
+ active: "bg-primary/80 hover:bg-primary",
35053
+ "in-progress": "bg-primary/80 hover:bg-primary",
35054
+ blocked: "bg-error/80 hover:bg-error",
35055
+ error: "bg-error/80 hover:bg-error",
35056
+ "at-risk": "bg-warning/80 hover:bg-warning",
35057
+ pending: "bg-muted-foreground/50 hover:bg-muted-foreground/70"
35058
+ };
35059
+ Gantt.displayName = "Gantt";
35060
+ }
35061
+ });
34821
35062
  var RepeatableFormSection;
34822
35063
  var init_RepeatableFormSection = __esm({
34823
35064
  "components/core/molecules/RepeatableFormSection.tsx"() {
@@ -53975,6 +54216,7 @@ var init_component_registry_generated = __esm({
53975
54216
  init_GameIcon();
53976
54217
  init_GameMenu();
53977
54218
  init_GameShell();
54219
+ init_Gantt();
53978
54220
  init_GenericAppTemplate();
53979
54221
  init_GeometricPattern();
53980
54222
  init_GradientDivider();
@@ -54254,6 +54496,7 @@ var init_component_registry_generated = __esm({
54254
54496
  "GameIcon": GameIcon,
54255
54497
  "GameMenu": GameMenu,
54256
54498
  "GameShell": GameShell,
54499
+ "Gantt": Gantt,
54257
54500
  "GenericAppTemplate": GenericAppTemplate,
54258
54501
  "GeometricPattern": GeometricPattern,
54259
54502
  "GradientDivider": GradientDivider,
@@ -60598,6 +60841,10 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60598
60841
  () => new Set(traits2.map((b) => b.trait.name).filter((n) => !!n)),
60599
60842
  [traits2]
60600
60843
  );
60844
+ const activeTraitNamesRef = React96.useRef(activeTraitNames);
60845
+ React96.useEffect(() => {
60846
+ activeTraitNamesRef.current = activeTraitNames;
60847
+ }, [activeTraitNames]);
60601
60848
  const withActiveTraits = React96.useCallback(
60602
60849
  (payload) => {
60603
60850
  if (!serverActiveTraits || serverActiveTraits.size === 0) return payload;
@@ -60622,7 +60869,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60622
60869
  }
60623
60870
  void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait).then(({ effects, meta }) => {
60624
60871
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60625
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
60872
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNamesRef.current, onNavigateBack);
60626
60873
  });
60627
60874
  }
60628
60875
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits]);
@@ -60685,7 +60932,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60685
60932
  effects: effectTraces,
60686
60933
  timestamp: Date.now()
60687
60934
  });
60688
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
60935
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNamesRef.current, onNavigateBack);
60689
60936
  }
60690
60937
  })();
60691
60938
  }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits, routeParams]);
package/dist/avl/index.js CHANGED
@@ -34742,6 +34742,247 @@ var init_WizardNavigation = __esm({
34742
34742
  WizardNavigation.displayName = "WizardNavigation";
34743
34743
  }
34744
34744
  });
34745
+ function parseDay(value) {
34746
+ if (value === void 0 || value === null || value === "") return null;
34747
+ const d = value instanceof Date ? new Date(value.getTime()) : new Date(value);
34748
+ if (Number.isNaN(d.getTime())) return null;
34749
+ d.setHours(0, 0, 0, 0);
34750
+ return d;
34751
+ }
34752
+ function Gantt({
34753
+ tasks = [],
34754
+ links = [],
34755
+ titleField = "title",
34756
+ startField = "start",
34757
+ endField = "end",
34758
+ durationField,
34759
+ statusField = "status",
34760
+ groupField = "",
34761
+ rangeStart,
34762
+ rangeEnd,
34763
+ showToday = true,
34764
+ dayWidth = 28,
34765
+ barClickEvent,
34766
+ className,
34767
+ isLoading = false,
34768
+ error = null
34769
+ }) {
34770
+ const { t } = useTranslate();
34771
+ const placed = useMemo(() => {
34772
+ const rows = Array.isArray(tasks) ? tasks : tasks ? [tasks] : [];
34773
+ const out = [];
34774
+ rows.forEach((row, idx) => {
34775
+ const start = parseDay(getNestedValue(row, startField));
34776
+ if (!start) return;
34777
+ let end = parseDay(getNestedValue(row, endField));
34778
+ if (!end && durationField) {
34779
+ const days2 = Number(getNestedValue(row, durationField));
34780
+ if (Number.isFinite(days2) && days2 > 0) {
34781
+ end = new Date(start.getTime() + days2 * DAY_MS);
34782
+ }
34783
+ }
34784
+ if (!end || end.getTime() < start.getTime()) end = new Date(start.getTime() + DAY_MS);
34785
+ out.push({
34786
+ row,
34787
+ id: String(row.id ?? idx),
34788
+ label: String(getNestedValue(row, titleField) ?? ""),
34789
+ status: String(getNestedValue(row, statusField) ?? "").toLowerCase(),
34790
+ group: groupField ? String(getNestedValue(row, groupField) ?? "") : "",
34791
+ start,
34792
+ end
34793
+ });
34794
+ });
34795
+ return out;
34796
+ }, [tasks, titleField, startField, endField, durationField, statusField, groupField]);
34797
+ const [axisStart, axisEnd] = useMemo(() => {
34798
+ const lo = parseDay(rangeStart) ?? (placed.length ? new Date(Math.min(...placed.map((p) => p.start.getTime())) - 2 * DAY_MS) : new Date((/* @__PURE__ */ new Date()).setHours(0, 0, 0, 0)));
34799
+ const hi = parseDay(rangeEnd) ?? (placed.length ? new Date(Math.max(...placed.map((p) => p.end.getTime())) + 2 * DAY_MS) : new Date(lo.getTime() + 30 * DAY_MS));
34800
+ return hi.getTime() > lo.getTime() ? [lo, hi] : [lo, new Date(lo.getTime() + DAY_MS)];
34801
+ }, [rangeStart, rangeEnd, placed]);
34802
+ const totalDays = Math.round((axisEnd.getTime() - axisStart.getTime()) / DAY_MS);
34803
+ const chartWidth = totalDays * dayWidth;
34804
+ const dayOffset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
34805
+ const displayItems = useMemo(() => {
34806
+ if (!groupField) return placed.map((task) => ({ kind: "task", task }));
34807
+ const items = [];
34808
+ const seen = /* @__PURE__ */ new Set();
34809
+ for (const task of placed) {
34810
+ if (!seen.has(task.group)) {
34811
+ seen.add(task.group);
34812
+ items.push({ kind: "group", label: task.group || "\u2014" });
34813
+ }
34814
+ items.push({ kind: "task", task });
34815
+ }
34816
+ return items;
34817
+ }, [placed, groupField]);
34818
+ const barGeometry = useMemo(() => {
34819
+ const offset = (d) => (d.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
34820
+ const map = /* @__PURE__ */ new Map();
34821
+ displayItems.forEach((item, idx) => {
34822
+ if (item.kind !== "task") return;
34823
+ const x0 = offset(item.task.start);
34824
+ const x1 = Math.max(offset(item.task.end), x0 + dayWidth / 2);
34825
+ map.set(item.task.id, { x0, x1, y: HEADER_HEIGHT + idx * ROW_HEIGHT + ROW_HEIGHT / 2 });
34826
+ });
34827
+ return map;
34828
+ }, [displayItems, axisStart, dayWidth]);
34829
+ const days = useMemo(() => {
34830
+ const out = [];
34831
+ for (let i = 0; i < totalDays; i++) out.push(new Date(axisStart.getTime() + i * DAY_MS));
34832
+ return out;
34833
+ }, [axisStart, totalDays]);
34834
+ const todayOffset = useMemo(() => {
34835
+ const today = parseDay(/* @__PURE__ */ new Date());
34836
+ if (!today || today < axisStart || today > axisEnd) return null;
34837
+ return (today.getTime() - axisStart.getTime()) / DAY_MS * dayWidth;
34838
+ }, [axisStart, axisEnd, dayWidth]);
34839
+ if (isLoading) {
34840
+ return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
34841
+ }
34842
+ if (error) {
34843
+ return /* @__PURE__ */ jsx(Box, { className: cn("p-4", className), children: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "error", children: error.message }) });
34844
+ }
34845
+ if (placed.length === 0) {
34846
+ return /* @__PURE__ */ jsx(
34847
+ EmptyState,
34848
+ {
34849
+ title: t("empty.noData"),
34850
+ className
34851
+ }
34852
+ );
34853
+ }
34854
+ return /* @__PURE__ */ jsx(
34855
+ Box,
34856
+ {
34857
+ className: cn("w-full overflow-auto rounded-md border border-border bg-card", className),
34858
+ children: /* @__PURE__ */ jsxs(Box, { className: "relative", style: { width: LABEL_WIDTH + chartWidth, minWidth: "100%" }, children: [
34859
+ /* @__PURE__ */ jsxs(HStack, { gap: "none", className: "sticky top-0 z-20 bg-card border-b border-border", style: { height: HEADER_HEIGHT }, children: [
34860
+ /* @__PURE__ */ jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card border-r border-border", style: { width: LABEL_WIDTH, height: HEADER_HEIGHT } }),
34861
+ /* @__PURE__ */ jsx(Box, { className: "relative", style: { width: chartWidth, height: HEADER_HEIGHT }, children: days.map((day, i) => /* @__PURE__ */ jsx(
34862
+ Box,
34863
+ {
34864
+ className: cn(
34865
+ "absolute top-0 bottom-0 border-l border-border/50 flex items-end justify-center pb-1",
34866
+ day.getDay() === 0 || day.getDay() === 6 ? "bg-muted/40" : void 0
34867
+ ),
34868
+ style: { left: i * dayWidth, width: dayWidth },
34869
+ children: dayWidth >= 20 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: day.getDate() })
34870
+ },
34871
+ i
34872
+ )) })
34873
+ ] }),
34874
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "relative", children: [
34875
+ displayItems.map(
34876
+ (item, idx) => item.kind === "group" ? /* @__PURE__ */ jsxs(
34877
+ HStack,
34878
+ {
34879
+ gap: "none",
34880
+ className: "border-b border-border bg-muted/30",
34881
+ style: { height: ROW_HEIGHT },
34882
+ children: [
34883
+ /* @__PURE__ */ jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-muted/30 px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsx(Typography, { variant: "caption", weight: "semibold", children: item.label }) }),
34884
+ /* @__PURE__ */ jsx(Box, { style: { width: chartWidth, height: ROW_HEIGHT } })
34885
+ ]
34886
+ },
34887
+ `g-${idx}`
34888
+ ) : /* @__PURE__ */ jsxs(
34889
+ HStack,
34890
+ {
34891
+ gap: "none",
34892
+ className: "border-b border-border/50",
34893
+ style: { height: ROW_HEIGHT },
34894
+ children: [
34895
+ /* @__PURE__ */ jsx(Box, { className: "sticky left-0 z-10 shrink-0 bg-card px-3 flex items-center border-r border-border", style: { width: LABEL_WIDTH, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "truncate", children: item.task.label }) }),
34896
+ /* @__PURE__ */ jsx(Box, { className: "relative", style: { width: chartWidth, height: ROW_HEIGHT }, children: /* @__PURE__ */ jsx(
34897
+ Box,
34898
+ {
34899
+ className: cn(
34900
+ "absolute top-1/2 -translate-y-1/2 h-4 rounded-sm transition-colors",
34901
+ STATUS_BAR[item.task.status] ?? "bg-primary/80 hover:bg-primary",
34902
+ barClickEvent ? "cursor-pointer" : void 0
34903
+ ),
34904
+ style: {
34905
+ left: dayOffset(item.task.start),
34906
+ width: Math.max(dayOffset(item.task.end) - dayOffset(item.task.start), dayWidth / 2)
34907
+ },
34908
+ action: barClickEvent,
34909
+ actionPayload: { id: item.task.id }
34910
+ }
34911
+ ) })
34912
+ ]
34913
+ },
34914
+ item.task.id
34915
+ )
34916
+ ),
34917
+ links.length > 0 && /* @__PURE__ */ jsxs(
34918
+ "svg",
34919
+ {
34920
+ className: "absolute pointer-events-none",
34921
+ style: { left: LABEL_WIDTH, top: 0 },
34922
+ width: chartWidth,
34923
+ height: HEADER_HEIGHT + displayItems.length * ROW_HEIGHT,
34924
+ children: [
34925
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("marker", { id: "gantt-arrow", markerWidth: "8", markerHeight: "8", refX: "7", refY: "4", orient: "auto", children: /* @__PURE__ */ jsx("path", { d: "M0,0 L8,4 L0,8 z", fill: "var(--muted-foreground, currentColor)" }) }) }),
34926
+ links.map((link, i) => {
34927
+ const from = barGeometry.get(link.from);
34928
+ const to = barGeometry.get(link.to);
34929
+ if (!from || !to) return null;
34930
+ const midX = from.x1 + Math.max(8, (to.x0 - from.x1) / 2);
34931
+ return /* @__PURE__ */ jsx(
34932
+ "path",
34933
+ {
34934
+ d: `M ${from.x1} ${from.y} L ${midX} ${from.y} L ${midX} ${to.y} L ${to.x0} ${to.y}`,
34935
+ fill: "none",
34936
+ stroke: "var(--muted-foreground, currentColor)",
34937
+ strokeWidth: 1.5,
34938
+ markerEnd: "url(#gantt-arrow)"
34939
+ },
34940
+ i
34941
+ );
34942
+ })
34943
+ ]
34944
+ }
34945
+ ),
34946
+ showToday && todayOffset !== null && /* @__PURE__ */ jsx(
34947
+ Box,
34948
+ {
34949
+ className: "absolute top-0 bottom-0 w-0.5 bg-error/70 pointer-events-none",
34950
+ style: { left: LABEL_WIDTH + todayOffset }
34951
+ }
34952
+ )
34953
+ ] })
34954
+ ] })
34955
+ }
34956
+ );
34957
+ }
34958
+ var DAY_MS, ROW_HEIGHT, HEADER_HEIGHT, LABEL_WIDTH, STATUS_BAR;
34959
+ var init_Gantt = __esm({
34960
+ "components/core/molecules/Gantt.tsx"() {
34961
+ "use client";
34962
+ init_cn();
34963
+ init_getNestedValue();
34964
+ init_Box();
34965
+ init_Stack();
34966
+ init_Typography();
34967
+ init_LoadingState();
34968
+ init_EmptyState();
34969
+ DAY_MS = 24 * 60 * 60 * 1e3;
34970
+ ROW_HEIGHT = 36;
34971
+ HEADER_HEIGHT = 44;
34972
+ LABEL_WIDTH = 192;
34973
+ STATUS_BAR = {
34974
+ complete: "bg-success/80 hover:bg-success",
34975
+ done: "bg-success/80 hover:bg-success",
34976
+ active: "bg-primary/80 hover:bg-primary",
34977
+ "in-progress": "bg-primary/80 hover:bg-primary",
34978
+ blocked: "bg-error/80 hover:bg-error",
34979
+ error: "bg-error/80 hover:bg-error",
34980
+ "at-risk": "bg-warning/80 hover:bg-warning",
34981
+ pending: "bg-muted-foreground/50 hover:bg-muted-foreground/70"
34982
+ };
34983
+ Gantt.displayName = "Gantt";
34984
+ }
34985
+ });
34745
34986
  var RepeatableFormSection;
34746
34987
  var init_RepeatableFormSection = __esm({
34747
34988
  "components/core/molecules/RepeatableFormSection.tsx"() {
@@ -53899,6 +54140,7 @@ var init_component_registry_generated = __esm({
53899
54140
  init_GameIcon();
53900
54141
  init_GameMenu();
53901
54142
  init_GameShell();
54143
+ init_Gantt();
53902
54144
  init_GenericAppTemplate();
53903
54145
  init_GeometricPattern();
53904
54146
  init_GradientDivider();
@@ -54178,6 +54420,7 @@ var init_component_registry_generated = __esm({
54178
54420
  "GameIcon": GameIcon,
54179
54421
  "GameMenu": GameMenu,
54180
54422
  "GameShell": GameShell,
54423
+ "Gantt": Gantt,
54181
54424
  "GenericAppTemplate": GenericAppTemplate,
54182
54425
  "GeometricPattern": GeometricPattern,
54183
54426
  "GradientDivider": GradientDivider,
@@ -60522,6 +60765,10 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60522
60765
  () => new Set(traits2.map((b) => b.trait.name).filter((n) => !!n)),
60523
60766
  [traits2]
60524
60767
  );
60768
+ const activeTraitNamesRef = useRef(activeTraitNames);
60769
+ useEffect(() => {
60770
+ activeTraitNamesRef.current = activeTraitNames;
60771
+ }, [activeTraitNames]);
60525
60772
  const withActiveTraits = useCallback(
60526
60773
  (payload) => {
60527
60774
  if (!serverActiveTraits || serverActiveTraits.size === 0) return payload;
@@ -60546,7 +60793,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60546
60793
  }
60547
60794
  void bridge.sendEvent(name, event, withActiveTraits(payload), void 0, void 0, locallyEmitted, results, entityByTrait).then(({ effects, meta }) => {
60548
60795
  recordServerResponse(name, event, { ...meta, effectResults: effectResultsToTraces(meta.effectResults) });
60549
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
60796
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNamesRef.current, onNavigateBack);
60550
60797
  });
60551
60798
  }
60552
60799
  }, [bridge.connected, bridge.sendEvent, orbitalNames, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits]);
@@ -60609,7 +60856,7 @@ function TraitInitializer({ traits: traits2, routeParams, orbitalNames, onNaviga
60609
60856
  effects: effectTraces,
60610
60857
  timestamp: Date.now()
60611
60858
  });
60612
- applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNames, onNavigateBack);
60859
+ applyServerEffects(effects, uiSlots, onNavigate, embeddedTraits, activeTraitNamesRef.current, onNavigateBack);
60613
60860
  }
60614
60861
  })();
60615
60862
  }, [bridge.connected, orbitalNames, bridge.sendEvent, uiSlots, onNavigate, onNavigateBack, embeddedTraits, activeTraitNames, withActiveTraits, routeParams]);