Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc9bf352

Browse files
authored
Ensure--button-width and--input-width are always up to date (#3786)
This PR fixes an issue where the `--button-width` and `--input-width`CSS variables weren't always up to date.We compute these values initially when the component mounts based on the`getBoundingClientRect` of the button and input elements.To ensure we catch changes in size, we setup a `ResizeObserver` thatwatches for changes to the button and input elements.Unfortunately, `ResizeObserver` doesn't fire when the size changes dueto CSS properties such as `transform` or `scale`. As far as I can tell,there isn't a single event or Observer we can use to catch all possiblechanges.One solution to this problem would be to delay the computation of thesizes until after all transitions have completed and then we could evenintroduce a small delay to ensure everything is in its final state.However, you could literally use `hover:scale-110` on the Listbox buttonwhich would mean that the size changes whenever you hover over thebutton.To fix this in a more generic way, we setup a `requestAnimationFrame`loop that checks the size of the button and input elements on eachframe. If the size has changed, we update the CSS variables.Note: we will only re-render if the size has actually changed, so thisshouldn't cause unnecessary re-renders.The internal hook we use (`useElementSize`) also now receives an`enabled` option such that we only run this `requestAnimationFrame` loopwhen the component is enabled.For components such as the `Combobox`, `Listbox` and `Menu` that meansthat we only start measuring when the corresponding dropdown is in anopen state.Hopefully we can fix this kind of issue with an Observer in the future(e.g.: `PerformanceObserver` with `LayoutShift`(https://developer.mozilla.org/en-US/docs/Web/API/LayoutShift)) but thisis still experimental today.Fixes:#3612Fixes:#3598
1 parent0f27e7f commitc9bf352

File tree

6 files changed

+31
-19
lines changed

6 files changed

+31
-19
lines changed

‎packages/@headlessui-react/CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- Support`<summary>` as a focusable element inside`<details>` ([#3389](https://github.com/tailwindlabs/headlessui/pull/3389))
1515
- Fix`Maximum update depth exceeded` crash when using`transition` prop ([#3782](https://github.com/tailwindlabs/headlessui/pull/3782))
1616
- Ensure pressing`Tab` in the`ComboboxInput`, correctly syncs the input value ([#3785](https://github.com/tailwindlabs/headlessui/pull/3785))
17+
- Ensure`--button-width` and`--input-width` have the latest value ([#3786](https://github.com/tailwindlabs/headlessui/pull/3786))
1718

1819
##[2.2.7] - 2025-07-30
1920

‎packages/@headlessui-react/src/components/combobox/combobox.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,8 +1337,8 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
13371337
style:{
13381338
...theirProps.style,
13391339
...style,
1340-
'--input-width':useElementSize(inputElement,true).width,
1341-
'--button-width':useElementSize(buttonElement,true).width,
1340+
'--input-width':useElementSize(visible,inputElement,true).width,
1341+
'--button-width':useElementSize(visible,buttonElement,true).width,
13421342
}asCSSProperties,
13431343
onWheel:activationTrigger===ActivationTrigger.Pointer ?undefined :handleWheel,
13441344
onMouseDown:handleMouseDown,

‎packages/@headlessui-react/src/components/listbox/listbox.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
794794
style:{
795795
...theirProps.style,
796796
...style,
797-
'--button-width':useElementSize(buttonElement,true).width,
797+
'--button-width':useElementSize(visible,buttonElement,true).width,
798798
}asCSSProperties,
799799
...transitionDataAttributes(transitionData),
800800
})

‎packages/@headlessui-react/src/components/menu/menu.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ function ItemsFn<TTag extends ElementType = typeof DEFAULT_ITEMS_TAG>(
581581
style:{
582582
...theirProps.style,
583583
...style,
584-
'--button-width':useElementSize(buttonElement,true).width,
584+
'--button-width':useElementSize(visible,buttonElement,true).width,
585585
}asCSSProperties,
586586
...transitionDataAttributes(transitionData),
587587
})

‎packages/@headlessui-react/src/components/popover/popover.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ function PanelFn<TTag extends ElementType = typeof DEFAULT_PANEL_TAG>(
851851
style:{
852852
...theirProps.style,
853853
...style,
854-
'--button-width':useElementSize(button,true).width,
854+
'--button-width':useElementSize(visible,button,true).width,
855855
}asReact.CSSProperties,
856856
...transitionDataAttributes(transitionData),
857857
})

‎packages/@headlessui-react/src/hooks/use-element-size.ts‎

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import{useMemo,useReducer}from'react'
1+
import{useState}from'react'
2+
import{disposables}from'../utils/disposables'
23
import{useIsoMorphicEffect}from'./use-iso-morphic-effect'
34

45
functioncomputeSize(element:HTMLElement|null){
@@ -7,26 +8,36 @@ function computeSize(element: HTMLElement | null) {
78
return{ width, height}
89
}
910

10-
exportfunctionuseElementSize(element:HTMLElement|null,unit=false){
11-
let[identity,forceRerender]=useReducer(()=>({}),{})
12-
13-
// When the element changes during a re-render, we want to make sure we
14-
// compute the correct size as soon as possible. However, once the element is
15-
// stable, we also want to watch for changes to the element. The `identity`
16-
// state can be used to recompute the size.
17-
letsize=useMemo(()=>computeSize(element),[element,identity])
11+
exportfunctionuseElementSize(enabled:boolean,element:HTMLElement|null,unit=false){
12+
let[size,setSize]=useState(()=>computeSize(element))
1813

1914
useIsoMorphicEffect(()=>{
2015
if(!element)return
16+
if(!enabled)return
17+
18+
letd=disposables()
19+
20+
// requestAnimationFrame loop to catch any visual changes such as a
21+
// `transform: scale` which wouldn't trigger a ResizeObserver
22+
d.requestAnimationFrame(functionrun(){
23+
d.requestAnimationFrame(run)
24+
25+
setSize((current)=>{
26+
letnewSize=computeSize(element)
27+
28+
if(newSize.width===current.width&&newSize.height===current.height){
29+
// Return the old object to avoid re-renders
30+
returncurrent
31+
}
2132

22-
// Trigger a re-render whenever the element resizes
23-
letobserver=newResizeObserver(forceRerender)
24-
observer.observe(element)
33+
returnnewSize
34+
})
35+
})
2536

2637
return()=>{
27-
observer.disconnect()
38+
d.dispose()
2839
}
29-
},[element])
40+
},[element,enabled])
3041

3142
if(unit){
3243
return{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp