HTML component

hello!
i’m implementing a sudoku solver using streamlit and i want to display an editable sudoku grid using HTML. however, i cannot manage to update the values of the edited cells of the HTML grid once the Enter key is pressed. i am not familiar with HTML and Javascript, so that part of the code was writen from ChatGPT, but i’m wondering whether such thing is doable in the first place.
appreciate the help!
giulio

import numpy as np
import streamlit as st


def generate_editable_sudoku_html(sudoku: np.ndarray) -> str:
    """Generate an editable HTML representation of a sudoku puzzle."""

    style = """
    <style>
        .sudoku-table {
            border-collapse: collapse;
            font-family: Calibri, sans-serif;
            margin: 0 auto;
        }
        .sudoku-table tbody {
            border: solid 3px black;
        }
        .sudoku-table td {
            border: solid 1px black;
            height: 2em;
            width: 2em;
            padding: 0;
        }
        .sudoku-input {
            width: 100%;
            height: 100%;
            border: none;
            text-align: center;
            font-family: Calibri, sans-serif;
            font-size: 1.2em;
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }
        .sudoku-input:focus {
            outline: none;
            background-color: #e8f0fe;
        }
    </style>
    """

    script = """
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        const inputs = document.getElementsByClassName('sudoku-input');
    
        for (let input of inputs) {
            input.addEventListener('keyup', function(e) {
                if (e.key === 'Enter' || this.value.length === 1) {
                    // Validate input to only allow numbers 1-9
                    let value = this.value.replace(/[^1-9]/g, '');
                    if (value.length > 1) value = value[0];
                    this.value = value;
    
                    // Get position data
                    let row = parseInt(this.getAttribute('data-row'));
                    let col = parseInt(this.getAttribute('data-col'));
    
                    // Save data to localStorage
                    localStorage.setItem('sudoku_update', JSON.stringify({ row, col, value: value || "0" }));
    
                    // Move to next input on Enter
                    if (e.key === 'Enter') {
                        let nextCol = col + 1;
                        let nextRow = row;
    
                        if (nextCol > 8) {
                            nextCol = 0;
                            nextRow++;
                        }
                        if (nextRow > 8) nextRow = 0;
    
                        let nextInput = document.querySelector(
                            `[data-row="${nextRow}"][data-col="${nextCol}"]`
                        );
                        if (nextInput) nextInput.focus();
                    }
                }
            });
        }
    });
    </script>


    """

    table = "<table class='sudoku-table'>"
    for i in range(9):
        table += "<tr>"
        for j in range(9):
            # Add thicker borders for 3x3 grid
            border_style = []
            if (i + 1) % 3 == 0 and i < 8:
                border_style.append("border-bottom: 3px solid black")
            if (j + 1) % 3 == 0 and j < 8:
                border_style.append("border-right: 3px solid black")

            cell_style = "; ".join(border_style)
            value = str(sudoku[i, j]) if sudoku[i, j] != 0 else ""

            table += f"""
                <td style="{cell_style}">
                    <input 
                        type="text" 
                        class="sudoku-input"
                        value="{value}"
                        data-row="{i}"
                        data-col="{j}"
                        maxlength="1"
                        pattern="[1-9]"
                    >
                </td>
            """
        table += "</tr>"
    table += "</table>"

    return f"<div style='text-align: center'>{style}{table}{script}</div>"

def main():
    st.title("Editable Sudoku")

    # Initialize session state for the sudoku grid
    if 'sudoku_state' not in st.session_state:
        st.session_state.sudoku_state = np.zeros((9, 9), dtype=int)

    # Create the editable grid
    grid_html = generate_editable_sudoku_html(st.session_state.sudoku_state)
    poll_script = """
    <script>
    const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

    async function pollForUpdates() {
        while (true) {
            const update = localStorage.getItem('sudoku_update');
            if (update) {
                localStorage.removeItem('sudoku_update');
                fetch('/update_sudoku', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: update
                });
            }
            await sleep(1); // Adjust polling interval as needed
        }
    }
    pollForUpdates();
    </script>
    """
    st.components.v1.html(grid_html + poll_script, height=450)

    # Handle updates posted to the backend
    if 'update' in st.query_params:
        update = st.query_params['update'][0]
        try:
            row, col, value = map(int, update.split(','))
            st.session_state.sudoku_state[row, col] = value
        except Exception as e:
            st.error(f"Error parsing update: {e}")

    # Display the current state of the Sudoku grid
    st.write("Current State:")
    st.write(st.session_state.sudoku_state)

if __name__ == "__main__":
    main()