codogo-react-widgets
Version:
Provides a unified way to access the styling of commonly used widgets across different apps
201 lines (169 loc) • 4.43 kB
JavaScript
import selectionManipulator from "selection-range";
import autobind from "autobind-decorator";
import hljs from "highlight.js";
import styled from "styled-components";
import { keyCodesToForwardOnChange, } from "./constants";
const MarkdownStyler = styled.div`
div {
display: inline-block;
margin: 0;
outline: 0px solid transparent;
pointer-events: all;
tabSize: 4;
white-space: pre-wrap;
width: 100%;
&:empty {
display: block;
}
&:empty::before {
content: "${R.prop("placeholder")}";
opacity: 0.33;
}
}
a,
a:hover,
a:visited,
a:active,
a:link {
color: ${R.path(["theme", "colors", "primary",])};
max-width: 100%;
cursor: pointer;
text-decoration: underline;
word-wrap: break-word;
}
.hljs-emphasis {
color: ${R.path(["theme", "colors", "red",])};
}
.hljs-strong {
color: ${R.path(["theme", "colors", "yellow",])};
}
.hljs-string {
color: ${R.path(["theme", "colors", "green",])};
}
.hljs-link {
color: ${R.path(["theme", "colors", "blue",])};
}
.hljs-code {
color: ${R.path(["theme", "colors", "orange",])};
}
`;
const selectionEq = (lhs = {}, rhs = {}) =>
lhs.start === rhs.start && lhs.end === rhs.end;
const isFirefox = typeof InstallTrigger !== "undefined";
//const isOpera = (!!window.opr && !!window.opr.addons) || !!window.opera || navigator.userAgent.indexOf(" OPR/") >= 0;
//const isSafari = /constructor/i.test(window.HTMLElement) || (function(p) { return p.toString() === "[object SafariRemoteNotification]"; })( !window["safari"] || (typeof safari !== "undefined" && safari.pushNotification),);
//const isIE = [>@cc_on!@<] false || !!document.documentMode;
//const isEdge = !isIE && !!window.StyleMedia;
//const isChrome = !!window.chrome && !!window.chrome.webstore;
//const isBlink = (isChrome || isOpera) && !!window.CSS;
export default class Markdown extends React.Component {
componentDidMount() {
if (this.ref) {
this.ref.innerHTML = hljs.highlight(
"markdown",
this.props.value,
).value;
}
this.componentDidX();
}
componentDidUpdate() {
this.componentDidX();
}
componentDidX() {
const domElement = this.ref;
if (this.props.focus) {
if (document.activeElement !== domElement) {
domElement.focus();
}
const oldValue = domElement.textContent;
if (oldValue !== this.props.value) {
domElement.textContent = this.props.value;
domElement.innerHTML = hljs.highlight(
"markdown",
this.props.value,
).value;
}
const oldSelection = selectionManipulator(domElement);
if (
!selectionEq(oldSelection, this.props.selection) &&
this.props.value.length
) {
selectionManipulator(domElement, this.props.selection || {});
}
} else {
domElement.textContent = this.props.value;
domElement.blur();
}
}
onRef(ref) {
if (ref) {
this.ref = ref;
}
}
onKeyDown() {}
onChange(event) {
const domElement = this.ref;
if (domElement) {
const selection = selectionManipulator(domElement);
const value = domElement.innerText;
if (isFirefox && event.keyCode === 13) {
selection.start = selection.start + 1;
selection.end = selection.end + 1;
}
const selectionChanged = !selectionEq(
selection,
this.props.selection,
);
const valueChanged = value !== this.props.value;
console.log("onChange", {
event,
value: valueChanged ? value : this.props.value,
selection: selectionChanged ? selection : this.props.selection,
});
this.props.onChange({
event,
value: valueChanged ? value : this.props.value,
selection: selectionChanged ? selection : this.props.selection,
});
}
}
onClick(event) {
this.onChange(event);
}
onKeyUp(event) {
//any key has been pressed,
//but this handler only deals with non-text-mutating actions
//so we'll need to weed those out
if (
this.lastCalled !== this.onInput &&
keyCodesToForwardOnChange.has(event.keyCode)
) {
this.onChange(event);
}
this.lastCalled = this.onKeyUp;
}
onInput(event) {
this.onChange(event);
this.lastCalled = this.onInput;
}
render() {
return (
<MarkdownStyler placeholder = { this.props.placeholder }>
<div
className = "markdown"
contentEditable
onKeyUp = { this.onKeyUp }
onInput = { this.onInput }
ref = { this.onRef }
/>
</MarkdownStyler>
);
}
}