Skip to content

aryu1217/cheonjiin-keyboard

Repository files navigation

react-cji-keyboard

React용 천지인 + 영문 + 숫자 + 기호 커스텀 키보드 컴포넌트

스마트폰 천지인 키보드를 웹앱, PWA 같은 환경에서도 쓸 수 있도록 만든 가상 키보드입니다.
(공모전 파트너 단체에서 “수중에서 모바일 키보드가 너무 작아 기록이 힘들다”는 피드백을 받고 시작한 프로젝트입니다.)

  • 장갑을 끼거나, 물속/현장 환경처럼 작은 쿼티 키보드를 누르기 어려운 상황,
  • 모바일 브라우저에서 기본 키보드를 숨기고 화면 안에 큰 키보드를 띄우고 싶은 경우,
  • 특정 입력 칸에서만 천지인 전용 입력 UX를 제공하고 싶은 경우

에 기본 키패드 대신 사용할 수 있도록 설계되었습니다.

천지인 키보드 - 한글 모드 천지인 키보드 - 영문 모드
천지인 키보드 - 숫자/기호 모드1 천지인 키보드 - 숫자/기호 모드2

설치

npm install react-cji-keyboard
# 또는
yarn add react-cji-keyboard

기본 사용법

이 라이브러리는 입력 상태를 내부에서 관리하면서 onChange(text: string) 콜백으로 완성된 문자열을 돌려줍니다.
TypeScript 프로젝트에서는 index.d.ts를 통해 자동으로 타입이 인식되고, JS/JSX 환경에서도 동일한 코드로 사용할 수 있습니다.

import { useState } from "react";
import CheonjiinKeyboard from "react-cji-keyboard";
import "react-cji-keyboard/style.css"; // ★ 기본 CSS

function App() {
  const [value, setValue] = useState("");

  return (
    <div style={{ maxWidth: 420, margin: "0 auto", padding: 16 }}>
      <h1>천지인 키보드 데모</h1>

      {/* 실제 입력을 보여줄 필드 (readOnly로 두고 onChange로만 갱신) */}
      <textarea
        value={value}
        readOnly
        rows={3}
        style={{
          width: "100%",
          borderRadius: 8,
          border: "1px solid #ddd",
          padding: "8px 10px",
          marginBottom: 12,
          whiteSpace: "pre-wrap",
        }}
        placeholder="천지인 키보드로 입력해보세요"
      />

      {/* 가상 키보드 */}
      <CheonjiinKeyboard onChange={setValue} />
    </div>
  );
}

export default App;

JS/JSX 프로젝트에서도 동일한 코드를 사용할 수 있고,
TypeScript에서는 onChange 인자와 value가 자동으로 string 타입으로 추론됩니다.


컴포넌트 API

<CheonjiinKeyboard />

export interface CheonjiinKeyboardProps {
  value?: string;
  onChange?: (text: string) => void;
  className?: string;
}

declare const CheonjiinKeyboard: React.FC<CheonjiinKeyboardProps>;

export default CheonjiinKeyboard;

onChange

  • 키보드에서 글자가 바뀔 때마다 호출됩니다.
  • 한글/영문/숫자/기호를 모두 포함한 현재 전체 문자열이 인자로 넘어옵니다.

보통 이렇게 사용합니다:

const [text, setText] = useState("");

return (
  <>
    <textarea value={text} readOnly />
    <CheonjiinKeyboard onChange={setText} />
  </>
);

value (선택)

  • 키보드의 값을 바깥에서 직접 관리하고 싶을 때 사용합니다.
  • 예를 들어, 상위 컴포넌트에서 상태를 들고 있다가 onChange로 받은 값을 다시 넣어주는 식으로 씁니다:
const [text, setText] = useState("");

return (
  <CheonjiinKeyboard
    value={text}
    onChange={setText}
  />
);
  • value를 지정하지 않으면, 키보드가 자기 내부에서 값 상태를 관리하면서 onChange로 결과만 알려줍니다.
  • 리셋 버튼으로 값 지우기, 다른 입력 컴포넌트와 값 공유하기 등 외부에서 값에 간섭해야 할 때 value를 함께 사용하는 패턴이 편합니다.

className (선택)

  • 키보드 최상위 래퍼에 추가로 클래스명을 붙이고 싶을 때 사용합니다.
  • 예를 들어, 화면 하단에 붙는 바텀시트 스타일로 쓰고 싶다면:
<CheonjiinKeyboard
  onChange={setText}
  className="fixed inset-x-0 bottom-0 border-t bg-white"
/>

처럼 프로젝트에서 사용하는 CSS / Tailwind 클래스와 함께 조합해서 쓸 수 있습니다.


스타일 커스터마이징

기본 스타일은 style.css 에 정의된 CSS 클래스 기반입니다.
프로젝트에서 같은 클래스 이름을 다시 정의하면 손쉽게 테마를 변경할 수 있습니다.

기본 클래스 목록 (일부)

  • .cheon-keyboard – 키보드 전체 래퍼
  • .cheon-grid – 5열(또는 4열) 그리드 레이아웃
  • .cheon-grid--english – 영문 모드에서 4열 그리드
  • .cheon-key – 기본 키 스타일
  • .cheon-key--func – 기능 키 (한/영, 123, 기호, 백스페이스 등)
  • .cheon-key--space – 스페이스 키
  • .cheon-key--enter – 엔터 키
  • .cheon-key--empty – 비워두는 자리용 키

예시 1) 다크 테마로 바꾸기 (CSS 덮어쓰기)

/* global.css 또는 App 전체에 적용되는 CSS에서 */
.cheon-keyboard {
  background: #020617;
  padding: 12px;
  border-radius: 16px 16px 0 0;
}

/* 모든 키 공통 스타일 */
.cheon-key {
  background: #111827;
  color: #e5e7eb;
  border-radius: 10px;
  border: 1px solid #1f2937;
  font-size: 16px;
}

/* 기능 키(한/영, 123, 기호, 백스페이스 등) 강조 */
.cheon-key--func {
  background: #1f2937;
  color: #f9fafb;
}

/* 스페이스바 크게/연하게 */
.cheon-key--space {
  background: #0f172a;
  color: #e5e7eb;
  font-size: 14px;
}

이렇게 하면 라이브러리 기본 스타일 위에 덮어씌워져,
레이아웃 구조는 그대로 유지하면서 색감/테마만 바꿀 수 있습니다.

예시 2) 입력창 + 바텀시트 형태로 사용하기 (Tailwind)

import CheonjiinKeyboard from "react-cji-keyboard";
import "react-cji-keyboard/style.css";

function BottomSheetKeyboard({ open, value, onChange }) {
  return (
    <div
      className={`fixed inset-x-0 bottom-0 transition-transform duration-200
      ${open ? "translate-y-0" : "translate-y-full"}`}
    >
      <div className="mx-auto max-w-sm bg-white rounded-t-2xl shadow-xl p-3">
        <textarea
          value={value}
          readOnly
          className="w-full mb-2 p-2 rounded-md border text-sm"
        />
        <CheonjiinKeyboard onChange={onChange} />
      </div>
    </div>
  );
}