86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo } from "react";
|
|
import type { TextRendererProps } from "./types";
|
|
|
|
const VERTICAL_ALIGN_MAP: Record<string, string> = {
|
|
top: "flex-start",
|
|
middle: "center",
|
|
bottom: "flex-end",
|
|
};
|
|
|
|
interface ConditionalStyleRule {
|
|
value: string;
|
|
backgroundColor?: string;
|
|
fontColor?: string;
|
|
}
|
|
|
|
function resolveConditionalStyles(
|
|
component: TextRendererProps["component"],
|
|
displayValue: string,
|
|
): { backgroundColor?: string; fontColor?: string } {
|
|
const rules = component.conditionalStyles as ConditionalStyleRule[] | undefined;
|
|
if (!rules || !Array.isArray(rules) || rules.length === 0) {
|
|
return {};
|
|
}
|
|
const normalizedValue = displayValue.trim();
|
|
const matched = rules.find((r) => r.value === normalizedValue);
|
|
if (!matched) return {};
|
|
return {
|
|
backgroundColor: matched.backgroundColor,
|
|
fontColor: matched.fontColor,
|
|
};
|
|
}
|
|
|
|
export function TextRenderer({ component, displayValue }: TextRendererProps) {
|
|
const isOverflowHidden =
|
|
component.textOverflow === "clip" || component.textOverflow === "ellipsis";
|
|
|
|
const conditionalOverrides = useMemo(
|
|
() => resolveConditionalStyles(component, displayValue),
|
|
[component, displayValue],
|
|
);
|
|
|
|
const bgColor = conditionalOverrides.backgroundColor || component.backgroundColor || undefined;
|
|
const fgColor = conditionalOverrides.fontColor || component.fontColor || "#000000";
|
|
|
|
return (
|
|
<div
|
|
className="h-full w-full"
|
|
style={{
|
|
display: "flex",
|
|
alignItems: VERTICAL_ALIGN_MAP[component.verticalAlign || "top"] || "flex-start",
|
|
backgroundColor: bgColor,
|
|
border:
|
|
(component.borderWidth ?? 0) > 0
|
|
? `${component.borderWidth}px solid ${component.borderColor || "#d1d5db"}`
|
|
: undefined,
|
|
borderRadius: component.borderRadius ? `${component.borderRadius}px` : undefined,
|
|
overflow: "hidden",
|
|
}}
|
|
>
|
|
<div
|
|
className="w-full"
|
|
style={{
|
|
fontSize: `${component.fontSize || 12}px`,
|
|
fontFamily: component.fontFamily || "Malgun Gothic",
|
|
color: fgColor,
|
|
fontWeight: component.fontWeight || "normal",
|
|
fontStyle: component.fontStyle || "normal",
|
|
textAlign: (component.textAlign as "left" | "center" | "right") || "left",
|
|
textDecoration: component.textDecoration || "none",
|
|
lineHeight: component.lineHeight || 1.4,
|
|
letterSpacing: component.letterSpacing ? `${component.letterSpacing}px` : undefined,
|
|
whiteSpace: isOverflowHidden ? "nowrap" : "pre-wrap",
|
|
overflow: "hidden",
|
|
textOverflow: component.textOverflow === "ellipsis" ? "ellipsis" : undefined,
|
|
wordBreak: !isOverflowHidden ? "break-word" : undefined,
|
|
maxHeight: "100%",
|
|
}}
|
|
>
|
|
{displayValue}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|