import { useDevice } from '../DeviceToggle'; import { ROLES } from './roles'; /** * How big each role is, at the width being edited. * * ── The same four roles as Fonts ── * * A template asks for a role and gets both the face and the size, so this section is the one above it * with numbers instead of names. What that costs is worth knowing: a role used at two sizes on purpose * collapses to one — `font-sub` was three sizes across the site and is now a single choice. * * ── One value per field ── * * The tabs at the top of the panel say which width. Unset inherits the smaller one, so "the same * everywhere" is one choice. * * ── The empty option NAMES the size ── * * It said "Inherit (default)", which answers a question nobody asked. What somebody wants from that * dropdown is "what is it now", and a label that does not say makes them change the setting to find * out — which is the one way to lose the answer. * * So it names the size that will actually apply: the nearest smaller width that has one, or the * stylesheet's own, which the API reads out of styles.css rather than this file guessing. */ export type FontSizes = Partial>>>; const BREAKPOINT = { desktop: 'lg', tablet: 'md', mobile: 'base' } as const; const inherited = ( steps: Partial> | undefined, key: 'base' | 'md' | 'lg', ): string | null => { const below = { base: [], md: ['base'], lg: ['md', 'base'] } as const; for (const smaller of below[key]) { const step = steps?.[smaller]; if (step) return step; } return null; }; export const FontSizesTab = ({ sizes, steps, defaults, onChange, }: { sizes: FontSizes; /** The scale, sent by the API so this file holds no copy of it. */ steps: string[]; /** What each role is with nothing chosen, read from the site's stylesheet. */ defaults: Record; onChange: (sizes: FontSizes) => void; }) => { const [device] = useDevice(); const key = BREAKPOINT[device]; const set = (role: string, value: string) => { const at = { ...((sizes as Record>>)[role] ?? {}) }; // Removed rather than stored empty: an absence is what "inherit" means, all the way up. if (value === '') delete at[key]; else at[key] = value; const next = { ...(sizes as Record) }; if (Object.keys(at).length) next[role] = at; else delete next[role]; onChange(next as FontSizes); }; return (
{ROLES.map((role) => { const current = sizes[role.size]; const own = current?.[key]; // The nearest smaller width that has one, or the stylesheet's. Either way, a size to read. const from = inherited(current, key) ?? defaults[role.size]; return (
); })}
); };