1import { css } from '@emotion/react';
2import { Button, shadows, theme } from '@expo/styleguide';
3import { breakpoints, spacing } from '@expo/styleguide-base';
4import { SearchSmIcon } from '@expo/styleguide-icons';
5import { Dispatch, SetStateAction, useEffect, useState } from 'react';
6
7import { isAppleDevice } from './utils';
8
9import { CALLOUT, KBD } from '~/ui/components/Text';
10
11type Props = {
12  setOpen: Dispatch<SetStateAction<boolean>>;
13};
14
15export const CommandMenuTrigger = ({ setOpen }: Props) => {
16  const [isMac, setIsMac] = useState<boolean | null>(null);
17
18  useEffect(() => {
19    setIsMac(typeof navigator !== 'undefined' && isAppleDevice());
20  }, []);
21
22  useEffect(() => {
23    if (isMac !== null) {
24      const keyDownListener = (e: KeyboardEvent) => {
25        if (e.key === 'k' && (isMac ? e.metaKey : e.ctrlKey)) {
26          e.preventDefault();
27          setOpen(open => !open);
28        }
29      };
30      document.addEventListener('keydown', keyDownListener, false);
31      return () => document.removeEventListener('keydown', keyDownListener);
32    }
33  }, [isMac]);
34
35  return (
36    <Button theme="secondary" css={buttonStyle} onClick={() => setOpen(true)}>
37      <SearchSmIcon />
38      <CALLOUT css={labelStyle}>Search</CALLOUT>
39      {isMac !== null && (
40        <div css={[keysWrapperStyle, hideOnMobileStyle]}>
41          <KBD>{isMac ? '⌘' : 'Ctrl'}</KBD> <KBD>K</KBD>
42        </div>
43      )}
44    </Button>
45  );
46};
47
48const buttonStyle = css({
49  backgroundColor: theme.background.default,
50  padding: `0 ${spacing[3]}px 0 ${spacing[2.5]}px`,
51  borderColor: theme.border.default,
52  boxShadow: shadows.xs,
53  marginBottom: spacing[2.5],
54  minHeight: spacing[10],
55  display: 'flex',
56
57  '&:focus': {
58    boxShadow: shadows.xs,
59  },
60
61  '> span': {
62    width: '100%',
63    gap: spacing[2],
64    alignItems: 'center',
65  },
66
67  kbd: {
68    height: 20,
69    lineHeight: '19px',
70  },
71});
72
73const labelStyle = css({
74  color: theme.icon.secondary,
75});
76
77const keysWrapperStyle = css({
78  marginLeft: 'auto',
79});
80
81const hideOnMobileStyle = css({
82  [`@media screen and (max-width: ${breakpoints.medium}px)`]: {
83    display: 'none',
84  },
85});
86