diff --git a/src/components/LoadingOverlay/LoadingOverlay.scss b/src/components/LoadingOverlay/LoadingOverlay.scss new file mode 100644 index 0000000000..bf83f8ff5a --- /dev/null +++ b/src/components/LoadingOverlay/LoadingOverlay.scss @@ -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); + } + } + } +} diff --git a/src/components/LoadingOverlay/LoadingOverlay.tsx b/src/components/LoadingOverlay/LoadingOverlay.tsx new file mode 100644 index 0000000000..5c18f7cbc5 --- /dev/null +++ b/src/components/LoadingOverlay/LoadingOverlay.tsx @@ -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 ( + +
+
+ +
+
{children}
+ + ); +} diff --git a/src/components/LoadingOverlay/README.md b/src/components/LoadingOverlay/README.md new file mode 100644 index 0000000000..455caefe4f --- /dev/null +++ b/src/components/LoadingOverlay/README.md @@ -0,0 +1,32 @@ + + +# Loader + + + +```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 + +
I am an example
+
content
+
+``` diff --git a/src/components/LoadingOverlay/__stories__/LoadingOverlay.scss b/src/components/LoadingOverlay/__stories__/LoadingOverlay.scss new file mode 100644 index 0000000000..d68344ee0a --- /dev/null +++ b/src/components/LoadingOverlay/__stories__/LoadingOverlay.scss @@ -0,0 +1,11 @@ +@use '../../variables'; + +$block: '.#{variables.$ns}loading-overlay-showcase'; + +#{$block} { + width: fit-content; + + &__content { + padding: var(--g-spacing-1); + } +} diff --git a/src/components/LoadingOverlay/__stories__/LoadingOverlay.stories.tsx b/src/components/LoadingOverlay/__stories__/LoadingOverlay.stories.tsx new file mode 100644 index 0000000000..efb734e50a --- /dev/null +++ b/src/components/LoadingOverlay/__stories__/LoadingOverlay.stories.tsx @@ -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 = (args) => { + const [showContent, setShowContent] = React.useState(true); + + return ( +
+ + {showContent && ( + +
I am an example
+
content
+
+ )} +
+ +
+ ); +}; +export const Default = DefaultTemplate.bind({}); + +Default.args = { + loading: true, +}; + +const BackgroundTemplate: StoryFn = (args) => { + return ( + +
+ +
I am an example
+
content
+
+
+ +
+ +
I am an example
+
content
+
+
+
+ ); +}; + +export const Background = BackgroundTemplate.bind({}); + +Background.args = { + loading: true, +}; diff --git a/src/components/LoadingOverlay/index.ts b/src/components/LoadingOverlay/index.ts new file mode 100644 index 0000000000..2453ce63f3 --- /dev/null +++ b/src/components/LoadingOverlay/index.ts @@ -0,0 +1 @@ +export * from './LoadingOverlay'; diff --git a/src/components/index.ts b/src/components/index.ts index 34146e1cf1..c0f9839f50 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -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';