This repository has been archived by the owner on Jul 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Currently still contains a bug, see enzoferey/slate-instant-replace#1. Add is-url as dependency Add slate-instant-replace as dependency
- Loading branch information
Showing
5 changed files
with
158 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React from 'react' | ||
|
||
import InstantReplace from 'slate-instant-replace' | ||
import isUrl from 'is-url' | ||
|
||
export default function AutoURL(options) { | ||
return { | ||
changes: {}, | ||
helpers: {}, | ||
components: {}, | ||
plugins: [ | ||
InstantReplace(AddURL), | ||
RenderLinkNode | ||
], | ||
} | ||
} | ||
|
||
const wrapLink = (change, href) => { | ||
change.wrapInline({ | ||
type: 'link', | ||
data: { href } | ||
}) | ||
change.collapseToEnd() | ||
} | ||
|
||
const unwrapLink = (change) => { | ||
change.unwrapInline('link') | ||
} | ||
|
||
const AddURL = (change, lastWord) => { | ||
if(isUrl(lastWord)) { | ||
change.extend(-lastWord.length) | ||
change.focus() | ||
|
||
change.call(unwrapLink) | ||
|
||
const href = lastWord.startsWith('http') ? lastWord : `https://${lastWord}`; | ||
|
||
change.call(wrapLink, href) | ||
} | ||
} | ||
|
||
function LinkNode(props) { | ||
const { attributes, children, node } = props | ||
const { data } = node | ||
const href = data.get('href') | ||
|
||
return ( | ||
<a { ...attributes } href={href}> | ||
{ children } | ||
</a> | ||
) | ||
} | ||
|
||
const RenderLinkNode = { | ||
renderNode(props) { | ||
return props.node.type === 'link' ? <LinkNode {...props} /> : null | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { Inline } from "slate"; | ||
|
||
export const isPrintableChar = event => event.key.length === 1; | ||
|
||
export const isCtrlOrCmd = event => event.ctrlKey || event.metaKey; | ||
|
||
const isSpace = event => event.key === " "; | ||
|
||
const getSelection = change => change.value.fragment.text; | ||
|
||
const getLastWordRec = (change, maxIndex, counter = 0) => { | ||
// If first char of the input is found just select everything (single word) | ||
// console.log(`counter ${counter} and maxi ${maxIndex}`) | ||
console.log(`start: ${change.value.selection.startKey} and end ${change.value.selection.endKey}`) | ||
console.log(`counter is ${counter} and maxi ${maxIndex}`) | ||
// alert() | ||
if (counter === maxIndex) { | ||
console.log('I AM IN') | ||
const selectedWord = getSelection(change); | ||
change.extend(counter); | ||
console.log(`extended by ${counter}`) | ||
return selectedWord; | ||
} | ||
|
||
// Move selection | ||
const selectedWord = getSelection(change.extend(-1)); | ||
|
||
// Exit condition | ||
if (selectedWord[0] === " ") { | ||
change.extend(counter + 1); // one more needed because space | ||
return selectedWord.substring(1); | ||
} | ||
|
||
return getLastWordRec(change, maxIndex, counter + 1); | ||
}; | ||
|
||
export const getLastWord = change => { | ||
const offsetCurrentWord = change.value.focusOffset; | ||
return getLastWordRec(change, offsetCurrentWord); | ||
}; | ||
|
||
const getPreviousNode = change => { | ||
const block = change.value.focusBlock; | ||
const activeKey = change.value.selection.focusKey; | ||
return block.getPreviousSibling(activeKey); | ||
}; | ||
|
||
export const focusPreviousNode = change => { | ||
const offsetCurrentWord = change.value.focusOffset; | ||
// check if we just started a the node | ||
if (offsetCurrentWord === 0) { | ||
const previousNode = getPreviousNode(change); | ||
if (previousNode && Inline.isInline(previousNode)) { | ||
change.extendToEndOf(previousNode).focus(); | ||
} | ||
} | ||
}; | ||
|
||
const InstantReplace = transforms => ({ | ||
onKeyDown(event, change) { | ||
if (!isPrintableChar(event)) return; | ||
|
||
// needed to handle space & control + key actions by default | ||
if (!isCtrlOrCmd(event)) { | ||
if (!isSpace(event)) focusPreviousNode(change); | ||
change.insertText(event.key); | ||
|
||
// Apply transforms | ||
if (Array.isArray(transforms)) { | ||
transforms.forEach(transform => { | ||
const lastWord = getLastWord(change); | ||
transform(change, lastWord); | ||
}); | ||
} else if (transforms) { | ||
const lastWord = getLastWord(change); | ||
transforms(change, lastWord); | ||
} | ||
|
||
// Prevent insertion of the char | ||
event.preventDefault(); | ||
} | ||
} | ||
}); | ||
|
||
export default InstantReplace; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters