@particle-academy/fancy-code 0.4.2 → 0.4.3

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.
package/README.md CHANGED
@@ -1,25 +1,20 @@
1
1
  # @particle-academy/fancy-code
2
2
 
3
- Lightweight embedded code editor with syntax highlighting, custom toolbar buttons, and extensible language/theme registries. Part of the `@particle-academy` component ecosystem.
3
+ Lightweight embedded code editor with syntax highlighting, custom toolbar buttons, and extensible language and theme registries. Part of the `@particle-academy` component ecosystem.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- # npm
9
8
  npm install @particle-academy/fancy-code
10
-
11
- # pnpm
12
- pnpm add @particle-academy/fancy-code
13
-
14
- # yarn
15
- yarn add @particle-academy/fancy-code
9
+ # or: pnpm add @particle-academy/fancy-code
10
+ # or: yarn add @particle-academy/fancy-code
16
11
  ```
17
12
 
18
13
  **Peer dependencies:** `react >= 18`, `react-dom >= 18`, `@particle-academy/react-fancy >= 1.5`
19
14
 
20
- ## Usage
15
+ ## Setup
21
16
 
22
- Add the `@source` directive to your main CSS file so Tailwind v4 scans the component library:
17
+ Add the package styles to your main CSS (Tailwind v4 scans via `@source`):
23
18
 
24
19
  ```css
25
20
  @import "tailwindcss";
@@ -27,22 +22,16 @@ Add the `@source` directive to your main CSS file so Tailwind v4 scans the compo
27
22
  @source "../node_modules/@particle-academy/fancy-code/dist/**/*.js";
28
23
  ```
29
24
 
30
- Then import and use:
25
+ ## Quick Start
31
26
 
32
27
  ```tsx
33
28
  import { CodeEditor } from "@particle-academy/fancy-code";
34
- import "@particle-academy/fancy-code/styles.css";
35
29
 
36
30
  function App() {
37
31
  const [code, setCode] = useState('console.log("Hello");');
38
32
 
39
33
  return (
40
- <CodeEditor
41
- value={code}
42
- onChange={setCode}
43
- language="javascript"
44
- className="rounded-xl border border-zinc-200 dark:border-zinc-700"
45
- >
34
+ <CodeEditor value={code} onChange={setCode} language="javascript">
46
35
  <CodeEditor.Toolbar />
47
36
  <CodeEditor.Panel />
48
37
  <CodeEditor.StatusBar />
@@ -51,7 +40,15 @@ function App() {
51
40
  }
52
41
  ```
53
42
 
54
- The component has no default border or rounding — add your own via `className` for standalone use, or embed directly into IDE layouts without visual conflicts.
43
+ The component ships with no default border or rounding — add your own via `className` for standalone use, or embed directly into IDE layouts without visual conflicts.
44
+
45
+ ## Documentation
46
+
47
+ | Topic | Doc |
48
+ |-------|-----|
49
+ | Full component API (props, sub-components, `useCodeEditor` hook) | [docs/CodeEditor.md](./docs/CodeEditor.md) |
50
+ | Built-in languages + registering custom ones | [docs/languages.md](./docs/languages.md) |
51
+ | Built-in themes + custom theme registration | [docs/themes.md](./docs/themes.md) |
55
52
 
56
53
  ## Commands
57
54
 
@@ -62,358 +59,14 @@ pnpm --filter @particle-academy/fancy-code lint # Type-check (tsc --noEmit)
62
59
  pnpm --filter @particle-academy/fancy-code clean # Remove dist/
63
60
  ```
64
61
 
65
- ## Component API
66
-
67
- ### Compound Components
68
-
69
- | Component | Description |
70
- |-----------|-------------|
71
- | `CodeEditor` | Root wrapper — context provider, state management |
72
- | `CodeEditor.Toolbar` | Action bar with default buttons or custom children |
73
- | `CodeEditor.Toolbar.Separator` | Vertical divider between toolbar groups |
74
- | `CodeEditor.Panel` | Code editing surface |
75
- | `CodeEditor.StatusBar` | Cursor position, language, tab size display |
76
-
77
- ### CodeEditor Props
78
-
79
- ```ts
80
- interface CodeEditorProps {
81
- children: ReactNode;
82
- className?: string;
83
- value?: string; // Controlled value
84
- defaultValue?: string; // Uncontrolled initial value
85
- onChange?: (value: string) => void;
86
- language?: string; // Language name or alias (default: "javascript")
87
- onLanguageChange?: (lang: string) => void;
88
- theme?: string; // "light" | "dark" | "auto" | custom name (default: "auto")
89
- readOnly?: boolean; // Default: false
90
- lineNumbers?: boolean; // Default: true
91
- wordWrap?: boolean; // Default: false
92
- tabSize?: number; // Default: 2
93
- placeholder?: string;
94
- minHeight?: number; // Minimum height in px
95
- maxHeight?: number; // Max height before scrolling
96
- }
97
- ```
98
-
99
- ### useCodeEditor Hook
100
-
101
- Access the editor context from custom toolbar buttons:
102
-
103
- ```tsx
104
- import { useCodeEditor } from "@particle-academy/fancy-code";
105
- import { Action } from "@particle-academy/react-fancy";
106
-
107
- function RunButton() {
108
- const { getValue } = useCodeEditor();
109
- return <Action size="xs" onClick={() => run(getValue())}>Run</Action>;
110
- }
111
-
112
- <CodeEditor value={code} onChange={setCode} language="javascript">
113
- <CodeEditor.Toolbar>
114
- <RunButton />
115
- <CodeEditor.Toolbar.Separator />
116
- </CodeEditor.Toolbar>
117
- <CodeEditor.Panel />
118
- </CodeEditor>
119
- ```
120
-
121
- **Context value:**
122
-
123
- | Method / Property | Description |
124
- |-------------------|-------------|
125
- | `getValue()` | Get current document text |
126
- | `getSelection()` | Get currently selected text |
127
- | `setValue(text)` | Replace entire document |
128
- | `replaceSelection(text)` | Replace current selection |
129
- | `focus()` | Focus the editor |
130
- | `language` | Current language name |
131
- | `setLanguage(name)` | Switch active language |
132
- | `theme` | Current theme name |
133
- | `readOnly` | Whether the editor is read-only |
134
- | `lineNumbers` | Whether line numbers are shown |
135
- | `wordWrap` | Whether word wrap is enabled |
136
- | `tabSize` | Current tab size |
137
- | `toggleWordWrap()` | Toggle word wrap on/off |
138
- | `toggleLineNumbers()` | Toggle line numbers on/off |
139
- | `copyToClipboard()` | Copy entire document to clipboard |
140
- | `cursorPosition` | `{ line, col }` — current cursor position |
141
- | `selectionLength` | Length of current selection (0 if none) |
142
-
143
- ## Examples
144
-
145
- ### Basic Editor
146
-
147
- ```tsx
148
- <CodeEditor value={code} onChange={setCode} language="typescript">
149
- <CodeEditor.Toolbar />
150
- <CodeEditor.Panel />
151
- <CodeEditor.StatusBar />
152
- </CodeEditor>
153
- ```
154
-
155
- ### Read-Only Code Display
156
-
157
- ```tsx
158
- <CodeEditor value={snippet} language="php" readOnly>
159
- <CodeEditor.Panel />
160
- </CodeEditor>
161
- ```
162
-
163
- ### Custom Toolbar
164
-
165
- ```tsx
166
- <CodeEditor value={code} onChange={setCode} language="javascript">
167
- <CodeEditor.Toolbar>
168
- <RunButton />
169
- <CodeEditor.Toolbar.Separator />
170
- <FormatButton />
171
- <CopyButton />
172
- </CodeEditor.Toolbar>
173
- <CodeEditor.Panel />
174
- <CodeEditor.StatusBar />
175
- </CodeEditor>
176
- ```
177
-
178
- ### Height Constraints
179
-
180
- ```tsx
181
- <CodeEditor value={longCode} language="javascript" maxHeight={400} minHeight={200}>
182
- <CodeEditor.Toolbar />
183
- <CodeEditor.Panel />
184
- <CodeEditor.StatusBar />
185
- </CodeEditor>
186
- ```
187
-
188
- ### Minimal (No Toolbar, No StatusBar)
189
-
190
- ```tsx
191
- <CodeEditor value={snippet} language="javascript" readOnly lineNumbers={false}>
192
- <CodeEditor.Panel />
193
- </CodeEditor>
194
- ```
195
-
196
- ## Built-in Languages
197
-
198
- | Language | Aliases |
199
- |----------|---------|
200
- | JavaScript | `js`, `javascript`, `jsx` |
201
- | TypeScript | `ts`, `typescript`, `tsx` |
202
- | HTML | `html`, `htm` |
203
- | PHP | `php` |
204
- | Python | `py`, `python` |
205
- | Go | `go`, `golang` |
206
-
207
- ## Custom Language Registration
208
-
209
- Add languages beyond the built-ins using `registerLanguage`:
210
-
211
- ```tsx
212
- import { registerLanguage } from "@particle-academy/fancy-code";
213
- import type { Tokenizer } from "@particle-academy/fancy-code";
214
-
215
- const tokenizeRuby: Tokenizer = (source) => {
216
- const tokens = [];
217
- // Your regex-based tokenizer logic here
218
- // See src/engine/tokenizers/javascript.ts for a full example
219
- return tokens;
220
- };
221
-
222
- registerLanguage({
223
- name: "Ruby",
224
- aliases: ["rb", "ruby"],
225
- tokenize: tokenizeRuby,
226
- });
227
- ```
228
-
229
- Then use it:
230
-
231
- ```tsx
232
- <CodeEditor language="python" ... />
233
- ```
234
-
235
- ## Built-in Color Schemes
236
-
237
- | Theme | Description |
238
- |-------|-------------|
239
- | `light` | White background, blue/purple/green token colors |
240
- | `dark` | Zinc-900 background, pastel token colors |
241
- | `auto` | Automatically selects light/dark based on `prefers-color-scheme` (default) |
242
-
243
- ## Custom Theme Registration
244
-
245
- Create custom syntax highlighting color schemes using `registerTheme`:
246
-
247
- ```tsx
248
- import { registerTheme } from "@particle-academy/fancy-code";
249
-
250
- registerTheme({
251
- name: "monokai",
252
- variant: "dark",
253
- editorTheme: /* editor chrome styles (background, gutter, cursor, selection) */,
254
- highlightStyle: /* token color definitions (keywords, strings, comments, etc.) */,
255
- });
256
- ```
257
-
258
- Then use it:
259
-
260
- ```tsx
261
- <CodeEditor theme="monokai" ... />
262
- ```
263
-
264
- **Theme definition:**
265
-
266
- ```ts
267
- interface ThemeDefinition {
268
- name: string; // Unique theme name
269
- variant: "light" | "dark"; // Light or dark base
270
- editorTheme: Extension; // Editor chrome styles (gutter, cursor, selection)
271
- highlightStyle: HighlightStyle; // Syntax token color definitions
272
- }
273
- ```
274
-
275
- ## Built-in Features
276
-
277
- - Syntax highlighting with language-aware tokenization
278
- - Line numbers with active line gutter highlight
279
- - Active line highlighting
280
- - Bracket matching and auto-close
281
- - Code folding with fold gutter
282
- - Search and replace (Ctrl+F / Cmd+F)
283
- - Autocompletion
284
- - History (undo/redo)
285
- - Indent on input
286
- - Selection highlighting
287
- - Tab key indentation
288
-
289
- All features are reconfigurable at runtime — switching languages, themes, line numbers, word wrap, tab size, and read-only mode happens without recreating the editor.
290
-
291
- ## Customization
292
-
293
- All components render `data-fancy-code-*` attributes on their root elements for external CSS targeting:
294
-
295
- | Attribute | Element |
296
- |-----------|---------|
297
- | `data-fancy-code-editor` | Root wrapper |
298
- | `data-fancy-code-toolbar` | Toolbar bar |
299
- | `data-fancy-code-toolbar-separator` | Toolbar separator |
300
- | `data-fancy-code-panel` | Editing surface |
301
- | `data-fancy-code-statusbar` | Status bar |
302
-
303
- ## Architecture
304
-
305
- ### Directory Layout
306
-
307
- ```
308
- src/
309
- ├── components/
310
- │ └── CodeEditor/
311
- │ ├── CodeEditor.tsx # Root compound component + context
312
- │ ├── CodeEditor.types.ts # All prop/context types
313
- │ ├── CodeEditor.context.ts # React context + useCodeEditor hook
314
- │ ├── CodeEditorPanel.tsx # Editing surface
315
- │ ├── CodeEditorToolbar.tsx # Default toolbar + custom children
316
- │ ├── CodeEditorToolbarSeparator.tsx
317
- │ ├── CodeEditorStatusBar.tsx # Cursor/language/tab display
318
- │ └── index.ts
319
- ├── hooks/
320
- │ ├── use-editor-engine.ts # Core editor lifecycle
321
- │ └── use-dark-mode.ts # Reactive prefers-color-scheme
322
- ├── languages/
323
- │ ├── registry.ts # Global language registry
324
- │ ├── builtin.ts # JS, TS, HTML, PHP registrations
325
- │ ├── types.ts # LanguageDefinition type
326
- │ └── index.ts
327
- ├── themes/
328
- │ ├── registry.ts # Global theme registry
329
- │ ├── light.ts # Built-in light color scheme
330
- │ ├── dark.ts # Built-in dark color scheme
331
- │ ├── types.ts # ThemeDefinition type
332
- │ └── index.ts
333
- ├── styles.css # Base structural styles
334
- └── index.ts # Public API
335
- ```
336
-
337
- ### Public Exports
338
-
339
- ```ts
340
- // Components
341
- export { CodeEditor, useCodeEditor };
342
- export type { CodeEditorProps, CodeEditorContextValue, CodeEditorToolbarProps, CodeEditorPanelProps, CodeEditorStatusBarProps };
343
-
344
- // Language registration
345
- export { registerLanguage, getLanguage, getRegisteredLanguages };
346
- export type { LanguageDefinition };
347
-
348
- // Theme registration
349
- export { registerTheme, getTheme, getRegisteredThemes };
350
- export type { ThemeDefinition };
351
- ```
352
-
353
- ## Related: TreeNav from react-fancy
354
-
355
- For IDE-style layouts, pair `CodeEditor` with the `TreeNav` component from `@particle-academy/react-fancy`. TreeNav provides hierarchical file/folder navigation with expand/collapse, selection, and extension-based file icons.
356
-
357
- ```tsx
358
- import { TreeNav } from "@particle-academy/react-fancy";
359
- import { CodeEditor } from "@particle-academy/fancy-code";
360
-
361
- <div className="flex" style={{ height: 600 }}>
362
- <TreeNav
363
- nodes={fileTree}
364
- selectedId={activeFile}
365
- onSelect={(id, node) => openFile(id, node)}
366
- />
367
- <CodeEditor value={code} onChange={setCode} language={lang}>
368
- <CodeEditor.Toolbar />
369
- <CodeEditor.Panel />
370
- <CodeEditor.StatusBar />
371
- </CodeEditor>
372
- </div>
373
- ```
374
-
375
- See the full IDE demo at `/react-demos/ide` in the monorepo.
376
-
377
- ## Demo Pages
378
-
379
- The demo page lives in the monorepo at `resources/js/react-demos/pages/CodeEditorDemo.tsx` and is accessible at `/react-demos/code-editor`. It demonstrates:
380
-
381
- 1. Basic editor with default toolbar
382
- 2. Read-only code display
383
- 3. Custom toolbar buttons via `useCodeEditor()`
384
- 4. Language switching (JS, TS, HTML, PHP)
385
- 5. Light vs dark theme showcase
386
- 6. Word wrap and configuration
387
- 7. Minimal mode (no toolbar, no status bar)
388
-
389
- ---
390
-
391
- ## Agent Guidelines
392
-
393
- Guidelines for AI agents (Claude Code, Copilot, etc.) working on this package.
394
-
395
- ### Component Pattern
396
-
397
- - Uses the same compound component pattern as `@particle-academy/react-fancy`'s Editor: `Object.assign(Root, { Toolbar, Panel, StatusBar })`.
398
- - Context is provided via `CodeEditorContext` and consumed with `useCodeEditor()`.
399
- - All root elements have `data-fancy-code-*` attributes for external CSS targeting.
400
-
401
- ### Editor Engine
402
-
403
- - The `useCodemirror` hook manages the editor lifecycle.
404
- - Uses compartments for hot-swapping language, theme, line numbers, word wrap, tab size, read-only, placeholder, and height constraints.
405
- - External value changes are synced via `isExternalUpdate` ref to prevent onChange loops.
406
- - SSR-safe: the editor is only created inside `useEffect`.
407
-
408
- ### Extension System
62
+ ## At a Glance
409
63
 
410
- - Languages and themes use the same global registry pattern as react-fancy's `registerExtension`.
411
- - Built-in languages/themes are registered via side-effect imports in `languages/builtin.ts` and `themes/light.ts`/`themes/dark.ts`.
412
- - The `sideEffects` field in `package.json` lists these files to prevent tree-shaking.
64
+ - **5 public exports** — `CodeEditor` (+ `Toolbar`, `Toolbar.Separator`, `Panel`, `StatusBar`) and the `useCodeEditor` hook
65
+ - **6 built-in languages** — JavaScript, TypeScript, HTML, PHP, Python, Go
66
+ - **3 built-in themes** — `light`, `dark`, `auto` (follows `prefers-color-scheme`)
67
+ - **Zero third-party dependencies** — custom engine, no Monaco / CodeMirror / Shiki
68
+ - **IDE-ready** — pairs with `TreeNav` from `@particle-academy/react-fancy` for full IDE layouts; see [docs/CodeEditor.md](./docs/CodeEditor.md) for an example.
413
69
 
414
- ### Build
70
+ ## License
415
71
 
416
- - tsup handles the build — ESM, CJS, and `.d.ts` generation.
417
- - `react`, `react-dom`, and `@particle-academy/react-fancy` are external dependencies.
418
- - All editor engine packages are **bundled** (not external) so consumers don't need to install them.
419
- - After any change, verify with `npm run build` from the monorepo root.
72
+ MIT