Skip to content

Commit

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

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

#{$block} {
position: absolute;
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%;

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

&_float {
background-color: var(--g-color-base-float);
}
}
}

&__children {
z-index: 0;
}
}
30 changes: 30 additions & 0 deletions src/components/Overlay/Overlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';

import {block} from '../utils/cn';

import './Overlay.scss';

const b = block('overlay');

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

export interface OverlayProps {
className?: string;
view?: OverlayBackground;
visible?: boolean;
children?: React.ReactNode;
}

export function Overlay({
className,
view = 'base',
visible: loading = false,
children,
}: OverlayProps) {
return (
<div className={b({visible: loading}, className)}>
<div className={b('background', {view})} />
{children && <div className={b('children')}>{children}</div>}
</div>
);
}
32 changes: 32 additions & 0 deletions src/components/Overlay/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!--GITHUB_BLOCK-->

# Loader

<!--/GITHUB_BLOCK-->

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

The `Overlay` component renders an overlay over the parent element with relative position.
For example, it can be used to preserve the desired layout while loading data.

### PropTypes

| Name | Type | Required | Default | Description |
| :-------- | :----------------- | :------: | :------ | :---------------------------------- |
| className | `String` | | | CSS class name of the root element |
| visible | `Boolean` | | `false` | Overlay visibility state |
| view | `"base"` `"float"` | | `base` | Overlay background style |
| children | `React.ReactNode` | | | Content, usually a Loader component |

### Basic usage

```jsx
<div style={{position: 'relative'}}>
<div>Some content to hide under overlay</div>
<Overlay visible={loading}>
<Loader />
</Overlay>
</div>
```
24 changes: 24 additions & 0 deletions src/components/Overlay/__stories__/Overlay.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@use '../../variables';

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

#{$block} {
&__content {
position: relative;

width: fit-content;
padding: var(--g-spacing-1);
}

&__table table {
min-width: 763px;
}

&__button {
margin-block-start: var(--g-spacing-1);

& + & {
margin-inline-start: var(--g-spacing-1);
}
}
}
151 changes: 151 additions & 0 deletions src/components/Overlay/__stories__/Overlay.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import React from 'react';

import {ArrowsRotateRight} from '@gravity-ui/icons';
import type {Meta, StoryFn} from '@storybook/react';

import {Button} from '../../Button';
import {Dialog as DialogComponent} from '../../Dialog';
import {Icon} from '../../Icon';
import {Loader} from '../../Loader';
import {Table as TableComponent} from '../../Table';
import {block} from '../../utils/cn';
import {Overlay} from '../Overlay';
import type {OverlayProps} from '../Overlay';

import {columns, data} from './utils';
import type {DataItem} from './utils';

import './Overlay.scss';

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

export default {
title: 'Components/Overlays/Overlay',
component: Overlay,
} as Meta;

const DefaultTemplate: StoryFn<OverlayProps> = (args) => {
return (
<div className={b()}>
<div className={b('content')}>
<div>Example of overlay</div>
<div>with loader</div>
<Overlay {...args}>
<Loader />
</Overlay>
</div>
<div className={b('content')}>
<div>Example of overlay</div>
<div>with text</div>
<Overlay {...args}>Loading...</Overlay>
</div>
<div className={b('content')}>
<div>Example of overlay</div>
<div>with icon</div>
<Overlay {...args}>
<Icon data={ArrowsRotateRight} />
</Overlay>
</div>
<div className={b('content')}>
<div>Example of overlay</div>
<div>without children</div>
<Overlay {...args} />
</div>
</div>
);
};
export const Default = DefaultTemplate.bind({});

Default.args = {
visible: true,
};

const BackgroundTemplate: StoryFn<OverlayProps> = (args) => {
return (
<div className={b()}>
<div className={b('content')}>
<div>I am an example</div>
<div>content</div>
<Overlay {...args} view="base" />
</div>
<span style={{margin: '16px'}} />
<div className={b('content')}>
<div>I am an example</div>
<div>content</div>
<Overlay {...args} view="float" />
</div>
</div>
);
};

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

Background.args = {
visible: true,
};

const DialogTemplate: StoryFn<OverlayProps> = (args) => {
const dialogTitleId = 'app-dialog-title';
return (
<DialogComponent
open
onClose={() => {}}
onEnterKeyDown={() => {
alert('onEnterKeyDown');
}}
aria-labelledby={dialogTitleId}
>
<div className={b('content')}>
<DialogComponent.Header caption="Caption" id={dialogTitleId} />
<DialogComponent.Body>Dialog.Body</DialogComponent.Body>
<DialogComponent.Footer
onClickButtonApply={() => alert('onApply')}
textButtonApply="Apply"
/>
<Overlay {...args}>
<Loader size="m" />
</Overlay>
</div>
</DialogComponent>
);
};

export const Dialog = DialogTemplate.bind({});

Dialog.args = {
visible: true,
};

const TableTemplate: StoryFn<OverlayProps> = (args) => {
const [loading, setLoading] = React.useState(false);
const [loadedData, setData] = React.useState<DataItem[]>([]);

return (
<div className={b()}>
<div className={b('content')}>
<TableComponent className={b('table')} columns={columns} data={loadedData} />
<Overlay {...args} visible={loading}>
<Loader size="m" />
</Overlay>
</div>
<Button
className={b('button')}
disabled={loading}
onClick={() => {
setLoading(true);
setTimeout(() => {
setLoading(false);
setData(data);
}, 1000);
}}
>
Load data
</Button>
<Button className={b('button')} disabled={loading} onClick={() => setData([])}>
Clear data
</Button>
</div>
);
};

export const Table = TableTemplate.bind({});
91 changes: 91 additions & 0 deletions src/components/Overlay/__stories__/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React from 'react';

import type {TableColumnConfig} from '../../Table';

export interface DataItem {
name: string;
location?: {region: string; city?: string};
phone: string;
count: number;
date: string;
disabled?: boolean;
}

export const columns: TableColumnConfig<DataItem>[] = [
{
id: 'name',
name: 'Name',
template(item, i) {
if (i % 2 === 0) {
return item.name;
}
const [name, surname] = item.name.split(' ');
return (
<div>
{name}
<br />
{surname}
</div>
);
},
},
{
id: 'location.region',
name: 'Region',
},
{
id: 'location.city',
name: 'City',
},
{
id: 'phone',
name: 'Phone',
},
{
id: 'count',
name: 'Count',
align: 'end',
},
{
id: 'date',
name: 'Date created',
},
];

export const data: DataItem[] = [
{
name: 'Nomlanga Compton',
location: {region: 'Liguria', city: 'Erli'},
phone: '+7 (923) 737-89-72',
count: 82,
date: '2019-03-15',
},
{
name: 'Paul Hatfield',
location: {region: 'Trentino-Alto Adige/Südtirol', city: 'Campitello di Fassa'},
phone: '+7 (900) 333-82-02',
count: 51,
date: '2019-11-23',
},
{
name: 'Phelan Daniel',
location: {region: 'Piedmont', city: 'Meugliano'},
phone: '+7 (925) 549-50-23',
count: 10,
date: '2019-05-14',
},
{
name: 'Hiram Mayer',
phone: '+7 (950) 372-56-84',
location: {region: 'Calabria'},
count: 54,
date: '2019-03-29',
},
{
name: 'Madeline Puckett',
phone: '+7 (908) 582-05-91',
count: 75,
date: '2019-02-01',
disabled: true,
},
];
1 change: 1 addition & 0 deletions src/components/Overlay/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Overlay';
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 './Overlay';
export * from './Menu';
export * from './Modal';
export * from './Pagination';
Expand Down

0 comments on commit 73868ac

Please sign in to comment.