import { PencilSimpleRegularIcon } from "alouette-icons/phosphor-icons/PencilSimple"; import { type ReactNode, useId } from "react"; import type { Accent } from "../../core/AlouetteConfig"; import type { IconButtonProps } from "../actions/IconButton"; import { IconButton } from "../actions/IconButton"; import type { SVGIconElement } from "../primitives/Icon"; import { Text } from "../primitives/Text"; import { View } from "../primitives/View"; import { Box, type BoxProps } from "./Box"; export interface EditableSectionProps extends Pick { accent?: Accent; /** Heading of the section, and the label of the region for assistive tech. */ title: string; /** * Rendered beside the title — a Badge, or anything short. It stays out of * the region's accessible name, which is the title alone. */ titleBadge?: ReactNode; /** Muted helper text under the title. */ details?: ReactNode; /** Names the edit button for assistive tech — it has no visible text. */ editAriaLabel: string; editIcon?: SVGIconElement; /** Variant of the edit IconButton. Defaults to `tonal`, or `soft` when the * section has an `accent`, where a tonal ground would dissolve. */ editIconVariant?: IconButtonProps["variant"]; disabled?: boolean; onEdit: () => void; /** The read-only body: as many blocks as the section needs. */ children: ReactNode; } /** * A titled section holding a block of read-only content behind a single edit * affordance. Where EditableItem is one label with a summary that fits beside * it, this is a section whose value spans several lines. Owns no editor: pair * it with FormEditableSection for a react-hook-form modal, or compose your own * Modal from `onEdit`. * * It brings no material of its own — the caller picks it through `className`: * `surface` for a card, `surface lowered`, an outline, or nothing inside a * container that already has one. */ export function EditableSection({ title, titleBadge, details, editAriaLabel, editIcon = , editIconVariant, accent, className, disabled, onEdit, children, }: EditableSectionProps): ReactNode { const titleId = useId(); return ( {/* The title is sized to the edit button's own height, so the row it shares with the button adds no dead space above and below it — at text-lg it would be 13px shorter than the button, which no amount of alignment can absorb. */} {title} {/* A Badge carries `self-start` so it doesn't stretch in a column; in this row that pins it 3px above the title's center, so it is wrapped in a View the row can align. */} {titleBadge ? {titleBadge} : null} {details ? ( {details} ) : null} {children} ); }