Skip to content
Clone

fix(repo-browse): fold tabs using the space actually left to them

The tab pill now hugs its labels (w-full -> w-fit), so strip.clientWidth
reported the pill's own answer as the budget: the measure loop fed its

previous output back in and the fit count oscillated. Size the labels
against the wrapper that holds the leftover row width instead, and
observe that wrapper for resizes.
ZhenYi committed
parent 25e4ac6 commit 561f1a7 Browse files

1 file changed

+16 −4

Modified web/src/pages/workspace/ui/layout/repo-layout.tsx View web/src/pages/workspace/ui/layout/repo-layout.tsx
@@ -160,6 +160,7 @@
160160 const strip = stripRef.current
161161 const probe = probeRef.current
162162 if (!strip || !probe) return
163 const host = strip.parentElement
163164 const measure = () => {
164165 const items = Array.from(probe.children) as HTMLElement[]
165166 if (items.length === 0) return
@@ -167,7 +168,15 @@
167168 const gap = Number.parseFloat(probeStyle.columnGap) || 0
168169 const pad =
169170 (Number.parseFloat(probeStyle.paddingLeft) || 0) + (Number.parseFloat(probeStyle.paddingRight) || 0)
170 const available = strip.clientWidth - pad
171 // The pill hugs its labels so it never shows a trailing blank stretch,
172 // so its own width says nothing about the room available: the wrapper
173 // holding it takes the row's leftover width, and that leftover (its
174 // padding aside) is what the labels have to fit into.
175 const hostStyle = host ? getComputedStyle(host) : null
176 const hostPad = hostStyle
177 ? (Number.parseFloat(hostStyle.paddingLeft) || 0) + (Number.parseFloat(hostStyle.paddingRight) || 0)
178 : 0
179 const available = Math.max(0, (host ? host.clientWidth - hostPad : strip.clientWidth) - pad)
171180 let used = 0
172181 let count = 0
173182 for (let index = 0; index < items.length; index += 1) {
@@ -183,8 +192,11 @@
183192 setFit(prev => (prev === next ? prev : next))
184193 }
185194 measure()
195 // The labels fit into the wrapper's leftover width, so that wrapper is what
196 // has to be watched: the pill re-sizes itself as labels move into the menu
197 // and would otherwise only report its own previous answer.
186198 const observer = new ResizeObserver(measure)
187 observer.observe(strip)
199 observer.observe(host ?? strip)
188200 // Label widths follow the locale, and webfonts land after first paint.
189201 document.fonts?.ready.then(measure).catch(() => {})
190202 return () => observer.disconnect()
@@ -210,7 +222,7 @@
210222
211223 if (!onChange) {
212224 return (
213 <nav className="flex h-9 w-full items-center gap-1 rounded-[11px] border border-shell-hairline bg-shell-field p-[3px]">
225 <nav className="flex h-9 w-fit items-center gap-1 rounded-[11px] border border-shell-hairline bg-shell-field p-[3px]">
214226 {tabLabels.map(([id, key]) => (
215227 <span key={id} className={tabItemClass(tabGroup(active) === id)}>
216228 {t(key)}
@@ -223,7 +235,7 @@
223235 return (
224236 <nav
225237 ref={stripRef}
226 className="relative flex h-9 w-full items-center gap-1 rounded-[11px] border border-shell-hairline bg-shell-field p-[3px]"
238 className="relative flex h-9 w-fit items-center gap-1 rounded-[11px] border border-shell-hairline bg-shell-field p-[3px]"
227239 >
228240 <nav
229241 ref={probeRef}