i'm trying to build some text editor with react
i'm not native in english, so sorry about below question
what i want to do is like this below
- if user drag text with mouse(or with keyboard) to set a block in some texts,
- popup menu(to edit 'seleted texts') show
i'm stuck at first one.
i can get whole text and selected text
let wholeText = whole.anchorNode.childNodes[0].defaultValue;
let selectedText = window.getSelection().toString();
but i can't get 'exact location' of selectedText
in wholeText
here's my code (react, styled-component)
import { useState, useEffect } from 'react';
import styled from 'styled-components';
import autosize from 'autosize';
export default function TextBox({ id, index, content, handleContentInput }) {
const [currentContent, setCurrentContent] = useState(content);
const [areaHeight, setAreaHeight] = useState(25);
useEffect(() => {
autosize(document.querySelector(`.TextBoxWrap_${id}`));
}, [currentContent]);
return (
<TextBoxContainer
className={`TextBoxContainer_${id}`}
areaHeight={areaHeight}
onClick={() => {
document.querySelector(`.TextBoxContainer_${id}`).focus();
}}
>
<TextBoxWrap
className={`TextBoxWrap_${id}`}
areaHeight={areaHeight}
onChange={(event) => {
setCurrentContent(event.target.value);
}}
onBlur={() => handleContentInput(id, index, currentContent)}
onKeyUp={() => {
let newHeight = document.querySelector(`.TextBoxWrap_${id}`)
.clientHeight;
setAreaHeight(newHeight);
}}
onMouseUp={() => {
let whole = window.getSelection();
if (!whole) return;
let range = whole.getRangeAt(0);
console.log({ whole, range });
let wholeText = whole.anchorNode.childNodes[0].defaultValue;
let selectedText = whole.toString();
console.log({ wholeText, selectedText });
let start = range.startOffset; // Start position
let end = range.endOffset; // End position
console.log({ start, end });
}}
value={currentContent}
></TextBoxWrap>
</TextBoxContainer>
);
}
const TextBoxContainer = styled.div`
max-width: 890px;
width: 100%;
height: ${(props) => `${props.areaHeight}px`};
border: 1px solid black;
margin: 3px;
padding: 2px;
`;
const TextBoxWrap = styled.textarea`
/* border: 1px solid black; */
box-sizing: 'border-box';
border: none;
outline: none;
width: 100%;
min-height: 20px;
height: 20px;
/* padding: 2x; */
box-shadow: none;
display: block;
overflow: hidden; // Removes scrollbar
resize: none;
font-size: 18px;
/* line-height: 1.5em; */
/* font-family: Georgia, 'Malgun Gothic', serif; */
`;
inside of onMouseUp
, it works like this
- console.log({ wholeText, selectedText }); : works fine
- console.log({ start, end }); : always 0, 0
wholeText.indexOf(selectedText)
was my option, but indexOf()
gives me just 'first' index matches,
so, even if i want "aaaaaa'a'aa" but indexOf will give me '0' (=> "'a'aaaaaaaaaa")
what i was thinking,
- get the 'exact index(location)', and cut
wholeText
with it - decorate
selectedText
with popup box (return html element? like <span style{{color: 'red'}}>${selectedText} - then, combine these three items (wholeText_front, decorated_selectedText, wholeText_back)
- and, to place popup menu div right above seleted texts
which means, i need 'selected one's location
how can i do this? plz give me advice
thank you!
posts i read before post this question