Skip to content

Commit

Permalink
feat: search, mobile fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
aulneau committed Jan 9, 2021
1 parent a82857f commit b96d074
Show file tree
Hide file tree
Showing 25 changed files with 555 additions and 320 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@promster/express": "^5.0.0",
"@promster/server": "^6.0.0",
"@reach/tooltip": "^0.12.1",
"@react-aria/interactions": "^3.3.2",
"@react-spectrum/utils": "^3.5.0",
"@react-stately/toggle": "^3.2.1",
"@stacks/auth": "^1.0.0-beta.20",
Expand Down Expand Up @@ -101,6 +102,7 @@
"use-events": "^1.4.2",
"use-onclickoutside": "^0.3.1",
"use-tweaks": "^0.3.1",
"valtio": "^0.5.2",
"wasm-loader": "^1.3.0",
"web-api-hooks": "^3.0.2",
"webassembly": "^0.11.0",
Expand Down
7 changes: 4 additions & 3 deletions src/common/hooks/search/use-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ export const useItem = (resultsData?: SearchResult): [any, boolean] => {
const searchResultsData =
(resultsData?.found && resultsData.result) || (data?.found && data?.result);

const [_, setItem] = useRecoilState(
const [item, setItem] = useRecoilState(
searchResultItemState(searchResultsData && searchResultsData?.entity_id)
);

const { data: item, isValidating } = useSWR(
const { isValidating } = useSWR(
searchResultsData
? [searchResultsData.entity_id, searchResultsData.entity_type, apiServer]
: null,
getFetcher,
{
refreshInterval: undefined,
onSuccess: data => setItem(data as any),
onError: error => setItem(error as any),
}
);

return [item || _, isValidating];
return [item, isValidating];
};
55 changes: 10 additions & 45 deletions src/common/hooks/search/use-search-component.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as React from 'react';
import { useRecentlyViewedItems } from '@common/hooks/search/use-recent-items';
import { useSearch } from '@common/hooks/search/use-search';
import { useSearchDropdown } from '@common/hooks/search/use-search-dropdown';
import { useTimeoutFn } from 'react-use';
import { useFocus, useHover } from 'web-api-hooks';
import { useHover } from 'web-api-hooks';
import { useRecoilFocus } from '@common/hooks/use-recoil-focus';
import { searchDropdownVisibilitySelector, searchFocusedState } from '@store/search';
import { useRecoilValue } from 'recoil';
import { useSearchFocus } from '@common/hooks/search/use-search-focus';

type Variant = 'default' | 'small';

Expand All @@ -15,11 +17,13 @@ export const useSearchComponent = ({
variant?: Variant;
inputRef: any;
timeoutRef: any;
containerRef?: any;
}) => {
const { isVisible, handleMakeHidden, handleMakeVisible } = useSearchDropdown();
const { recentItemsArray } = useRecentlyViewedItems();
const [isHovered, bindHover] = useHover();
const [_, bindFocus] = useFocus();
const [isFocused] = useRecoilFocus(searchFocusedState);
const [_, __, { removeFocus }] = useSearchFocus();
const isVisible = useRecoilValue(searchDropdownVisibilitySelector);
const {
query,
handleUpdateQuery,
Expand All @@ -32,9 +36,6 @@ export const useSearchComponent = ({
value,
} = useSearch(inputRef, timeoutRef);

const isFocused =
inputRef?.current === (typeof document !== 'undefined' && document?.activeElement);

const spinnerVisible = query && isLoading;

const isSmall = variant === 'small';
Expand All @@ -46,43 +47,8 @@ export const useSearchComponent = ({

const hasRecentItems = !!recentItemsArray?.length;

// const [isReady, cancel, reset] = useTimeoutFn(handleMakeHidden, 100);

React.useEffect(() => {
if (isFocused) {
if (!isVisible) {
console.log({ isFocusedIsVisible: isVisible });
handleMakeVisible();
}
} else {
if (isVisible) {
handleMakeHidden();
}
}
// if (!isFocused && isVisible) {
// handleMakeHidden();
// }
}, [isFocused, isVisible]);

// React.useEffect(() => {
// if (isFocused) {
// if (!isVisible) {
// if (hasRecentItems || hasSearchResult) {
// cancel();
// handleMakeVisible();
// }
// }
// } else {
// if (isVisible && !isFocused) {
// // reset();
// // handleMakeHidden();
// }
// }
// }, [isFocused, isVisible, hasRecentItems, hasSearchResult, handleMakeVisible, handleMakeHidden]);

const handleClearResults = () => {
inputRef?.current?.focus?.();
// cancel();
handleClearState();
};

Expand All @@ -92,7 +58,7 @@ export const useSearchComponent = ({

const handleItemOnClick = React.useCallback(() => {
handleClearState();
inputRef?.current?.blur?.();
removeFocus();
}, [inputRef]);

return {
Expand All @@ -117,6 +83,5 @@ export const useSearchComponent = ({
handleSetExiting,
isLoading,
bindHover,
bindFocus,
};
};
7 changes: 7 additions & 0 deletions src/common/hooks/search/use-search-focus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { searchFocusedState } from '@store/search';
import { useRecoilFocus } from '@common/hooks/use-recoil-focus';

export const useSearchFocus = () => {
const results = useRecoilFocus(searchFocusedState);
return [...results];
};
14 changes: 0 additions & 14 deletions src/common/hooks/search/use-search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ import {
} from '@store/search';
import { useItem } from '@common/hooks/search/use-item';
import { usePrevious } from '@common/hooks/search/use-previous';
import { useRecentlyViewedItems } from '@common/hooks/search/use-recent-items';

export const useSearch = (ref: any, isLoadingTimeoutRef: any) => {
const { recentItemsArray } = useRecentlyViewedItems();
const [query, handleSetQuery] = useRecoilState(searchQueryState);
const [value, setValue] = useRecoilState(searchValueState);
const [exiting, handleSetExiting] = useRecoilState(searchExitingState);
Expand Down Expand Up @@ -91,18 +89,6 @@ export const useSearch = (ref: any, isLoadingTimeoutRef: any) => {
isLoadingTimeoutRef.current,
]);

// React.useEffect(() => {
// if (!value) {
// if (recentItemsArray.length === 0) {
// if (previous || item) {
// handleSetExiting(false);
// }
// } else {
// handleClearState();
// }
// }
// }, [query, value, previous, item]);

return {
value,
setValue,
Expand Down
67 changes: 67 additions & 0 deletions src/common/hooks/use-focus-within.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { FocusEvent, HTMLAttributes, MutableRefObject } from 'react';

interface FocusWithinProps {
/** Whether the focus within events should be disabled. */
isDisabled?: boolean;
/** Handler that is called when the target element or a descendant receives focus. */
onFocusWithin?: (e: FocusEvent) => void;
/** Handler that is called when the target element and all descendants lose focus. */
onBlurWithin?: (e: FocusEvent) => void;
/** Handler that is called when the the focus within state changes. */
onFocusWithinChange?: (isFocusWithin: boolean) => void;
ref: MutableRefObject<{ isFocusWithin: boolean }>;
}

interface FocusWithinResult {
/** Props to spread onto the target element. */
focusWithinProps: HTMLAttributes<HTMLElement>;
}

/**
* Handles focus events for the target and its descendants.
*/
export function useFocusWithin(props: FocusWithinProps): FocusWithinResult {
const state = props.ref.current;

if (props.isDisabled) {
return { focusWithinProps: {} };
}

const onFocus = (e: FocusEvent) => {
if (!state.isFocusWithin) {
if (props.onFocusWithin) {
props.onFocusWithin(e);
}

if (props.onFocusWithinChange) {
props.onFocusWithinChange(true);
}

state.isFocusWithin = true;
}
};

const onBlur = (e: FocusEvent) => {
// We don't want to trigger onBlurWithin and then immediately onFocusWithin again
// when moving focus inside the element. Only trigger if the currentTarget doesn't
// include the relatedTarget (where focus is moving).
if (state.isFocusWithin && !e.currentTarget.contains(e.relatedTarget as HTMLElement)) {
if (props.onBlurWithin) {
props.onBlurWithin(e);
}

if (props.onFocusWithinChange) {
props.onFocusWithinChange(false);
}

state.isFocusWithin = false;
}
};

return {
focusWithinProps: {
onFocus: onFocus,
onBlur: onBlur,
},
};
}
18 changes: 5 additions & 13 deletions src/common/hooks/use-network-mode.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import useSWR from 'swr';
import { getNetworkMode } from '@common/api/network';
import { useApiServer } from '@common/hooks/use-api';
import { useRecoilValue } from 'recoil';
import { networkModeState } from '@pages/_app';

export const useNetworkMode = (initialData?: 'Testnet' | 'Mainnet') => {
const apiServer = useApiServer();
const { data } = useSWR<'Testnet' | 'Mainnet' | undefined>(
'/v2/info',
() => getNetworkMode(apiServer),
{
initialData,
}
);
return data;
export const useNetworkMode = () => {
const state = useRecoilValue(networkModeState);
return state;
};
25 changes: 25 additions & 0 deletions src/common/hooks/use-recoil-focus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { RecoilState, useRecoilState } from 'recoil';
import { useFocusWithin } from '@common/hooks/use-focus-within';

export function useRecoilFocus(
atom: RecoilState<boolean>
): [boolean, any, { removeFocus: () => void }] {
const [isFocused, setIsFocused] = useRecoilState(atom);

const ref = React.useRef({
isFocusWithin: false,
});

const { focusWithinProps } = useFocusWithin({
onFocusWithinChange: setIsFocused,
ref,
});

const removeFocus = () => {
setIsFocused(false);
ref.current.isFocusWithin = false;
};

return [isFocused, focusWithinProps, { removeFocus }];
}
Loading

0 comments on commit b96d074

Please # to comment.