-
Notifications
You must be signed in to change notification settings - Fork 37
/
Skeleton.tsx
64 lines (60 loc) · 1.68 KB
/
Skeleton.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { useMergeRefs } from '@floating-ui/react';
import { Slot } from '@radix-ui/react-slot';
import cl from 'clsx/lite';
import { type HTMLAttributes, forwardRef } from 'react';
import { useSynchronizedAnimation } from '../../../utilities';
export type SkeletonProps = {
/**
* Change the default rendered element for the one passed as a child, merging their props and behavior.
* @default false
*/
asChild?: boolean;
/** The width of the component */
width?: string | number;
/** The height of the component */
height?: string | number;
/**
* The shape variant
* @default 'rectangle'
* */
variant?: 'rectangle' | 'circle' | 'text';
} & HTMLAttributes<HTMLSpanElement> &
(
| { variant: 'text'; characters?: number }
| { variant?: 'rectangle' | 'circle'; characters?: never }
);
export const Skeleton = forwardRef<HTMLSpanElement, SkeletonProps>(
function Skeleton(
{
asChild,
className,
children,
height,
style,
variant = 'rectangle',
width,
...rest
},
ref,
) {
const Component = asChild ? Slot : 'span';
const isText = variant === 'text';
const childrenText = isText && '-'.repeat(Number(width) || 1);
const animationRef = useSynchronizedAnimation<HTMLSpanElement>(
'ds-skeleton-opacity-fade',
);
const mergedRefs = useMergeRefs([animationRef, ref]);
return (
<Component
aria-hidden='true'
className={cl('ds-skeleton', className)}
data-variant={variant}
ref={mergedRefs}
style={isText ? style : { width, height, ...style }}
{...rest}
>
{children || childrenText}
</Component>
);
},
);