Skip to content

Commit

Permalink
Merge pull request #114 from sima-land/110-badge-hint
Browse files Browse the repository at this point in the history
#110 Добавить возможность выводить хинты для Badge
  • Loading branch information
krutoo authored May 17, 2022
2 parents 68243e2 + 5f191c0 commit a0ce5c1
Show file tree
Hide file tree
Showing 10 changed files with 375 additions and 204 deletions.
28 changes: 28 additions & 0 deletions src/common/components/badge-list/__stories__/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { BadgeList } from '..';
import { Badge, BadgeProps } from '../../badge';
import { addMonths } from 'date-fns';
import { WithHint } from '@sima-land/ui-nucleons/with-hint';

const items: BadgeProps[] = [
{
Expand Down Expand Up @@ -72,3 +73,30 @@ export const Primary = () => (
</DemoBlock>
</>
);

Primary.storyName = 'Простой пример';

export function Hints() {
return (
<DemoBlock>
<BadgeList lineLimit={3}>
{items.map((item, index) => (
<BadgeList.Slot key={index}>
<WithHint hint='Тестовый хинт для шильика!' direction='right'>
{(ref, toggle) => (
<Badge
{...item}
ref={ref as any}
onMouseOver={() => toggle(true)}
onMouseLeave={() => toggle(false)}
/>
)}
</WithHint>
</BadgeList.Slot>
))}
</BadgeList>
</DemoBlock>
);
}

Hints.storyName = 'С хинтами';
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,66 @@ exports[`<BadgeList /> renders correctly 1`] = `
<div
class="root test"
>
<a
class="root item"
data-testid="badge"
style="--badge-color: #b52ea8;"
<div
class="item"
>
<span
class="content"
<a
class="root"
data-testid="badge"
style="--badge-color: #b52ea8;"
>
-56%
</span>
</a>
<a
class="root item"
data-testid="badge"
style="--badge-color: #ff7200;"
<span
class="content"
>
-56%
</span>
</a>
</div>
<div
class="item"
>
<span
class="content"
<a
class="root"
data-testid="badge"
style="--badge-color: #ff7200;"
>
3 по цене 2
</span>
</a>
<a
class="root item"
data-testid="badge"
style="--badge-color: #2962ff;"
<span
class="content"
>
3 по цене 2
</span>
</a>
</div>
<div
class="item"
>
<span
class="content"
<a
class="root"
data-testid="badge"
style="--badge-color: #2962ff;"
>
Товар месяца
</span>
</a>
<a
class="root item"
data-testid="badge"
style="--badge-color: #00b8d4;"
<span
class="content"
>
Товар месяца
</span>
</a>
</div>
<div
class="item"
>
<span
class="content"
<a
class="root"
data-testid="badge"
style="--badge-color: #00b8d4;"
>
Акция
</span>
</a>
<span
class="content"
>
Акция
</span>
</a>
</div>
</div>
</div>
`;
24 changes: 23 additions & 1 deletion src/common/components/badge-list/__test__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { ReactNode } from 'react';
import { BadgeList } from '..';
import { Badge, BadgeProps } from '../../badge';
import { render } from '@testing-library/react';
Expand All @@ -23,4 +23,26 @@ describe('<BadgeList />', () => {
expect(container).toMatchSnapshot();
expect(getAllByTestId('badge')).toHaveLength(4);
});

it('should ignore non Badge/BadgeList.Slot children', () => {
function SomeWrapper({ children }: { children: ReactNode }) {
return <>{children}</>;
}

const { queryAllByTestId } = render(
<BadgeList className='test'>
{badges.map((item, index) => (
<BadgeList.Slot key={index}>
<SomeWrapper>
<Badge {...item} />
</SomeWrapper>
</BadgeList.Slot>
))}
<div data-testid='invalid-child'>Hello</div>
</BadgeList>,
);

expect(queryAllByTestId('badge')).toHaveLength(4);
expect(queryAllByTestId('invalid-child')).toHaveLength(0);
});
});
1 change: 1 addition & 0 deletions src/common/components/badge-list/badge-list.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
}

.item {
max-width: 100%;
margin-bottom: 4px;
&:not(:last-child) {
margin-right: 4px;
Expand Down
24 changes: 17 additions & 7 deletions src/common/components/badge-list/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Children, cloneElement, isValidElement } from 'react';
import React, { Children, isValidElement, ReactNode } from 'react';
import { Badge } from '../badge';
import classnames from 'classnames/bind';
import styles from './badge-list.module.scss';
Expand Down Expand Up @@ -29,11 +29,21 @@ export const BadgeList = ({ children, className, lineLimit, style }: BadgeListPr
className={cx('root', className, lineLimit && 'line-limit')}
style={lineLimit ? ({ ...style, '--line-limit': lineLimit } as React.CSSProperties) : style}
>
{Children.toArray(children).reduce<React.ReactElement[]>((list, item) => {
isValidElement(item) &&
item.type === Badge &&
list.push(cloneElement(item, { className: cx('item', item.props.className) }));
return list;
}, [])}
{Children.toArray(children).map(child => {
switch (true) {
case isValidElement(child) && child.type === Badge:
return <BadgeListSlot>{child}</BadgeListSlot>;
case isValidElement(child) && child.type === BadgeListSlot:
return child;
default:
return null;
}
})}
</div>
);

function BadgeListSlot({ children }: { children?: ReactNode }) {
return <div className={cx('item')}>{children}</div>;
}

BadgeList.Slot = BadgeListSlot;
20 changes: 20 additions & 0 deletions src/common/components/badge/__stories__/badge.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Badge } from '..';
import { addDays, addMonths } from 'date-fns';
import { WithHint } from '@sima-land/ui-nucleons/with-hint';

export default {
title: 'common/Badge',
Expand Down Expand Up @@ -101,3 +102,22 @@ export const NoInteractiveView = () => (
);

NoInteractiveView.storyName = 'Без ссылки и hover';

export const Hints = () => (
<div style={{ padding: '48px', display: 'flex', justifyContent: 'center' }}>
<WithHint hint='Привет, это очень простой хинт'>
{(ref, toggle) => (
<Badge
ref={ref as any}
color='#607d8b'
href='https://sima-land.ru'
fields={[{ type: 'text', value: 'Уценённый товар' }]}
onMouseOver={() => toggle(true)}
onMouseLeave={() => toggle(false)}
/>
)}
</WithHint>
</div>
);

Hints.storyName = 'С хинтом';
18 changes: 17 additions & 1 deletion src/common/components/badge/__test__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { createRef } from 'react';
import { render } from '@testing-library/react';
import { Badge, BadgeProps } from '..';
import { addDays, addMonths } from 'date-fns';
Expand Down Expand Up @@ -73,4 +73,20 @@ describe('<Badge />', () => {

expect(getByRole('link').getAttribute('rel')).toBe('nofollow');
});

it('should handle ref', () => {
const ref = createRef<HTMLAnchorElement>();

const { getByTestId } = render(
<Badge
ref={ref}
href='https://www.ya.ru'
rel='nofollow'
color='#f00'
fields={[{ type: 'text', value: 'Some text' }]}
/>,
);

expect(ref.current).toBe(getByTestId('badge'));
});
});
24 changes: 9 additions & 15 deletions src/common/components/badge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import classnames from 'classnames/bind';
import React, { forwardRef } from 'react';
import { Timer } from '@sima-land/ui-nucleons/timer';
import classnames from 'classnames/bind';
import styles from './badge.module.scss';

export interface BadgeField {
Expand All @@ -24,24 +24,17 @@ const cx = classnames.bind(styles);
/**
* Шильдик.
* @param props Свойства.
* @param props.color Цвет.
* @param props.fields Содержимое.
* @param props.href Ссылка.
* @return Элемент.
*/
export const Badge = ({
className,
color,
fields,
href,
style,
'data-testid': testId = 'badge',
...restProps
}: BadgeProps) => {
export const Badge = forwardRef<HTMLAnchorElement, BadgeProps>(function Badge(
{ className, color, fields, href, style, 'data-testid': testId = 'badge', ...restProps },
ref,
) {
const iconOnly = fields.length === 1 && fields[0].type === 'svg-url';

return (
<a
ref={ref}
{...restProps}
data-testid={testId}
href={href}
Expand Down Expand Up @@ -69,6 +62,7 @@ export const Badge = ({
}

acc.push(result);

i < fields.length - 1 && acc.push(' ');

return acc;
Expand All @@ -78,7 +72,7 @@ export const Badge = ({
}
/>
);
};
});

/**
* Форматирует оставшееся время.
Expand Down
Loading

0 comments on commit a0ce5c1

Please sign in to comment.