@cntyclub/ui-react 0.12.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/dist/index.d.ts +14 -1
- package/dist/index.js +131 -101
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ui/aurora-text.tsx +6 -3
- package/src/components/ui/avatar-group.tsx +63 -10
- package/src/styles.css +18 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cntyclub/ui-react",
|
|
3
|
-
"version": "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": [
|
|
@@ -47,7 +47,10 @@ export const AuroraText = memo(function AuroraText({
|
|
|
47
47
|
backgroundClip: "text",
|
|
48
48
|
WebkitTextFillColor: "transparent",
|
|
49
49
|
color: "transparent",
|
|
50
|
-
|
|
50
|
+
// Full `animation` inline (not the `animate-aurora` utility): the keyframe
|
|
51
|
+
// ships in styles.css unconditionally, so the sweep runs even if the
|
|
52
|
+
// consumer's Tailwind never generates that utility class.
|
|
53
|
+
animation: `aurora ${10 / speed}s ease infinite`,
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
return (
|
|
@@ -57,13 +60,13 @@ export const AuroraText = memo(function AuroraText({
|
|
|
57
60
|
{glow ? (
|
|
58
61
|
<span
|
|
59
62
|
aria-hidden="true"
|
|
60
|
-
className="
|
|
63
|
+
className="pointer-events-none absolute inset-0 select-none blur-[6px] opacity-60"
|
|
61
64
|
style={gradientStyle}
|
|
62
65
|
>
|
|
63
66
|
{children}
|
|
64
67
|
</span>
|
|
65
68
|
) : null}
|
|
66
|
-
<span aria-hidden="true" className="
|
|
69
|
+
<span aria-hidden="true" className="relative" style={gradientStyle}>
|
|
67
70
|
{children}
|
|
68
71
|
</span>
|
|
69
72
|
</span>
|
|
@@ -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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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 };
|
package/src/styles.css
CHANGED
|
@@ -14,6 +14,24 @@
|
|
|
14
14
|
|
|
15
15
|
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
|
|
16
16
|
|
|
17
|
+
/*
|
|
18
|
+
* Emitted unconditionally (NOT inside @theme) so AuroraText's gradient sweep
|
|
19
|
+
* runs in every consumer — even when their Tailwind build doesn't generate the
|
|
20
|
+
* `animate-aurora` utility from the theme token (keyframes declared inside
|
|
21
|
+
* @theme are dropped unless that utility is scanned/used). AuroraText applies
|
|
22
|
+
* this keyframe via an inline `animation`, so it no longer depends on the
|
|
23
|
+
* utility class existing at all.
|
|
24
|
+
*/
|
|
25
|
+
@keyframes aurora {
|
|
26
|
+
0%,
|
|
27
|
+
100% {
|
|
28
|
+
background-position: 0% 50%;
|
|
29
|
+
}
|
|
30
|
+
50% {
|
|
31
|
+
background-position: 100% 50%;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
17
35
|
@theme inline {
|
|
18
36
|
--animate-skeleton: skeleton 2s -1s infinite linear;
|
|
19
37
|
--animate-qr-scan: qr-scan 2.6s ease-in-out infinite alternate;
|