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

@shnea/blocknote

v0.1.5

Published

Reusable BlockNote editor and JSON viewer components.

Readme

@shnea/blocknote

BlockNote 기반 React 에디터와 JSON 뷰어를 재사용하기 위한 패키지입니다.

저장 형식은 BlockNote 문서 JSON 문자열만 사용합니다. Markdown 저장 기능은 제공하지 않지만, 에디터에 Markdown 텍스트를 붙여 넣으면 BlockNote 기본 paste 동작으로 블록 변환됩니다.

  • 샘플 페이지: https://bn.shnea.kr
  • 참고 페이지: https://www.blocknotejs.org

설치

npm install @shnea/blocknote

@blocknote/*, @mantine/* 의존성은 패키지에 포함되어 함께 설치됩니다. React 앱이 아니라면 react, react-dom은 별도로 필요하지만, Next.js나 Vite React 프로젝트라면 보통 이미 설치되어 있습니다.

CSS도 함께 import해야 합니다.

import "@shnea/blocknote/style.css";

기본 사용법

import { useState } from "react";
import { BlockNoteEditor, BlockNoteViewer } from "@shnea/blocknote";
import "@shnea/blocknote/style.css";

export function Example() {
  const [json, setJson] = useState("");

  return (
    <>
      <BlockNoteEditor value={json} onChange={setJson} />
      <BlockNoteViewer value={json} />
    </>
  );
}

BlockNoteEditorvalue로 JSON 문자열을 받고, 변경 시 onChange로 JSON 문자열을 반환합니다. BlockNoteViewer도 같은 JSON 문자열을 읽기 전용으로 렌더링합니다.

폰트 사용법

폰트는 패키지 안에 고정하지 않고, 사용하는 애플리케이션에서 목록만 넘깁니다. 사용자는 텍스트를 선택한 뒤 포맷 툴바의 폰트 메뉴에서 적용합니다. 이미 적용된 폰트를 다시 누르면 해당 폰트가 해제됩니다.

가장 단순한 형태는 key, label, value, url을 가진 배열입니다.

import { BlockNoteEditor, BlockNoteViewer, type FontFamilyOption } from "@shnea/blocknote";

const fonts: FontFamilyOption[] = [
  {
    key: "pretendard",
    label: "Pretendard",
    value: "\"Pretendard\", sans-serif",
    url: "https://cdnjs.cloudflare.com/ajax/libs/pretendard/1.2.1/static/woff2/Pretendard-Regular.woff2"
  },
  {
    key: "neo-dunggeunmo",
    label: "Neo둥근모",
    value: "\"NeoDunggeunmo\", monospace",
    url: "https://cdn.jsdelivr.net/gh/projectnoonnu/[email protected]/NeoDunggeunmo.woff",
    format: "woff"
  }
];

export function Example() {
  const [json, setJson] = useState("");

  return (
    <>
      <BlockNoteEditor
        value={json}
        onChange={setJson}
        fontFamilies={fonts}
      />
      <BlockNoteViewer value={json} fontFamilies={fonts} />
    </>
  );
}

Google Fonts처럼 CSS 파일을 불러와야 하는 폰트는 stylesheetUrl을 사용합니다.

const fonts: FontFamilyOption[] = [
  {
    key: "noto-sans-kr",
    label: "Noto Sans KR",
    value: "\"Noto Sans KR\", sans-serif",
    stylesheetUrl: "https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;600&display=swap"
  }
];

한 폰트에 여러 굵기를 넣고 싶으면 faces를 사용합니다.

const fonts: FontFamilyOption[] = [
    {
        key: "pretendard",
        label: "Pretendard",
        value: "\"Pretendard\", sans-serif",
        faces: [
            {
                url: "https://cdnjs.cloudflare.com/ajax/libs/pretendard/1.2.1/static/woff2/Pretendard-Regular.woff2",
                weight: "400"
            },
            {
                url: "https://cdnjs.cloudflare.com/ajax/libs/pretendard/1.2.1/static/woff2/Pretendard-SemiBold.woff2",
                weight: "600"
            }
        ]
    },
    {
        key: "noto-sans-kr",
        label: "Noto Sans KR",
        value: "\"Noto Sans KR\", sans-serif",
        stylesheetUrl: "https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;600&display=swap"
    }
];

폰트 크기는 기본 목록이 내장되어 있어 별도 설정 없이 포맷 툴바에 표시됩니다. 기본값 대신 직접 지정하고 싶으면 fontSizes를 넘기면 됩니다. 크기도 이미 적용된 값을 다시 누르면 해제됩니다.

<BlockNoteEditor
  value={json}
  onChange={setJson}
  fontFamilies={fonts}
  fontSizes={[
    { label: "14px", value: "14px" },
    { label: "18px", value: "18px" },
    { label: "24px", value: "24px" }
  ]}
/>

에디터에서 선택한 폰트와 크기는 문서 JSON 안에 inline style로 저장됩니다. 읽기 전용 화면에서도 같은 폰트를 보이게 하려면 BlockNoteViewer에도 같은 fontFamilies 배열을 넘기세요.

테마 사용법

BlockNoteEditorBlockNoteViewer 모두 theme을 받을 수 있습니다. 문자열 테마는 "light" 또는 "dark"를 사용합니다. BlockNoteViewer의 기본값은 기존 동작과 같은 "light"입니다.

<BlockNoteEditor value={json} onChange={setJson} theme="dark" />
<BlockNoteViewer value={json} theme="dark" />

BlockNote Mantine 테마 객체도 넘길 수 있습니다.

import type { BlockNoteTheme } from "@shnea/blocknote";

const theme: BlockNoteTheme = {
  colors: {
    editor: {
      text: "#111827",
      background: "#ffffff"
    }
  },
  fontFamily: "\"Pretendard\", sans-serif",
  borderRadius: 6
};

<BlockNoteEditor value={json} onChange={setJson} theme={theme} />
<BlockNoteViewer value={json} theme={theme} />

라이트/다크 테마를 함께 정의하려면 { light, dark } 형태로 넘길 수 있습니다.

Editor Props

export type BlockNoteEditorProps = {
  value?: string;
  className?: string;
  editable?: boolean;
  theme?: BlockNoteTheme;
  fontFamilies?: readonly FontFamilyOption[];
  fontSizes?: readonly FontSizeOption[];
  onChange?: (json: string) => void;
  uploadFile?: (file: File) => Promise<string>;
};
  • value: BlockNote 문서 JSON 문자열입니다. 비어 있으면 빈 에디터로 시작합니다.
  • className: 내부 BlockNoteView에 추가할 클래스 이름입니다.
  • onChange: 에디터 문서가 바뀔 때 JSON.stringify(editor.document) 결과를 받습니다.
  • editable: false면 편집을 막습니다.
  • theme: "light", "dark", BlockNote Mantine 테마 객체, 또는 { light, dark } 테마 객체를 넘깁니다.
  • fontFamilies: 선택 툴바에 표시할 폰트 목록입니다. 선택 시 필요한 폰트 CSS를 자동으로 로드합니다.
  • fontSizes: 선택 툴바에 표시할 폰트 크기 목록입니다. 넘기지 않으면 기본 크기 목록을 사용합니다.
  • uploadFile: 이미지/파일 업로드 처리를 애플리케이션에서 주입합니다. 반환값은 에디터에 삽입할 URL입니다.

Viewer Props

export type BlockNoteViewerProps = {
  value?: string;
  className?: string;
  theme?: BlockNoteTheme;
  fontFamilies?: readonly FontFamilyOption[];
  enableImageModal?: boolean;
};
  • value: BlockNote 문서 JSON 문자열입니다. 비어 있으면 빈 문서를 렌더링합니다.
  • className: 내부 BlockNoteView에 추가할 클래스 이름입니다.
  • theme: "light", "dark", BlockNote Mantine 테마 객체, 또는 { light, dark } 테마 객체를 넘깁니다. 기본값은 "light"입니다.
  • fontFamilies: 문서 JSON에 저장된 폰트를 뷰어에서도 렌더링할 수 있도록 같은 폰트 목록을 넘깁니다.
  • enableImageModal: 기본값은 true입니다. 이미지 클릭 시 확대 모달을 엽니다.

모바일 화면에서는 뷰어의 좌우 여백과 중첩 블록 들여쓰기 간격이 데스크톱보다 좁게 적용됩니다.

파일 업로드 원칙

이 패키지는 특정 파일 서비스에 결합하지 않습니다. file-service도 패키지 내부에서 자동으로 호출하지 않습니다.

각 애플리케이션은 자기 환경에 맞게 업로드 API를 개별적으로 만들고, 그 API를 호출하는 uploadFile 함수만 BlockNoteEditor에 넘겨야 합니다.

권장 구조:

브라우저
  -> 애플리케이션 API route 또는 백엔드
    -> 각 프로젝트에서 선택한 파일 저장소

이 구조를 쓰는 이유:

  • 브라우저에 업로드 토큰이나 내부 파일 서비스 주소를 노출하지 않습니다.
  • 프로젝트마다 인증, 저장 위치, 보관 정책, 에러 처리를 다르게 가져갈 수 있습니다.
  • @shnea/blocknote 패키지는 에디터/뷰어 역할만 유지합니다.

예시:

<BlockNoteEditor
  value={json}
  onChange={setJson}
  uploadFile={async (file) => {
    const formData = new FormData();
    formData.append("file", file);

    const response = await fetch("/api/upload", {
      method: "POST",
      body: formData
    });

    const data = await response.json();

    if (!response.ok || !data.previewUrl) {
      throw new Error(data.error ?? "Upload failed");
    }

    return data.previewUrl;
  }}
/>

file-service를 사용하는 경우

file-service 연동은 선택 사항입니다. 사용하는 프로젝트마다 별도의 API route나 백엔드 엔드포인트를 만들어 개별적으로 연결하세요.

examples/next에는 참고용 file-service 프록시가 들어 있습니다. 이 예제는 패키지의 기본 동작이 아니라, 특정 프로젝트에서 file-service를 붙이는 방법을 보여주는 샘플입니다.

예제 환경변수:

FILE_SERVICE_BASE_URL=http://localhost:30700
FILE_SERVICE_BEARER_TOKEN=
FILE_SERVICE_RETENTION_CATEGORY=blog
  • FILE_SERVICE_BASE_URL: 해당 프로젝트가 사용할 file-service 주소입니다.
  • FILE_SERVICE_BEARER_TOKEN: 서버 전용 Bearer 토큰입니다. NEXT_PUBLIC_을 붙이면 안 됩니다.
  • FILE_SERVICE_RETENTION_CATEGORY: file-service multipart 업로드의 retentionCategory 필드로 전달됩니다. 예: default, tmp, blog, image

다른 프로젝트에서 file-service를 쓰려면 해당 프로젝트의 .env, 인증 방식, 업로드 라우트에 맞게 별도로 설정하세요. 이 패키지에 file-service 주소나 토큰을 넣지 않습니다.

Next 예제

예제 앱은 examples/next에 있습니다. 에디터, 뷰어, JSON 미리보기, 선택적 file-service 업로드 프록시 예제를 포함합니다.

실행:

npm install
npm run dev

빌드 확인:

npm run typecheck
npm run build
npm run example:build

Docker 로컬 실행:

cd examples/next
cp .env.example .env
docker compose up --build -d
docker compose down

Docker 운영용 이미지 실행:

cd examples/next
docker compose -f docker-compose.prod.yml up -dㅇ
docker compose -f docker-compose.prod.yml down

기본 포트는 3000이며 .envNEXT_EXAMPLE_PORT로 바꿀 수 있습니다.

Apple Silicon Mac에서 빌드한 이미지를 Linux amd64 서버에서 실행하려면 amd64 이미지로 빌드해 push해야 합니다.

cd ../..
docker buildx create --use --name shnea-blocknote-builder || docker buildx use shnea-blocknote-builder
docker buildx build \
  --platform linux/amd64 \
  -t registry.shnea.kr/shnea-blocknote-next-example:0.1.0 \
  -f examples/next/Dockerfile \
  --push .

arm64와 amd64를 같이 지원하려면:

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t registry.shnea.kr/shnea-blocknote-next-example:0.1.0 \
  -f examples/next/Dockerfile \
  --push .

WARNING: Error loading config file: /.docker/config.json 경고가 나오면 Docker 설정 경로가 루트로 잡힌 상태입니다. 현재 사용자 설정으로 돌리세요.

export DOCKER_CONFIG="$HOME/.docker"

내보내는 항목

export { BlockNoteEditor, BlockNoteViewer };
export type {
  BlockNoteEditorHandle,
  BlockNoteEditorProps,
  BlockNoteViewerProps,
  BlockNoteTheme,
  FontFaceOption,
  FontFamilyOption,
  FontSizeOption
};
export { schema };
export type { CustomBlock, CustomBlockNoteEditor };