From 3793ee9f5b7419865f6c10f0b63631fa11d47775 Mon Sep 17 00:00:00 2001 From: LucasDLTG Date: Sat, 12 Sep 2026 13:35:02 +0200 Subject: [PATCH] feat: prevent text selection on add dsp page --- src/pages/AddDspPage/AddDspPage.css | 11 +++++ src/pages/AddDspPage/AddDspPage.tsx | 77 ++++++++++++++++++++++++++--- src/pages/HomePage/HomePage.css | 2 + 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/pages/AddDspPage/AddDspPage.css b/src/pages/AddDspPage/AddDspPage.css index 61940c0..321ba06 100644 --- a/src/pages/AddDspPage/AddDspPage.css +++ b/src/pages/AddDspPage/AddDspPage.css @@ -161,3 +161,14 @@ font-family: var(--font-mono); font-weight: var(--font-weight-normal); } + +.add-dsp-form { + user-select: none; + -webkit-user-select: none; +} + +.add-dsp-form input, +.add-dsp-form select { + user-select: text; + -webkit-user-select: text; +} \ No newline at end of file diff --git a/src/pages/AddDspPage/AddDspPage.tsx b/src/pages/AddDspPage/AddDspPage.tsx index 0ce060d..cd3fbae 100644 --- a/src/pages/AddDspPage/AddDspPage.tsx +++ b/src/pages/AddDspPage/AddDspPage.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useRef } from 'react'; import { DSP, DSP_DEFAULT_PARAMETERS, DSPTypes } from '../../types'; import Button from '../../components/Button/Button'; import Card from '../../components/Card/Card'; @@ -18,12 +18,26 @@ type DSPForm = { const DSP_TYPES = Object.keys(DSP_DEFAULT_PARAMETERS) as DSPTypes[]; +function isValidIPv4(value: string): boolean { + const parts = value.trim().split('.'); + + if (parts.length !== 4) return false; + + return parts.every((part) => { + if (!/^\d+$/.test(part)) return false; + + const n = Number(part); + + return n >= 0 && n <= 255; + }); +} + function AddDSPForm({ onCancel, onAdd, }: { onCancel: () => void; - onAdd: (d: Omit) => void; + onAdd: (dsp: Omit) => void; }) { const [form, setForm] = useState({ name: '', @@ -34,23 +48,51 @@ function AddDSPForm({ demo: false, }); + const lastValidIp = useRef(form.ip); + + const validIp = form.demo || isValidIPv4(form.ip); + const canSubmit = form.name.trim().length > 0 && - (form.demo || form.ip.trim().length > 0) && + validIp && Number.isInteger(form.deviceId) && form.deviceId >= 1 && form.deviceId <= 255; + function validateIp() { + if (form.demo) return; + + const ip = form.ip.trim(); + + if (isValidIPv4(ip)) { + lastValidIp.current = ip; + + if (ip !== form.ip) { + setForm((prev) => ({ ...prev, ip })); + } + + return; + } + + setForm((prev) => ({ + ...prev, + ip: lastValidIp.current, + })); +} + function submit() { if (!canSubmit) return; + onAdd({ ...form }); } return ( - +

Add DSP

-

Register a new device to control from this app.

+

+ Register a new device to control from this app. +

@@ -91,12 +133,26 @@ function AddDSPForm({
+ setForm({ ...form, ip: e.target.value })} + onChange={(e) => + setForm((prev) => ({ + ...prev, + ip: e.target.value, + })) + } + onBlur={validateIp} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + validateIp(); + e.currentTarget.blur(); + } + }} />
@@ -121,7 +177,11 @@ function AddDSPForm({ id="f-demo" type="checkbox" checked={form.demo} - onChange={(e) => setForm({ ...form, demo: e.target.checked })} + onChange={(e) => { + const demo = e.target.checked; + + setForm({ ...form, demo }); + }} /> Demo mode (simulate device, no network connection) @@ -131,6 +191,7 @@ function AddDSPForm({ + @@ -139,4 +200,4 @@ function AddDSPForm({ ); } -export default AddDSPForm; +export default AddDSPForm; \ No newline at end of file diff --git a/src/pages/HomePage/HomePage.css b/src/pages/HomePage/HomePage.css index b40e4c5..123bedb 100644 --- a/src/pages/HomePage/HomePage.css +++ b/src/pages/HomePage/HomePage.css @@ -9,6 +9,8 @@ padding: var(--space-6); box-sizing: border-box; + -webkit-user-select: none; + user-select: none; } .specs {