From 1c5679b41ec3613889ba6e32a801088d8eb1f7ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 08:55:54 +0000 Subject: [PATCH 1/2] Initial plan From 348ed456f16429def8fc02ede8e7af58bcb2eba7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 09:02:47 +0000 Subject: [PATCH 2/2] @remotion/design: Fix Counter input to allow typing numbers Co-authored-by: JonnyBurger <1629785+JonnyBurger@users.noreply.github.com> --- packages/design/src/Counter.tsx | 59 +++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/packages/design/src/Counter.tsx b/packages/design/src/Counter.tsx index e6287a49893..5a4662ef6cf 100644 --- a/packages/design/src/Counter.tsx +++ b/packages/design/src/Counter.tsx @@ -1,5 +1,5 @@ import type {ChangeEvent} from 'react'; -import React from 'react'; +import React, {useEffect, useState} from 'react'; import {Card} from './Card'; import {cn} from './helpers/cn'; @@ -53,6 +53,17 @@ export const Counter: React.FC = ({ minCount = 0, step = 1, }) => { + // Local state to track the input value while typing + const [inputValue, setInputValue] = useState(String(count)); + const [isFocused, setIsFocused] = useState(false); + + // Update local input value when count changes from outside (e.g., increment/decrement) + useEffect(() => { + if (!isFocused) { + setInputValue(String(count)); + } + }, [count, isFocused]); + const decrement = () => { if (count > minCount) { setCount(Math.max(minCount, count - step)); @@ -63,6 +74,29 @@ export const Counter: React.FC = ({ setCount(count + step); }; + const validateAndSetCount = (value: string) => { + if (value.trim() === '') { + setCount(step === 1 ? 1 : minCount); + return; + } + + const parsedValue = parseInt(value, 10); + if (isNaN(parsedValue)) { + setInputValue(String(count)); + return; + } + + const validValue = Math.max(parsedValue, minCount); + + // For steps > 1, round to the nearest valid step + if (step > 1) { + const roundedValue = Math.round(validValue / step) * step; + setCount(Math.max(roundedValue, minCount)); + } else { + setCount(validValue); + } + }; + return ( = ({ } type="number" onClick={(e) => e.currentTarget.select()} - value={count} + value={inputValue} onChange={(e: ChangeEvent) => { - if (e.target.value.trim() === '') { - setCount(step === 1 ? 1 : minCount); - return; - } - - const inputValue = parseInt(e.target.value, 10); - const validValue = Math.max(inputValue, minCount); - - // For steps > 1, round to the nearest valid step - if (step > 1) { - const roundedValue = Math.round(validValue / step) * step; - setCount(Math.max(roundedValue, minCount)); - } else { - setCount(validValue); - } + setInputValue(e.target.value); + }} + onFocus={() => setIsFocused(true)} + onBlur={() => { + setIsFocused(false); + validateAndSetCount(inputValue); }} />