chaeditor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.ko.md +250 -0
  3. package/README.md +242 -0
  4. package/dist/core.cjs +1034 -0
  5. package/dist/core.d.mts +347 -0
  6. package/dist/core.d.ts +347 -0
  7. package/dist/core.mjs +988 -0
  8. package/dist/default-host.cjs +243 -0
  9. package/dist/default-host.d.mts +52 -0
  10. package/dist/default-host.d.ts +52 -0
  11. package/dist/default-host.mjs +239 -0
  12. package/dist/default-markdown-primitive-registry-B3PGEkqs.d.mts +12 -0
  13. package/dist/default-markdown-primitive-registry-CqzwhHj2.d.ts +12 -0
  14. package/dist/image-upload-kind-BJqItE_C.d.mts +18 -0
  15. package/dist/image-upload-kind-BJqItE_C.d.ts +18 -0
  16. package/dist/index.cjs +8736 -0
  17. package/dist/index.d.mts +7 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.mjs +8668 -0
  20. package/dist/markdown-editor-B1qvE40Z.d.mts +460 -0
  21. package/dist/markdown-editor-Ce6DpnQk.d.ts +460 -0
  22. package/dist/markdown-primitive-contract-BXsqbKwY.d.mts +124 -0
  23. package/dist/markdown-primitive-contract-BXsqbKwY.d.ts +124 -0
  24. package/dist/panda-primitives.cjs +1299 -0
  25. package/dist/panda-primitives.d.mts +21127 -0
  26. package/dist/panda-primitives.d.ts +21127 -0
  27. package/dist/panda-primitives.mjs +1285 -0
  28. package/dist/react.cjs +8558 -0
  29. package/dist/react.d.mts +35 -0
  30. package/dist/react.d.ts +35 -0
  31. package/dist/react.mjs +8531 -0
  32. package/dist/toolbar-preset-B9ttTEol.d.ts +236 -0
  33. package/dist/toolbar-preset-DIsQN390.d.mts +236 -0
  34. package/package.json +151 -0
  35. package/recipes/host-presets/README.md +16 -0
  36. package/recipes/host-presets/emotion-host-preset.tsx.template +109 -0
  37. package/recipes/host-presets/styled-components-host-preset.tsx.template +102 -0
  38. package/recipes/host-presets/tailwind-host-preset.tsx.template +116 -0
  39. package/recipes/host-presets/vanilla-extract-host-preset.tsx.template +116 -0
  40. package/styled-system/styles.css +3370 -0
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chaen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.ko.md ADDED
@@ -0,0 +1,250 @@
1
+ # chaeditor
2
+
3
+ [English](./README.md) | 한국어
4
+
5
+ `chaeditor`는 React 애플리케이션을 위한 조합형 마크다운 에디터 툴킷입니다.
6
+ 작성 보조 도구, 임베드 워크플로우, 리치 마크다운 렌더링을 하나의 패키지 안에서 제공하면서도, host 통합, 스타일, primitive shell은 외부에서 주입하거나 교체할 수 있도록 설계되어 있습니다.
7
+
8
+ ## Features
9
+
10
+ - 마크다운 작성 보조와 selection transform 유틸
11
+ - preset 기반 toolbar 조합
12
+ - attachment, gallery, math, Mermaid, spoiler, video를 포함한 리치 마크다운 렌더링
13
+ - upload, href 해석, 이미지 렌더링, 링크 미리보기 메타데이터를 위한 host adapter
14
+ - theme variable override와 primitive shell replacement
15
+
16
+ ## 가이드
17
+
18
+ - [Next.js 통합 가이드](https://github.com/pcwadarong/chaeditor/wiki/KO-%3A-Next.js-%ED%86%B5%ED%95%A9-%EA%B0%80%EC%9D%B4%EB%93%9C)
19
+ - [패키지 표면과 import 매트릭스](https://github.com/pcwadarong/chaeditor/wiki/KO-%3A-%ED%8C%A8%ED%82%A4%EC%A7%80-%ED%91%9C%EB%A9%B4%EA%B3%BC-import-%EB%A7%A4%ED%8A%B8%EB%A6%AD%EC%8A%A4)
20
+ - [아키텍처와 폴더 책임](https://github.com/pcwadarong/chaeditor/wiki/KO-%3A--%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98%EC%99%80-%ED%8F%B4%EB%8D%94-%EC%B1%85%EC%9E%84)
21
+
22
+ ## 설치
23
+
24
+ ```bash
25
+ npm install react react-dom chaeditor
26
+ pnpm add react react-dom chaeditor
27
+ yarn add react react-dom chaeditor
28
+ bun add react react-dom chaeditor
29
+ ```
30
+
31
+ 기본 Panda 스타일과 theme token을 같이 쓰려면 CSS도 불러옵니다.
32
+
33
+ ```tsx
34
+ import 'chaeditor/styles.css';
35
+ ```
36
+
37
+ ## 패키지 표면
38
+
39
+ `chaeditor`는 하나의 패키지로 배포됩니다.
40
+ subpath를 따로 설치하는 구조가 아니라, `chaeditor`를 한 번 설치한 뒤 필요한 entrypoint만 골라 import하는 방식으로 사용합니다.
41
+
42
+ | Import 경로 | 제공 내용 | 사용할 때 |
43
+ | ---------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
44
+ | `chaeditor/react` | `MarkdownEditor`, `MarkdownToolbar`, `MarkdownRenderer` 같은 React surface와 primitive registry contract | 대부분의 앱 통합 |
45
+ | `chaeditor/core` | 순수 유틸, 마크다운 helper, parser contract, `createChaeditorThemeVars()` | UI 없이 로직만 쓸 때, 서버 안전 유틸이 필요할 때 |
46
+ | `chaeditor/default-host` | 기본 upload adapter 구현 | 번들된 기본 업로드 구현이 필요할 때만 |
47
+ | `chaeditor/panda-primitives` | 패키지에 번들된 Panda 기반 primitive shell | 기본 primitive 구현을 재사용하거나 감쌀 때만 |
48
+ | `chaeditor/styles.css` | 기본 theme token과 컴포넌트 스타일 | 패키지 기본 스타일을 쓸 때 |
49
+
50
+ ## 선택적 import
51
+
52
+ 설치는 `chaeditor` 한 번만 하고, 사용은 필요한 subpath만 import하면 됩니다.
53
+ `default-host`, `panda-primitives`는 opt-in surface입니다.
54
+
55
+ 대표 예시는 아래 정도면 충분합니다.
56
+
57
+ ### 기본 editor
58
+
59
+ ```tsx
60
+ import 'chaeditor/styles.css';
61
+
62
+ import { MarkdownEditor } from 'chaeditor/react';
63
+
64
+ const Example = () => {
65
+ const [value, setValue] = useState('# Hello chaeditor');
66
+
67
+ return <MarkdownEditor contentType="article" onChange={setValue} value={value} />;
68
+ };
69
+ ```
70
+
71
+ ### core 유틸만 사용
72
+
73
+ ```ts
74
+ import {
75
+ createImageGalleryMarkdown,
76
+ createMathEmbedMarkdown,
77
+ parseRichMarkdownSegments,
78
+ } from 'chaeditor/core';
79
+ ```
80
+
81
+ ### 기본 host adapter를 선택적으로 연결
82
+
83
+ ```tsx
84
+ import 'chaeditor/styles.css';
85
+
86
+ import { uploadEditorFile, uploadEditorImage, uploadEditorVideo } from 'chaeditor/default-host';
87
+ import { MarkdownEditor } from 'chaeditor/react';
88
+
89
+ const Example = () => (
90
+ <MarkdownEditor
91
+ adapters={{
92
+ uploadFile: uploadEditorFile,
93
+ uploadImage: uploadEditorImage,
94
+ uploadVideo: uploadEditorVideo,
95
+ }}
96
+ contentType="article"
97
+ onChange={() => {}}
98
+ value=""
99
+ />
100
+ );
101
+ ```
102
+
103
+ ### Panda primitive를 선택적으로 재사용
104
+
105
+ ```tsx
106
+ import { Button, createPandaMarkdownPrimitiveRegistry } from 'chaeditor/panda-primitives';
107
+ ```
108
+
109
+ ## Theme Override
110
+
111
+ 기본 스타일 구현은 Panda CSS를 사용하지만, 공개된 theme contract는 CSS variable 기반입니다.
112
+ 즉 패키지 기본값을 그대로 써도 되고, host app이 필요한 값만 override해도 됩니다.
113
+
114
+ ```tsx
115
+ import 'chaeditor/styles.css';
116
+
117
+ import { createChaeditorThemeVars } from 'chaeditor/core';
118
+ import { MarkdownEditor } from 'chaeditor/react';
119
+
120
+ const themeVars = createChaeditorThemeVars({
121
+ primary: '#0f766e',
122
+ primarySubtle: '#ccfbf1',
123
+ surface: '#f8fafc',
124
+ surfaceMuted: '#eff6ff',
125
+ text: '#0f172a',
126
+ textSubtle: '#475569',
127
+ sansFont: 'var(--app-font-sans), system-ui, sans-serif',
128
+ monoFont: "var(--font-d2coding), 'D2Coding', monospace",
129
+ });
130
+
131
+ const Example = () => (
132
+ <div style={themeVars}>
133
+ <MarkdownEditor contentType="article" onChange={() => {}} value="" />
134
+ </div>
135
+ );
136
+ ```
137
+
138
+ 폰트 정책은 아래처럼 가져가면 됩니다.
139
+
140
+ - `sansFont`: host app의 기본 sans 폰트
141
+ - `sansJaFont`: 다국어 fallback이 필요할 때만 override
142
+ - `monoFont`: 필요하면 host mono를 넣고, 비워두면 D2Coding fallback chain이 기본으로 동작
143
+
144
+ ## Styling Runtime Recipes
145
+
146
+ 패키지 기본 스타일 런타임은 Panda CSS입니다.
147
+ host 쪽 스타일링 레시피는 host app이 variable을 override하거나 primitive shell을 교체하고 싶을 때만 필요합니다.
148
+
149
+ 지원 예시는 아래 범위로 제공합니다.
150
+
151
+ - Tailwind CSS
152
+ - Emotion
153
+ - styled-components
154
+ - vanilla-extract
155
+ - primitive shell replacement
156
+
157
+ 바로 가져다 쓸 수 있는 host wrapper 템플릿은 [recipes/host-presets](./recipes/host-presets/README.md)에 정리되어 있습니다.
158
+
159
+ ## Primitive Shell Replacement
160
+
161
+ 색상, 폰트, spacing 정도는 theme variable override로 충분하지만, 실제 `Button`, `Input`, `Textarea`, `Popover`, `Modal`, `Tooltip` shell 자체를 교체해야 할 수도 있습니다.
162
+ 그럴 때는 `primitiveRegistry`를 사용합니다.
163
+
164
+ ```tsx
165
+ import 'chaeditor/styles.css';
166
+
167
+ import { MarkdownEditor } from 'chaeditor/react';
168
+
169
+ const HostButton = props => (
170
+ <button {...props} className={`host-button ${props.className ?? ''}`.trim()} />
171
+ );
172
+
173
+ const HostInput = props => (
174
+ <input {...props} className={`host-input ${props.className ?? ''}`.trim()} />
175
+ );
176
+
177
+ const HostTextarea = props => (
178
+ <textarea {...props} className={`host-textarea ${props.className ?? ''}`.trim()} />
179
+ );
180
+
181
+ const HostPopover = props => (
182
+ <Popover
183
+ {...props}
184
+ panelClassName={`host-popover-panel ${props.panelClassName ?? ''}`.trim()}
185
+ triggerClassName={`host-popover-trigger ${props.triggerClassName ?? ''}`.trim()}
186
+ />
187
+ );
188
+
189
+ const HostModal = props => (
190
+ <Modal
191
+ {...props}
192
+ backdropClassName={`host-modal-backdrop ${props.backdropClassName ?? ''}`.trim()}
193
+ closeButtonClassName={`host-modal-close ${props.closeButtonClassName ?? ''}`.trim()}
194
+ frameClassName={`host-modal-frame ${props.frameClassName ?? ''}`.trim()}
195
+ />
196
+ );
197
+
198
+ const HostTooltip = props => (
199
+ <Tooltip
200
+ {...props}
201
+ contentClassName={`host-tooltip ${props.contentClassName ?? ''}`.trim()}
202
+ portalClassName={`host-tooltip-portal ${props.portalClassName ?? ''}`.trim()}
203
+ />
204
+ );
205
+
206
+ const Example = () => (
207
+ <MarkdownEditor
208
+ contentType="article"
209
+ onChange={() => {}}
210
+ primitiveRegistry={{
211
+ Button: HostButton,
212
+ Input: HostInput,
213
+ Modal: HostModal,
214
+ Popover: HostPopover,
215
+ Textarea: HostTextarea,
216
+ Tooltip: HostTooltip,
217
+ }}
218
+ value=""
219
+ />
220
+ );
221
+ ```
222
+
223
+ 기준을 정리하면:
224
+
225
+ - `createChaeditorThemeVars()`는 semantic token을 바꿉니다.
226
+ - `primitiveRegistry`는 실제 shell 컴포넌트를 바꿉니다.
227
+
228
+ ## 로컬 개발
229
+
230
+ ```bash
231
+ pnpm install
232
+ pnpm lint
233
+ pnpm check-types
234
+ pnpm build
235
+ pnpm test
236
+ ```
237
+
238
+ ## 이슈 제보
239
+
240
+ 새 이슈를 열기 전에 같은 문제가 이미 등록되어 있는지 먼저 확인해 주세요.
241
+ 버그를 제보할 때는 아래 정보를 함께 적어 주세요.
242
+
243
+ - 패키지 버전
244
+ - 런타임 또는 프레임워크 버전
245
+ - 에러 메시지나 스택 트레이스
246
+ - 관련 설정
247
+
248
+ ## 기여하기
249
+
250
+ 기여 가이드는 [CONTRIBUTING.ko.md](./CONTRIBUTING.ko.md)에서 확인할 수 있습니다.
package/README.md ADDED
@@ -0,0 +1,242 @@
1
+ # chaeditor
2
+
3
+ English | [한국어](./README.ko.md)
4
+
5
+ `chaeditor` is a composable markdown editor toolkit for React applications.
6
+ It combines authoring helpers, embed workflows, and rich markdown rendering in a single package while keeping host integration, styling, and primitive shells open to override.
7
+
8
+ ## Features
9
+
10
+ - markdown authoring helpers and selection transform utilities
11
+ - preset-based toolbar composition
12
+ - rich markdown rendering for attachments, galleries, math, Mermaid, spoilers, and video
13
+ - host adapters for uploads, href resolution, image rendering, and link preview metadata
14
+ - theme variable overrides and primitive shell replacement
15
+
16
+ ## Guides
17
+
18
+ - [Next.js Integration](https://github.com/pcwadarong/chaeditor/wiki/EN-%3A-Next.js-Integration)
19
+ - [Package Surface and Import Matrix](https://github.com/pcwadarong/chaeditor/wiki/EN-%3A-Package-Surface-and-Import-Matrix)
20
+ - [Architecture and Folder Ownership](https://github.com/pcwadarong/chaeditor/wiki/EN-%3A-Architecture-and-Folder-Ownership)
21
+
22
+ ## Installation
23
+
24
+ Install `chaeditor` once, then import only the subpaths you need.
25
+
26
+ ```bash
27
+ npm install react react-dom chaeditor
28
+ pnpm add react react-dom chaeditor
29
+ yarn add react react-dom chaeditor
30
+ bun add react react-dom chaeditor
31
+ ```
32
+
33
+ If you want the bundled Panda-based default styles and theme tokens, import the package CSS as well.
34
+
35
+ ```tsx
36
+ import 'chaeditor/styles.css';
37
+ ```
38
+
39
+ ## Package Surface
40
+
41
+ `chaeditor` is published as a single npm package.
42
+ You do not install subpaths separately. Install `chaeditor` once, then selectively import the entrypoints you actually need.
43
+
44
+ | Import path | Provides | Use when |
45
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
46
+ | `chaeditor/react` | React surfaces such as `MarkdownEditor`, `MarkdownToolbar`, `MarkdownRenderer`, and the primitive registry contract | most app integrations |
47
+ | `chaeditor/core` | pure utilities, markdown helpers, parser contracts, and `createChaeditorThemeVars()` | logic-only usage or server-safe helpers |
48
+ | `chaeditor/default-host` | bundled default upload adapters | only when you want the packaged upload implementations |
49
+ | `chaeditor/panda-primitives` | the bundled Panda-based primitive shells | only when you want to reuse or wrap the default primitives |
50
+ | `chaeditor/styles.css` | bundled theme tokens and component styles | when you want the default package styling |
51
+
52
+ ## Selective Imports
53
+
54
+ Install `chaeditor` once, then import only the subpaths you need.
55
+ `default-host` and `panda-primitives` are opt-in surfaces.
56
+
57
+ Representative examples:
58
+
59
+ ### Basic editor
60
+
61
+ ```tsx
62
+ import 'chaeditor/styles.css';
63
+
64
+ import { MarkdownEditor } from 'chaeditor/react';
65
+
66
+ const Example = () => {
67
+ const [value, setValue] = useState('# Hello chaeditor');
68
+
69
+ return <MarkdownEditor contentType="article" onChange={setValue} value={value} />;
70
+ };
71
+ ```
72
+
73
+ ### Core utilities only
74
+
75
+ ```ts
76
+ import {
77
+ createImageGalleryMarkdown,
78
+ createMathEmbedMarkdown,
79
+ parseRichMarkdownSegments,
80
+ } from 'chaeditor/core';
81
+ ```
82
+
83
+ ### Optional default host adapters
84
+
85
+ ```tsx
86
+ import 'chaeditor/styles.css';
87
+
88
+ import { uploadEditorFile, uploadEditorImage, uploadEditorVideo } from 'chaeditor/default-host';
89
+ import { MarkdownEditor } from 'chaeditor/react';
90
+
91
+ const Example = () => (
92
+ <MarkdownEditor
93
+ adapters={{
94
+ uploadFile: uploadEditorFile,
95
+ uploadImage: uploadEditorImage,
96
+ uploadVideo: uploadEditorVideo,
97
+ }}
98
+ contentType="article"
99
+ onChange={() => {}}
100
+ value=""
101
+ />
102
+ );
103
+ ```
104
+
105
+ ### Optional Panda primitive reuse
106
+
107
+ ```tsx
108
+ import { Button, createPandaMarkdownPrimitiveRegistry } from 'chaeditor/panda-primitives';
109
+ ```
110
+
111
+ ## Theme Override
112
+
113
+ The default implementation uses Panda CSS, but the public theme contract is CSS-variable based.
114
+ You can keep the package defaults as-is, or override only the values your host app actually owns.
115
+
116
+ ```tsx
117
+ import 'chaeditor/styles.css';
118
+
119
+ import { createChaeditorThemeVars } from 'chaeditor/core';
120
+ import { MarkdownEditor } from 'chaeditor/react';
121
+
122
+ const themeVars = createChaeditorThemeVars({
123
+ primary: '#0f766e',
124
+ primarySubtle: '#ccfbf1',
125
+ surface: '#f8fafc',
126
+ surfaceMuted: '#eff6ff',
127
+ text: '#0f172a',
128
+ textSubtle: '#475569',
129
+ sansFont: 'var(--app-font-sans), system-ui, sans-serif',
130
+ monoFont: "var(--font-d2coding), 'D2Coding', monospace",
131
+ });
132
+
133
+ const Example = () => (
134
+ <div style={themeVars}>
135
+ <MarkdownEditor contentType="article" onChange={() => {}} value="" />
136
+ </div>
137
+ );
138
+ ```
139
+
140
+ Recommended font ownership:
141
+
142
+ - `sansFont`: host app sans font stack
143
+ - `sansJaFont`: optional multilingual fallback
144
+ - `monoFont`: optional host mono stack, otherwise the built-in D2Coding fallback chain is used
145
+
146
+ ## Styling Runtime Recipes
147
+
148
+ The default package styling runtime is Panda CSS.
149
+ Host-side styling recipes are only needed when the host app wants to override variables or replace primitive shells.
150
+
151
+ Available examples:
152
+
153
+ - Tailwind CSS
154
+ - Emotion
155
+ - styled-components
156
+ - vanilla-extract
157
+ - primitive shell replacement
158
+
159
+ Ready-to-adapt host wrapper templates are available in [recipes/host-presets](./recipes/host-presets/README.md).
160
+
161
+ ## Primitive Shell Replacement
162
+
163
+ Theme variables are enough for colors, fonts, and semantic tokens.
164
+ If you need to replace the actual `Button`, `Input`, `Textarea`, `Popover`, `Modal`, or `Tooltip` shells, use `primitiveRegistry`.
165
+
166
+ ```tsx
167
+ import 'chaeditor/styles.css';
168
+
169
+ import { MarkdownEditor } from 'chaeditor/react';
170
+
171
+ const HostButton = props => (
172
+ <button {...props} className={`host-button ${props.className ?? ''}`.trim()} />
173
+ );
174
+
175
+ const HostInput = props => (
176
+ <input {...props} className={`host-input ${props.className ?? ''}`.trim()} />
177
+ );
178
+
179
+ const HostTextarea = props => (
180
+ <textarea {...props} className={`host-textarea ${props.className ?? ''}`.trim()} />
181
+ );
182
+
183
+ const HostPopover = props => (
184
+ <Popover
185
+ {...props}
186
+ panelClassName={`host-popover-panel ${props.panelClassName ?? ''}`.trim()}
187
+ triggerClassName={`host-popover-trigger ${props.triggerClassName ?? ''}`.trim()}
188
+ />
189
+ );
190
+
191
+ const HostModal = props => (
192
+ <Modal
193
+ {...props}
194
+ backdropClassName={`host-modal-backdrop ${props.backdropClassName ?? ''}`.trim()}
195
+ closeButtonClassName={`host-modal-close ${props.closeButtonClassName ?? ''}`.trim()}
196
+ frameClassName={`host-modal-frame ${props.frameClassName ?? ''}`.trim()}
197
+ />
198
+ );
199
+
200
+ const HostTooltip = props => (
201
+ <Tooltip
202
+ {...props}
203
+ contentClassName={`host-tooltip ${props.contentClassName ?? ''}`.trim()}
204
+ portalClassName={`host-tooltip-portal ${props.portalClassName ?? ''}`.trim()}
205
+ />
206
+ );
207
+
208
+ const Example = () => (
209
+ <MarkdownEditor
210
+ contentType="article"
211
+ onChange={() => {}}
212
+ primitiveRegistry={{
213
+ Button: HostButton,
214
+ Input: HostInput,
215
+ Modal: HostModal,
216
+ Popover: HostPopover,
217
+ Textarea: HostTextarea,
218
+ Tooltip: HostTooltip,
219
+ }}
220
+ value=""
221
+ />
222
+ );
223
+ ```
224
+
225
+ Rule of thumb:
226
+
227
+ - `createChaeditorThemeVars()` changes semantic tokens
228
+ - `primitiveRegistry` changes shell components
229
+
230
+ ## Local Development
231
+
232
+ ```bash
233
+ pnpm install
234
+ pnpm lint
235
+ pnpm check-types
236
+ pnpm build
237
+ pnpm test
238
+ ```
239
+
240
+ ## Contributing
241
+
242
+ If you want to contribute, see [CONTRIBUTING.md](./CONTRIBUTING.md).