From 6f43707e9914672c06a16ff0ec9aed768e2b4837 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Fri, 9 Aug 2024 10:39:26 +0300 Subject: [PATCH 01/15] feat(PlaceholderContainer): add component and showcases --- .../PlaceholderContainer.scss | 219 ++++++++++++++++ .../PlaceholderContainer.tsx | 124 +++++++++ .../PlaceholderContainerAction.tsx | 45 ++++ .../PlaceholderContainer.stories.tsx | 28 +++ .../PlaceholderContainerShowcase.scss | 37 +++ .../PlaceholderContainerShowcase.tsx | 238 ++++++++++++++++++ .../PlaceholderContainer/constants.ts | 11 + src/components/PlaceholderContainer/index.ts | 6 + src/components/PlaceholderContainer/types.ts | 38 +++ src/components/variables.scss | 13 + 10 files changed, 759 insertions(+) create mode 100644 src/components/PlaceholderContainer/PlaceholderContainer.scss create mode 100644 src/components/PlaceholderContainer/PlaceholderContainer.tsx create mode 100644 src/components/PlaceholderContainer/PlaceholderContainerAction.tsx create mode 100644 src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx create mode 100644 src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss create mode 100644 src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx create mode 100644 src/components/PlaceholderContainer/constants.ts create mode 100644 src/components/PlaceholderContainer/index.ts create mode 100644 src/components/PlaceholderContainer/types.ts diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.scss b/src/components/PlaceholderContainer/PlaceholderContainer.scss new file mode 100644 index 0000000000..741b1be4d3 --- /dev/null +++ b/src/components/PlaceholderContainer/PlaceholderContainer.scss @@ -0,0 +1,219 @@ +@import '../variables'; +@import '../../../styles/mixins'; + +$imageSmallSize: 100px; +$imageMediumSize: 150px; +$imageLargeSize: 230px; + +$contentHeightSmallSize: 130px; +$contentHeightMediumSize: 180px; +$contentHeightLargeSize: 320px; + +$containerSmallRowSize: 320px; +$containerMediumRowSize: 430px; +$containerLargeRowSize: 600px; + +$containerSmallColSize: 320px; +$containerMediumColSize: 320px; +$containerLargeColSize: 430px; + +$block: '.#{$ns}placeholder-container'; + +@mixin container-row-sizes($bodyWidth, $imageSize, $contentHeight, $contentOffset) { + #{$block}__body { + max-width: $bodyWidth; + } + + #{$block}__image { + width: $imageSize; + + & > * { + max-width: $imageSize; + } + } + + #{$block}__content { + margin-inline-start: $contentOffset; + min-height: $contentHeight; + } +} + +@mixin container-column-sizes($bodyWidth, $imageSize) { + #{$block}__body { + max-width: $bodyWidth; + } + + #{$block}__image { + max-height: $imageSize; + + & > * { + max-height: $imageSize; + } + } +} + +#{$block} { + box-sizing: border-box; + display: flex; + align-items: center; + padding: $mediumOffset; + + &#{$block}_align { + &_left { + justify-content: flex-start; + } + + &_center { + justify-content: center; + } + } + + &__body { + box-sizing: border-box; + display: flex; + align-items: center; + } + + &_size_s { + padding: $normalOffset; + + #{$block}__description { + margin-block-start: $nanoOffset; + } + } + + &_size_m { + padding: $mediumOffset; + + #{$block}__description { + margin-block-start: $microOffset; + } + } + + &_size_promo, + &_size_l { + #{$block}__description { + margin-block-start: $smallOffset; + } + } + + &__image { + flex-shrink: 0; + + img { + display: block; + } + } + + &__content { + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + flex-grow: 1; + } + + &__title { + #{$block}_size_s & { + @include text-subheader-1(); + } + + #{$block}_size_m & { + @include text-subheader-2(); + } + + #{$block}_size_l & { + @include text-subheader-3(); + } + + #{$block}_size_promo & { + @include text-header-1(); + } + } + + &__actions { + margin-block-start: $normalOffset; + display: flex; + flex-direction: row; + } + + &_direction_row { + &#{$block}_size_s { + @include container-row-sizes( + $containerSmallRowSize, + $imageSmallSize, + $contentHeightSmallSize, + $normalOffset + ); + } + + &#{$block}_size_m { + @include container-row-sizes( + $containerMediumRowSize, + $imageMediumSize, + $contentHeightMediumSize, + $mediumOffset + ); + } + + &#{$block}_size_l { + @include container-row-sizes( + $containerLargeRowSize, + $imageLargeSize, + $contentHeightLargeSize, + $bigOffset + ); + } + + &#{$block}_size_promo { + @include container-row-sizes($containerLargeRowSize, $imageLargeSize, none, $bigOffset); + } + } + + &_direction_column { + #{$block}__body { + flex-direction: column; + } + + #{$block}__content { + margin-block-start: $normalOffset; + align-items: center; + text-align: center; + flex-shrink: 0; + } + + #{$block}__image { + flex-shrink: 0; + } + + &#{$block}_size_s { + @include container-column-sizes($containerSmallColSize, $imageSmallSize); + } + + &#{$block}_size_m { + @include container-column-sizes($containerMediumColSize, $imageMediumSize); + } + + &#{$block}_size_l { + @include container-column-sizes($containerLargeColSize, $imageLargeSize); + } + + &#{$block}_size_promo { + padding: $normalOffset; + + @include container-column-sizes($containerLargeColSize, $imageLargeSize); + + #{$block}__body { + width: 100%; + } + } + } + + &__action { + margin-inline-end: $normalOffset; + } + + &__action:last-child { + margin-inline-end: 0; + } +} diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx new file mode 100644 index 0000000000..8f018f166c --- /dev/null +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -0,0 +1,124 @@ +import React from 'react'; + +import {block} from '../utils/cn'; + +import {PlaceholderContainerAction} from './PlaceholderContainerAction'; +import {Align, Direction, componentClassName} from './constants'; +import type { + PlaceholderContainerDefaultProps, + PlaceholderContainerImageSettingsProps, + PlaceholderContainerInnerProps, + PlaceholderContainerState, +} from './types'; + +import './PlaceholderContainer.scss'; + +const b = block(componentClassName); + +export class PlaceholderContainer extends React.Component< + PlaceholderContainerInnerProps, + PlaceholderContainerState +> { + static Direction = Direction; + static Align = Align; + + static defaultProps: PlaceholderContainerDefaultProps = { + size: 'l', + direction: Direction.Row, + align: Align.Center, + }; + + render() { + const {direction, align, size} = this.props; + const className: string = this.props.className || b(); + + return ( +
+
+
{this.renderImage()}
+ {this.renderContent()} +
+
+ ); + } + + private renderImage(): NonNullable { + if (typeof this.props.image === 'object' && 'url' in this.props.image) { + const image: PlaceholderContainerImageSettingsProps = this.props.image; + return {image.alt; + } + + return this.props.image; + } + + private renderContent() { + const {size} = this.props; + const content = this.props.renderContent ? ( + this.props.renderContent() + ) : ( + + {this.renderTitle()} + {this.renderDescription()} + + ); + + return ( +
+ {content} + {this.renderAction()} +
+ ); + } + + private renderTitle() { + const {title} = this.props; + + if (!title) { + return null; + } + + return
{title}
; + } + + private renderDescription() { + const {description} = this.props; + + if (!description) { + return null; + } + + return
{description}
; + } + + private renderAction() { + const {action, renderAction} = this.props; + + if (renderAction) { + return renderAction(); + } + + if (!action) { + return null; + } + + if (Array.isArray(action)) { + if (!action.length) { + return null; + } + + return ( +
+ {action.map((actionItem) => ( + + ))} +
+ ); + } + + return ( +
+ +
+ ); + } +} diff --git a/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx b/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx new file mode 100644 index 0000000000..f3c8288ff3 --- /dev/null +++ b/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx @@ -0,0 +1,45 @@ +import React from 'react'; + +import type {ButtonSize, ButtonView} from '../Button'; +import {Button} from '../Button'; +import {block} from '../utils/cn'; + +import {componentClassName} from './constants'; + +import './PlaceholderContainer.scss'; + +const b = block(componentClassName); + +export interface Action { + text: string; + loading?: boolean; + disabled?: boolean; + view?: ButtonView; + size?: ButtonSize; + handler?: (event: React.MouseEvent) => void; + href?: string; +} + +interface PlaceholderContainerActionProps { + action: Action; +} + +export const PlaceholderContainerAction = ({action}: PlaceholderContainerActionProps) => { + const {text, handler, loading, disabled, view = 'normal', size = 'm', href} = action; + + return ( +
+ +
+ ); +}; diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx new file mode 100644 index 0000000000..3be85d1478 --- /dev/null +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import type {Meta, StoryFn} from '@storybook/react'; + +import {PlaceholderContainer} from '../PlaceholderContainer'; + +import {PlaceholderContainerShowcase} from './PlaceholderContainerShowcase'; + +export default { + title: 'Components/PlaceholderContainer', + component: PlaceholderContainer, + parameters: { + a11y: { + element: '#storybook-root', + config: { + rules: [ + { + id: 'color-contrast', + enabled: false, + }, + ], + }, + }, + }, +} as Meta; + +const ShowcaseTemplate: StoryFn = () => ; +export const Showcase = ShowcaseTemplate.bind({}); diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss new file mode 100644 index 0000000000..c62c04d4bf --- /dev/null +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss @@ -0,0 +1,37 @@ +@import '../../variables'; + +$block: '.#{$ns}placeholder-container-showcase'; + +#{$block} { + display: grid; + + &__placeholder-examples { + grid-area: auto; + display: grid; + grid-template: 'title' auto; + gap: 20px; + padding: 20px; + } + + &__section + &__section { + border-block-start: 1px solid var(--g-color-text-hint); + } + + &__examples-row { + display: grid; + grid-template-columns: 1fr 1fr; + + &__sub-title { + grid-area: subtitle; + } + } + + &__title { + grid-area: title; + margin: 0; + } + + &__custom-action { + margin-block-start: 20px; + } +} diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx new file mode 100644 index 0000000000..1003f150ba --- /dev/null +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx @@ -0,0 +1,238 @@ +import React from 'react'; + +import {ChevronDown} from '@gravity-ui/icons'; + +import {Button} from '../../Button'; +import {DropdownMenu} from '../../DropdownMenu'; +import {Icon} from '../../Icon'; +import {block} from '../../utils/cn'; +import type {Action} from '../PlaceholderContainerAction'; +import type {PlaceholderContainerProps} from '../index'; +import {PlaceholderContainer} from '../index'; + +import './PlaceholderContainerShowcase.scss'; + +const b = block('placeholder-container-showcase'); + +const ImageComponentTest = () => { + return ( + + + + + 1:1 + + + + ); +}; + +const ContentComponentTest = () => { + return ( +
+

There is any custom title here

+

+ You can add here any long text with custom content and use custom + content size for displaying very long texts. +

+
+ ); +}; + +const ActionComponentTest = () => { + return ( +
+ {}}, + {text: 'text 2', action: () => {}}, + ]} + onSwitcherClick={(e) => e?.stopPropagation()} + switcher={ + + } + /> +
+ ); +}; + +const actionMainProps: Action = { + text: 'Main button', + view: 'normal', + handler: () => alert('Click by main button'), +}; + +const actionAdditionalBtnProps: Action = { + text: 'Additional button', + view: 'flat-secondary', + handler: () => alert('Click by additional button'), +}; + +const baseProps = { + title: 'Container with one button & image component', + image: , + className: 'placeholder-container', +}; + +const placeholderContainerProps: PlaceholderContainerProps = { + ...baseProps, + action: { + ...actionMainProps, + }, + align: 'center', +}; + +const actionsProps = { + action: [actionMainProps, actionAdditionalBtnProps], +}; + +const placeholderContainerCustomRenderedProps: PlaceholderContainerProps = { + ...placeholderContainerProps, + renderContent: () => , +}; + +const placeholderContainerCustomActionProps: PlaceholderContainerProps = { + ...placeholderContainerProps, + renderAction: () => , +}; + +const descriptionProps = { + description: + 'Some long descriptionProps text that can contain of long long very long text etc. It can be repeated like this. Some long descriptionProps text that can contain of long long very long text etc.', +}; + +const imageProps = { + url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEFklEQVR4nO2Y6U4iQRSF5/3fwAX3aGKMonHBHVFxxy3unmfpyalYpGlAZeJ4Sjw/btIWt6Tq+27dbvoPgMyBZBj8US/AAQtBwoXgEwK9BAuBHryFQA/bQqAHbCHQQ7UQ6EFaCPTwLAR6YBYCPSQLgR6MhSQAAwmEX51AL8FCoAdvIdDDthDoAVsI9FAtBHqQFgI9PAuBHpiFQA/JQqAHYyEJwEAC4Vcn0EuwEOjBWwj0sC0EesAWAj1UC4EepIVAD89CoAdmIdBDshDowVhIAjCQQPjVCfQSLAR68BYCPWwLgR6whUAP1UKgB2kh0MOzEOiB/SghNzc32fb2dnZ1ddX22evra3Z4eJhtbGxke3t72cPDQ1vO/f19Vq1WQ069Xg9z/sem7+7uwjovLi46rvP4+DisgWthbjHn8fExq9VqIefg4CB7fn5OT8jp6WlWKpWygYGBALy4genp6fBZDOY2Go1mDq9Lb/NjzMzMZE9PT18qg98zOjoa/v/m5mbLZwQ7Ozvbsobh4eGwt3zRxfkxpqamQjElI4QCBgcHmwssClleXg7ja2trAfDR0VHIn5iYCBXJGB8fz4aGhkJ1Moe5nLOysvJlMnjqCDiusyiEFc/xpaWlsIazs7OQPzIy0iyMWFjxZGxtbYW/FxYW0hDC9sQFcaGVSqVNyMvLS3NTvI7j5XI55J6cnITgdblcbpnHOZybnxeDc+bm5lraBdvI4uJix1bH1sMimJycbEIsChkbGws5PNFxbHV1NeTu7+8398pTlJ/HwuK8Tm1YckIIh2B2d3fbhFxeXoYxwsvPYX/mOKsyVma1Wm3J4RyO838UvzO2OMLhd1MGcwmw2zpZ8ax03suKQigsFlbxVHGcp5z7imvO5/BExeJKQkiMTkJi9XPR3TbKtsTrer3e00ajFPbwj2Tko5OQboVzfn4exufn50N+p8KJnYFF8auFAMjW19dDDtvNZ592frWQz7Ssbhude6dlMWKb4r0n377+RcivaVkf3dT5SMno9aZeK9wziveUXoV8dFPnU9WPuam/J+Szj728HurhsZd5bBX5MUrhd330g7KbkL547M0f2WJw0d1+GHKT3/3DsPLW64uxs7PTXz8MeeNjCynG7e1tUq9OGo1Gx3VeX1/336sTBywEfVgIPiHQS7AQ6MFbCPSwLQR6wBYCPVQLgR6khUAPz0KgB2Yh0EOyEOjBWEgCMJBA+NUJ9BIsBHrwFgI9bAuBHrCFQA/VQqAHaSHQw7MQ6IFZCPSQLAR6MBaSAAwkEH51Ar0EC4EevIVAD9tCoAdsIdBDtRDoQVoI9PAsBHpgFgI9JAuBHoyFJAADCYRfnUAvwUKgB28h0MO2EOgBWwj0UC0EepAWAj08C4EemIVAD+k7hfwFjRtJ9Zn/PDYAAAAASUVORK5CYII=', + alt: 'image alt text', +}; + +export const PlaceholderContainerShowcase = () => { + return ( +
+
+

PlaceholderContainer

+
+

Sizes:

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+

With buttons:

+ +
+
+

With image props:

+ +
+
+

Custom content:

+ +
+
+

Custom action:

+ +
+
+
+ ); +}; diff --git a/src/components/PlaceholderContainer/constants.ts b/src/components/PlaceholderContainer/constants.ts new file mode 100644 index 0000000000..ee6e721995 --- /dev/null +++ b/src/components/PlaceholderContainer/constants.ts @@ -0,0 +1,11 @@ +export const componentClassName = 'placeholder-container'; + +export const Direction = { + Row: 'row', + Column: 'column', +} as const; + +export const Align = { + Left: 'left', + Center: 'center', +} as const; diff --git a/src/components/PlaceholderContainer/index.ts b/src/components/PlaceholderContainer/index.ts new file mode 100644 index 0000000000..3fa2c4a1d0 --- /dev/null +++ b/src/components/PlaceholderContainer/index.ts @@ -0,0 +1,6 @@ +export * from './PlaceholderContainer'; +export * from './types'; +export { + Direction as PlaceholderContainerDirection, + Align as PlaceholderContainerAlign, +} from './constants'; diff --git a/src/components/PlaceholderContainer/types.ts b/src/components/PlaceholderContainer/types.ts new file mode 100644 index 0000000000..6474befe00 --- /dev/null +++ b/src/components/PlaceholderContainer/types.ts @@ -0,0 +1,38 @@ +import type React from 'react'; + +import type {Action} from './PlaceholderContainerAction'; +import type {Align, Direction} from './constants'; + +type Size = 's' | 'm' | 'l' | 'promo'; + +type PlaceholderContainerImageNodeProps = NonNullable; + +export type PlaceholderContainerImageSettingsProps = { + url: string; + alt?: string; +}; + +interface PlaceholderContainerGeneralProps { + title?: string; + description?: React.ReactNode; + renderContent?: () => React.ReactNode; + action?: Action | Action[]; + renderAction?: () => React.ReactNode; + className?: string; + image: PlaceholderContainerImageNodeProps | PlaceholderContainerImageSettingsProps; +} + +export interface PlaceholderContainerDefaultProps { + size: Size; + direction: (typeof Direction)[keyof typeof Direction]; + align: (typeof Align)[keyof typeof Align]; +} + +export type PlaceholderContainerInnerProps = PlaceholderContainerGeneralProps & + PlaceholderContainerDefaultProps; + +export interface PlaceholderContainerProps + extends PlaceholderContainerGeneralProps, + Partial {} + +export interface PlaceholderContainerState {} diff --git a/src/components/variables.scss b/src/components/variables.scss index e7fd20e983..06ca1d3d1f 100644 --- a/src/components/variables.scss +++ b/src/components/variables.scss @@ -10,3 +10,16 @@ $button-shrink-transition: transform 0.1s ease-out; $button-shrink-transform: scale(0.96); $modal-default-margin: 20px; + +// Sizes +$tinyOffset: 5px; +$inlineOffset: 12px; +$regularOffset: 16px; +$normalOffset: 20px; +$mediumOffset: 30px; +$bigOffset: 40px; +$doubleInlineOffset: $inlineOffset * 2; +$doubleRegularOffset: $regularOffset * 2; +$smallOffset: calc(#{$normalOffset} * 0.5); +$microOffset: calc(#{$regularOffset} * 0.5); +$nanoOffset: calc(#{$microOffset} * 0.5); From ee1ff72344ceb71d94928376d241461a6eee0397 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 13 Aug 2024 13:08:34 +0300 Subject: [PATCH 02/15] fix(PlaceholderContainer): move story to folder --- .../__stories__/PlaceholderContainer.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx index 3be85d1478..acf4e5147b 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx @@ -7,7 +7,7 @@ import {PlaceholderContainer} from '../PlaceholderContainer'; import {PlaceholderContainerShowcase} from './PlaceholderContainerShowcase'; export default { - title: 'Components/PlaceholderContainer', + title: 'Components/Data Display/PlaceholderContainer', component: PlaceholderContainer, parameters: { a11y: { From 00f3d5de88e1e5108f71c1d6c457d084164b5918 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 13 Aug 2024 13:10:46 +0300 Subject: [PATCH 03/15] fix(PlaceholderContainer): change custom style vars to spacings --- .../PlaceholderContainer/PlaceholderContainer.scss | 10 +++++++--- src/components/variables.scss | 13 ------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.scss b/src/components/PlaceholderContainer/PlaceholderContainer.scss index 741b1be4d3..a68fbb4103 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.scss +++ b/src/components/PlaceholderContainer/PlaceholderContainer.scss @@ -17,6 +17,10 @@ $containerSmallColSize: 320px; $containerMediumColSize: 320px; $containerLargeColSize: 430px; +$normalOffset: var(--g-spacing-5); +$mediumOffset: var(--g-spacing-7); +$bigOffset: var(--g-spacing-10); + $block: '.#{$ns}placeholder-container'; @mixin container-row-sizes($bodyWidth, $imageSize, $contentHeight, $contentOffset) { @@ -78,7 +82,7 @@ $block: '.#{$ns}placeholder-container'; padding: $normalOffset; #{$block}__description { - margin-block-start: $nanoOffset; + margin-block-start: var(--g-spacing-1); } } @@ -86,14 +90,14 @@ $block: '.#{$ns}placeholder-container'; padding: $mediumOffset; #{$block}__description { - margin-block-start: $microOffset; + margin-block-start: var(--g-spacing-2); } } &_size_promo, &_size_l { #{$block}__description { - margin-block-start: $smallOffset; + margin-block-start: var(--g-spacing-3); } } diff --git a/src/components/variables.scss b/src/components/variables.scss index 06ca1d3d1f..e7fd20e983 100644 --- a/src/components/variables.scss +++ b/src/components/variables.scss @@ -10,16 +10,3 @@ $button-shrink-transition: transform 0.1s ease-out; $button-shrink-transform: scale(0.96); $modal-default-margin: 20px; - -// Sizes -$tinyOffset: 5px; -$inlineOffset: 12px; -$regularOffset: 16px; -$normalOffset: 20px; -$mediumOffset: 30px; -$bigOffset: 40px; -$doubleInlineOffset: $inlineOffset * 2; -$doubleRegularOffset: $regularOffset * 2; -$smallOffset: calc(#{$normalOffset} * 0.5); -$microOffset: calc(#{$regularOffset} * 0.5); -$nanoOffset: calc(#{$microOffset} * 0.5); From a6133e4d692e8ad6cd64054cf565934ef786df07 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 13 Aug 2024 13:12:03 +0300 Subject: [PATCH 04/15] chore(PlaceholderContainer): add PlaceholderContainer codeowner --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 55e3a6e5d4..bac006d50e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -27,6 +27,7 @@ /src/components/Pagination @jhoncool /src/components/Palette @Ruminat /src/components/PinInput @amje +/src/components/PlaceholderContainer @Marginy605 /src/components/Popover @kseniya57 /src/components/Popup @amje /src/components/Portal @amje From 3d678307d9fb8fd8e6729c1178aeaa3c68e45d49 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 13 Aug 2024 18:03:01 +0300 Subject: [PATCH 05/15] chore(PlaceholderContainer): add Readme and doc info --- src/components/PlaceholderContainer/README.md | 267 ++++++++++++++++++ .../PlaceholderContainer/__stories__/Docs.mdx | 7 + 2 files changed, 274 insertions(+) create mode 100644 src/components/PlaceholderContainer/README.md create mode 100644 src/components/PlaceholderContainer/__stories__/Docs.mdx diff --git a/src/components/PlaceholderContainer/README.md b/src/components/PlaceholderContainer/README.md new file mode 100644 index 0000000000..687638e228 --- /dev/null +++ b/src/components/PlaceholderContainer/README.md @@ -0,0 +1,267 @@ + + +# PlaceholderContainer + + + +`PlaceholderContainer` is a component for displaying content with image, text content and action controls. + +## Direction + +The component has `row` and `column` directions of the content layout. To control it use the `direction` property. The default size is `row`. + +## Size + +To control the size of the `PlaceholderContainer` use the `size` property. The default size is `l`. Possible values: `s`, `m`, `l`, `promo`. The `promo` value sets full width of the content block and a larger title size. + +## Action controls + +The component can render button control or array of buttons. To display it use `action` property. + + + +```tsx + ( + + + + + 1:1 + + + + )} + action={{ + text: 'Main button', + view: 'normal', + handler: () => console.log('Click by main button'), + }} +/> +``` + + + +with array of buttons + + + +```tsx + ( + + + + + 1:1 + + + + )} + action={[ + { + text: 'Main button', + view: 'normal', + handler: () => console.log('Click by main button'), + }, + { + text: 'Additional button', + view: 'flat-secondary', + handler: () => console.log('Click by additional button'), + }, + ]} +/> +``` + + + +To render custom controls use `renderAction` property. + + + +```tsx + ( + + + + + 1:1 + + + + )} + renderAction={() => ( + console.log()}, + {text: 'text 2', action: () => console.log()}, + ]} + onSwitcherClick={(e) => console.log(e)} + switcher={ + + } + /> + )} +/> +``` + + + +## Image and content + +The property `image` allows to set up image `url` and `alt` settings or react node. + + + +```tsx + ( + + + + + 1:1 + + + + )} +/> +``` + +with url and alt settings + +```tsx + +``` + + + +The content of component contains from title and description blocks that can be set by the same properties names. To render custom content use `renderContent` property. + +```tsx + ( + + + + + 1:1 + + + + )} + renderContent={() => ( +
+

There is any custom title here

+

+ You can add here any long text with custom content and use custom content + size for displaying very long texts. +

+
+ )} +/> +``` + +## Align + +To control alignment of content inside parent container use `align` property. The default value is `center`. + +## Properties + +| Name | Description | Type | Default | +| :------------ | :---------------------------------------------------------------------------------- | :-----------------------------------------------------------------------------------: | :--------: | --- | +| className | Optional HTML `class` attribute | `string` | | +| direction | Used to set the direction of content layout, possible values: `"row"` or `"column"` | `string` | `"row"` | +| size | Size of component, possible values: `"s"`, `"m"`, `"l"` or `"promo"` | `string` | `"l"` | +| align | Used to set content horizontal align, possible values: `"center"` or `"left"` | `string` | `"center"` | +| title | Content title text | `string` | | +| description | Content description text | `string` | | +| image | Used to set image by src url or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageSettingsProps` | | +| renderContent | Used to render node instead of content (title, description and actions) | `string` | | +| action | Used to render button control node or array of button controls | `Action \ | Action[]` | | +| renderAction | Used to render node instead of default action | `string` | | diff --git a/src/components/PlaceholderContainer/__stories__/Docs.mdx b/src/components/PlaceholderContainer/__stories__/Docs.mdx new file mode 100644 index 0000000000..8a02df5a2f --- /dev/null +++ b/src/components/PlaceholderContainer/__stories__/Docs.mdx @@ -0,0 +1,7 @@ +import {Meta, Markdown} from '@storybook/addon-docs'; +import * as Stories from './PlaceholderContainer.stories'; +import Readme from '../README.md?raw'; + + + +{Readme} From c4a2372f7596deef16119213c574b0828b458f4b Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 20 Aug 2024 12:51:53 +0300 Subject: [PATCH 06/15] fix(PlaceholderContainer): improve typings and clear constants --- .../PlaceholderContainer.tsx | 17 ++++++------- .../PlaceholderContainerAction.tsx | 12 ++++------ src/components/PlaceholderContainer/README.md | 24 +++++++++---------- .../PlaceholderContainer/constants.ts | 10 -------- src/components/PlaceholderContainer/index.ts | 4 ---- src/components/PlaceholderContainer/types.ts | 13 +++++----- 6 files changed, 29 insertions(+), 51 deletions(-) diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index 8f018f166c..0e1430e593 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -3,10 +3,10 @@ import React from 'react'; import {block} from '../utils/cn'; import {PlaceholderContainerAction} from './PlaceholderContainerAction'; -import {Align, Direction, componentClassName} from './constants'; +import {componentClassName} from './constants'; import type { PlaceholderContainerDefaultProps, - PlaceholderContainerImageSettingsProps, + PlaceholderContainerImageProps, PlaceholderContainerInnerProps, PlaceholderContainerState, } from './types'; @@ -19,13 +19,10 @@ export class PlaceholderContainer extends React.Component< PlaceholderContainerInnerProps, PlaceholderContainerState > { - static Direction = Direction; - static Align = Align; - static defaultProps: PlaceholderContainerDefaultProps = { size: 'l', - direction: Direction.Row, - align: Align.Center, + direction: 'row', + align: 'center', }; render() { @@ -44,7 +41,7 @@ export class PlaceholderContainer extends React.Component< private renderImage(): NonNullable { if (typeof this.props.image === 'object' && 'url' in this.props.image) { - const image: PlaceholderContainerImageSettingsProps = this.props.image; + const image: PlaceholderContainerImageProps = this.props.image; return {image.alt; } @@ -109,7 +106,7 @@ export class PlaceholderContainer extends React.Component< return (
{action.map((actionItem) => ( - + ))}
); @@ -117,7 +114,7 @@ export class PlaceholderContainer extends React.Component< return (
- +
); } diff --git a/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx b/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx index f3c8288ff3..b89a7e29ad 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx @@ -10,7 +10,7 @@ import './PlaceholderContainer.scss'; const b = block(componentClassName); -export interface Action { +export type PlaceholderContainerActionProps = { text: string; loading?: boolean; disabled?: boolean; @@ -18,14 +18,10 @@ export interface Action { size?: ButtonSize; handler?: (event: React.MouseEvent) => void; href?: string; -} - -interface PlaceholderContainerActionProps { - action: Action; -} +}; -export const PlaceholderContainerAction = ({action}: PlaceholderContainerActionProps) => { - const {text, handler, loading, disabled, view = 'normal', size = 'm', href} = action; +export const PlaceholderContainerAction = (props: PlaceholderContainerActionProps) => { + const {text, handler, loading, disabled, view = 'normal', size = 'm', href} = props; return (
diff --git a/src/components/PlaceholderContainer/README.md b/src/components/PlaceholderContainer/README.md index 687638e228..b5cafcb97b 100644 --- a/src/components/PlaceholderContainer/README.md +++ b/src/components/PlaceholderContainer/README.md @@ -253,15 +253,15 @@ To control alignment of content inside parent container use `align` property. Th ## Properties -| Name | Description | Type | Default | -| :------------ | :---------------------------------------------------------------------------------- | :-----------------------------------------------------------------------------------: | :--------: | --- | -| className | Optional HTML `class` attribute | `string` | | -| direction | Used to set the direction of content layout, possible values: `"row"` or `"column"` | `string` | `"row"` | -| size | Size of component, possible values: `"s"`, `"m"`, `"l"` or `"promo"` | `string` | `"l"` | -| align | Used to set content horizontal align, possible values: `"center"` or `"left"` | `string` | `"center"` | -| title | Content title text | `string` | | -| description | Content description text | `string` | | -| image | Used to set image by src url or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageSettingsProps` | | -| renderContent | Used to render node instead of content (title, description and actions) | `string` | | -| action | Used to render button control node or array of button controls | `Action \ | Action[]` | | -| renderAction | Used to render node instead of default action | `string` | | +| Name | Description | Type | Default | +| :------------ | :---------------------------------------------------------------------------------- | :---------------------------------------------------------------------------: | :--------: | +| className | Optional HTML `class` attribute | `string` | | +| direction | Used to set the direction of content layout, possible values: `"row"` or `"column"` | `string` | `"row"` | +| size | Size of component, possible values: `"s"`, `"m"`, `"l"` or `"promo"` | `string` | `"l"` | +| align | Used to set content horizontal align, possible values: `"center"` or `"left"` | `string` | `"center"` | +| title | Content title text | `string` | | +| description | Content description text | `string` | | +| image | Used to set image by src url or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageProps` | | +| renderContent | Used to render node instead of content (title, description and actions) | `string` | | +| action | Used to render button control node or array of button controls | `PlaceholderContainerActionProps`
`\| PlaceholderContainerActionProps[]` | | +| renderAction | Used to render node instead of default action | `string` | | diff --git a/src/components/PlaceholderContainer/constants.ts b/src/components/PlaceholderContainer/constants.ts index ee6e721995..65ffe4dbc9 100644 --- a/src/components/PlaceholderContainer/constants.ts +++ b/src/components/PlaceholderContainer/constants.ts @@ -1,11 +1 @@ export const componentClassName = 'placeholder-container'; - -export const Direction = { - Row: 'row', - Column: 'column', -} as const; - -export const Align = { - Left: 'left', - Center: 'center', -} as const; diff --git a/src/components/PlaceholderContainer/index.ts b/src/components/PlaceholderContainer/index.ts index 3fa2c4a1d0..b7219e682a 100644 --- a/src/components/PlaceholderContainer/index.ts +++ b/src/components/PlaceholderContainer/index.ts @@ -1,6 +1,2 @@ export * from './PlaceholderContainer'; export * from './types'; -export { - Direction as PlaceholderContainerDirection, - Align as PlaceholderContainerAlign, -} from './constants'; diff --git a/src/components/PlaceholderContainer/types.ts b/src/components/PlaceholderContainer/types.ts index 6474befe00..ee7b3d149e 100644 --- a/src/components/PlaceholderContainer/types.ts +++ b/src/components/PlaceholderContainer/types.ts @@ -1,13 +1,12 @@ import type React from 'react'; -import type {Action} from './PlaceholderContainerAction'; -import type {Align, Direction} from './constants'; +import type {PlaceholderContainerActionProps} from './PlaceholderContainerAction'; type Size = 's' | 'm' | 'l' | 'promo'; type PlaceholderContainerImageNodeProps = NonNullable; -export type PlaceholderContainerImageSettingsProps = { +export type PlaceholderContainerImageProps = { url: string; alt?: string; }; @@ -16,16 +15,16 @@ interface PlaceholderContainerGeneralProps { title?: string; description?: React.ReactNode; renderContent?: () => React.ReactNode; - action?: Action | Action[]; + action?: PlaceholderContainerActionProps | PlaceholderContainerActionProps[]; renderAction?: () => React.ReactNode; className?: string; - image: PlaceholderContainerImageNodeProps | PlaceholderContainerImageSettingsProps; + image: PlaceholderContainerImageNodeProps | PlaceholderContainerImageProps; } export interface PlaceholderContainerDefaultProps { size: Size; - direction: (typeof Direction)[keyof typeof Direction]; - align: (typeof Align)[keyof typeof Align]; + direction: 'row' | 'column'; + align: 'left' | 'center'; } export type PlaceholderContainerInnerProps = PlaceholderContainerGeneralProps & From 7440d3384af701baa7e1f49a0c67f667ec18cbf9 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 20 Aug 2024 14:22:10 +0300 Subject: [PATCH 07/15] fix(PlaceholderContainer): refactor class component to functional --- .../PlaceholderContainer.tsx | 145 +++++++++--------- .../PlaceholderContainerAction.tsx | 41 ----- .../PlaceholderContainerShowcase.tsx | 11 +- src/components/PlaceholderContainer/types.ts | 29 ++-- 4 files changed, 90 insertions(+), 136 deletions(-) delete mode 100644 src/components/PlaceholderContainer/PlaceholderContainerAction.tsx diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index 0e1430e593..7f898d6e4d 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -1,95 +1,69 @@ import React from 'react'; +import {Button} from '../Button'; import {block} from '../utils/cn'; -import {PlaceholderContainerAction} from './PlaceholderContainerAction'; import {componentClassName} from './constants'; -import type { - PlaceholderContainerDefaultProps, - PlaceholderContainerImageProps, - PlaceholderContainerInnerProps, - PlaceholderContainerState, -} from './types'; +import type {PlaceholderContainerActionProps, PlaceholderContainerProps} from './types'; import './PlaceholderContainer.scss'; const b = block(componentClassName); -export class PlaceholderContainer extends React.Component< - PlaceholderContainerInnerProps, - PlaceholderContainerState -> { - static defaultProps: PlaceholderContainerDefaultProps = { - size: 'l', - direction: 'row', - align: 'center', - }; - - render() { - const {direction, align, size} = this.props; - const className: string = this.props.className || b(); - - return ( -
-
-
{this.renderImage()}
- {this.renderContent()} -
-
- ); - } - - private renderImage(): NonNullable { - if (typeof this.props.image === 'object' && 'url' in this.props.image) { - const image: PlaceholderContainerImageProps = this.props.image; - return {image.alt; - } - - return this.props.image; - } - - private renderContent() { - const {size} = this.props; - const content = this.props.renderContent ? ( - this.props.renderContent() - ) : ( - - {this.renderTitle()} - {this.renderDescription()} - - ); - - return ( -
- {content} - {this.renderAction()} -
- ); - } - - private renderTitle() { - const {title} = this.props; - +const PlaceholderContainerAction = (props: PlaceholderContainerActionProps) => { + return ( +
+ +
+ ); +}; + +export const PlaceholderContainer = ({ + direction = 'row', + align = 'center', + size = 'l', + className = b(), + title, + description, + image, + renderContent, + action, + renderAction, +}: PlaceholderContainerProps) => { + const renderTitle = () => { if (!title) { return null; } return
{title}
; - } - - private renderDescription() { - const {description} = this.props; - + }; + const renderDescription = () => { if (!description) { return null; } return
{description}
; - } + }; + + const renderImage = (): NonNullable => { + if (typeof image === 'object' && 'url' in image) { + return {image.alt; + } - private renderAction() { - const {action, renderAction} = this.props; + return image; + }; + const renderActionFn = () => { if (renderAction) { return renderAction(); } @@ -117,5 +91,32 @@ export class PlaceholderContainer extends React.Component<
); - } -} + }; + + const renderContentFn = () => { + const content = renderContent ? ( + renderContent() + ) : ( + + {renderTitle()} + {renderDescription()} + + ); + + return ( +
+ {content} + {renderActionFn()} +
+ ); + }; + + return ( +
+
+
{renderImage()}
+ {renderContentFn()} +
+
+ ); +}; diff --git a/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx b/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx deleted file mode 100644 index b89a7e29ad..0000000000 --- a/src/components/PlaceholderContainer/PlaceholderContainerAction.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; - -import type {ButtonSize, ButtonView} from '../Button'; -import {Button} from '../Button'; -import {block} from '../utils/cn'; - -import {componentClassName} from './constants'; - -import './PlaceholderContainer.scss'; - -const b = block(componentClassName); - -export type PlaceholderContainerActionProps = { - text: string; - loading?: boolean; - disabled?: boolean; - view?: ButtonView; - size?: ButtonSize; - handler?: (event: React.MouseEvent) => void; - href?: string; -}; - -export const PlaceholderContainerAction = (props: PlaceholderContainerActionProps) => { - const {text, handler, loading, disabled, view = 'normal', size = 'm', href} = props; - - return ( -
- -
- ); -}; diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx index 1003f150ba..abb37ab99e 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx @@ -6,8 +6,7 @@ import {Button} from '../../Button'; import {DropdownMenu} from '../../DropdownMenu'; import {Icon} from '../../Icon'; import {block} from '../../utils/cn'; -import type {Action} from '../PlaceholderContainerAction'; -import type {PlaceholderContainerProps} from '../index'; +import type {PlaceholderContainerActionProps, PlaceholderContainerProps} from '../index'; import {PlaceholderContainer} from '../index'; import './PlaceholderContainerShowcase.scss'; @@ -69,16 +68,16 @@ const ActionComponentTest = () => { ); }; -const actionMainProps: Action = { +const actionMainProps: PlaceholderContainerActionProps = { text: 'Main button', view: 'normal', - handler: () => alert('Click by main button'), + onClick: () => alert('Click by main button'), }; -const actionAdditionalBtnProps: Action = { +const actionAdditionalBtnProps: PlaceholderContainerActionProps = { text: 'Additional button', view: 'flat-secondary', - handler: () => alert('Click by additional button'), + onClick: () => alert('Click by additional button'), }; const baseProps = { diff --git a/src/components/PlaceholderContainer/types.ts b/src/components/PlaceholderContainer/types.ts index ee7b3d149e..de56e2a303 100644 --- a/src/components/PlaceholderContainer/types.ts +++ b/src/components/PlaceholderContainer/types.ts @@ -1,6 +1,6 @@ import type React from 'react'; -import type {PlaceholderContainerActionProps} from './PlaceholderContainerAction'; +import type {ButtonProps} from '../Button'; type Size = 's' | 'm' | 'l' | 'promo'; @@ -11,7 +11,17 @@ export type PlaceholderContainerImageProps = { alt?: string; }; -interface PlaceholderContainerGeneralProps { +export type PlaceholderContainerActionProps = Pick< + ButtonProps, + 'disabled' | 'loading' | 'view' | 'size' | 'href' | 'onClick' +> & { + text: string; +}; + +export interface PlaceholderContainerProps { + size: Size; + direction: 'row' | 'column'; + align: 'left' | 'center'; title?: string; description?: React.ReactNode; renderContent?: () => React.ReactNode; @@ -20,18 +30,3 @@ interface PlaceholderContainerGeneralProps { className?: string; image: PlaceholderContainerImageNodeProps | PlaceholderContainerImageProps; } - -export interface PlaceholderContainerDefaultProps { - size: Size; - direction: 'row' | 'column'; - align: 'left' | 'center'; -} - -export type PlaceholderContainerInnerProps = PlaceholderContainerGeneralProps & - PlaceholderContainerDefaultProps; - -export interface PlaceholderContainerProps - extends PlaceholderContainerGeneralProps, - Partial {} - -export interface PlaceholderContainerState {} From d702ffd0b676f57ddb3345c222a305ae7a88d6fa Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 20 Aug 2024 16:52:45 +0300 Subject: [PATCH 08/15] fix(PlaceholderContainer): refactor action and renderAction props --- .../PlaceholderContainer.tsx | 31 +++------- src/components/PlaceholderContainer/README.md | 60 +++---------------- .../PlaceholderContainerShowcase.tsx | 46 +++++++------- src/components/PlaceholderContainer/types.ts | 3 +- 4 files changed, 38 insertions(+), 102 deletions(-) diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index 7f898d6e4d..f94c56a2fe 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -37,8 +37,7 @@ export const PlaceholderContainer = ({ description, image, renderContent, - action, - renderAction, + actions, }: PlaceholderContainerProps) => { const renderTitle = () => { if (!title) { @@ -63,32 +62,20 @@ export const PlaceholderContainer = ({ return image; }; - const renderActionFn = () => { - if (renderAction) { - return renderAction(); - } - - if (!action) { + const renderAction = () => { + if (!actions || (!React.isValidElement(actions) && !actions.length)) { return null; } - if (Array.isArray(action)) { - if (!action.length) { - return null; - } - - return ( -
- {action.map((actionItem) => ( - - ))} -
- ); + if (React.isValidElement(actions)) { + return {actions}; } return (
- + {actions.map((actionItem) => ( + + ))}
); }; @@ -106,7 +93,7 @@ export const PlaceholderContainer = ({ return (
{content} - {renderActionFn()} + {renderAction()}
); }; diff --git a/src/components/PlaceholderContainer/README.md b/src/components/PlaceholderContainer/README.md index b5cafcb97b..8802e7e65b 100644 --- a/src/components/PlaceholderContainer/README.md +++ b/src/components/PlaceholderContainer/README.md @@ -16,7 +16,7 @@ To control the size of the `PlaceholderContainer` use the `size` property. The d ## Action controls -The component can render button control or array of buttons. To display it use `action` property. +The component can render button control or array of buttons. To display it use `actions` property. @@ -46,56 +46,11 @@ The component can render button control or array of buttons. To display it use ` )} - action={{ - text: 'Main button', - view: 'normal', - handler: () => console.log('Click by main button'), - }} -/> -``` - - - -with array of buttons - - - -```tsx - ( - - - - - 1:1 - - - - )} - action={[ + actions={[ { text: 'Main button', view: 'normal', - handler: () => console.log('Click by main button'), - }, - { - text: 'Additional button', - view: 'flat-secondary', - handler: () => console.log('Click by additional button'), + onClick: () => console.log('Click by main button'), }, ]} /> @@ -103,7 +58,7 @@ with array of buttons -To render custom controls use `renderAction` property. +It is also possible to render custom controls: @@ -133,7 +88,7 @@ To render custom controls use `renderAction` property. )} - renderAction={() => ( + actions={ } /> - )} + } /> ``` @@ -263,5 +218,4 @@ To control alignment of content inside parent container use `align` property. Th | description | Content description text | `string` | | | image | Used to set image by src url or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageProps` | | | renderContent | Used to render node instead of content (title, description and actions) | `string` | | -| action | Used to render button control node or array of button controls | `PlaceholderContainerActionProps`
`\| PlaceholderContainerActionProps[]` | | -| renderAction | Used to render node instead of default action | `string` | | +| actions | Used to render array of button controls or custom node | `PlaceholderContainerActionProps[]`
`\| React.ReactNode ` | | diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx index abb37ab99e..8e2c519aa2 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx @@ -47,26 +47,24 @@ const ContentComponentTest = () => { ); }; -const ActionComponentTest = () => { - return ( -
- {}}, - {text: 'text 2', action: () => {}}, - ]} - onSwitcherClick={(e) => e?.stopPropagation()} - switcher={ - - } - /> -
- ); -}; +const actionComponentTest = ( +
+ {}}, + {text: 'text 2', action: () => {}}, + ]} + onSwitcherClick={(e) => e?.stopPropagation()} + switcher={ + + } + /> +
+); const actionMainProps: PlaceholderContainerActionProps = { text: 'Main button', @@ -88,14 +86,12 @@ const baseProps = { const placeholderContainerProps: PlaceholderContainerProps = { ...baseProps, - action: { - ...actionMainProps, - }, + actions: [actionMainProps], align: 'center', }; const actionsProps = { - action: [actionMainProps, actionAdditionalBtnProps], + actions: [actionMainProps, actionAdditionalBtnProps], }; const placeholderContainerCustomRenderedProps: PlaceholderContainerProps = { @@ -105,7 +101,7 @@ const placeholderContainerCustomRenderedProps: PlaceholderContainerProps = { const placeholderContainerCustomActionProps: PlaceholderContainerProps = { ...placeholderContainerProps, - renderAction: () => , + actions: actionComponentTest, }; const descriptionProps = { diff --git a/src/components/PlaceholderContainer/types.ts b/src/components/PlaceholderContainer/types.ts index de56e2a303..121e326615 100644 --- a/src/components/PlaceholderContainer/types.ts +++ b/src/components/PlaceholderContainer/types.ts @@ -25,8 +25,7 @@ export interface PlaceholderContainerProps { title?: string; description?: React.ReactNode; renderContent?: () => React.ReactNode; - action?: PlaceholderContainerActionProps | PlaceholderContainerActionProps[]; - renderAction?: () => React.ReactNode; + actions?: PlaceholderContainerActionProps[] | React.ReactNode; className?: string; image: PlaceholderContainerImageNodeProps | PlaceholderContainerImageProps; } From fa2128e4f1cd456a2706683f0de79f71779b7c7c Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 20 Aug 2024 18:11:00 +0300 Subject: [PATCH 09/15] fix(PlaceholderContainer): refactor content prop and fix image samples --- .../PlaceholderContainer.tsx | 12 +++-- src/components/PlaceholderContainer/README.md | 44 +++++++++---------- .../PlaceholderContainerShowcase.tsx | 22 +++++----- src/components/PlaceholderContainer/types.ts | 2 +- 4 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index f94c56a2fe..bbfbc1aa26 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -36,7 +36,7 @@ export const PlaceholderContainer = ({ title, description, image, - renderContent, + content, actions, }: PlaceholderContainerProps) => { const renderTitle = () => { @@ -80,10 +80,8 @@ export const PlaceholderContainer = ({ ); }; - const renderContentFn = () => { - const content = renderContent ? ( - renderContent() - ) : ( + const renderContent = () => { + const contentNode = content || ( {renderTitle()} {renderDescription()} @@ -92,7 +90,7 @@ export const PlaceholderContainer = ({ return (
- {content} + {contentNode} {renderAction()}
); @@ -102,7 +100,7 @@ export const PlaceholderContainer = ({
{renderImage()}
- {renderContentFn()} + {renderContent()}
); diff --git a/src/components/PlaceholderContainer/README.md b/src/components/PlaceholderContainer/README.md index 8802e7e65b..1566b14951 100644 --- a/src/components/PlaceholderContainer/README.md +++ b/src/components/PlaceholderContainer/README.md @@ -27,7 +27,7 @@ The component can render button control or array of buttons. To display it use ` direction="column" size="s" align="center" - image={() => ( + image={ @@ -45,7 +45,7 @@ The component can render button control or array of buttons. To display it use ` - )} + } actions={[ { text: 'Main button', @@ -69,7 +69,7 @@ It is also possible to render custom controls: direction="row" size="s" align="center" - image={() => ( + image={ @@ -87,7 +87,7 @@ It is also possible to render custom controls: - )} + } actions={ ( + image={ @@ -140,7 +140,7 @@ The property `image` allows to set up image `url` and `alt` settings or react no - )} + } /> ``` @@ -162,7 +162,7 @@ with url and alt settings -The content of component contains from title and description blocks that can be set by the same properties names. To render custom content use `renderContent` property. +The content of component contains from title and description blocks that can be set by the same properties names. To render custom content use `content` property. ```tsx ( + image={ @@ -189,8 +189,8 @@ The content of component contains from title and description blocks that can be - )} - renderContent={() => ( + } + content={

There is any custom title here

@@ -198,7 +198,7 @@ The content of component contains from title and description blocks that can be size for displaying very long texts.

- )} + } /> ``` @@ -208,14 +208,14 @@ To control alignment of content inside parent container use `align` property. Th ## Properties -| Name | Description | Type | Default | -| :------------ | :---------------------------------------------------------------------------------- | :---------------------------------------------------------------------------: | :--------: | -| className | Optional HTML `class` attribute | `string` | | -| direction | Used to set the direction of content layout, possible values: `"row"` or `"column"` | `string` | `"row"` | -| size | Size of component, possible values: `"s"`, `"m"`, `"l"` or `"promo"` | `string` | `"l"` | -| align | Used to set content horizontal align, possible values: `"center"` or `"left"` | `string` | `"center"` | -| title | Content title text | `string` | | -| description | Content description text | `string` | | -| image | Used to set image by src url or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageProps` | | -| renderContent | Used to render node instead of content (title, description and actions) | `string` | | -| actions | Used to render array of button controls or custom node | `PlaceholderContainerActionProps[]`
`\| React.ReactNode ` | | +| Name | Description | Type | Default | +| :---------- | :---------------------------------------------------------------------------------- | :---------------------------------------------------------------------------: | :--------: | +| className | Optional HTML `class` attribute | `string` | | +| direction | Used to set the direction of content layout, possible values: `"row"` or `"column"` | `string` | `"row"` | +| size | Size of component, possible values: `"s"`, `"m"`, `"l"` or `"promo"` | `string` | `"l"` | +| align | Used to set content horizontal align, possible values: `"center"` or `"left"` | `string` | `"center"` | +| title | Content title text | `string` | | +| description | Content description text | `string` | | +| image | Used to set image by src url or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageProps` | | +| content | Used to render node instead of content (title, description and actions) | `React.ReactNode` | | +| actions | Used to render array of button controls or custom node | `PlaceholderContainerActionProps[]`
`\| React.ReactNode ` | | diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx index 8e2c519aa2..98d39be0c2 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx @@ -35,17 +35,15 @@ const ImageComponentTest = () => { ); }; -const ContentComponentTest = () => { - return ( -
-

There is any custom title here

-

- You can add here any long text with custom content and use custom - content size for displaying very long texts. -

-
- ); -}; +const contentComponentTest = ( +
+

There is any custom title here

+

+ You can add here any long text with custom content and use custom + content size for displaying very long texts. +

+
+); const actionComponentTest = (
@@ -96,7 +94,7 @@ const actionsProps = { const placeholderContainerCustomRenderedProps: PlaceholderContainerProps = { ...placeholderContainerProps, - renderContent: () => , + content: contentComponentTest, }; const placeholderContainerCustomActionProps: PlaceholderContainerProps = { diff --git a/src/components/PlaceholderContainer/types.ts b/src/components/PlaceholderContainer/types.ts index 121e326615..a573f1b56c 100644 --- a/src/components/PlaceholderContainer/types.ts +++ b/src/components/PlaceholderContainer/types.ts @@ -24,7 +24,7 @@ export interface PlaceholderContainerProps { align: 'left' | 'center'; title?: string; description?: React.ReactNode; - renderContent?: () => React.ReactNode; + content?: React.ReactNode; actions?: PlaceholderContainerActionProps[] | React.ReactNode; className?: string; image: PlaceholderContainerImageNodeProps | PlaceholderContainerImageProps; From a68246c7e122e3315290a2ea4ca37afccc8412cb Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Tue, 20 Aug 2024 19:37:09 +0300 Subject: [PATCH 10/15] chore(PlaceholderContainer): refactor stories --- .../PlaceholderContainer.tsx | 4 +- .../PlaceholderContainer.stories.tsx | 246 +++++++++++++++++- .../PlaceholderContainerShowcase.scss | 28 -- .../PlaceholderContainerShowcase.tsx | 231 ---------------- 4 files changed, 244 insertions(+), 265 deletions(-) delete mode 100644 src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index bbfbc1aa26..b6899a997a 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -63,7 +63,7 @@ export const PlaceholderContainer = ({ }; const renderAction = () => { - if (!actions || (!React.isValidElement(actions) && !actions.length)) { + if (!actions || !React.isValidElement(actions) || !Array.isArray(actions)) { return null; } @@ -73,7 +73,7 @@ export const PlaceholderContainer = ({ return (
- {actions.map((actionItem) => ( + {(actions as PlaceholderContainerActionProps[]).map((actionItem) => ( ))}
diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx index acf4e5147b..d0f8c0706b 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx @@ -1,10 +1,18 @@ import React from 'react'; -import type {Meta, StoryFn} from '@storybook/react'; +import {ChevronDown} from '@gravity-ui/icons'; +import type {Meta, /*StoryFn,*/ StoryObj} from '@storybook/react'; +import {Showcase} from '../../../demo/Showcase'; +import {ShowcaseItem} from '../../../demo/ShowcaseItem'; +import {Button} from '../../Button'; +import {DropdownMenu} from '../../DropdownMenu'; +import {Icon} from '../../Icon'; +import {block} from '../../utils/cn'; import {PlaceholderContainer} from '../PlaceholderContainer'; +import type {PlaceholderContainerActionProps, PlaceholderContainerProps} from '../types'; -import {PlaceholderContainerShowcase} from './PlaceholderContainerShowcase'; +import './PlaceholderContainerShowcase.scss'; export default { title: 'Components/Data Display/PlaceholderContainer', @@ -24,5 +32,235 @@ export default { }, } as Meta; -const ShowcaseTemplate: StoryFn = () => ; -export const Showcase = ShowcaseTemplate.bind({}); +type Story = StoryObj; + +const b = block('placeholder-container-showcase'); + +const ImageComponentTest = () => { + return ( + + + + + 1:1 + + + + ); +}; + +const contentComponentTest = ( +
+

Custom title

+

with custom subtitle

+

and etc

+

+ You can add here any long text with custom content and use custom + content size for displaying very long texts. +

+
+); + +const actionComponentTest = ( +
+ {}}, + {text: 'text 2', action: () => {}}, + ]} + onSwitcherClick={(e) => e?.stopPropagation()} + switcher={ + + } + /> +
+); + +const actionMainProps: PlaceholderContainerActionProps = { + text: 'Main button', + view: 'normal', + onClick: () => alert('Click by main button'), +}; + +const actionAdditionalBtnProps: PlaceholderContainerActionProps = { + text: 'Additional button', + view: 'flat-secondary', + onClick: () => alert('Click by additional button'), +}; + +const baseProps = { + title: 'Container with one button & image component', + image: , + className: 'placeholder-container', +}; + +const placeholderContainerProps: Omit = { + ...baseProps, + actions: [actionMainProps], + align: 'center', +}; + +const actionsProps = { + actions: [actionMainProps, actionAdditionalBtnProps], +}; + +const placeholderContainerCustomRenderedProps: Omit< + PlaceholderContainerProps, + 'size' | 'direction' +> = { + ...placeholderContainerProps, + content: contentComponentTest, +}; + +const placeholderContainerCustomActionProps: Omit = + { + ...placeholderContainerProps, + actions: actionComponentTest, + }; + +const descriptionProps = { + description: + 'Some long descriptionProps text that can contain of long long very long text etc. It can be repeated like this. Some long descriptionProps text that can contain of long long very long text etc.', + promoDescription: + "Comparing to 'L' size promo size has full width of the content block, a larger title size and alignment", +}; + +export const Size: Story = { + render: () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ), +}; + +export const Actions: Story = { + render: () => ( + + + + + + + + + + + + + + ), +}; + +export const Content: Story = { + render: () => ( + + + + + + ), +}; diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss index c62c04d4bf..ee3fe3bea1 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss @@ -3,34 +3,6 @@ $block: '.#{$ns}placeholder-container-showcase'; #{$block} { - display: grid; - - &__placeholder-examples { - grid-area: auto; - display: grid; - grid-template: 'title' auto; - gap: 20px; - padding: 20px; - } - - &__section + &__section { - border-block-start: 1px solid var(--g-color-text-hint); - } - - &__examples-row { - display: grid; - grid-template-columns: 1fr 1fr; - - &__sub-title { - grid-area: subtitle; - } - } - - &__title { - grid-area: title; - margin: 0; - } - &__custom-action { margin-block-start: 20px; } diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx deleted file mode 100644 index 98d39be0c2..0000000000 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.tsx +++ /dev/null @@ -1,231 +0,0 @@ -import React from 'react'; - -import {ChevronDown} from '@gravity-ui/icons'; - -import {Button} from '../../Button'; -import {DropdownMenu} from '../../DropdownMenu'; -import {Icon} from '../../Icon'; -import {block} from '../../utils/cn'; -import type {PlaceholderContainerActionProps, PlaceholderContainerProps} from '../index'; -import {PlaceholderContainer} from '../index'; - -import './PlaceholderContainerShowcase.scss'; - -const b = block('placeholder-container-showcase'); - -const ImageComponentTest = () => { - return ( - - - - - 1:1 - - - - ); -}; - -const contentComponentTest = ( -
-

There is any custom title here

-

- You can add here any long text with custom content and use custom - content size for displaying very long texts. -

-
-); - -const actionComponentTest = ( -
- {}}, - {text: 'text 2', action: () => {}}, - ]} - onSwitcherClick={(e) => e?.stopPropagation()} - switcher={ - - } - /> -
-); - -const actionMainProps: PlaceholderContainerActionProps = { - text: 'Main button', - view: 'normal', - onClick: () => alert('Click by main button'), -}; - -const actionAdditionalBtnProps: PlaceholderContainerActionProps = { - text: 'Additional button', - view: 'flat-secondary', - onClick: () => alert('Click by additional button'), -}; - -const baseProps = { - title: 'Container with one button & image component', - image: , - className: 'placeholder-container', -}; - -const placeholderContainerProps: PlaceholderContainerProps = { - ...baseProps, - actions: [actionMainProps], - align: 'center', -}; - -const actionsProps = { - actions: [actionMainProps, actionAdditionalBtnProps], -}; - -const placeholderContainerCustomRenderedProps: PlaceholderContainerProps = { - ...placeholderContainerProps, - content: contentComponentTest, -}; - -const placeholderContainerCustomActionProps: PlaceholderContainerProps = { - ...placeholderContainerProps, - actions: actionComponentTest, -}; - -const descriptionProps = { - description: - 'Some long descriptionProps text that can contain of long long very long text etc. It can be repeated like this. Some long descriptionProps text that can contain of long long very long text etc.', -}; - -const imageProps = { - url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEFklEQVR4nO2Y6U4iQRSF5/3fwAX3aGKMonHBHVFxxy3unmfpyalYpGlAZeJ4Sjw/btIWt6Tq+27dbvoPgMyBZBj8US/AAQtBwoXgEwK9BAuBHryFQA/bQqAHbCHQQ7UQ6EFaCPTwLAR6YBYCPSQLgR6MhSQAAwmEX51AL8FCoAdvIdDDthDoAVsI9FAtBHqQFgI9PAuBHpiFQA/JQqAHYyEJwEAC4Vcn0EuwEOjBWwj0sC0EesAWAj1UC4EepIVAD89CoAdmIdBDshDowVhIAjCQQPjVCfQSLAR68BYCPWwLgR6whUAP1UKgB2kh0MOzEOiB/SghNzc32fb2dnZ1ddX22evra3Z4eJhtbGxke3t72cPDQ1vO/f19Vq1WQ069Xg9z/sem7+7uwjovLi46rvP4+DisgWthbjHn8fExq9VqIefg4CB7fn5OT8jp6WlWKpWygYGBALy4genp6fBZDOY2Go1mDq9Lb/NjzMzMZE9PT18qg98zOjoa/v/m5mbLZwQ7Ozvbsobh4eGwt3zRxfkxpqamQjElI4QCBgcHmwssClleXg7ja2trAfDR0VHIn5iYCBXJGB8fz4aGhkJ1Moe5nLOysvJlMnjqCDiusyiEFc/xpaWlsIazs7OQPzIy0iyMWFjxZGxtbYW/FxYW0hDC9sQFcaGVSqVNyMvLS3NTvI7j5XI55J6cnITgdblcbpnHOZybnxeDc+bm5lraBdvI4uJix1bH1sMimJycbEIsChkbGws5PNFxbHV1NeTu7+8398pTlJ/HwuK8Tm1YckIIh2B2d3fbhFxeXoYxwsvPYX/mOKsyVma1Wm3J4RyO838UvzO2OMLhd1MGcwmw2zpZ8ax03suKQigsFlbxVHGcp5z7imvO5/BExeJKQkiMTkJi9XPR3TbKtsTrer3e00ajFPbwj2Tko5OQboVzfn4exufn50N+p8KJnYFF8auFAMjW19dDDtvNZ592frWQz7Ssbhude6dlMWKb4r0n377+RcivaVkf3dT5SMno9aZeK9wziveUXoV8dFPnU9WPuam/J+Szj728HurhsZd5bBX5MUrhd330g7KbkL547M0f2WJw0d1+GHKT3/3DsPLW64uxs7PTXz8MeeNjCynG7e1tUq9OGo1Gx3VeX1/336sTBywEfVgIPiHQS7AQ6MFbCPSwLQR6wBYCPVQLgR6khUAPz0KgB2Yh0EOyEOjBWEgCMJBA+NUJ9BIsBHrwFgI9bAuBHrCFQA/VQqAHaSHQw7MQ6IFZCPSQLAR6MBaSAAwkEH51Ar0EC4EevIVAD9tCoAdsIdBDtRDoQVoI9PAsBHpgFgI9JAuBHoyFJAADCYRfnUAvwUKgB28h0MO2EOgBWwj0UC0EepAWAj08C4EemIVAD+k7hfwFjRtJ9Zn/PDYAAAAASUVORK5CYII=', - alt: 'image alt text', -}; - -export const PlaceholderContainerShowcase = () => { - return ( -
-
-

PlaceholderContainer

-
-

Sizes:

-
- - -
-
- - -
-
- - -
-
- - -
-
-
-

With buttons:

- -
-
-

With image props:

- -
-
-

Custom content:

- -
-
-

Custom action:

- -
-
-
- ); -}; From 3104f8e235a0b04fe1850e7e52df639676f3f635 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Mon, 2 Sep 2024 18:38:30 +0300 Subject: [PATCH 11/15] fix(PlaceholderContainer): renamed img url prop to src --- .../PlaceholderContainer/PlaceholderContainer.tsx | 4 ++-- src/components/PlaceholderContainer/README.md | 10 +++++----- src/components/PlaceholderContainer/types.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index b6899a997a..e48a26bc64 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -55,8 +55,8 @@ export const PlaceholderContainer = ({ }; const renderImage = (): NonNullable => { - if (typeof image === 'object' && 'url' in image) { - return {image.alt; + if (typeof image === 'object' && 'src' in image) { + return {image.alt; } return image; diff --git a/src/components/PlaceholderContainer/README.md b/src/components/PlaceholderContainer/README.md index 1566b14951..e205bfee84 100644 --- a/src/components/PlaceholderContainer/README.md +++ b/src/components/PlaceholderContainer/README.md @@ -111,7 +111,7 @@ It is also possible to render custom controls: ## Image and content -The property `image` allows to set up image `url` and `alt` settings or react node. +The property `image` allows to set up image `src` and `alt` settings or react node. @@ -144,17 +144,17 @@ The property `image` allows to set up image `url` and `alt` settings or react no /> ``` -with url and alt settings +with src and alt settings ```tsx @@ -216,6 +216,6 @@ To control alignment of content inside parent container use `align` property. Th | align | Used to set content horizontal align, possible values: `"center"` or `"left"` | `string` | `"center"` | | title | Content title text | `string` | | | description | Content description text | `string` | | -| image | Used to set image by src url or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageProps` | | +| image | Used to set image by src or passing react node | `PlaceholderContainerImageNodeProps`
`\| PlaceholderContainerImageProps` | | | content | Used to render node instead of content (title, description and actions) | `React.ReactNode` | | | actions | Used to render array of button controls or custom node | `PlaceholderContainerActionProps[]`
`\| React.ReactNode ` | | diff --git a/src/components/PlaceholderContainer/types.ts b/src/components/PlaceholderContainer/types.ts index a573f1b56c..497d73038b 100644 --- a/src/components/PlaceholderContainer/types.ts +++ b/src/components/PlaceholderContainer/types.ts @@ -7,7 +7,7 @@ type Size = 's' | 'm' | 'l' | 'promo'; type PlaceholderContainerImageNodeProps = NonNullable; export type PlaceholderContainerImageProps = { - url: string; + src: string; alt?: string; }; From 8ed80bb04eb79733454ec1ef6e1064dfd92afcb2 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Mon, 2 Sep 2024 18:48:50 +0300 Subject: [PATCH 12/15] chore(PlaceholderContainer): add default story --- .../__stories__/PlaceholderContainer.stories.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx index d0f8c0706b..b47152238c 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx @@ -138,6 +138,18 @@ const descriptionProps = { "Comparing to 'L' size promo size has full width of the content block, a larger title size and alignment", }; +export const Default: Story = { + render: () => ( + + } + description="Default description" + /> + + ), +}; + export const Size: Story = { render: () => ( From 26e0700cd1316f959807f6107cd0af92847a1909 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Thu, 5 Sep 2024 19:33:18 +0300 Subject: [PATCH 13/15] fix(PlaceholderContainer): fix props & styles, refactor stories --- .../PlaceholderContainer.scss | 1 + .../PlaceholderContainer.tsx | 2 +- .../PlaceholderContainer.stories.tsx | 233 ++++++------------ .../PlaceholderContainerShowcase.scss | 14 ++ src/components/PlaceholderContainer/types.ts | 6 +- 5 files changed, 88 insertions(+), 168 deletions(-) diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.scss b/src/components/PlaceholderContainer/PlaceholderContainer.scss index a68fbb4103..3e14317664 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.scss +++ b/src/components/PlaceholderContainer/PlaceholderContainer.scss @@ -33,6 +33,7 @@ $block: '.#{$ns}placeholder-container'; & > * { max-width: $imageSize; + display: block; } } diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index e48a26bc64..2430bfc778 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -63,7 +63,7 @@ export const PlaceholderContainer = ({ }; const renderAction = () => { - if (!actions || !React.isValidElement(actions) || !Array.isArray(actions)) { + if (!actions || !(React.isValidElement(actions) || Array.isArray(actions))) { return null; } diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx index b47152238c..5215c57589 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainer.stories.tsx @@ -1,16 +1,15 @@ import React from 'react'; import {ChevronDown} from '@gravity-ui/icons'; -import type {Meta, /*StoryFn,*/ StoryObj} from '@storybook/react'; +import type {Meta, StoryObj} from '@storybook/react'; import {Showcase} from '../../../demo/Showcase'; -import {ShowcaseItem} from '../../../demo/ShowcaseItem'; import {Button} from '../../Button'; import {DropdownMenu} from '../../DropdownMenu'; import {Icon} from '../../Icon'; import {block} from '../../utils/cn'; import {PlaceholderContainer} from '../PlaceholderContainer'; -import type {PlaceholderContainerActionProps, PlaceholderContainerProps} from '../types'; +import type {PlaceholderContainerActionProps} from '../types'; import './PlaceholderContainerShowcase.scss'; @@ -58,18 +57,6 @@ const ImageComponentTest = () => { ); }; -const contentComponentTest = ( -
-

Custom title

-

with custom subtitle

-

and etc

-

- You can add here any long text with custom content and use custom - content size for displaying very long texts. -

-
-); - const actionComponentTest = (
alert('Click by additional button'), }; -const baseProps = { - title: 'Container with one button & image component', - image: , - className: 'placeholder-container', -}; - -const placeholderContainerProps: Omit = { - ...baseProps, - actions: [actionMainProps], - align: 'center', -}; - -const actionsProps = { - actions: [actionMainProps, actionAdditionalBtnProps], -}; - -const placeholderContainerCustomRenderedProps: Omit< - PlaceholderContainerProps, - 'size' | 'direction' -> = { - ...placeholderContainerProps, - content: contentComponentTest, -}; - -const placeholderContainerCustomActionProps: Omit = - { - ...placeholderContainerProps, - actions: actionComponentTest, - }; - -const descriptionProps = { - description: - 'Some long descriptionProps text that can contain of long long very long text etc. It can be repeated like this. Some long descriptionProps text that can contain of long long very long text etc.', - promoDescription: - "Comparing to 'L' size promo size has full width of the content block, a larger title size and alignment", +export const Default: Story = { + args: { + title: 'Some title', + image: , + description: + 'Some long descriptionProps text that can contain of long long very long text etc. It can be repeated like this. Some long descriptionProps text that can contain of long long very long text etc.', + }, }; -export const Default: Story = { - render: () => ( - - } - description="Default description" - /> - +export const Direction: Story = { + render: (args) => ( + + + + + + + + ), + args: { + ...Default.args, + title: 'Direction', + }, }; -export const Size: Story = { - render: () => ( +export const Align: Story = { + render: (args) => ( - - - - - - - - - - - - - + + - - - - - - - - - - - - - + + ), + args: { + ...Default.args, + title: 'Align of component inside flex parent', + }, }; -export const Actions: Story = { - render: () => ( +export const Size: Story = { + render: (args) => ( - - - - - - - - - - + + + + + + + + + + + ), + args: { + ...Default.args, + description: 'Description text', + }, }; -export const Content: Story = { - render: () => ( +export const Actions: Story = { + render: (args) => ( + + + ), + args: { + ...Default.args, + }, }; diff --git a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss index ee3fe3bea1..00eb2d1078 100644 --- a/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss +++ b/src/components/PlaceholderContainer/__stories__/PlaceholderContainerShowcase.scss @@ -1,9 +1,23 @@ @import '../../variables'; $block: '.#{$ns}placeholder-container-showcase'; +$body: '.#{$ns}placeholder-container__body'; #{$block} { &__custom-action { margin-block-start: 20px; } + + &__full-width .showcase__content { + display: block; + width: 100%; + } + + &__container { + border: 3px dashed var(--g-color-line-generic); + + #{$body} { + border: 3px dashed var(--g-color-line-generic); + } + } } diff --git a/src/components/PlaceholderContainer/types.ts b/src/components/PlaceholderContainer/types.ts index 497d73038b..db0b4c691c 100644 --- a/src/components/PlaceholderContainer/types.ts +++ b/src/components/PlaceholderContainer/types.ts @@ -19,9 +19,9 @@ export type PlaceholderContainerActionProps = Pick< }; export interface PlaceholderContainerProps { - size: Size; - direction: 'row' | 'column'; - align: 'left' | 'center'; + size?: Size; + direction?: 'row' | 'column'; + align?: 'left' | 'center'; title?: string; description?: React.ReactNode; content?: React.ReactNode; From 648f3547a9b4bb3530584ff97cb1373d4170957c Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Fri, 6 Sep 2024 16:00:49 +0300 Subject: [PATCH 14/15] chore(PlaceholderContainer): improve readme --- src/components/PlaceholderContainer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PlaceholderContainer/README.md b/src/components/PlaceholderContainer/README.md index e205bfee84..e7b1b6b9b8 100644 --- a/src/components/PlaceholderContainer/README.md +++ b/src/components/PlaceholderContainer/README.md @@ -12,7 +12,7 @@ The component has `row` and `column` directions of the content layout. To contro ## Size -To control the size of the `PlaceholderContainer` use the `size` property. The default size is `l`. Possible values: `s`, `m`, `l`, `promo`. The `promo` value sets full width of the content block and a larger title size. +To control the size of the `PlaceholderContainer` use the `size` property. The default size is `l`. Possible values: `s`, `m`, `l`, `promo`. The `promo` value sets full width of the content block without minimal content height and a larger title size. ## Action controls From 8305ddc0cbc311e45155294a01facb0b593f1b09 Mon Sep 17 00:00:00 2001 From: Elena Martynova Date: Fri, 6 Sep 2024 16:04:22 +0300 Subject: [PATCH 15/15] fix(PlaceholderContainer): fix className --- src/components/PlaceholderContainer/PlaceholderContainer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/PlaceholderContainer/PlaceholderContainer.tsx b/src/components/PlaceholderContainer/PlaceholderContainer.tsx index 2430bfc778..7ff190f24c 100644 --- a/src/components/PlaceholderContainer/PlaceholderContainer.tsx +++ b/src/components/PlaceholderContainer/PlaceholderContainer.tsx @@ -32,7 +32,7 @@ export const PlaceholderContainer = ({ direction = 'row', align = 'center', size = 'l', - className = b(), + className, title, description, image, @@ -97,7 +97,7 @@ export const PlaceholderContainer = ({ }; return ( -
+
{renderImage()}
{renderContent()}