/** * RegexList — editable list of regex patterns. * * Renders a list of monospace inputs with add/delete controls. * Used in jail config panels and the filter form. */ import { useCallback, useMemo, useRef, useState } from "react"; import { Button, Input, Text } from "@fluentui/react-components"; import { Dismiss24Regular } from "@fluentui/react-icons"; import { useConfigStyles } from "./configStyles"; import { createStableStringEntry, reconcileStableStringEntries, StableStringEntry, } from "./stableListEntries"; export interface RegexListProps { /** Section label displayed above the list. */ label: string; /** Current list of regex patterns. */ patterns: string[]; /** Called when the list changes (add, delete, or edit). */ onChange: (next: string[]) => void; /** When true, patterns are displayed read-only with no add/delete controls. */ readOnly?: boolean; } /** * Renders an editable list of regex patterns with add and delete controls. * * @param props - Component props. * @returns JSX element. */ export function RegexList({ label, patterns, onChange, readOnly = false, }: RegexListProps): React.JSX.Element { const styles = useConfigStyles(); const entriesRef = useRef( patterns.map(createStableStringEntry), ); const entries = useMemo(() => { if ( entriesRef.current.length === patterns.length && entriesRef.current.every((entry, index) => entry.value === patterns[index]) ) { return entriesRef.current; } const reconciled = reconcileStableStringEntries(entriesRef.current, patterns); entriesRef.current = reconciled; return reconciled; }, [patterns]); const [newPattern, setNewPattern] = useState(""); const handleAdd = useCallback(() => { const p = newPattern.trim(); if (p) { onChange([...patterns, p]); setNewPattern(""); } }, [newPattern, patterns, onChange]); const handleDelete = useCallback( (idx: number) => { onChange(patterns.filter((_, i) => i !== idx)); }, [patterns, onChange], ); return (
{label} {patterns.length === 0 && ( {" "} (none) )} {entries.map(({ id, value }, i) => (
{ const next = [...patterns]; next[i] = d.value; onChange(next); }} /> {!readOnly && (
))} {!readOnly && (
{ setNewPattern(d.value); }} onKeyDown={(e) => { if (e.key === "Enter") handleAdd(); }} />
)}
); }