Skip to content

Commit

Permalink
feat(Overlay): implement component (#1474)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladeeg authored Jun 25, 2024
1 parent 39cd8ad commit ef47354
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 1 deletion.
49 changes: 49 additions & 0 deletions src/components/Overlay/Overlay.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
@use '../variables';

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

#{$block} {
position: absolute;
inset: 0;

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

isolation: isolate;

opacity: 0;

transition:
visibility 0.1s,
opacity 0.1s linear;

&_visible {
visibility: visible;

opacity: 1;
}

&__background {
position: absolute;
z-index: 0;
inset: 0;

opacity: 0.8;

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

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

&__children {
z-index: 1;
}
}
25 changes: 25 additions & 0 deletions src/components/Overlay/Overlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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;
background?: OverlayBackground;
visible?: boolean;
children?: React.ReactNode;
}

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

# Overlay

<!--/GITHUB_BLOCK-->

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

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

```jsx
import {Box, Overlay, Loader} from '@gravity-ui/uikit';

<Box position="relative">
<div>Some content to hide under overlay</div>
<Overlay visible={loading}>
<Loader />
</Overlay>
</Box>;
```

## Appearance

### Background

You can use `base` or `float` background colors.

<!--GITHUB_BLOCK-->

```tsx
<Overlay background="base">
<Overlay background="float">
```

<!--/GITHUB_BLOCK-->

## Properties

| Name | Description | Type | Default |
| :--------- | :---------------------------------- | :----------------: | :-----: |
| className | CSS class name of the root element | `string` | |
| visible | Overlay visibility state | `boolean` | `false` |
| background | Overlay background style | `"base"` `"float"` | `base` |
| children | Content, usually a Loader component | `React.ReactNode` | |
7 changes: 7 additions & 0 deletions src/components/Overlay/__stories__/Docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {Meta, Markdown} from '@storybook/addon-docs';
import * as Stories from './Overlay.stories';
import Readme from '../README.md?raw';

<Meta of={Stories} />

<Markdown>{Readme}</Markdown>
22 changes: 22 additions & 0 deletions src/components/Overlay/__stories__/Overlay.stories.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@use '../../variables';

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

#{$block} {
&__content {
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);
}
}
}
128 changes: 128 additions & 0 deletions src/components/Overlay/__stories__/Overlay.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React from 'react';

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

import {Showcase} from '../../../demo/Showcase';
import {ShowcaseItem} from '../../../demo/ShowcaseItem';
import {Button} from '../../Button';
import {Icon} from '../../Icon';
import {Loader} from '../../Loader';
import {Table as TableComponent} from '../../Table';
import {Box} from '../../layout';
import {block} from '../../utils/cn';
import {Overlay} from '../Overlay';
import type {OverlayProps} from '../Overlay';

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

import './Overlay.stories.scss';

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

type Story = StoryObj<typeof Overlay>;

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

export const Default: Story = {
args: {
visible: true,
},
render: (args) => {
return (
<Showcase>
<Box position="relative" className={b('content')}>
<div>Example of overlay</div>
<div>with loader</div>
<Overlay {...args}>
<Loader size="m" />
</Overlay>
</Box>
<Box position="relative" className={b('content')}>
<div>Example of overlay</div>
<div>with text</div>
<Overlay {...args}>Loading...</Overlay>
</Box>
<Box position="relative" className={b('content')}>
<div>Example of overlay</div>
<div>with icon</div>
<Overlay {...args}>
<Icon data={ArrowsRotateRight} />
</Overlay>
</Box>
<Box position="relative" className={b('content')}>
<div>Example of overlay</div>
<div>without children</div>
<Overlay {...args} />
</Box>
</Showcase>
);
},
};

export const Background: Story = {
args: {
visible: true,
},
render: (args) => {
return (
<Showcase>
<ShowcaseItem title="base">
<Box position="relative" className={b('content')}>
<div>I am an example</div>
<div>content</div>
<Overlay {...args} background="base" />
</Box>
</ShowcaseItem>
<ShowcaseItem title="float">
<Box position="relative" className={b('content')}>
<div>I am an example</div>
<div>content</div>
<Overlay {...args} background="float" />
</Box>
</ShowcaseItem>
</Showcase>
);
},
};

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

return (
<div className={b()}>
<Box position="relative" className={b('content')}>
<TableComponent className={b('table')} columns={columns} data={loadedData} />
<Overlay {...args} visible={loading}>
<Loader size="m" />
</Overlay>
</Box>
<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: Story = {
args: {},
render: TableView,
};
91 changes: 91 additions & 0 deletions src/components/Overlay/__stories__/data.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 @@ -25,6 +25,7 @@ export * from './List';
export * from './Loader';
export * from './Menu';
export * from './Modal';
export * from './Overlay';
export * from './Pagination';
export * from './Palette';
export * from './UserLabel';
Expand Down
Loading

0 comments on commit ef47354

Please sign in to comment.