@sproutsocial/seeds-react-loader 1.0.23 → 1.0.24
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/dist/esm/index.js +62 -46
- package/dist/esm/index.js.map +1 -1
- package/dist/index.js +65 -49
- package/dist/index.js.map +1 -1
- package/dist/loader.css +55 -37
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -8,33 +8,12 @@ import React2 from "react";
|
|
|
8
8
|
import styled, { css, keyframes } from "styled-components";
|
|
9
9
|
import { COMMON } from "@sproutsocial/seeds-react-system-props";
|
|
10
10
|
import { visuallyHidden } from "@sproutsocial/seeds-react-mixins";
|
|
11
|
-
var getSize = (size) => {
|
|
12
|
-
const spinnerSize = Math.round(size * 1);
|
|
13
|
-
const borderWidth = Math.round(size * 0.1);
|
|
14
|
-
return css`
|
|
15
|
-
width: ${size}px;
|
|
16
|
-
height: ${size}px;
|
|
17
|
-
box-shadow: ${({ theme }) => `0 0 0 2px ${theme.colors.neutral[600]},
|
|
18
|
-
inset 0 0 0 ${borderWidth + 2}px ${theme.colors.neutral[600]}`};
|
|
19
|
-
|
|
20
|
-
&:after {
|
|
21
|
-
width: ${spinnerSize}px;
|
|
22
|
-
height: ${spinnerSize}px;
|
|
23
|
-
box-sizing: border-box;
|
|
24
|
-
border-width: ${borderWidth}px;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.no-cssanimations &::after {
|
|
28
|
-
background-size: ${spinnerSize}px;
|
|
29
|
-
}
|
|
30
|
-
`;
|
|
31
|
-
};
|
|
32
11
|
var spin = keyframes`
|
|
33
12
|
from {
|
|
34
|
-
transform:
|
|
13
|
+
transform: rotate(0deg);
|
|
35
14
|
}
|
|
36
15
|
to {
|
|
37
|
-
transform:
|
|
16
|
+
transform: rotate(360deg);
|
|
38
17
|
}
|
|
39
18
|
`;
|
|
40
19
|
var delayAnimation = keyframes`
|
|
@@ -48,39 +27,70 @@ var delayAnimation = keyframes`
|
|
|
48
27
|
opacity: 1;
|
|
49
28
|
}
|
|
50
29
|
`;
|
|
30
|
+
var getContainerSize = (size) => css`
|
|
31
|
+
width: ${size}px;
|
|
32
|
+
height: ${size}px;
|
|
33
|
+
`;
|
|
34
|
+
var getSpinnerSize = (size) => {
|
|
35
|
+
const borderWidth = Math.round(size * 0.1);
|
|
36
|
+
const half = Math.round(size / 2);
|
|
37
|
+
return css`
|
|
38
|
+
width: ${size}px;
|
|
39
|
+
height: ${size}px;
|
|
40
|
+
clip: rect(${half}px, ${size}px, ${size}px, 0);
|
|
41
|
+
|
|
42
|
+
&::before,
|
|
43
|
+
&::after {
|
|
44
|
+
width: ${size}px;
|
|
45
|
+
height: ${size}px;
|
|
46
|
+
border-width: ${borderWidth}px;
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
};
|
|
51
50
|
var Container = styled.div.attrs({
|
|
52
51
|
className: "Loader"
|
|
53
52
|
})`
|
|
54
53
|
position: relative;
|
|
55
54
|
margin: 0 auto;
|
|
56
55
|
padding: 0;
|
|
57
|
-
overflow: hidden;
|
|
58
|
-
border-radius: 100%;
|
|
59
56
|
|
|
60
57
|
animation: ${(props) => props.delay ? css`
|
|
61
|
-
${delayAnimation} 2s 1
|
|
62
|
-
` :
|
|
58
|
+
${spin} 3s infinite linear, ${delayAnimation} 2s 1
|
|
59
|
+
` : css`
|
|
60
|
+
${spin} 3s infinite linear
|
|
61
|
+
`};
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
${(props) => props.small ? getContainerSize(20) : getContainerSize(40)}
|
|
64
|
+
${COMMON}
|
|
65
|
+
`;
|
|
66
|
+
var Spinner = styled.span`
|
|
67
|
+
position: absolute;
|
|
68
|
+
inset: 0;
|
|
69
|
+
margin: auto;
|
|
70
|
+
animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;
|
|
71
|
+
|
|
72
|
+
&::before,
|
|
73
|
+
&::after {
|
|
74
|
+
content: "";
|
|
65
75
|
position: absolute;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
inset: 0;
|
|
77
|
+
margin: auto;
|
|
78
|
+
box-sizing: border-box;
|
|
69
79
|
border-style: solid;
|
|
70
80
|
border-radius: 100%;
|
|
71
|
-
|
|
72
|
-
transition: opacity 250ms;
|
|
73
|
-
border-color: ${({ theme }) => `${theme.colors.neutral[0]} ${theme.colors.neutral[0]} ${theme.colors.neutral[600]} ${theme.colors.neutral[600]}`};
|
|
81
|
+
}
|
|
74
82
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
`};
|
|
83
|
+
&::before {
|
|
84
|
+
border-color: transparent;
|
|
85
|
+
border-top-color: ${({ theme }) => theme.colors.neutral[0]};
|
|
86
|
+
animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;
|
|
80
87
|
}
|
|
81
88
|
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
&::after {
|
|
90
|
+
border-color: ${({ theme }) => theme.colors.neutral[600]};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
${(props) => props.small ? getSpinnerSize(20) : getSpinnerSize(40)}
|
|
84
94
|
`;
|
|
85
95
|
var Text = styled.div`
|
|
86
96
|
${visuallyHidden}
|
|
@@ -89,7 +99,7 @@ var styles_default = Container;
|
|
|
89
99
|
|
|
90
100
|
// src/LoaderTailwind.tsx
|
|
91
101
|
import React from "react";
|
|
92
|
-
import { jsx } from "react/jsx-runtime";
|
|
102
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
93
103
|
function cn(...inputs) {
|
|
94
104
|
const classes = [];
|
|
95
105
|
for (const input of inputs) {
|
|
@@ -127,7 +137,10 @@ var LoaderTailwind = React.forwardRef(
|
|
|
127
137
|
return (
|
|
128
138
|
// QA default precedes {...rest} so a consumer-provided data-qa-loader
|
|
129
139
|
// (via {...rest} or the qa prop) overrides the default.
|
|
130
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ jsxs("div", { "data-qa-loader": "", ...rest, className: classes, ref, ...qa, children: [
|
|
141
|
+
/* @__PURE__ */ jsx("span", { className: "seeds-loader-spinner", "aria-hidden": "true" }),
|
|
142
|
+
/* @__PURE__ */ jsx("span", { className: "seeds-loader-visually-hidden", children: text || "Loading" })
|
|
143
|
+
] })
|
|
131
144
|
);
|
|
132
145
|
}
|
|
133
146
|
);
|
|
@@ -135,7 +148,7 @@ LoaderTailwind.displayName = "LoaderTailwind";
|
|
|
135
148
|
|
|
136
149
|
// src/LoaderHybrid.tsx
|
|
137
150
|
import { hasStyledProps } from "@sproutsocial/seeds-react-system-props";
|
|
138
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
151
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
139
152
|
var LoaderHybrid = React2.forwardRef(
|
|
140
153
|
(props, ref) => {
|
|
141
154
|
const {
|
|
@@ -147,7 +160,7 @@ var LoaderHybrid = React2.forwardRef(
|
|
|
147
160
|
...rest
|
|
148
161
|
} = props;
|
|
149
162
|
if (hasStyledProps(rest)) {
|
|
150
|
-
return /* @__PURE__ */
|
|
163
|
+
return /* @__PURE__ */ jsxs2(
|
|
151
164
|
styles_default,
|
|
152
165
|
{
|
|
153
166
|
small: size === "small",
|
|
@@ -157,7 +170,10 @@ var LoaderHybrid = React2.forwardRef(
|
|
|
157
170
|
ref,
|
|
158
171
|
...qa,
|
|
159
172
|
...rest,
|
|
160
|
-
children:
|
|
173
|
+
children: [
|
|
174
|
+
/* @__PURE__ */ jsx2(Spinner, { small: size === "small", "aria-hidden": "true" }),
|
|
175
|
+
/* @__PURE__ */ jsx2(Text, { children: text || "Loading" })
|
|
176
|
+
]
|
|
161
177
|
}
|
|
162
178
|
);
|
|
163
179
|
}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/Loader.tsx","../../src/LoaderHybrid.tsx","../../src/styles.ts","../../src/LoaderTailwind.tsx","../../src/index.ts"],"sourcesContent":["import React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport LoaderHybrid from \"./LoaderHybrid\";\n\n/**\n * Loader component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system props or a styled() extension).\n */\nconst Loader = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => <LoaderHybrid {...props} ref={ref} />\n);\n\nLoader.displayName = \"Loader\";\nexport default Loader;\n","/**\n * Hybrid Loader Component\n * Automatically chooses between Tailwind and styled-components based on props\n */\n\nimport React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport Container, { Text } from \"./styles\"; // Styled-components version\nimport { LoaderTailwind } from \"./LoaderTailwind\"; // Tailwind version\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\n\nconst LoaderHybrid = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => {\n const {\n size = \"large\",\n text = \"\",\n delay = true,\n color = \"dark\",\n qa,\n ...rest\n } = props;\n\n if (hasStyledProps(rest)) {\n return (\n <Container\n small={size === \"small\"}\n dark={color === \"dark\"}\n delay={delay}\n data-qa-loader=\"\"\n ref={ref}\n {...qa}\n {...rest}\n >\n <Text>{text || \"Loading\"}</Text>\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return <LoaderTailwind {...props} ref={ref} />;\n }\n);\n\nLoaderHybrid.displayName = \"Loader\";\nexport default LoaderHybrid;\n","import styled, { css, keyframes } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { visuallyHidden } from \"@sproutsocial/seeds-react-mixins\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\n\nconst
|
|
1
|
+
{"version":3,"sources":["../../src/Loader.tsx","../../src/LoaderHybrid.tsx","../../src/styles.ts","../../src/LoaderTailwind.tsx","../../src/index.ts"],"sourcesContent":["import React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport LoaderHybrid from \"./LoaderHybrid\";\n\n/**\n * Loader component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system props or a styled() extension).\n */\nconst Loader = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => <LoaderHybrid {...props} ref={ref} />\n);\n\nLoader.displayName = \"Loader\";\nexport default Loader;\n","/**\n * Hybrid Loader Component\n * Automatically chooses between Tailwind and styled-components based on props\n */\n\nimport React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport Container, { Spinner, Text } from \"./styles\"; // Styled-components version\nimport { LoaderTailwind } from \"./LoaderTailwind\"; // Tailwind version\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\n\nconst LoaderHybrid = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => {\n const {\n size = \"large\",\n text = \"\",\n delay = true,\n color = \"dark\",\n qa,\n ...rest\n } = props;\n\n if (hasStyledProps(rest)) {\n return (\n <Container\n small={size === \"small\"}\n dark={color === \"dark\"}\n delay={delay}\n data-qa-loader=\"\"\n ref={ref}\n {...qa}\n {...rest}\n >\n <Spinner small={size === \"small\"} aria-hidden=\"true\" />\n <Text>{text || \"Loading\"}</Text>\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return <LoaderTailwind {...props} ref={ref} />;\n }\n);\n\nLoaderHybrid.displayName = \"Loader\";\nexport default LoaderHybrid;\n","import styled, { css, keyframes } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { visuallyHidden } from \"@sproutsocial/seeds-react-mixins\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\n\nconst spin = keyframes`\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n`;\n\nconst delayAnimation = keyframes`\n 0% {\n opacity: 0;\n }\n 80% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n`;\n\n// Size for the container box.\nconst getContainerSize = (size: number) => css`\n width: ${size}px;\n height: ${size}px;\n`;\n\n// Size for the visual spinner: dimensions, the clipped half, and the arc/ring\n// border widths all scale together so the arc clips correctly at every size.\nconst getSpinnerSize = (size: number) => {\n const borderWidth = Math.round(size * 0.1);\n const half = Math.round(size / 2);\n\n return css`\n width: ${size}px;\n height: ${size}px;\n clip: rect(${half}px, ${size}px, ${size}px, 0);\n\n &::before,\n &::after {\n width: ${size}px;\n height: ${size}px;\n border-width: ${borderWidth}px;\n }\n `;\n};\n\ninterface TypeLoaderContainer extends Pick<TypeLoaderProps, \"delay\"> {\n small?: boolean;\n dark?: boolean;\n}\n\nconst Container = styled.div.attrs<{ className: string }>({\n className: \"Loader\",\n})<TypeLoaderContainer>`\n position: relative;\n margin: 0 auto;\n padding: 0;\n\n animation: ${(props) =>\n props.delay\n ? css`\n ${spin} 3s infinite linear, ${delayAnimation} 2s 1\n `\n : css`\n ${spin} 3s infinite linear\n `};\n\n ${(props) => (props.small ? getContainerSize(20) : getContainerSize(40))}\n ${COMMON}\n`;\n\n// Visual spinner — the bright rotating arc (&::before) and faint arc ring\n// (&::after), both clipped to the bottom half. Hidden from assistive tech\n// via aria-hidden in markup.\nexport const Spinner = styled.span<{ small?: boolean }>`\n position: absolute;\n inset: 0;\n margin: auto;\n animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;\n\n &::before,\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n margin: auto;\n box-sizing: border-box;\n border-style: solid;\n border-radius: 100%;\n }\n\n &::before {\n border-color: transparent;\n border-top-color: ${({ theme }) => theme.colors.neutral[0]};\n animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;\n }\n\n &::after {\n border-color: ${({ theme }) => theme.colors.neutral[600]};\n }\n\n ${(props) => (props.small ? getSpinnerSize(20) : getSpinnerSize(40))}\n`;\n\nexport const Text = styled.div<Pick<TypeLoaderProps, \"text\">>`\n ${visuallyHidden}\n`;\n\nexport default Container;\n","/**\n * Tailwind CSS implementation of Loader component\n * Uses Seeds loader CSS classes from loader.css\n */\n\nimport React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const LoaderTailwind = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (\n {\n size = \"large\",\n text = \"\",\n delay = true,\n // color is accepted but intentionally unused — it is a visual no-op in the\n // styled-components implementation too, so the API stays unchanged.\n color: _color = \"dark\",\n qa = {},\n className,\n ...rest\n }: TypeLoaderProps,\n ref: React.Ref<HTMLDivElement>\n ) => {\n const classes = cn(\n \"seeds-loader\",\n { \"seeds-loader-sm\": size === \"small\" },\n { \"seeds-loader-delay\": delay },\n className\n );\n\n return (\n // QA default precedes {...rest} so a consumer-provided data-qa-loader\n // (via {...rest} or the qa prop) overrides the default.\n <div data-qa-loader=\"\" {...rest} className={classes} ref={ref} {...qa}>\n {/* visual spinner — hosts the ::before (arc) pseudo-element;\n hidden from assistive tech. */}\n <span className=\"seeds-loader-spinner\" aria-hidden=\"true\" />\n {/* a11y label — must stay discoverable by getByText(\"Loading\"). */}\n <span className=\"seeds-loader-visually-hidden\">\n {text || \"Loading\"}\n </span>\n </div>\n );\n }\n);\n\nLoaderTailwind.displayName = \"LoaderTailwind\";\n","import Loader from \"./Loader\";\n\nexport default Loader;\nexport { Loader };\nexport * from \"./LoaderTypes\";\n"],"mappings":"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","names":["React","React","jsx","jsxs","React","jsx","React"]}
|
package/dist/index.js
CHANGED
|
@@ -45,33 +45,12 @@ var import_react2 = __toESM(require("react"));
|
|
|
45
45
|
var import_styled_components = __toESM(require("styled-components"));
|
|
46
46
|
var import_seeds_react_system_props = require("@sproutsocial/seeds-react-system-props");
|
|
47
47
|
var import_seeds_react_mixins = require("@sproutsocial/seeds-react-mixins");
|
|
48
|
-
var getSize = (size) => {
|
|
49
|
-
const spinnerSize = Math.round(size * 1);
|
|
50
|
-
const borderWidth = Math.round(size * 0.1);
|
|
51
|
-
return import_styled_components.css`
|
|
52
|
-
width: ${size}px;
|
|
53
|
-
height: ${size}px;
|
|
54
|
-
box-shadow: ${({ theme }) => `0 0 0 2px ${theme.colors.neutral[600]},
|
|
55
|
-
inset 0 0 0 ${borderWidth + 2}px ${theme.colors.neutral[600]}`};
|
|
56
|
-
|
|
57
|
-
&:after {
|
|
58
|
-
width: ${spinnerSize}px;
|
|
59
|
-
height: ${spinnerSize}px;
|
|
60
|
-
box-sizing: border-box;
|
|
61
|
-
border-width: ${borderWidth}px;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.no-cssanimations &::after {
|
|
65
|
-
background-size: ${spinnerSize}px;
|
|
66
|
-
}
|
|
67
|
-
`;
|
|
68
|
-
};
|
|
69
48
|
var spin = import_styled_components.keyframes`
|
|
70
49
|
from {
|
|
71
|
-
transform:
|
|
50
|
+
transform: rotate(0deg);
|
|
72
51
|
}
|
|
73
52
|
to {
|
|
74
|
-
transform:
|
|
53
|
+
transform: rotate(360deg);
|
|
75
54
|
}
|
|
76
55
|
`;
|
|
77
56
|
var delayAnimation = import_styled_components.keyframes`
|
|
@@ -85,39 +64,70 @@ var delayAnimation = import_styled_components.keyframes`
|
|
|
85
64
|
opacity: 1;
|
|
86
65
|
}
|
|
87
66
|
`;
|
|
67
|
+
var getContainerSize = (size) => import_styled_components.css`
|
|
68
|
+
width: ${size}px;
|
|
69
|
+
height: ${size}px;
|
|
70
|
+
`;
|
|
71
|
+
var getSpinnerSize = (size) => {
|
|
72
|
+
const borderWidth = Math.round(size * 0.1);
|
|
73
|
+
const half = Math.round(size / 2);
|
|
74
|
+
return import_styled_components.css`
|
|
75
|
+
width: ${size}px;
|
|
76
|
+
height: ${size}px;
|
|
77
|
+
clip: rect(${half}px, ${size}px, ${size}px, 0);
|
|
78
|
+
|
|
79
|
+
&::before,
|
|
80
|
+
&::after {
|
|
81
|
+
width: ${size}px;
|
|
82
|
+
height: ${size}px;
|
|
83
|
+
border-width: ${borderWidth}px;
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
};
|
|
88
87
|
var Container = import_styled_components.default.div.attrs({
|
|
89
88
|
className: "Loader"
|
|
90
89
|
})`
|
|
91
90
|
position: relative;
|
|
92
91
|
margin: 0 auto;
|
|
93
92
|
padding: 0;
|
|
94
|
-
overflow: hidden;
|
|
95
|
-
border-radius: 100%;
|
|
96
93
|
|
|
97
94
|
animation: ${(props) => props.delay ? import_styled_components.css`
|
|
98
|
-
${delayAnimation} 2s 1
|
|
99
|
-
` :
|
|
95
|
+
${spin} 3s infinite linear, ${delayAnimation} 2s 1
|
|
96
|
+
` : import_styled_components.css`
|
|
97
|
+
${spin} 3s infinite linear
|
|
98
|
+
`};
|
|
99
|
+
|
|
100
|
+
${(props) => props.small ? getContainerSize(20) : getContainerSize(40)}
|
|
101
|
+
${import_seeds_react_system_props.COMMON}
|
|
102
|
+
`;
|
|
103
|
+
var Spinner = import_styled_components.default.span`
|
|
104
|
+
position: absolute;
|
|
105
|
+
inset: 0;
|
|
106
|
+
margin: auto;
|
|
107
|
+
animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;
|
|
100
108
|
|
|
101
|
-
|
|
109
|
+
&::before,
|
|
110
|
+
&::after {
|
|
111
|
+
content: "";
|
|
102
112
|
position: absolute;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
inset: 0;
|
|
114
|
+
margin: auto;
|
|
115
|
+
box-sizing: border-box;
|
|
106
116
|
border-style: solid;
|
|
107
117
|
border-radius: 100%;
|
|
108
|
-
|
|
109
|
-
transition: opacity 250ms;
|
|
110
|
-
border-color: ${({ theme }) => `${theme.colors.neutral[0]} ${theme.colors.neutral[0]} ${theme.colors.neutral[600]} ${theme.colors.neutral[600]}`};
|
|
118
|
+
}
|
|
111
119
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
`};
|
|
120
|
+
&::before {
|
|
121
|
+
border-color: transparent;
|
|
122
|
+
border-top-color: ${({ theme }) => theme.colors.neutral[0]};
|
|
123
|
+
animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;
|
|
117
124
|
}
|
|
118
125
|
|
|
119
|
-
|
|
120
|
-
|
|
126
|
+
&::after {
|
|
127
|
+
border-color: ${({ theme }) => theme.colors.neutral[600]};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
${(props) => props.small ? getSpinnerSize(20) : getSpinnerSize(40)}
|
|
121
131
|
`;
|
|
122
132
|
var Text = import_styled_components.default.div`
|
|
123
133
|
${import_seeds_react_mixins.visuallyHidden}
|
|
@@ -126,7 +136,11 @@ var styles_default = Container;
|
|
|
126
136
|
|
|
127
137
|
// src/LoaderTailwind.tsx
|
|
128
138
|
var import_react = __toESM(require("react"));
|
|
129
|
-
var import_jsx_runtime =
|
|
139
|
+
var import_jsx_runtime = (
|
|
140
|
+
// QA default precedes {...rest} so a consumer-provided data-qa-loader
|
|
141
|
+
// (via {...rest} or the qa prop) overrides the default.
|
|
142
|
+
require("react/jsx-runtime")
|
|
143
|
+
);
|
|
130
144
|
function cn(...inputs) {
|
|
131
145
|
const classes = [];
|
|
132
146
|
for (const input of inputs) {
|
|
@@ -161,11 +175,10 @@ var LoaderTailwind = import_react.default.forwardRef(
|
|
|
161
175
|
{ "seeds-loader-delay": delay },
|
|
162
176
|
className
|
|
163
177
|
);
|
|
164
|
-
return (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { "data-qa-loader": "", ...rest, className: classes, ref, ...qa, children: [
|
|
179
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "seeds-loader-spinner", "aria-hidden": "true" }),
|
|
180
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "seeds-loader-visually-hidden", children: text || "Loading" })
|
|
181
|
+
] });
|
|
169
182
|
}
|
|
170
183
|
);
|
|
171
184
|
LoaderTailwind.displayName = "LoaderTailwind";
|
|
@@ -184,7 +197,7 @@ var LoaderHybrid = import_react2.default.forwardRef(
|
|
|
184
197
|
...rest
|
|
185
198
|
} = props;
|
|
186
199
|
if ((0, import_seeds_react_system_props2.hasStyledProps)(rest)) {
|
|
187
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
188
201
|
styles_default,
|
|
189
202
|
{
|
|
190
203
|
small: size === "small",
|
|
@@ -194,7 +207,10 @@ var LoaderHybrid = import_react2.default.forwardRef(
|
|
|
194
207
|
ref,
|
|
195
208
|
...qa,
|
|
196
209
|
...rest,
|
|
197
|
-
children:
|
|
210
|
+
children: [
|
|
211
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Spinner, { small: size === "small", "aria-hidden": "true" }),
|
|
212
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { children: text || "Loading" })
|
|
213
|
+
]
|
|
198
214
|
}
|
|
199
215
|
);
|
|
200
216
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Loader.tsx","../src/LoaderHybrid.tsx","../src/styles.ts","../src/LoaderTailwind.tsx"],"sourcesContent":["import Loader from \"./Loader\";\n\nexport default Loader;\nexport { Loader };\nexport * from \"./LoaderTypes\";\n","import React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport LoaderHybrid from \"./LoaderHybrid\";\n\n/**\n * Loader component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system props or a styled() extension).\n */\nconst Loader = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => <LoaderHybrid {...props} ref={ref} />\n);\n\nLoader.displayName = \"Loader\";\nexport default Loader;\n","/**\n * Hybrid Loader Component\n * Automatically chooses between Tailwind and styled-components based on props\n */\n\nimport React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport Container, { Text } from \"./styles\"; // Styled-components version\nimport { LoaderTailwind } from \"./LoaderTailwind\"; // Tailwind version\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\n\nconst LoaderHybrid = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => {\n const {\n size = \"large\",\n text = \"\",\n delay = true,\n color = \"dark\",\n qa,\n ...rest\n } = props;\n\n if (hasStyledProps(rest)) {\n return (\n <Container\n small={size === \"small\"}\n dark={color === \"dark\"}\n delay={delay}\n data-qa-loader=\"\"\n ref={ref}\n {...qa}\n {...rest}\n >\n <Text>{text || \"Loading\"}</Text>\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return <LoaderTailwind {...props} ref={ref} />;\n }\n);\n\nLoaderHybrid.displayName = \"Loader\";\nexport default LoaderHybrid;\n","import styled, { css, keyframes } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { visuallyHidden } from \"@sproutsocial/seeds-react-mixins\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\n\nconst getSize = (size: number) => {\n const spinnerSize = Math.round(size * 1);\n const borderWidth = Math.round(size * 0.1);\n\n return css`\n width: ${size}px;\n height: ${size}px;\n box-shadow: ${({ theme }) =>\n `0 0 0 2px ${theme.colors.neutral[600]}, \n inset 0 0 0 ${borderWidth + 2}px ${theme.colors.neutral[600]}`};\n\n &:after {\n width: ${spinnerSize}px;\n height: ${spinnerSize}px;\n box-sizing: border-box;\n border-width: ${borderWidth}px;\n }\n\n .no-cssanimations &::after {\n background-size: ${spinnerSize}px;\n }\n `;\n};\n\nconst spin = keyframes`\n from {\n transform: translate(-50%,-50%) rotate(0deg);\n }\n to {\n transform: translate(-50%,-50%) rotate(360deg);\n }\n`;\n\nconst delayAnimation = keyframes`\n 0% {\n opacity: 0;\n }\n 80% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n`;\n\ninterface TypeLoaderContainer extends Pick<TypeLoaderProps, \"delay\"> {\n small?: boolean;\n dark?: boolean;\n}\n\nconst Container = styled.div.attrs<{ className: string }>({\n className: \"Loader\",\n})<TypeLoaderContainer>`\n position: relative;\n margin: 0 auto;\n padding: 0;\n overflow: hidden;\n border-radius: 100%;\n\n animation: ${(props) =>\n props.delay\n ? css`\n ${delayAnimation} 2s 1;\n `\n : \"none\"};\n\n &:after {\n position: absolute;\n top: 50%;\n left: 50%;\n background: transparent;\n border-style: solid;\n border-radius: 100%;\n content: \"\";\n transition: opacity 250ms;\n border-color: ${({ theme }) =>\n `${theme.colors.neutral[0]} ${theme.colors.neutral[0]} ${theme.colors.neutral[600]} ${theme.colors.neutral[600]}`};\n\n animation: ${(props) =>\n props.delay\n ? css`\n ${spin} 2.25s infinite linear, ${delayAnimation} 2s 1\n `\n : css`\n ${spin} 2.25s infinite linear\n `};\n }\n\n ${(props) => (props.small ? getSize(20) : getSize(40))}\n ${COMMON}\n`;\n\nexport const Text = styled.div<Pick<TypeLoaderProps, \"text\">>`\n ${visuallyHidden}\n`;\n\nexport default Container;\n","/**\n * Tailwind CSS implementation of Loader component\n * Uses Seeds loader CSS classes from loader.css\n */\n\nimport React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const LoaderTailwind = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (\n {\n size = \"large\",\n text = \"\",\n delay = true,\n // color is accepted but intentionally unused — it is a visual no-op in the\n // styled-components implementation too, so the API stays unchanged.\n color: _color = \"dark\",\n qa = {},\n className,\n ...rest\n }: TypeLoaderProps,\n ref: React.Ref<HTMLDivElement>\n ) => {\n const classes = cn(\n \"seeds-loader\",\n { \"seeds-loader-sm\": size === \"small\" },\n { \"seeds-loader-delay\": delay },\n className\n );\n\n return (\n // QA default precedes {...rest} so a consumer-provided data-qa-loader\n // (via {...rest} or the qa prop) overrides the default.\n <div data-qa-loader=\"\" {...rest} className={classes} ref={ref} {...qa}>\n <span className=\"seeds-loader-visually-hidden\">\n {text || \"Loading\"}\n </span>\n </div>\n );\n }\n);\n\nLoaderTailwind.displayName = \"LoaderTailwind\";\n"],"mappings":"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","names":["import_react","import_react","styled","React","import_seeds_react_system_props","import_jsx_runtime","React","import_jsx_runtime","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Loader.tsx","../src/LoaderHybrid.tsx","../src/styles.ts","../src/LoaderTailwind.tsx"],"sourcesContent":["import Loader from \"./Loader\";\n\nexport default Loader;\nexport { Loader };\nexport * from \"./LoaderTypes\";\n","import React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport LoaderHybrid from \"./LoaderHybrid\";\n\n/**\n * Loader component. Automatically routes between the Tailwind implementation\n * (preferred) and the styled-components implementation (for consumers using\n * system props or a styled() extension).\n */\nconst Loader = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => <LoaderHybrid {...props} ref={ref} />\n);\n\nLoader.displayName = \"Loader\";\nexport default Loader;\n","/**\n * Hybrid Loader Component\n * Automatically chooses between Tailwind and styled-components based on props\n */\n\nimport React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\nimport Container, { Spinner, Text } from \"./styles\"; // Styled-components version\nimport { LoaderTailwind } from \"./LoaderTailwind\"; // Tailwind version\nimport { hasStyledProps } from \"@sproutsocial/seeds-react-system-props\";\n\nconst LoaderHybrid = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (props, ref) => {\n const {\n size = \"large\",\n text = \"\",\n delay = true,\n color = \"dark\",\n qa,\n ...rest\n } = props;\n\n if (hasStyledProps(rest)) {\n return (\n <Container\n small={size === \"small\"}\n dark={color === \"dark\"}\n delay={delay}\n data-qa-loader=\"\"\n ref={ref}\n {...qa}\n {...rest}\n >\n <Spinner small={size === \"small\"} aria-hidden=\"true\" />\n <Text>{text || \"Loading\"}</Text>\n </Container>\n );\n }\n\n // Use Tailwind version (preferred - better performance)\n return <LoaderTailwind {...props} ref={ref} />;\n }\n);\n\nLoaderHybrid.displayName = \"Loader\";\nexport default LoaderHybrid;\n","import styled, { css, keyframes } from \"styled-components\";\nimport { COMMON } from \"@sproutsocial/seeds-react-system-props\";\nimport { visuallyHidden } from \"@sproutsocial/seeds-react-mixins\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\n\nconst spin = keyframes`\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n`;\n\nconst delayAnimation = keyframes`\n 0% {\n opacity: 0;\n }\n 80% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n`;\n\n// Size for the container box.\nconst getContainerSize = (size: number) => css`\n width: ${size}px;\n height: ${size}px;\n`;\n\n// Size for the visual spinner: dimensions, the clipped half, and the arc/ring\n// border widths all scale together so the arc clips correctly at every size.\nconst getSpinnerSize = (size: number) => {\n const borderWidth = Math.round(size * 0.1);\n const half = Math.round(size / 2);\n\n return css`\n width: ${size}px;\n height: ${size}px;\n clip: rect(${half}px, ${size}px, ${size}px, 0);\n\n &::before,\n &::after {\n width: ${size}px;\n height: ${size}px;\n border-width: ${borderWidth}px;\n }\n `;\n};\n\ninterface TypeLoaderContainer extends Pick<TypeLoaderProps, \"delay\"> {\n small?: boolean;\n dark?: boolean;\n}\n\nconst Container = styled.div.attrs<{ className: string }>({\n className: \"Loader\",\n})<TypeLoaderContainer>`\n position: relative;\n margin: 0 auto;\n padding: 0;\n\n animation: ${(props) =>\n props.delay\n ? css`\n ${spin} 3s infinite linear, ${delayAnimation} 2s 1\n `\n : css`\n ${spin} 3s infinite linear\n `};\n\n ${(props) => (props.small ? getContainerSize(20) : getContainerSize(40))}\n ${COMMON}\n`;\n\n// Visual spinner — the bright rotating arc (&::before) and faint arc ring\n// (&::after), both clipped to the bottom half. Hidden from assistive tech\n// via aria-hidden in markup.\nexport const Spinner = styled.span<{ small?: boolean }>`\n position: absolute;\n inset: 0;\n margin: auto;\n animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;\n\n &::before,\n &::after {\n content: \"\";\n position: absolute;\n inset: 0;\n margin: auto;\n box-sizing: border-box;\n border-style: solid;\n border-radius: 100%;\n }\n\n &::before {\n border-color: transparent;\n border-top-color: ${({ theme }) => theme.colors.neutral[0]};\n animation: ${spin} 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;\n }\n\n &::after {\n border-color: ${({ theme }) => theme.colors.neutral[600]};\n }\n\n ${(props) => (props.small ? getSpinnerSize(20) : getSpinnerSize(40))}\n`;\n\nexport const Text = styled.div<Pick<TypeLoaderProps, \"text\">>`\n ${visuallyHidden}\n`;\n\nexport default Container;\n","/**\n * Tailwind CSS implementation of Loader component\n * Uses Seeds loader CSS classes from loader.css\n */\n\nimport React from \"react\";\nimport type { TypeLoaderProps } from \"./LoaderTypes\";\n\n// Utility for merging class names properly\nfunction cn(\n ...inputs: (string | undefined | null | false | Record<string, boolean>)[]\n): string {\n const classes: string[] = [];\n\n for (const input of inputs) {\n if (!input) continue;\n\n if (typeof input === \"string\") {\n classes.push(input);\n } else if (typeof input === \"object\") {\n for (const [key, value] of Object.entries(input)) {\n if (value) {\n classes.push(key);\n }\n }\n }\n }\n\n return classes.join(\" \");\n}\n\nexport const LoaderTailwind = React.forwardRef<HTMLDivElement, TypeLoaderProps>(\n (\n {\n size = \"large\",\n text = \"\",\n delay = true,\n // color is accepted but intentionally unused — it is a visual no-op in the\n // styled-components implementation too, so the API stays unchanged.\n color: _color = \"dark\",\n qa = {},\n className,\n ...rest\n }: TypeLoaderProps,\n ref: React.Ref<HTMLDivElement>\n ) => {\n const classes = cn(\n \"seeds-loader\",\n { \"seeds-loader-sm\": size === \"small\" },\n { \"seeds-loader-delay\": delay },\n className\n );\n\n return (\n // QA default precedes {...rest} so a consumer-provided data-qa-loader\n // (via {...rest} or the qa prop) overrides the default.\n <div data-qa-loader=\"\" {...rest} className={classes} ref={ref} {...qa}>\n {/* visual spinner — hosts the ::before (arc) pseudo-element;\n hidden from assistive tech. */}\n <span className=\"seeds-loader-spinner\" aria-hidden=\"true\" />\n {/* a11y label — must stay discoverable by getByText(\"Loading\"). */}\n <span className=\"seeds-loader-visually-hidden\">\n {text || \"Loading\"}\n </span>\n </div>\n );\n }\n);\n\nLoaderTailwind.displayName = \"LoaderTailwind\";\n"],"mappings":"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","names":["import_react","import_react","styled","React","import_seeds_react_system_props","import_jsx_runtime","React","import_jsx_runtime","React"]}
|
package/dist/loader.css
CHANGED
|
@@ -7,19 +7,23 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* <div class="seeds-loader seeds-loader-delay">
|
|
10
|
+
* <span class="seeds-loader-spinner" aria-hidden="true"></span>
|
|
10
11
|
* <span class="seeds-loader-visually-hidden">Loading</span>
|
|
11
12
|
* </div>
|
|
12
13
|
* <div class="seeds-loader seeds-loader-sm">...</div> (small)
|
|
13
14
|
* <div class="seeds-loader">...</div> (no delay)
|
|
15
|
+
*
|
|
16
|
+
* The visual is a thin rotating arc (--color-neutral-0) over a faint arc ring
|
|
17
|
+
* (--color-neutral-600), both clipped to the bottom half by the spinner span.
|
|
14
18
|
*/
|
|
15
19
|
|
|
16
20
|
@layer components {
|
|
17
21
|
@keyframes seeds-loader-spin {
|
|
18
22
|
from {
|
|
19
|
-
transform:
|
|
23
|
+
transform: rotate(0deg);
|
|
20
24
|
}
|
|
21
25
|
to {
|
|
22
|
-
transform:
|
|
26
|
+
transform: rotate(360deg);
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
|
|
@@ -35,70 +39,84 @@
|
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
/* Base (large / 40px) */
|
|
42
|
+
/* Base (large / 40px) — slow outer rotation hosting the spinner */
|
|
39
43
|
.seeds-loader {
|
|
40
44
|
position: relative;
|
|
41
45
|
margin: 0 auto;
|
|
42
46
|
padding: 0;
|
|
43
|
-
overflow: hidden;
|
|
44
|
-
border-radius: 100%;
|
|
45
47
|
width: 40px;
|
|
46
48
|
height: 40px;
|
|
47
|
-
|
|
48
|
-
0 0 0 2px var(--color-neutral-600),
|
|
49
|
-
inset 0 0 0 6px var(--color-neutral-600);
|
|
49
|
+
animation: seeds-loader-spin 3s infinite linear;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
/* Visual spinner — clipped to bottom half, faster eased rotation */
|
|
53
|
+
.seeds-loader-spinner {
|
|
53
54
|
position: absolute;
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
inset: 0;
|
|
56
|
+
margin: auto;
|
|
57
|
+
width: 40px;
|
|
58
|
+
height: 40px;
|
|
59
|
+
clip: rect(20px, 40px, 40px, 0);
|
|
60
|
+
animation: seeds-loader-spin 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Bright arc */
|
|
64
|
+
.seeds-loader-spinner::before {
|
|
65
|
+
content: "";
|
|
66
|
+
position: absolute;
|
|
67
|
+
inset: 0;
|
|
68
|
+
margin: auto;
|
|
56
69
|
width: 40px;
|
|
57
70
|
height: 40px;
|
|
58
71
|
box-sizing: border-box;
|
|
59
|
-
border
|
|
60
|
-
|
|
61
|
-
border-style: solid;
|
|
72
|
+
border: 4px solid transparent;
|
|
73
|
+
border-top-color: var(--color-neutral-0);
|
|
62
74
|
border-radius: 100%;
|
|
63
|
-
|
|
64
|
-
transition: opacity 250ms;
|
|
65
|
-
border-color: var(--color-neutral-0) var(--color-neutral-0)
|
|
66
|
-
var(--color-neutral-600) var(--color-neutral-600);
|
|
67
|
-
animation: seeds-loader-spin 2.25s infinite linear;
|
|
75
|
+
animation: seeds-loader-spin 1.5s cubic-bezier(0.77, 0, 0.175, 1) infinite;
|
|
68
76
|
}
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
/* Faint arc ring (static) — clipped to bottom half alongside the bright arc */
|
|
79
|
+
.seeds-loader-spinner::after {
|
|
80
|
+
content: "";
|
|
81
|
+
position: absolute;
|
|
82
|
+
inset: 0;
|
|
83
|
+
margin: auto;
|
|
84
|
+
width: 40px;
|
|
85
|
+
height: 40px;
|
|
86
|
+
box-sizing: border-box;
|
|
87
|
+
border: 4px solid var(--color-neutral-600);
|
|
88
|
+
border-radius: 100%;
|
|
72
89
|
}
|
|
73
90
|
|
|
74
|
-
/*
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
/* When animations are disabled, the faint arc still renders so the loader
|
|
92
|
+
is never invisible. */
|
|
93
|
+
.no-cssanimations .seeds-loader-spinner::after {
|
|
94
|
+
border-color: var(--color-neutral-600);
|
|
77
95
|
}
|
|
78
96
|
|
|
79
|
-
|
|
97
|
+
/* Delay variant — fades the whole spinner in alongside the outer rotation */
|
|
98
|
+
.seeds-loader-delay {
|
|
80
99
|
animation:
|
|
81
|
-
seeds-loader-spin
|
|
100
|
+
seeds-loader-spin 3s infinite linear,
|
|
82
101
|
seeds-loader-delay-anim 2s 1;
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
/* Small (20px) */
|
|
86
|
-
.seeds-loader-sm
|
|
104
|
+
/* Small (20px) — scale size, border width, and the clip rect together */
|
|
105
|
+
.seeds-loader-sm,
|
|
106
|
+
.seeds-loader-sm .seeds-loader-spinner,
|
|
107
|
+
.seeds-loader-sm .seeds-loader-spinner::before,
|
|
108
|
+
.seeds-loader-sm .seeds-loader-spinner::after {
|
|
87
109
|
width: 20px;
|
|
88
110
|
height: 20px;
|
|
89
|
-
box-shadow:
|
|
90
|
-
0 0 0 2px var(--color-neutral-600),
|
|
91
|
-
inset 0 0 0 4px var(--color-neutral-600);
|
|
92
111
|
}
|
|
93
112
|
|
|
94
|
-
.seeds-loader-sm
|
|
95
|
-
|
|
96
|
-
height: 20px;
|
|
97
|
-
border-width: 2px;
|
|
113
|
+
.seeds-loader-sm .seeds-loader-spinner {
|
|
114
|
+
clip: rect(10px, 20px, 20px, 0);
|
|
98
115
|
}
|
|
99
116
|
|
|
100
|
-
.
|
|
101
|
-
|
|
117
|
+
.seeds-loader-sm .seeds-loader-spinner::before,
|
|
118
|
+
.seeds-loader-sm .seeds-loader-spinner::after {
|
|
119
|
+
border-width: 2px;
|
|
102
120
|
}
|
|
103
121
|
|
|
104
122
|
/* Visually-hidden accessibility text */
|