const VARIANT_CLASS = {
primary: 'button button--primary',
outline: 'button button--outline',
danger: 'button button--danger',
};
export function Button({
variant = 'primary',
loading = false,
disabled = false,
children,
...rest
}) {
const isDisabled = disabled || loading;
return (
<button
type="button"
className={VARIANT_CLASS[variant] ?? VARIANT_CLASS.primary}
disabled={isDisabled}
aria-busy={loading || undefined}
{...rest}
>
{loading ? 'Загрузка…' : children}
</button>
);
} const VARIANT_CLASS = {
primary: 'button button--primary',
outline: 'button button--outline',
danger: 'button button--danger',
};
export function Button({
variant = 'primary',
loading = false,
disabled = false,
children,
...rest
}) {
const isDisabled = disabled || loading;
return (
<button
type="button"
className={VARIANT_CLASS[variant] ?? VARIANT_CLASS.primary}
disabled={isDisabled}
aria-busy={loading || undefined}
{...rest}
>
{loading ? 'Загрузка…' : children}
</button>
);
} import { useState } from 'react';
import { Button } from './components/Button';
export default function App() {
const [busy, setBusy] = useState(false);
function simulateSave() {
setBusy(true);
setTimeout(() => setBusy(false), 1200);
}
return (
<div className="app">
<h1>Кнопки</h1>
<div className="button-row">
<Button variant="primary">Сохранить</Button>
<Button variant="outline">Отмена</Button>
<Button variant="danger">Удалить</Button>
<Button variant="primary" loading={busy} onClick={simulateSave}>
Отправить
</Button>
</div>
</div>
);
} import { useState } from 'react';
import { Button } from './components/Button';
export default function App() {
const [busy, setBusy] = useState(false);
function simulateSave() {
setBusy(true);
setTimeout(() => setBusy(false), 1200);
}
return (
<div className="app">
<h1>Кнопки</h1>
<div className="button-row">
<Button variant="primary">Сохранить</Button>
<Button variant="outline">Отмена</Button>
<Button variant="danger">Удалить</Button>
<Button variant="primary" loading={busy} onClick={simulateSave}>
Отправить
</Button>
</div>
</div>
);
} .button-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.5rem;
font: inherit;
font-weight: 600;
border-radius: 8px;
border: 1px solid transparent;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.button--primary { background: #7b68ee; color: #fff; }
.button--outline { background: transparent; color: #7b68ee; border-color: #7b68ee; }
.button--danger { background: #dc3545; color: #fff; }
.button:disabled { opacity: 0.65; cursor: not-allowed; }
.button:not(:disabled):active { transform: translateY(1px); } .button-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.5rem;
font: inherit;
font-weight: 600;
border-radius: 8px;
border: 1px solid transparent;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.button--primary { background: #7b68ee; color: #fff; }
.button--outline { background: transparent; color: #7b68ee; border-color: #7b68ee; }
.button--danger { background: #dc3545; color: #fff; }
.button:disabled { opacity: 0.65; cursor: not-allowed; }
.button:not(:disabled):active { transform: translateY(1px); }