UNPKG

shahnevis-core

Version:

**Shahnevis Core** is a lightweight and flexible library for building custom code editors. It provides essential features like syntax highlighting, a minimap, multi-cursor support, line numbering, and plugin management. This library is framework-agnostic,

139 lines (118 loc) 5.96 kB
/* This file is part of Shahnevis Core. Copyright (C) 2024 shahrooz saneidarani (github.com/shahroozD) Shahnevis Core is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Shahnevis Core is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ export function updateMinimapContent(minimapContent, highlighter) { // Update the minimap content based on the highlighted code minimapContent.innerHTML = highlighter.innerHTML; } export function syncMinimapScroll(codeEditor, minimap, minimapScrollbar) { // Calculate the scroll percentage of the editor var editorScrollPercentage = codeEditor.scrollTop / (codeEditor.scrollHeight - codeEditor.clientHeight); // Calculate scrollbar height proportionally to the minimap and editor heights var scrollbarHeight = codeEditor.clientHeight / codeEditor.scrollHeight * minimap.clientHeight; // Adjust the minimap scrollbar height and position based on the scroll percentage minimapScrollbar.style.height = "".concat(scrollbarHeight, "px"); minimapScrollbar.style.top = "".concat(editorScrollPercentage * (minimap.clientHeight - scrollbarHeight), "px"); } export function handleMinimapClick(event, codeEditor, minimap) { // Calculate where the user clicked within the minimap var minimapClickPercentage = event.offsetY / minimap.clientHeight; // Calculate the new scroll position in the editor based on where they clicked in the minimap var editorScrollPosition = minimapClickPercentage * (codeEditor.scrollHeight - codeEditor.clientHeight); // Set the editor's scroll position accordingly codeEditor.scrollTop = editorScrollPosition; } export default function minimapHandler(editor, codeEditor, highlighter, minimap, minimapContent, minimapScrollbar) { // Sync the minimap with the editor's content and scroll var updateContentAndScroll = function updateContentAndScroll() { updateMinimapContent(minimapContent, highlighter); syncMinimapScroll(codeEditor, minimap, minimapScrollbar); }; // Event listener for input in the editor var onInput = function onInput() { updateContentAndScroll(); }; // Event listener for scroll in the code editor var onScroll = function onScroll() { syncMinimapScroll(codeEditor, minimap, minimapScrollbar); }; // Event listener for clicking on the minimap to navigate var onMinimapClick = function onMinimapClick(event) { handleMinimapClick(event, codeEditor, minimap); }; // Combined mousedown handler for both click and drag var onMinimapMouseDown = function onMinimapMouseDown(event) { // Prevent default behavior (like text selection) event.preventDefault(); // Record the starting coordinates and scroll position var startX = event.clientX; var startY = event.clientY; var dragged = false; var startScrollTop = codeEditor.scrollTop; // Calculate the total scrollable area of the code editor var codeEditorScrollableHeight = codeEditor.scrollHeight - codeEditor.clientHeight; // Determine the minimap dimensions and thumb limits var minimapHeight = minimap.clientHeight; var thumbHeight = minimapScrollbar.clientHeight; var maxThumbMove = minimapHeight - thumbHeight; // Mousemove handler to update the scroll position if dragging occurs var onMouseMove = function onMouseMove(e) { var deltaX = Math.abs(e.clientX - startX); var deltaY = Math.abs(e.clientY - startY); // If the movement exceeds a small threshold, consider it a drag. if (!dragged && (deltaX > 5 || deltaY > 5)) { dragged = true; // Change the cursor to indicate dragging minimap.style.cursor = 'grabbing'; } if (dragged) { // Calculate how much the mouse has moved vertically var moveY = e.clientY - startY; // Convert thumb movement into a scroll delta for the code editor var scrollDelta = moveY / maxThumbMove * codeEditorScrollableHeight; var newScrollTop = startScrollTop + scrollDelta; // Clamp the new scroll position within valid bounds newScrollTop = Math.max(0, Math.min(newScrollTop, codeEditorScrollableHeight)); codeEditor.scrollTop = newScrollTop; // Update the minimap thumb position using your sync function syncMinimapScroll(codeEditor, minimap, minimapScrollbar); } }; // Mouseup handler: if no dragging occurred, treat as a click. var onMouseUp = function onMouseUp(e) { window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mouseup", onMouseUp); // Restore the original cursor regardless of the action minimap.style.cursor = ''; // If the mouse hasn't moved much, it's a click rather than a drag. if (!dragged) { onMinimapClick(e); } }; window.addEventListener("mousemove", onMouseMove); window.addEventListener("mouseup", onMouseUp); }; // Add event listeners (only once) editor.addEventListener('input', onInput); codeEditor.addEventListener('scroll', onScroll); minimap.addEventListener('mousedown', onMinimapMouseDown); // Initialize the minimap with current content and scroll position updateContentAndScroll(); // Optionally, return a cleanup function (useful if used in a React useEffect) return function cleanup() { editor.removeEventListener('input', onInput); codeEditor.removeEventListener('scroll', onScroll); minimap.removeEventListener('mousedown', onMinimapMouseDown); }; }