Skip to content

Move Cursor on the string

Following the screenshot below I’m trying to move the cursor through the string which I have no idea how to do.

I’m trying to achieve the effect of an old-phone UI. I’m already managed to make it blink.

desired result

I’m using ReactJs and styled-components. Follow the code below:

import console from 'console';
import { useContext, useEffect, useState } from 'react'
import { PhonewordsContext } from '../../PhonewordsContext';

import { Container, Keyboard, Screen, Cursor } from './styles'

export function Phone() {
    const { getWords } = useContext(PhonewordsContext);

    const [number, setNumber] = useState<string>('');
    const [position, setPosition] = useState<number>(0);
   
    useEffect(() => {
        getWords(number)
    },[number]); // @todo: warning

    function onBtnClicked(char: string) {
        // in case is not in the end of string add substring in the index
        if (position !== number.length){
            setNumber(number.slice(0, position) + char + number.slice(position)) 
        } else {
            setNumber(`${number}${char}`)
        }

        setPosition(position +1)
    }

    function onRemoveChar() {// @todo: how remove words box when empty. re-render?
        const rightPosition = position - 1
        if (position > 0) {
            // concatenate slices of the string before and after the current index
            setNumber(number.slice(0, rightPosition) + number.slice(rightPosition + 1)) 
            setPosition(position -1)
        }
    }

    function onUpClicked() {
        // position never be negative
        if (position > 0)setPosition(position - 1) 
    }

    function onDownClicked() {
        // check for max position
        if (position < number.length) setPosition(position + 1) 
    }

    return (
        <Container>
            <Screen> 
                {/* MOVE CURSOR */}
                <span>
                    {number.split('').map(i => 
                       alert(`here ${i}`)
                    )}
                </span>
                <Cursor />
                {number}
            </Screen>  

            {position}
            <Keyboard>
                <button onClick={() => onUpClicked()}>⬆</button>
                <button onClick={() => onDownClicked()}>⬇</button>
                <button onClick={() => onRemoveChar()}>⌫</button>
                <button disabled>1</button>
                <button onClick={() => onBtnClicked('2')}>2 abc</button>
                <button onClick={() => onBtnClicked('3')}>3 def</button>
                <button onClick={() => onBtnClicked('4')}>4 ghi</button>
                <button onClick={() => onBtnClicked('5')}>5 jkl</button>
                <button onClick={() => onBtnClicked('6')}>6 mno</button>
                <button onClick={() => onBtnClicked('7')}>7 pqrs</button>
                <button onClick={() => onBtnClicked('8')}>8 tuv</button>
                <button onClick={() => onBtnClicked('9')}>9 wxyz</button>
                <button disabled>*</button>
                <button disabled>0 ⌴</button>
                <button disabled>#</button>
            </Keyboard> 
        </Container>
    )
}

and the css file using styled-components:

import styled from "styled-components"

export const Container = styled.div`
    display: flex;
    align-items: center;
    flex-direction: column;
    width: 100%;
`
export const Screen = styled.div`
    padding: 1rem 2rem;
    border: 0;
    border-radius: 0.25rem;
    background: var(--white);
    width: 15rem;
    height: 8rem;
`
export const Keyboard = styled.div`
    display: grid;
    padding: 2rem 0;
    grid-template-columns: repeat(3, 64px);
    grid-template-rows: 32px repeat(4, 64px);
    gap: 8px;

    button {
        border-radius: 0.25rem;
        border: 0;
        box-shadow: #777 2px 1px 10px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;

        transition: 0.4s;
        &:active {
            box-shadow: 2px 2px 2px #777;
            transform: translateY(3px);
        }
    }
`
  
export const Cursor = styled.span`
    animation: blink 1.5s linear infinite alternate;
    border-color: #333;
    border-left: 1px solid;
    margin-left: -1px;

    @keyframes blink {
        50% {
            opacity: 0;
        }
        100% {
            opacity: 1;
        }
    }
`

Thanks for any help!

Answer

 <Screen> 
    {/* MOVE CURSOR */
    <span>{number.slice(0, position)} <Cursor /> {number.slice(position)}</span>
</Screen>  

Managed to implement it using the solution above!