@spark-web/spinner 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/CHANGELOG.md +18 -0
- package/README.md +57 -0
- package/dist/declarations/src/Spinner.d.ts +10 -0
- package/dist/declarations/src/index.d.ts +2 -0
- package/dist/spark-web-spinner.cjs.d.ts +1 -0
- package/dist/spark-web-spinner.cjs.dev.js +72 -0
- package/dist/spark-web-spinner.cjs.js +7 -0
- package/dist/spark-web-spinner.cjs.prod.js +72 -0
- package/dist/spark-web-spinner.esm.js +68 -0
- package/package.json +24 -0
- package/src/Spinner.stories.tsx +43 -0
- package/src/Spinner.tsx +55 -0
- package/src/index.ts +5 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# @spark-web/spinner
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#44](https://github.com/brighte-labs/spark-web/pull/44)
|
|
8
|
+
[`11e7365`](https://github.com/brighte-labs/spark-web/commit/11e73659ff4a01a48a8761821bff34c6ec28568b)
|
|
9
|
+
Thanks [@matildaPan](https://github.com/matildaPan)! - initial release of
|
|
10
|
+
spinner component
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies
|
|
15
|
+
[[`11e7365`](https://github.com/brighte-labs/spark-web/commit/11e73659ff4a01a48a8761821bff34c6ec28568b),
|
|
16
|
+
[`11e7365`](https://github.com/brighte-labs/spark-web/commit/11e73659ff4a01a48a8761821bff34c6ec28568b)]:
|
|
17
|
+
- @spark-web/icon@1.1.0
|
|
18
|
+
- @spark-web/utils@1.1.0
|
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Spinner
|
|
3
|
+
storybookPath: feedback-overlays-spinner-—default
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Spinner indicates users that their request is in progress
|
|
7
|
+
|
|
8
|
+
## Examples
|
|
9
|
+
|
|
10
|
+
### Tones
|
|
11
|
+
|
|
12
|
+
The appearance of Spinner can be cutomised with the tone prop.
|
|
13
|
+
|
|
14
|
+
Defaults to `primary`.
|
|
15
|
+
|
|
16
|
+
```jsx live
|
|
17
|
+
const tones = ['secondary', 'critical', 'positive', 'neutral'];
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Stack align="left" gap="xxlarge">
|
|
21
|
+
<Inline gap="xxlarge">
|
|
22
|
+
{tones.map((tone, index) => (
|
|
23
|
+
<Button tone={tone} prominence="low" key={`low-btn-${index}`}>
|
|
24
|
+
<Spinner />
|
|
25
|
+
</Button>
|
|
26
|
+
))}
|
|
27
|
+
</Inline>
|
|
28
|
+
<Inline gap="xxlarge">
|
|
29
|
+
{tones.map((tone, index) => (
|
|
30
|
+
<Button tone={tone} key={`btn-${index}`}>
|
|
31
|
+
<Spinner />
|
|
32
|
+
</Button>
|
|
33
|
+
))}
|
|
34
|
+
</Inline>
|
|
35
|
+
<Inline gap="xxlarge">
|
|
36
|
+
{tones.map((tone, index) => (
|
|
37
|
+
<Spinner tone={tone} key={`spinner-${index}`} />
|
|
38
|
+
))}
|
|
39
|
+
</Inline>
|
|
40
|
+
</Stack>
|
|
41
|
+
);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Size
|
|
45
|
+
|
|
46
|
+
Spinners available in two size: `xxsmall` and `xsmall`.
|
|
47
|
+
|
|
48
|
+
Defaults to `xsmall`.
|
|
49
|
+
|
|
50
|
+
```jsx live
|
|
51
|
+
<Inline gap="xxlarge">
|
|
52
|
+
<Row gap="xxlarge">
|
|
53
|
+
<Spinner size="xxsmall" />
|
|
54
|
+
<Spinner size="xsmall" />
|
|
55
|
+
</Row>
|
|
56
|
+
</Inline>
|
|
57
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { IconProps } from '@spark-web/icon';
|
|
3
|
+
export declare type SpinnerProps = {
|
|
4
|
+
tone?: IconProps['tone'];
|
|
5
|
+
size?: 'xxsmall' | 'xsmall';
|
|
6
|
+
};
|
|
7
|
+
export declare function Spinner({ tone, size }: SpinnerProps): JSX.Element;
|
|
8
|
+
export declare namespace Spinner {
|
|
9
|
+
var displayName: string;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./declarations/src/index";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var css = require('@emotion/css');
|
|
6
|
+
var box = require('@spark-web/box');
|
|
7
|
+
var icon = require('@spark-web/icon');
|
|
8
|
+
var utils = require('@spark-web/utils');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
|
|
11
|
+
function Spinner(_ref) {
|
|
12
|
+
var tone = _ref.tone,
|
|
13
|
+
_ref$size = _ref.size,
|
|
14
|
+
size = _ref$size === void 0 ? 'xxsmall' : _ref$size;
|
|
15
|
+
var spinAnimationRef = utils.useSynchronizedAnimation(spinAnimation);
|
|
16
|
+
var strokeAnimationRef = utils.useSynchronizedAnimation(strokeDashAnimation);
|
|
17
|
+
var styles = useSpinnerStyles();
|
|
18
|
+
return /*#__PURE__*/jsxRuntime.jsx(box.Box, {
|
|
19
|
+
as: "span",
|
|
20
|
+
ref: spinAnimationRef,
|
|
21
|
+
className: css.css(styles),
|
|
22
|
+
height: size,
|
|
23
|
+
width: size,
|
|
24
|
+
display: "inline-flex",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
justifyContent: "center",
|
|
27
|
+
children: /*#__PURE__*/jsxRuntime.jsx(SpinnerIcon, {
|
|
28
|
+
size: size,
|
|
29
|
+
tone: tone,
|
|
30
|
+
ref: strokeAnimationRef
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
Spinner.displayName = 'Spinner';
|
|
35
|
+
var SpinnerIcon = icon.createIcon( /*#__PURE__*/jsxRuntime.jsx("circle", {
|
|
36
|
+
cx: 12,
|
|
37
|
+
cy: 12,
|
|
38
|
+
r: 9
|
|
39
|
+
}), 'SpinnerIcon');
|
|
40
|
+
var spinAnimation = css.keyframes({
|
|
41
|
+
from: {
|
|
42
|
+
transform: 'rotate(0deg)'
|
|
43
|
+
},
|
|
44
|
+
to: {
|
|
45
|
+
transform: 'rotate(360deg)'
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
var strokeDashAnimation = css.keyframes({
|
|
49
|
+
'0%': {
|
|
50
|
+
strokeDasharray: '1px, 200px',
|
|
51
|
+
strokeDashoffset: 0
|
|
52
|
+
},
|
|
53
|
+
'50%': {
|
|
54
|
+
strokeDasharray: '100px, 200px',
|
|
55
|
+
strokeDashoffset: '-15px'
|
|
56
|
+
},
|
|
57
|
+
'100%': {
|
|
58
|
+
strokeDasharray: '100px, 200px',
|
|
59
|
+
strokeDashoffset: '-125px'
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function useSpinnerStyles() {
|
|
64
|
+
return {
|
|
65
|
+
animation: "".concat(spinAnimation, " 1.4s linear infinite"),
|
|
66
|
+
'& circle': {
|
|
67
|
+
animation: "".concat(strokeDashAnimation, " 1.4s ease-in-out infinite")
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
exports.Spinner = Spinner;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var css = require('@emotion/css');
|
|
6
|
+
var box = require('@spark-web/box');
|
|
7
|
+
var icon = require('@spark-web/icon');
|
|
8
|
+
var utils = require('@spark-web/utils');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
|
|
11
|
+
function Spinner(_ref) {
|
|
12
|
+
var tone = _ref.tone,
|
|
13
|
+
_ref$size = _ref.size,
|
|
14
|
+
size = _ref$size === void 0 ? 'xxsmall' : _ref$size;
|
|
15
|
+
var spinAnimationRef = utils.useSynchronizedAnimation(spinAnimation);
|
|
16
|
+
var strokeAnimationRef = utils.useSynchronizedAnimation(strokeDashAnimation);
|
|
17
|
+
var styles = useSpinnerStyles();
|
|
18
|
+
return /*#__PURE__*/jsxRuntime.jsx(box.Box, {
|
|
19
|
+
as: "span",
|
|
20
|
+
ref: spinAnimationRef,
|
|
21
|
+
className: css.css(styles),
|
|
22
|
+
height: size,
|
|
23
|
+
width: size,
|
|
24
|
+
display: "inline-flex",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
justifyContent: "center",
|
|
27
|
+
children: /*#__PURE__*/jsxRuntime.jsx(SpinnerIcon, {
|
|
28
|
+
size: size,
|
|
29
|
+
tone: tone,
|
|
30
|
+
ref: strokeAnimationRef
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
Spinner.displayName = 'Spinner';
|
|
35
|
+
var SpinnerIcon = icon.createIcon( /*#__PURE__*/jsxRuntime.jsx("circle", {
|
|
36
|
+
cx: 12,
|
|
37
|
+
cy: 12,
|
|
38
|
+
r: 9
|
|
39
|
+
}), 'SpinnerIcon');
|
|
40
|
+
var spinAnimation = css.keyframes({
|
|
41
|
+
from: {
|
|
42
|
+
transform: 'rotate(0deg)'
|
|
43
|
+
},
|
|
44
|
+
to: {
|
|
45
|
+
transform: 'rotate(360deg)'
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
var strokeDashAnimation = css.keyframes({
|
|
49
|
+
'0%': {
|
|
50
|
+
strokeDasharray: '1px, 200px',
|
|
51
|
+
strokeDashoffset: 0
|
|
52
|
+
},
|
|
53
|
+
'50%': {
|
|
54
|
+
strokeDasharray: '100px, 200px',
|
|
55
|
+
strokeDashoffset: '-15px'
|
|
56
|
+
},
|
|
57
|
+
'100%': {
|
|
58
|
+
strokeDasharray: '100px, 200px',
|
|
59
|
+
strokeDashoffset: '-125px'
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function useSpinnerStyles() {
|
|
64
|
+
return {
|
|
65
|
+
animation: "".concat(spinAnimation, " 1.4s linear infinite"),
|
|
66
|
+
'& circle': {
|
|
67
|
+
animation: "".concat(strokeDashAnimation, " 1.4s ease-in-out infinite")
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
exports.Spinner = Spinner;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { keyframes, css } from '@emotion/css';
|
|
2
|
+
import { Box } from '@spark-web/box';
|
|
3
|
+
import { createIcon } from '@spark-web/icon';
|
|
4
|
+
import { useSynchronizedAnimation } from '@spark-web/utils';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function Spinner(_ref) {
|
|
8
|
+
var tone = _ref.tone,
|
|
9
|
+
_ref$size = _ref.size,
|
|
10
|
+
size = _ref$size === void 0 ? 'xxsmall' : _ref$size;
|
|
11
|
+
var spinAnimationRef = useSynchronizedAnimation(spinAnimation);
|
|
12
|
+
var strokeAnimationRef = useSynchronizedAnimation(strokeDashAnimation);
|
|
13
|
+
var styles = useSpinnerStyles();
|
|
14
|
+
return /*#__PURE__*/jsx(Box, {
|
|
15
|
+
as: "span",
|
|
16
|
+
ref: spinAnimationRef,
|
|
17
|
+
className: css(styles),
|
|
18
|
+
height: size,
|
|
19
|
+
width: size,
|
|
20
|
+
display: "inline-flex",
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
justifyContent: "center",
|
|
23
|
+
children: /*#__PURE__*/jsx(SpinnerIcon, {
|
|
24
|
+
size: size,
|
|
25
|
+
tone: tone,
|
|
26
|
+
ref: strokeAnimationRef
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
Spinner.displayName = 'Spinner';
|
|
31
|
+
var SpinnerIcon = createIcon( /*#__PURE__*/jsx("circle", {
|
|
32
|
+
cx: 12,
|
|
33
|
+
cy: 12,
|
|
34
|
+
r: 9
|
|
35
|
+
}), 'SpinnerIcon');
|
|
36
|
+
var spinAnimation = keyframes({
|
|
37
|
+
from: {
|
|
38
|
+
transform: 'rotate(0deg)'
|
|
39
|
+
},
|
|
40
|
+
to: {
|
|
41
|
+
transform: 'rotate(360deg)'
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
var strokeDashAnimation = keyframes({
|
|
45
|
+
'0%': {
|
|
46
|
+
strokeDasharray: '1px, 200px',
|
|
47
|
+
strokeDashoffset: 0
|
|
48
|
+
},
|
|
49
|
+
'50%': {
|
|
50
|
+
strokeDasharray: '100px, 200px',
|
|
51
|
+
strokeDashoffset: '-15px'
|
|
52
|
+
},
|
|
53
|
+
'100%': {
|
|
54
|
+
strokeDasharray: '100px, 200px',
|
|
55
|
+
strokeDashoffset: '-125px'
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
function useSpinnerStyles() {
|
|
60
|
+
return {
|
|
61
|
+
animation: "".concat(spinAnimation, " 1.4s linear infinite"),
|
|
62
|
+
'& circle': {
|
|
63
|
+
animation: "".concat(strokeDashAnimation, " 1.4s ease-in-out infinite")
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { Spinner };
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spark-web/spinner",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"main": "dist/spark-web-spinner.cjs.js",
|
|
6
|
+
"module": "dist/spark-web-spinner.esm.js",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@babel/runtime": "^7.14.6",
|
|
9
|
+
"@emotion/css": "^11.7.1",
|
|
10
|
+
"@spark-web/box": "^1.0.2",
|
|
11
|
+
"@spark-web/icon": "^1.1.0",
|
|
12
|
+
"@spark-web/utils": "^1.1.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/react": "^17.0.12",
|
|
16
|
+
"react": "^17.0.2"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": ">=17.0.2"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">= 14.13"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Inline } from '@spark-web/inline';
|
|
2
|
+
import { Stack } from '@spark-web/stack';
|
|
3
|
+
import type { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
4
|
+
|
|
5
|
+
import type { SpinnerProps } from './Spinner';
|
|
6
|
+
import { Spinner } from './Spinner';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: 'Feedback & Overlays / Spinner',
|
|
10
|
+
component: Spinner,
|
|
11
|
+
} as ComponentMeta<typeof Spinner>;
|
|
12
|
+
|
|
13
|
+
const SpinnerStory: ComponentStory<typeof Spinner> = (args: SpinnerProps) => (
|
|
14
|
+
<Stack align="left" gap="xxlarge">
|
|
15
|
+
<Inline gap="xxlarge">
|
|
16
|
+
<Spinner {...args} />
|
|
17
|
+
</Inline>
|
|
18
|
+
</Stack>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export const Default = SpinnerStory.bind({});
|
|
22
|
+
export const Critical = SpinnerStory.bind({});
|
|
23
|
+
export const Caution = SpinnerStory.bind({});
|
|
24
|
+
export const Positive = SpinnerStory.bind({});
|
|
25
|
+
export const Primary = SpinnerStory.bind({});
|
|
26
|
+
|
|
27
|
+
Default.args = {} as SpinnerProps;
|
|
28
|
+
|
|
29
|
+
Caution.args = {
|
|
30
|
+
tone: 'caution',
|
|
31
|
+
} as SpinnerProps;
|
|
32
|
+
|
|
33
|
+
Critical.args = {
|
|
34
|
+
tone: 'critical',
|
|
35
|
+
} as SpinnerProps;
|
|
36
|
+
|
|
37
|
+
Positive.args = {
|
|
38
|
+
tone: 'positive',
|
|
39
|
+
} as SpinnerProps;
|
|
40
|
+
|
|
41
|
+
Primary.args = {
|
|
42
|
+
tone: 'primary',
|
|
43
|
+
} as SpinnerProps;
|
package/src/Spinner.tsx
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { css, keyframes } from '@emotion/css';
|
|
2
|
+
import { Box } from '@spark-web/box';
|
|
3
|
+
import type { IconProps } from '@spark-web/icon';
|
|
4
|
+
import { createIcon } from '@spark-web/icon';
|
|
5
|
+
import { useSynchronizedAnimation } from '@spark-web/utils';
|
|
6
|
+
|
|
7
|
+
export type SpinnerProps = {
|
|
8
|
+
// TODO: match tones to design in Figma
|
|
9
|
+
tone?: IconProps['tone'];
|
|
10
|
+
size?: 'xxsmall' | 'xsmall';
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function Spinner({ tone, size = 'xxsmall' }: SpinnerProps) {
|
|
14
|
+
const spinAnimationRef = useSynchronizedAnimation(spinAnimation);
|
|
15
|
+
const strokeAnimationRef = useSynchronizedAnimation(strokeDashAnimation);
|
|
16
|
+
const styles = useSpinnerStyles();
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Box
|
|
20
|
+
as="span"
|
|
21
|
+
ref={spinAnimationRef}
|
|
22
|
+
className={css(styles)}
|
|
23
|
+
height={size}
|
|
24
|
+
width={size}
|
|
25
|
+
display="inline-flex"
|
|
26
|
+
alignItems="center"
|
|
27
|
+
justifyContent="center"
|
|
28
|
+
>
|
|
29
|
+
<SpinnerIcon size={size} tone={tone} ref={strokeAnimationRef} />
|
|
30
|
+
</Box>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
Spinner.displayName = 'Spinner';
|
|
34
|
+
|
|
35
|
+
const SpinnerIcon = createIcon(<circle cx={12} cy={12} r={9} />, 'SpinnerIcon');
|
|
36
|
+
|
|
37
|
+
const spinAnimation = keyframes({
|
|
38
|
+
from: { transform: 'rotate(0deg)' },
|
|
39
|
+
to: { transform: 'rotate(360deg)' },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const strokeDashAnimation = keyframes({
|
|
43
|
+
'0%': { strokeDasharray: '1px, 200px', strokeDashoffset: 0 },
|
|
44
|
+
'50%': { strokeDasharray: '100px, 200px', strokeDashoffset: '-15px' },
|
|
45
|
+
'100%': { strokeDasharray: '100px, 200px', strokeDashoffset: '-125px' },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
function useSpinnerStyles() {
|
|
49
|
+
return {
|
|
50
|
+
animation: `${spinAnimation} 1.4s linear infinite`,
|
|
51
|
+
'& circle': {
|
|
52
|
+
animation: `${strokeDashAnimation} 1.4s ease-in-out infinite`,
|
|
53
|
+
},
|
|
54
|
+
} as const;
|
|
55
|
+
}
|