• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alma-oss / spirit-design-system / 29926312974

22 Jul 2026 01:57PM UTC coverage: 85.422% (-1.0%) from 86.381%
29926312974

Pull #2814

github

pavelklibani
test(e2e): update web-react demo homepage snapshot #DS-2304
Pull Request #2814: 🚧 [WIP] feat(web-react): introduce `UNSTABLE_Combobox` component #DS-2304

2868 of 3885 branches covered (73.82%)

Branch coverage included in aggregate %.

401 of 512 new or added lines in 16 files covered. (78.32%)

7738 of 8531 relevant lines covered (90.7%)

226.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.42
/packages/web-react/src/components/UNSTABLE_Combobox/useComboboxOpenState.ts
1
'use client';
2

3
import { type RefObject, useCallback, useEffect, useState } from 'react';
175✔
4

5
export interface UseComboboxOpenStateProps {
6
  inputRef: RefObject<HTMLInputElement | null>;
7
  isDisabled?: boolean;
8
  isOpen: boolean;
9
  onToggle: () => void;
10
}
11

12
export interface UseComboboxOpenStateReturn {
13
  activeDescendantId: string | undefined;
14
  close: () => void;
15
  focusInput: () => void;
16
  handleDropdownToggle: () => void;
17
  open: () => void;
18
  setActiveDescendantId: (id: string | undefined) => void;
19
}
20

21
/**
22
 * Open/close controls and `aria-activedescendant` lifecycle for Combobox.
23
 *
24
 * @param props Hook configuration
25
 * @param props.inputRef Combobox input
26
 * @param props.isDisabled Whether the Combobox is disabled
27
 * @param props.isOpen Whether the popover is open
28
 * @param props.onToggle Toggle open state
29
 * @returns {{ open: () => void, close: () => void, handleDropdownToggle: () => void, activeDescendantId: string | undefined, setActiveDescendantId: (id: string | undefined) => void, focusInput: () => void }}
30
 */
31
export const useComboboxOpenState = ({
175✔
32
  inputRef,
33
  isDisabled = false,
7✔
34
  isOpen,
35
  onToggle,
36
}: UseComboboxOpenStateProps): UseComboboxOpenStateReturn => {
37
  const [activeDescendantId, setActiveDescendantId] = useState<string | undefined>();
58✔
38

39
  const open = useCallback(() => {
58✔
40
    if (!isOpen && !isDisabled) {
3!
41
      onToggle();
3✔
42
    }
43
  }, [isDisabled, isOpen, onToggle]);
44

45
  const close = useCallback(() => {
58✔
46
    if (isOpen) {
2!
47
      onToggle();
2✔
48
    }
49

50
    setActiveDescendantId(undefined);
2✔
51
  }, [isOpen, onToggle]);
52

53
  const handleDropdownToggle = useCallback(() => {
58✔
NEW
54
    if (isOpen) {
×
NEW
55
      close();
×
56
    } else {
NEW
57
      onToggle();
×
58
    }
59
  }, [close, isOpen, onToggle]);
60

61
  // Safety net for any close path that does not go through `close()` (e.g. parent-driven `isOpen`).
62
  useEffect(() => {
58✔
63
    if (!isOpen) {
44✔
64
      setActiveDescendantId(undefined);
31✔
65
    }
66
  }, [isOpen]);
67

68
  const focusInput = useCallback(() => {
58✔
69
    inputRef.current?.focus();
1✔
70
  }, [inputRef]);
71

72
  return {
58✔
73
    activeDescendantId,
74
    close,
75
    focusInput,
76
    handleDropdownToggle,
77
    open,
78
    setActiveDescendantId,
79
  };
80
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc