@kokotu0/koko-ui
v0.7.0
Published
캘린더·중첩 카테고리 등 React UI 컴포넌트 모음
Readme
@kokotu0/koko-ui
캘린더 · 간트 · 중첩 카테고리 · Lexical 에디터 등 React UI 컴포넌트 모음.
npm i @kokotu0/koko-ui스타일시트를 한 번 불러와야 합니다.
import '@kokotu0/koko-ui/styles.css';엔트리
패키지는 목적별로 나뉘어 있습니다. 필요한 엔트리만 import하면 그 엔트리의 의존만 필요합니다.
| 지정자 | 내용 | JS | peer |
|---|---|---|---|
| @kokotu0/koko-ui | 배럴 — 캘린더 + SchedulePickr + FormBuilder | 169KB | 3 |
| @kokotu0/koko-ui/calendar | 캘린더 (월/주/일/연 뷰) | 132KB | 3 |
| @kokotu0/koko-ui/gantt | 간트차트 (가로 무한 스크롤, 의존성 화살표) | 57KB | 3 |
| @kokotu0/koko-ui/datepickr | SchedulePickr (기간 선택) | 24KB | 1 |
| @kokotu0/koko-ui/form-builder | 폼 플러그인 시스템 | 13KB | 3 |
| @kokotu0/koko-ui/nested-category | 중첩 카테고리 트리 | 38KB | 3 |
| @kokotu0/koko-ui/chat-input | BlockInput · DictEditor | 63KB | 11 |
| @kokotu0/koko-ui/richtext | RichTextEditor — /editor로 수렴 중, 폼 블록은 /editor에서 재수출 | 23KB | 11 |
| @kokotu0/koko-ui/editor | Notion형 Lexical 에디터 (폼 블록 포함) | 72KB | 17 |
| @kokotu0/koko-ui/event-table | MRT 기반 이벤트 테이블 | 748KB | 10 |
| @kokotu0/koko-ui/styles.css | 스타일시트 | 39KB | — |
수치는 배포 tarball의 import 그래프를 청크까지 전이 추적해 실측한 값입니다.
배럴에는 무거운 것을 넣지 않습니다. import 한 줄이 그래프 전체를 당기므로, 배럴에 있으면
optionalpeer 선언이 무의미해집니다.EventTable·chat-input·richtext·editor·gantt·nested-category는 서브패스 전용입니다. 기능 하나만 쓸 거면 서브패스가 항상 낫습니다.
peerDependencies — 엔트리별로 다릅니다
모든 peer는 optional로 선언돼 있습니다. 즉 npm i가 자동으로 깔아주지 않으므로,
쓰려는 엔트리에 해당하는 것을 직접 설치해야 합니다.
| 엔트리 | 함께 설치해야 하는 것 |
|---|---|
| 배럴 · /calendar · /gantt · /form-builder | react framer-motion lucide-react |
| /datepickr | react |
| /nested-category | react @mui/material @emotion/react @emotion/styled lucide-react |
| /chat-input · /richtext | 위 배럴 3개 + react-dom lexical @lexical/{list,markdown,react,rich-text,selection,utils} |
| /editor | react react-dom lucide-react framer-motion lexical @lexical/{clipboard,code,link,list,markdown,react,rich-text,selection,table,utils} @mui/material @mui/icons-material @emotion/react @emotion/styled |
| /event-table | react react-dom lucide-react material-react-table @mui/material @mui/icons-material @emotion/react @emotion/styled @mui/x-date-pickers @tanstack/react-query @tanstack/react-virtual date-fns lodash |
이 표는 배포 tarball의 import 그래프를 청크까지 전이 추적해 뽑았고, Node ESM에서 엔트리별로 실제 import를 태워 확인했습니다. 표에 없는 것을 빼고 깔면 그 엔트리는 빠진 패키지 이름을 그대로 알려주며 실패합니다.
@emotion/react/@emotion/styled는 dist가 직접 import하지 않지만 MUI v7의 런타임 요구라 peer에 남겨 뒀습니다.@mui/x-date-pickers는 우리가 import하지 않고material-react-table이 필수 peer로 요구해서/event-table에 필요합니다.
optional은 "자동 설치하지 않는다"는 뜻이고 "버전 충돌을 무시한다"는 뜻이 아닙니다. 0.4.1에서 공개 엔트리가 쓰지 않는 peer 6개(zustandthree@react-three/*react-router-dom@lexical/html)를 제거했습니다 — 쓰지도 않는 선언이 소비자의npm i를ERESOLVE로 막는 일이 있었습니다.
⚠️ QueryClientProvider가 필요한 엔트리
koko-ui/event-table 하나뿐입니다. 서버 페이지네이션·필터를 @tanstack/react-query로
돌리므로 Provider 없이 렌더하면 죽습니다.
Error: No QueryClient set, use QueryClientProvider to set oneimport { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import { EventTable } from '@kokotu0/koko-ui/event-table';
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<EventTable … />
</QueryClientProvider>다른 엔트리는 react-query를 쓰지 않습니다.
0.5.0부터
koko-ui/editor는 react-query가 필요 없습니다. 예전에는 이미지 업로드 한 곳에서useMutation을 쓰는 바람에 — 캐시도 queryKey도 안 쓰면서 — 에디터를 렌더하려면 소비 앱이 react-query를 채택해야 했습니다.uploader는 이미 prop으로 주입받으므로 그냥await합니다. 라이브러리가 소비 앱의 상태 관리 스택을 결정하지 않습니다.
사용 예
캘린더
상태는 useCalendar()가 만들고, CalendarProvider의 value로 넘깁니다. 이벤트 타입은
자유롭고 날짜를 어디서 읽을지는 dateExtractor로 알려줍니다.
import { Calendar, CalendarProvider, useCalendar } from '@kokotu0/koko-ui/calendar';
import '@kokotu0/koko-ui/styles.css';
function MyCalendar({ events }) {
const state = useCalendar({
events,
dateExtractor: {
getStart: (e) => e.start,
getEnd: (e) => e.end,
},
});
return (
<CalendarProvider value={state}>
<Calendar />
</CalendarProvider>
);
}useCalendar() 호출을 호출자에게 남겨 둔 것은 의도입니다 — 페이지가 상태를 직접 읽어야 하는
경우(쿼리 기간 동기화, 모달 초기값)가 있습니다. Provider 안에서는 슬라이스 훅으로 읽습니다:
useNavigation() · useSelection() · useEvents() · useLayout() · useCalendarTheme().
간트
extractor는 개별 prop으로 평탄화되어 있습니다.
import { GanttChart } from '@kokotu0/koko-ui/gantt';
<GanttChart
tasks={tasks}
getTaskId={(t) => t.id}
getTaskRange={(t) => ({ start: t.start, end: t.end })}
getTaskLabel={(t) => t.name}
links={links} // 의존성 화살표 (선택)
initialViewMode="month"
/>부품(TaskRow / Bar / GroupSection / DependencyLayer / TimeHeader)은 공개 조립 부품입니다.
Provider 없이 단독 조립해도 동작합니다 — 테마는 prop > context > lightTheme 순으로 찾고,
Provider 밖에서도 던지지 않습니다.
중첩 카테고리
선택 상태는 경로 문자열의 Set입니다 (구분자 기본값 '>').
import { useState } from 'react';
import { NestedCategory } from '@kokotu0/koko-ui/nested-category';
const [selected, setSelected] = useState<Set<string>>(new Set());
<NestedCategory
categories={categories}
selected={selected}
onChange={setSelected}
expandMode="toggle"
searchable
/>트리 파생·조상/자손 판정이 직접 필요하면 useNestedCategory(categories, selected, onChange)가
tree · toggle · getDescendantPaths 등을 돌려줍니다.
에디터
import { Editor } from '@kokotu0/koko-ui/editor';
<Editor value={content} onChange={handleChange} uploader={myUploader} />uploader를 주입하지 않으면 파일 업로드가 에러로 거부됩니다 — 백엔드 결합물은 소비 앱이
주입하는 구조입니다. 도메인 노드나 슬래시 메뉴 항목도 extraNodes · extraSlashItems로
넣습니다.
value는 봉투({v, doc, files})든 구 형식({text} · Yoopta)이든 그대로 넘기면 됩니다 —
에디터가 Lexical 문서로 맞춥니다(toSeedableContent, 0.6.0). 오른쪽 위 전체화면 버튼은
기본 켜짐이며 fullscreenButton={false}로 끕니다. firstLineTitle을 켜면 첫 블록이
제목(h1)이 됩니다. 슬래시 항목은 label · description · keywords · icon을 직접 갖고,
onSelect(editor, { query })로 자기 동작을 붙입니다.
/richtext에서 옮겨 오는 소비자용 호환 표면도 있습니다 — value에 JSON 문자열,
onTextChange(plainText, json)(봉투 없는 문서), editorRef · placeholder · autoFocus ·
minHeight, 마크다운 단축 입력(markdownShortcuts, 기본 켜짐), 슬래시 메뉴 초성 검색.
폼 블록(FormBlockNode)은 기본 등록되며 formPlugins={formPresets}로 폼 정의를 넘깁니다.
색은 MUI theme palette에서 나오므로 다크 테마를 쓰면 본문도 함께 어두워집니다.
테마
캘린더와 간트는 같은 테마 타입을 공유합니다(캘린더에서는 CalendarTheme 별칭).
lightTheme / darkTheme를 그대로 쓰거나 mergeTheme로 부분 덮어쓰기 할 수 있습니다 —
두 번째 인자는 DeepPartial이라 필요한 가지만 적으면 됩니다.
import { lightTheme, mergeTheme } from '@kokotu0/koko-ui/calendar';
const theme = mergeTheme(lightTheme, {
colors: {
today: { bg: '#7c3aed' },
},
});
<CalendarProvider value={state} theme={theme}>…</CalendarProvider>theme을 생략하면 lightTheme입니다.
요구 환경
- React 18 또는 19
- ESM 전용 (
"type": "module"). CommonJSrequire()는 지원하지 않습니다.
라이선스
MIT
