Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | 318x 318x 668x | /**
* SectionHeader -- shared uppercase section label with optional icon-button actions.
*
* Used atop every sidebar nav (Tasks, Environments, Schedules, Personas, Coordination)
* to provide a consistent header strip. Actions (filter, group, sort, add, etc.) only
* render when provided.
*
* @module
*/
import { type JSX, type ReactNode } from "react";
import { Tooltip } from "./Tooltip.js";
import styles from "./SectionHeader.module.scss";
/** A single action button rendered in the SectionHeader trailing slot. */
export interface SectionHeaderAction {
/** Unique key for React rendering. */
key: string;
/** Icon element (typically a lucide-react component). */
icon: ReactNode;
/** Tooltip text shown on hover. */
tooltip: string;
/** Accessible label for the button. */
ariaLabel: string;
/** Click handler. */
onClick: () => void;
/** Whether this action is currently active (renders with green accent). */
active?: boolean;
/** aria-pressed value for toggle buttons. */
ariaPressed?: boolean;
/** aria-haspopup value for buttons that open menus. */
ariaHasPopup?: boolean;
/** aria-expanded value for buttons that control a popup. */
ariaExpanded?: boolean;
/** Optional data-testid for the button. */
testId?: string;
}
/** Props for the {@link SectionHeader} component. */
export interface SectionHeaderProps {
/** Section title text (rendered uppercase via section-label mixin). */
title: string;
/** Optional action buttons rendered in the trailing slot. Only renders the actions container when non-empty. */
actions?: SectionHeaderAction[];
/** Optional data-testid for the header root. */
"data-testid"?: string;
}
/** Uppercase section label with optional trailing icon-button actions. */
export function SectionHeader({
title,
actions,
"data-testid": testId,
}: SectionHeaderProps): JSX.Element {
const hasActions = actions !== undefined && actions.length > 0;
return (
<div className={styles.header} data-testid={testId}>
<span className={styles.title}>{title}</span>
{hasActions && (
<div className={styles.actions}>
{actions.map((action) => (
<Tooltip key={action.key} text={action.tooltip}>
<button
type="button"
className={`${styles.actionButton} ${action.active ? styles.actionActive : ""}`}
onClick={action.onClick}
aria-label={action.ariaLabel}
aria-pressed={action.ariaPressed}
aria-haspopup={action.ariaHasPopup}
aria-expanded={action.ariaExpanded}
data-testid={action.testId}
>
{action.icon}
</button>
</Tooltip>
))}
</div>
)}
</div>
);
}
|