Skip to content

Commit

Permalink
feat(Loader): add _view_circle (#3849)
Browse files Browse the repository at this point in the history
closes #3589
closes #3545
closes #3543
closes #3519
closes #3847

---------

Co-authored-by: alyonurchick1 <[email protected]>
  • Loading branch information
gizeasy and alyonurchick1 authored Dec 12, 2024
1 parent 7e7004f commit 8a2180b
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 93 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"@babel/preset-typescript": "^7.18.6",
"@bem/sdk.naming.cell.match": "^0.1.3",
"@bem/sdk.naming.presets": "^0.2.3",
"@consta/stand": "^0.0.141",
"@consta/stand": "^0.0.148",
"@consta/uikit": "^5.4.1",
"@cspell/dict-ru_ru": "^2.2.4",
"@mdx-js/loader": "^2.1.5",
Expand Down
9 changes: 8 additions & 1 deletion src/components/Button/Button.css
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,15 @@
}

& .Button-Loader {
--loaderBackgroundColor: var(--button-loader-color);
--loader-color-prop: var(--button-loader-color);
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
}
}
}
9 changes: 7 additions & 2 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import './Button.css';
import { IconComponent, IconPropSize } from '@consta/icons/Icon';
import React, { HTMLProps, useRef } from 'react';

import { Loader } from '##/components/Loader';

import { useForkRef } from '../../hooks/useForkRef/useForkRef';
import { cnMixFocus } from '../../mixs/MixFocus/MixFocus';
import { cn } from '../../utils/bem';
import { getByMap } from '../../utils/getByMap';
import { forwardRefWithAs } from '../../utils/types/PropsWithAsAttributes';
import { usePropsHandler } from '../EventInterceptor/usePropsHandler';
import { Loader } from '../LoaderDeprecated/LoaderDeprecated';

export const buttonPropSize = ['m', 'xs', 's', 'l'] as const;
export type ButtonPropSize = typeof buttonPropSize[number];
Expand Down Expand Up @@ -197,7 +198,11 @@ export const Button = forwardRefWithAs<Props, 'button'>((props, ref) => {
) : (
label
))}
{loading && <Loader className={cnButton('Loader')} size="s" />}
{loading && (
<div className={cnButton('Loader')}>
<Loader size="s" />
</div>
)}
</Tag>
);
});
135 changes: 103 additions & 32 deletions src/components/Loader/Loader.css
Original file line number Diff line number Diff line change
@@ -1,55 +1,126 @@
/* --loader-size-prop - задайте для указания размера */
.Loader {
--backgroundColor:
var(
--loaderBackgroundColor,
var(--color-control-bg-primary)
--loader-color-var: var(--loader-color-prop, var(--loader-color));
--loader-type-circle-size-var:
max(
var(--loader-size-prop, var(--loader-type-circle-size)),
var(--space-s)
);
--loader-type-dot-size-var:
max(
var(--loader-size-prop, var(--loader-type-dot-size)),
calc(var(--space-l) - var(--space-3xs))
);
display: inline-flex;
padding: calc(var(--loader-size) * 0.25);
gap: var(--loader-gap);

&-Dot {
width: var(--loader-size);
height: var(--loader-size);
background: var(--backgroundColor);
border-radius: 50%;
animation: var(--loader-dot-animation);

&_side {
&_left {
--loader-dot-animation: loader 1s ease infinite;
}
box-sizing: border-box;

&_center {
--loader-dot-animation: loader 1s -0.18s ease infinite;
}
&_view {
&_primary {
--loader-color: var(--color-control-bg-primary);
}

&_right {
--loader-dot-animation: loader 1s -0.36s ease infinite;
}
&_clear {
--loader-color: var(--color-control-typo-clear);
}
}

&_size {
&_xs {
--loader-size: var(--space-2xs);
--loader-gap: var(--space-3xs);
--loader-type-circle-size: var(--space-s);
--loader-type-dot-size: calc(var(--space-l) - var(--space-3xs));
}

&_s {
--loader-size: var(--space-2xs);
--loader-gap: var(--space-2xs);
--loader-type-circle-size: var(--space-m);
--loader-type-dot-size: calc(var(--space-xl) - var(--space-3xs));
}

&_m {
--loader-size: var(--space-xs);
--loader-gap: calc(var(--space-xs) - var(--space-3xs));
--loader-type-circle-size: var(--space-xl);
--loader-type-dot-size: var(--space-3xl);
}
}

&_type {
&_dots {
--loader-dot-padding:
round(
down,
calc(var(--loader-type-dot-size-var) / 12),
1px
);
--loader-dot-size:
round(
down,
calc(
var(--loader-type-dot-size-var) / 3 - var(--loader-dot-padding) * 1.4
),
2px
);
--loader-dot-scale:
calc(
var(--loader-dot-padding) + var(--loader-dot-size)
);
justify-content: space-between;
width: var(--loader-type-dot-size-var);
margin: calc(var(--loader-dot-scale) * 1px);
padding: max(calc(var(--loader-dot-padding) / 2), 1px);

&::before,
&::after,
.Loader-Dot {
flex: none;
width: var(--loader-dot-size);
height: var(--loader-dot-size);
background: var(--loader-color-var);
border-radius: 50%;
animation:
Loader-Animate_type_dots 1s
var(--loader-type-dot-animation-delay) ease infinite;
}

&::before,
&::after {
content: '';
}

&::before {
--loader-type-dot-animation-delay: 0s;
}

&::after {
--loader-type-dot-animation-delay: 0.36s;
}

.Loader-Dot {
--loader-type-dot-animation-delay: 0.18s;
}
}

&_circle {
--loader-type-circle-mask:
conic-gradient(#0000 2%, #000),
linear-gradient(#000 0 0) content-box;
width: var(--loader-type-circle-size-var);
height: var(--loader-type-circle-size-var);
padding: round(up, calc(var(--loader-type-circle-size-var) / 10), 1px);
background: var(--loader-color-var);
border-radius: 50%;
animation: Loader-Animate_type_circle 1.2s infinite linear;
mask: var(--loader-type-circle-mask);
mask-composite: subtract;
}
}
}

@keyframes loader {
@keyframes Loader-Animate_type_dots {
50% {
transform: scale(1.5);
transform: scale(1.4);
}
}

@keyframes Loader-Animate_type_circle {
to {
transform: rotate(1turn);
}
}
21 changes: 10 additions & 11 deletions src/components/Loader/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,26 @@ import './Loader.css';
import React from 'react';

import { cn } from '../../utils/bem';
import { LoaderProps, loaderPropSizeDefault } from './types';
import { LoaderProps } from './types';

export const cnLoader = cn('Loader');

const sides = ['left', 'center', 'right'];

export const Loader = React.forwardRef<HTMLDivElement, LoaderProps>(
(props, ref) => {
const { className, size = loaderPropSizeDefault, ...otherProps } = props;
const {
className,
size = 'm',
type = 'dots',
view = 'primary',
...otherProps
} = props;
return (
<div
{...otherProps}
ref={ref}
className={cnLoader({ size }, [className])}
className={cnLoader({ size, view, type }, [className])}
>
{sides.map((side, index) => (
<div
key={cnLoader('Dot', { index })}
className={cnLoader('Dot', { side })}
/>
))}
{type === 'dots' && <div className={cnLoader('Dot')} />}
</div>
);
},
Expand Down
Loading

0 comments on commit 8a2180b

Please sign in to comment.