@sproutsocial/seeds-react-profile 0.3.36 → 0.3.39

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.
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Seeds InlineProfile component classes
3
+ *
4
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
5
+ * CSS variable definitions and dark mode support.
6
+ */
7
+
8
+ @layer components {
9
+ .seeds-inline-profile {
10
+ display: inline-flex;
11
+ flex-direction: row;
12
+ align-items: center;
13
+ gap: var(--space-200);
14
+ max-width: 100%;
15
+ font-size: var(--font-size-200);
16
+ line-height: var(--line-height-200);
17
+ color: var(--color-text-subtext);
18
+ text-align: inherit;
19
+ }
20
+
21
+ .seeds-inline-profile-avatar {
22
+ display: inline-flex;
23
+ flex-shrink: 0;
24
+ }
25
+
26
+ .seeds-inline-profile-content {
27
+ display: inline-flex;
28
+ align-items: center;
29
+ gap: var(--space-200);
30
+ min-width: 0;
31
+ flex: 1;
32
+ }
33
+
34
+ .seeds-inline-profile-network {
35
+ display: inline-flex;
36
+ align-items: center;
37
+ flex-shrink: 0;
38
+ }
39
+
40
+ .seeds-inline-profile-text {
41
+ display: inline-flex;
42
+ flex-direction: row;
43
+ align-items: center;
44
+ gap: var(--space-200);
45
+ min-width: 0;
46
+ flex: 1;
47
+ }
48
+
49
+ .seeds-inline-profile-name {
50
+ display: inline-block;
51
+ font-size: var(--font-size-200);
52
+ line-height: var(--line-height-200);
53
+ font-family: var(--font-family);
54
+ font-weight: var(--font-weight-semibold);
55
+ color: var(--color-text-body);
56
+ max-width: 100%;
57
+ overflow: hidden;
58
+ text-overflow: ellipsis;
59
+ white-space: nowrap;
60
+ }
61
+
62
+ .seeds-inline-profile-handle {
63
+ display: inline-block;
64
+ font-size: var(--font-size-200);
65
+ line-height: var(--line-height-200);
66
+ font-family: var(--font-family);
67
+ color: var(--color-text-subtext);
68
+ max-width: 100%;
69
+ overflow: hidden;
70
+ text-overflow: ellipsis;
71
+ white-space: nowrap;
72
+ }
73
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Seeds ProfileCard component classes
3
+ *
4
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
5
+ * CSS variable definitions and dark mode support.
6
+ *
7
+ * The header background color is dynamic (consumer bannerColor or the network
8
+ * color for the partner) and is supplied via the
9
+ * --seeds-profile-card-banner-bg custom property set as an inline style on the
10
+ * header element; the background declaration below consumes it.
11
+ */
12
+
13
+ @layer components {
14
+ .seeds-profile-card {
15
+ max-width: 300px;
16
+ border-radius: var(--radius-500);
17
+ background-color: var(--color-container-bg-base);
18
+ border: 1px solid var(--color-container-border-base);
19
+ }
20
+
21
+ .seeds-profile-card-header {
22
+ display: flex;
23
+ flex-direction: row;
24
+ position: relative;
25
+ height: 80px;
26
+ padding: var(--space-400) var(--space-400) 0 var(--space-400);
27
+ margin-bottom: 0;
28
+ color: var(--color-text-inverse);
29
+ background: var(--seeds-profile-card-banner-bg, transparent);
30
+ border-radius: var(--radius-500) var(--radius-500) 0 0;
31
+ }
32
+
33
+ .seeds-profile-card-footer {
34
+ border-top: 1px solid var(--color-container-border-base);
35
+ border-radius: 0 0 var(--radius-500) var(--radius-500);
36
+ padding: var(--space-400);
37
+ }
38
+
39
+ .seeds-profile-card-banner-content {
40
+ display: flex;
41
+ justify-content: flex-end;
42
+ width: 100%;
43
+ }
44
+
45
+ .seeds-profile-card-actions {
46
+ display: flex;
47
+ justify-content: flex-end;
48
+ gap: var(--space-100);
49
+ padding: 0 var(--space-300);
50
+ }
51
+
52
+ .seeds-profile-card-actions:empty {
53
+ min-height: 44px;
54
+ }
55
+
56
+ .seeds-profile-card-content {
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: var(--space-300);
60
+ padding: 0 var(--space-400) var(--space-400);
61
+ }
62
+
63
+ .seeds-profile-card-name-section {
64
+ display: flex;
65
+ align-items: center;
66
+ gap: var(--space-200);
67
+ }
68
+
69
+ .seeds-profile-card-info-row {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: var(--space-300);
73
+ }
74
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Seeds ProfileToken component classes
3
+ *
4
+ * Requires @sproutsocial/seeds-react-theme/dist/theme-all.css imported for
5
+ * CSS variable definitions and dark mode support.
6
+ */
7
+
8
+ @layer components {
9
+ /*
10
+ * The rendered element carries both .seeds-token (from Token) and
11
+ * .seeds-profile-token at equal specificity, so the tighter profile padding
12
+ * would otherwise depend on CSS concatenation order. The compound selector
13
+ * raises specificity so this override deterministically wins over .seeds-token.
14
+ */
15
+ .seeds-token.seeds-profile-token {
16
+ box-sizing: border-box;
17
+ display: inline-flex;
18
+ max-width: 100%;
19
+ vertical-align: middle;
20
+ padding: var(--space-100) var(--space-200);
21
+ margin: var(--space-100) 0;
22
+ }
23
+ }
package/package.json CHANGED
@@ -1,15 +1,25 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-profile",
3
- "version": "0.3.36",
3
+ "version": "0.3.39",
4
4
  "description": "Seeds React Profile",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/esm/index.js",
9
9
  "types": "dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/esm/index.js",
13
+ "require": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./dist/inline-profile.css": "./dist/inline-profile.css",
17
+ "./dist/profile-card.css": "./dist/profile-card.css",
18
+ "./dist/profile-token.css": "./dist/profile-token.css"
19
+ },
10
20
  "scripts": {
11
- "build": "tsup --dts",
12
- "build:debug": "tsup --dts --metafile",
21
+ "build": "tsup --dts && cp src/*.css dist/",
22
+ "build:debug": "tsup --dts --metafile && cp src/*.css dist/",
13
23
  "dev": "tsup --watch --dts",
14
24
  "clean": "rm -rf .turbo dist",
15
25
  "clean:modules": "rm -rf node_modules",
@@ -20,13 +30,14 @@
20
30
  "lint:fix": "eslint --fix"
21
31
  },
22
32
  "dependencies": {
23
- "@sproutsocial/seeds-react-avatar": "^1.1.18",
24
- "@sproutsocial/seeds-react-card": "^1.1.43",
25
- "@sproutsocial/seeds-react-icon": "^2.4.1",
26
- "@sproutsocial/seeds-react-link": "^1.1.14",
27
- "@sproutsocial/seeds-react-partner-logo": "^1.7.14",
28
- "@sproutsocial/seeds-react-text": "^1.5.0",
29
- "@sproutsocial/seeds-react-token": "^1.5.8"
33
+ "@sproutsocial/seeds-react-avatar": "^1.1.20",
34
+ "@sproutsocial/seeds-react-card": "^1.1.45",
35
+ "@sproutsocial/seeds-react-icon": "^2.4.3",
36
+ "@sproutsocial/seeds-react-link": "^1.1.16",
37
+ "@sproutsocial/seeds-react-partner-logo": "^1.7.16",
38
+ "@sproutsocial/seeds-react-system-props": "^3.1.2",
39
+ "@sproutsocial/seeds-react-text": "^1.5.1",
40
+ "@sproutsocial/seeds-react-token": "^1.5.10"
30
41
  },
31
42
  "devDependencies": {
32
43
  "@types/react": "^18.0.0",
@@ -153,6 +153,33 @@ export const LongNamesTruncation: Story = {
153
153
  ),
154
154
  };
155
155
 
156
+ export const TailwindClassOverride: Story = {
157
+ name: "Tailwind class override",
158
+ render: () => (
159
+ <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
160
+ <div style={{ border: "1px dashed #ccc" }}>
161
+ <InlineProfile
162
+ name="Default spacing"
163
+ secondaryName="@default"
164
+ avatarUrl={avatarUrl}
165
+ partnerName="twitter"
166
+ />
167
+ </div>
168
+ <div style={{ border: "1px dashed #ccc" }}>
169
+ {/* Utility classes (p-300, mx-200) override the component CSS,
170
+ proving the @layer components fix lets Tailwind win the cascade. */}
171
+ <InlineProfile
172
+ name="Override Demo"
173
+ secondaryName="@override"
174
+ avatarUrl={avatarUrl}
175
+ partnerName="twitter"
176
+ className="p-300 mx-200"
177
+ />
178
+ </div>
179
+ </div>
180
+ ),
181
+ };
182
+
156
183
  export const WithoutAvatarUrl: Story = {
157
184
  args: {
158
185
  name: "John Doe",
@@ -1,153 +1 @@
1
- import styled from "styled-components";
2
- import { PartnerLogo } from "@sproutsocial/seeds-react-partner-logo";
3
- import { Avatar } from "@sproutsocial/seeds-react-avatar";
4
- import type { TypeInlineProfileProps } from "./types";
5
- import { VerifiedProfileIcon } from "./VerifiedProfileIcon";
6
-
7
- const InlineProfileContainer = styled.span<{
8
- $size?: "small" | "medium" | "large";
9
- }>`
10
- display: inline-flex;
11
- flex-direction: row;
12
- align-items: center;
13
- gap: ${(props) => props.theme.space[200]};
14
- max-width: 100%;
15
- ${(props) => props.theme.typography[200]}
16
- color: ${(props) => props.theme.colors.text.subtext};
17
- text-align: inherit;
18
- `;
19
-
20
- const InlineProfileAvatar = styled.span`
21
- display: inline-flex;
22
- flex-shrink: 0;
23
- `;
24
-
25
- const InlineProfileContent = styled.span`
26
- display: inline-flex;
27
- align-items: center;
28
- gap: ${(props) => props.theme.space[200]};
29
- min-width: 0;
30
- flex: 1;
31
- `;
32
-
33
- const InlineProfileNetwork = styled.span`
34
- display: inline-flex;
35
- align-items: center;
36
- flex-shrink: 0;
37
- `;
38
-
39
- const InlineProfileText = styled.span`
40
- display: inline-flex;
41
- flex-direction: row;
42
- align-items: center;
43
- gap: ${(props) => props.theme.space[200]};
44
- min-width: 0;
45
- flex: 1;
46
- `;
47
-
48
- const InlineProfileName = styled.span`
49
- display: inline-block;
50
- ${(props) => props.theme.typography[200]}
51
- font-family: ${(props) => props.theme.fontFamily};
52
- font-weight: ${(props) => props.theme.fontWeights.semibold};
53
- color: ${(props) => props.theme.colors.text.body};
54
- max-width: 100%;
55
- overflow: hidden;
56
- text-overflow: ellipsis;
57
- white-space: nowrap;
58
- `;
59
-
60
- const InlineProfileHandle = styled.span`
61
- display: inline-block;
62
- ${(props) => props.theme.typography[200]}
63
- font-family: ${(props) => props.theme.fontFamily};
64
- color: ${(props) => props.theme.colors.text.subtext};
65
- max-width: 100%;
66
- overflow: hidden;
67
- text-overflow: ellipsis;
68
- white-space: nowrap;
69
- `;
70
-
71
- const avatarSizeMap = {
72
- small: "16px",
73
- medium: "20px",
74
- large: "24px",
75
- } as const;
76
-
77
- /**
78
- * A compact inline profile component that displays avatar, name/handle, and verification.
79
- * Perfect for use in post headers, comments, or other compact spaces.
80
- *
81
- * @param props - Profile props
82
- * @param props.name - Name of the profile
83
- * @param props.secondaryName - Secondary name of the profile
84
- * @param props.partnerName - Partner logo name
85
- * @param props.partnerLogoLabel - Aria-label for the partner logo
86
- * @param props.avatarSize - Size of the avatar
87
- * @param props.avatarUrl - Image URL for the avatar
88
- * @param props.children - Additional elements to render within the profile component
89
- * @returns JSX.Element representing a user profile
90
- *
91
- * @example
92
- * <InlineProfile
93
- * name="John Doe"
94
- * secondaryName="johndoe123"
95
- * partnerName="facebook"
96
- * partnerLogoLabel="Facebook Logo"
97
- * avatarSize="24px"
98
- * avatarUrl="https://example.com/avatar.jpg"
99
- * >
100
- * <Badge text="Moderator" badgeColor="green" />
101
- * </InlineProfile>
102
- */
103
- export const InlineProfile = ({
104
- name,
105
- secondaryName,
106
- partnerName,
107
- partnerLogoLabel,
108
- size = "medium",
109
- avatarSize: avatarSizeOverride,
110
- avatarUrl,
111
- verificationType,
112
- className,
113
- }: TypeInlineProfileProps) => {
114
- const displayName = name || secondaryName || "Unknown Profile";
115
- const avatarSize = avatarSizeOverride || avatarSizeMap[size];
116
-
117
- return (
118
- <InlineProfileContainer className={className} $size={size}>
119
- {avatarUrl && (
120
- <InlineProfileAvatar>
121
- <Avatar src={avatarUrl} name={displayName} size={avatarSize} />
122
- </InlineProfileAvatar>
123
- )}
124
-
125
- <InlineProfileContent>
126
- {partnerName && (
127
- <InlineProfileNetwork>
128
- <PartnerLogo
129
- partnerName={partnerName}
130
- aria-label={partnerLogoLabel || `${partnerName} profile`}
131
- size="small"
132
- />
133
- </InlineProfileNetwork>
134
- )}
135
-
136
- <InlineProfileText>
137
- {name && <InlineProfileName>{name}</InlineProfileName>}
138
-
139
- {secondaryName && (
140
- <InlineProfileHandle>{secondaryName}</InlineProfileHandle>
141
- )}
142
- </InlineProfileText>
143
-
144
- {verificationType && (
145
- <VerifiedProfileIcon
146
- partnerName={partnerName}
147
- verificationType={verificationType}
148
- />
149
- )}
150
- </InlineProfileContent>
151
- </InlineProfileContainer>
152
- );
153
- };
1
+ export { InlineProfileHybrid as InlineProfile } from "./InlineProfileHybrid";
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Hybrid InlineProfile component.
3
+ * Routes between the Tailwind implementation (preferred) and the
4
+ * styled-components implementation (for consumers using styled-system props or
5
+ * a styled() extension).
6
+ */
7
+
8
+ import { needsStyledComponents } from "@sproutsocial/seeds-react-system-props";
9
+ import type { TypeInlineProfileProps } from "./types";
10
+ import { InlineProfileStyled } from "./InlineProfileStyled";
11
+ import { InlineProfileTailwind } from "./InlineProfileTailwind";
12
+
13
+ export const InlineProfileHybrid = (props: TypeInlineProfileProps) => {
14
+ if (needsStyledComponents(props)) {
15
+ return <InlineProfileStyled {...props} />;
16
+ }
17
+ return <InlineProfileTailwind {...props} />;
18
+ };
@@ -0,0 +1,143 @@
1
+ import styled from "styled-components";
2
+ import { PartnerLogo } from "@sproutsocial/seeds-react-partner-logo";
3
+ import { Avatar } from "@sproutsocial/seeds-react-avatar";
4
+ import type { TypeInlineProfileProps } from "./types";
5
+ import { VerifiedProfileIcon } from "./VerifiedProfileIcon";
6
+
7
+ const InlineProfileContainer = styled.span<{
8
+ $size?: "small" | "medium" | "large";
9
+ }>`
10
+ display: inline-flex;
11
+ flex-direction: row;
12
+ align-items: center;
13
+ gap: ${(props) => props.theme.space[200]};
14
+ max-width: 100%;
15
+ ${(props) => props.theme.typography[200]}
16
+ color: ${(props) => props.theme.colors.text.subtext};
17
+ text-align: inherit;
18
+ `;
19
+
20
+ const InlineProfileAvatar = styled.span`
21
+ display: inline-flex;
22
+ flex-shrink: 0;
23
+ `;
24
+
25
+ const InlineProfileContent = styled.span`
26
+ display: inline-flex;
27
+ align-items: center;
28
+ gap: ${(props) => props.theme.space[200]};
29
+ min-width: 0;
30
+ flex: 1;
31
+ `;
32
+
33
+ const InlineProfileNetwork = styled.span`
34
+ display: inline-flex;
35
+ align-items: center;
36
+ flex-shrink: 0;
37
+ `;
38
+
39
+ const InlineProfileText = styled.span`
40
+ display: inline-flex;
41
+ flex-direction: row;
42
+ align-items: center;
43
+ gap: ${(props) => props.theme.space[200]};
44
+ min-width: 0;
45
+ flex: 1;
46
+ `;
47
+
48
+ const InlineProfileName = styled.span`
49
+ display: inline-block;
50
+ ${(props) => props.theme.typography[200]}
51
+ font-family: ${(props) => props.theme.fontFamily};
52
+ font-weight: ${(props) => props.theme.fontWeights.semibold};
53
+ color: ${(props) => props.theme.colors.text.body};
54
+ max-width: 100%;
55
+ overflow: hidden;
56
+ text-overflow: ellipsis;
57
+ white-space: nowrap;
58
+ `;
59
+
60
+ const InlineProfileHandle = styled.span`
61
+ display: inline-block;
62
+ ${(props) => props.theme.typography[200]}
63
+ font-family: ${(props) => props.theme.fontFamily};
64
+ color: ${(props) => props.theme.colors.text.subtext};
65
+ max-width: 100%;
66
+ overflow: hidden;
67
+ text-overflow: ellipsis;
68
+ white-space: nowrap;
69
+ `;
70
+
71
+ const avatarSizeMap = {
72
+ small: "16px",
73
+ medium: "20px",
74
+ large: "24px",
75
+ } as const;
76
+
77
+ /**
78
+ * Styled-components implementation of InlineProfile.
79
+ *
80
+ * Preserved as the legacy rendering path: the Hybrid routes here when the
81
+ * component is extended via styled() or receives styled-system props. The
82
+ * markup is byte-for-byte identical to the pre-migration InlineProfile.
83
+ *
84
+ * @param props - Profile props
85
+ * @param props.name - Name of the profile
86
+ * @param props.secondaryName - Secondary name of the profile
87
+ * @param props.partnerName - Partner logo name
88
+ * @param props.partnerLogoLabel - Aria-label for the partner logo
89
+ * @param props.avatarSize - Size of the avatar
90
+ * @param props.avatarUrl - Image URL for the avatar
91
+ * @returns JSX.Element representing a user profile
92
+ */
93
+ export const InlineProfileStyled = ({
94
+ name,
95
+ secondaryName,
96
+ partnerName,
97
+ partnerLogoLabel,
98
+ size = "medium",
99
+ avatarSize: avatarSizeOverride,
100
+ avatarUrl,
101
+ verificationType,
102
+ className,
103
+ }: TypeInlineProfileProps) => {
104
+ const displayName = name || secondaryName || "Unknown Profile";
105
+ const avatarSize = avatarSizeOverride || avatarSizeMap[size];
106
+
107
+ return (
108
+ <InlineProfileContainer className={className} $size={size}>
109
+ {avatarUrl && (
110
+ <InlineProfileAvatar>
111
+ <Avatar src={avatarUrl} name={displayName} size={avatarSize} />
112
+ </InlineProfileAvatar>
113
+ )}
114
+
115
+ <InlineProfileContent>
116
+ {partnerName && (
117
+ <InlineProfileNetwork>
118
+ <PartnerLogo
119
+ partnerName={partnerName}
120
+ aria-label={partnerLogoLabel || `${partnerName} profile`}
121
+ size="small"
122
+ />
123
+ </InlineProfileNetwork>
124
+ )}
125
+
126
+ <InlineProfileText>
127
+ {name && <InlineProfileName>{name}</InlineProfileName>}
128
+
129
+ {secondaryName && (
130
+ <InlineProfileHandle>{secondaryName}</InlineProfileHandle>
131
+ )}
132
+ </InlineProfileText>
133
+
134
+ {verificationType && (
135
+ <VerifiedProfileIcon
136
+ partnerName={partnerName}
137
+ verificationType={verificationType}
138
+ />
139
+ )}
140
+ </InlineProfileContent>
141
+ </InlineProfileContainer>
142
+ );
143
+ };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Tailwind/CSS-class implementation of InlineProfile.
3
+ * Uses Seeds InlineProfile CSS classes from inline-profile.css.
4
+ */
5
+
6
+ import { PartnerLogo } from "@sproutsocial/seeds-react-partner-logo";
7
+ import { Avatar } from "@sproutsocial/seeds-react-avatar";
8
+ import type { TypeInlineProfileProps } from "./types";
9
+ import { VerifiedProfileIcon } from "./VerifiedProfileIcon";
10
+ import { cn } from "./cn";
11
+
12
+ const avatarSizeMap = {
13
+ small: "16px",
14
+ medium: "20px",
15
+ large: "24px",
16
+ } as const;
17
+
18
+ /**
19
+ * A compact inline profile component that displays avatar, name/handle, and verification.
20
+ * Perfect for use in post headers, comments, or other compact spaces.
21
+ *
22
+ * @param props - Profile props
23
+ * @param props.name - Name of the profile
24
+ * @param props.secondaryName - Secondary name of the profile
25
+ * @param props.partnerName - Partner logo name
26
+ * @param props.partnerLogoLabel - Aria-label for the partner logo
27
+ * @param props.avatarSize - Size of the avatar
28
+ * @param props.avatarUrl - Image URL for the avatar
29
+ * @returns JSX.Element representing a user profile
30
+ */
31
+ export const InlineProfileTailwind = ({
32
+ name,
33
+ secondaryName,
34
+ partnerName,
35
+ partnerLogoLabel,
36
+ size = "medium",
37
+ avatarSize: avatarSizeOverride,
38
+ avatarUrl,
39
+ verificationType,
40
+ className,
41
+ }: TypeInlineProfileProps) => {
42
+ const displayName = name || secondaryName || "Unknown Profile";
43
+ const avatarSize = avatarSizeOverride || avatarSizeMap[size];
44
+
45
+ return (
46
+ <span className={cn("seeds-inline-profile", className)}>
47
+ {avatarUrl && (
48
+ <span className="seeds-inline-profile-avatar">
49
+ <Avatar src={avatarUrl} name={displayName} size={avatarSize} />
50
+ </span>
51
+ )}
52
+
53
+ <span className="seeds-inline-profile-content">
54
+ {partnerName && (
55
+ <span className="seeds-inline-profile-network">
56
+ <PartnerLogo
57
+ partnerName={partnerName}
58
+ aria-label={partnerLogoLabel || `${partnerName} profile`}
59
+ size="small"
60
+ />
61
+ </span>
62
+ )}
63
+
64
+ <span className="seeds-inline-profile-text">
65
+ {name && <span className="seeds-inline-profile-name">{name}</span>}
66
+
67
+ {secondaryName && (
68
+ <span className="seeds-inline-profile-handle">{secondaryName}</span>
69
+ )}
70
+ </span>
71
+
72
+ {verificationType && (
73
+ <VerifiedProfileIcon
74
+ partnerName={partnerName}
75
+ verificationType={verificationType}
76
+ />
77
+ )}
78
+ </span>
79
+ </span>
80
+ );
81
+ };
@@ -238,6 +238,33 @@ export const DifferentNetworks: Story = {
238
238
  ),
239
239
  };
240
240
 
241
+ export const TailwindClassOverride: Story = {
242
+ name: "Tailwind class override",
243
+ render: () => (
244
+ <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
245
+ <ProfileCard
246
+ name="Default spacing"
247
+ secondaryName="@default"
248
+ partnerName="twitter"
249
+ avatarUrl="https://via.placeholder.com/60"
250
+ description="Default card spacing."
251
+ />
252
+ {/* The bare className prop is not forwarded to the card root, so the
253
+ override goes through cardProps. Utility classes (p-300, mx-200)
254
+ override the component CSS, proving the @layer components fix lets
255
+ Tailwind win the cascade. */}
256
+ <ProfileCard
257
+ name="Override Demo"
258
+ secondaryName="@override"
259
+ partnerName="twitter"
260
+ avatarUrl="https://via.placeholder.com/60"
261
+ description="Card with Tailwind utility overrides."
262
+ cardProps={{ role: "presentation", className: "p-300 mx-200" }}
263
+ />
264
+ </div>
265
+ ),
266
+ };
267
+
241
268
  export const LongContentTruncation: Story = {
242
269
  render: () => (
243
270
  <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>