/* ============================================================================
* 서명전에 — TDS Post 컴포넌트
* · 포스트 형식 줄글 (공지·이벤트·약관) 전용 컨테이너 묶음.
* · 8 서브:
* Post.H1 / Post.H2 / Post.H3 / Post.H4 — 시멘틱 h1~h4 + 기본 typography
* Post.Paragraph — 시멘틱 p (본문)
* Post.Ol / Post.Ul — 시멘틱 ol/ul (중첩 가능)
* Post.Li — 시멘틱 li (Ol/Ul 안에서만)
* Post.Hr — 시멘틱 hr (구분선)
*
* · 공통 props:
* typography "t1"~"t7" | "st1"~"st13"
* — 미지정 시 헤딩은 자기 기본값, 본문/리스트는 부모 상속
* paddingBottom number | string
* — 자기 아래 여백. number 면 `${n}px`, string 은 그대로.
*
* · Hr 만 typography 없음 — paddingBottom 만.
*
* · 디자인 원칙:
* - margin 은 CSS 에서 0 으로 초기화 — 위아래 간격 = paddingBottom 으로만 조립.
* - 헤딩은 굵게 + 살짝 음수 letter-spacing.
* - 리스트는 decimal/disc 기본, 중첩되어도 동일.
* - 본문 p 는 white-space: pre-wrap — `
` 또는 `\n` 모두 줄바꿈으로 인정.
* ========================================================================== */
// ----- typography → utility class 매핑 (Paragraph 와 동일 규칙) -----
function __postTypoClass(typo) {
if (!typo || typeof typo !== "string") return "";
let m = typo.match(/^t(\d+)$/i);
if (m) {
const n = parseInt(m[1], 10);
if (n >= 1 && n <= 7) return `ty-${n}`;
}
m = typo.match(/^st(\d+)$/i);
if (m) {
const n = parseInt(m[1], 10);
if (n >= 1 && n <= 13) return `sub-ty-${n}`;
}
if (window.console && console.warn) {
console.warn(
`[Post] \`typography\` 는 t1~t7 또는 st1~st13 만 가능해요. 받은 값: ${typo}`
);
}
return "";
}
// ----- paddingBottom 정규화 -----
function __postPb(pb) {
if (pb === undefined || pb === null || pb === "") return undefined;
if (typeof pb === "number" && Number.isFinite(pb)) return `${pb}px`;
return String(pb);
}
// ----- 공통 헤딩 팩토리 -----
function __makeHeading(Tag, defaultTypo, displayName) {
function Heading({
typography,
paddingBottom,
className = "",
style,
id,
children,
...rest
}) {
const typo = typography || defaultTypo;
const cls = [
"tds-post__h",
`tds-post__${Tag}`,
__postTypoClass(typo),
className,
].filter(Boolean).join(" ");
const pb = __postPb(paddingBottom);
const mergedStyle = pb !== undefined
? Object.assign({ paddingBottom: pb }, style || {})
: style;
return React.createElement(
Tag,
Object.assign({ id: id, className: cls, style: mergedStyle }, rest),
children
);
}
Heading.displayName = displayName;
return Heading;
}
// =============================================================================
// Root Post — 보통 서브만 쓰는데, 포스트 영역을 명시적으로 감싸고 싶을 때 사용
// =============================================================================
function Post({ className = "", style, id, children, ...rest }) {
const cls = ["tds-post", className].filter(Boolean).join(" ");
return (
본문 // ============================================================================= function PostParagraph({ typography, paddingBottom, className = "", style, id, children, ...rest }) { const cls = [ "tds-post__paragraph", __postTypoClass(typography), className, ].filter(Boolean).join(" "); const pb = __postPb(paddingBottom); const mergedStyle = pb !== undefined ? Object.assign({ paddingBottom: pb }, style || {}) : style; return (
{children}
); } // ============================================================================= // Post.Ol — 시멘틱