From 963cf15d7f380ea8cc96bd8a007ed46cfd43ad56 Mon Sep 17 00:00:00 2001 From: Dinakar Sarbada Date: Thu, 19 Mar 2026 00:45:09 -0700 Subject: [PATCH 1/5] fix: update string input value in real-time Previously, string inputs only committed changes to the store on blur. This change makes onUpdate fire on every keystroke for string inputs only - number inputs retain their original commit behavior (on blur/enter). Added comment explaining the type !== 'number' guard. Fixes #599 --- packages/leva/src/components/ValueInput/ValueInput.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/leva/src/components/ValueInput/ValueInput.tsx b/packages/leva/src/components/ValueInput/ValueInput.tsx index 4bbcd5c0..04c56c62 100644 --- a/packages/leva/src/components/ValueInput/ValueInput.tsx +++ b/packages/leva/src/components/ValueInput/ValueInput.tsx @@ -84,7 +84,12 @@ export function ValueInput({ autoComplete="off" spellCheck="false" value={value} - onChange={update(onChange)} + onChange={update((value) => { + onChange(value) + // Only call onUpdate for non-number inputs; number inputs retain + // their original commit behavior (on blur/Enter via dragEnd) + if (type !== "number") onUpdate(value) + })} onFocus={() => emitOnEditStart()} onKeyPress={onKeyPress} onKeyDown={onKeyDown} From 38a01ed512d5db71c28c51e29771471c8cc88489 Mon Sep 17 00:00:00 2001 From: Dinakar Sarbada Date: Fri, 20 Mar 2026 03:09:36 -0700 Subject: [PATCH 2/5] chore: add changeset for string input realtime update --- .changeset/plenty-spies-provide.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/plenty-spies-provide.md diff --git a/.changeset/plenty-spies-provide.md b/.changeset/plenty-spies-provide.md new file mode 100644 index 00000000..0b63c906 --- /dev/null +++ b/.changeset/plenty-spies-provide.md @@ -0,0 +1,5 @@ +--- +"leva": patch +--- + +fix: update string input value in real-time From 91c6ba078d6b1025e3541424fd39c9981f65815e Mon Sep 17 00:00:00 2001 From: Dinakar Sarbada Date: Fri, 20 Mar 2026 03:10:43 -0700 Subject: [PATCH 3/5] fix: update folder height when content changes dynamically --- packages/leva/src/hooks/useToggle.ts | 45 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/leva/src/hooks/useToggle.ts b/packages/leva/src/hooks/useToggle.ts index b5676b03..1cc33c5b 100644 --- a/packages/leva/src/hooks/useToggle.ts +++ b/packages/leva/src/hooks/useToggle.ts @@ -94,35 +94,48 @@ export function useToggle(toggled: boolean) { }, []) useEffect(() => { - // prevents first animation + const ref = wrapperRef.current! + const contentEl = contentRef.current! + + const updateHeight = () => { + const { height } = contentEl.getBoundingClientRect() + if (ref.style.height !== `${height}px` && height > 0) { + ref.style.height = `${height}px` + } + } + + if (!toggled) { + ref.style.height = '0px' + ref.style.overflow = 'hidden' + return + } + + // prevents first animation on initial expand if (firstRender.current) { firstRender.current = false + updateHeight() return } - let timeout: number - const ref = wrapperRef.current! - const fixHeight = () => { - if (toggled) { - ref.style.removeProperty('height') - ref.style.removeProperty('overflow') - contentRef.current!.scrollIntoView({ behavior: 'smooth', block: 'nearest' }) - } + ref.style.removeProperty('height') + ref.style.removeProperty('overflow') + contentEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' }) } ref.addEventListener('transitionend', fixHeight, { once: true }) - const { height } = contentRef.current!.getBoundingClientRect() - ref.style.height = height + 'px' - if (!toggled) { - ref.style.overflow = 'hidden' - timeout = window.setTimeout(() => (ref.style.height = '0px'), 50) - } + const { height } = contentEl.getBoundingClientRect() + ref.style.height = `${height}px` + + const resizeObserver = new ResizeObserver(() => { + updateHeight() + }) + resizeObserver.observe(contentEl) return () => { ref.removeEventListener('transitionend', fixHeight) - clearTimeout(timeout) + resizeObserver.disconnect() } }, [toggled]) From d466d38184aae60be11793bc7fd577b64a37f44c Mon Sep 17 00:00:00 2001 From: Dinakar Sarbada Date: Fri, 20 Mar 2026 19:23:23 -0700 Subject: [PATCH 4/5] fix: add transitionend guard and update changeset for folder height - Guard against transitionend not firing when height already matches target - Update changeset to reflect folder height dynamic update --- .changeset/plenty-spies-provide.md | 2 +- packages/leva/src/hooks/useToggle.ts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.changeset/plenty-spies-provide.md b/.changeset/plenty-spies-provide.md index 0b63c906..b99a5bd4 100644 --- a/.changeset/plenty-spies-provide.md +++ b/.changeset/plenty-spies-provide.md @@ -2,4 +2,4 @@ "leva": patch --- -fix: update string input value in real-time +fix: update folder height when content changes dynamically diff --git a/packages/leva/src/hooks/useToggle.ts b/packages/leva/src/hooks/useToggle.ts index 1cc33c5b..69f2581b 100644 --- a/packages/leva/src/hooks/useToggle.ts +++ b/packages/leva/src/hooks/useToggle.ts @@ -126,8 +126,15 @@ export function useToggle(toggled: boolean) { ref.addEventListener('transitionend', fixHeight, { once: true }) const { height } = contentEl.getBoundingClientRect() + const currentHeight = ref.style.height ref.style.height = `${height}px` + // If no transition will occur, call fixHeight directly + if (currentHeight === `${height}px`) { + ref.removeEventListener('transitionend', fixHeight) + fixHeight() + } + const resizeObserver = new ResizeObserver(() => { updateHeight() }) From f32b583d663030cfadf4568c4fd8240c70e0ea5d Mon Sep 17 00:00:00 2001 From: Dinakar Sarbada Date: Sun, 22 Mar 2026 21:55:59 -0700 Subject: [PATCH 5/5] Retrigger CI