UNPKG

@mtg-rio/mui-mentions

Version:

@mention people in a MUI TextField

78 lines 3.71 kB
import { Box, Portal } from '@mui/material'; import React from 'react'; import Mention from './Mention'; import { iterateMentionsMarkup } from './utils/utils'; function Highlighter(props) { const { highlighterRef, cursorRef, selectionEnd, selectionStart, value, dataSources, multiline } = props; const components = []; const handleMention = (_markup, index, _plainTextIndex, id, display) => { components.push(React.createElement(Mention, { key: `${id}-${index}`, display: display, color: props.color })); }; const handlePlainText = (text, index, indexInPlaintext) => { if (!multiline) { text = text.replaceAll('\n', ''); } const renderCursor = selectionStart && selectionStart === selectionEnd && selectionStart >= indexInPlaintext && selectionStart <= indexInPlaintext + text.length; if (!renderCursor) { components.push(React.createElement(Box, { key: `${index}-${indexInPlaintext}`, component: 'span', visibility: 'hidden' }, text)); } else { const splitIndex = selectionStart - indexInPlaintext; const startText = text.substring(0, splitIndex); const endText = text.substring(splitIndex); if (startText) { components.push(React.createElement(Box, { key: `${index}-${indexInPlaintext}-precursor`, component: 'span', visibility: 'hidden' }, startText)); } components.push(React.createElement(Box, { key: 'cursor', ref: cursorRef, component: 'span', visibility: 'hidden' })); if (endText) { components.push(React.createElement(Box, { key: `${index}-${indexInPlaintext}-postcursor`, component: 'span', visibility: 'hidden' }, endText)); } } }; iterateMentionsMarkup(value, dataSources, handleMention, handlePlainText, multiline); const rect = getHighlighterRect(props.inputRef); return (React.createElement(Portal, { container: () => { var _a; return ((_a = props.inputRef) === null || _a === void 0 ? void 0 : _a.parentElement) || null; } }, React.createElement(Box, { ref: highlighterRef, sx: { position: 'absolute', top: `${rect.y}px`, left: `${rect.x}px`, width: `${rect.width}px`, height: `${rect.height}px`, whiteSpace: multiline ? 'pre-wrap' : 'pre', overflow: 'hidden', overscrollBehavior: 'none', zIndex: -1, } }, components, React.createElement(Box, { component: 'span', visibility: 'hidden' }, ' ')))); } export default Highlighter; /** * Gets the highlighter rectangle (x, y, width, height) for the provided input element. * @param input The input element to overlay. * @returns The highlighter rectangle. */ function getHighlighterRect(input) { const rec = { x: 0, y: 0, width: 0, height: 0 }; if (!input) { return rec; } const computedStyle = getComputedStyle(input); rec.width = input.clientWidth; rec.width -= parseFloat(computedStyle.paddingLeft); rec.width -= parseFloat(computedStyle.paddingRight); rec.height = input.clientHeight; rec.height -= parseFloat(computedStyle.paddingTop); rec.height -= parseFloat(computedStyle.paddingBottom); rec.x = input.offsetLeft; rec.x += parseFloat(computedStyle.paddingLeft); rec.x += parseFloat(computedStyle.borderLeft); rec.y = input.offsetTop; rec.y += parseFloat(computedStyle.paddingTop); rec.y += parseFloat(computedStyle.borderTop); return rec; } //# sourceMappingURL=Highlighter.js.map