[READ-ONLY] Mirror of https://github.com/lukebennett88/luke-ui. luke-ui.netlify.app/
0

Configure Feed

Select the types of activity you want to include in your feed.

Tidy combobox tray internals

Use mergeRefs from @react-aria/utils instead of a hand-rolled ref
merge, drop the redundant SSR guard (effects never run on the server),
and reformat the popover transition list.

Luke Bennett (Jul 11, 2026, 4:18 PM +1000) 4bd29cb2 e8ce3c82

+11 -22
+5 -1
packages/@luke-ui/react/src/recipes/combobox.css.ts
··· 234 234 // A subtle fade for the desktop popover; the tray media query below swaps this for a 235 235 // slide. RAC keeps the element mounted during data-entering/data-exiting so the 236 236 // transition has time to run. 237 - transition: `opacity ${vars.motion.duration.fast} ${vars.motion.easing.standard}, translate ${vars.motion.duration.fast} ${vars.motion.easing.standard}, box-shadow ${vars.motion.duration.fast} ${vars.motion.easing.standard}`, 237 + transition: [ 238 + `opacity ${vars.motion.duration.fast} ${vars.motion.easing.standard}`, 239 + `translate ${vars.motion.duration.fast} ${vars.motion.easing.standard}`, 240 + `box-shadow ${vars.motion.duration.fast} ${vars.motion.easing.standard}`, 241 + ].join(', '), 238 242 239 243 selectors: { 240 244 '&[data-entering]': {
+2 -11
packages/@luke-ui/react/src/combobox-field/primitive/popover.tsx
··· 1 + import { mergeRefs } from '@react-aria/utils'; 1 2 import type { JSX, Ref } from 'react'; 2 3 import { useState } from 'react'; 3 4 import type { PopoverProps as RacPopoverProps } from 'react-aria-components/ComboBox'; ··· 21 22 /** Popover surface used for listbox content. */ 22 23 export function ComboboxPopover(props: ComboboxPopoverProps): JSX.Element { 23 24 const { ref, ...restProps } = props; 24 - // Captured so `useVisualViewportVars` can write CSS custom properties directly onto the 25 - // popover element for the mobile tray. The popover only mounts while open, so the hook's 26 - // listeners are naturally scoped to open state. 27 25 const [element, setElement] = useState<HTMLElement | null>(null); 28 26 useVisualViewportVars(element); 29 27 ··· 33 31 className={composeRenderProps(restProps.className, (className) => { 34 32 return cx(themeRootClassName, styles.comboboxPopover(), className); 35 33 })} 36 - ref={(node: HTMLElement | null) => { 37 - setElement(node); 38 - if (typeof ref === 'function') { 39 - ref(node); 40 - } else if (ref != null) { 41 - ref.current = node; 42 - } 43 - }} 34 + ref={mergeRefs(ref, (node: HTMLElement | null) => setElement(node))} 44 35 /> 45 36 ); 46 37 }
+4 -10
packages/@luke-ui/react/src/combobox-field/primitive/use-visual-viewport-vars.ts
··· 4 4 comboboxTrayViewportHeightVar, 5 5 } from '../../recipes/combobox.css.js'; 6 6 7 - /** 8 - * Mirrors the browser's Visual Viewport onto CSS custom properties set on `element`, so the mobile 9 - * combobox tray (see `recipes/combobox.css.ts`) can size itself against the space actually visible 10 - * above an on-screen keyboard instead of the full layout viewport. Modeled on the approach described 11 - * in Adobe Spectrum's combobox write-up (https://react-aria.adobe.com/blog/building-a-combobox). 12 - * 13 - * No-ops during SSR, when `element` is `null` (the popover isn't mounted while closed), and in 14 - * browsers without `visualViewport` support. 15 - */ 7 + /** Sets the visible viewport height and keyboard inset on the mobile tray. */ 16 8 export function useVisualViewportVars(element: HTMLElement | null): void { 17 9 useEffect(() => { 18 10 if (element === null) return; 19 - if (typeof window === 'undefined' || window.visualViewport == null) return; 11 + if (window.visualViewport == null) return; 20 12 21 13 // Reassigned into locals so TypeScript keeps them narrowed to non-null inside `update`, 22 14 // a nested function declaration whose narrowing TS can't otherwise carry over. ··· 33 25 } 34 26 35 27 update(); 28 + // VisualViewport is not an Element, so ResizeObserver cannot observe it. Scroll also reports 29 + // changes to offsetTop that do not resize the viewport. 36 30 visualViewport.addEventListener('resize', update); 37 31 visualViewport.addEventListener('scroll', update); 38 32