UNPKG

react-text-holder-insertable

Version:
134 lines (106 loc) 3.95 kB
import $ from 'jquery'; import { get } from 'lodash'; import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import ContentEditable from 'react-contenteditable'; var style = {"text-holder":"_text-holder-module__text-holder__YG9kW","text-holder-label":"_text-holder-module__text-holder-label__2FfSn","text-holder-cancel":"_text-holder-module__text-holder-cancel__3Sv40"}; class TextHolder { constructor(label, options = {}) { this.getJq = () => { const holderLabel = $("<span/>").addClass(style["text-holder-label"]).css(this.options.textHolderLabelStyle || {}).html(this.label); const jq = $("<span/>").addClass(style["text-holder"]).css(this.options.textHolderStyle || {}).attr("contenteditable", "false").append(holderLabel); if (this.options.withCancel) { const holderCancel = $("<span/>").addClass(style["text-holder-cancel"]).css(this.options.textHolderCancelStyle || {}).html("x"); jq.append(holderCancel); } return jq; }; this.getEl = () => this.getJq()[0]; this.getHolderOuterHTML = () => this.getEl().outerHTML; this.insert = (anchorOffset, setHtml, boxRef) => { const inputBox = get(boxRef, "current.el.current"); if (anchorOffset >= 0 && anchorOffset !== null && inputBox) { let __html = $(inputBox).html(); const front = __html.substring(0, anchorOffset); const latter = __html.substring(anchorOffset); const inserted = this.getEl().outerHTML; __html = `${front}${inserted}${latter}`; setHtml(__html); } }; this.label = label; this.options = options; } } function TextHolderInsertable({ html, onChange, initialAnchorOffset, onAnchorOffsetChange, onTextChange, boxRef }) { const [__anchorOffset, __setAnchorOffset] = useState(initialAnchorOffset || 0); const [__html, __setHtml] = useState(html || ""); const handleChange = e => { onChange(e); __setHtml(e.target.value); }; useEffect(() => { onAnchorOffsetChange(__anchorOffset); }, [__anchorOffset, onAnchorOffsetChange]); useEffect(() => { __setHtml(html); }, [html]); useEffect(() => { onTextChange && onTextChange(getText()); }, [__html]); function getText() { const jq = $("<div/>").html(__html); jq.find(`.${style["text-holder-cancel"]}`).each((_, ele) => $(ele).remove()); return jq.text(); } function getTextActualStartOffset(startContainer) { const prevSib = startContainer.previousSibling; if (!prevSib) return 0; const prevSibContentLen = prevSib.nodeType === 1 ? prevSib.outerHTML.length : prevSib.textContent.length; return prevSibContentLen + getTextActualStartOffset(prevSib); } const updateAnchorOffset = e => { const sel = window.getSelection(); const jq = $(e.target); if ([style["text-holder"], style["text-holder-label"], style["text-holder-cancel"]].every(className => !jq.hasClass(className))) { __setAnchorOffset(getTextActualStartOffset(sel.getRangeAt(0).startContainer) + sel.anchorOffset); } }; const handleClick = e => { if ($(e.target).hasClass(style["text-holder-cancel"])) { const box = e.target.parentNode.parentNode; $(e.target.parentNode).remove(); __setHtml($(box).html()); } updateAnchorOffset(e); }; const handleKeyUp = e => { updateAnchorOffset(e); }; return /*#__PURE__*/React.createElement(ContentEditable, { ref: boxRef, html: __html, disabled: false, onChange: handleChange, onClick: handleClick, onKeyUp: handleKeyUp }); } TextHolderInsertable.propTypes = { ref: PropTypes.object, html: PropTypes.string, onChange: PropTypes.func, onTextChange: PropTypes.func, initialAnchorOffset: PropTypes.number, onAnchorOffsetChange: PropTypes.func }; export default TextHolderInsertable; export { TextHolder }; //# sourceMappingURL=index.modern.js.map