Files
sam-react-prod/claudedocs/guides/[GUIDE] print-area-utility.md
byeongcheolryu 386cd30bc0 feat(WEB): 입찰/계약/주문관리 기능 추가 및 견적 상세 리팩토링
- 입찰관리: 목록/상세/수정 페이지 및 목업 데이터
- 계약관리: 목록/상세/수정 페이지 구현
- 주문관리: 수주/발주 목록 및 상세 페이지 구현
- 견적 상세 폼: 섹션별 분리 및 hooks/utils 리팩토링
- 품목관리, 카테고리관리, 단가관리 기능 추가
- 현장설명회/협력업체 폼 개선
- 프린트 유틸리티 공통화 (print-utils.ts)
- 문서 모달 공통 컴포넌트 정리
- IntegratedListTemplateV2, StatCards 개선

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 18:59:04 +09:00

5.5 KiB

인쇄 모달 printArea 유틸리티 적용 가이드

작성일: 2026-01-02 적용 범위: 모든 인쇄 가능한 모달/다이얼로그

개요

기존 window.print() 방식은 Radix UI Dialog 포털 구조로 인해 CSS @media print 제어가 어렵고, 인쇄 시 모달 헤더/버튼이 함께 출력되거나 여러 페이지로 나뉘는 문제가 있었습니다.

이를 해결하기 위해 JavaScript 기반 printArea() 유틸리티를 도입하여 .print-area 영역만 새 창에서 인쇄하도록 통일했습니다.

공통 컴포넌트 변경

1. print-utils.ts (신규)

파일 위치: /src/lib/print-utils.ts

interface PrintOptions {
  title?: string;      // 브라우저 인쇄 다이얼로그에 표시될 제목
  styles?: string;     // 추가 CSS 스타일
  closeAfterPrint?: boolean; // 인쇄 후 창 닫기 (기본: true)
}

// 특정 요소 인쇄
export function printElement(
  elementOrSelector: HTMLElement | string,
  options?: PrintOptions
): void;

// .print-area 클래스 요소 인쇄 (주로 사용)
export function printArea(options?: PrintOptions): void;

동작 방식:

  1. 새 창 열기
  2. 현재 페이지의 스타일시트 복사
  3. .print-area 요소 내용 복제
  4. .print-hidden 요소 제거
  5. A4 용지에 맞는 인쇄 스타일 적용
  6. 자동 인쇄 실행 후 창 닫기

2. globals.css 인쇄 스타일 (간소화)

파일 위치: /src/app/globals.css

@media print {
  @page {
    size: A4 portrait;
    margin: 10mm;
  }

  * {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  html, body {
    background: white !important;
  }

  .print-hidden {
    display: none !important;
  }
}

적용된 모달 목록

컴포넌트 파일 경로 인쇄 제목
DocumentDetailModal src/components/approval/DocumentDetail/index.tsx 문서 타입별 (품의서, 기안서 등)
ProcessWorkLogPreviewModal src/components/process-management/ProcessWorkLogPreviewModal.tsx 작업일지 템플릿명
ReceivingReceiptDialog src/components/material/ReceivingManagement/ReceivingReceiptDialog.tsx 입고증 인쇄
WorkLogModal src/components/production/WorkerScreen/WorkLogModal.tsx 작업일지 인쇄
OrderDocumentModal src/components/orders/documents/OrderDocumentModal.tsx 계약서/거래명세서/발주서
ShipmentDetail src/components/outbound/ShipmentManagement/ShipmentDetail.tsx 출고증/거래명세서/납품확인서
EstimateDocumentModal src/components/business/juil/estimates/modals/EstimateDocumentModal.tsx 견적서 인쇄
ContractDocumentModal src/components/business/juil/contract/modals/ContractDocumentModal.tsx 계약서 인쇄

사용 방법

기본 사용법

import { printArea } from '@/lib/print-utils';

// 인쇄 핸들러
const handlePrint = () => {
  printArea({ title: '문서 인쇄' });
};

모달 구조 규칙

인쇄 가능한 모달은 다음 구조를 따라야 합니다:

<Dialog>
  <DialogContent>
    {/* 헤더 영역 - 인쇄에서 제외 */}
    <div className="print-hidden">
      <h2>문서 제목</h2>
      <Button onClick={handlePrint}>인쇄</Button>
      <Button onClick={onClose}>닫기</Button>
    </div>

    {/* 버튼 영역 - 인쇄에서 제외 */}
    <div className="print-hidden">
      <Button>수정</Button>
      <Button>인쇄</Button>
    </div>

    {/* 문서 영역 - 이 영역만 인쇄됨 */}
    <div className="print-area">
      {/* 실제 문서 내용 */}
    </div>
  </DialogContent>
</Dialog>

CSS 클래스 규칙

클래스 용도
.print-area 인쇄될 영역 (필수)
.print-hidden 인쇄에서 제외할 영역 (헤더, 버튼 등)

이전 방식 vs 새 방식

이전 방식 (문제점)

const handlePrint = () => {
  window.print(); // 전체 페이지 인쇄 시도
};

문제점:

  • Radix UI 포털 구조로 CSS @media print 제어 어려움
  • visibility: hidden 사용 시 빈 공간으로 인해 3-4페이지로 출력
  • display: none 사용 시 빈 페이지 출력
  • 모달 헤더/버튼이 함께 인쇄됨

새 방식 (해결)

const handlePrint = () => {
  printArea({ title: '문서 인쇄' });
};

장점:

  • 새 창에서 .print-area 내용만 추출하여 인쇄
  • Radix UI 포털 구조 영향 없음
  • 항상 1페이지로 깔끔하게 인쇄
  • 문서 내용만 인쇄 (헤더/버튼 제외)

새 인쇄 모달 추가 시

  1. printArea import 추가
  2. handlePrint 함수에서 printArea() 호출
  3. 모달 구조에 .print-hidden / .print-area 클래스 적용
import { printArea } from '@/lib/print-utils';

export function NewDocumentModal() {
  const handlePrint = () => {
    printArea({ title: '새 문서 인쇄' });
  };

  return (
    <Dialog>
      <DialogContent>
        <div className="print-hidden">
          {/* 헤더/버튼 */}
        </div>
        <div className="print-area">
          {/* 인쇄될 문서 내용 */}
        </div>
      </DialogContent>
    </Dialog>
  );
}

주의사항

  1. .print-area 클래스 필수: 인쇄 영역에 반드시 .print-area 클래스 적용
  2. 중첩 .print-area 금지: 하나의 모달에 .print-area는 하나만 존재해야 함
  3. 스타일 복제: 인쇄 시 현재 페이지의 스타일시트가 자동으로 복사됨
  4. 팝업 차단 주의: 브라우저 팝업 차단 시 인쇄 창이 열리지 않을 수 있음