@particle-academy/fancy-code 0.4.0 → 0.4.2
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 +11 -17
- package/dist/index.cjs +34 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +34 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -210,25 +210,19 @@ Add languages beyond the built-ins using `registerLanguage`:
|
|
|
210
210
|
|
|
211
211
|
```tsx
|
|
212
212
|
import { registerLanguage } from "@particle-academy/fancy-code";
|
|
213
|
+
import type { Tokenizer } from "@particle-academy/fancy-code";
|
|
213
214
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return python();
|
|
221
|
-
},
|
|
222
|
-
});
|
|
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
|
+
};
|
|
223
221
|
|
|
224
|
-
// Lazy-loaded
|
|
225
222
|
registerLanguage({
|
|
226
|
-
name: "
|
|
227
|
-
aliases: ["
|
|
228
|
-
|
|
229
|
-
const { rust } = await import("@codemirror/lang-rust");
|
|
230
|
-
return rust();
|
|
231
|
-
},
|
|
223
|
+
name: "Ruby",
|
|
224
|
+
aliases: ["rb", "ruby"],
|
|
225
|
+
tokenize: tokenizeRuby,
|
|
232
226
|
});
|
|
233
227
|
```
|
|
234
228
|
|
|
@@ -323,7 +317,7 @@ src/
|
|
|
323
317
|
│ ├── CodeEditorStatusBar.tsx # Cursor/language/tab display
|
|
324
318
|
│ └── index.ts
|
|
325
319
|
├── hooks/
|
|
326
|
-
│ ├── use-
|
|
320
|
+
│ ├── use-editor-engine.ts # Core editor lifecycle
|
|
327
321
|
│ └── use-dark-mode.ts # Reactive prefers-color-scheme
|
|
328
322
|
├── languages/
|
|
329
323
|
│ ├── registry.ts # Global language registry
|
package/dist/index.cjs
CHANGED
|
@@ -85,7 +85,7 @@ function CodeEditorPanel({ className }) {
|
|
|
85
85
|
children: lineNumberElements
|
|
86
86
|
}
|
|
87
87
|
),
|
|
88
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-w-0
|
|
88
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: reactFancy.cn("relative flex-1", wordWrap && "min-w-0"), children: [
|
|
89
89
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
90
90
|
"pre",
|
|
91
91
|
{
|
|
@@ -110,10 +110,14 @@ function CodeEditorPanel({ className }) {
|
|
|
110
110
|
"textarea",
|
|
111
111
|
{
|
|
112
112
|
ref: textareaRef,
|
|
113
|
-
className:
|
|
113
|
+
className: reactFancy.cn(
|
|
114
|
+
"relative m-0 block resize-none border-none bg-transparent p-2.5 text-[13px] leading-[1.5] text-transparent outline-none",
|
|
115
|
+
wordWrap ? "w-full" : "min-w-full"
|
|
116
|
+
),
|
|
114
117
|
style: {
|
|
115
118
|
caretColor: themeColors.cursorColor,
|
|
116
119
|
minHeight: _minHeight ? _minHeight - 40 : 80,
|
|
120
|
+
overflow: "hidden",
|
|
117
121
|
whiteSpace: wordWrap ? "pre-wrap" : "pre",
|
|
118
122
|
overflowWrap: wordWrap ? "break-word" : "normal"
|
|
119
123
|
},
|
|
@@ -1294,6 +1298,7 @@ function useEditorEngine({
|
|
|
1294
1298
|
language,
|
|
1295
1299
|
theme,
|
|
1296
1300
|
readOnly,
|
|
1301
|
+
wordWrap,
|
|
1297
1302
|
tabSize,
|
|
1298
1303
|
onCursorChange
|
|
1299
1304
|
}) {
|
|
@@ -1327,14 +1332,29 @@ function useEditorEngine({
|
|
|
1327
1332
|
}
|
|
1328
1333
|
return count;
|
|
1329
1334
|
}, [value]);
|
|
1335
|
+
const autoResize = react.useCallback(() => {
|
|
1336
|
+
const ta = textareaRef.current;
|
|
1337
|
+
if (!ta) return;
|
|
1338
|
+
ta.style.height = "auto";
|
|
1339
|
+
ta.style.height = ta.scrollHeight + "px";
|
|
1340
|
+
if (!wordWrap) {
|
|
1341
|
+
ta.style.width = "0";
|
|
1342
|
+
ta.style.width = ta.scrollWidth + "px";
|
|
1343
|
+
} else {
|
|
1344
|
+
ta.style.width = "";
|
|
1345
|
+
}
|
|
1346
|
+
}, [wordWrap]);
|
|
1330
1347
|
react.useEffect(() => {
|
|
1331
1348
|
const ta = textareaRef.current;
|
|
1332
|
-
if (!ta
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1349
|
+
if (!ta) return;
|
|
1350
|
+
if (ta.value !== value) {
|
|
1351
|
+
const { selectionStart, selectionEnd } = ta;
|
|
1352
|
+
ta.value = value;
|
|
1353
|
+
ta.selectionStart = selectionStart;
|
|
1354
|
+
ta.selectionEnd = selectionEnd;
|
|
1355
|
+
}
|
|
1356
|
+
autoResize();
|
|
1357
|
+
}, [value, autoResize]);
|
|
1338
1358
|
const updateCursorInfo = react.useCallback(() => {
|
|
1339
1359
|
const ta = textareaRef.current;
|
|
1340
1360
|
if (!ta) return;
|
|
@@ -1351,8 +1371,9 @@ function useEditorEngine({
|
|
|
1351
1371
|
const ta = textareaRef.current;
|
|
1352
1372
|
if (!ta) return;
|
|
1353
1373
|
onChangeRef.current?.(ta.value);
|
|
1374
|
+
autoResize();
|
|
1354
1375
|
updateCursorInfo();
|
|
1355
|
-
}, [updateCursorInfo]);
|
|
1376
|
+
}, [autoResize, updateCursorInfo]);
|
|
1356
1377
|
const handleSelect = react.useCallback(() => {
|
|
1357
1378
|
updateCursorInfo();
|
|
1358
1379
|
}, [updateCursorInfo]);
|
|
@@ -1412,6 +1433,7 @@ function useEditorEngine({
|
|
|
1412
1433
|
ta.selectionStart = ta.selectionEnd = start + tabSize;
|
|
1413
1434
|
onChangeRef.current?.(ta.value);
|
|
1414
1435
|
}
|
|
1436
|
+
autoResize();
|
|
1415
1437
|
updateCursorInfo();
|
|
1416
1438
|
return;
|
|
1417
1439
|
}
|
|
@@ -1430,11 +1452,12 @@ function useEditorEngine({
|
|
|
1430
1452
|
ta.value = before + insertion + after;
|
|
1431
1453
|
ta.selectionStart = ta.selectionEnd = start + insertion.length;
|
|
1432
1454
|
onChangeRef.current?.(ta.value);
|
|
1455
|
+
autoResize();
|
|
1433
1456
|
updateCursorInfo();
|
|
1434
1457
|
return;
|
|
1435
1458
|
}
|
|
1436
1459
|
},
|
|
1437
|
-
[readOnly, tabSize, updateCursorInfo]
|
|
1460
|
+
[readOnly, tabSize, autoResize, updateCursorInfo]
|
|
1438
1461
|
);
|
|
1439
1462
|
return {
|
|
1440
1463
|
textareaRef,
|
|
@@ -1508,6 +1531,7 @@ function CodeEditorRoot({
|
|
|
1508
1531
|
language: currentLanguage,
|
|
1509
1532
|
theme: resolvedTheme,
|
|
1510
1533
|
readOnly,
|
|
1534
|
+
wordWrap: isWordWrap,
|
|
1511
1535
|
tabSize: tabSizeProp,
|
|
1512
1536
|
onCursorChange: ({ line, col, selectionLength: sel }) => {
|
|
1513
1537
|
setCursorPosition({ line, col });
|