@devfellowship/components 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -726,6 +726,149 @@ function registerUxPaths(program2) {
726
726
  registerStamp(group);
727
727
  }
728
728
 
729
+ // src/cli/check-style-imports/index.ts
730
+ import { resolve as resolve6 } from "path";
731
+ import { existsSync as existsSync6 } from "fs";
732
+ import chalk9 from "chalk";
733
+
734
+ // src/cli/check-style-imports/detect.ts
735
+ import { readdirSync, readFileSync as readFileSync5 } from "fs";
736
+ import { join, relative, sep } from "path";
737
+ var SCAN_EXTENSIONS = [".css", ".scss", ".sass", ".less", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
738
+ var IGNORE_DIRS = /* @__PURE__ */ new Set([
739
+ "node_modules",
740
+ "dist",
741
+ "build",
742
+ ".git",
743
+ ".next",
744
+ ".expo",
745
+ "storybook-static",
746
+ "coverage",
747
+ ".turbo",
748
+ ".cache"
749
+ ]);
750
+ function importRegex(exportName) {
751
+ return new RegExp(
752
+ String.raw`(?:@import\s+url\(\s*|@import\s+|import\s+|require\(\s*)` + String.raw`['"]@devfellowship/components/${exportName}(?:\.css)?['"]`
753
+ );
754
+ }
755
+ var STYLES_RE = importRegex("styles");
756
+ var SHADCN_RE = importRegex("shadcn");
757
+ function detectInText(text, file = "<text>") {
758
+ const hits = [];
759
+ const lines = text.split(/\r?\n/);
760
+ for (let i = 0; i < lines.length; i++) {
761
+ const raw = lines[i];
762
+ if (STYLES_RE.test(raw)) {
763
+ hits.push({ file, line: i + 1, export: "styles", text: raw.trim() });
764
+ }
765
+ if (SHADCN_RE.test(raw)) {
766
+ hits.push({ file, line: i + 1, export: "shadcn", text: raw.trim() });
767
+ }
768
+ }
769
+ return hits;
770
+ }
771
+ function* walk(dir) {
772
+ let entries;
773
+ try {
774
+ entries = readdirSync(dir, { withFileTypes: true, encoding: "utf8" });
775
+ } catch {
776
+ return;
777
+ }
778
+ for (const entry of entries) {
779
+ const full = join(dir, entry.name);
780
+ if (entry.isDirectory()) {
781
+ if (IGNORE_DIRS.has(entry.name)) continue;
782
+ yield* walk(full);
783
+ } else if (entry.isFile()) {
784
+ const dot = entry.name.lastIndexOf(".");
785
+ if (dot < 0) continue;
786
+ const ext = entry.name.slice(dot);
787
+ if (SCAN_EXTENSIONS.includes(ext)) yield full;
788
+ }
789
+ }
790
+ }
791
+ function detectInDir(root) {
792
+ const hits = [];
793
+ for (const full of walk(root)) {
794
+ let text;
795
+ try {
796
+ text = readFileSync5(full, "utf8");
797
+ } catch {
798
+ continue;
799
+ }
800
+ const rel = relative(root, full).split(sep).join("/");
801
+ hits.push(...detectInText(text, rel));
802
+ }
803
+ return summarize(hits);
804
+ }
805
+ function summarize(hits) {
806
+ const styles = hits.filter((h) => h.export === "styles");
807
+ const shadcn = hits.filter((h) => h.export === "shadcn");
808
+ return {
809
+ hits,
810
+ styles,
811
+ shadcn,
812
+ conflict: styles.length > 0 && shadcn.length > 0
813
+ };
814
+ }
815
+
816
+ // src/cli/check-style-imports/index.ts
817
+ var DOC_URL = "https://github.com/devfellowship/dfl-components-cli#consuming-the-ds-styles-in-an-app";
818
+ function registerCheckStyleImports(program2) {
819
+ program2.command("check-style-imports [dir]").description(
820
+ "Fail if an app imports BOTH @devfellowship/components/styles and /shadcn (clobbers --background \u2192 transparent surfaces)."
821
+ ).option("--json", "Emit the raw detection result as JSON instead of a human report.").action((maybeDir, opts) => {
822
+ const root = resolve6(process.cwd(), maybeDir || ".");
823
+ if (!existsSync6(root)) {
824
+ console.error(chalk9.red("Directory not found:"), root);
825
+ process.exit(2);
826
+ }
827
+ const result = detectInDir(root);
828
+ if (opts.json) {
829
+ console.log(JSON.stringify(result, null, 2));
830
+ process.exit(result.conflict ? 1 : 0);
831
+ }
832
+ if (!result.conflict) {
833
+ if (result.hits.length === 0) {
834
+ console.log(
835
+ chalk9.green("OK"),
836
+ "no @devfellowship/components/{styles,shadcn} imports found."
837
+ );
838
+ } else {
839
+ const which = result.styles.length > 0 ? "styles" : "shadcn";
840
+ console.log(
841
+ chalk9.green("OK"),
842
+ `app imports only @devfellowship/components/${which} (${result.hits.length} reference${result.hits.length === 1 ? "" : "s"}).`
843
+ );
844
+ }
845
+ process.exit(0);
846
+ }
847
+ console.error(
848
+ chalk9.red("CONFLICT"),
849
+ "this app imports BOTH @devfellowship/components/styles AND /shadcn."
850
+ );
851
+ console.error(
852
+ chalk9.yellow(
853
+ "\nThese exports define the SAME CSS vars (--background, --primary, \u2026) in INCOMPATIBLE formats:\n - /styles ships them as HEX (#0A0908)\n - /shadcn ships them as HSL CHANNELS (30 11% 4%)\nImporting both clobbers --background \u2014 e.g. hsl(#0A0908) is invalid CSS \u2192 the\ndeclaration drops \u2192 surfaces render TRANSPARENT (the transparent-dialog bug).\n"
854
+ )
855
+ );
856
+ console.error(chalk9.bold(" /styles imports:"));
857
+ for (const h of result.styles) console.error(` ${h.file}:${h.line} ${h.text}`);
858
+ console.error(chalk9.bold(" /shadcn imports:"));
859
+ for (const h of result.shadcn) console.error(` ${h.file}:${h.line} ${h.text}`);
860
+ console.error(
861
+ chalk9.cyan(
862
+ `
863
+ FIX: keep exactly ONE. A DS-native (hex) app imports /styles only; a
864
+ shadcn-slate (HSL-channel) app imports /shadcn only. NEVER both.
865
+ See: ${DOC_URL}`
866
+ )
867
+ );
868
+ process.exit(1);
869
+ });
870
+ }
871
+
729
872
  // src/cli/index.ts
730
873
  var program = new Command();
731
874
  program.name("dfl-components").description(
@@ -734,4 +877,5 @@ program.name("dfl-components").description(
734
877
  program.command("init").description("Initialize your project with dfl-components configuration").option("-y, --yes", "Skip prompts and use defaults").option("-c, --cwd <path>", "Working directory", process.cwd()).action(init);
735
878
  program.command("add").description("Add a component to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation prompts").option("-o, --overwrite", "Overwrite existing files").option("-c, --cwd <path>", "Working directory", process.cwd()).option("-a, --all", "Add all available components").action(add);
736
879
  registerUxPaths(program);
880
+ registerCheckStyleImports(program);
737
881
  program.parse();
package/dist/index.cjs CHANGED
@@ -112,6 +112,7 @@ __export(src_exports, {
112
112
  ContextMenuSubContent: () => ContextMenuSubContent,
113
113
  ContextMenuSubTrigger: () => ContextMenuSubTrigger,
114
114
  ContextMenuTrigger: () => ContextMenuTrigger,
115
+ DEFAULT_NAME_COL_WIDTH: () => DEFAULT_NAME_COL_WIDTH,
115
116
  DflRemote: () => DflRemote,
116
117
  Dialog: () => Dialog,
117
118
  DialogClose: () => DialogClose,
@@ -311,6 +312,7 @@ __export(src_exports, {
311
312
  memberHueVar: () => memberHueVar,
312
313
  navigationMenuTriggerStyle: () => navigationMenuTriggerStyle,
313
314
  parseTags: () => parseTags,
315
+ resolveNameColWidth: () => resolveNameColWidth,
314
316
  resolveWeekCount: () => resolveWeekCount,
315
317
  resolveWeekLabels: () => resolveWeekLabels,
316
318
  stageProgress: () => stageProgress,
@@ -5074,6 +5076,12 @@ function AppNavbar({
5074
5076
  // src/components/organisms/Gantt.tsx
5075
5077
  var React44 = __toESM(require("react"), 1);
5076
5078
  var import_jsx_runtime63 = require("react/jsx-runtime");
5079
+ var DEFAULT_NAME_COL_WIDTH = 320;
5080
+ function resolveNameColWidth(nameColWidth, labelWidth) {
5081
+ if (typeof nameColWidth === "number" && nameColWidth > 0) return Math.round(nameColWidth);
5082
+ if (typeof labelWidth === "number" && labelWidth > 0) return Math.round(labelWidth);
5083
+ return DEFAULT_NAME_COL_WIDTH;
5084
+ }
5077
5085
  function clampPct(value) {
5078
5086
  if (value == null || Number.isNaN(value)) return 0;
5079
5087
  return Math.max(0, Math.min(100, Math.round(value)));
@@ -5116,14 +5124,17 @@ function Gantt({
5116
5124
  rowsHeader = "Stage / Task",
5117
5125
  stagesOnly = false,
5118
5126
  header,
5119
- labelWidth = 240,
5127
+ labelWidth,
5128
+ nameColWidth,
5120
5129
  weekMinWidth = 64,
5130
+ onMilestoneClick,
5121
5131
  className,
5122
5132
  style,
5123
5133
  ...rest
5124
5134
  }) {
5125
5135
  const weekCount = resolveWeekCount(stages, weeks);
5126
5136
  const weekLabels = resolveWeekLabels(weekCount, weeks);
5137
+ const nameWidth = resolveNameColWidth(nameColWidth, labelWidth);
5127
5138
  const [collapsed, setCollapsed] = React44.useState(
5128
5139
  () => Object.fromEntries(stages.filter((s) => s.collapsed).map((s) => [s.id, true]))
5129
5140
  );
@@ -5164,7 +5175,8 @@ function Gantt({
5164
5175
  window.addEventListener("resize", handler);
5165
5176
  return () => window.removeEventListener("resize", handler);
5166
5177
  }, [dependencies.length, recomputeEdges]);
5167
- const trackTemplate = `${labelWidth}px repeat(${weekCount}, minmax(${weekMinWidth}px, 1fr))`;
5178
+ const trackTemplate = `${nameWidth}px repeat(${weekCount}, minmax(${weekMinWidth}px, 1fr))`;
5179
+ const stickyCol = "sticky left-0 z-20 after:absolute after:inset-y-0 after:right-0 after:w-px after:bg-[var(--s-border-subtle,#2A2622)]";
5168
5180
  return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5169
5181
  "div",
5170
5182
  {
@@ -5227,7 +5239,16 @@ function Gantt({
5227
5239
  className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-raised,#1A1714)]",
5228
5240
  style: { gridTemplateColumns: trackTemplate },
5229
5241
  children: [
5230
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("div", { className: "px-4 py-2.5 font-[var(--s-font-mono,monospace)] text-[10.5px] font-medium uppercase tracking-[0.6px] text-[var(--s-ink-muted,#7D7568)]", children: rowsHeader }),
5242
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5243
+ "div",
5244
+ {
5245
+ className: cn(
5246
+ stickyCol,
5247
+ "bg-[var(--s-surface-raised,#1A1714)] px-4 py-2.5 font-[var(--s-font-mono,monospace)] text-[10.5px] font-medium uppercase tracking-[0.6px] text-[var(--s-ink-muted,#7D7568)]"
5248
+ ),
5249
+ children: rowsHeader
5250
+ }
5251
+ ),
5231
5252
  weekLabels.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5232
5253
  "div",
5233
5254
  {
@@ -5258,7 +5279,10 @@ function Gantt({
5258
5279
  {
5259
5280
  type: "button",
5260
5281
  onClick: () => toggle(stage.id),
5261
- className: "flex items-center gap-2 px-4 py-3 text-left hover:bg-[var(--s-surface-raised,#1A1714)] transition-colors",
5282
+ className: cn(
5283
+ stickyCol,
5284
+ "flex items-center gap-2 bg-[var(--s-surface-panel,#141210)] px-4 py-3 text-left transition-colors hover:bg-[var(--s-surface-raised,#1A1714)]"
5285
+ ),
5262
5286
  "aria-expanded": !isCollapsed,
5263
5287
  children: [
5264
5288
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Chevron, { open: !isCollapsed }),
@@ -5270,8 +5294,22 @@ function Gantt({
5270
5294
  }
5271
5295
  ),
5272
5296
  /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "min-w-0", children: [
5273
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "block truncate text-[13px] font-semibold text-[var(--s-ink-primary,#F6F1E7)]", children: stage.title }),
5274
- stage.subtitle && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "block truncate text-[11px] text-[var(--s-ink-muted,#7D7568)]", children: stage.subtitle })
5297
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5298
+ "span",
5299
+ {
5300
+ className: "block truncate text-[13px] font-semibold text-[var(--s-ink-primary,#F6F1E7)]",
5301
+ title: stage.title,
5302
+ children: stage.title
5303
+ }
5304
+ ),
5305
+ stage.subtitle && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5306
+ "span",
5307
+ {
5308
+ className: "block truncate text-[11px] text-[var(--s-ink-muted,#7D7568)]",
5309
+ title: stage.subtitle,
5310
+ children: stage.subtitle
5311
+ }
5312
+ )
5275
5313
  ] }),
5276
5314
  ms.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("span", { className: "ml-auto shrink-0 rounded-[var(--c-badge-radius,4px)] bg-[var(--s-surface-elevated,#1F1C18)] px-1.5 py-0.5 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-secondary,#C9C0B4)]", children: [
5277
5315
  done,
@@ -5330,20 +5368,42 @@ function Gantt({
5330
5368
  className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-page,#0A0908)]",
5331
5369
  style: { gridTemplateColumns: trackTemplate },
5332
5370
  children: [
5333
- /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex items-center gap-2 py-2 pl-10 pr-4", children: [
5334
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(StatusDot, { done: m.done, color: dot }),
5335
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5336
- "span",
5337
- {
5338
- className: cn(
5339
- "min-w-0 flex-1 truncate text-[13px]",
5340
- m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5371
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(
5372
+ "div",
5373
+ {
5374
+ className: cn(
5375
+ stickyCol,
5376
+ "flex items-center gap-2 bg-[var(--s-surface-page,#0A0908)] py-2 pl-10 pr-4"
5377
+ ),
5378
+ children: [
5379
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(StatusDot, { done: m.done, color: dot }),
5380
+ onMilestoneClick ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5381
+ "button",
5382
+ {
5383
+ type: "button",
5384
+ onClick: () => onMilestoneClick(m, stage),
5385
+ title: m.title,
5386
+ className: cn(
5387
+ "min-w-0 flex-1 truncate rounded-[var(--p-radius-sm,4px)] text-left text-[13px] transition-colors hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--s-brand-solid,#E07A4A)]",
5388
+ m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5389
+ ),
5390
+ children: m.title
5391
+ }
5392
+ ) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5393
+ "span",
5394
+ {
5395
+ className: cn(
5396
+ "min-w-0 flex-1 truncate text-[13px]",
5397
+ m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5398
+ ),
5399
+ title: m.title,
5400
+ children: m.title
5401
+ }
5341
5402
  ),
5342
- children: m.title
5343
- }
5344
- ),
5345
- m.points != null && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "shrink-0 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-muted,#7D7568)]", children: m.points })
5346
- ] }),
5403
+ m.points != null && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: "shrink-0 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-muted,#7D7568)]", children: m.points })
5404
+ ]
5405
+ }
5406
+ ),
5347
5407
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5348
5408
  "div",
5349
5409
  {
@@ -5896,6 +5956,7 @@ var useFeatureFlags = () => {
5896
5956
  ContextMenuSubContent,
5897
5957
  ContextMenuSubTrigger,
5898
5958
  ContextMenuTrigger,
5959
+ DEFAULT_NAME_COL_WIDTH,
5899
5960
  DflRemote,
5900
5961
  Dialog,
5901
5962
  DialogClose,
@@ -6095,6 +6156,7 @@ var useFeatureFlags = () => {
6095
6156
  memberHueVar,
6096
6157
  navigationMenuTriggerStyle,
6097
6158
  parseTags,
6159
+ resolveNameColWidth,
6098
6160
  resolveWeekCount,
6099
6161
  resolveWeekLabels,
6100
6162
  stageProgress,
package/dist/index.d.cts CHANGED
@@ -985,11 +985,33 @@ interface GanttProps extends React$1.HTMLAttributes<HTMLDivElement> {
985
985
  stagesOnly?: boolean;
986
986
  /** Optional header strip (e.g. member + per-stage progress pills). */
987
987
  header?: React$1.ReactNode;
988
- /** Px width of the left rows column. Defaults to 240. */
988
+ /**
989
+ * Px width of the left (sticky) name column.
990
+ * @deprecated prefer `nameColWidth` — kept as a fallback for back-compat.
991
+ */
989
992
  labelWidth?: number;
993
+ /**
994
+ * Px width of the left (sticky) STAGE/TASK name column. Takes precedence
995
+ * over `labelWidth`. Defaults to 320 — wide enough that long stage/task
996
+ * titles read in full; overflow ellipsizes with a native tooltip. Bump this
997
+ * higher (e.g. 420) on full-width pages where you have the room.
998
+ */
999
+ nameColWidth?: number;
990
1000
  /** Min px width of a single week column. Defaults to 64. */
991
1001
  weekMinWidth?: number;
1002
+ /**
1003
+ * Optional click handler for a milestone. When provided, each milestone's
1004
+ * name-column cell becomes a keyboard-accessible button that invokes this
1005
+ * callback with the milestone and its parent stage. When omitted, milestone
1006
+ * rows render exactly as before (a non-interactive cell) — fully
1007
+ * backward-compatible, so existing consumers are unaffected.
1008
+ */
1009
+ onMilestoneClick?: (milestone: GanttMilestone, stage: GanttStage) => void;
992
1010
  }
1011
+ /** Default width of the sticky name column. ~2× the original 240 → readable. */
1012
+ declare const DEFAULT_NAME_COL_WIDTH = 320;
1013
+ /** Resolve the effective name-column width: `nameColWidth` > `labelWidth` > default. */
1014
+ declare function resolveNameColWidth(nameColWidth?: number, labelWidth?: number): number;
993
1015
  /** Clamp a 0..100 percentage to an integer. */
994
1016
  declare function clampPct(value: number | undefined): number;
995
1017
  /** Progress for a stage: explicit `progress`, else done/total of milestones. */
@@ -1006,7 +1028,7 @@ declare function barGridColumn(weekStart: number, weekSpan: number, weekCount: n
1006
1028
  start: number;
1007
1029
  span: number;
1008
1030
  };
1009
- declare function Gantt({ stages, weeks, dependencies, rowsHeader, stagesOnly, header, labelWidth, weekMinWidth, className, style, ...rest }: GanttProps): react_jsx_runtime.JSX.Element;
1031
+ declare function Gantt({ stages, weeks, dependencies, rowsHeader, stagesOnly, header, labelWidth, nameColWidth, weekMinWidth, onMilestoneClick, className, style, ...rest }: GanttProps): react_jsx_runtime.JSX.Element;
1010
1032
 
1011
1033
  /** Minimal subset of `@supabase/supabase-js` SupabaseClient we rely on.
1012
1034
  * Kept structural so the package never hard-depends on supabase-js. */
@@ -1083,4 +1105,4 @@ declare function validatePublishForm(input: {
1083
1105
  }): string | null;
1084
1106
  declare function PublishDrawer({ open, onOpenChange, supabase, videoUrl, transcript, suggestedTitle, suggestedDescription, suggestedThumbnailUrl, thumbnailTemplateId, buId, registerLesson, onPublished, onError, className, }: PublishDrawerProps): react_jsx_runtime.JSX.Element;
1085
1107
 
1086
- export { ALLOWED_ORIGINS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppNavbar, type AppNavbarProps, AppSidebar, type AppSidebarProps, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEntry, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, type DflIframeMessage, type DflNavigateMessage, type DflReadyMessage, DflRemote, type DflRemoteProps, type DflResizeMessage, type DflSetTokenMessage, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Gantt, type GanttDependency, type GanttMilestone, type GanttProps, type GanttStage, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, type IconButtonProps, IframeAware, type IframeAwareProps, IframeContext, type IframeContextValue, type IframeMessageType, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Kbd, type KbdProps, Label, LoginPage, type LoginPageProps, LoginScreen, type LoginScreenProps, MEMBER_PALETTE_SIZE, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavGroup, type NavItem, type NavbarUserInfo, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, type PasswordInputProps, Popover, PopoverContent, PopoverTrigger, Progress, ProtectedRoute, type ProtectedRouteProps, PublishDrawer, type PublishDrawerProps, type PublishDrawerSupabase, type PublishResult, type PublishStatus, type PublisherAccount, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SonnerToaster, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, Toast, ToastAction, type ToastActionElement, ToastClose, type ToastComponentProps, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatar, type UserAvatarProps, type UserInfo, UserMenu, type UserMenuItem, type UserMenuProps, badgeVariants, barGridColumn, buttonVariants, clampPct, filterPublishableAccounts, getInitials, iconButtonVariants, isAllowedOrigin, kbdVariants, labelVariants, memberHueIndex, memberHueVar, navigationMenuTriggerStyle, parseTags, resolveWeekCount, resolveWeekLabels, stageProgress, toggleVariants, useFormField, useSidebar, validatePublishForm };
1108
+ export { ALLOWED_ORIGINS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppNavbar, type AppNavbarProps, AppSidebar, type AppSidebarProps, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEntry, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_NAME_COL_WIDTH, type DflIframeMessage, type DflNavigateMessage, type DflReadyMessage, DflRemote, type DflRemoteProps, type DflResizeMessage, type DflSetTokenMessage, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Gantt, type GanttDependency, type GanttMilestone, type GanttProps, type GanttStage, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, type IconButtonProps, IframeAware, type IframeAwareProps, IframeContext, type IframeContextValue, type IframeMessageType, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Kbd, type KbdProps, Label, LoginPage, type LoginPageProps, LoginScreen, type LoginScreenProps, MEMBER_PALETTE_SIZE, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavGroup, type NavItem, type NavbarUserInfo, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, type PasswordInputProps, Popover, PopoverContent, PopoverTrigger, Progress, ProtectedRoute, type ProtectedRouteProps, PublishDrawer, type PublishDrawerProps, type PublishDrawerSupabase, type PublishResult, type PublishStatus, type PublisherAccount, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SonnerToaster, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, Toast, ToastAction, type ToastActionElement, ToastClose, type ToastComponentProps, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatar, type UserAvatarProps, type UserInfo, UserMenu, type UserMenuItem, type UserMenuProps, badgeVariants, barGridColumn, buttonVariants, clampPct, filterPublishableAccounts, getInitials, iconButtonVariants, isAllowedOrigin, kbdVariants, labelVariants, memberHueIndex, memberHueVar, navigationMenuTriggerStyle, parseTags, resolveNameColWidth, resolveWeekCount, resolveWeekLabels, stageProgress, toggleVariants, useFormField, useSidebar, validatePublishForm };
package/dist/index.d.ts CHANGED
@@ -985,11 +985,33 @@ interface GanttProps extends React$1.HTMLAttributes<HTMLDivElement> {
985
985
  stagesOnly?: boolean;
986
986
  /** Optional header strip (e.g. member + per-stage progress pills). */
987
987
  header?: React$1.ReactNode;
988
- /** Px width of the left rows column. Defaults to 240. */
988
+ /**
989
+ * Px width of the left (sticky) name column.
990
+ * @deprecated prefer `nameColWidth` — kept as a fallback for back-compat.
991
+ */
989
992
  labelWidth?: number;
993
+ /**
994
+ * Px width of the left (sticky) STAGE/TASK name column. Takes precedence
995
+ * over `labelWidth`. Defaults to 320 — wide enough that long stage/task
996
+ * titles read in full; overflow ellipsizes with a native tooltip. Bump this
997
+ * higher (e.g. 420) on full-width pages where you have the room.
998
+ */
999
+ nameColWidth?: number;
990
1000
  /** Min px width of a single week column. Defaults to 64. */
991
1001
  weekMinWidth?: number;
1002
+ /**
1003
+ * Optional click handler for a milestone. When provided, each milestone's
1004
+ * name-column cell becomes a keyboard-accessible button that invokes this
1005
+ * callback with the milestone and its parent stage. When omitted, milestone
1006
+ * rows render exactly as before (a non-interactive cell) — fully
1007
+ * backward-compatible, so existing consumers are unaffected.
1008
+ */
1009
+ onMilestoneClick?: (milestone: GanttMilestone, stage: GanttStage) => void;
992
1010
  }
1011
+ /** Default width of the sticky name column. ~2× the original 240 → readable. */
1012
+ declare const DEFAULT_NAME_COL_WIDTH = 320;
1013
+ /** Resolve the effective name-column width: `nameColWidth` > `labelWidth` > default. */
1014
+ declare function resolveNameColWidth(nameColWidth?: number, labelWidth?: number): number;
993
1015
  /** Clamp a 0..100 percentage to an integer. */
994
1016
  declare function clampPct(value: number | undefined): number;
995
1017
  /** Progress for a stage: explicit `progress`, else done/total of milestones. */
@@ -1006,7 +1028,7 @@ declare function barGridColumn(weekStart: number, weekSpan: number, weekCount: n
1006
1028
  start: number;
1007
1029
  span: number;
1008
1030
  };
1009
- declare function Gantt({ stages, weeks, dependencies, rowsHeader, stagesOnly, header, labelWidth, weekMinWidth, className, style, ...rest }: GanttProps): react_jsx_runtime.JSX.Element;
1031
+ declare function Gantt({ stages, weeks, dependencies, rowsHeader, stagesOnly, header, labelWidth, nameColWidth, weekMinWidth, onMilestoneClick, className, style, ...rest }: GanttProps): react_jsx_runtime.JSX.Element;
1010
1032
 
1011
1033
  /** Minimal subset of `@supabase/supabase-js` SupabaseClient we rely on.
1012
1034
  * Kept structural so the package never hard-depends on supabase-js. */
@@ -1083,4 +1105,4 @@ declare function validatePublishForm(input: {
1083
1105
  }): string | null;
1084
1106
  declare function PublishDrawer({ open, onOpenChange, supabase, videoUrl, transcript, suggestedTitle, suggestedDescription, suggestedThumbnailUrl, thumbnailTemplateId, buId, registerLesson, onPublished, onError, className, }: PublishDrawerProps): react_jsx_runtime.JSX.Element;
1085
1107
 
1086
- export { ALLOWED_ORIGINS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppNavbar, type AppNavbarProps, AppSidebar, type AppSidebarProps, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEntry, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, type DflIframeMessage, type DflNavigateMessage, type DflReadyMessage, DflRemote, type DflRemoteProps, type DflResizeMessage, type DflSetTokenMessage, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Gantt, type GanttDependency, type GanttMilestone, type GanttProps, type GanttStage, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, type IconButtonProps, IframeAware, type IframeAwareProps, IframeContext, type IframeContextValue, type IframeMessageType, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Kbd, type KbdProps, Label, LoginPage, type LoginPageProps, LoginScreen, type LoginScreenProps, MEMBER_PALETTE_SIZE, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavGroup, type NavItem, type NavbarUserInfo, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, type PasswordInputProps, Popover, PopoverContent, PopoverTrigger, Progress, ProtectedRoute, type ProtectedRouteProps, PublishDrawer, type PublishDrawerProps, type PublishDrawerSupabase, type PublishResult, type PublishStatus, type PublisherAccount, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SonnerToaster, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, Toast, ToastAction, type ToastActionElement, ToastClose, type ToastComponentProps, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatar, type UserAvatarProps, type UserInfo, UserMenu, type UserMenuItem, type UserMenuProps, badgeVariants, barGridColumn, buttonVariants, clampPct, filterPublishableAccounts, getInitials, iconButtonVariants, isAllowedOrigin, kbdVariants, labelVariants, memberHueIndex, memberHueVar, navigationMenuTriggerStyle, parseTags, resolveWeekCount, resolveWeekLabels, stageProgress, toggleVariants, useFormField, useSidebar, validatePublishForm };
1108
+ export { ALLOWED_ORIGINS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppNavbar, type AppNavbarProps, AppSidebar, type AppSidebarProps, AspectRatio, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEntry, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_NAME_COL_WIDTH, type DflIframeMessage, type DflNavigateMessage, type DflReadyMessage, DflRemote, type DflRemoteProps, type DflResizeMessage, type DflSetTokenMessage, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Gantt, type GanttDependency, type GanttMilestone, type GanttProps, type GanttStage, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, type IconButtonProps, IframeAware, type IframeAwareProps, IframeContext, type IframeContextValue, type IframeMessageType, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Kbd, type KbdProps, Label, LoginPage, type LoginPageProps, LoginScreen, type LoginScreenProps, MEMBER_PALETTE_SIZE, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavGroup, type NavItem, type NavbarUserInfo, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, type PasswordInputProps, Popover, PopoverContent, PopoverTrigger, Progress, ProtectedRoute, type ProtectedRouteProps, PublishDrawer, type PublishDrawerProps, type PublishDrawerSupabase, type PublishResult, type PublishStatus, type PublisherAccount, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SonnerToaster, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, Toast, ToastAction, type ToastActionElement, ToastClose, type ToastComponentProps, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatar, type UserAvatarProps, type UserInfo, UserMenu, type UserMenuItem, type UserMenuProps, badgeVariants, barGridColumn, buttonVariants, clampPct, filterPublishableAccounts, getInitials, iconButtonVariants, isAllowedOrigin, kbdVariants, labelVariants, memberHueIndex, memberHueVar, navigationMenuTriggerStyle, parseTags, resolveNameColWidth, resolveWeekCount, resolveWeekLabels, stageProgress, toggleVariants, useFormField, useSidebar, validatePublishForm };
package/dist/index.js CHANGED
@@ -4754,6 +4754,12 @@ function AppNavbar({
4754
4754
  // src/components/organisms/Gantt.tsx
4755
4755
  import * as React44 from "react";
4756
4756
  import { jsx as jsx63, jsxs as jsxs31 } from "react/jsx-runtime";
4757
+ var DEFAULT_NAME_COL_WIDTH = 320;
4758
+ function resolveNameColWidth(nameColWidth, labelWidth) {
4759
+ if (typeof nameColWidth === "number" && nameColWidth > 0) return Math.round(nameColWidth);
4760
+ if (typeof labelWidth === "number" && labelWidth > 0) return Math.round(labelWidth);
4761
+ return DEFAULT_NAME_COL_WIDTH;
4762
+ }
4757
4763
  function clampPct(value) {
4758
4764
  if (value == null || Number.isNaN(value)) return 0;
4759
4765
  return Math.max(0, Math.min(100, Math.round(value)));
@@ -4796,14 +4802,17 @@ function Gantt({
4796
4802
  rowsHeader = "Stage / Task",
4797
4803
  stagesOnly = false,
4798
4804
  header,
4799
- labelWidth = 240,
4805
+ labelWidth,
4806
+ nameColWidth,
4800
4807
  weekMinWidth = 64,
4808
+ onMilestoneClick,
4801
4809
  className,
4802
4810
  style,
4803
4811
  ...rest
4804
4812
  }) {
4805
4813
  const weekCount = resolveWeekCount(stages, weeks);
4806
4814
  const weekLabels = resolveWeekLabels(weekCount, weeks);
4815
+ const nameWidth = resolveNameColWidth(nameColWidth, labelWidth);
4807
4816
  const [collapsed, setCollapsed] = React44.useState(
4808
4817
  () => Object.fromEntries(stages.filter((s) => s.collapsed).map((s) => [s.id, true]))
4809
4818
  );
@@ -4844,7 +4853,8 @@ function Gantt({
4844
4853
  window.addEventListener("resize", handler);
4845
4854
  return () => window.removeEventListener("resize", handler);
4846
4855
  }, [dependencies.length, recomputeEdges]);
4847
- const trackTemplate = `${labelWidth}px repeat(${weekCount}, minmax(${weekMinWidth}px, 1fr))`;
4856
+ const trackTemplate = `${nameWidth}px repeat(${weekCount}, minmax(${weekMinWidth}px, 1fr))`;
4857
+ const stickyCol = "sticky left-0 z-20 after:absolute after:inset-y-0 after:right-0 after:w-px after:bg-[var(--s-border-subtle,#2A2622)]";
4848
4858
  return /* @__PURE__ */ jsxs31(
4849
4859
  "div",
4850
4860
  {
@@ -4907,7 +4917,16 @@ function Gantt({
4907
4917
  className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-raised,#1A1714)]",
4908
4918
  style: { gridTemplateColumns: trackTemplate },
4909
4919
  children: [
4910
- /* @__PURE__ */ jsx63("div", { className: "px-4 py-2.5 font-[var(--s-font-mono,monospace)] text-[10.5px] font-medium uppercase tracking-[0.6px] text-[var(--s-ink-muted,#7D7568)]", children: rowsHeader }),
4920
+ /* @__PURE__ */ jsx63(
4921
+ "div",
4922
+ {
4923
+ className: cn(
4924
+ stickyCol,
4925
+ "bg-[var(--s-surface-raised,#1A1714)] px-4 py-2.5 font-[var(--s-font-mono,monospace)] text-[10.5px] font-medium uppercase tracking-[0.6px] text-[var(--s-ink-muted,#7D7568)]"
4926
+ ),
4927
+ children: rowsHeader
4928
+ }
4929
+ ),
4911
4930
  weekLabels.map((label, i) => /* @__PURE__ */ jsx63(
4912
4931
  "div",
4913
4932
  {
@@ -4938,7 +4957,10 @@ function Gantt({
4938
4957
  {
4939
4958
  type: "button",
4940
4959
  onClick: () => toggle(stage.id),
4941
- className: "flex items-center gap-2 px-4 py-3 text-left hover:bg-[var(--s-surface-raised,#1A1714)] transition-colors",
4960
+ className: cn(
4961
+ stickyCol,
4962
+ "flex items-center gap-2 bg-[var(--s-surface-panel,#141210)] px-4 py-3 text-left transition-colors hover:bg-[var(--s-surface-raised,#1A1714)]"
4963
+ ),
4942
4964
  "aria-expanded": !isCollapsed,
4943
4965
  children: [
4944
4966
  /* @__PURE__ */ jsx63(Chevron, { open: !isCollapsed }),
@@ -4950,8 +4972,22 @@ function Gantt({
4950
4972
  }
4951
4973
  ),
4952
4974
  /* @__PURE__ */ jsxs31("span", { className: "min-w-0", children: [
4953
- /* @__PURE__ */ jsx63("span", { className: "block truncate text-[13px] font-semibold text-[var(--s-ink-primary,#F6F1E7)]", children: stage.title }),
4954
- stage.subtitle && /* @__PURE__ */ jsx63("span", { className: "block truncate text-[11px] text-[var(--s-ink-muted,#7D7568)]", children: stage.subtitle })
4975
+ /* @__PURE__ */ jsx63(
4976
+ "span",
4977
+ {
4978
+ className: "block truncate text-[13px] font-semibold text-[var(--s-ink-primary,#F6F1E7)]",
4979
+ title: stage.title,
4980
+ children: stage.title
4981
+ }
4982
+ ),
4983
+ stage.subtitle && /* @__PURE__ */ jsx63(
4984
+ "span",
4985
+ {
4986
+ className: "block truncate text-[11px] text-[var(--s-ink-muted,#7D7568)]",
4987
+ title: stage.subtitle,
4988
+ children: stage.subtitle
4989
+ }
4990
+ )
4955
4991
  ] }),
4956
4992
  ms.length > 0 && /* @__PURE__ */ jsxs31("span", { className: "ml-auto shrink-0 rounded-[var(--c-badge-radius,4px)] bg-[var(--s-surface-elevated,#1F1C18)] px-1.5 py-0.5 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-secondary,#C9C0B4)]", children: [
4957
4993
  done,
@@ -5010,20 +5046,42 @@ function Gantt({
5010
5046
  className: "grid items-center border-b border-[var(--s-border-subtle,#2A2622)] bg-[var(--s-surface-page,#0A0908)]",
5011
5047
  style: { gridTemplateColumns: trackTemplate },
5012
5048
  children: [
5013
- /* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2 py-2 pl-10 pr-4", children: [
5014
- /* @__PURE__ */ jsx63(StatusDot, { done: m.done, color: dot }),
5015
- /* @__PURE__ */ jsx63(
5016
- "span",
5017
- {
5018
- className: cn(
5019
- "min-w-0 flex-1 truncate text-[13px]",
5020
- m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5049
+ /* @__PURE__ */ jsxs31(
5050
+ "div",
5051
+ {
5052
+ className: cn(
5053
+ stickyCol,
5054
+ "flex items-center gap-2 bg-[var(--s-surface-page,#0A0908)] py-2 pl-10 pr-4"
5055
+ ),
5056
+ children: [
5057
+ /* @__PURE__ */ jsx63(StatusDot, { done: m.done, color: dot }),
5058
+ onMilestoneClick ? /* @__PURE__ */ jsx63(
5059
+ "button",
5060
+ {
5061
+ type: "button",
5062
+ onClick: () => onMilestoneClick(m, stage),
5063
+ title: m.title,
5064
+ className: cn(
5065
+ "min-w-0 flex-1 truncate rounded-[var(--p-radius-sm,4px)] text-left text-[13px] transition-colors hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--s-brand-solid,#E07A4A)]",
5066
+ m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5067
+ ),
5068
+ children: m.title
5069
+ }
5070
+ ) : /* @__PURE__ */ jsx63(
5071
+ "span",
5072
+ {
5073
+ className: cn(
5074
+ "min-w-0 flex-1 truncate text-[13px]",
5075
+ m.done ? "text-[var(--s-ink-muted,#7D7568)] line-through" : "text-[var(--s-ink-secondary,#C9C0B4)]"
5076
+ ),
5077
+ title: m.title,
5078
+ children: m.title
5079
+ }
5021
5080
  ),
5022
- children: m.title
5023
- }
5024
- ),
5025
- m.points != null && /* @__PURE__ */ jsx63("span", { className: "shrink-0 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-muted,#7D7568)]", children: m.points })
5026
- ] }),
5081
+ m.points != null && /* @__PURE__ */ jsx63("span", { className: "shrink-0 font-[var(--s-font-mono,monospace)] text-[10px] tabular-nums text-[var(--s-ink-muted,#7D7568)]", children: m.points })
5082
+ ]
5083
+ }
5084
+ ),
5027
5085
  /* @__PURE__ */ jsx63(
5028
5086
  "div",
5029
5087
  {
@@ -5579,6 +5637,7 @@ export {
5579
5637
  ContextMenuSubContent,
5580
5638
  ContextMenuSubTrigger,
5581
5639
  ContextMenuTrigger,
5640
+ DEFAULT_NAME_COL_WIDTH,
5582
5641
  DflRemote,
5583
5642
  Dialog,
5584
5643
  DialogClose,
@@ -5778,6 +5837,7 @@ export {
5778
5837
  memberHueVar,
5779
5838
  navigationMenuTriggerStyle,
5780
5839
  parseTags,
5840
+ resolveNameColWidth,
5781
5841
  resolveWeekCount,
5782
5842
  resolveWeekLabels,
5783
5843
  stageProgress,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devfellowship/components",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "DFL Design System — UI components, hooks, utils and providers",
5
5
  "type": "module",
6
6
  "sideEffects": [