@particle-academy/fancy-code 0.6.0 → 0.7.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.
- package/dist/index.cjs +46 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +47 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1346,6 +1346,19 @@ function highlightCode(source, tokens, colors) {
|
|
|
1346
1346
|
return parts.join("");
|
|
1347
1347
|
}
|
|
1348
1348
|
|
|
1349
|
+
// src/engine/position.ts
|
|
1350
|
+
function lineColumnToOffset(text, line, column = 1) {
|
|
1351
|
+
const lines = text.split("\n");
|
|
1352
|
+
const targetLine = Math.max(1, Math.min(Math.trunc(line) || 1, lines.length));
|
|
1353
|
+
let offset = 0;
|
|
1354
|
+
for (let i = 0; i < targetLine - 1; i++) {
|
|
1355
|
+
offset += lines[i].length + 1;
|
|
1356
|
+
}
|
|
1357
|
+
const lineText = lines[targetLine - 1] ?? "";
|
|
1358
|
+
const col = Math.max(1, Math.min(Math.trunc(column) || 1, lineText.length + 1));
|
|
1359
|
+
return offset + (col - 1);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1349
1362
|
// src/hooks/use-editor-engine.ts
|
|
1350
1363
|
var DEFAULT_COLORS = {
|
|
1351
1364
|
background: "#18181b",
|
|
@@ -1460,6 +1473,28 @@ function useEditorEngine({
|
|
|
1460
1473
|
setScrollTop(ta.scrollTop);
|
|
1461
1474
|
setScrollLeft(ta.scrollLeft);
|
|
1462
1475
|
}, []);
|
|
1476
|
+
const revealLine = react.useCallback(
|
|
1477
|
+
(line, column = 1, opts) => {
|
|
1478
|
+
const ta = textareaRef.current;
|
|
1479
|
+
if (!ta) return;
|
|
1480
|
+
const offset = lineColumnToOffset(ta.value, line, column);
|
|
1481
|
+
if (opts?.focus) ta.focus();
|
|
1482
|
+
ta.selectionStart = ta.selectionEnd = offset;
|
|
1483
|
+
updateCursorInfo();
|
|
1484
|
+
const panel = ta.closest("[data-fancy-code-panel]");
|
|
1485
|
+
if (!panel) return;
|
|
1486
|
+
const cs = getComputedStyle(ta);
|
|
1487
|
+
const lineHeight = parseFloat(cs.lineHeight) || 19.5;
|
|
1488
|
+
const paddingTop = parseFloat(cs.paddingTop) || 0;
|
|
1489
|
+
const lineIndex = (ta.value.slice(0, offset).match(/\n/g) || []).length;
|
|
1490
|
+
const textareaTopInPanel = ta.getBoundingClientRect().top - panel.getBoundingClientRect().top + panel.scrollTop;
|
|
1491
|
+
const lineTop = textareaTopInPanel + paddingTop + lineIndex * lineHeight;
|
|
1492
|
+
const target = lineTop - panel.clientHeight / 2 + lineHeight / 2;
|
|
1493
|
+
const maxScroll = panel.scrollHeight - panel.clientHeight;
|
|
1494
|
+
panel.scrollTop = Math.max(0, Math.min(target, maxScroll));
|
|
1495
|
+
},
|
|
1496
|
+
[updateCursorInfo]
|
|
1497
|
+
);
|
|
1463
1498
|
const handleKeyDown = react.useCallback(
|
|
1464
1499
|
(e) => {
|
|
1465
1500
|
if (readOnly) {
|
|
@@ -1546,6 +1581,7 @@ function useEditorEngine({
|
|
|
1546
1581
|
handleInput,
|
|
1547
1582
|
handleScroll,
|
|
1548
1583
|
handleSelect,
|
|
1584
|
+
revealLine,
|
|
1549
1585
|
scrollTop,
|
|
1550
1586
|
scrollLeft
|
|
1551
1587
|
};
|
|
@@ -1579,7 +1615,9 @@ function CodeEditorRoot({
|
|
|
1579
1615
|
tabSize: tabSizeProp = 2,
|
|
1580
1616
|
placeholder,
|
|
1581
1617
|
minHeight,
|
|
1582
|
-
maxHeight
|
|
1618
|
+
maxHeight,
|
|
1619
|
+
cursorLine,
|
|
1620
|
+
cursorColumn
|
|
1583
1621
|
}) {
|
|
1584
1622
|
const [currentValue, setCurrentValue] = reactFancy.useControllableState(valueProp, defaultValue, onChange);
|
|
1585
1623
|
const isDark = useDarkMode();
|
|
@@ -1615,6 +1653,11 @@ function CodeEditorRoot({
|
|
|
1615
1653
|
setSelectionLength(sel);
|
|
1616
1654
|
}
|
|
1617
1655
|
});
|
|
1656
|
+
const { revealLine: revealLineImpl } = engineReturn;
|
|
1657
|
+
react.useEffect(() => {
|
|
1658
|
+
if (cursorLine == null) return;
|
|
1659
|
+
revealLineImpl(cursorLine, cursorColumn ?? 1, { focus: false });
|
|
1660
|
+
}, [cursorLine, cursorColumn, revealLineImpl]);
|
|
1618
1661
|
const contextValue = react.useMemo(
|
|
1619
1662
|
() => ({
|
|
1620
1663
|
getValue: () => engineReturn.textareaRef.current?.value ?? currentValue,
|
|
@@ -1636,6 +1679,8 @@ function CodeEditorRoot({
|
|
|
1636
1679
|
setCurrentValue(ta.value);
|
|
1637
1680
|
},
|
|
1638
1681
|
focus: () => engineReturn.textareaRef.current?.focus(),
|
|
1682
|
+
revealLine: (line, column) => engineReturn.revealLine(line, column ?? 1, { focus: true }),
|
|
1683
|
+
setCursor: ({ line, column }) => engineReturn.revealLine(line, column ?? 1, { focus: true }),
|
|
1639
1684
|
language: currentLanguage,
|
|
1640
1685
|
setLanguage,
|
|
1641
1686
|
theme: resolvedTheme,
|