mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
Add markdown link tooltip support to the visual editor
GitOrigin-RevId: 7ab4fd0793f057c86e4fc0307d81df376efe4d34
This commit is contained in:
committed by
Copybot
parent
93a4f0c88a
commit
8ccdc0fbc4
+13
-4
@@ -5,8 +5,10 @@ import {
|
|||||||
} from './codemirror-context'
|
} from './codemirror-context'
|
||||||
import {
|
import {
|
||||||
closeCommandTooltip,
|
closeCommandTooltip,
|
||||||
|
commandTooltipHandlers,
|
||||||
commandTooltipState,
|
commandTooltipState,
|
||||||
} from '../extensions/command-tooltip'
|
} from '../extensions/command-tooltip'
|
||||||
|
import type { CommandTooltipHandler } from '../extensions/command-tooltip'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import { HrefTooltipContent } from './command-tooltip/href-tooltip'
|
import { HrefTooltipContent } from './command-tooltip/href-tooltip'
|
||||||
import { UrlTooltipContent } from './command-tooltip/url-tooltip'
|
import { UrlTooltipContent } from './command-tooltip/url-tooltip'
|
||||||
@@ -68,14 +70,18 @@ export const CodeMirrorCommandTooltip = memo(function CodeMirrorLinkTooltip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ReactDOM.createPortal(
|
return ReactDOM.createPortal(
|
||||||
<CodeMirrorCommandTooltipContent command={tooltipState.command} />,
|
<CodeMirrorCommandTooltipContent
|
||||||
|
command={tooltipState.command}
|
||||||
|
handlers={state.facet(commandTooltipHandlers)}
|
||||||
|
/>,
|
||||||
tooltipView.dom
|
tooltipView.dom
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const CodeMirrorCommandTooltipContent = memo<{
|
const CodeMirrorCommandTooltipContent = memo<{
|
||||||
command: string
|
command: string
|
||||||
}>(function CodeMirrorCommandTooltipContent({ command }) {
|
handlers: readonly CommandTooltipHandler[]
|
||||||
|
}>(function CodeMirrorCommandTooltipContent({ command, handlers }) {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'HrefCommand':
|
case 'HrefCommand':
|
||||||
return <HrefTooltipContent />
|
return <HrefTooltipContent />
|
||||||
@@ -89,7 +95,10 @@ const CodeMirrorCommandTooltipContent = memo<{
|
|||||||
return <InputTooltipContent />
|
return <InputTooltipContent />
|
||||||
case 'Subfile':
|
case 'Subfile':
|
||||||
return <SubfileTooltipContent />
|
return <SubfileTooltipContent />
|
||||||
default:
|
default: {
|
||||||
return null
|
// Tooltips contributed by modules via the `commandTooltipHandlers` facet
|
||||||
|
const handler = handlers.find(handler => handler.command === command)
|
||||||
|
return handler ? handler.render() : null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ import {
|
|||||||
import {
|
import {
|
||||||
EditorSelection,
|
EditorSelection,
|
||||||
EditorState,
|
EditorState,
|
||||||
|
Facet,
|
||||||
Prec,
|
Prec,
|
||||||
SelectionRange,
|
SelectionRange,
|
||||||
StateEffect,
|
StateEffect,
|
||||||
StateField,
|
StateField,
|
||||||
} from '@codemirror/state'
|
} from '@codemirror/state'
|
||||||
|
import type { ReactNode } from 'react'
|
||||||
import { ancestorOfNodeWithType } from '../utils/tree-query'
|
import { ancestorOfNodeWithType } from '../utils/tree-query'
|
||||||
import { ensureSyntaxTree, syntaxTree } from '@codemirror/language'
|
import { ensureSyntaxTree, syntaxTree } from '@codemirror/language'
|
||||||
import {
|
import {
|
||||||
@@ -32,12 +34,30 @@ import {
|
|||||||
} from '@codemirror/autocomplete'
|
} from '@codemirror/autocomplete'
|
||||||
import { SyntaxNode } from '@lezer/common'
|
import { SyntaxNode } from '@lezer/common'
|
||||||
|
|
||||||
type ActiveTooltip = {
|
export type ActiveTooltip = {
|
||||||
range: SelectionRange
|
range: SelectionRange
|
||||||
tooltip: Tooltip
|
tooltip: Tooltip
|
||||||
command: string
|
command: string
|
||||||
} | null
|
} | null
|
||||||
|
|
||||||
|
export type CommandTooltipContext = {
|
||||||
|
state: EditorState
|
||||||
|
pos: number
|
||||||
|
value: ActiveTooltip
|
||||||
|
commandNode: SyntaxNode
|
||||||
|
}
|
||||||
|
|
||||||
|
// A command-tooltip handler lets a module add a tooltip for a syntax node type
|
||||||
|
// that isn't part of the LaTeX `$CommandTooltipCommand` group (e.g. the
|
||||||
|
// markdown `Link` node)
|
||||||
|
export type CommandTooltipHandler = {
|
||||||
|
command: string
|
||||||
|
createTooltip: (context: CommandTooltipContext) => ActiveTooltip
|
||||||
|
render: () => ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export const commandTooltipHandlers = Facet.define<CommandTooltipHandler>()
|
||||||
|
|
||||||
const createTooltipView = (
|
const createTooltipView = (
|
||||||
update?: (update: ViewUpdate) => void
|
update?: (update: ViewUpdate) => void
|
||||||
): TooltipView => {
|
): TooltipView => {
|
||||||
@@ -47,7 +67,7 @@ const createTooltipView = (
|
|||||||
return { dom, update }
|
return { dom, update }
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildTooltip = (
|
export const buildTooltip = (
|
||||||
command: string,
|
command: string,
|
||||||
pos: number,
|
pos: number,
|
||||||
value: ActiveTooltip,
|
value: ActiveTooltip,
|
||||||
@@ -89,7 +109,12 @@ const createTooltipState = (
|
|||||||
const { main } = state.selection
|
const { main } = state.selection
|
||||||
const pos = main.head
|
const pos = main.head
|
||||||
const node = syntaxTree(state).resolveInner(pos, 0)
|
const node = syntaxTree(state).resolveInner(pos, 0)
|
||||||
const commandNode = ancestorOfNodeWithType(node, '$CommandTooltipCommand')
|
const moduleHandlers = state.facet(commandTooltipHandlers)
|
||||||
|
const commandNode = ancestorOfNodeWithType(
|
||||||
|
node,
|
||||||
|
'$CommandTooltipCommand',
|
||||||
|
...moduleHandlers.map(handler => handler.command)
|
||||||
|
)
|
||||||
if (!commandNode) {
|
if (!commandNode) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -99,6 +124,15 @@ const createTooltipState = (
|
|||||||
}
|
}
|
||||||
const commandName = commandNode.name
|
const commandName = commandNode.name
|
||||||
|
|
||||||
|
// Module-provided handlers (e.g. the markdown link tooltip) take priority
|
||||||
|
// over the built-in LaTeX commands below.
|
||||||
|
const handler = moduleHandlers.find(
|
||||||
|
handler => handler.command === commandName
|
||||||
|
)
|
||||||
|
if (handler) {
|
||||||
|
return handler.createTooltip({ state, pos, value, commandNode })
|
||||||
|
}
|
||||||
|
|
||||||
switch (commandName) {
|
switch (commandName) {
|
||||||
// a hyperlink (\href)
|
// a hyperlink (\href)
|
||||||
case 'HrefCommand': {
|
case 'HrefCommand': {
|
||||||
@@ -317,7 +351,7 @@ export const commandTooltipState = (
|
|||||||
state: EditorState
|
state: EditorState
|
||||||
): ActiveTooltip | undefined => state.field(commandTooltipStateField, false)
|
): ActiveTooltip | undefined => state.field(commandTooltipStateField, false)
|
||||||
|
|
||||||
const firstInteractiveElement = (
|
export const firstInteractiveElement = (
|
||||||
view: EditorView,
|
view: EditorView,
|
||||||
tooltipState: NonNullable<ActiveTooltip>
|
tooltipState: NonNullable<ActiveTooltip>
|
||||||
) =>
|
) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user