UNPKG

@trap_stevo/legendarybuilderproreact-ui

Version:

The legendary UI & utility API that makes your application a legendary application. ~ Created by Steven Compton

622 lines 26 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React, { useState, useEffect, useRef } from "react"; import { ConvertNumberToMoneyFormat, useTimeout } from "../HUDManagers/HUDUniversalHUDUtilityManager.js"; import { lightenColor } from "./HUDPaletteProvider.js"; import { HUDIcon } from "./HUDIcon.js"; var HUDTextEditor = function HUDTextEditor(_ref) { var _selectedWord$positio, _selectedWord$positio2; var _ref$versionNavigatio = _ref.versionNavigationContainerConfigurationSettings, versionNavigationContainerConfigurationSettings = _ref$versionNavigatio === void 0 ? {} : _ref$versionNavigatio, _ref$suggestionsConta = _ref.suggestionsContainerConfigurationSettings, suggestionsContainerConfigurationSettings = _ref$suggestionsConta === void 0 ? {} : _ref$suggestionsConta, _ref$iconButtonDisabl = _ref.iconButtonDisabledConfigurationSettings, iconButtonDisabledConfigurationSettings = _ref$iconButtonDisabl === void 0 ? {} : _ref$iconButtonDisabl, _ref$buttonsContainer = _ref.buttonsContainerConfigurationSettings, buttonsContainerConfigurationSettings = _ref$buttonsContainer === void 0 ? {} : _ref$buttonsContainer, _ref$footerContainerC = _ref.footerContainerConfigurationSettings, footerContainerConfigurationSettings = _ref$footerContainerC === void 0 ? {} : _ref$footerContainerC, _ref$highlightedTextC = _ref.highlightedTextConfigurationSettings, highlightedTextConfigurationSettings = _ref$highlightedTextC === void 0 ? {} : _ref$highlightedTextC, _ref$suggestionCellCo = _ref.suggestionCellConfigurationSettings, suggestionCellConfigurationSettings = _ref$suggestionCellCo === void 0 ? {} : _ref$suggestionCellCo, _ref$versionLabelConf = _ref.versionLabelConfigurationSettings, versionLabelConfigurationSettings = _ref$versionLabelConf === void 0 ? {} : _ref$versionLabelConf, _ref$utilityMenuConfi = _ref.utilityMenuConfigurationSettings, utilityMenuConfigurationSettings = _ref$utilityMenuConfi === void 0 ? {} : _ref$utilityMenuConfi, _ref$iconButtonConfig = _ref.iconButtonConfigurationSettings, iconButtonConfigurationSettings = _ref$iconButtonConfig === void 0 ? {} : _ref$iconButtonConfig, _ref$containerConfigu = _ref.containerConfigurationSettings, containerConfigurationSettings = _ref$containerConfigu === void 0 ? {} : _ref$containerConfigu, _ref$editorConfigurat = _ref.editorConfigurationSettings, editorConfigurationSettings = _ref$editorConfigurat === void 0 ? {} : _ref$editorConfigurat, _ref$footerConfigurat = _ref.footerConfigurationSettings, footerConfigurationSettings = _ref$footerConfigurat === void 0 ? {} : _ref$footerConfigurat, _ref$inputConfigurati = _ref.inputConfigurationSettings, inputConfigurationSettings = _ref$inputConfigurati === void 0 ? {} : _ref$inputConfigurati, _ref$onVersionUpdate = _ref.onVersionUpdate, onVersionUpdate = _ref$onVersionUpdate === void 0 ? null : _ref$onVersionUpdate, _ref$onTextChange = _ref.onTextChange, onTextChange = _ref$onTextChange === void 0 ? null : _ref$onTextChange, _ref$currentVersionRi = _ref.currentVersionRightButtonActivatedColor, currentVersionRightButtonActivatedColor = _ref$currentVersionRi === void 0 ? "#00ffcc" : _ref$currentVersionRi, _ref$currentVersionRi2 = _ref.currentVersionRightButtonDeactivatedColor, currentVersionRightButtonDeactivatedColor = _ref$currentVersionRi2 === void 0 ? "#888" : _ref$currentVersionRi2, _ref$currentVersionLe = _ref.currentVersionLeftButtonActivatedColor, currentVersionLeftButtonActivatedColor = _ref$currentVersionLe === void 0 ? "#00ffcc" : _ref$currentVersionLe, _ref$currentVersionLe2 = _ref.currentVersionLeftButtonDeactivatedColor, currentVersionLeftButtonDeactivatedColor = _ref$currentVersionLe2 === void 0 ? "#888" : _ref$currentVersionLe2, _ref$fillerWords = _ref.fillerWords, fillerWords = _ref$fillerWords === void 0 ? ["uh", "um", "like", "you know", "okay", "and", "a", "an", "as", "it", "in", "that", "the"] : _ref$fillerWords, _ref$initialText = _ref.initialText, initialText = _ref$initialText === void 0 ? "Start editing here..." : _ref$initialText, _ref$historyUpdateDel = _ref.historyUpdateDelay, historyUpdateDelay = _ref$historyUpdateDel === void 0 ? 869 : _ref$historyUpdateDel, _ref$editorID = _ref.editorID, editorID = _ref$editorID === void 0 ? "text-editor" : _ref$editorID; var _useTimeout = useTimeout(), schedule = _useTimeout.schedule, cancelSchedule = _useTimeout.cancelSchedule; var _useState = useState(null), _useState2 = _slicedToArray(_useState, 2), selectedWord = _useState2[0], setSelectedWord = _useState2[1]; var _useState3 = useState(""), _useState4 = _slicedToArray(_useState3, 2), replacementText = _useState4[0], setReplacementText = _useState4[1]; var _useState5 = useState(""), _useState6 = _slicedToArray(_useState5, 2), editedWord = _useState6[0], setEditedWord = _useState6[1]; var _useState7 = useState([initialText]), _useState8 = _slicedToArray(_useState7, 2), history = _useState8[0], setHistory = _useState8[1]; var _useState9 = useState([]), _useState10 = _slicedToArray(_useState9, 2), suggestions = _useState10[0], setSuggestions = _useState10[1]; var _useState11 = useState([]), _useState12 = _slicedToArray(_useState11, 2), occurrences = _useState12[0], setOccurrences = _useState12[1]; var _useState13 = useState(0), _useState14 = _slicedToArray(_useState13, 2), currentOccurrenceIndex = _useState14[0], setCurrentOccurrenceIndex = _useState14[1]; var _useState15 = useState(0), _useState16 = _slicedToArray(_useState15, 2), currentVersionIndex = _useState16[0], setCurrentVersionIndex = _useState16[1]; var currentContentRef = useRef(initialText); var utilityMenuRef = useRef(null); var editorRef = useRef(null); var editorStyles = { container: _objectSpread({ position: "relative", maxWidth: "800px", fontFamily: "Arial, sans-serif", margin: "50px auto" }, containerConfigurationSettings), footerContainer: _objectSpread({ position: "absolute", display: "flex", flexDirection: "column", bottom: "10px", right: "10px" }, footerContainerConfigurationSettings), footer: _objectSpread({ position: "relative", display: "flex", flexDirection: "row", justifyContent: "flex-end", alignItems: "center", marginTop: "0.369rem" }, footerConfigurationSettings), editor: _objectSpread({ position: "relative", transition: "all 0.369s ease-out", overflowY: "auto", whiteSpace: "pre-wrap", wordWrap: "break-word", outline: "none", padding: "15px", fontSize: "1rem", lineHeight: "1.5", color: "#ffffff", backgroundColor: "#1e1e2f", border: "2px solid #ffcc00", borderRadius: "10px", maxHeight: "527px", minHeight: "200px", cursor: "text", paddingBottom: "2.169rem" }, editorConfigurationSettings), utilityMenu: _objectSpread({ position: "absolute", top: (selectedWord === null || selectedWord === void 0 || (_selectedWord$positio = selectedWord.position) === null || _selectedWord$positio === void 0 ? void 0 : _selectedWord$positio.top) || 0, left: (selectedWord === null || selectedWord === void 0 || (_selectedWord$positio2 = selectedWord.position) === null || _selectedWord$positio2 === void 0 ? void 0 : _selectedWord$positio2.left) || 0, background: "rgba(35, 35, 68, 0.95)", color: "#ffffff", maxWidth: "15.69rem", padding: "20px", borderRadius: "15px", boxShadow: "0 10px 30px rgba(0, 0, 0, 0.7)", zIndex: 1000, transform: "translateY(10px)", backdropFilter: "blur(12px)" }, utilityMenuConfigurationSettings), suggestions: _objectSpread({ display: "flex", flexDirection: "row", overflowX: "auto", maxWidth: "12.69rem", gap: "10px", paddingBottom: "0.269rem", marginBottom: "15px" }, suggestionsContainerConfigurationSettings), suggestion: _objectSpread({ background: lightenColor("#1e1e2f", 0.269), color: "#000", borderRadius: "8px", padding: "5px 12px", cursor: "pointer", fontSize: "0.9rem", transition: "transform 0.2s ease", boxShadow: "0 4px 8px rgba(0, 0, 0, 0.4)" }, suggestionCellConfigurationSettings), highlightedText: _objectSpread({ transition: "all 0.369s ease-out", fontWeight: "569", fontSize: "1.069rem", borderRadius: "0.269rem", backgroundColor: lightenColor("#1e1e2f", 0.0269), color: "#ffffff", padding: "0 2px" }, highlightedTextConfigurationSettings), input: _objectSpread({ padding: "8px 12px", borderRadius: "8px", border: "none", background: "linear-gradient(to right, #1f1f3f, #29294f)", color: "#ffffff", fontSize: "1rem", outline: "none", width: "100%", marginBottom: "10px" }, inputConfigurationSettings), buttons: _objectSpread({ display: "flex", justifyContent: "space-between", gap: "10px" }, buttonsContainerConfigurationSettings), versionNavigation: _objectSpread({ position: "relative", display: "flex", alignItems: "center", borderRadius: "0.369rem", background: "rgba(15, 15, 15, 0.69)", color: "white", gap: "8px", zIndex: 100, padding: "5.69px", marginRight: "0.369rem", marginLeft: "0.869rem" }, versionNavigationContainerConfigurationSettings), versionLabel: _objectSpread({ userSelect: "none", fontWeight: "469", fontSize: "0.869rem", borderRadius: "0.369rem", background: "rgba(15, 15, 15, 0.69)", color: "white", padding: "5.69px" }, versionLabelConfigurationSettings), iconButton: _objectSpread({ cursor: "pointer", opacity: 1, transition: "opacity 0.2s ease" }, iconButtonConfigurationSettings), iconButtonDisabled: _objectSpread({ cursor: "not-allowed", opacity: 0.4 }, iconButtonDisabledConfigurationSettings) }; var parseUniqueWords = function parseUniqueWords(text) { var matchedWords = text.toLowerCase().match(/\b[a-z]+\b/gi); var words = matchedWords ? matchedWords.filter(function (word) { return !fillerWords.includes(word); }) : [text]; return _toConsumableArray(new Set(words)); }; var clearHighlights = function clearHighlights() { if (!editorRef.current) { return; } var highlights = editorRef.current.querySelectorAll("span[data-highlight='true']"); highlights.forEach(function (highlight) { var parent = highlight.parentNode; if (!parent) { return; } while (highlight.firstChild) { parent.insertBefore(highlight.firstChild, highlight); } parent.removeChild(highlight); }); editorRef.current.normalize(); }; var highlightRange = function highlightRange(range) { clearHighlights(); var startContainer = range.startContainer; var endContainer = range.endContainer; if (!editorRef.current.contains(startContainer) || !editorRef.current.contains(endContainer)) { console.log("Highlight range outside of the editable area."); return; } var span = document.createElement("span"); span.style.transition = editorStyles.highlightedText.transition; span.style.fontWeight = editorStyles.highlightedText.fontWeight; span.style.fontSize = editorStyles.highlightedText.fontSize; span.style.borderRadius = editorStyles.highlightedText.borderRadius; span.style.backgroundColor = editorStyles.highlightedText.backgroundColor; span.style.color = editorStyles.highlightedText.color; span.style.padding = editorStyles.highlightedText.padding; span.setAttribute("data-highlight", "true"); var fragment = range.extractContents(); span.appendChild(fragment); range.insertNode(span); if (!editorRef.current._highlights) { editorRef.current._highlights = []; } editorRef.current._highlights.push(span); if (!editorRef.current._highlights) { editorRef.current._highlights = []; } editorRef.current._highlights.push(span); }; var handleSelection = function handleSelection() { var selection = window.getSelection(); if (!selection || selection.rangeCount === 0 || !editorRef.current.contains(selection.anchorNode)) { setSelectedWord(null); setOccurrences([]); clearHighlights(); return; } var range = selection.getRangeAt(0); var selectedText = selection.toString().trim(); if (!selectedText) { setSelectedWord(null); setOccurrences([]); clearHighlights(); return; } var regex = new RegExp("\\b".concat(selectedText, "\\b"), "gi"); var matches = []; currentContentRef.current.replace(regex, function (match, offset) { matches.push({ word: match, start: offset }); return match; }); setOccurrences(matches); setCurrentOccurrenceIndex(0); setEditedWord(selectedText); highlightRange(range); requestAnimationFrame(function () { setSelectedWord({ text: selectedText, position: null }); schedule(function () { var _utilityMenuRef$curre; var rect = range.getBoundingClientRect(); var editorRect = editorRef.current.getBoundingClientRect(); var menuHeight = ((_utilityMenuRef$curre = utilityMenuRef.current) === null || _utilityMenuRef$curre === void 0 ? void 0 : _utilityMenuRef$curre.offsetHeight) || 0; var spaceAbove = rect.top - editorRect.top; var spaceBelow = editorRect.bottom - rect.bottom; var offset = 10; var fitsBelow = spaceBelow > menuHeight + offset; var fitsAbove = spaceAbove > menuHeight + offset; var top = fitsBelow ? rect.bottom - editorRect.top + editorRef.current.scrollTop + offset : fitsAbove ? rect.top - editorRect.top + editorRef.current.scrollTop - menuHeight - offset : rect.bottom - editorRect.top + editorRef.current.scrollTop + offset; var left = rect.left - editorRect.left + editorRef.current.scrollLeft; setSelectedWord({ text: selectedText, position: { top: top, left: left } }); }, 1); }); }; var handleInput = function handleInput() { var newText = editorRef.current.innerHTML; debounceHistoryUpdate(newText); }; var debounceHistoryUpdate = function debounceHistoryUpdate(updatedText) { cancelSchedule(); schedule(function () { updateTextHistory(updatedText); }, historyUpdateDelay); }; var updateTextHistory = function updateTextHistory(updatedText) { if (currentContentRef.current !== updatedText) { currentContentRef.current = updatedText; setHistory(function (prev) { var updatedHistory = [].concat(_toConsumableArray(prev), [updatedText]); setCurrentVersionIndex(updatedHistory.length - 1); return updatedHistory; }); if (onTextChange) { onTextChange(updatedText, history, currentVersionIndex); } } }; var replaceOccurrence = function replaceOccurrence() { if (!occurrences.length) { return; } var occurrence = occurrences[currentOccurrenceIndex]; var regex = new RegExp("\\b".concat(occurrence.word, "\\b"), "g"); var updatedOccurrenceIndex = currentOccurrenceIndex; var replaced = false; clearHighlights(); var updatedContent = currentContentRef.current.replace(regex, function (match, offset) { if (offset === occurrence.start && !replaced) { replaced = true; return replacementText; } return match; }); editorRef.current.innerHTML = updatedContent; updateTextHistory(updatedContent); setOccurrences(function (prev) { return prev.filter(function (_, i) { return i !== currentOccurrenceIndex; }); }); setCurrentOccurrenceIndex(function (prev) { var occurrenceIndex = occurrences.length > 1 ? (prev + 1) % occurrences.length : 0; updatedOccurrenceIndex = occurrenceIndex; return occurrenceIndex; }); }; var replaceAllOccurrences = function replaceAllOccurrences() { var regex = new RegExp("\\b".concat(editedWord !== "" ? editedWord : selectedWord.text, "\\b"), "gi"); var updatedContent = currentContentRef.current.replace(regex, replacementText); editorRef.current.innerHTML = updatedContent; setOccurrences([]); setSelectedWord(null); setReplacementText(""); setEditedWord(""); updateTextHistory(updatedContent); }; var jumpToOccurrence = function jumpToOccurrence(index) { if (!occurrences.length) { return; } var wrappedIndex = (index + occurrences.length) % occurrences.length; setCurrentOccurrenceIndex(wrappedIndex); var occurrence = occurrences[wrappedIndex]; var selection = window.getSelection(); var range = document.createRange(); clearHighlights(); var textNodes = []; var collectTextNodes = function collectTextNodes(node) { if (node.nodeType === Node.TEXT_NODE) { textNodes.push(node); } else if (node.nodeType === Node.ELEMENT_NODE) { node.childNodes.forEach(collectTextNodes); } }; collectTextNodes(editorRef.current); var offset = 0; for (var _i = 0, _textNodes = textNodes; _i < _textNodes.length; _i++) { var node = _textNodes[_i]; var nodeLength = node.textContent.length; if (offset + nodeLength > occurrence.start) { var startOffset = occurrence.start - offset; var endOffset = startOffset + occurrence.word.length; if (startOffset >= 0 && startOffset < nodeLength && endOffset <= nodeLength) { range.setStart(node, startOffset); range.setEnd(node, endOffset); } break; } offset += nodeLength; } highlightRange(range); selection.removeAllRanges(); selection.addRange(range); }; var updateEditedWord = function updateEditedWord(editInput) { setEditedWord(editInput); var regex = new RegExp("\\b".concat(editInput, "\\b"), "gi"); var matches = []; currentContentRef.current.replace(regex, function (match, offset) { matches.push({ word: match, start: offset }); return match; }); setOccurrences(matches); setCurrentOccurrenceIndex(0); }; var navigateVersion = function navigateVersion(direction) { var newIndex = currentVersionIndex + direction; if (newIndex < 0 || newIndex >= history.length) { return; } setCurrentVersionIndex(newIndex); var newText = history[newIndex]; currentContentRef.current = newText; editorRef.current.innerHTML = newText; if (onTextChange) { onTextChange(newText, history, newIndex); } if (onVersionUpdate) { onVersionUpdate(newText, newIndex); } }; useEffect(function () { var uniqueWords = parseUniqueWords(currentContentRef.current); setSuggestions(uniqueWords); }, [initialText]); useEffect(function () { var editor = editorRef.current; if (!editor) { return; } editor.addEventListener("input", handleInput); editor.addEventListener("mouseup", handleSelection); return function () { editor.removeEventListener("input", handleInput); editor.removeEventListener("mouseup", handleSelection); }; }, []); useEffect(function () { var editor = editorRef.current; if (!editor) { return; } var handleCopy = function handleCopy(event) { event.preventDefault(); var selection = window.getSelection(); if (!selection) { return; } var copiedText = ""; for (var i = 0; i < selection.rangeCount; i++) { var range = selection.getRangeAt(i); var clonedRange = range.cloneContents(); var tempDiv = document.createElement("div"); tempDiv.appendChild(clonedRange); copiedText = tempDiv.innerText || tempDiv.textContent; } event.clipboardData.setData("text/plain", copiedText); }; editor.addEventListener("copy", handleCopy); return function () { editor.removeEventListener("copy", handleCopy); }; }, []); useEffect(function () { var handleClickOutside = function handleClickOutside(event) { if (utilityMenuRef.current && !utilityMenuRef.current.contains(event.target) && !editorRef.current.contains(event.target)) { setSelectedWord(null); setOccurrences([]); clearHighlights(); } }; document.addEventListener("mousedown", handleClickOutside); return function () { document.removeEventListener("mousedown", handleClickOutside); }; }, []); useEffect(function () { if (editorRef.current && currentContentRef.current) { editorRef.current.innerText = currentContentRef.current; } }, []); return /*#__PURE__*/React.createElement("div", { style: editorStyles.container }, /*#__PURE__*/React.createElement("style", null, "\n #".concat(editorID, " *::selection {\n background-color: transparent;\n color: inherit;\n }\n ")), /*#__PURE__*/React.createElement("div", { ref: editorRef, id: editorID, style: editorStyles.editor, contentEditable: true, suppressContentEditableWarning: true }), selectedWord && /*#__PURE__*/React.createElement("div", { ref: utilityMenuRef, style: editorStyles.utilityMenu }, /*#__PURE__*/React.createElement("div", { style: editorStyles.suggestions }, suggestions.map(function (word, index) { return /*#__PURE__*/React.createElement("div", { key: index, style: editorStyles.suggestion, onClick: function onClick() { updateEditedWord(word); } }, word); })), /*#__PURE__*/React.createElement("input", { type: "text", value: editedWord, onChange: function onChange(e) { updateEditedWord(e.target.value); }, placeholder: "Edit selected word...", style: editorStyles.input }), /*#__PURE__*/React.createElement("input", { type: "text", value: replacementText, onChange: function onChange(e) { return setReplacementText(e.target.value); }, placeholder: "Replace with...", style: editorStyles.input }), /*#__PURE__*/React.createElement("div", { style: editorStyles.buttons }, /*#__PURE__*/React.createElement(HUDIcon, { iconConfigurationSettings: _objectSpread({}, editorStyles.iconButton), name: "arrow-left", color: "#00ffcc", onClick: function onClick() { return jumpToOccurrence(currentOccurrenceIndex - 1); } }), /*#__PURE__*/React.createElement(HUDIcon, { iconConfigurationSettings: _objectSpread({}, editorStyles.iconButton), name: "check", color: "#4caf50", onClick: replaceOccurrence }), /*#__PURE__*/React.createElement(HUDIcon, { iconConfigurationSettings: _objectSpread({}, editorStyles.iconButton), name: "arrow-right", color: "#00ffcc", onClick: function onClick() { return jumpToOccurrence(currentOccurrenceIndex + 1); } }), /*#__PURE__*/React.createElement(HUDIcon, { iconConfigurationSettings: _objectSpread({}, editorStyles.iconButton), name: "sync", color: "#ff5722", onClick: replaceAllOccurrences }), /*#__PURE__*/React.createElement(HUDIcon, { iconConfigurationSettings: _objectSpread({}, editorStyles.iconButton), name: "times", color: "#f44336", onClick: function onClick() { return setSelectedWord(null); } }))), /*#__PURE__*/React.createElement("div", { style: editorStyles.footerContainer }, /*#__PURE__*/React.createElement("div", { style: editorStyles.footer }, /*#__PURE__*/React.createElement("div", { style: editorStyles.versionNavigation }, /*#__PURE__*/React.createElement(HUDIcon, { style: currentVersionIndex > 0 ? editorStyles.iconButton : editorStyles.iconButtonDisabled, onClick: function onClick() { return navigateVersion(-1); }, color: currentVersionIndex > 0 ? currentVersionLeftButtonActivatedColor : currentVersionLeftButtonDeactivatedColor, name: "arrow-left" }), /*#__PURE__*/React.createElement(HUDIcon, { style: currentVersionIndex < history.length - 1 ? editorStyles.iconButton : editorStyles.iconButtonDisabled, onClick: function onClick() { return navigateVersion(1); }, color: currentVersionIndex < history.length - 1 ? currentVersionRightButtonActivatedColor : currentVersionRightButtonDeactivatedColor, name: "arrow-right" })), /*#__PURE__*/React.createElement("div", { style: editorStyles.versionLabel }, ConvertNumberToMoneyFormat(currentVersionIndex, false))))); }; export default HUDTextEditor;