import { EditorState, TextSelection } from "prosemirror-state"; import { UxCommand } from "../constants"; import { LinkAttr, schema } from "../schema"; import { Command, Dispatch, DocPos } from "../types"; import { getPluginStateOrThrow, LinkPluginStateType, pickIdleOrDetail, setPluginState, transition, tryComposeAttemptOnRange } from "./LinkPlugin"; /** * Compose a text link from the current selection. */ export const composeTextLink: Command = function composeTextLink(state, dispatch) { const { selection } = state; if (selection instanceof TextSelection) { const pluginState = getPluginStateOrThrow(state); if (pluginState.type === LinkPluginStateType.IDLE) { const { from, to } = selection; const draft = tryComposeAttemptOnRange(state.doc, { from: from as DocPos, to: to as DocPos }); if (draft !== null) { if (dispatch !== undefined) { setPluginState({ state, dispatch }, transition(pluginState).showComposer(draft)); } return true; } } } return false; }; export const editTextLink: Command = function editTextLink(state, dispatch) { const pluginState = getPluginStateOrThrow(state); if (pluginState.type === LinkPluginStateType.SHOW_DETAIL) { if (dispatch !== undefined) { setPluginState({ state, dispatch }, transition(pluginState).showEditor(pluginState.link)); } return true; } return false; }; export const saveTextLink = function saveTextLink( state: EditorState, link: { text: string; url: string }, dispatch?: Dispatch ): boolean { const pluginState = getPluginStateOrThrow(state); if (pluginState.type === LinkPluginStateType.SHOW_EDITOR || pluginState.type === LinkPluginStateType.SHOW_COMPOSER) { if (dispatch !== undefined) { const markRange = pluginState.type === LinkPluginStateType.SHOW_EDITOR ? pluginState.link.range : pluginState.draft.markRange; const textRange = pluginState.type === LinkPluginStateType.SHOW_EDITOR ? pluginState.link.range : pluginState.draft.textRange; const mark = schema.marks.l.create({ [LinkAttr.URL]: link.url }); const tr = state.tr .removeMark(markRange.from, markRange.to, schema.marks.l) .addMark(markRange.from, markRange.to, mark) .replaceRangeWith(textRange.from, textRange.to, schema.text(link.text, [mark])); setPluginState({ state, tr, dispatch }, pickIdleOrDetail(tr)); } return true; } return false; }; export const removeLink: Command = function removeLink(state, dispatch) { const pluginState = getPluginStateOrThrow(state); if (pluginState.type === LinkPluginStateType.SHOW_EDITOR || pluginState.type === LinkPluginStateType.SHOW_DETAIL) { if (dispatch !== undefined) { const { from, to } = pluginState.link.range; const tr = state.tr.removeMark(from, to, schema.marks.l); setPluginState({ state, tr }, pickIdleOrDetail(tr)); dispatch(tr); } return true; } return false; }; export const dismissEditorOrComposer: Command = function dismissEditorOrComposer(state, dispatch) { if (dispatch !== undefined) { setPluginState({ state, dispatch }, pickIdleOrDetail(state)); } return true; }; export const ux = { [UxCommand.ComposeLink]: composeTextLink };