npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@depart-os/text-diff

v0.4.1

Published

Inline-tag (1-round) text diff utilities for React (Korean/English) — used by depart-os proposal review flow.

Downloads

226

Readme

@depart-os/text-diff

인라인 태그 기반 1라운드 텍스트 diff 유틸리티. 한국어·영어 텍스트의 변경 부분을 <del>/<ins> 태그로 단일 string 에 마킹하고, React 컴포넌트로 모드별 렌더한다.

Install

pnpm add @depart-os/text-diff
# or: npm install @depart-os/text-diff / yarn add @depart-os/text-diff

저장 포맷

원본:    "신호일 수 있어요"
수정후:  "신호<del>일 수 있어요</del><ins>입니다</ins>"
  • <del> : 원본에 있다가 삭제
  • <ins> : 새로 추가
  • 태그 밖 : 양쪽 공통

1라운드 전용. 같은 문서를 두 번 이상 누적 수정하는 워크플로우는 지원하지 않는다. 매 수정마다 항상 최초 원본 vs 새 수정본 으로 새 태그 string 을 만든다.

Usage

빌더 측 — 수정 전송 시 태그 string 생성

import { generateTagged } from "@depart-os/text-diff";

async function submitEdit(originalContent: string, newContent: string) {
  const tagged = generateTagged(originalContent, newContent);
  // tagged === "신호<del>일 수 있어요</del><ins>입니다</ins>"
  await api.put("/captions/123", { content: tagged });
}

받는 쪽 — 모드별 렌더

import { WordDiff } from "@depart-os/text-diff";

function ReviewPanel({ content }: { content: string }) {
  return (
    <>
      <section>
        <h3>변경사항</h3>
        <WordDiff content={content} mode="diff" />
      </section>
      <section>
        <h3>수정본</h3>
        <WordDiff content={content} mode="after" />
      </section>
      <section>
        <h3>원본</h3>
        <WordDiff content={content} mode="before" />
      </section>
    </>
  );
}

추가된 단어는 파란 톤(bg-blue-100), 삭제된 단어는 분홍 톤(bg-rose-50)에 취소선으로 표시된다.

양방향 협업 (편집 ↔ 컨펌)

A 측이 수정해서 B 측에 보내고, B 가 다시 수정해서 A 에 보내는 ping-pong 흐름:

import { extractAfter, generateTagged } from "@depart-os/text-diff";

// 받았을 때 — textarea 초기값은 직전 상대 시안의 plain
function startEditing(serverContent: string) {
  return extractAfter(serverContent);
}

// 보낼 때 — 새 tagged = 직전 상대 시안 vs 내 새 시안
async function submitMyEdit(serverContent: string, myDraft: string) {
  const baseline = extractAfter(serverContent);
  const newTagged = generateTagged(baseline, myDraft);
  await api.put("/...", { content: newTagged });
}

서버는 매번 새 tagged 로 덮어씀. DB 컬럼 1개로 무한 라운드 가능. extractAfter 가 plain 도 그대로 통과시키므로 기존 plain 데이터와도 자동 호환.

Plain text 호환

태그 없는 plain text 를 넘기면 모든 모드에서 그대로 렌더된다 (변경 표시 없음). 기존 데이터와 신규 데이터를 한 컬럼에 섞어 보관해도 안전하다.

Tailwind v4 설정

이 패키지는 Tailwind v3/v4 클래스 문자열을 그대로 출력한다. 소비측 프로젝트의 Tailwind 가 패키지 dist 도 스캔해야 색이 입혀진다.

Tailwind v4 (CSS-first) — globals.css 에서:

@import "tailwindcss";
@source '../../node_modules/@depart-os/text-diff/dist';

@source 의 상대 경로는 그 CSS 파일의 위치 기준으로 조정한다.

Tailwind v3 — tailwind.config.js 의 content 에 추가:

export default {
  content: [
    "./src/**/*.{ts,tsx}",
    "./node_modules/@depart-os/text-diff/dist/**/*.{js,mjs,cjs}",
  ],
};

API

generateTagged(before: string, after: string): string

LCS 기반 워드 단위 diff 를 계산하고 <del>/<ins> 태그로 직렬화한 단일 string 을 반환. 한글/영문/공백/구두점을 각각의 토큰으로 분리.

extractBefore(content: string): string

tagged string 에서 "직전 baseline" plain text 를 추출. <ins> 블록은 제거하고 <del> 내용만 살림. plain text 입력은 no-op 으로 그대로 반환.

extractBefore("신호<del>일 수 있어요</del><ins>입니다</ins>");
// → '신호일 수 있어요'

extractAfter(content: string): string

tagged string 에서 "최신 시안" plain text 를 추출. <del> 블록은 제거하고 <ins> 내용만 살림. plain text 입력은 no-op 으로 그대로 반환.

extractAfter("신호<del>일 수 있어요</del><ins>입니다</ins>");
// → '신호입니다'

라운드트립 보장: extractBefore(generateTagged(a, b)) === a && extractAfter(generateTagged(a, b)) === b.

<WordDiff content mode className? />

태그 문자열을 파싱해서 mode 별로 렌더.

| mode | 동작 | | ---------- | --------------------------------------------------------- | | 'diff' | <del> 분홍+취소선, <ins> 파란 강조, eq 일반 | | 'after' | <del> 제외, <ins> 내용만 살림 → 수정 후 평문처럼 보임 | | 'before' | <ins> 제외, <del> 내용만 살림 → 수정 전 평문처럼 보임 |

className 은 컨테이너 <p> 에 추가된다.

인라인 서식 (굵게·기울임·밑줄)

v0.3.0 부터 인라인 서식 3종을 diff 와 공존시켜 저장·렌더할 수 있다.

  • 서식은 <strong>/<em>/<u> 태그로 문자열에 저장된다.
  • 중첩 규칙: diff 태그(<del>/<ins>)가 바깥, 서식 태그가 안쪽. 예: <ins><strong>x</strong></ins>
  • 서식만 바뀐 단어도 변경으로 취급되어 <del>(이전 서식) + <ins>(새 서식)으로 표시된다.
  • 서식 태그가 없는 문자열은 v0.2.0 과 완전히 동일하게 동작한다 (마이그레이션 불필요).
  • 태그 외 텍스트의 & < > 는 HTML 엔티티로 이스케이프되어 저장되고, 렌더 시 안전하게 복원된다.
import { InlineEditor, WordDiff } from '@depart-os/text-diff'

// 편집: contentEditable + 굵게·기울임·밑줄 툴바
<InlineEditor value={value} onChange={setValue} />

// 표시: 서식이 diff 하이라이트 안에 중첩 렌더됨
<WordDiff content={saved} mode="diff" />

<InlineEditor value onChange className? placeholder? marks? />

contentEditable 기반 인라인 에디터. 툴바 버튼(굵게·기울임·밑줄)으로 서식을 토글하고, onChange 로 정규화된 태그 문자열을 돌려준다. 붙여넣기는 평문으로만 삽입된다. marks 로 노출할 버튼을 제한할 수 있다 (기본 ['b','i','u']).

domToTagged(root: HTMLElement): string

편집 영역 DOM 을 정규 태그 문자열로 직렬화. <b>/<i>/인라인 스타일(bold·italic·underline)을 <strong>/<em>/<u> 로 정규화하고 텍스트를 이스케이프한다.

taggedToHtml(content: string): string

저장 문자열(잔여 <del>/<ins> 포함 가능)을 after 기준의 편집용 innerHTML 로 변환.

Sanitization

<del>/<ins> 는 HTML5 표준 시맨틱 태그라 DOMPurify 등 대부분의 sanitizer 기본 whitelist 에 포함된다. 통상 별도 작업 없이 통과한다. 보수적인 환경이면 운영 적용 전 PUT → GET 라운드트립을 한 번 확인.

License

MIT