@cntyclub/ui-react 0.13.0 → 0.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntyclub/ui-react",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
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": [
@@ -5,6 +5,12 @@ import type * as React from "react";
5
5
 
6
6
  import { cn } from "../../lib/utils/css";
7
7
  import { Avatar, avatarVariants } from "./avatar";
8
+ import {
9
+ Tooltip,
10
+ TooltipPopup,
11
+ TooltipProvider,
12
+ TooltipTrigger,
13
+ } from "./tooltip";
8
14
 
9
15
  type AvatarSize = NonNullable<VariantProps<typeof avatarVariants>["size"]>;
10
16
 
@@ -29,6 +35,11 @@ interface AvatarGroupItem {
29
35
  /** Initials shown when there is no image. */
30
36
  initials?: React.ReactNode;
31
37
  alt?: string;
38
+ /**
39
+ * Label revealed on hover when `showNameOnHover` is set (e.g. the person's
40
+ * name). Falls back to `alt` when omitted.
41
+ */
42
+ name?: React.ReactNode;
32
43
  }
33
44
 
34
45
  interface AvatarGroupProps
@@ -39,11 +50,19 @@ interface AvatarGroupProps
39
50
  /** Cap the visible avatars; the rest collapse into a "+N" chip. */
40
51
  max?: number;
41
52
  size?: AvatarSize;
53
+ /**
54
+ * Reveal each avatar's `name` (or `alt`) in a tooltip above it on hover /
55
+ * focus. Only applies to the data-driven `items` path.
56
+ */
57
+ showNameOnHover?: boolean;
42
58
  }
43
59
 
44
60
  /**
45
61
  * A row of overlapping avatars with an overflow "+N" chip. Pass `items` for the
46
62
  * data-driven path, or compose `<Avatar>` children directly for full control.
63
+ *
64
+ * With `showNameOnHover`, hovering (or focusing) an avatar reveals its `name`
65
+ * in a tooltip — e.g. hovering Amir's photo shows "Amir".
47
66
  */
48
67
  function AvatarGroup({
49
68
  className,
@@ -51,13 +70,14 @@ function AvatarGroup({
51
70
  max,
52
71
  size = "sm",
53
72
  overlap,
73
+ showNameOnHover = false,
54
74
  children,
55
75
  ...props
56
76
  }: AvatarGroupProps) {
57
77
  const shown = items && max ? items.slice(0, max) : items;
58
78
  const overflow = items && max ? items.length - max : 0;
59
79
 
60
- return (
80
+ const group = (
61
81
  <div
62
82
  className={cn(avatarGroupVariants({ overlap }), className)}
63
83
  data-slot="avatar-group"
@@ -65,16 +85,36 @@ function AvatarGroup({
65
85
  {...props}
66
86
  >
67
87
  {items
68
- ? shown?.map((item, i) => (
69
- <Avatar
70
- alt={item.alt}
88
+ ? shown?.map((item, i) => {
89
+ const label = item.name ?? item.alt;
90
+ const avatar = (
91
+ <Avatar
92
+ alt={item.alt}
93
+ initials={item.initials}
94
+ size={size}
95
+ src={item.src}
96
+ />
97
+ );
98
+ if (!(showNameOnHover && label)) {
71
99
  // biome-ignore lint/suspicious/noArrayIndexKey: order is stable
72
- key={i}
73
- initials={item.initials}
74
- size={size}
75
- src={item.src}
76
- />
77
- ))
100
+ return <Avatar alt={item.alt} initials={item.initials} key={i} size={size} src={item.src} />;
101
+ }
102
+ return (
103
+ // The span wrapper is the group's direct child, so it carries the
104
+ // ring/overlap styling; the tooltip anchors to it (Base UI needs a
105
+ // ref-able host, which the Avatar fn component doesn't forward).
106
+ // biome-ignore lint/suspicious/noArrayIndexKey: order is stable
107
+ <Tooltip key={i}>
108
+ <TooltipTrigger
109
+ className="inline-flex cursor-default"
110
+ render={<span />}
111
+ >
112
+ {avatar}
113
+ </TooltipTrigger>
114
+ <TooltipPopup>{label}</TooltipPopup>
115
+ </Tooltip>
116
+ );
117
+ })
78
118
  : children}
79
119
  {overflow > 0 ? (
80
120
  <span
@@ -92,6 +132,19 @@ function AvatarGroup({
92
132
  ) : null}
93
133
  </div>
94
134
  );
135
+
136
+ // Self-contained: provide a tooltip context so the hover mode works without
137
+ // the consumer having to mount a TooltipProvider. A short delay keeps names
138
+ // from flickering as the pointer sweeps across the row.
139
+ if (showNameOnHover) {
140
+ return (
141
+ <TooltipProvider delay={150} closeDelay={0}>
142
+ {group}
143
+ </TooltipProvider>
144
+ );
145
+ }
146
+
147
+ return group;
95
148
  }
96
149
 
97
150
  export { AvatarGroup, avatarGroupVariants };