Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/short-rings-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@alfalab/core-components-tag': minor
'@alfalab/core-components': minor
---

##### Tag

- Добавлен компонент `IndicatorTag` для тега с числовым индикатором
1 change: 1 addition & 0 deletions packages/tag/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"main": "index.js",
"module": "./esm/index.js",
"dependencies": {
"@alfalab/core-components-indicator": "^4.0.2",
"@alfalab/core-components-mq": "^6.0.3",
"@alfalab/hooks": "^1.13.1",
"classnames": "^2.5.1",
Expand Down
6 changes: 3 additions & 3 deletions packages/tag/src/Component.responsive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React, { forwardRef } from 'react';

import { useIsDesktop } from '@alfalab/core-components-mq';

import { type BaseTagProps } from './components/base-tag';
import { TagDesktop } from './desktop';
import { TagMobile } from './mobile';
import { type BaseTagProps } from './typings';

export type TagProps = Omit<BaseTagProps, 'styles' | 'colorStylesMap'> & {
export interface TagProps extends Omit<BaseTagProps, 'styles' | 'colorStylesMap'> {
/**
* Контрольная точка, с нее начинается desktop версия
* @default 1024
Expand All @@ -23,7 +23,7 @@ export type TagProps = Omit<BaseTagProps, 'styles' | 'colorStylesMap'> & {
* @deprecated Используйте client
*/
defaultMatchMediaValue?: boolean | (() => boolean);
};
}

export const Tag = forwardRef<HTMLButtonElement, TagProps>(
(
Expand Down
189 changes: 17 additions & 172 deletions packages/tag/src/components/base-tag/Component.tsx
Original file line number Diff line number Diff line change
@@ -1,155 +1,30 @@
import React, {
type ButtonHTMLAttributes,
forwardRef,
type ReactNode,
type RefObject,
useRef,
} from 'react';
import React, { forwardRef, useRef } from 'react';
import mergeRefs from 'react-merge-refs';
import cn from 'classnames';

import { useFocus } from '@alfalab/hooks';

import defaultColors from './default.module.css';
import commonStyles from './index.module.css';
import invertedColors from './inverted.module.css';

const colorCommonStyles = {
default: defaultColors,
inverted: invertedColors,
} as const;

export type StyleColors = {
default: {
[key: string]: string;
};
inverted: {
[key: string]: string;
};
};

export type NativeProps = ButtonHTMLAttributes<HTMLButtonElement>;

export type BaseTagProps = Omit<NativeProps, 'onClick'> & {
/**
* Отображение кнопки в отмеченном (зажатом) состоянии
*/
checked?: boolean;

/**
* Размер компонента
*/
size?: 32 | 40 | 48 | 56 | 64 | 72;

/**
* Дочерние элементы.
*/
children?: ReactNode;

/**
* Дополнительный класс для обёртки children
*/
childrenClassName?: string;

/**
* Слот слева
*/
leftAddons?: ReactNode;

/**
* Слот справа
*/
rightAddons?: ReactNode;

/**
* Идентификатор для систем автоматизированного тестирования
*/
dataTestId?: string;

/**
* Обработчик нажатия
*/
onClick?: (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
payload: {
checked: boolean;
name?: string;
},
) => void;

/**
* ref на children
*/

childrenRef?: RefObject<HTMLSpanElement>;

/**
* Набор цветов для компонента
*/
colors?: 'default' | 'inverted';

/**
* @deprecated данный проп больше не используется, временно оставлен для обратной совместимости
* Используйте props shape и view
* Вариант тега
*/
variant?: 'default' | 'alt';

/**
* Форма тега
*/
shape?: 'rounded' | 'rectangular';

/**
* Стиль тега
* @default outlined
*/
view?: 'outlined' | 'filled' | 'transparent';

/**
* Включает размытие фона для некоторых вариантов тега
* @description Может привести к просадке fps и другим багам. Старайтесь не размещать слишком много заблюреных элементов на одной странице.
*/
allowBackdropBlur?: boolean;

/**
* Основные стили компонента.
*/
styles?: { [key: string]: string };

/**
* Стили компонента для default и inverted режима.
*/
colorStylesMap?: StyleColors;
};
import { type BaseTagProps } from '../../typings';
import { NativeTag as DefaultTag } from '../native-tag';

export const BaseTag = forwardRef<HTMLButtonElement, BaseTagProps>(
(
{
allowBackdropBlur,
rightAddons,
leftAddons,
Component = DefaultTag,
children,
size = 48,
checked,
className,
dataTestId,
name,
colors = 'default',
onClick,
variant = 'default',
shape,
view = 'outlined',
childrenClassName,
childrenRef,
shape,
onClick,
styles = {},
colorStylesMap = { default: {}, inverted: {} },
...restProps
},
ref,
) => {
const colorStyles = colorStylesMap[colors];

const tagRef = useRef<HTMLButtonElement>(null);

const [focused] = useFocus(tagRef, 'keyboard');
Expand All @@ -158,58 +33,28 @@ export const BaseTag = forwardRef<HTMLButtonElement, BaseTagProps>(

const shapeClassName = shape || variantClassName;

const sizeClassName = `size-${size}`;

const tagProps = {
className: cn(
commonStyles.component,
colorCommonStyles[colors].component,
colorStyles.component,
commonStyles[sizeClassName],
styles[sizeClassName],
colorCommonStyles[colors][view],
commonStyles[view],
{
[commonStyles.allowBackdropBlur]: allowBackdropBlur,
[commonStyles.checked]: checked,
[commonStyles[shapeClassName]]: Boolean(commonStyles[shapeClassName]),
[styles[shapeClassName]]: Boolean(styles[shapeClassName]),
[colorCommonStyles[colors].checked]: checked,
[colorStyles[view]]: Boolean(colorStyles[view]),
[commonStyles.focused]: focused,
[commonStyles.withRightAddons]: Boolean(rightAddons),
[commonStyles.withLeftAddons]: Boolean(leftAddons),
[commonStyles.noContent]: Boolean((leftAddons || rightAddons) && !children),
},
className,
),
'data-test-id': dataTestId,
};

const handleClick = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
if (onClick) {
onClick(event, { name, checked: !checked });
}
};

return (
<button
<Component
ref={mergeRefs([tagRef, ref])}
type='button'
checked={checked}
colors={colors}
view={view}
colorStyles={colorStylesMap[colors]}
shape={shapeClassName}
size={size}
styles={styles}
focused={focused}
onClick={handleClick}
{...tagProps}
{...restProps}
>
{leftAddons ? <span className={commonStyles.addons}>{leftAddons}</span> : null}

{children && (
<span ref={childrenRef} className={childrenClassName}>
{children}
</span>
)}

{rightAddons ? <span className={commonStyles.addons}>{rightAddons}</span> : null}
</button>
{children}
</Component>
);
},
);
9 changes: 9 additions & 0 deletions packages/tag/src/components/button/Component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React, { type ButtonHTMLAttributes, forwardRef } from 'react';

export const Button = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
({ children, onClick, ...rest }, ref) => (
<button ref={ref} type='button' {...rest} onClick={onClick}>
{children}
</button>
),
);
1 change: 1 addition & 0 deletions packages/tag/src/components/button/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Component';
Loading