diff --git a/frontend/app/module/input/page/PollingStationPage.tsx b/frontend/app/module/input/page/PollingStationPage.tsx index b8da00238..82a5643c4 100644 --- a/frontend/app/module/input/page/PollingStationPage.tsx +++ b/frontend/app/module/input/page/PollingStationPage.tsx @@ -8,7 +8,7 @@ export function PollingStationPage() { const targetForm = section || "recount"; - const { register } = useInputMask({}); + const { register, format } = useInputMask({}); return ( <>
@@ -31,7 +31,7 @@ export function PollingStationPage() { Is er herteld? - + Aantal kiezers en stemmen @@ -61,7 +61,7 @@ export function PollingStationPage() { A - + Stempassen @@ -71,7 +71,7 @@ export function PollingStationPage() { A - + Stempassen diff --git a/frontend/lib/ui/inputgrid/InputGrid.tsx b/frontend/lib/ui/inputgrid/InputGrid.tsx index cb02d6563..4c25e9abb 100644 --- a/frontend/lib/ui/inputgrid/InputGrid.tsx +++ b/frontend/lib/ui/inputgrid/InputGrid.tsx @@ -32,11 +32,16 @@ export function InputGrid({ zebra, children }: InputGridProps) { targetIndex = 0; } - inputList.current[activeIndex].el.blur(); - inputList.current[targetIndex].el.focus(); - setTimeout(() => { - inputList.current[targetIndex].el.select(); - }, 1); + const cur = inputList.current[activeIndex]; + const next = inputList.current[targetIndex]; + + if (cur && next) { + cur.el.blur(); + next.el.focus(); + setTimeout(() => { + next.el.select(); + }, 1); + } }, []); React.useEffect(() => { @@ -89,11 +94,9 @@ export function InputGrid({ zebra, children }: InputGridProps) { }); return () => { - if (tableEl) { - tableEl.querySelectorAll("input").forEach((input) => { - input.removeEventListener("focus", handleFocus); - }); - } + tableEl.querySelectorAll("input").forEach((input) => { + input.removeEventListener("focus", handleFocus); + }); }; } }, []); diff --git a/frontend/lib/ui/inputgrid/inputgrid.module.css b/frontend/lib/ui/inputgrid/inputgrid.module.css index 0d5875f8b..81c91bb63 100644 --- a/frontend/lib/ui/inputgrid/inputgrid.module.css +++ b/frontend/lib/ui/inputgrid/inputgrid.module.css @@ -45,6 +45,7 @@ padding-left: 8px; padding-right: 8px; font-style: normal; + font-feature-settings: "ss09" on; } } diff --git a/frontend/lib/util/classnames.test.ts b/frontend/lib/util/classnames.test.ts index 9633bff0b..775df26a2 100644 --- a/frontend/lib/util/classnames.test.ts +++ b/frontend/lib/util/classnames.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "vitest"; import { classnames, cn } from "./classnames"; -test("classnames result", async () => { +test("classnames result", () => { const result = classnames("test", { test2: true, test3: false }); const result2 = cn("test", { test2: true, test3: false }); expect(result2).toBe(result); diff --git a/frontend/lib/util/classnames.ts b/frontend/lib/util/classnames.ts index 8a349b414..1141b6e57 100644 --- a/frontend/lib/util/classnames.ts +++ b/frontend/lib/util/classnames.ts @@ -1,4 +1,6 @@ -export function classnames(...args: (string | Record)[]): string { +export function classnames( + ...args: (string | undefined | Record)[] +): string { const classes: string[] = []; for (const arg of args) { diff --git a/frontend/lib/util/domtoren.test.ts b/frontend/lib/util/domtoren.test.ts index 16f726fd7..0855c7f6e 100644 --- a/frontend/lib/util/domtoren.test.ts +++ b/frontend/lib/util/domtoren.test.ts @@ -1,4 +1,4 @@ -import { expect, test } from "vitest"; +import { expect, test, assert } from "vitest"; import { domtoren } from "./domtoren"; const div = document.createElement("div"); @@ -8,14 +8,15 @@ div.innerHTML = `

`; -test("domtoren closest", async () => { +test("domtoren closest", () => { const aEl = div.querySelector("a"); - const pEl = domtoren(aEl!).closest("p").el(); + assert(aEl !== null, "aEl is null"); - expect(pEl!.tagName.toLowerCase()).toBe("p"); + const pEl = domtoren(aEl).closest("p").el(); + expect(pEl.tagName.toLowerCase()).toBe("p"); }); -test("domtoren toggleClass", async () => { +test("domtoren toggleClass", () => { domtoren(div).toggleClass("testclass"); expect(div.classList.contains("testclass")).toBe(true); }); diff --git a/frontend/lib/util/hook/useInputMask.ts b/frontend/lib/util/hook/useInputMask.ts index 00c0851f8..90b213eab 100644 --- a/frontend/lib/util/hook/useInputMask.ts +++ b/frontend/lib/util/hook/useInputMask.ts @@ -2,39 +2,57 @@ import * as React from "react"; export interface UseInputMaskParams {} +export type FormatFunc = (s: string | number | null | undefined) => string; + export interface UseInputMaskReturn { + format: FormatFunc; register: () => { onChange: React.ChangeEventHandler; + onLoad: React.ChangeEventHandler; }; } +const numberFormatter = new Intl.NumberFormat("nl-NL", { + maximumFractionDigits: 0 +}); + export function useInputMask({}: UseInputMaskParams): UseInputMaskReturn { - const numberFormatter = React.useMemo(() => { - return new Intl.NumberFormat("nl-NL", { - maximumFractionDigits: 0 - }); + const format: FormatFunc = React.useCallback((s) => { + if (!s) return ""; + if (s === "") { + return ""; + } + + let result = `${s}`.replace(/\D/g, ""); + result = numberFormatter.format(Number(result)); + return result; }, []); const onChange: React.ChangeEventHandler = React.useCallback( (event) => { //remove all non numbers - const value = event.target.value.replace(/\D/g, ""); - if (value !== "") { - event.target.value = numberFormatter.format(Number(value)); - } else { - event.target.value = ""; - } + event.target.value = format(event.target.value); + }, + [format] + ); + + const onLoad: React.ChangeEventHandler = React.useCallback( + (event) => { + console.log("Onload??", event.target.value); + event.target.value = format(event.target.value); }, - [numberFormatter] + [format] ); const register = () => { return { - onChange + onChange, + onLoad }; }; return { + format, register }; }