Skip to content

Commit

Permalink
feat(LoadingOverlay): implement component
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladeeg committed Apr 2, 2024
1 parent 2f0e83e commit 0368a2c
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/components/LoadingOverlay/LoadingOverlay.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@use '../variables';

$block: '.#{variables.$ns}loading-overlay';

#{$block} {
position: relative;

&__overlay {
position: absolute;
z-index: 200;
inset: 0;

display: flex;
visibility: hidden;
justify-content: center;
align-items: center;

opacity: 0;

transition:
visibility 0.1s linear,
opacity 0.1s linear;

&_visible {
visibility: visible;
opacity: 1;
}
}

&__background {
position: absolute;
inset: 0;

opacity: 80%;

&_type {
&_base {
background-color: var(--g-color-base-background);
}

&_float {
background-color: var(--g-color-base-float);
}
}
}
}
42 changes: 42 additions & 0 deletions src/components/LoadingOverlay/LoadingOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';

import {Loader} from '../Loader';
import type {LoaderProps} from '../Loader';
import {Box} from '../layout';
import type {BoxProps} from '../layout';
import {block} from '../utils/cn';

import './LoadingOverlay.scss';

const b = block('loading-overlay');

export type OverlayBackground = 'base' | 'float';

export interface LoadingOverlayProps extends BoxProps {
loaderProps?: LoaderProps;
background?: OverlayBackground;
loading?: boolean;
children?: React.ReactNode;
className?: string;
contentClassName?: string;
}

export function LoadingOverlay({
loaderProps,
background = 'base',
loading = false,
children,
className,
contentClassName,
...boxProps
}: LoadingOverlayProps) {
return (
<Box className={b(null, className)} {...boxProps}>
<div className={b('overlay', {visible: loading})}>
<div className={b('background', {type: background})} />
<Loader {...loaderProps} />
</div>
<div className={b('content', contentClassName)}>{children}</div>
</Box>
);
}
32 changes: 32 additions & 0 deletions src/components/LoadingOverlay/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--GITHUB_BLOCK-->

# Loader

<!--/GITHUB_BLOCK-->

```tsx
import {LoadingOverlay} from '@gravity-ui/uikit';
```

The `LoadingOverlay` component renders an overlay with a loader over the content. It can be used to preserve the desired layout while loading data.

### PropTypes

| Name | Type | Required | Default | Description |
| :--------------- | :----------------- | :------: | :------ | :------------------------------------------ |
| className | `String` | | | CSS class name of root element |
| contentClassName | `String` | | | CSS class name of a content wrapper element |
| loading | `Boolean` | | `false` | Overlay visibility state |
| background | `"base"` `"float"` | | `base` | Background style |
| loaderProps | `LoaderProps` | | | Props of a Loader element |
| children | `React.ReactNode` | | | Content |
| ...props | `BoxProps` | | | Props of a wrapping Box element |

### Basic usage

```jsx
<LoadingOverlay loading={loading} contentClassName={b('content')}>
<div>I am an example</div>
<div>content</div>
</LoadingOverlay>
```
11 changes: 11 additions & 0 deletions src/components/LoadingOverlay/__stories__/LoadingOverlay.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@use '../../variables';

$block: '.#{variables.$ns}loading-overlay-showcase';

#{$block} {
width: fit-content;

&__content {
padding: var(--g-spacing-1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';

import type {Meta, StoryFn} from '@storybook/react';

import {Button} from '../../Button';
import {spacing} from '../../layout';
import {block} from '../../utils/cn';
import {LoadingOverlay} from '../LoadingOverlay';
import type {LoadingOverlayProps} from '../LoadingOverlay';

import './LoadingOverlay.scss';

const b = block('loading-overlay-showcase');

export default {
title: 'Components/Feedback/LoadingOverlay',
component: LoadingOverlay,
} as Meta;

const DefaultTemplate: StoryFn<LoadingOverlayProps> = (args) => {
const [showContent, setShowContent] = React.useState<boolean>(true);

return (
<div className={b()}>
<LoadingOverlay {...args} contentClassName={b('content')} minHeight={44}>
{showContent && (
<React.Fragment>
<div>I am an example</div>
<div>content</div>
</React.Fragment>
)}
</LoadingOverlay>
<Button className={spacing({mt: 2})} onClick={() => setShowContent((value) => !value)}>
Toggle content
</Button>
</div>
);
};
export const Default = DefaultTemplate.bind({});

Default.args = {
loading: true,
};

const BackgroundTemplate: StoryFn<LoadingOverlayProps> = (args) => {
return (
<React.Fragment>
<div className={b()}>
<LoadingOverlay {...args} background="base" contentClassName={b('content')}>
<div>I am an example</div>
<div>content</div>
</LoadingOverlay>
</div>
<span style={{margin: '16px'}} />
<div className={b()}>
<LoadingOverlay {...args} background="float" contentClassName={b('content')}>
<div>I am an example</div>
<div>content</div>
</LoadingOverlay>
</div>
</React.Fragment>
);
};

export const Background = BackgroundTemplate.bind({});

Background.args = {
loading: true,
};
1 change: 1 addition & 0 deletions src/components/LoadingOverlay/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './LoadingOverlay';
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from './Label';
export * from './Link';
export * from './List';
export * from './Loader';
export * from './LoadingOverlay';
export * from './Menu';
export * from './Modal';
export * from './Pagination';
Expand Down

0 comments on commit 0368a2c

Please sign in to comment.