Skip to content

Commit

Permalink
Merge pull request #207 from 10up/feat/34
Browse files Browse the repository at this point in the history
feat/34: Add faux cursor to preserve context
  • Loading branch information
Sidsector9 authored Aug 4, 2023
2 parents 7d8d781 + dd2dc94 commit b2e1873
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 3 deletions.
133 changes: 130 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import { registerFormatType, toggleFormat, insert } from '@wordpress/rich-text';
import { Fragment } from '@wordpress/element';
import { BlockControls, RichTextShortcut } from '@wordpress/block-editor';
import { Fragment, useEffect, useState } from '@wordpress/element';
import {
BlockControls,
RichTextShortcut,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { Popover, ToolbarButton, ToolbarGroup } from '@wordpress/components';
import { applyFilters } from '@wordpress/hooks';
import { displayShortcut } from '@wordpress/keycodes';
import {
select,
useSelect,
dispatch,
createReduxStore,
register,
} from '@wordpress/data';
import { __ } from '@wordpress/i18n';

import { CharacterMap } from 'react-character-map';
Expand All @@ -24,6 +35,55 @@ const type = `special-characters/${ name }`;
let anchorRange;
let anchorRect;

const DEFAULT_STATE = {
clientId: '',
originalContent: '',
};

const caretDataStore = createReduxStore( 'caret-data-store', {
reducer( state = DEFAULT_STATE, action ) {
switch ( action.type ) {
case 'SET_CLIENT_ID':
return {
...state,
clientId: action.clientId,
};

case 'SET_ORIGINAL_CONTENT':
return {
...state,
originalContent: action.originalContent,
};
}

return state;
},
actions: {
setClientId( clientId ) {
return {
type: 'SET_CLIENT_ID',
clientId,
};
},
setOriginalContent( originalContent ) {
return {
type: 'SET_ORIGINAL_CONTENT',
originalContent,
};
},
},
selectors: {
getClientId( state ) {
return state.clientId;
},
getOriginalContent( state ) {
return state.originalContent;
},
},
} );

register( caretDataStore );

/**
* Register the "Format Type" to create the character inserter.
*/
Expand All @@ -42,7 +102,72 @@ registerFormatType( type, {
* @param {Function} props.onChange Event handler to detect range selection.
* @param {HTMLElement} props.contentRef The editable element.
*/
edit( { isActive, value, onChange, contentRef } ) {
edit: function Edit( { isActive, value, onChange, contentRef } ) {
const [ inActiveBySelection, setInactiveBySelection ] =
useState( false );
const { start, end, selectedBlock } = useSelect( ( __select ) => {
return {
start: __select( blockEditorStore ).getSelectionStart().offset,
end: __select( blockEditorStore ).getSelectionEnd().offset,
selectedBlock: __select( blockEditorStore ).getSelectedBlock(),
};
} );

useEffect( () => {
const content = selectedBlock.attributes.content.replace(
/<insertspecialcharacters>|<\/insertspecialcharacters>/g,
''
);
dispatch( caretDataStore ).setClientId( selectedBlock.clientId );

const preBreak = content.substring( 0, start );

if ( ( isActive || inActiveBySelection ) && start - end === 0 ) {
dispatch( caretDataStore ).setOriginalContent( content );
const postBreak = content.substring( start );
const postBreakFirstChar = postBreak.substring( 0, 1 );
const postBreakWithoutFirstChar = postBreak.substring( 1 );

if ( contentRef && contentRef.current ) {
contentRef.current.innerHTML =
preBreak +
`<span class="insert-special-character__faux-caret">${ postBreakFirstChar }</span>` +
postBreakWithoutFirstChar;
}
} else if (
( isActive || inActiveBySelection ) &&
end - start > 0
) {
dispatch( caretDataStore ).setOriginalContent( content );
const selectedText = content.substring( start, end );
const preSelectText = content.substring( 0, start );
const postSelectText = content.substring( end );

if ( contentRef && contentRef.current ) {
contentRef.current.innerHTML =
preSelectText +
`<span class="insert-special-character__faux-selection">${ selectedText }</span>` +
postSelectText;
}
}

return () => {
const storedClientId = select( caretDataStore ).getClientId();

if ( selectedBlock.clientId !== storedClientId ) {
return;
}

const backupUpContent =
select( caretDataStore ).getOriginalContent();

if ( backupUpContent ) {
contentRef.current.innerHTML = backupUpContent;
dispatch( caretDataStore ).setOriginalContent( '' );
}
};
}, [ isActive, inActiveBySelection ] );

const onToggle = () => {
const selection = contentRef.current.ownerDocument.getSelection();

Expand Down Expand Up @@ -90,6 +215,8 @@ registerFormatType( type, {
text: char.char,
};

setInactiveBySelection( true );

onChange(
insert(
value,
Expand Down
18 changes: 18 additions & 0 deletions src/insert-special-characters.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
$grid-border-color: #c8c8c8;

.insert-special-character__faux-caret {
border-left: 1px solid #000;
animation: 1s caret-blink step-end infinite;
}

.insert-special-character__faux-selection {
background-color: rgba(0, 0, 0, 0.2);
}

@keyframes caret-blink {
from, to {
border-color: black;
}
50% {
border-color: transparent;
}
}

.character-map-popover {
.components-popover__content {
border: 1px solid #1e1e1e
Expand Down

0 comments on commit b2e1873

Please sign in to comment.