Skip to content

Commit

Permalink
feat(mention): use useClickOutside to handle onBlur event
Browse files Browse the repository at this point in the history
  • Loading branch information
kpman committed Mar 27, 2019
1 parent f34c4be commit 2830512
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 14 deletions.
46 changes: 44 additions & 2 deletions packages/tailor-ui-lab/src/Mention/Mention.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import React, {
useRef,
} from 'react';

import { useClickOutside } from 'tailor-ui';

import Suggestions from './Suggestions';
import { Highlights, MentionWrapper, Textarea } from './styles';
import {
Expand Down Expand Up @@ -40,6 +42,7 @@ export interface FilteredSuggestion {
export type FilteredSuggestions = FilteredSuggestion[];

interface MentionReducerState {
isFocus: boolean;
value: string;
height: number;
activeIndex: number;
Expand All @@ -66,7 +69,9 @@ interface MentionReducerAction {
| 'setSpecfiedItemActive'
| 'updateValue'
| 'updateHeight'
| 'updateCaretPos';
| 'updateCaretPos'
| 'onFocus'
| 'onBlur';
payload?: any;
}

Expand All @@ -77,6 +82,7 @@ interface InitialState {

const initialState = ({ value, suggestions }: InitialState) => ({
value,
isFocus: false,
height: 0,
activeIndex: -1,
caretPos: -1,
Expand Down Expand Up @@ -147,6 +153,16 @@ const reducer: Reducer<MentionReducerState, MentionReducerAction> = (
...state,
caretPos: action.payload,
};
case 'onFocus':
return {
...state,
isFocus: true,
};
case 'onBlur':
return {
...state,
isFocus: false,
};
default:
throw new Error();
}
Expand All @@ -166,6 +182,7 @@ interface MentionProps {
creatable: boolean;
highlightInvalid: boolean;
formatCreateText: FormatCreateText;
onBlur?: () => void;
onChange?: (value: string) => void;
onMentionCreate: (newMention: string) => void;
}
Expand All @@ -174,6 +191,7 @@ const Mention: FunctionComponent<MentionProps> = ({
value: valueFromProps,
defaultValue,
suggestions,
onBlur,
onChange,
onMentionCreate,
disabled,
Expand All @@ -184,6 +202,7 @@ const Mention: FunctionComponent<MentionProps> = ({
}) => {
const mentionRef = useRef<HTMLTextAreaElement>(null);
const highlightRef = useRef<HTMLDivElement>(null);
const suggestionsRef = useRef<HTMLDivElement>(null);

const cursorMention = useRef<CursorMention>({
mention: null,
Expand Down Expand Up @@ -220,6 +239,18 @@ const Mention: FunctionComponent<MentionProps> = ({
}
}, [state.caretPos]);

useClickOutside({
listening: state.isFocus,
refs: [suggestionsRef, mentionRef],
onClickOutside: () => {
if (onBlur) {
onBlur();
}

dispatch({ type: 'onBlur' });
},
});

const resetDropdown = ({ currentTarget }: ResetDropdownType) => {
const cursor = getMentionCursor(
currentTarget.value,
Expand Down Expand Up @@ -368,10 +399,13 @@ const Mention: FunctionComponent<MentionProps> = ({
resetDropdown(event);
};

const handleOnFocus = (event: ChangeEvent<HTMLTextAreaElement>) => {
dispatch({ type: 'onFocus' });
};

const composedProps = mergeEventProps(props, {
onKeyUp: handleKeyUp,
onKeyDown: handleKeyDown,
onBlur: () => dispatch({ type: 'closeDropdown' }),
onClick: resetDropdown,
onChange: handleChange,
onScroll: (event: UIEvent<HTMLTextAreaElement>) => {
Expand All @@ -391,6 +425,7 @@ const Mention: FunctionComponent<MentionProps> = ({
})
);
},
onFocus: handleOnFocus,
});

return (
Expand All @@ -407,8 +442,15 @@ const Mention: FunctionComponent<MentionProps> = ({
value={value}
disabled={disabled}
{...composedProps}
onBlur={(event: ChangeEvent<HTMLTextAreaElement>) => {
event.preventDefault();
event.stopPropagation();

dispatch({ type: 'closeDropdown' });
}}
/>
<Suggestions
ref={suggestionsRef}
formatCreateText={formatCreateText}
dropdownVisible={state.dropdownVisible}
overlayPosition={state.overlayPosition}
Expand Down
26 changes: 14 additions & 12 deletions packages/tailor-ui-lab/src/Mention/Suggestions.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FunctionComponent, useEffect, useRef } from 'react';
import React, { FunctionComponent, forwardRef, useEffect, useRef } from 'react';
import { config, useTransition } from 'react-spring';

import { Portal } from 'tailor-ui';
Expand All @@ -20,15 +20,17 @@ interface SuggestionsProps {
onSuggestionClick: (suggestion: FilteredSuggestion) => void;
}

const Suggestions: FunctionComponent<SuggestionsProps> = ({
dropdownVisible,
activeIndex,
formatCreateText,
overlayPosition,
filteredSuggestions,
onSuggestionClick,
}) => {
const suggestionRef = useRef<HTMLDivElement>(null);
const Suggestions = forwardRef<any, SuggestionsProps>(function Suggestions(
{
dropdownVisible,
activeIndex,
formatCreateText,
overlayPosition,
filteredSuggestions,
onSuggestionClick,
},
suggestionRef
) {
const translations = useTransition(dropdownVisible, null, {
from: {
opacity: 0,
Expand Down Expand Up @@ -56,7 +58,7 @@ const Suggestions: FunctionComponent<SuggestionsProps> = ({
suggestionRef.current.scrollTop = activeItemScrollTop;
}
}
}, [activeIndex]);
}, [activeIndex, suggestionRef]);

return (
<Portal appendFor="mention">
Expand Down Expand Up @@ -93,6 +95,6 @@ const Suggestions: FunctionComponent<SuggestionsProps> = ({
)}
</Portal>
);
};
});

export default Suggestions;

0 comments on commit 2830512

Please sign in to comment.