prism-react-editor
Version:
Lightweight, extensible code editor component for React apps
116 lines (115 loc) • 3.67 kB
JavaScript
"use client";
import { jsx } from "react/jsx-runtime";
import { useRef, useLayoutEffect, useMemo } from "react";
import { k as createTemplate } from "../local-Cq-4Fajb.js";
import { u as useStableRef } from "../core-Dm5I6BkG.js";
const getIndentGuides = (code, tabSize) => {
const lines = code.split("\n");
const l = lines.length;
const stack = [];
const results = [];
for (let prevIndent = 0, emptyPos = -1, i = 0, p = 0; ; i++) {
let last = i == l;
let line = lines[i];
let pos = last ? 0 : line.search(/\S/);
let indent = 0;
let j = 0;
if (pos < 0) {
if (emptyPos < 0) emptyPos = i;
} else {
for (; j < pos; ) {
indent += line[j++] == " " ? tabSize - indent % tabSize : 1;
}
if (indent) indent = Math.ceil(indent / tabSize);
for (j = indent; j < prevIndent; j++) {
stack[j][2] = (emptyPos < 0 || j == indent && !last ? i : emptyPos) - stack[j][0];
}
for (j = prevIndent; j < indent; ) {
results[p++] = stack[j] = [emptyPos < 0 || j > prevIndent ? i : emptyPos, j++, 0];
}
emptyPos = -1;
prevIndent = indent;
}
if (last) break;
}
return results;
};
const guideTemplate = /* @__PURE__ */ createTemplate(
"<div style=width:1px;position:absolute;background:var(--bg-guide-indent)>"
);
const IndentGuides = ({ editor }) => {
let prevLength = 0;
let lineIndentMap;
let active;
const container = useRef(null);
const lines = [];
const indents = [];
const update = (code) => {
lineIndentMap = [];
const tabSize = editor.props.tabSize || 2;
const newIndents = getIndentGuides(code, tabSize);
const l = newIndents.length;
for (let i = 0, prev = [], next = newIndents[0]; next; i++) {
const style = (lines[i] ||= guideTemplate()).style;
const [top, left, height] = next;
const old = indents[i];
next = newIndents[i + 1];
if (top != old?.[0]) style.top = top + "00%";
if (left != old?.[1]) style.left = left + "00%";
if (height != old?.[2]) style.height = height + "00%";
const isSingleIndent = prev[0] != top && next?.[0] != top, isSingleOutdent = prev[0] + prev[1] != top + height && next?.[0] + next?.[1] != top + height;
for (let j = -isSingleIndent, l2 = height + isSingleOutdent; j < l2; j++)
lineIndentMap[j + top] = i;
prev = indents[i] = newIndents[i];
}
for (let i = l; i < prevLength; ) lines[i++].remove();
container.current.append(...lines.slice(prevLength, prevLength = l));
};
const updateActive = () => {
const newActive = lines[lineIndentMap[editor.activeLine - 1]];
if (newActive != active) {
if (active) active.className = "";
if (newActive) newActive.className = "active-indent";
active = newActive;
}
};
const props = editor.props;
const noWrap = !props.wordWrap;
useLayoutEffect(
useStableRef(() => {
const value = editor.value;
const cleanup1 = editor.on("update", update);
const cleanup2 = editor.on("selectionChange", updateActive);
if (value) {
update(value);
updateActive();
}
return () => {
cleanup1();
cleanup2();
};
}),
[props.tabSize]
);
return useMemo(() => {
return /* @__PURE__ */ jsx(
"div",
{
ref: container,
className: "guide-indents",
style: {
left: "var(--padding-left)",
bottom: "auto",
right: "auto",
display: noWrap ? "" : "none"
},
children: " "
}
);
}, [noWrap]);
};
export {
IndentGuides,
getIndentGuides
};
//# sourceMappingURL=guides.js.map