diff --git a/packages/vkui/src/components/FloatingArrow/DefaultIcon.tsx b/packages/vkui/src/components/FloatingArrow/DefaultIcon.tsx index ab425980e7..d795345046 100644 --- a/packages/vkui/src/components/FloatingArrow/DefaultIcon.tsx +++ b/packages/vkui/src/components/FloatingArrow/DefaultIcon.tsx @@ -1,6 +1,15 @@ import * as React from 'react'; +export const DEFAULT_ARROW_WIDTH = 20; +export const DEFAULT_ARROW_HEIGHT = 8; +export const DEFAULT_ARROW_PADDING = 10; + +const PLATFORM_HEIGHT = 1; +const ARROW_HEIGHT_WITH_WHITE_SPACE = DEFAULT_ARROW_HEIGHT + PLATFORM_HEIGHT; + /** + * Стрелка для всплывающих окон. + * * Примечание 1. * * В компоненте, SVG элемент `` представляет собой стрелку с платформой в виде прямоугольника в 1px. Платформа @@ -12,15 +21,9 @@ import * as React from 'react'; * 2. Сместить положение SVG контейнера на высоту платформы – сделано в CSS через `translateY(1px)`. * * https://github.com/VKCOM/VKUI/issues/2123 + * + * @since 7.0.0 */ - -export const DEFAULT_ARROW_WIDTH = 20; -export const DEFAULT_ARROW_HEIGHT = 8; -export const DEFAULT_ARROW_PADDING = 10; - -const PLATFORM_HEIGHT = 1; -const ARROW_HEIGHT_WITH_WHITE_SPACE = DEFAULT_ARROW_HEIGHT + PLATFORM_HEIGHT; - export const DefaultIcon = (props: React.SVGAttributes): React.ReactNode => { return ( ((acc, placement) => { + acc.push(placement, `${placement}-start`, `${placement}-end`); + return acc; +}, []); + +describe(FloatingArrow, () => { + baselineComponent(FloatingArrow); + + test('props to icon', () => { + const result = render( + , + ); + + const icon = result.getByTestId('host').querySelector('.icon'); + expect(icon).toBeInTheDocument(); + expect(icon).toHaveStyle({ display: 'none' }); + }); + + test.each(PLACEMENT_WITH_SIDE)('arrow position for %s placement', (placement) => { + const result = render(); + + if (placement.startsWith('top')) { + expect(result.getByTestId('host')).toHaveClass(placementClassNames.bottom); + } else if (placement.startsWith('right')) { + expect(result.getByTestId('host')).toHaveClass(placementClassNames.left); + } else if (placement.startsWith('bottom')) { + expect(result.getByTestId('host')).not.toHaveClass(...Object.values(placementClassNames)); + } else if (placement.startsWith('left')) { + expect(result.getByTestId('host')).toHaveClass(placementClassNames.right); + } + }); + + test.each(PLACEMENT_WITH_SIDE)('arrow offset by %s placement', (placement) => { + const result = render( + , + ); + + if (placement.startsWith('top')) { + expect(result.getByTestId('host')).toHaveStyle({ top: '100%', left: '14px' }); + } else if (placement.startsWith('right')) { + expect(result.getByTestId('host')).toHaveStyle({ left: '0px', top: '16px' }); + } else if (placement.startsWith('bottom')) { + expect(result.getByTestId('host')).toHaveStyle({ bottom: '100%', left: '14px' }); + } else if (placement.startsWith('left')) { + expect(result.getByTestId('host')).toHaveStyle({ right: '0px', top: '16px' }); + } + }); + + test.each(PLACEMENT_WITH_SIDE)('arrow static offset by %s placement', (placement) => { + const result = render( + , + ); + + if (placement.endsWith('end')) { + if (placement.startsWith('top')) { + expect(result.getByTestId('host')).toHaveStyle({ top: '100%', right: '8px' }); + } else if (placement.startsWith('right')) { + expect(result.getByTestId('host')).toHaveStyle({ left: '0px', bottom: '8px' }); + } else if (placement.startsWith('bottom')) { + expect(result.getByTestId('host')).toHaveStyle({ bottom: '100%', right: '8px' }); + } else if (placement.startsWith('left')) { + expect(result.getByTestId('host')).toHaveStyle({ right: '0px', bottom: '8px' }); + } + } else { + if (placement.startsWith('top')) { + expect(result.getByTestId('host')).toHaveStyle({ top: '100%', left: '8px' }); + } else if (placement.startsWith('right')) { + expect(result.getByTestId('host')).toHaveStyle({ left: '0px', top: '8px' }); + } else if (placement.startsWith('bottom')) { + expect(result.getByTestId('host')).toHaveStyle({ bottom: '100%', left: '8px' }); + } else if (placement.startsWith('left')) { + expect(result.getByTestId('host')).toHaveStyle({ right: '0px', top: '8px' }); + } + } + }); +}); diff --git a/packages/vkui/src/components/FloatingArrow/FloatingArrow.tsx b/packages/vkui/src/components/FloatingArrow/FloatingArrow.tsx index 430e0740a3..60a866ce63 100644 --- a/packages/vkui/src/components/FloatingArrow/FloatingArrow.tsx +++ b/packages/vkui/src/components/FloatingArrow/FloatingArrow.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { classNames } from '@vkontakte/vkjs'; import type { Placement } from '../../lib/floating'; import type { HasDataAttribute, HTMLAttributesWithRootRef } from '../../types'; +import { RootComponent } from '../RootComponent/RootComponent'; import { DefaultIcon } from './DefaultIcon'; import styles from './FloatingArrow.module.css'; @@ -10,7 +11,7 @@ export type Coords = { y?: number; }; -const placementClassNames = { +export const placementClassNames = { right: styles.placementRight, bottom: styles.placementBottom, left: styles.placementLeft, @@ -35,7 +36,9 @@ export interface FloatingArrowProps } /** - * @private + * Иконка-стрелка для всплывающих окон. + * + * @since 7.0.0 */ export const FloatingArrow = ({ offset, @@ -44,7 +47,6 @@ export const FloatingArrow = ({ iconStyle, iconClassName, placement = 'bottom', - getRootRef, Icon = DefaultIcon, ...restProps }: FloatingArrowProps): React.ReactNode => { @@ -56,14 +58,13 @@ export const FloatingArrow = ({ ); return ( -
-
+ ); }; diff --git a/packages/vkui/src/index.ts b/packages/vkui/src/index.ts index f3351f65ab..efb114c7a1 100644 --- a/packages/vkui/src/index.ts +++ b/packages/vkui/src/index.ts @@ -356,6 +356,14 @@ export type { SkeletonProps } from './components/Skeleton/Skeleton'; */ export { Div } from './components/Div/Div'; export type { DivProps } from './components/Div/Div'; +export { + DEFAULT_ARROW_HEIGHT as DEFAULT_ICON_ARROW_HEIGHT, + DEFAULT_ARROW_WIDTH as DEFAULT_ICON_ARROW_WIDTH, + DEFAULT_ARROW_PADDING as DEFAULT_ICON_ARROW_PADDING, + DefaultIcon, +} from './components/FloatingArrow/DefaultIcon'; +export { FloatingArrow } from './components/FloatingArrow/FloatingArrow'; +export type { FloatingArrowProps } from './components/FloatingArrow/FloatingArrow'; export { Touch } from './components/Touch/Touch'; export type { TouchProps, CustomTouchEvent } from './components/Touch/Touch'; export { PanelSpinner } from './components/PanelSpinner/PanelSpinner';