@shipfox/react-ui 0.1.0 → 0.3.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/.turbo/turbo-build.log +2 -2
- package/.turbo/turbo-check.log +3 -3
- package/.turbo/turbo-type.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/components/alert/alert.d.ts +18 -0
- package/dist/components/alert/alert.d.ts.map +1 -0
- package/dist/components/alert/alert.js +123 -0
- package/dist/components/alert/alert.js.map +1 -0
- package/dist/components/alert/alert.stories.js +112 -0
- package/dist/components/alert/alert.stories.js.map +1 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.d.ts.map +1 -0
- package/dist/components/alert/index.js +3 -0
- package/dist/components/alert/index.js.map +1 -0
- package/dist/components/avatar/avatar-group.d.ts +18 -0
- package/dist/components/avatar/avatar-group.d.ts.map +1 -0
- package/dist/components/avatar/avatar-group.js +132 -0
- package/dist/components/avatar/avatar-group.js.map +1 -0
- package/dist/components/avatar/avatar.d.ts +21 -0
- package/dist/components/avatar/avatar.d.ts.map +1 -0
- package/dist/components/avatar/avatar.js +166 -0
- package/dist/components/avatar/avatar.js.map +1 -0
- package/dist/components/avatar/avatar.stories.js +255 -0
- package/dist/components/avatar/avatar.stories.js.map +1 -0
- package/dist/components/avatar/index.d.ts +3 -0
- package/dist/components/avatar/index.d.ts.map +1 -0
- package/dist/components/avatar/index.js +4 -0
- package/dist/components/avatar/index.js.map +1 -0
- package/dist/components/icon/custom/index.d.ts +1 -0
- package/dist/components/icon/custom/index.d.ts.map +1 -1
- package/dist/components/icon/custom/index.js +1 -0
- package/dist/components/icon/custom/index.js.map +1 -1
- package/dist/components/icon/custom/shipfox-logo.d.ts +8 -0
- package/dist/components/icon/custom/shipfox-logo.d.ts.map +1 -0
- package/dist/components/icon/custom/shipfox-logo.js +22 -0
- package/dist/components/icon/custom/shipfox-logo.js.map +1 -0
- package/dist/components/icon/icon.d.ts +4 -1
- package/dist/components/icon/icon.d.ts.map +1 -1
- package/dist/components/icon/icon.js +6 -3
- package/dist/components/icon/icon.js.map +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/inline-tips/index.d.ts +2 -0
- package/dist/components/inline-tips/index.d.ts.map +1 -0
- package/dist/components/inline-tips/index.js +3 -0
- package/dist/components/inline-tips/index.js.map +1 -0
- package/dist/components/inline-tips/inline-tips.d.ts +19 -0
- package/dist/components/inline-tips/inline-tips.d.ts.map +1 -0
- package/dist/components/inline-tips/inline-tips.js +98 -0
- package/dist/components/inline-tips/inline-tips.js.map +1 -0
- package/dist/components/inline-tips/inline-tips.stories.js +214 -0
- package/dist/components/inline-tips/inline-tips.stories.js.map +1 -0
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/index.d.ts.map +1 -0
- package/dist/components/textarea/index.js +3 -0
- package/dist/components/textarea/index.js.map +1 -0
- package/dist/components/textarea/textarea.d.ts +10 -0
- package/dist/components/textarea/textarea.d.ts.map +1 -0
- package/dist/components/textarea/textarea.js +31 -0
- package/dist/components/textarea/textarea.js.map +1 -0
- package/dist/components/textarea/textarea.stories.js +333 -0
- package/dist/components/textarea/textarea.stories.js.map +1 -0
- package/dist/components/tooltip/tooltip.d.ts +7 -0
- package/dist/components/tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip/tooltip.js +38 -0
- package/dist/components/tooltip/tooltip.js.map +1 -0
- package/dist/utils/avatar.d.ts +3 -0
- package/dist/utils/avatar.d.ts.map +1 -0
- package/dist/utils/avatar.js +32 -0
- package/dist/utils/avatar.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/index.css +32 -1
- package/package.json +5 -5
- package/src/components/alert/alert.stories.tsx +77 -0
- package/src/components/alert/alert.tsx +144 -0
- package/src/components/alert/index.ts +1 -0
- package/src/components/avatar/avatar-group.tsx +186 -0
- package/src/components/avatar/avatar.stories.tsx +172 -0
- package/src/components/avatar/avatar.tsx +215 -0
- package/src/components/avatar/index.ts +2 -0
- package/src/components/icon/custom/index.ts +1 -0
- package/src/components/icon/custom/shipfox-logo.tsx +20 -0
- package/src/components/icon/icon.tsx +11 -1
- package/src/components/index.ts +4 -0
- package/src/components/inline-tips/index.ts +1 -0
- package/src/components/inline-tips/inline-tips.stories.tsx +126 -0
- package/src/components/inline-tips/inline-tips.tsx +132 -0
- package/src/components/textarea/index.ts +1 -0
- package/src/components/textarea/textarea.stories.tsx +190 -0
- package/src/components/textarea/textarea.tsx +42 -0
- package/src/components/tooltip/tooltip.tsx +52 -0
- package/src/utils/avatar.ts +27 -0
- package/src/utils/index.ts +1 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import {cva, type VariantProps} from 'class-variance-authority';
|
|
2
|
+
import {Icon} from 'components/icon';
|
|
3
|
+
import type {ComponentProps} from 'react';
|
|
4
|
+
import {cn} from 'utils/cn';
|
|
5
|
+
|
|
6
|
+
const alertVariants = cva(
|
|
7
|
+
'relative w-full rounded-l-4 rounded-r-8 px-16 py-12 text-sm flex gap-12 items-start border',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-tag-neutral-bg text-foreground-neutral-base border-tag-neutral-border',
|
|
12
|
+
info: 'bg-tag-blue-bg text-foreground-neutral-base border-tag-blue-border',
|
|
13
|
+
success: 'bg-tag-success-bg text-foreground-neutral-base border-tag-success-border',
|
|
14
|
+
warning: 'bg-tag-warning-bg text-foreground-neutral-base border-tag-warning-border',
|
|
15
|
+
destructive: 'bg-tag-error-bg text-foreground-neutral-base border-tag-error-border',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
variant: 'default',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const alertLineVariants = cva('w-4 self-stretch rounded-full', {
|
|
25
|
+
variants: {
|
|
26
|
+
variant: {
|
|
27
|
+
default: 'bg-tag-neutral-icon',
|
|
28
|
+
info: 'bg-tag-blue-icon',
|
|
29
|
+
success: 'bg-tag-success-icon',
|
|
30
|
+
warning: 'bg-tag-warning-icon',
|
|
31
|
+
destructive: 'bg-tag-error-icon',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
variant: 'default',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const closeIconVariants = cva('w-16 h-16', {
|
|
40
|
+
variants: {
|
|
41
|
+
variant: {
|
|
42
|
+
default: 'text-tag-neutral-icon',
|
|
43
|
+
info: 'text-tag-blue-icon',
|
|
44
|
+
success: 'text-tag-success-icon',
|
|
45
|
+
warning: 'text-tag-warning-icon',
|
|
46
|
+
destructive: 'text-tag-error-icon',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
defaultVariants: {
|
|
50
|
+
variant: 'default',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
type AlertProps = ComponentProps<'div'> & VariantProps<typeof alertVariants>;
|
|
55
|
+
|
|
56
|
+
function Alert({className, variant, children, ...props}: AlertProps) {
|
|
57
|
+
return (
|
|
58
|
+
<div className="w-full flex items-start gap-4">
|
|
59
|
+
<div data-slot="alert-line" className={cn(alertLineVariants({variant}))} aria-hidden="true" />
|
|
60
|
+
<div
|
|
61
|
+
data-slot="alert"
|
|
62
|
+
role="alert"
|
|
63
|
+
className={cn(alertVariants({variant}), className)}
|
|
64
|
+
{...props}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function AlertContent({className, ...props}: ComponentProps<'div'>) {
|
|
73
|
+
return <div data-slot="alert-content" className={cn('flex-1 min-w-0', className)} {...props} />;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function AlertTitle({className, ...props}: ComponentProps<'div'>) {
|
|
77
|
+
return (
|
|
78
|
+
<div
|
|
79
|
+
data-slot="alert-title"
|
|
80
|
+
className={cn('font-medium text-sm leading-20 text-foreground-neutral-base mb-4', className)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function AlertDescription({className, ...props}: ComponentProps<'div'>) {
|
|
87
|
+
return (
|
|
88
|
+
<div
|
|
89
|
+
data-slot="alert-description"
|
|
90
|
+
className={cn(
|
|
91
|
+
'text-xs leading-20 text-foreground-neutral-base [&_p]:leading-relaxed',
|
|
92
|
+
className,
|
|
93
|
+
)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function AlertActions({className, ...props}: ComponentProps<'div'>) {
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
data-slot="alert-actions"
|
|
103
|
+
className={cn('flex items-center gap-8 mt-8', className)}
|
|
104
|
+
{...props}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function AlertAction({className, ...props}: ComponentProps<'button'>) {
|
|
110
|
+
return (
|
|
111
|
+
<button
|
|
112
|
+
data-slot="alert-action"
|
|
113
|
+
type="button"
|
|
114
|
+
className={cn(
|
|
115
|
+
'bg-transparent border-none p-0 cursor-pointer text-xs font-medium leading-20 text-foreground-neutral-base hover:text-foreground-neutral-subtle transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-background-accent-blue-base focus-visible:ring-offset-2',
|
|
116
|
+
className,
|
|
117
|
+
)}
|
|
118
|
+
{...props}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function AlertClose({
|
|
124
|
+
className,
|
|
125
|
+
variant = 'default',
|
|
126
|
+
...props
|
|
127
|
+
}: ComponentProps<'button'> & VariantProps<typeof closeIconVariants>) {
|
|
128
|
+
return (
|
|
129
|
+
<button
|
|
130
|
+
data-slot="alert-close"
|
|
131
|
+
type="button"
|
|
132
|
+
className={cn(
|
|
133
|
+
'absolute cursor-pointer top-12 right-12 rounded-4 p-4 bg-transparent border-none text-foreground-neutral-muted hover:text-foreground-neutral-base hover:bg-background-components-hover transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-background-accent-blue-base focus-visible:ring-offset-2',
|
|
134
|
+
className,
|
|
135
|
+
)}
|
|
136
|
+
aria-label="Close"
|
|
137
|
+
{...props}
|
|
138
|
+
>
|
|
139
|
+
<Icon name="close" className={cn(closeIconVariants({variant}))} />
|
|
140
|
+
</button>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export {Alert, AlertContent, AlertTitle, AlertDescription, AlertActions, AlertAction, AlertClose};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './alert';
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
2
|
+
import {cva, type VariantProps} from 'class-variance-authority';
|
|
3
|
+
import {
|
|
4
|
+
Children,
|
|
5
|
+
type ComponentProps,
|
|
6
|
+
cloneElement,
|
|
7
|
+
type ReactElement,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
useMemo,
|
|
10
|
+
} from 'react';
|
|
11
|
+
import {cn} from 'utils/cn';
|
|
12
|
+
import {TooltipContent, TooltipProvider, TooltipTrigger} from '../tooltip/tooltip';
|
|
13
|
+
|
|
14
|
+
const avatarGroupVariants = cva('flex items-start', {
|
|
15
|
+
variants: {
|
|
16
|
+
size: {
|
|
17
|
+
'3xs': '-space-x-4',
|
|
18
|
+
'2xs': '-space-x-4',
|
|
19
|
+
xs: '-space-x-4',
|
|
20
|
+
sm: '-space-x-4',
|
|
21
|
+
md: '-space-x-4',
|
|
22
|
+
lg: '-space-x-6',
|
|
23
|
+
xl: '-space-x-6',
|
|
24
|
+
'2xl': '-space-x-12',
|
|
25
|
+
'3xl': '-space-x-12',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultVariants: {
|
|
29
|
+
size: 'md',
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const avatarGroupOverflowVariants = cva(
|
|
34
|
+
'flex shrink-0 items-center justify-center rounded-full bg-background-components-base text-foreground-neutral-subtle font-medium ring-1 ring-border-neutral-base-component ring-offset-1 ring-offset-background-neutral-base shadow-button-neutral',
|
|
35
|
+
{
|
|
36
|
+
variants: {
|
|
37
|
+
size: {
|
|
38
|
+
'3xs': 'size-[18px] text-[10px] leading-[10px]',
|
|
39
|
+
'2xs': 'size-[20px] text-[11px] leading-[11px]',
|
|
40
|
+
xs: 'size-[24px] text-xs leading-4',
|
|
41
|
+
sm: 'size-[28px] text-xs leading-5',
|
|
42
|
+
md: 'size-[32px] text-sm leading-5',
|
|
43
|
+
lg: 'size-[36px] text-sm leading-5',
|
|
44
|
+
xl: 'size-[40px] text-base leading-6',
|
|
45
|
+
'2xl': 'size-[80px] text-2xl leading-8',
|
|
46
|
+
'3xl': 'size-[120px] text-4xl leading-[56px]',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
defaultVariants: {
|
|
50
|
+
size: 'md',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
type TooltipContentProps = ComponentProps<typeof TooltipContent>;
|
|
56
|
+
|
|
57
|
+
type AvatarContainerProps = {
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
zIndex: number;
|
|
60
|
+
tooltipContent?: ReactNode;
|
|
61
|
+
tooltipProps?: Partial<TooltipContentProps>;
|
|
62
|
+
animateOnHover?: boolean;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function AvatarContainer({
|
|
66
|
+
children,
|
|
67
|
+
zIndex,
|
|
68
|
+
tooltipContent,
|
|
69
|
+
tooltipProps,
|
|
70
|
+
animateOnHover = false,
|
|
71
|
+
}: AvatarContainerProps) {
|
|
72
|
+
return (
|
|
73
|
+
<TooltipPrimitive.Root>
|
|
74
|
+
<TooltipTrigger asChild>
|
|
75
|
+
<div
|
|
76
|
+
data-slot="avatar-container"
|
|
77
|
+
className={cn(
|
|
78
|
+
'relative',
|
|
79
|
+
animateOnHover && 'transition-transform duration-300 ease-out hover:-translate-y-2',
|
|
80
|
+
)}
|
|
81
|
+
style={{zIndex}}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</div>
|
|
85
|
+
</TooltipTrigger>
|
|
86
|
+
{tooltipContent && (
|
|
87
|
+
<AvatarGroupTooltip {...tooltipProps}>{tooltipContent}</AvatarGroupTooltip>
|
|
88
|
+
)}
|
|
89
|
+
</TooltipPrimitive.Root>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getTooltipContent(children: ReactNode): ReactNode | null {
|
|
94
|
+
const tooltip = Children.toArray(children).find(
|
|
95
|
+
(child) =>
|
|
96
|
+
typeof child === 'object' &&
|
|
97
|
+
child !== null &&
|
|
98
|
+
'type' in child &&
|
|
99
|
+
child.type === AvatarGroupTooltip,
|
|
100
|
+
) as ReactElement<ComponentProps<typeof AvatarGroupTooltip>> | undefined;
|
|
101
|
+
|
|
102
|
+
return tooltip?.props.children || null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
type AvatarGroupTooltipProps = TooltipContentProps;
|
|
106
|
+
|
|
107
|
+
function AvatarGroupTooltip(props: AvatarGroupTooltipProps) {
|
|
108
|
+
return <TooltipContent {...props} />;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type AvatarGroupProps = ComponentProps<'div'> &
|
|
112
|
+
VariantProps<typeof avatarGroupVariants> & {
|
|
113
|
+
children: ReactElement[];
|
|
114
|
+
maxVisible?: number;
|
|
115
|
+
animateOnHover?: boolean;
|
|
116
|
+
tooltipProps?: Partial<TooltipContentProps>;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export function AvatarGroup({
|
|
120
|
+
className,
|
|
121
|
+
size = 'md',
|
|
122
|
+
children,
|
|
123
|
+
maxVisible,
|
|
124
|
+
animateOnHover = false,
|
|
125
|
+
tooltipProps = {side: 'top', sideOffset: 8},
|
|
126
|
+
...props
|
|
127
|
+
}: AvatarGroupProps) {
|
|
128
|
+
const normalizedSize = size ?? 'md';
|
|
129
|
+
|
|
130
|
+
const childrenArray = Children.toArray(children) as ReactElement[];
|
|
131
|
+
|
|
132
|
+
const {visibleCount, visibleAvatars, overflowCount} = useMemo(() => {
|
|
133
|
+
const count =
|
|
134
|
+
maxVisible !== undefined ? Math.min(maxVisible, childrenArray.length) : childrenArray.length;
|
|
135
|
+
return {
|
|
136
|
+
visibleCount: count,
|
|
137
|
+
visibleAvatars: childrenArray.slice(0, count),
|
|
138
|
+
overflowCount: childrenArray.length - count,
|
|
139
|
+
};
|
|
140
|
+
}, [childrenArray, maxVisible]);
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<TooltipProvider delayDuration={0}>
|
|
144
|
+
<div
|
|
145
|
+
className={cn(avatarGroupVariants({size: normalizedSize}), className)}
|
|
146
|
+
data-slot="avatar-group"
|
|
147
|
+
{...props}
|
|
148
|
+
>
|
|
149
|
+
{visibleAvatars.map((child, index) => {
|
|
150
|
+
const zIndex = index + 1;
|
|
151
|
+
const childProps = 'props' in child ? (child.props as {children?: ReactNode}) : {};
|
|
152
|
+
const tooltipContent = getTooltipContent(childProps.children);
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<AvatarContainer
|
|
156
|
+
key={child.key || index}
|
|
157
|
+
zIndex={zIndex}
|
|
158
|
+
tooltipContent={tooltipContent}
|
|
159
|
+
tooltipProps={tooltipProps}
|
|
160
|
+
animateOnHover={animateOnHover}
|
|
161
|
+
>
|
|
162
|
+
{cloneElement(child, {
|
|
163
|
+
...childProps,
|
|
164
|
+
children: tooltipContent ? undefined : childProps.children,
|
|
165
|
+
} as Partial<typeof childProps>)}
|
|
166
|
+
</AvatarContainer>
|
|
167
|
+
);
|
|
168
|
+
})}
|
|
169
|
+
{overflowCount > 0 && (
|
|
170
|
+
<div
|
|
171
|
+
className={cn(
|
|
172
|
+
'relative',
|
|
173
|
+
avatarGroupOverflowVariants({size: normalizedSize}),
|
|
174
|
+
'rounded-full',
|
|
175
|
+
)}
|
|
176
|
+
style={{zIndex: visibleCount + 1}}
|
|
177
|
+
>
|
|
178
|
+
+{overflowCount}
|
|
179
|
+
</div>
|
|
180
|
+
)}
|
|
181
|
+
</div>
|
|
182
|
+
</TooltipProvider>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export {AvatarGroupTooltip, type AvatarGroupTooltipProps};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/react';
|
|
2
|
+
import {Code} from 'components/typography';
|
|
3
|
+
import {Avatar} from './avatar';
|
|
4
|
+
import {AvatarGroup, AvatarGroupTooltip} from './avatar-group';
|
|
5
|
+
|
|
6
|
+
const contentOptions = ['letters', 'logo', 'logoPlaceholder', 'image', 'upload'] as const;
|
|
7
|
+
const radiusOptions = ['full', 'rounded'] as const;
|
|
8
|
+
const sizeOptions = ['3xs', '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'] as const;
|
|
9
|
+
|
|
10
|
+
const meta = {
|
|
11
|
+
title: 'Components/Avatar',
|
|
12
|
+
component: Avatar,
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
argTypes: {
|
|
15
|
+
content: {
|
|
16
|
+
control: 'select',
|
|
17
|
+
options: contentOptions,
|
|
18
|
+
},
|
|
19
|
+
radius: {
|
|
20
|
+
control: 'select',
|
|
21
|
+
options: radiusOptions,
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
control: 'select',
|
|
25
|
+
options: sizeOptions,
|
|
26
|
+
},
|
|
27
|
+
fallback: {
|
|
28
|
+
control: 'text',
|
|
29
|
+
},
|
|
30
|
+
src: {
|
|
31
|
+
control: 'text',
|
|
32
|
+
},
|
|
33
|
+
alt: {
|
|
34
|
+
control: 'text',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
args: {
|
|
38
|
+
content: 'letters',
|
|
39
|
+
radius: 'full',
|
|
40
|
+
size: 'md',
|
|
41
|
+
fallback: 'John Doe',
|
|
42
|
+
},
|
|
43
|
+
} satisfies Meta<typeof Avatar>;
|
|
44
|
+
|
|
45
|
+
export default meta;
|
|
46
|
+
type Story = StoryObj<typeof meta>;
|
|
47
|
+
|
|
48
|
+
export const Default: Story = {
|
|
49
|
+
args: {
|
|
50
|
+
content: 'upload',
|
|
51
|
+
fallback: 'Kyle Nguyen',
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
render: (args) => (
|
|
55
|
+
<div className="flex flex-wrap items-end gap-16">
|
|
56
|
+
{sizeOptions.map((size) => (
|
|
57
|
+
<div key={size} className="flex flex-col items-center gap-8">
|
|
58
|
+
<Avatar {...args} size={size} />
|
|
59
|
+
<Code variant="label" className="text-foreground-neutral-base">
|
|
60
|
+
{size}
|
|
61
|
+
</Code>
|
|
62
|
+
</div>
|
|
63
|
+
))}
|
|
64
|
+
</div>
|
|
65
|
+
),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// AvatarGroup Stories
|
|
69
|
+
const avatarGroupMeta = {
|
|
70
|
+
title: 'Components/AvatarGroup',
|
|
71
|
+
component: AvatarGroup,
|
|
72
|
+
tags: ['autodocs'],
|
|
73
|
+
argTypes: {
|
|
74
|
+
size: {
|
|
75
|
+
control: 'select',
|
|
76
|
+
options: sizeOptions,
|
|
77
|
+
},
|
|
78
|
+
maxVisible: {
|
|
79
|
+
control: 'number',
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
args: {
|
|
83
|
+
size: 'md',
|
|
84
|
+
children: [],
|
|
85
|
+
},
|
|
86
|
+
} satisfies Meta<typeof AvatarGroup>;
|
|
87
|
+
|
|
88
|
+
export const AvatarGroupDefault: StoryObj<typeof avatarGroupMeta> = {
|
|
89
|
+
args: {
|
|
90
|
+
children: [],
|
|
91
|
+
},
|
|
92
|
+
render: () => {
|
|
93
|
+
const avatars = [
|
|
94
|
+
{name: 'John Doe', content: 'image'},
|
|
95
|
+
{name: 'Jane Smith', content: 'image'},
|
|
96
|
+
{name: 'Bob Johnson', content: 'image'},
|
|
97
|
+
{name: 'Alice Brown', content: 'image'},
|
|
98
|
+
] as const;
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className="flex flex-col gap-16">
|
|
102
|
+
<div className="flex flex-col gap-8">
|
|
103
|
+
<Code variant="label" className="text-foreground-neutral-base">
|
|
104
|
+
Default (without tooltips)
|
|
105
|
+
</Code>
|
|
106
|
+
<AvatarGroup size="md">
|
|
107
|
+
{avatars.map((avatar) => (
|
|
108
|
+
<Avatar key={avatar.name} content={avatar.content} fallback={avatar.name} />
|
|
109
|
+
))}
|
|
110
|
+
</AvatarGroup>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const AvatarGroupWithTooltips: StoryObj<typeof avatarGroupMeta> = {
|
|
118
|
+
args: {
|
|
119
|
+
children: [],
|
|
120
|
+
},
|
|
121
|
+
render: () => {
|
|
122
|
+
const avatars = [
|
|
123
|
+
{name: 'John Doe', content: 'image'},
|
|
124
|
+
{name: 'Jane Smith', content: 'image'},
|
|
125
|
+
{name: 'Bob Johnson', content: 'image'},
|
|
126
|
+
{name: 'Alice Brown', content: 'image'},
|
|
127
|
+
{name: 'Carlos Vega', content: 'image'},
|
|
128
|
+
{name: 'Linda Tran', content: 'image'},
|
|
129
|
+
] as const;
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div className="flex flex-col gap-16">
|
|
133
|
+
<div className="flex flex-col gap-8">
|
|
134
|
+
<Code variant="label" className="text-foreground-neutral-base">
|
|
135
|
+
With Tooltips
|
|
136
|
+
</Code>
|
|
137
|
+
<AvatarGroup size="md">
|
|
138
|
+
{avatars.map((avatar) => (
|
|
139
|
+
<Avatar key={avatar.name} content={avatar.content} fallback={avatar.name}>
|
|
140
|
+
<AvatarGroupTooltip>{avatar.name}</AvatarGroupTooltip>
|
|
141
|
+
</Avatar>
|
|
142
|
+
))}
|
|
143
|
+
</AvatarGroup>
|
|
144
|
+
</div>
|
|
145
|
+
<div className="flex flex-col gap-8">
|
|
146
|
+
<Code variant="label" className="text-foreground-neutral-base">
|
|
147
|
+
With Tooltips (maxVisible: 4)
|
|
148
|
+
</Code>
|
|
149
|
+
<AvatarGroup size="md" maxVisible={4}>
|
|
150
|
+
{avatars.map((avatar) => (
|
|
151
|
+
<Avatar key={avatar.name} content={avatar.content} fallback={avatar.name}>
|
|
152
|
+
<AvatarGroupTooltip>{avatar.name}</AvatarGroupTooltip>
|
|
153
|
+
</Avatar>
|
|
154
|
+
))}
|
|
155
|
+
</AvatarGroup>
|
|
156
|
+
</div>
|
|
157
|
+
<div className="flex flex-col gap-8">
|
|
158
|
+
<Code variant="label" className="text-foreground-neutral-base">
|
|
159
|
+
With Tooltips and Hover Animation
|
|
160
|
+
</Code>
|
|
161
|
+
<AvatarGroup size="md" maxVisible={4} animateOnHover>
|
|
162
|
+
{avatars.map((avatar) => (
|
|
163
|
+
<Avatar key={avatar.name} content={avatar.content} fallback={avatar.name}>
|
|
164
|
+
<AvatarGroupTooltip>{avatar.name}</AvatarGroupTooltip>
|
|
165
|
+
</Avatar>
|
|
166
|
+
))}
|
|
167
|
+
</AvatarGroup>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
},
|
|
172
|
+
};
|