Skip to content

Instantly share code, notes, and snippets.

@javierfernandes
Created November 15, 2020 14:40
Show Gist options
  • Save javierfernandes/6ca5a72fa13dca9f5e847ff22a5c8968 to your computer and use it in GitHub Desktop.
Save javierfernandes/6ca5a72fa13dca9f5e847ff22a5c8968 to your computer and use it in GitHub Desktop.
const expectIsWithin = text => {
const { state, entityMatch } = createStateAndEntityMatch(text)
return expect(isWithinEntityMatch(state, entityMatch))
}
export const DELIM_START = '{'
export const DELIM_END = '}'
/**
* Creates a DraftJS State (content) Interpreting {...} as entities.
* As it uses `createState()` it supports the "selection" DSL.
*/
const createStateAndEntityMatch = text => {
const state = createState(text)
const initialSelection = state.getSelection()
return {
state: pipe(
updateContent('create-entity',
createEntityOnSelection('myEntity', 'MUTABLE', () => createSelectionOnBlock(
state.getCurrentContent().getFirstBlock().getKey(),
{ anchorOffset: text.indexOf(DELIM_START), focusOffset: text.indexOf(DELIM_END) }
))
),
forceSelection(() => initialSelection)
)(state),
entityMatch: {
start: text.indexOf(DELIM_START),
end: text.indexOf(DELIM_END),
}
}
}
// UTILITY to create a content with a single block using a "DSL" to specify the selection
// Like this "Hello [>World>] how are you ?"
// Selection range is specified either by [> ... >] for left to right
// or [< ... <] for right to left
const createState = (...blockLines) => {
// parse lines
const parsedBlocks = blockLines.reduce((acc, dslText) => {
const { text, anchorOffset, focusOffset } = createStateForText(dslText)
const block = {
key: uuid(),
text,
type: 'unstyled',
depth: 0,
inlineStyleRanges: [],
entityRanges: [],
data: {}
}
acc.blocks.push(block)
if (!acc.selection && anchorOffset !== undefined) {
acc.selection = {
anchorKey: block.key,
anchorOffset,
focusKey: block.key,
focusOffset,
isBackward: focusOffset < anchorOffset
}
}
return acc
}, { blocks: [] })
// create state
const state = createEditorStateFromRawContent({ blocks: parsedBlocks.blocks, entityMap: {} })
// select
return parsedBlocks.selection ?
EditorState.forceSelection(state, createSelectionOnBlock(parsedBlocks.selection.anchorKey, parsedBlocks.selection))
: state
}
export const createStateForText = text => {
const ltrSelectionIdx = text.indexOf('[>')
if (ltrSelectionIdx >= 0) {
return {
text: text.replace(/(\[>|>\])/g, ''),
anchorOffset: ltrSelectionIdx,
focusOffset: text.substring(ltrSelectionIdx + 2).indexOf('>]') + ltrSelectionIdx
}
}
const rtlSelectionIdx = text.indexOf('[<')
if (rtlSelectionIdx >= 0) {
return {
text: text.replace(/(\[<|<\])/g, ''),
focusOffset: rtlSelectionIdx,
anchorOffset: text.substring(rtlSelectionIdx + 2).indexOf('<]') + rtlSelectionIdx
}
}
const cursorPosition = text.indexOf('[|]')
if (cursorPosition >= 0) {
return {
text: text.replace(/(\[\|\])/g, ''),
focusOffset: cursorPosition,
anchorOffset: cursorPosition,
}
}
return { text }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment