@devfellowship/components 1.4.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
@@ -5127,6 +5127,7 @@ function Gantt({
5127
5127
  labelWidth,
5128
5128
  nameColWidth,
5129
5129
  weekMinWidth = 64,
5130
+ onMilestoneClick,
5130
5131
  className,
5131
5132
  style,
5132
5133
  ...rest
@@ -5376,7 +5377,19 @@ function Gantt({
5376
5377
  ),
5377
5378
  children: [
5378
5379
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(StatusDot, { done: m.done, color: dot }),
5379
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
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)(
5380
5393
  "span",
5381
5394
  {
5382
5395
  className: cn(
package/dist/index.d.cts CHANGED
@@ -999,6 +999,14 @@ interface GanttProps extends React$1.HTMLAttributes<HTMLDivElement> {
999
999
  nameColWidth?: number;
1000
1000
  /** Min px width of a single week column. Defaults to 64. */
1001
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;
1002
1010
  }
1003
1011
  /** Default width of the sticky name column. ~2× the original 240 → readable. */
1004
1012
  declare const DEFAULT_NAME_COL_WIDTH = 320;
@@ -1020,7 +1028,7 @@ declare function barGridColumn(weekStart: number, weekSpan: number, weekCount: n
1020
1028
  start: number;
1021
1029
  span: number;
1022
1030
  };
1023
- declare function Gantt({ stages, weeks, dependencies, rowsHeader, stagesOnly, header, labelWidth, nameColWidth, 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;
1024
1032
 
1025
1033
  /** Minimal subset of `@supabase/supabase-js` SupabaseClient we rely on.
1026
1034
  * Kept structural so the package never hard-depends on supabase-js. */
package/dist/index.d.ts CHANGED
@@ -999,6 +999,14 @@ interface GanttProps extends React$1.HTMLAttributes<HTMLDivElement> {
999
999
  nameColWidth?: number;
1000
1000
  /** Min px width of a single week column. Defaults to 64. */
1001
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;
1002
1010
  }
1003
1011
  /** Default width of the sticky name column. ~2× the original 240 → readable. */
1004
1012
  declare const DEFAULT_NAME_COL_WIDTH = 320;
@@ -1020,7 +1028,7 @@ declare function barGridColumn(weekStart: number, weekSpan: number, weekCount: n
1020
1028
  start: number;
1021
1029
  span: number;
1022
1030
  };
1023
- declare function Gantt({ stages, weeks, dependencies, rowsHeader, stagesOnly, header, labelWidth, nameColWidth, 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;
1024
1032
 
1025
1033
  /** Minimal subset of `@supabase/supabase-js` SupabaseClient we rely on.
1026
1034
  * Kept structural so the package never hard-depends on supabase-js. */
package/dist/index.js CHANGED
@@ -4805,6 +4805,7 @@ function Gantt({
4805
4805
  labelWidth,
4806
4806
  nameColWidth,
4807
4807
  weekMinWidth = 64,
4808
+ onMilestoneClick,
4808
4809
  className,
4809
4810
  style,
4810
4811
  ...rest
@@ -5054,7 +5055,19 @@ function Gantt({
5054
5055
  ),
5055
5056
  children: [
5056
5057
  /* @__PURE__ */ jsx63(StatusDot, { done: m.done, color: dot }),
5057
- /* @__PURE__ */ jsx63(
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(
5058
5071
  "span",
5059
5072
  {
5060
5073
  className: cn(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devfellowship/components",
3
- "version": "1.4.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": [