import React, { type ReactNode } from "react"; /** * Shared icon renderers for theme knob controls. * * Each icon function accepts a pre-resolved foreground `color` string so * that both the TanStack Devtools panel and the Storybook addon can use * the same rendering logic with their own color schemes. * * TanStack: `ic(active, isDark)` → theme-adaptive foreground * Storybook: `ic(active)` → purple accent for active, gray for inactive */ export function fillIcon(value: string, color: string): ReactNode { if (value === "filled") { return
; } return
; } export function spaceIcon(value: string, color: string): ReactNode { const size = ({ small: 8, medium: 12, large: 16 } as Record)[value] ?? 12; return
; } export function sizeIcon(value: string, color: string): ReactNode { const height = ({ small: 8, medium: 11, large: 14 } as Record)[value] ?? 11; return
; } export function densityIcon(value: string, color: string): ReactNode { // Comfortable = taller stack; compact = compressed stack. const gap = value === "compact" ? 1 : 2; const barH = value === "compact" ? 3 : 4; return (
); } export function borderRadiusIcon(value: string, color: string): ReactNode { const radius = ({ none: 0, small: 2, medium: 4, large: 7, full: 10 } as Record)[value] ?? 0; return (
); } export function cornerSmoothingIcon(value: string, color: string): ReactNode { // Same nominal corner size, different curvature: circular-arc rounded // rect for `round`, continuous-curvature superellipse for `smooth`. const smooth = value === "smooth"; return ( {value} {smooth ? ( ) : ( )} ); } export function borderWidthIcon(value: string, color: string): ReactNode { if (value === "none") { return (
); } const width = ({ small: 1, medium: 1.5, large: 2 } as Record)[value] ?? 1; return (
); } export function elevationIcon(value: string, color: string, _isDark: boolean): ReactNode { const shadowColor = "rgba(128,128,128,0.55)"; const offset = ({ none: 0, small: 1, medium: 2, large: 3 } as Record)[value] ?? 0; const shadowSize = ({ none: 0, small: 10, medium: 11, large: 12 } as Record)[value] ?? 0; const squareSize = 10; const total = squareSize + offset * 2 + 1; if (offset === 0) { return (
); } return (
); } export function textAccentIcon(value: string, color: string): ReactNode { const weight = value === "low" ? 300 : value === "medium" ? 500 : 700; const opacity = value === "low" ? 0.35 : value === "medium" ? 0.7 : 1; return ( Aa ); } const fontCategoryStyles: Record< string, { family: string; label: string; letterSpacing?: string; style?: string } > = { "sans-serif": { family: "-apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif", label: "Aa", }, serif: { family: "Georgia, 'Times New Roman', Times, serif", label: "Aa" }, mono: { family: "'SF Mono', 'Cascadia Code', Menlo, monospace", label: "Aa" }, slab: { family: "'Rockwell', 'Courier New', serif", label: "Aa" }, rounded: { family: "'Nunito', 'Varela Round', system-ui, sans-serif", label: "Aa" }, condensed: { family: "'Arial Narrow', sans-serif", label: "Aa", letterSpacing: "-0.03em" }, cursive: { family: "'Segoe Script', cursive", label: "Aa", style: "italic" }, handwriting: { family: "'Comic Sans MS', 'Caveat', cursive", label: "Aa" }, pixel: { family: "'Courier New', monospace", label: "Aa", letterSpacing: "0.05em" }, blackletter: { family: "'Old English Text MT', serif", label: "Aa" }, geometric: { family: "'Century Gothic', 'Futura', sans-serif", label: "Aa" }, }; export function headingFontIcon(value: string, color: string): ReactNode { const s = fontCategoryStyles[value] ?? { family: "inherit", label: "Aa" }; return ( {s.label} ); } export function bodyFontIcon(value: string, color: string): ReactNode { const s = fontCategoryStyles[value] ?? { family: "inherit", label: "Aa" }; return ( {s.label} ); } export function fontWeightIcon(value: string, color: string): ReactNode { const weight = ({ light: 300, regular: 400, bold: 700 } as Record)[value] ?? 400; return ( W ); } export function modeIcon(value: "system" | "light" | "dark", color: string): ReactNode { const base = { width: 14, height: 14, borderRadius: "50%" } as const; if (value === "system") { return (
); } if (value === "light") { return
; } return
; } /** Compact text glyph used by house-decision knobs in the panel. */ function glyph(label: string, color: string, size = 9): ReactNode { return ( {label} ); } export function fieldLabelPlacementIcon(value: string, color: string): ReactNode { if (value === "side") return glyph("⊟", color, 12); if (value === "floating") return glyph("⬚", color, 12); return glyph("⊞", color, 12); // top } export function requiredMarkingIcon(value: string, color: string): ReactNode { if (value === "asterisk") return glyph("*", color, 14); if (value === "optional") return glyph("opt", color, 8); return glyph("min", color, 8); // minority } export function tableZebraIcon(value: string, color: string): ReactNode { const on = value === "on"; return (
); } export function bulkBarPlacementIcon(value: string, color: string): ReactNode { const top = value !== "bottom"; return (
); } export function selectAllScopeIcon(value: string, color: string): ReactNode { const filtered = value === "filtered"; // Three rows; page scope highlights only the top rows (current page), // filtered scope highlights all rows (all matching). return (
); } export function timestampStyleIcon(value: string, color: string): ReactNode { return glyph(value === "relative" ? "~t" : "12:00", color, value === "relative" ? 10 : 7); } export function disabledStyleIcon(value: string, color: string): ReactNode { if (value === "dimWhole") { return (
); } // keepLabel — solid label bar over a dimmed body return (
); } export function formAutofocusIcon(value: string, color: string): ReactNode { return (
); }