/** * Theme Builder — Formats panel (docs/chart-theming-scope.md §5). * * Default number and date formatting (`config.numberFormat`, * `normalizedNumberFormat`, `timeFormat`) plus the count-field title — the * brand-level "always show currency / thousands / short dates" knobs Vega-Lite * applies to guide labels, text marks, and tooltips. The values are d3-format / * d3-time-format strings; each field is free text with quick-fill presets for * the common patterns, since the pattern space is open (the JSON stays the way * to write any string). Each writes a minimal diff via the shared setter. */ import type { JsonObject } from '@core/spec-config'; import { asString, type ConfigPath, countSet, getConfigValue } from '@core/theme-controls'; import { useConfigSetter } from '../stores/CustomThemeStore'; import { Button } from './Button'; import { Accordion, type AccordionSection, TextRow } from './ThemeFields'; import styles from './ThemeFields.module.css'; const NUMBER: ConfigPath = ['numberFormat']; const NORMALIZED: ConfigPath = ['normalizedNumberFormat']; const TIME: ConfigPath = ['timeFormat']; const COUNT_TITLE: ConfigPath = ['countTitle']; interface Preset { /** The d3 pattern written into the config. */ code: string; /** A rendered example, shown as the chip label. */ sample: string; } const NUMBER_PRESETS: Preset[] = [ { code: ',', sample: '1,234' }, { code: '$,.2f', sample: '$1,234.00' }, { code: '.0%', sample: '12%' }, { code: '.2s', sample: '1.2k' }, { code: '+,', sample: '+1,234' }, ]; const TIME_PRESETS: Preset[] = [ { code: '%b %Y', sample: 'Jan 2026' }, { code: '%Y-%m-%d', sample: '2026-01-01' }, { code: '%b %-d', sample: 'Jan 1' }, { code: '%-d %b %Y', sample: '1 Jan 2026' }, ]; /** A row of quick-fill chips that write a preset pattern into a config key. */ function Presets({ presets, onPick }: { presets: Preset[]; onPick: (code: string) => void }) { return (
{presets.map((p) => ( ))}
); } export function FormatControls({ config }: { config: JsonObject }) { const set = useConfigSetter(); const sections: AccordionSection[] = [ { id: 'numbers', title: 'Numbers', hint: 'd3-format pattern for labels, text, and tooltips.', badge: countSet(config, [NUMBER, NORMALIZED]), children: ( <> set(NUMBER, v)} /> set(NUMBER, code)} /> set(NORMALIZED, v)} /> ), }, { id: 'dates', title: 'Dates', hint: 'd3-time-format pattern for raw time values.', badge: countSet(config, [TIME]), children: ( <> set(TIME, v)} /> set(TIME, code)} /> ), }, { id: 'labels', title: 'Labels', badge: countSet(config, [COUNT_TITLE]), children: ( set(COUNT_TITLE, v)} /> ), }, ]; return ; }