diff --git a/packages/screenshots/testplane/chrome/components/loader/squares/squares-dark.png b/packages/screenshots/testplane/chrome/components/loader/squares/squares-dark.png
new file mode 100644
index 00000000000..50a6b485232
--- /dev/null
+++ b/packages/screenshots/testplane/chrome/components/loader/squares/squares-dark.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:48255cff394cf01166cc48c82af41aa475ce5865cfdd0c56b454a1620307b9a6
+size 2498
diff --git a/packages/screenshots/testplane/chrome/components/loader/squares/squares.png b/packages/screenshots/testplane/chrome/components/loader/squares/squares.png
new file mode 100644
index 00000000000..90690cdfafa
--- /dev/null
+++ b/packages/screenshots/testplane/chrome/components/loader/squares/squares.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2489de9451d81373fedc0773d6d55bd7010700d785f18469d3aa37652013aa78
+size 2489
diff --git a/packages/screenshots/testplane/firefox/components/loader/squares/squares-dark.png b/packages/screenshots/testplane/firefox/components/loader/squares/squares-dark.png
new file mode 100644
index 00000000000..c1276b407de
--- /dev/null
+++ b/packages/screenshots/testplane/firefox/components/loader/squares/squares-dark.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f485279d9ec123e5fe0e8fd587a0e65d2629d5280c589de1fa30bbd322e200a7
+size 3194
diff --git a/packages/screenshots/testplane/firefox/components/loader/squares/squares.png b/packages/screenshots/testplane/firefox/components/loader/squares/squares.png
new file mode 100644
index 00000000000..d054974fe25
--- /dev/null
+++ b/packages/screenshots/testplane/firefox/components/loader/squares/squares.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5430768c00c2d7708b946603ef2b6567816498a5ffb569ea66d868c3ac48bed2
+size 3124
diff --git a/src/button/button.stories.tsx b/src/button/button.stories.tsx
index 96ab5cdfb0e..8e13113d1ee 100644
--- a/src/button/button.stories.tsx
+++ b/src/button/button.stories.tsx
@@ -3,7 +3,8 @@ import pencilIcon from '@jetbrains/icons/pencil';
import pencil12pxIcon from '@jetbrains/icons/pencil-12px';
import hourglassIcon from '@jetbrains/icons/hourglass';
-import Loader from '../loader-inline/loader-inline';
+import Loader from '../loader/loader';
+import LoaderInline from '../loader-inline/loader-inline';
import {ControlsHeight, ControlsHeightContext} from '../global/controls-height';
import {Col, Grid} from '../grid/grid';
import Row from '../grid/row';
@@ -138,7 +139,12 @@ export const longAction = () => {
Sleep
- {loading && }
+ {loading && (
+ <>
+
+
+ >
+ )}
);
}
diff --git a/src/loader/loader.css b/src/loader/loader.css
index c17280c3403..27f3641e342 100644
--- a/src/loader/loader.css
+++ b/src/loader/loader.css
@@ -1,5 +1,13 @@
@import '../global/variables.css';
+/* stylelint-disable color-no-hex */
+:root {
+ --ring-loader-color-1: #3bea62;
+ --ring-loader-color-2: #6b57ff;
+ --ring-loader-color-3: #07c3f2;
+}
+/* stylelint-enable */
+
@keyframes rotation-keyframes {
100% {
transform: rotate(360deg);
@@ -14,6 +22,147 @@
pointer-events: none;
}
+.squares {
+ position: relative;
+
+ width: 60px;
+ height: 60px;
+}
+
+@keyframes square-animation-main {
+ 0% {
+ transform: rotate(0deg);
+ animation-timing-function: cubic-bezier(0.333, 0, 0, 1);
+ }
+
+ 37.5% {
+ transform: rotate(182deg);
+ animation-timing-function: cubic-bezier(0.333, 0, 0.657, 1);
+ }
+
+ 50% {
+ transform: rotate(180deg);
+ animation-timing-function: cubic-bezier(0.333, 0, 0, 1);
+ }
+
+ 87.5% {
+ transform: rotate(362deg);
+ animation-timing-function: cubic-bezier(0.333, 0, 0.657, 1);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ animation-timing-function: cubic-bezier(0.333, 0, 0, 1);
+ }
+}
+
+@keyframes square-animation-pseudo {
+ 0% {
+ animation-timing-function: cubic-bezier(0.333, 0, 0, 1);
+
+ opacity: 0;
+ }
+
+ 18.75% {
+ animation-timing-function: cubic-bezier(0.333, 0, 0.657, 1);
+
+ opacity: 1;
+ }
+
+ 25% {
+ animation-timing-function: cubic-bezier(0.333, 0, 0, 1);
+
+ opacity: 1;
+ }
+
+ 43.75% {
+ animation-timing-function: cubic-bezier(0.333, 0, 0.657, 1);
+
+ opacity: 0;
+ }
+
+ 100% {
+ animation-timing-function: cubic-bezier(0.333, 0, 0, 1);
+
+ opacity: 0;
+ }
+}
+
+.square {
+ animation: square-animation-main 3.2s infinite;
+
+ background: var(--ring-loader-color-1);
+ mask-image: linear-gradient(to top, rgb(0, 0, 0) 0%, rgba(0, 0, 0, 0.5) 100%);
+
+ &,
+ &::before,
+ &::after {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+
+ border-radius: 20%;
+ }
+
+ &::before {
+ content: '';
+ animation: square-animation-pseudo 6.4s infinite;
+
+ opacity: 0;
+
+ background: var(--ring-loader-color-2);
+ }
+
+ &::after {
+ content: '';
+ animation: square-animation-pseudo 6.4s 3.2s infinite;
+
+ opacity: 0;
+
+ background: var(--ring-loader-color-3);
+ }
+}
+
+.inner {
+ top: 20px;
+ right: 20px;
+ bottom: 20px;
+ left: 20px;
+}
+
+.middle {
+ top: 10px;
+ right: 10px;
+ bottom: 10px;
+ left: 10px;
+
+ opacity: 0.8;
+
+ &,
+ &::before {
+ animation-delay: 0.08s;
+ }
+
+ &::after {
+ animation-delay: 3.28s;
+ }
+}
+
+.outer {
+ opacity: 0.7;
+
+ &,
+ &::before {
+ animation-delay: 0.16s;
+ }
+
+ &::after {
+ animation-delay: 3.36s;
+ }
+}
+
.animate {
animation: rotation-keyframes 36s linear infinite;
}
diff --git a/src/loader/loader.stories.tsx b/src/loader/loader.stories.tsx
index 8bd7531a3b6..a63bd4b5d56 100644
--- a/src/loader/loader.stories.tsx
+++ b/src/loader/loader.stories.tsx
@@ -1,4 +1,4 @@
-import {type StoryFn} from '@storybook/react-webpack5';
+import {type StoryFn, type StoryObj} from '@storybook/react-webpack5';
import Loader, {type LoaderProps} from './loader';
@@ -6,12 +6,16 @@ export default {
title: 'Components/Loader',
component: Loader,
- parameters: {
- screenshots: {skip: true},
- },
};
export const basic: StoryFn = args => ;
basic.storyName = 'Loader';
basic.args = {message: 'Loading...'};
+basic.parameters = {
+ screenshots: {skip: true},
+};
+
+export const squares: StoryObj = {
+ args: {message: 'Loading...', squares: true},
+};
diff --git a/src/loader/loader.tsx b/src/loader/loader.tsx
index 01510d01b22..b4993e6e458 100644
--- a/src/loader/loader.tsx
+++ b/src/loader/loader.tsx
@@ -1,9 +1,20 @@
import {type HTMLAttributes, PureComponent} from 'react';
+import classNames from 'classnames';
import LoaderCore, {type LoaderCoreProps} from './loader-core';
+import styles from './loader.css';
+
+declare module 'csstype' {
+ interface Properties {
+ '--ring-loader-color-1'?: string;
+ '--ring-loader-color-2'?: string;
+ '--ring-loader-color-3'?: string;
+ }
+}
export interface LoaderProps extends Partial, HTMLAttributes {
'data-test'?: string | null | undefined;
+ squares?: boolean; // TODO make default in 8.0
}
/**
@@ -35,8 +46,26 @@ export default class Loader extends PureComponent {
};
render() {
- const {message, size, colors, 'data-test': dataTest, stop, deterministic, ...restProps} = this.props;
+ const {message, size, colors, 'data-test': dataTest, stop, deterministic, squares, ...restProps} = this.props;
- return ;
+ return squares ? (
+
+
+ {message &&
{message}
}
+
+ ) : (
+
+ );
}
}