'use client'; import * as React from 'react'; import { Icon24Cancel, Icon24Chevron, Icon24Dismiss, Icon24DismissDark } from '@vkontakte/icons'; import { classNames, hasReactNode } from '@vkontakte/vkjs'; import { usePlatform } from '../../hooks/usePlatform'; import { IconButton } from '../IconButton/IconButton'; import { Tappable, type TappableOmitProps } from '../Tappable/Tappable'; import { Headline } from '../Typography/Headline/Headline'; import { Subhead } from '../Typography/Subhead/Subhead'; import { Text } from '../Typography/Text/Text'; import { Title } from '../Typography/Title/Title'; import styles from './Banner.module.css'; export interface BannerProps extends Omit { /** * Тип баннера. */ mode?: 'tint' | 'image'; /** * Размер баннера. */ size?: 's' | 'm'; /** * Тип действия в правой части баннера. * * - `dismiss` – отображается иконка крестика, при нажатии на неё сработает свойство `onDismiss`. * - `chevron` – отображается иконка шеврона, которая подразумевает, что при нажатии на баннер можно куда-то перейти. */ after?: 'dismiss' | 'chevron' | React.ReactNode; /** * Срабатывает при нажатии на иконку крестика при `after="dismiss"`. */ onDismiss?: React.MouseEventHandler; /** * Текст кнопки закрытия. Делает ее доступной для ассистивных технологий. */ dismissLabel?: string; /** * Содержимое, отображаемое в левой части баннера. */ before?: React.ReactNode; /** * Заголовок. */ title?: React.ReactNode; /** * Подзаголовок. */ subtitle?: React.ReactNode; /** * Дополнительный подзаголовок баннера. */ extraSubtitle?: React.ReactNode; /** * При использовании `mode="image"`. * * - `light` – в качестве фона используется светлое изображение, цвет текста в баннере будет тёмным. * - `dark` – в качестве фона используется тёмное изображение, цвет текста будет светлым. */ imageTheme?: 'light' | 'dark'; /** * При использовании `mode="image"`. * * Элемент, который нужно стилизовать цветом и/или фоном. Этот элемент будет растянут на 100% ширины и высоты баннера. */ background?: React.ReactNode; /** * Кнопки-действия. Принимает [`Button`](https://vkui.io/components/button). * * - В режиме `tint` или `image` со светлым фоном используйте только с параметрами: * - `mode="primary"` * - `mode="secondary"` * - В режиме `image` с тёмным фоном используйте с параметрами: * - `appearance="overlay"`. * * Для набора кнопок используйте [`ButtonGroup`](https://vkui.io/components/button-group) с параметрами: * * - `gap="m" mode="horizontal" stretched` * - `gap="m" mode="vertical" stretched`. */ actions?: React.ReactNode; } /** * @see https://vkui.io/components/banner */ export const Banner = ({ mode = 'tint', imageTheme = 'dark', size = 's', before, after: afterProp, title, subtitle, extraSubtitle, children, background, actions, onDismiss, dismissLabel = 'Скрыть', Component, ...restProps }: BannerProps): React.ReactNode => { const platform = usePlatform(); const HeaderTypography = size === 'm' ? Title : Headline; const SubheadTypography = size === 'm' ? Text : Subhead; const IconDismissIOS = mode === 'image' ? Icon24DismissDark : Icon24Dismiss; const content = ( <> {mode === 'image' && background && (
{background}
)} {before &&
{before}
}
{hasReactNode(title) && ( {title} )} {hasReactNode(subtitle) && ( {subtitle} )} {hasReactNode(extraSubtitle) && ( {extraSubtitle} )} {hasReactNode(actions) && React.Children.count(actions) > 0 && (
{actions}
)}
); const afterMap: Record = { chevron: , dismiss: ( {platform === 'ios' ? : } ), }; const after = afterProp && (
{typeof afterProp === 'string' ? afterMap[afterProp] : afterProp}
); const isClickable = restProps.onClick || restProps.onClickCapture || restProps.href; return ( {content} {after} ); };