shinkan-jinkendo/frontend/src/components/FormActionBar.jsx
Lars c9175bd2fd
All checks were successful
Deploy Development / deploy (push) Successful in 39s
Test Suite / pytest-backend (push) Successful in 37s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 13s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m14s
Refactor modal components and enhance FormActionBar functionality
- Updated modal components to utilize a consistent overlay and panel structure, improving layout and responsiveness.
- Enhanced FormActionBar to support short labels for action buttons, improving usability in mobile views.
- Introduced new styling for action buttons and modal titles, ensuring better alignment and visual consistency across forms.
- Improved accessibility by adding aria-labels and titles to buttons for better screen reader support.
2026-05-19 10:20:49 +02:00

115 lines
3.7 KiB
JavaScript

import { Check, Save, X } from 'lucide-react'
/**
* Feste Aktionsleiste für Formulare/Modale: Speichern, Speichern & schließen, Abbrechen.
* Bleibt sichtbar (sticky), während der Formularinhalt scrollt.
*/
function ActionLabel({ Icon, long, short, saving, savingShort = '…' }) {
if (saving) {
return <span className="form-action-bar__saving">{savingShort}</span>
}
return (
<>
{Icon ? <Icon size={17} strokeWidth={2.25} className="form-action-bar__icon" aria-hidden /> : null}
<span className="form-action-bar__text form-action-bar__text--long">{long}</span>
{short != null && short !== '' ? (
<span className="form-action-bar__text form-action-bar__text--short">{short}</span>
) : null}
</>
)
}
export default function FormActionBar({
placement = 'bottom',
variant = 'default',
saving = false,
saveLabel,
saveShortLabel,
saveAndCloseLabel = 'Speichern & schließen',
saveAndCloseShortLabel,
cancelLabel = 'Abbrechen',
onSave,
onSaveAndClose,
onCancel,
showSave = true,
showSaveAndClose = true,
showCancel = true,
formId,
isNew = false,
primaryIsSaveOnly = false,
}) {
const labelSave = saveLabel ?? (isNew ? 'Anlegen' : 'Speichern')
const shortSave = saveShortLabel ?? (isNew ? 'Neu' : 'Sichern')
const shortClose = saveAndCloseShortLabel ?? 'Fertig'
const showSaveBtn = showSave && (Boolean(onSave) || Boolean(formId))
const showCloseBtn = showSaveAndClose && (Boolean(onSaveAndClose) || Boolean(formId))
const showCancelBtn = showCancel && Boolean(onCancel)
if (!showSaveBtn && !showCloseBtn && !showCancelBtn) return null
const saveBtnClass = `btn form-action-bar__btn${
primaryIsSaveOnly ? ' btn-primary' : ' btn-secondary'
}`
const closeBtnClass = `btn form-action-bar__btn${
primaryIsSaveOnly ? ' btn-secondary' : ' btn-primary'
}`
const primaryCount = (showSaveBtn ? 1 : 0) + (showCloseBtn ? 1 : 0)
return (
<div
className={`form-action-bar form-action-bar--${placement} form-action-bar--${variant}${
primaryCount === 1 ? ' form-action-bar--single-primary' : ''
}`}
role="group"
aria-label="Formularaktionen"
>
<div className="form-action-bar__inner">
{showCancelBtn ? (
<button
type="button"
className="btn btn-secondary form-action-bar__btn form-action-bar__btn--cancel"
onClick={onCancel}
disabled={saving}
aria-label={cancelLabel}
title={cancelLabel}
>
<ActionLabel Icon={X} long={cancelLabel} short="" saving={saving} />
</button>
) : null}
<div className="form-action-bar__primary-group">
{showSaveBtn ? (
<button
type={formId && !onSave ? 'submit' : 'button'}
form={formId && !onSave ? formId : undefined}
className={saveBtnClass}
disabled={saving}
onClick={onSave || undefined}
title={labelSave}
>
<ActionLabel Icon={Save} long={labelSave} short={shortSave} saving={saving} />
</button>
) : null}
{showCloseBtn ? (
<button
type={formId && !onSaveAndClose ? 'submit' : 'button'}
form={formId && !onSaveAndClose ? formId : undefined}
className={closeBtnClass}
disabled={saving}
onClick={onSaveAndClose || undefined}
title={saveAndCloseLabel}
>
<ActionLabel
Icon={Check}
long={saveAndCloseLabel}
short={shortClose}
saving={saving}
/>
</button>
) : null}
</div>
</div>
</div>
)
}