diff --git a/A00_Common/spreadsheet/spreadsheet_clipboard.ts b/A00_Common/spreadsheet/spreadsheet_clipboard.ts index 5b5e0093..2c03858b 100644 --- a/A00_Common/spreadsheet/spreadsheet_clipboard.ts +++ b/A00_Common/spreadsheet/spreadsheet_clipboard.ts @@ -252,29 +252,39 @@ function unescapeMsoNumFmt(v: string): string { return v.replace(/^"|"$/g, "").replace(/\\(.)/g, "$1"); } -const BORDER_STYLE_MAP: Record = { - solid: "thin", - dashed: "dashed", - dotted: "dotted", - double: "double", -}; +/** pt 굵기 → 우리 선 종류(엑셀 내보내기 흔한 값 기준 — hairline ≈ .5pt 이하 · thin ≈ 1pt · medium ≈ + * 1.5~2pt · thick ≈ 2pt 넘음). `solid` 아닌 것은 굵기와 상관없이 그 모양. */ +function ptToBorderLine(pt: number, cssStyle: string): BorderLine { + if (cssStyle === "dashed") return "dashed"; + if (cssStyle === "dotted") return "dotted"; + if (cssStyle === "double") return "double"; + if (pt <= 0.5) return "hair"; + if (pt <= 1.25) return "thin"; + if (pt <= 2) return "medium"; + return "thick"; +} function parseBorderShorthand(v: string): BorderSide | undefined { const m = /([\d.]+)\s*(?:pt|px)\s+(solid|dashed|dotted|double)\s*([^;]*)/i.exec(v); if (!m) return undefined; - const 선 = BORDER_STYLE_MAP[m[2].toLowerCase()] ?? "thin"; + const 선 = ptToBorderLine(Number(m[1]), m[2].toLowerCase()); const 색 = cssColorToHex(m[3]); return 색 ? { 선, 색 } : { 선 }; } -/** `` 안 `.xl65 {...}` 짜임(엑셀이 인라인 대신 클래스로 서식을 실을 때) → 클래스별 선언. */ +/** `` 안 `.xl65 {...}` · `.xl65, .xl70 {...}`(묶음 선택자) 짜임(엑셀이 인라인 대신 + * 클래스로 서식을 실을 때) → 클래스별 선언(같은 클래스가 여러 규칙에 나오면 뒤엣것이 이김). */ function parseClassRules(doc: Document): Record> { const css = Array.from(doc.querySelectorAll("style")) .map((s) => s.textContent ?? "") .join("\n"); const rules: Record> = {}; - for (const m of css.matchAll(/\.([a-zA-Z0-9_-]+)\s*\{([^}]*)\}/g)) { - rules[m[1]] = parseStyleAttr(m[2]); + for (const m of css.matchAll(/([^{}]+)\{([^}]*)\}/g)) { + const decls = parseStyleAttr(m[2]); + for (const selectorPart of m[1].split(",")) { + const cls = /\.([a-zA-Z0-9_-]+)\s*$/.exec(selectorPart.trim()); + if (cls) Object.assign((rules[cls[1]] ??= {}), decls); + } } return rules; } diff --git a/resources/tester/spreadsheet/fixture_excel_style_paste.html b/resources/tester/spreadsheet/fixture_excel_style_paste.html new file mode 100644 index 00000000..139c4167 --- /dev/null +++ b/resources/tester/spreadsheet/fixture_excel_style_paste.html @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
품목수량금액
터파기1201200000
메우기80800000
합계2002000000
+ + +