Skip to content

Commit

Permalink
#90
Browse files Browse the repository at this point in the history
- добавлен компонент InteractiveImage
- InteractiveImage: добавлены тесты
- InteractiveImage: добавлены stories
  • Loading branch information
krutoo committed Mar 17, 2022
1 parent 46dd98c commit c569e60
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 0 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { action } from '@storybook/addon-actions';
import React from 'react';
import { InteractiveImage, Parts } from '..';
import imageSrc from './image.png';

export default {
title: 'common/InteractiveImage',
component: InteractiveImage,
parameters: {
layout: 'padded',
},
};

interface TitledPoint {
x: number;
y: number;
title: string;
}

export const Primary = () => {
const points: TitledPoint[] = [
{ x: 28, y: 30, title: 'Яйца' },
{ x: 63, y: 35, title: 'Кружка' },
{ x: 49, y: 70, title: 'Тарелка' },
{ x: 83, y: 69, title: 'Приборы' },
];

const style: React.CSSProperties = {
borderRadius: '8px',
width: '600px',
maxWidth: '100%',
marginBottom: '32px',
};

const ClickHandler = (value: string) => () => {
action('click')(value);
};

return (
<>
<h3>Простое изображение</h3>
<img src={imageSrc} style={style} />

<h3>Интерактивное изображение</h3>
<InteractiveImage style={style}>
<Parts.Image src={imageSrc} />

{points.map((point, index) => (
<Parts.Point key={index} role='button' {...point} onClick={ClickHandler(point.title)} />
))}
</InteractiveImage>
</>
);
};

Primary.storyName = 'Простой пример';
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`InteractiveImage should handle props 1`] = `
<DocumentFragment>
<div
class="root"
>
<img
class="image"
data-testid="interactive-image:image"
src="https://www.images.com/123"
/>
<a
aria-label="Точка на изображении"
class="point"
data-testid="interactive-image:point"
role="button"
style="top: 2%; left: 1%;"
/>
<a
aria-label="Точка на изображении"
class="point"
data-testid="interactive-image:point"
role="button"
style="top: 3%; left: 2%;"
/>
<a
aria-label="Точка на изображении"
class="point"
data-testid="interactive-image:point"
role="button"
style="top: 4%; left: 3%;"
/>
<a
aria-label="Точка на изображении"
class="point"
data-testid="interactive-image:point"
role="button"
style="top: 5%; left: 4%;"
/>
</div>
</DocumentFragment>
`;
22 changes: 22 additions & 0 deletions src/common/components/intractive-image/__test__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { render } from '@testing-library/react';
import React from 'react';
import { InteractiveImage, Parts } from '..';

describe('InteractiveImage', () => {
it('should handle props', () => {
const { asFragment, queryAllByTestId } = render(
<InteractiveImage>
<Parts.Image src='https://www.images.com/123' />
<Parts.Point role='button' x={1} y={2} />
<Parts.Point role='button' x={2} y={3} />
<Parts.Point role='button' x={3} y={4} />
<Parts.Point role='button' x={4} y={5} />
</InteractiveImage>,
);

expect(asFragment()).toMatchSnapshot();

expect(queryAllByTestId('interactive-image:image')).toHaveLength(1);
expect(queryAllByTestId('interactive-image:point')).toHaveLength(4);
});
});
52 changes: 52 additions & 0 deletions src/common/components/intractive-image/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { Children, forwardRef, isValidElement } from 'react';
import classNames from 'classnames';
import styles from './interactive-image.module.scss';

export interface InteractiveImageProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
'data-testid'?: string;
}

export interface InteractiveImageImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
'data-testid'?: string;
}

export interface InteractiveImagePointProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
x: number;
y: number;
'data-testid'?: string;
}

export const InteractiveImage = ({
children,
'data-testid': testId,
className,
...rest
}: InteractiveImageProps) => (
<div className={classNames(styles.root, className)} {...rest} data-testid={testId}>
{Children.toArray(children).filter(
child => isValidElement(child) && (child.type === Image || child.type === Point),
)}
</div>
);

const Image = forwardRef<HTMLImageElement, InteractiveImageImageProps>(
({ className, 'data-testid': testId = 'interactive-image:image', ...rest }, ref) => (
<img ref={ref} className={classNames(styles.image, className)} data-testid={testId} {...rest} />
),
);

const Point = forwardRef<HTMLAnchorElement, InteractiveImagePointProps>(
({ x, y, className, style, 'data-testid': testId = 'interactive-image:point', ...rest }, ref) => (
<a
ref={ref}
aria-label='Точка на изображении'
data-testid={testId}
className={classNames(styles.point, className)}
style={{ ...style, top: `${y}%`, left: `${x}%` }}
{...rest}
/>
),
);

export const Parts = { Image, Point } as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@use 'node_modules/@sima-land/ui-nucleons/colors';
@use 'node_modules/@sima-land/ui-nucleons/breakpoints';

.root {
display: inline-block;
font-size: 0;
position: relative;
overflow: hidden;
background: colors.$basic-gray4;
}

.image {
display: block;
max-width: 100%;
max-height: 100%;
min-width: 100%;
min-height: 100%;
}

.point {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: 64px;
height: 64px;
background: rgba(colors.$basic-gray87, 0.4);
border-radius: 50%;
transform: translate(-50%, -50%);
&:hover {
cursor: pointer;
background: rgba(colors.$basic-gray87, 0.64);
}
&::after {
content: '';
display: block;
width: 24px;
height: 24px;
background: #fff;
border-radius: 50%;
}
@include breakpoints.down('xs') {
width: 40px;
height: 40px;
&::after {
width: 16px;
height: 16px;
}
}
}
9 changes: 9 additions & 0 deletions src/custom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,12 @@ declare module '*.svg' {
const content: React.FC<React.SVGProps<SVGSVGElement>>;
export default content;
}

// изображения
declare module '*.jpg' {
export default string;
}

declare module '*.png' {
export default string;
}

0 comments on commit c569e60

Please sign in to comment.