UNPKG

@gpa-gemstone/react-forms

Version:
169 lines (168 loc) 8.7 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = AutoCompleteTextArea; var React = require("react"); var TextArea_1 = require("./TextArea"); var react_portal_1 = require("react-portal"); var _ = require("lodash"); var AutoCompleteInput_1 = require("./AutoCompleteInput"); function AutoCompleteTextArea(props) { var autoCompleteTextArea = React.useRef(null); var tableContainer = React.useRef(null); var selectTable = React.useRef(null); var textAreaElement = React.useRef(null); var _a = React.useState([]), suggestions = _a[0], setSuggestions = _a[1]; var _b = React.useState(null), position = _b[0], setPosition = _b[1]; var _c = React.useState({ Start: 0, End: 0, Variable: "" }), variable = _c[0], setVariable = _c[1]; var _d = React.useState(true), show = _d[0], setShow = _d[1]; // Handle showing and hiding of the dropdown. var HandleShow = React.useCallback(function (evt) { var _a; // Ignore if disabled or not a mousedown event if ((props.Disabled === undefined ? false : props.Disabled) || evt.type !== 'mousedown') { return; } //ignore the click if it was inside the table or table container if ((selectTable.current != null && selectTable.current.contains(evt.target)) || (tableContainer.current != null && tableContainer.current.contains(evt.target))) { return; } if (textAreaElement.current !== null && !((_a = textAreaElement.current) === null || _a === void 0 ? void 0 : _a.contains(evt.target))) { setShow(false); } else { setShow(true); } }, [props.Disabled]); // add listeners to follow caret React.useEffect(function () { var autoComplete = textAreaElement.current; if (autoComplete == null) return; autoComplete.addEventListener("keyup", handleCaretPosition); autoComplete.addEventListener("click", handleCaretPosition); return function () { autoComplete.removeEventListener("keyup", handleCaretPosition); autoComplete.removeEventListener("click", handleCaretPosition); }; }, []); // set position of the suggestion dropdown React.useLayoutEffect(function () { if ((suggestions === null || suggestions === void 0 ? void 0 : suggestions.length) == 0) { setPosition(null); return; } var updatePosition = _.debounce(function () { if (textAreaElement.current == null) { return; } var rect = textAreaElement.current.getBoundingClientRect(); var _a = getTextDimensions(textAreaElement, variable.Start - 1, "\n"), caret_X = _a[0], caret_Y = _a[1]; setPosition({ Top: rect.top + caret_Y, Left: rect.left + caret_X, Width: rect.width - caret_X, Height: rect.height }); }, 200); var handleScroll = function () { if (tableContainer.current == null) return; updatePosition(); }; updatePosition(); window.addEventListener('scroll', handleScroll, true); window.addEventListener('resize', updatePosition); window.addEventListener('mousedown', HandleShow, false); return function () { window.removeEventListener('scroll', handleScroll, true); window.removeEventListener('resize', updatePosition); window.removeEventListener('mousedown', HandleShow, false); updatePosition.cancel(); }; }, [suggestions, HandleShow]); // update variable and suggestions when caret position changes var handleCaretPosition = function () { var _a, _b, _c, _d; if (textAreaElement.current !== null) { var selection = textAreaElement.current.selectionStart; var variable_1 = (0, AutoCompleteInput_1.getCurrentVariable)((_b = (_a = textAreaElement.current) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : "", selection); setVariable(variable_1); var suggests = (0, AutoCompleteInput_1.getSuggestions)(variable_1, (_d = (_c = textAreaElement.current) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : "", props.Options); setSuggestions(suggests); } }; // edit text area contents with selected suggestion var handleOptionClick = function (option) { var _a; var _b, _c, _d, _e; var currentPos = textAreaElement.current !== null ? textAreaElement.current.selectionStart : 0; var optionLength = option.Value.length; props.Setter(__assign(__assign({}, props.Record), (_a = {}, _a[props.Field] = option.Value, _a))); var textLength = textAreaElement.current !== null ? (_c = (_b = textAreaElement.current.textContent) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0 : 0; var newCaretPos = (optionLength > textLength ? textLength - 1 : optionLength + currentPos); (_d = textAreaElement.current) === null || _d === void 0 ? void 0 : _d.focus(); (_e = textAreaElement.current) === null || _e === void 0 ? void 0 : _e.setSelectionRange(newCaretPos, newCaretPos); setSuggestions([]); }; return (React.createElement("div", { ref: autoCompleteTextArea }, React.createElement(TextArea_1.default, __assign({}, props, { TextAreaRef: textAreaElement, SpellCheck: false })), position == null || !show ? React.createElement(React.Fragment, null) : React.createElement(react_portal_1.Portal, null, React.createElement("div", { ref: tableContainer, className: 'popover', style: { maxHeight: window.innerHeight - position.Top, overflowY: 'auto', padding: '10 5', display: 'block', position: 'absolute', zIndex: 9999, maxWidth: '100%', top: "".concat(position.Top, "px"), left: "".concat(position.Left, "px"), minWidth: "".concat(Math.min(position.Width, window.innerWidth - position.Left), "px"), overflowWrap: 'break-word', } }, React.createElement("table", { className: "table table-hover", style: { margin: 0 }, ref: selectTable }, React.createElement("tbody", null, suggestions.map(function (f, i) { return (f.Value === props.Record[props.Field] ? null : React.createElement("tr", { key: i, onMouseDown: function (_) { return handleOptionClick(f); } }, React.createElement("td", null, f.Label))); }))))))); } var getTextDimensions = function (textArea, selection, prefix) { var _a; if (textArea.current == null) return [0, 0]; var textarea = textArea.current; if (textarea.parentNode == null) return [0, 0]; var hiddenDiv = document.createElement('div'); var style = getComputedStyle(textarea); Array.from(style).forEach(function (propertyName) { var value = style.getPropertyValue(propertyName); hiddenDiv.style.setProperty(propertyName, value); }); // Set text content up to caret var beforeSelection = textarea.value.substring(0, selection); var afterSelection = (_a = textarea.value.substring(selection)) !== null && _a !== void 0 ? _a : '.'; hiddenDiv.textContent = (prefix !== null && prefix !== void 0 ? prefix : "") + beforeSelection; // Create a span to mark caret position var span = document.createElement('span'); span.textContent = afterSelection[0]; hiddenDiv.appendChild(span); textarea.parentNode.appendChild(hiddenDiv); // Get caret's vertical position relative to textarea var caretX = span.offsetLeft - hiddenDiv.offsetLeft - hiddenDiv.scrollLeft; var caretY = span.offsetTop - hiddenDiv.offsetTop - textarea.scrollTop; textarea.parentNode.removeChild(hiddenDiv); return [caretX, caretY]; };