Add a text edit area

This commit is contained in:
DD 2018-03-20 10:48:35 -04:00
parent cbd2a89cd0
commit da0864b81b
4 changed files with 80 additions and 29 deletions

View file

@ -0,0 +1,15 @@
.text-area {
background: transparent;
border: none;
display: none;
font-family: Times;
font-size: 30px;
left: 0;
outline: none;
overflow: hidden;
position: absolute;
resize: none;
top: 0;
white-space: nowrap;
z-index: 1;
}

View file

@ -3,23 +3,32 @@ import PropTypes from 'prop-types';
import ToolSelectComponent from '../tool-select-base/tool-select-base.jsx';
import textIcon from './text.svg';
import styles from './text-mode.css';
const TextModeComponent = props => (
<ToolSelectComponent
imgDescriptor={{
defaultMessage: 'Text',
description: 'Label for the text tool',
id: 'paint.textMode.text'
}}
imgSrc={textIcon}
isSelected={props.isSelected}
onMouseDown={props.onMouseDown}
/>
<div>
<ToolSelectComponent
imgDescriptor={{
defaultMessage: 'Text',
description: 'Label for the text tool',
id: 'paint.textMode.text'
}}
imgSrc={textIcon}
isSelected={props.isSelected}
onMouseDown={props.onMouseDown}
/>
<textarea
className={styles.textArea}
ref={props.setTextArea}
/>
</div>
);
TextModeComponent.propTypes = {
isSelected: PropTypes.bool.isRequired,
onMouseDown: PropTypes.func.isRequired
onMouseDown: PropTypes.func.isRequired,
setTextArea: PropTypes.func.isRequired
};
export default TextModeComponent;

View file

@ -21,7 +21,8 @@ class TextMode extends React.Component {
super(props);
bindAll(this, [
'activateTool',
'deactivateTool'
'deactivateTool',
'setTextArea'
]);
}
componentDidMount () {
@ -64,6 +65,7 @@ class TextMode extends React.Component {
this.props.onChangeStrokeColor(null);
}
this.tool = new TextTool(
this.textArea,
this.props.setSelectedItems,
this.props.clearSelectedItems,
this.props.onUpdateSvg,
@ -77,11 +79,15 @@ class TextMode extends React.Component {
this.tool.remove();
this.tool = null;
}
setTextArea (element) {
this.textArea = element;
}
render () {
return (
<TextModeComponent
isSelected={this.props.isTextModeActive}
onMouseDown={this.props.handleMouseDown}
setTextArea={this.setTextArea}
/>
);
}

View file

@ -28,13 +28,15 @@ class TextTool extends paper.Tool {
return 8;
}
/**
* @param {HTMLTextAreaElement} textAreaElement dom element for the editable text field
* @param {function} setSelectedItems Callback to set the set of selected items in the Redux state
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
* @param {!function} setTextEditTarget Call to set text editing target whenever text editing is active
*/
constructor (setSelectedItems, clearSelectedItems, onUpdateSvg, setTextEditTarget) {
constructor (textAreaElement, setSelectedItems, clearSelectedItems, onUpdateSvg, setTextEditTarget) {
super();
this.element = textAreaElement;
this.setSelectedItems = setSelectedItems;
this.clearSelectedItems = clearSelectedItems;
this.onUpdateSvg = onUpdateSvg;
@ -141,10 +143,6 @@ class TextTool extends paper.Tool {
const hitResults = paper.project.hitTestAll(event.point, this.getTextEditHitOptions());
if (hitResults.length) {
// Clicking a text item to begin text edit mode on that item
if (this.guide) {
this.guide.remove();
this.guide = null;
}
this.textBox = hitResults[0].item;
this.mode = TextTool.TEXT_EDIT_MODE;
} else if (this.mode === TextTool.TEXT_EDIT_MODE) {
@ -171,13 +169,9 @@ class TextTool extends paper.Tool {
}
if (this.mode === TextTool.TEXT_EDIT_MODE) {
this.guide = hoverBounds(this.textBox, TextTool.TEXT_PADDING);
this.guide.dashArray = [4, 4];
this.setTextEditTarget(this.textBox.id);
} else if (this.guide) {
this.guide.remove();
this.guide = null;
this.setTextEditTarget();
this.beginTextEdit(event.point);
} else {
this.endTextEdit();
}
}
handleMouseDrag (event) {
@ -224,17 +218,44 @@ class TextTool extends paper.Tool {
this.guide.dashArray = [4, 4];
}
}
beginTextEdit (location) {
if (this.guide) {
this.guide.remove();
}
this.guide = hoverBounds(this.textBox, TextTool.TEXT_PADDING);
this.guide.dashArray = [4, 4];
this.setTextEditTarget(this.textBox.id);
const canvasRect = paper.view.element.getBoundingClientRect();
this.element.style.display = 'initial';
this.element.style.text = 'hello';
this.element.style['text-fill-color'] = this.colorState.fillColor;
this.element.style['text-stroke-color'] = this.colorState.strokeColor;
this.element.style['text-stroke-width'] = this.colorState.strokeWidth;
this.element.style['-webkit-text-fill-color'] = this.colorState.fillColor;
this.element.style['-webkit-text-stroke-color'] = this.colorState.strokeColor;
this.element.style['-webkit-text-stroke-width'] = this.colorState.strokeWidth + 'px';
this.element.style.transform =
`translate(${location.x + canvasRect.x}px, ${location.y + canvasRect.y}px)`;
this.element.focus();
}
endTextEdit () {
if (this.guide) {
this.guide.remove();
this.guide = null;
this.setTextEditTarget();
}
this.element.style.display = 'none';
}
deactivateTool () {
this.boundingBoxTool.removeBoundsPath();
if (this.textBox && this.textBox.content.trim() === '') {
this.textBox.remove();
this.textBox = null;
}
if (this.guide) {
this.guide.remove();
this.guide = null;
this.setTextEditTarget();
}
this.endTextEdit();
}
}