@sproutsocial/seeds-react-skeleton 1.0.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/.eslintignore +6 -0
- package/.eslintrc.js +4 -0
- package/.turbo/turbo-build.log +21 -0
- package/CHANGELOG.md +7 -0
- package/dist/esm/index.js +136 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +173 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +9 -0
- package/package.json +43 -0
- package/src/Skeleton.stories.tsx +41 -0
- package/src/Skeleton.tsx +142 -0
- package/src/__tests__/Skeleton.test.tsx +31 -0
- package/src/__tests__/Skeleton.typetest.tsx +13 -0
- package/src/index.ts +4 -0
- package/src/styled.d.ts +7 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +12 -0
package/.eslintignore
ADDED
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
yarn run v1.22.22
|
|
2
|
+
$ tsup --dts
|
|
3
|
+
CLI Building entry: src/index.ts
|
|
4
|
+
CLI Using tsconfig: tsconfig.json
|
|
5
|
+
CLI tsup v8.0.2
|
|
6
|
+
CLI Using tsup config: /home/runner/work/seeds/seeds/seeds-react/seeds-react-skeleton/tsup.config.ts
|
|
7
|
+
CLI Target: es2022
|
|
8
|
+
CLI Cleaning output folder
|
|
9
|
+
CJS Build start
|
|
10
|
+
ESM Build start
|
|
11
|
+
CJS dist/index.js 4.96 KB
|
|
12
|
+
CJS dist/index.js.map 5.24 KB
|
|
13
|
+
CJS ⚡️ Build success in 119ms
|
|
14
|
+
ESM dist/esm/index.js 3.23 KB
|
|
15
|
+
ESM dist/esm/index.js.map 5.17 KB
|
|
16
|
+
ESM ⚡️ Build success in 125ms
|
|
17
|
+
DTS Build start
|
|
18
|
+
DTS ⚡️ Build success in 33302ms
|
|
19
|
+
DTS dist/index.d.ts 317.00 B
|
|
20
|
+
DTS dist/index.d.mts 317.00 B
|
|
21
|
+
Done in 41.01s.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// src/Skeleton.tsx
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
import Box from "@sproutsocial/seeds-react-box";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
var SkeletonAttrs = ({ borderRadius, height, width }) => ({
|
|
6
|
+
className: borderRadius === "pill" && height === width ? "circular" : "linear"
|
|
7
|
+
});
|
|
8
|
+
var Skeleton = styled(Box).attrs(SkeletonAttrs)`
|
|
9
|
+
position: relative;
|
|
10
|
+
background: ${(props) => props.theme.colors.container.background.decorative.neutral};
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
&.circular {
|
|
13
|
+
&:before {
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: -25%;
|
|
16
|
+
left: -25%;
|
|
17
|
+
content: '';
|
|
18
|
+
background-image: ${(props) => `conic-gradient(
|
|
19
|
+
${props.theme.colors.container.background.decorative.neutral} 270deg,
|
|
20
|
+
${props.theme.colors.container.border.decorative.neutral} 300deg
|
|
21
|
+
);`};
|
|
22
|
+
height: 150%;
|
|
23
|
+
width: 150%;
|
|
24
|
+
animation: SkeletonRotate 2s infinite linear;
|
|
25
|
+
}
|
|
26
|
+
&:after {
|
|
27
|
+
position: absolute;
|
|
28
|
+
top: 50%;
|
|
29
|
+
left: 50%;
|
|
30
|
+
transform: translate(-50%, -50%);
|
|
31
|
+
content: '';
|
|
32
|
+
height: calc(100% - 8px);
|
|
33
|
+
width: calc(100% - 8px);
|
|
34
|
+
background: ${(p) => p.theme.colors.app.background.base};
|
|
35
|
+
border-radius: 50%;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
&.linear {
|
|
39
|
+
position: relative;
|
|
40
|
+
background-image: ${(props) => `linear-gradient(
|
|
41
|
+
288deg,
|
|
42
|
+
${props.theme.colors.container.background.decorative.neutral} 32%,
|
|
43
|
+
${props.theme.colors.container.border.decorative.neutral},
|
|
44
|
+
${props.theme.colors.container.background.decorative.neutral} 68%
|
|
45
|
+
);`}
|
|
46
|
+
background-size: 400%;
|
|
47
|
+
background-repeat: no-repeat;
|
|
48
|
+
animation: SkeletonShimmer 2s linear infinite reverse;
|
|
49
|
+
overflow: hidden;
|
|
50
|
+
&:after {
|
|
51
|
+
position: absolute;
|
|
52
|
+
bottom: 0;
|
|
53
|
+
content: "";
|
|
54
|
+
height: calc(100% - 4px);
|
|
55
|
+
width: 100%;
|
|
56
|
+
background: ${(props) => props.theme.colors.container.background.decorative.neutral};
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@media (prefers-reduced-motion) {
|
|
62
|
+
&.linear,
|
|
63
|
+
&.circular::before {
|
|
64
|
+
animation: none;
|
|
65
|
+
}
|
|
66
|
+
&:before,
|
|
67
|
+
&:after {
|
|
68
|
+
display: none;
|
|
69
|
+
}
|
|
70
|
+
&.linear,
|
|
71
|
+
&.circular {
|
|
72
|
+
border: 1px solid ${(props) => props.theme.colors.container.border.decorative.neutral};
|
|
73
|
+
animation: SkeletonPulse 2s linear infinite alternate;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@keyframes SkeletonRotate {
|
|
78
|
+
100% {
|
|
79
|
+
transform: rotate(360deg);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
@keyframes SkeletonRotateFade {
|
|
83
|
+
50% {
|
|
84
|
+
transform: rotate(360deg);
|
|
85
|
+
}
|
|
86
|
+
90% {
|
|
87
|
+
opacity: 1;
|
|
88
|
+
}
|
|
89
|
+
100% {
|
|
90
|
+
transform: rotate(720deg);
|
|
91
|
+
opacity: 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@keyframes SkeletonShimmer {
|
|
96
|
+
0% {
|
|
97
|
+
background-position: 0% 0;
|
|
98
|
+
}
|
|
99
|
+
100% {
|
|
100
|
+
background-position: 100% 0;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
@keyframes SkeletonPulse {
|
|
104
|
+
0% {
|
|
105
|
+
border-color: ${(props) => props.theme.colors.container.border.decorative.neutral}FF;
|
|
106
|
+
}
|
|
107
|
+
100% {
|
|
108
|
+
border-color: ${(props) => props.theme.colors.container.border.decorative.neutral}1A;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
`;
|
|
112
|
+
var SkeletonComponent = ({
|
|
113
|
+
borderRadius,
|
|
114
|
+
height,
|
|
115
|
+
width,
|
|
116
|
+
...props
|
|
117
|
+
}) => {
|
|
118
|
+
return /* @__PURE__ */ jsx(
|
|
119
|
+
Skeleton,
|
|
120
|
+
{
|
|
121
|
+
borderRadius,
|
|
122
|
+
height,
|
|
123
|
+
width,
|
|
124
|
+
...props
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
var Skeleton_default = SkeletonComponent;
|
|
129
|
+
|
|
130
|
+
// src/index.ts
|
|
131
|
+
var src_default = Skeleton_default;
|
|
132
|
+
export {
|
|
133
|
+
Skeleton_default as Skeleton,
|
|
134
|
+
src_default as default
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/Skeleton.tsx","../../src/index.ts"],"sourcesContent":["import styled from \"styled-components\";\nimport Box, { type TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\n/**\n *\n * @param borderRadius\n * @returns classname string for handling appropriate loader style depending on passed in properties\n */\n// @ts-ignore TODO: fix noImplicitAny error here. IDK why there are no types for this component\nconst SkeletonAttrs = ({ borderRadius, height, width }) => ({\n className:\n borderRadius === \"pill\" && height === width ? \"circular\" : \"linear\",\n});\n\nconst Skeleton = styled(Box).attrs(SkeletonAttrs)`\n position: relative;\n background: ${(props) =>\n props.theme.colors.container.background.decorative.neutral};\n overflow: hidden;\n &.circular {\n &:before {\n position: absolute;\n top: -25%;\n left: -25%;\n content: '';\n background-image: ${(props) => `conic-gradient(\n ${props.theme.colors.container.background.decorative.neutral} 270deg,\n ${props.theme.colors.container.border.decorative.neutral} 300deg\n );`};\n height: 150%;\n width: 150%;\n animation: SkeletonRotate 2s infinite linear;\n }\n &:after {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n content: '';\n height: calc(100% - 8px);\n width: calc(100% - 8px);\n background: ${(p) => p.theme.colors.app.background.base};\n border-radius: 50%;\n }\n }\n &.linear {\n position: relative;\n background-image: ${(props) => `linear-gradient(\n 288deg,\n ${props.theme.colors.container.background.decorative.neutral} 32%,\n ${props.theme.colors.container.border.decorative.neutral},\n ${props.theme.colors.container.background.decorative.neutral} 68%\n );`}\n background-size: 400%;\n background-repeat: no-repeat;\n animation: SkeletonShimmer 2s linear infinite reverse;\n overflow: hidden;\n &:after {\n position: absolute;\n bottom: 0;\n content: \"\";\n height: calc(100% - 4px);\n width: 100%;\n background: ${(props) =>\n props.theme.colors.container.background.decorative.neutral};\n \n }\n }\n\n @media (prefers-reduced-motion) {\n &.linear,\n &.circular::before {\n animation: none;\n }\n &:before,\n &:after {\n display: none;\n }\n &.linear,\n &.circular {\n border: 1px solid ${(props) =>\n props.theme.colors.container.border.decorative.neutral};\n animation: SkeletonPulse 2s linear infinite alternate; \n }\n }\n\n @keyframes SkeletonRotate {\n 100% {\n transform: rotate(360deg);\n }\n }\n @keyframes SkeletonRotateFade {\n 50% {\n transform: rotate(360deg);\n }\n 90% {\n opacity: 1;\n }\n 100% {\n transform: rotate(720deg);\n opacity: 0;\n }\n }\n\n @keyframes SkeletonShimmer {\n 0% {\n background-position: 0% 0;\n }\n 100% {\n background-position: 100% 0;\n }\n }\n @keyframes SkeletonPulse {\n 0% {\n border-color: ${(props) =>\n props.theme.colors.container.border.decorative.neutral}FF;\n }\n 100% {\n border-color: ${(props) =>\n props.theme.colors.container.border.decorative.neutral}1A;\n }\n }\n`;\n\n// @TODO: Refine types that are passed to SkeletonComponent\nconst SkeletonComponent = ({\n borderRadius,\n height,\n width,\n ...props\n}: TypeBoxProps) => {\n return (\n <Skeleton\n borderRadius={borderRadius}\n height={height}\n width={width}\n {...props}\n />\n );\n};\n\nexport default SkeletonComponent;\n","import Skeleton from \"./Skeleton\";\n\nexport default Skeleton;\nexport { Skeleton };\n"],"mappings":";AAAA,OAAO,YAAY;AACnB,OAAO,SAAgC;AAmInC;AA3HJ,IAAM,gBAAgB,CAAC,EAAE,cAAc,QAAQ,MAAM,OAAO;AAAA,EAC1D,WACE,iBAAiB,UAAU,WAAW,QAAQ,aAAa;AAC/D;AAEA,IAAM,WAAW,OAAO,GAAG,EAAE,MAAM,aAAa;AAAA;AAAA,gBAEhC,CAAC,UACb,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAQpC,CAAC,UAAU;AAAA,QAC7B,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA,QAC1D,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA,OACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAaa,CAAC,MAAM,EAAE,MAAM,OAAO,IAAI,WAAW,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMrC,CAAC,UAAU;AAAA;AAAA,QAE3B,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA,QAC1D,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA,QACtD,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA,OAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAWa,CAAC,UACb,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAgBxC,CAAC,UACnB,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAiCxC,CAAC,UACf,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA;AAAA;AAAA,sBAGxC,CAAC,UACf,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA;AAAA;AAAA;AAM9D,IAAM,oBAAoB,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAoB;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAO,mBAAQ;;;AC3If,IAAO,cAAQ;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { TypeBoxProps } from '@sproutsocial/seeds-react-box';
|
|
3
|
+
|
|
4
|
+
declare const SkeletonComponent: ({ borderRadius, height, width, ...props }: TypeBoxProps) => react_jsx_runtime.JSX.Element;
|
|
5
|
+
|
|
6
|
+
export { SkeletonComponent as Skeleton, SkeletonComponent as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { TypeBoxProps } from '@sproutsocial/seeds-react-box';
|
|
3
|
+
|
|
4
|
+
declare const SkeletonComponent: ({ borderRadius, height, width, ...props }: TypeBoxProps) => react_jsx_runtime.JSX.Element;
|
|
5
|
+
|
|
6
|
+
export { SkeletonComponent as Skeleton, SkeletonComponent as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
Skeleton: () => Skeleton_default,
|
|
34
|
+
default: () => src_default
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(src_exports);
|
|
37
|
+
|
|
38
|
+
// src/Skeleton.tsx
|
|
39
|
+
var import_styled_components = __toESM(require("styled-components"));
|
|
40
|
+
var import_seeds_react_box = __toESM(require("@sproutsocial/seeds-react-box"));
|
|
41
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
42
|
+
var SkeletonAttrs = ({ borderRadius, height, width }) => ({
|
|
43
|
+
className: borderRadius === "pill" && height === width ? "circular" : "linear"
|
|
44
|
+
});
|
|
45
|
+
var Skeleton = (0, import_styled_components.default)(import_seeds_react_box.default).attrs(SkeletonAttrs)`
|
|
46
|
+
position: relative;
|
|
47
|
+
background: ${(props) => props.theme.colors.container.background.decorative.neutral};
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
&.circular {
|
|
50
|
+
&:before {
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: -25%;
|
|
53
|
+
left: -25%;
|
|
54
|
+
content: '';
|
|
55
|
+
background-image: ${(props) => `conic-gradient(
|
|
56
|
+
${props.theme.colors.container.background.decorative.neutral} 270deg,
|
|
57
|
+
${props.theme.colors.container.border.decorative.neutral} 300deg
|
|
58
|
+
);`};
|
|
59
|
+
height: 150%;
|
|
60
|
+
width: 150%;
|
|
61
|
+
animation: SkeletonRotate 2s infinite linear;
|
|
62
|
+
}
|
|
63
|
+
&:after {
|
|
64
|
+
position: absolute;
|
|
65
|
+
top: 50%;
|
|
66
|
+
left: 50%;
|
|
67
|
+
transform: translate(-50%, -50%);
|
|
68
|
+
content: '';
|
|
69
|
+
height: calc(100% - 8px);
|
|
70
|
+
width: calc(100% - 8px);
|
|
71
|
+
background: ${(p) => p.theme.colors.app.background.base};
|
|
72
|
+
border-radius: 50%;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
&.linear {
|
|
76
|
+
position: relative;
|
|
77
|
+
background-image: ${(props) => `linear-gradient(
|
|
78
|
+
288deg,
|
|
79
|
+
${props.theme.colors.container.background.decorative.neutral} 32%,
|
|
80
|
+
${props.theme.colors.container.border.decorative.neutral},
|
|
81
|
+
${props.theme.colors.container.background.decorative.neutral} 68%
|
|
82
|
+
);`}
|
|
83
|
+
background-size: 400%;
|
|
84
|
+
background-repeat: no-repeat;
|
|
85
|
+
animation: SkeletonShimmer 2s linear infinite reverse;
|
|
86
|
+
overflow: hidden;
|
|
87
|
+
&:after {
|
|
88
|
+
position: absolute;
|
|
89
|
+
bottom: 0;
|
|
90
|
+
content: "";
|
|
91
|
+
height: calc(100% - 4px);
|
|
92
|
+
width: 100%;
|
|
93
|
+
background: ${(props) => props.theme.colors.container.background.decorative.neutral};
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@media (prefers-reduced-motion) {
|
|
99
|
+
&.linear,
|
|
100
|
+
&.circular::before {
|
|
101
|
+
animation: none;
|
|
102
|
+
}
|
|
103
|
+
&:before,
|
|
104
|
+
&:after {
|
|
105
|
+
display: none;
|
|
106
|
+
}
|
|
107
|
+
&.linear,
|
|
108
|
+
&.circular {
|
|
109
|
+
border: 1px solid ${(props) => props.theme.colors.container.border.decorative.neutral};
|
|
110
|
+
animation: SkeletonPulse 2s linear infinite alternate;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@keyframes SkeletonRotate {
|
|
115
|
+
100% {
|
|
116
|
+
transform: rotate(360deg);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
@keyframes SkeletonRotateFade {
|
|
120
|
+
50% {
|
|
121
|
+
transform: rotate(360deg);
|
|
122
|
+
}
|
|
123
|
+
90% {
|
|
124
|
+
opacity: 1;
|
|
125
|
+
}
|
|
126
|
+
100% {
|
|
127
|
+
transform: rotate(720deg);
|
|
128
|
+
opacity: 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes SkeletonShimmer {
|
|
133
|
+
0% {
|
|
134
|
+
background-position: 0% 0;
|
|
135
|
+
}
|
|
136
|
+
100% {
|
|
137
|
+
background-position: 100% 0;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
@keyframes SkeletonPulse {
|
|
141
|
+
0% {
|
|
142
|
+
border-color: ${(props) => props.theme.colors.container.border.decorative.neutral}FF;
|
|
143
|
+
}
|
|
144
|
+
100% {
|
|
145
|
+
border-color: ${(props) => props.theme.colors.container.border.decorative.neutral}1A;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
`;
|
|
149
|
+
var SkeletonComponent = ({
|
|
150
|
+
borderRadius,
|
|
151
|
+
height,
|
|
152
|
+
width,
|
|
153
|
+
...props
|
|
154
|
+
}) => {
|
|
155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
156
|
+
Skeleton,
|
|
157
|
+
{
|
|
158
|
+
borderRadius,
|
|
159
|
+
height,
|
|
160
|
+
width,
|
|
161
|
+
...props
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
var Skeleton_default = SkeletonComponent;
|
|
166
|
+
|
|
167
|
+
// src/index.ts
|
|
168
|
+
var src_default = Skeleton_default;
|
|
169
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
170
|
+
0 && (module.exports = {
|
|
171
|
+
Skeleton
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Skeleton.tsx"],"sourcesContent":["import Skeleton from \"./Skeleton\";\n\nexport default Skeleton;\nexport { Skeleton };\n","import styled from \"styled-components\";\nimport Box, { type TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\n/**\n *\n * @param borderRadius\n * @returns classname string for handling appropriate loader style depending on passed in properties\n */\n// @ts-ignore TODO: fix noImplicitAny error here. IDK why there are no types for this component\nconst SkeletonAttrs = ({ borderRadius, height, width }) => ({\n className:\n borderRadius === \"pill\" && height === width ? \"circular\" : \"linear\",\n});\n\nconst Skeleton = styled(Box).attrs(SkeletonAttrs)`\n position: relative;\n background: ${(props) =>\n props.theme.colors.container.background.decorative.neutral};\n overflow: hidden;\n &.circular {\n &:before {\n position: absolute;\n top: -25%;\n left: -25%;\n content: '';\n background-image: ${(props) => `conic-gradient(\n ${props.theme.colors.container.background.decorative.neutral} 270deg,\n ${props.theme.colors.container.border.decorative.neutral} 300deg\n );`};\n height: 150%;\n width: 150%;\n animation: SkeletonRotate 2s infinite linear;\n }\n &:after {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n content: '';\n height: calc(100% - 8px);\n width: calc(100% - 8px);\n background: ${(p) => p.theme.colors.app.background.base};\n border-radius: 50%;\n }\n }\n &.linear {\n position: relative;\n background-image: ${(props) => `linear-gradient(\n 288deg,\n ${props.theme.colors.container.background.decorative.neutral} 32%,\n ${props.theme.colors.container.border.decorative.neutral},\n ${props.theme.colors.container.background.decorative.neutral} 68%\n );`}\n background-size: 400%;\n background-repeat: no-repeat;\n animation: SkeletonShimmer 2s linear infinite reverse;\n overflow: hidden;\n &:after {\n position: absolute;\n bottom: 0;\n content: \"\";\n height: calc(100% - 4px);\n width: 100%;\n background: ${(props) =>\n props.theme.colors.container.background.decorative.neutral};\n \n }\n }\n\n @media (prefers-reduced-motion) {\n &.linear,\n &.circular::before {\n animation: none;\n }\n &:before,\n &:after {\n display: none;\n }\n &.linear,\n &.circular {\n border: 1px solid ${(props) =>\n props.theme.colors.container.border.decorative.neutral};\n animation: SkeletonPulse 2s linear infinite alternate; \n }\n }\n\n @keyframes SkeletonRotate {\n 100% {\n transform: rotate(360deg);\n }\n }\n @keyframes SkeletonRotateFade {\n 50% {\n transform: rotate(360deg);\n }\n 90% {\n opacity: 1;\n }\n 100% {\n transform: rotate(720deg);\n opacity: 0;\n }\n }\n\n @keyframes SkeletonShimmer {\n 0% {\n background-position: 0% 0;\n }\n 100% {\n background-position: 100% 0;\n }\n }\n @keyframes SkeletonPulse {\n 0% {\n border-color: ${(props) =>\n props.theme.colors.container.border.decorative.neutral}FF;\n }\n 100% {\n border-color: ${(props) =>\n props.theme.colors.container.border.decorative.neutral}1A;\n }\n }\n`;\n\n// @TODO: Refine types that are passed to SkeletonComponent\nconst SkeletonComponent = ({\n borderRadius,\n height,\n width,\n ...props\n}: TypeBoxProps) => {\n return (\n <Skeleton\n borderRadius={borderRadius}\n height={height}\n width={width}\n {...props}\n />\n );\n};\n\nexport default SkeletonComponent;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,+BAAmB;AACnB,6BAAuC;AAmInC;AA3HJ,IAAM,gBAAgB,CAAC,EAAE,cAAc,QAAQ,MAAM,OAAO;AAAA,EAC1D,WACE,iBAAiB,UAAU,WAAW,QAAQ,aAAa;AAC/D;AAEA,IAAM,eAAW,yBAAAA,SAAO,uBAAAC,OAAG,EAAE,MAAM,aAAa;AAAA;AAAA,gBAEhC,CAAC,UACb,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAQpC,CAAC,UAAU;AAAA,QAC7B,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA,QAC1D,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA,OACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAaa,CAAC,MAAM,EAAE,MAAM,OAAO,IAAI,WAAW,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMrC,CAAC,UAAU;AAAA;AAAA,QAE3B,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA,QAC1D,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA,QACtD,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA,OAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAWa,CAAC,UACb,MAAM,MAAM,OAAO,UAAU,WAAW,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAgBxC,CAAC,UACnB,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAiCxC,CAAC,UACf,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA;AAAA;AAAA,sBAGxC,CAAC,UACf,MAAM,MAAM,OAAO,UAAU,OAAO,WAAW,OAAO;AAAA;AAAA;AAAA;AAM9D,IAAM,oBAAoB,CAAC;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAoB;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAO,mBAAQ;;;AD3If,IAAO,cAAQ;","names":["styled","Box"]}
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sproutsocial/seeds-react-skeleton",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Seeds React Skeleton",
|
|
5
|
+
"author": "Sprout Social, Inc.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/esm/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup --dts",
|
|
12
|
+
"build:debug": "tsup --dts --metafile",
|
|
13
|
+
"dev": "tsup --watch --dts",
|
|
14
|
+
"clean": "rm -rf .turbo dist",
|
|
15
|
+
"clean:modules": "rm -rf node_modules",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"test:watch": "jest --watch --coverage=false"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@sproutsocial/seeds-react-theme": "*",
|
|
22
|
+
"@sproutsocial/seeds-react-system-props": "*",
|
|
23
|
+
"@sproutsocial/seeds-react-box": "*"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/react": "^18.0.0",
|
|
27
|
+
"@types/styled-components": "^5.1.26",
|
|
28
|
+
"@sproutsocial/eslint-config-seeds": "*",
|
|
29
|
+
"react": "^18.0.0",
|
|
30
|
+
"styled-components": "^5.2.3",
|
|
31
|
+
"tsup": "^8.0.2",
|
|
32
|
+
"typescript": "^5.6.2",
|
|
33
|
+
"@sproutsocial/seeds-tsconfig": "*",
|
|
34
|
+
"@sproutsocial/seeds-testing": "*",
|
|
35
|
+
"@sproutsocial/seeds-react-testing-library": "*"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"styled-components": "^5.2.3"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import Box from "@sproutsocial/seeds-react-box";
|
|
4
|
+
import Banner from "@sproutsocial/seeds-react-banner";
|
|
5
|
+
import Skeleton from "./Skeleton";
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Skeleton> = {
|
|
8
|
+
title: "Components/Skeleton",
|
|
9
|
+
component: Skeleton,
|
|
10
|
+
};
|
|
11
|
+
export default meta;
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof Skeleton>;
|
|
14
|
+
|
|
15
|
+
export const Default: Story = {
|
|
16
|
+
name: "Usage Example",
|
|
17
|
+
render: () => (
|
|
18
|
+
<>
|
|
19
|
+
<Banner
|
|
20
|
+
type="info"
|
|
21
|
+
text="When using a skeleton component, it's important to wrap it in a container with a role attribute set to status and an appropriate aria-label attribute. This helps ensure that screen readers and other assistive technologies can properly convey the purpose of the skeleton to users with screen readers."
|
|
22
|
+
mb={400}
|
|
23
|
+
/>
|
|
24
|
+
<Box
|
|
25
|
+
maxWidth={200}
|
|
26
|
+
p={400}
|
|
27
|
+
borderRadius="outer"
|
|
28
|
+
border={500}
|
|
29
|
+
borderColor="container.border.base"
|
|
30
|
+
tabIndex={0}
|
|
31
|
+
role="status"
|
|
32
|
+
aria-label="Content is loading"
|
|
33
|
+
>
|
|
34
|
+
<Skeleton borderRadius="pill" height={48} width={48} mb={400} />
|
|
35
|
+
<Skeleton borderRadius="inner" height={16} width="100%" mb={400} />
|
|
36
|
+
<Skeleton borderRadius="inner" height={16} width="100%" mb={400} />
|
|
37
|
+
<Skeleton borderRadius="inner" height={128} width="100%" />
|
|
38
|
+
</Box>
|
|
39
|
+
</>
|
|
40
|
+
),
|
|
41
|
+
};
|
package/src/Skeleton.tsx
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
import Box, { type TypeBoxProps } from "@sproutsocial/seeds-react-box";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param borderRadius
|
|
7
|
+
* @returns classname string for handling appropriate loader style depending on passed in properties
|
|
8
|
+
*/
|
|
9
|
+
// @ts-ignore TODO: fix noImplicitAny error here. IDK why there are no types for this component
|
|
10
|
+
const SkeletonAttrs = ({ borderRadius, height, width }) => ({
|
|
11
|
+
className:
|
|
12
|
+
borderRadius === "pill" && height === width ? "circular" : "linear",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const Skeleton = styled(Box).attrs(SkeletonAttrs)`
|
|
16
|
+
position: relative;
|
|
17
|
+
background: ${(props) =>
|
|
18
|
+
props.theme.colors.container.background.decorative.neutral};
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
&.circular {
|
|
21
|
+
&:before {
|
|
22
|
+
position: absolute;
|
|
23
|
+
top: -25%;
|
|
24
|
+
left: -25%;
|
|
25
|
+
content: '';
|
|
26
|
+
background-image: ${(props) => `conic-gradient(
|
|
27
|
+
${props.theme.colors.container.background.decorative.neutral} 270deg,
|
|
28
|
+
${props.theme.colors.container.border.decorative.neutral} 300deg
|
|
29
|
+
);`};
|
|
30
|
+
height: 150%;
|
|
31
|
+
width: 150%;
|
|
32
|
+
animation: SkeletonRotate 2s infinite linear;
|
|
33
|
+
}
|
|
34
|
+
&:after {
|
|
35
|
+
position: absolute;
|
|
36
|
+
top: 50%;
|
|
37
|
+
left: 50%;
|
|
38
|
+
transform: translate(-50%, -50%);
|
|
39
|
+
content: '';
|
|
40
|
+
height: calc(100% - 8px);
|
|
41
|
+
width: calc(100% - 8px);
|
|
42
|
+
background: ${(p) => p.theme.colors.app.background.base};
|
|
43
|
+
border-radius: 50%;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
&.linear {
|
|
47
|
+
position: relative;
|
|
48
|
+
background-image: ${(props) => `linear-gradient(
|
|
49
|
+
288deg,
|
|
50
|
+
${props.theme.colors.container.background.decorative.neutral} 32%,
|
|
51
|
+
${props.theme.colors.container.border.decorative.neutral},
|
|
52
|
+
${props.theme.colors.container.background.decorative.neutral} 68%
|
|
53
|
+
);`}
|
|
54
|
+
background-size: 400%;
|
|
55
|
+
background-repeat: no-repeat;
|
|
56
|
+
animation: SkeletonShimmer 2s linear infinite reverse;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
&:after {
|
|
59
|
+
position: absolute;
|
|
60
|
+
bottom: 0;
|
|
61
|
+
content: "";
|
|
62
|
+
height: calc(100% - 4px);
|
|
63
|
+
width: 100%;
|
|
64
|
+
background: ${(props) =>
|
|
65
|
+
props.theme.colors.container.background.decorative.neutral};
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@media (prefers-reduced-motion) {
|
|
71
|
+
&.linear,
|
|
72
|
+
&.circular::before {
|
|
73
|
+
animation: none;
|
|
74
|
+
}
|
|
75
|
+
&:before,
|
|
76
|
+
&:after {
|
|
77
|
+
display: none;
|
|
78
|
+
}
|
|
79
|
+
&.linear,
|
|
80
|
+
&.circular {
|
|
81
|
+
border: 1px solid ${(props) =>
|
|
82
|
+
props.theme.colors.container.border.decorative.neutral};
|
|
83
|
+
animation: SkeletonPulse 2s linear infinite alternate;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@keyframes SkeletonRotate {
|
|
88
|
+
100% {
|
|
89
|
+
transform: rotate(360deg);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
@keyframes SkeletonRotateFade {
|
|
93
|
+
50% {
|
|
94
|
+
transform: rotate(360deg);
|
|
95
|
+
}
|
|
96
|
+
90% {
|
|
97
|
+
opacity: 1;
|
|
98
|
+
}
|
|
99
|
+
100% {
|
|
100
|
+
transform: rotate(720deg);
|
|
101
|
+
opacity: 0;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@keyframes SkeletonShimmer {
|
|
106
|
+
0% {
|
|
107
|
+
background-position: 0% 0;
|
|
108
|
+
}
|
|
109
|
+
100% {
|
|
110
|
+
background-position: 100% 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
@keyframes SkeletonPulse {
|
|
114
|
+
0% {
|
|
115
|
+
border-color: ${(props) =>
|
|
116
|
+
props.theme.colors.container.border.decorative.neutral}FF;
|
|
117
|
+
}
|
|
118
|
+
100% {
|
|
119
|
+
border-color: ${(props) =>
|
|
120
|
+
props.theme.colors.container.border.decorative.neutral}1A;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
// @TODO: Refine types that are passed to SkeletonComponent
|
|
126
|
+
const SkeletonComponent = ({
|
|
127
|
+
borderRadius,
|
|
128
|
+
height,
|
|
129
|
+
width,
|
|
130
|
+
...props
|
|
131
|
+
}: TypeBoxProps) => {
|
|
132
|
+
return (
|
|
133
|
+
<Skeleton
|
|
134
|
+
borderRadius={borderRadius}
|
|
135
|
+
height={height}
|
|
136
|
+
width={width}
|
|
137
|
+
{...props}
|
|
138
|
+
/>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export default SkeletonComponent;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen } from "@sproutsocial/seeds-react-testing-library";
|
|
3
|
+
import Skeleton from "../Skeleton";
|
|
4
|
+
|
|
5
|
+
describe("Skeleton Component", () => {
|
|
6
|
+
it("renders with circular class when borderRadius is 'pill' and height equals width", () => {
|
|
7
|
+
render(
|
|
8
|
+
<Skeleton
|
|
9
|
+
borderRadius="pill"
|
|
10
|
+
height="50px"
|
|
11
|
+
width="50px"
|
|
12
|
+
data-testid="skeleton"
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
const skeletonElement = screen.getByTestId("skeleton");
|
|
16
|
+
expect(skeletonElement).toHaveClass("circular");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("renders with linear class when borderRadius is not 'pill' or height does not equal width", () => {
|
|
20
|
+
render(
|
|
21
|
+
<Skeleton
|
|
22
|
+
borderRadius="square"
|
|
23
|
+
height="50px"
|
|
24
|
+
width="100px"
|
|
25
|
+
data-testid="skeleton"
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
const skeletonElement = screen.getByTestId("skeleton");
|
|
29
|
+
expect(skeletonElement).toHaveClass("linear");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import Skeleton from "../Skeleton";
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5
|
+
function SkeletonTypes() {
|
|
6
|
+
return (
|
|
7
|
+
<>
|
|
8
|
+
<Skeleton />
|
|
9
|
+
{/* @ts-expect-error - test that invalid prop is rejected */}
|
|
10
|
+
<Skeleton flexDirection="invalid" />
|
|
11
|
+
</>
|
|
12
|
+
);
|
|
13
|
+
}
|
package/src/index.ts
ADDED
package/src/styled.d.ts
ADDED
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig((options) => ({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
format: ["cjs", "esm"],
|
|
6
|
+
clean: true,
|
|
7
|
+
legacyOutput: true,
|
|
8
|
+
dts: options.dts,
|
|
9
|
+
external: ["react"],
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
metafile: options.metafile,
|
|
12
|
+
}));
|