@cntyclub/ui-react 0.7.1 → 0.8.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntyclub/ui-react",
3
- "version": "0.7.1",
3
+ "version": "0.8.1",
4
4
  "description": "React component library for the Country Club UI Kit — Base UI primitives styled with the Country Club design system (Tailwind CSS v4)",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
 
3
+ import { Fragment } from "react";
3
4
  import type * as React from "react";
5
+ import { ChevronRight } from "lucide-react";
4
6
 
5
7
  import { cn } from "../../lib/utils/css";
6
8
 
@@ -17,51 +19,70 @@ interface PipelineProps extends React.ComponentProps<"div"> {
17
19
  /** Ordered funnel stages, left to right. */
18
20
  stages: PipelineStage[];
19
21
  /**
20
- * Conversion markers shown after each stage (length = `stages.length - 1`).
21
- * Typically a percentage string; any node works.
22
+ * Step-to-step conversion markers. `conversions[i]` is the share of stage `i`
23
+ * that advances to stage `i + 1`, and is shown as a pill right beside stage
24
+ * `i`'s number (length = `stages.length - 1`). Typically a percentage string.
22
25
  */
23
26
  conversions?: React.ReactNode[];
24
27
  }
25
28
 
26
29
  /**
27
- * A horizontal conversion funnel — a row of headline stages, each with the
28
- * step-to-step conversion pill sitting right beside its number. The row wraps
29
- * onto multiple lines when space is tight (e.g. beside a docked panel), so it
30
- * stays readable without stretching the stages apart.
30
+ * A conversion funnel — equal-width stages laid left to right. Each stage
31
+ * carries its own step-to-step conversion in a pill next to the number, and a
32
+ * chevron points to the next stage, so the row reads as a flow rather than a
33
+ * set of loose stats.
34
+ *
35
+ * The component is its own container query context: when it gets narrow (e.g.
36
+ * beside a docked panel) the chevrons hide and the stages reflow into a
37
+ * two-column grid, staying readable without squashing the numbers.
31
38
  */
32
39
  function Pipeline({ stages, conversions = [], className, ...props }: PipelineProps) {
33
40
  return (
34
41
  <div
35
- className={cn("flex flex-wrap items-start gap-x-5 gap-y-4", className)}
42
+ className={cn(
43
+ "@container flex items-stretch @max-[560px]:grid @max-[560px]:grid-cols-2 @max-[560px]:gap-x-6 @max-[560px]:gap-y-5",
44
+ className,
45
+ )}
36
46
  data-slot="pipeline"
37
47
  {...props}
38
48
  >
39
49
  {stages.map((stage, i) => {
40
50
  const conv = i < stages.length - 1 ? conversions[i] : undefined;
41
51
  return (
42
- <div key={i} data-slot="pipeline-stage">
43
- <div className="flex items-baseline gap-2">
44
- <span
45
- className={cn(
46
- "font-sans font-semibold text-3xl text-foreground leading-none tabular-nums tracking-tight",
47
- stage.accent && "text-primary",
48
- )}
49
- >
50
- {stage.value}
51
- </span>
52
- {conv != null ? <PipelineConversion>{conv}</PipelineConversion> : null}
53
- </div>
54
- <div className="mt-1.5 text-muted-foreground text-xs leading-snug">
55
- {stage.label}
52
+ <Fragment key={i}>
53
+ <div className="min-w-0 flex-1 px-0.5" data-slot="pipeline-stage">
54
+ <div className="flex items-center gap-2">
55
+ <span
56
+ className={cn(
57
+ "font-sans font-bold text-3xl text-foreground leading-none tabular-nums tracking-tight",
58
+ stage.accent && "text-success",
59
+ )}
60
+ >
61
+ {stage.value}
62
+ </span>
63
+ {conv != null ? <PipelineConversion>{conv}</PipelineConversion> : null}
64
+ </div>
65
+ <div className="mt-2 text-muted-foreground text-xs leading-snug">
66
+ {stage.label}
67
+ </div>
56
68
  </div>
57
- </div>
69
+ {conv != null ? (
70
+ <div
71
+ className="flex flex-none items-center px-1 @max-[560px]:hidden"
72
+ data-slot="pipeline-arrow"
73
+ aria-hidden
74
+ >
75
+ <ChevronRight className="size-3.5 text-muted-foreground/40" />
76
+ </div>
77
+ ) : null}
78
+ </Fragment>
58
79
  );
59
80
  })}
60
81
  </div>
61
82
  );
62
83
  }
63
84
 
64
- /** The small pill that carries a stage-to-stage conversion value. */
85
+ /** The conversion pill sitting beside a stage number. */
65
86
  function PipelineConversion({
66
87
  className,
67
88
  ...props
@@ -69,7 +90,7 @@ function PipelineConversion({
69
90
  return (
70
91
  <span
71
92
  className={cn(
72
- "inline-flex items-center rounded-full border border-border bg-secondary px-2 py-0.5 font-medium text-secondary-foreground text-xs tabular-nums",
93
+ "inline-flex items-center rounded-full border border-success/20 bg-success/10 px-2 py-0.5 font-medium text-[11px] text-success tabular-nums dark:bg-success/16",
73
94
  className,
74
95
  )}
75
96
  data-slot="pipeline-conversion"