Skip to content

Commit 2519e8d

Browse files
committed
refactor(action-button): used BaseButtonCandidate
1 parent 6a0a5d8 commit 2519e8d

12 files changed

Lines changed: 209 additions & 281 deletions

packages/action-button/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@
1010
"main": "index.js",
1111
"module": "./esm/index.js",
1212
"dependencies": {
13+
"@alfalab/core-components-button": "^13.1.0",
1314
"@alfalab/core-components-shared": "^2.1.0",
14-
"@alfalab/core-components-spinner": "^6.0.2",
15-
"@alfalab/hooks": "^1.13.1",
1615
"classnames": "^2.5.1",
1716
"react-merge-refs": "^1.1.0",
1817
"tslib": "^2.4.0"

packages/action-button/src/Component.screenshots.test.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,10 @@ describe(
8787
},
8888
}),
8989
screenshotOpts: { clip },
90-
evaluate: (page: Page) =>
91-
page.hover('button[class^=component]').then(() => page.waitForTimeout(500)),
90+
evaluate: async (page) => {
91+
await page.hover('button[class*=component]');
92+
await page.waitForTimeout(500);
93+
},
9294
matchImageSnapshotOptions: {
9395
customSnapshotIdentifier: (...args) => `hover-${customSnapshotIdentifier(...args)}`,
9496
},
@@ -106,10 +108,10 @@ describe(
106108
},
107109
}),
108110
screenshotOpts: { clip },
109-
evaluate: (page: Page) => {
110-
return page.mouse
111-
.move(30, 30)
112-
.then(() => page.mouse.down().then(() => page.waitForTimeout(500)));
111+
evaluate: async (page) => {
112+
await page.mouse.move(30, 30);
113+
await page.mouse.down();
114+
await page.waitForTimeout(500);
113115
},
114116
matchImageSnapshotOptions: {
115117
customSnapshotIdentifier: (...args) => `pressed-${customSnapshotIdentifier(...args)}`,

packages/action-button/src/Component.test.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ describe('ActionButton', () => {
4141
it('should use "href" prop and become a link', () => {
4242
const href = 'http://127.0.0.1';
4343

44-
render(<ActionButton href={href} />);
44+
render(<ActionButton href={href} dataTestId={dti} />);
4545

46-
expect(screen.getByRole('button')).toHaveAttribute('href', href);
46+
expect(screen.getByTestId(dti)).toHaveAttribute('href', href);
4747
});
4848

4949
it('should use "disabled" prop (button)', () => {
@@ -57,13 +57,13 @@ describe('ActionButton', () => {
5757
});
5858

5959
it('should use "disabled" prop (link)', () => {
60-
const { rerender } = render(<ActionButton href='http://localhost' />);
60+
const { rerender } = render(<ActionButton href='http://localhost' dataTestId={dti} />);
6161

62-
expect(screen.getByRole('button')).not.toHaveAttribute('aria-disabled', 'true');
62+
expect(screen.getByTestId(dti)).not.toHaveAttribute('aria-disabled', 'true');
6363

64-
rerender(<ActionButton href='http://localhost' disabled={true} />);
64+
rerender(<ActionButton href='http://localhost' dataTestId={dti} disabled={true} />);
6565

66-
expect(screen.getByRole('button')).toHaveAttribute('aria-disabled', 'true');
66+
expect(screen.getByTestId(dti)).toHaveAttribute('aria-disabled', 'true');
6767
});
6868

6969
it('should use "loading" prop (button)', () => {
@@ -81,12 +81,12 @@ describe('ActionButton', () => {
8181
it('should use "loading" prop (link)', () => {
8282
const { rerender } = render(<ActionButton href='http://localhost' dataTestId={dti} />);
8383

84-
expect(screen.getByRole('button')).not.toHaveAttribute('aria-disabled', 'true');
84+
expect(screen.getByTestId(dti)).not.toHaveAttribute('aria-disabled', 'true');
8585
expect(screen.queryByTestId(loaderDti)).toBeNull();
8686

8787
rerender(<ActionButton href='http://localhost' loading={true} dataTestId={dti} />);
8888

89-
expect(screen.getByRole('button')).toHaveAttribute('aria-disabled', 'true');
89+
expect(screen.getByTestId(dti)).toHaveAttribute('aria-disabled', 'true');
9090
expect(screen.getByTestId(loaderDti)).toBeInTheDocument();
9191
});
9292

packages/action-button/src/Component.tsx

Lines changed: 54 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
1-
import React, {
2-
type AnchorHTMLAttributes,
3-
type ButtonHTMLAttributes,
4-
forwardRef,
5-
Fragment,
6-
useRef,
7-
} from 'react';
1+
import React, { type AnchorHTMLAttributes, type ButtonHTMLAttributes, forwardRef } from 'react';
82
import mergeRefs from 'react-merge-refs';
93
import cn from 'classnames';
104

5+
import {
6+
BaseButtonCandidate,
7+
type BaseButtonOwnProps,
8+
type MaybeAnchorAttributes,
9+
} from '@alfalab/core-components-button/components/base-button-candidate';
10+
import { ButtonContent } from '@alfalab/core-components-button/components/button-content';
11+
import { useLoading } from '@alfalab/core-components-button/shared';
1112
import { getDataTestId } from '@alfalab/core-components-shared';
12-
import { Spinner } from '@alfalab/core-components-spinner';
13-
import { useFocus } from '@alfalab/hooks';
14-
15-
import { LOADER_MIN_DISPLAY_INTERVAL } from './constants/loader-min-display-interval';
16-
import { useLoader } from './hooks';
1713

1814
import defaultColors from './default.module.css';
1915
import styles from './index.module.css';
@@ -24,11 +20,12 @@ const colorStyles = {
2420
default: defaultColors,
2521
inverted: invertedColors,
2622
static: staticColors,
27-
};
23+
} as const;
2824

2925
type Colors = 'default' | 'inverted' | 'static';
3026

31-
type ComponentProps = {
27+
interface ComponentProps
28+
extends Omit<BaseButtonOwnProps, 'disabledClassName' | 'Content' | 'block'> {
3229
/**
3330
* Иконка кнопки
3431
*/
@@ -44,92 +41,69 @@ type ComponentProps = {
4441
*/
4542
view?: 'primary' | 'secondary';
4643

47-
/**
48-
* Дополнительный класс
49-
*/
50-
className?: string;
51-
5244
/**
5345
* Дополнительный класс для обертки иконки
5446
*/
5547
iconWrapperClassName?: string;
5648

57-
/**
58-
* Значение href для ссылки
59-
*/
60-
href?: string;
61-
62-
/**
63-
* Заблокировать кнопку
64-
*/
65-
disabled?: boolean;
66-
67-
/**
68-
* Показать лоадер
69-
*/
70-
loading?: boolean;
71-
72-
/**
73-
* Идентификатор для систем автоматизированного тестирования.
74-
* Для спиннера используется модификатор -loader
75-
*/
76-
dataTestId?: string;
77-
7849
/**
7950
* Палитра, в контексте которой используется кнопка
8051
*/
8152
colors?: Colors;
82-
};
53+
}
54+
55+
interface AnchorLikeProps
56+
extends MaybeAnchorAttributes<string>,
57+
ComponentProps,
58+
Omit<AnchorHTMLAttributes<HTMLElement>, keyof ComponentProps> {}
8359

84-
type AnchorProps = ComponentProps & AnchorHTMLAttributes<HTMLAnchorElement>;
85-
type ButtonProps = ComponentProps & ButtonHTMLAttributes<HTMLButtonElement>;
86-
export type ActionButtonProps = Partial<AnchorProps | ButtonProps>;
60+
interface ButtonLikeProps
61+
extends MaybeAnchorAttributes<undefined>,
62+
ComponentProps,
63+
Omit<ButtonHTMLAttributes<HTMLElement>, keyof ComponentProps> {}
64+
65+
export type ActionButtonProps = AnchorLikeProps | ButtonLikeProps;
8766

8867
export const ActionButton = forwardRef<HTMLAnchorElement | HTMLButtonElement, ActionButtonProps>(
8968
(
9069
{
91-
className,
70+
className: classNameFromProps,
9271
icon,
9372
children,
94-
href,
9573
size = 48,
9674
view = 'primary',
97-
type = 'button',
9875
iconWrapperClassName,
9976
disabled,
100-
loading,
101-
dataTestId,
77+
loading: loadingFromProps,
10278
colors = 'default',
79+
dataTestId,
10380
...rest
10481
},
10582
ref,
10683
) => {
107-
const componentRef = useRef<HTMLElement>(null);
108-
109-
const [focused] = useFocus(componentRef, 'keyboard');
110-
111-
const { showLoader } = useLoader(!!loading, LOADER_MIN_DISPLAY_INTERVAL);
84+
const loading = useLoading(loadingFromProps);
11285

11386
const styleSize = `size-${size}`;
11487

115-
const componentProps = {
116-
className: cn(
117-
styles.component,
118-
colorStyles[colors][view],
119-
styles[styleSize],
120-
{
121-
[styles.focused]: focused,
122-
[styles.disabled]: disabled,
123-
[colorStyles[colors].disabled]: disabled,
124-
[styles.loading]: showLoader,
125-
},
126-
className,
127-
),
128-
'data-test-id': dataTestId,
129-
};
130-
131-
const buttonChildren = (
132-
<Fragment>
88+
const className = cn(
89+
styles.component,
90+
colorStyles[colors].component,
91+
colorStyles[colors][view],
92+
styles[styleSize],
93+
loading && [colorStyles[colors].loading, styles.loading],
94+
classNameFromProps,
95+
);
96+
97+
return (
98+
<BaseButtonCandidate
99+
{...rest}
100+
dataTestId={dataTestId}
101+
ref={mergeRefs([ref])}
102+
className={className}
103+
disabled={disabled}
104+
disabledClassName={colorStyles[colors].disabled}
105+
loading={loading}
106+
>
133107
<span
134108
role='img'
135109
className={cn(
@@ -139,47 +113,16 @@ export const ActionButton = forwardRef<HTMLAnchorElement | HTMLButtonElement, Ac
139113
iconWrapperClassName,
140114
)}
141115
>
142-
{showLoader ? (
143-
<Spinner
144-
preset={24}
145-
dataTestId={getDataTestId(dataTestId, 'loader')}
146-
visible={true}
147-
className={cn(styles.loader, colorStyles[colors].loader)}
148-
/>
149-
) : (
150-
icon
151-
)}
116+
<ButtonContent
117+
loading={loading}
118+
loaderClassName={cn(styles.loader, colorStyles[colors].loader)}
119+
dataTestId={getDataTestId(dataTestId, 'loader')}
120+
>
121+
{icon}
122+
</ButtonContent>
152123
</span>
153124
<span className={styles.label}>{children}</span>
154-
</Fragment>
155-
);
156-
157-
if (href) {
158-
return (
159-
<a
160-
role='button'
161-
ref={mergeRefs([componentRef, ref])}
162-
href={href}
163-
aria-disabled={disabled || loading}
164-
{...componentProps}
165-
{...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}
166-
>
167-
{buttonChildren}
168-
</a>
169-
);
170-
}
171-
172-
return (
173-
<button
174-
ref={mergeRefs([componentRef, ref])}
175-
// eslint-disable-next-line react/button-has-type
176-
type={type as ButtonHTMLAttributes<HTMLButtonElement>['type']}
177-
disabled={disabled || loading}
178-
{...componentProps}
179-
{...(rest as ButtonHTMLAttributes<HTMLButtonElement>)}
180-
>
181-
{buttonChildren}
182-
</button>
125+
</BaseButtonCandidate>
183126
);
184127
},
185128
);
Lines changed: 2 additions & 2 deletions
Loading

0 commit comments

Comments
 (0)