feat: prevent text selection on add dsp page
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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<DSP, 'status' | 'id' | 'state' | 'meters' | 'pollingPaused'>) => void;
|
||||
onAdd: (dsp: Omit<DSP, 'status' | 'id' | 'state' | 'meters' | 'pollingPaused'>) => void;
|
||||
}) {
|
||||
const [form, setForm] = useState<DSPForm>({
|
||||
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 (
|
||||
<Card>
|
||||
<Card className="add-dsp-form">
|
||||
<div className="add-dsp-form__header">
|
||||
<h1 className="add-dsp-form__title">Add DSP</h1>
|
||||
<p className="add-dsp-form__hint">Register a new device to control from this app.</p>
|
||||
<p className="add-dsp-form__hint">
|
||||
Register a new device to control from this app.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="add-dsp-form__field">
|
||||
@@ -91,12 +133,26 @@ function AddDSPForm({
|
||||
<div className="add-dsp-form__row">
|
||||
<div className="add-dsp-form__field">
|
||||
<label htmlFor="f-ip">IP address</label>
|
||||
|
||||
<input
|
||||
id="f-ip"
|
||||
className="mono"
|
||||
value={form.ip}
|
||||
disabled={form.demo}
|
||||
onChange={(e) => 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();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -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)
|
||||
</label>
|
||||
@@ -131,6 +191,7 @@ function AddDSPForm({
|
||||
<Button variant="ghost" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
<Button variant="primary" onClick={submit} disabled={!canSubmit}>
|
||||
Add DSP
|
||||
</Button>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
padding: var(--space-6);
|
||||
|
||||
box-sizing: border-box;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.specs {
|
||||
|
||||
Reference in New Issue
Block a user