Skip to content

Commit 43cb82d

Browse files
committed
Merge remote-tracking branch 'origin/master' into unify-ds
# Conflicts: # package-lock.json # package.json # src/elements/Avatar/Avatar.tsx # src/elements/index.ts # src/utils/Theme/themes/theme.ts # src/utils/index.ts
2 parents 3dd354e + 49a3303 commit 43cb82d

File tree

12 files changed

+533
-18
lines changed

12 files changed

+533
-18
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 9.3.0 - 10/22/25
2+
- [chore] Skeleton loading component with theme support, animation, and predefined variants
3+
4+
# 9.2.2 - 10/14/25
5+
- [chore] Replace vulnerable @marko19907/string-to-color with secure custom implementation #312
6+
17
# 9.2.1 - 9/11/25
28
- [fix] Add return to clone element to add ability use values from overridden fn #308
39

package-lock.json

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "reablocks",
3-
"version": "10.0.0-alpha.8",
3+
"version": "10.0.0-alpha.9",
44
"description": "Component library for React",
55
"scripts": {
66
"build": "npm run build:js && npm run build:styles && npm run rewrite:stories && npm run build:docs",
@@ -60,7 +60,6 @@
6060
"homepage": "https://github.com/reaviz/reablocks#readme",
6161
"dependencies": {
6262
"@floating-ui/react": "^0.27.16",
63-
"@marko19907/string-to-color": "^1.0.0",
6463
"@reaviz/react-use-fuzzy": "^1.0.3",
6564
"body-scroll-lock-upgrade": "^1.1.0",
6665
"chroma-js": "^3.1.2",
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import React from 'react';
2+
3+
import { Skeleton } from './Skeleton';
4+
5+
export default {
6+
title: 'Components/Elements/Skeleton',
7+
component: Skeleton
8+
};
9+
10+
export const Simple = () => {
11+
return (
12+
<div className="w-[300px]">
13+
<Skeleton className="h-5 mb-2.5" />
14+
</div>
15+
);
16+
};
17+
18+
export const Animated = () => {
19+
return (
20+
<div className="w-[300px]">
21+
<Skeleton animated className="h-5 mb-2.5" />
22+
</div>
23+
);
24+
};
25+
26+
export const Sizes = () => {
27+
return (
28+
<div className="w-[300px]">
29+
<Skeleton className="h-2.5 mb-2.5" />
30+
<Skeleton className="h-5 mb-2.5" />
31+
<Skeleton className="h-[30px] mb-2.5" />
32+
<Skeleton className="h-10" />
33+
</div>
34+
);
35+
};
36+
37+
export const Multiple = () => {
38+
const widths = ['w-full', 'w-[90%]', 'w-[80%]', 'w-[70%]', 'w-[60%]'];
39+
return (
40+
<div className="w-[300px]">
41+
{[...Array(5)].map((_, i) => (
42+
<Skeleton key={i} animated className={`h-5 mb-2.5 ${widths[i]}`} />
43+
))}
44+
</div>
45+
);
46+
};
47+
48+
export const Shapes = () => {
49+
return (
50+
<div className="flex gap-5 items-center flex-wrap">
51+
<Skeleton animated className="w-[60px] h-[60px] rounded-full" />
52+
<Skeleton animated className="w-[200px] h-[60px]" />
53+
<Skeleton animated className="w-[100px] h-[100px] rounded-lg" />
54+
</div>
55+
);
56+
};
57+
58+
export const CardPlaceholder = () => {
59+
return (
60+
<div className="w-[400px] p-5 border border-gray-300 rounded-lg">
61+
<Skeleton animated className="w-[60px] h-[60px] rounded-full mb-2.5" />
62+
<Skeleton animated className="h-6 mb-2.5 w-[60%]" />
63+
<Skeleton animated className="h-4 mb-2" />
64+
<Skeleton animated className="h-4 mb-2 w-[90%]" />
65+
<Skeleton animated className="h-4 w-[70%]" />
66+
</div>
67+
);
68+
};
69+
70+
export const CustomStyles = () => {
71+
return (
72+
<div className="w-[300px]">
73+
<Skeleton
74+
animated
75+
className="my-4 h-[100px] rounded-2xl bg-blue-500 opacity-30"
76+
/>
77+
<Skeleton className="h-[50px] rounded bg-gradient-to-r from-red-400 to-yellow-300" />
78+
</div>
79+
);
80+
};
81+
82+
export const Variants = () => {
83+
return (
84+
<div className="flex flex-col gap-6">
85+
<div>
86+
<h3 className="text-sm font-semibold mb-2 light:text-gray-700 dark:text-gray-300">
87+
Text
88+
</h3>
89+
<Skeleton variant="text" animated />
90+
</div>
91+
<div>
92+
<h3 className="text-sm font-semibold mb-2 light:text-gray-700 dark:text-gray-300">
93+
Rounded
94+
</h3>
95+
<Skeleton variant="rounded" animated />
96+
</div>
97+
<div>
98+
<h3 className="text-sm font-semibold mb-2 light:text-gray-700 dark:text-gray-300">
99+
Rectangle
100+
</h3>
101+
<Skeleton variant="rectangle" animated />
102+
</div>
103+
<div>
104+
<h3 className="text-sm font-semibold mb-2 light:text-gray-700 dark:text-gray-300">
105+
Square
106+
</h3>
107+
<Skeleton variant="square" animated />
108+
</div>
109+
</div>
110+
);
111+
};
112+
113+
export const VariantsInContext = () => {
114+
return (
115+
<div className="w-[400px] p-5 border border-gray-300 rounded-lg">
116+
<div className="flex items-center gap-4 mb-4">
117+
<Skeleton variant="rounded" animated />
118+
<div className="flex-1">
119+
<Skeleton variant="text" animated className="mb-2" />
120+
<Skeleton variant="text" animated className="w-3/4" />
121+
</div>
122+
</div>
123+
<Skeleton variant="rectangle" animated className="mb-3" />
124+
<Skeleton variant="text" animated className="mb-2" />
125+
<Skeleton variant="text" animated className="w-5/6" />
126+
</div>
127+
);
128+
};

src/elements/Skeleton/Skeleton.tsx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import type { FC } from 'react';
2+
import React from 'react';
3+
import { twMerge } from 'tailwind-merge';
4+
5+
import { useComponentTheme } from '@/utils';
6+
7+
import type { SkeletonTheme } from './SkeletonTheme';
8+
9+
export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
10+
/**
11+
* Additional CSS class names to apply to the skeleton.
12+
*/
13+
className?: string;
14+
15+
/**
16+
* Inline styles to apply to the skeleton.
17+
*/
18+
style?: React.CSSProperties;
19+
20+
/**
21+
* Whether to show animated shimmer effect.
22+
* @default false
23+
*/
24+
animated?: boolean;
25+
26+
/**
27+
* Predefined variant for the skeleton.
28+
* - text: Single line of text (h-4 w-full)
29+
* - rounded: Circular shape for avatars (rounded-full w-10 h-10)
30+
* - rectangle: Wide rectangular shape (h-24 w-full)
31+
* - square: Square shape (w-24 h-24)
32+
*/
33+
variant?: 'text' | 'rounded' | 'rectangle' | 'square' | string;
34+
35+
/**
36+
* Theme for the Skeleton.
37+
*/
38+
theme?: SkeletonTheme;
39+
}
40+
41+
export const Skeleton: FC<SkeletonProps> = ({
42+
className,
43+
style,
44+
animated = false,
45+
variant,
46+
theme: customTheme,
47+
...rest
48+
}) => {
49+
const theme: SkeletonTheme = useComponentTheme('skeleton', customTheme);
50+
51+
return (
52+
<div
53+
className={twMerge(
54+
theme.base,
55+
animated && theme.animated,
56+
variant && theme.variants[variant],
57+
className
58+
)}
59+
style={style}
60+
aria-busy="true"
61+
aria-live="polite"
62+
{...rest}
63+
/>
64+
);
65+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export interface SkeletonTheme {
2+
base: string;
3+
animated: string;
4+
variants: {
5+
text: string;
6+
rounded: string;
7+
rectangle: string;
8+
square: string;
9+
[key: string]: string;
10+
};
11+
}
12+
13+
const baseTheme: SkeletonTheme = {
14+
base: 'rounded-md',
15+
animated: '',
16+
variants: {
17+
text: 'h-4 w-full',
18+
rounded: 'rounded-full w-10 h-10',
19+
rectangle: 'h-24 w-full',
20+
square: 'w-24 h-24'
21+
}
22+
};
23+
24+
export const skeletonTheme: SkeletonTheme = {
25+
...baseTheme,
26+
base: [baseTheme.base, 'light:bg-gray-200 dark:bg-gray-700'].join(' '),
27+
animated:
28+
'animate-[pulse_1.5s_ease-in-out_infinite] light:bg-gradient-to-r light:from-gray-200 light:via-gray-300 light:to-gray-200 dark:bg-gradient-to-r dark:from-gray-700 dark:via-gray-600 dark:to-gray-700 bg-[length:200%_100%]',
29+
variants: baseTheme.variants
30+
};
31+
32+
export const legacySkeletonTheme: SkeletonTheme = {
33+
...baseTheme,
34+
base: [baseTheme.base, 'bg-[var(--skeleton-background)]'].join(' '),
35+
animated:
36+
'animate-[pulse_1.5s_ease-in-out_infinite] bg-[var(--skeleton-gradient)] bg-[length:200%_100%]',
37+
variants: baseTheme.variants
38+
};

src/elements/Skeleton/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './Skeleton';
2+
export * from './SkeletonTheme';

src/elements/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export * from './IconButton';
99
export * from './Kbd';
1010
export * from './Loader';
1111
export * from './Navigation';
12+
export * from './Skeleton';

src/utils/Theme/themes/theme.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { ellipsisTheme } from '@/data/Ellipsis/EllipsisTheme';
1010
import { pagerTheme } from '@/data/Pager/PagerTheme';
1111
import { redactTheme } from '@/data/Redact/RedactTheme';
1212
import { sortTheme } from '@/data/Sort/SortTheme';
13+
import type { SkeletonTheme } from '@/elements';
1314
import {
1415
type ArrowTheme,
1516
type AvatarGroupTheme,
@@ -32,6 +33,7 @@ import { commandPaletteTheme } from '@/elements/CommandPalette/CommandPaletteThe
3233
import { kbdTheme } from '@/elements/Kbd/KbdTheme';
3334
import { dotsLoaderTheme } from '@/elements/Loader/DotsLoaderTheme';
3435
import { navigationTheme } from '@/elements/Navigation/NavigationTheme';
36+
import { skeletonTheme } from '@/elements/Skeleton';
3537
import type {
3638
CalendarRangeTheme,
3739
CalendarTheme,
@@ -154,6 +156,7 @@ export interface ReablocksTheme {
154156
callout: CalloutTheme;
155157
backdrop: BackdropTheme;
156158
navigation: NavigationTheme;
159+
skeleton: SkeletonTheme;
157160
};
158161
}
159162

@@ -206,6 +209,7 @@ export const theme: ReablocksTheme = {
206209
stepper: stepperTheme,
207210
callout: calloutTheme,
208211
backdrop: backdropTheme,
212+
skeleton: skeletonTheme,
209213
navigation: navigationTheme
210214
}
211215
};

src/utils/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ export * from './ExitListener';
33
export * from './Overlay';
44
export * from './Portal';
55
export * from './Position';
6+
export * from './stringToColor';
67
export * from './Theme';
78
export * from './useCursor';
9+
export * from './useCursor';
810
export * from './useId';
911
export * from './useUserSelect';

0 commit comments

Comments
 (0)