From 6aa2f73a956cc5b6f00a5c3e4d62dc0ca4f3e67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Fri, 10 Nov 2023 13:32:06 +0100 Subject: [PATCH] [dome/richtext] gutter clicks --- ivette/src/dome/renderer/text/richtext.tsx | 29 +++++++++++++++++++--- ivette/src/sandbox/text.tsx | 12 +++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/ivette/src/dome/renderer/text/richtext.tsx b/ivette/src/dome/renderer/text/richtext.tsx index a78353fff81..22405ddb87c 100644 --- a/ivette/src/dome/renderer/text/richtext.tsx +++ b/ivette/src/dome/renderer/text/richtext.tsx @@ -479,12 +479,26 @@ const OnClick = new MouseCallbackField(); const OnPopup = new MouseCallbackField(); const OnHover = new MouseCallbackField(); const OnDouble = new MouseCallbackField(); +const OnGutter = new MouseCallbackField(); + +const gutterEventHandlers = { + click: (view: CM.EditorView, block: CM.BlockInfo, evt: Event) => { + const fn = view.state.field(OnGutter.field); + if (fn) { + const offset = block.from; + const line = view.state.doc.lineAt(offset).number; + fn({ offset, line }, evt as MouseEvent); + } + return false; + } +}; const MouseEvents : CS.Extension = [ OnClick, OnHover, OnPopup, OnDouble, + OnGutter, CM.EditorView.domEventHandlers({ click: (evt: MouseEvent, view: CM.EditorView) => { OnClick.callback(evt, view); @@ -618,7 +632,7 @@ class GutterMark extends CM.GutterMarker { const { gutter, className, title } = this.spec; const textNode = document.createTextNode(gutter); if (!className && !title) return textNode; - const span = document.createElement("div"); + const span = document.createElement("span"); span.appendChild(textNode); if (className) span.className = className; if (title) span.title = title; @@ -759,14 +773,20 @@ function dispatchDecorations(view: View, spec: Decorations): void { const Decorations: CS.Extension = [ DecoratorState, CM.EditorView.decorations.from(DecoratorState, ({ ranges }) => ranges), - CM.gutter({ markers: (view) => view.state.field(DecoratorState).gutters, }), + OnGutter, + CM.gutter({ + markers: (view) => view.state.field(DecoratorState).gutters, + domEventHandlers: gutterEventHandlers, + }), ]; /* -------------------------------------------------------------------------- */ /* --- Line Numbers --- */ /* -------------------------------------------------------------------------- */ -const LineNumbers = new Option(CM.lineNumbers()); +const LineNumbers = new Option( + CM.lineNumbers({ domEventHandlers: gutterEventHandlers }) +); /* -------------------------------------------------------------------------- */ /* --- Active Line --- */ @@ -810,6 +830,7 @@ export interface TextViewProps { onClick?: MouseCallback; onPopup?: MouseCallback; onHover?: MouseCallback; + onGutter?: MouseCallback; onDoubleClick?: MouseCallback; decorations?: Decorations; lineNumbers?: boolean; @@ -838,6 +859,7 @@ export function TextView(props: TextViewProps) : JSX.Element { onClick = null, onPopup = null, onHover = null, + onGutter = null, onChange = null, readOnly = false, onViewport: onReview = null, @@ -850,6 +872,7 @@ export function TextView(props: TextViewProps) : JSX.Element { React.useEffect(() => OnPopup.dispatch(view, onPopup), [view, onPopup]); React.useEffect(() => OnHover.dispatch(view, onHover), [view, onHover]); React.useEffect(() => OnDouble.dispatch(view, onDouble), [view, onDouble]); + React.useEffect(() => OnGutter.dispatch(view, onGutter), [view, onGutter]); React.useEffect(() => OnChange.dispatch(view, onChange), [view, onChange]); React.useEffect(() => OnSelect.dispatch(view, onSelect), [view, onSelect]); React.useEffect(() => Viewport.dispatch(view, onReview), [view, onReview]); diff --git a/ivette/src/sandbox/text.tsx b/ivette/src/sandbox/text.tsx index 6b588b943c3..e1e9bf2c6ae 100644 --- a/ivette/src/sandbox/text.tsx +++ b/ivette/src/sandbox/text.tsx @@ -102,7 +102,7 @@ function UseText(): JSX.Element { setDecorations([...decorations, { line: s.fromLine, className: 'line-decoration', - title: 'Line Decorated' + title: 'Line Decorated', }]); }, [decorations, s]); @@ -111,6 +111,7 @@ function UseText(): JSX.Element { setDecorations([...decorations, { line: s.fromLine, gutter: '*', + title: 'Gutter Mark', }]); }, [decorations, s]); @@ -122,7 +123,7 @@ function UseText(): JSX.Element { }, [decorations, h]); const clearEvent = React.useCallback(() => setEvent(''), []); - const triggerCancelEvent = Dome.useDebounced(clearEvent, 1000); + const triggerCancelEvent = Dome.useDebounced(clearEvent, 1200); const onClick = React.useCallback( (pos: Position | null, evt: MouseEvent) => { @@ -147,6 +148,12 @@ function UseText(): JSX.Element { triggerCancelEvent(); }, [triggerCancelEvent]); + const onGutter = React.useCallback( + (pos: Position | null) => { + setEvent(`Gutter-Click L${pos ? pos.line : 'null'}`); + triggerCancelEvent(); + }, [triggerCancelEvent]); + return ( <> <ToolBar> @@ -213,6 +220,7 @@ function UseText(): JSX.Element { onHover={onHover} onClick={onClick} onPopup={onPopup} + onGutter={onGutter} onDoubleClick={onDoubleClick} onViewport={onViewport} decorations={allDecorations} -- GitLab