"use client"; import type { TextBlockProps } from "@/features/editor/state/editorStore"; import { PropertySliderField } from "@/features/editor/components/PropertySliderField"; import { ColorPickerField, TEXT_COLOR_PALETTE } from "@/features/editor/components/ColorPickerField"; import { NumericPropertyControl } from "@/features/editor/components/NumericPropertyControl"; export type TextPropertiesPanelProps = { textProps: TextBlockProps; selectedBlockId: string; updateBlock: (id: string, partial: Partial) => void; editingBlockId: string | null; setEditingText: (value: string) => void; }; export function TextPropertiesPanel({ textProps, selectedBlockId, updateBlock, editingBlockId, setEditingText, }: TextPropertiesPanelProps) { const fontSizeMode = textProps.fontSizeMode ?? "scale"; const fallbackScale = textProps.size === "sm" ? "sm" : textProps.size === "lg" ? "lg" : "base"; const fontSizeScale = textProps.fontSizeScale ?? fallbackScale; const lineHeightMode = textProps.lineHeightMode ?? "scale"; const lineHeightScale = textProps.lineHeightScale ?? "normal"; const fontWeightMode = textProps.fontWeightMode ?? "scale"; const fontWeightScale = textProps.fontWeightScale ?? "normal"; const colorPalette = textProps.colorPalette ?? "default"; const maxWidthMode = textProps.maxWidthMode ?? "scale"; const maxWidthScale = textProps.maxWidthScale ?? "none"; const fontSizeScaleToPx: Record, number> = { xs: 12, sm: 14, base: 16, lg: 18, xl: 20, "2xl": 24, "3xl": 30, }; const parsedFontSize = (() => { const raw = textProps.fontSizeCustom ?? ""; const match = raw.match(/([0-9]+(?:\.[0-9]+)?)/); if (match) return Number(match[1]); return fontSizeScaleToPx[fontSizeScale]; })(); const parsedLineHeight = (() => { const raw = textProps.lineHeightCustom ?? ""; const match = raw.match(/(-?[0-9]+(?:\.[0-9]+)?)/); if (match) return Number(match[1]); return 1.5; })(); // 글자 간격: 내부 저장은 em 이지만, UI 에서는 px 단위로 보여준다. const parsedLetterSpacingPx = (() => { const raw = textProps.letterSpacingCustom ?? ""; const match = raw.match(/(-?[0-9]+(?:\.[0-9]+)?)/); if (match) { const em = Number(match[1]); if (Number.isFinite(em)) { return em * 16; // 1em = 16px 기준으로 환산 } } return 0; })(); const letterSpacingPreset = (() => { const px = parsedLetterSpacingPx; if (px <= -1) return "tighter" as const; if (px < 0) return "tight" as const; if (px < 1) return "normal" as const; if (px < 3) return "wide" as const; return "wider" as const; })(); const parsedFontWeight = (() => { const raw = textProps.fontWeightCustom ?? ""; const match = raw.match(/([0-9]{3})/); if (match) return Number(match[1]); switch (fontWeightScale) { case "medium": return 500; case "semibold": return 600; case "bold": return 700; default: return 400; } })(); return ( <>

선택한 텍스트 블록 내용