Skip to content

Instantly share code, notes, and snippets.

@christianscott
Created April 12, 2018 00:13
Show Gist options
  • Save christianscott/5eda52147f5d43443b1705ee87b56286 to your computer and use it in GitHub Desktop.
Save christianscott/5eda52147f5d43443b1705ee87b56286 to your computer and use it in GitHub Desktop.
Component that wraps the value of an input in quotes
import React from "react";
import { wrapInQuotemarks, stripQuotationMarks, noop } from "./utils";
let previousQuote = null;
export default class QuotationWrappedInput extends React.Component {
static defaultProps = {
InputComponent: ({ handleRef, ...props }) => <textarea ref={handleRef} {...props} />,
handleRef: noop,
maxLength: 320,
placeholder: "Type here",
style: {},
open: '‘',
close: '’'
}
constructor(props) {
super(props);
this.textArea = React.createRef();
this.handleInputChange = this.handleInputChange.bind(this);
}
componentDidMount() {
this.textArea.current.focus();
if (this.props.inputValue.length > 0) {
// The quote marks add +2 to the length, so +1 is -1 from the end of the input
const oneFromTheEnd = this.props.inputValue.length + 1;
this.textArea.current.selectionStart = this.textArea.current.selectionEnd = oneFromTheEnd;
}
}
render() {
const {
InputComponent,
placeholder,
handleInputChange,
handleRef,
style,
maxLength,
inputValue,
open,
close
} = this.props;
const quotedValue = wrapInQuotemarks(inputValue, open, close);
return (
<InputComponent
handleRef={this.textArea}
placeholder={placeholder}
value={quotedValue}
onChange={this.handleInputChange}
style={style}
maxLength={maxLength}
/>
);
}
/**
* Modify the value of the event target, then pass it
* up to the parent. This preserves encapsulation as the
* parent should have no knowledge of the quote marks.
*
* @param {React.KeyboardEvent} ev
* @returns {React.KeyboardEvent}
*/
handleInputChange(ev) {
let s = stripQuotationMarks(ev.target.value, this.props.open, this.props.close);
/*
* If the previous input is the same as the current input
* after stripping quotation marks, then the user must have
* hit the backspace key & removed the trailing quotation
* mark
*/
if (previousQuote != null && previousQuote === s) {
s = s.slice(0, -1);
}
previousQuote = s;
ev.target.value = s;
this.props.handleInputChange(ev);
}
}
/**
* Strip single quotes from a string
*
* @param {string} s target string
* @returns {string}
*/
export function stripQuotationMarks(s, open='‘', close='’') {
const quoteRe = new Regex(`(${open}|${close})`, 'g');
return s.replace(quoteRe, '');
}
/**
* Wraps a string in quotation marks, after stripping any
* other quote marks from the beginning/end of the string.
*
* If the string is empty after stripping quotes,
* returns the empty string.
*
* @param {string} s target string
* @returns {string}
*/
export function wrapInQuotemarks(s, open='‘', close='’') {
const stripped = stripQuotationMarks(s, open, close);
if (stripped === "") {
return "";
}
return `${open}${stripped}${close}`;
}
export function noop() {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment