Skip to content
This repository has been archived by the owner on Jun 11, 2021. It is now read-only.

Commit

Permalink
feat(core): introduce getDropdownProps
Browse files Browse the repository at this point in the history
The `onMouseLeave` event handler shouldn't be on the menu (a.k.a. list) because there might be some titles or other DOM elements in between.
  • Loading branch information
francoischalifour committed Mar 10, 2020
1 parent 31347a7 commit 9b758ee
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 48 deletions.
8 changes: 5 additions & 3 deletions packages/autocomplete-core/src/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ function createAutocomplete<
getEnvironmentProps,
getRootProps,
getFormProps,
getInputProps,
getItemProps,
getLabelProps,
getInputProps,
getDropdownProps,
getMenuProps,
getItemProps,
} = getPropGetters<TItem, TEvent, TMouseEvent, TKeyboardEvent>({
store,
props,
Expand All @@ -55,9 +56,10 @@ function createAutocomplete<
getRootProps,
getFormProps,
getInputProps,
getItemProps,
getLabelProps,
getDropdownProps,
getMenuProps,
getItemProps,
};
}

Expand Down
59 changes: 33 additions & 26 deletions packages/autocomplete-core/src/propGetters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import {
GetEnvironmentProps,
GetRootProps,
GetFormProps,
GetInputProps,
GetItemProps,
GetLabelProps,
GetInputProps,
GetDropdownProps,
GetMenuProps,
GetItemProps,
AutocompleteStore,
AutocompleteOptions,
AutocompleteSetters,
Expand All @@ -30,8 +31,6 @@ export function getPropGetters<TItem, TEvent, TMouseEvent, TKeyboardEvent>({
setStatus,
setContext,
}: GetPropGettersOptions<TItem>) {
const isTouchDevice = 'ontouchstart' in props.environment;

const getEnvironmentProps: GetEnvironmentProps = getterProps => {
return {
// On touch devices, we do not rely on the native `blur` event of the
Expand Down Expand Up @@ -165,6 +164,7 @@ export function getPropGetters<TItem, TEvent, TMouseEvent, TKeyboardEvent>({
store.send('focus', null);
}

const isTouchDevice = 'ontouchstart' in props.environment;
const { inputElement, ...rest } = providedProps;

return {
Expand Down Expand Up @@ -240,6 +240,32 @@ export function getPropGetters<TItem, TEvent, TMouseEvent, TKeyboardEvent>({
};
};

const getLabelProps: GetLabelProps = rest => {
return {
htmlFor: `${props.id}-input`,
id: `${props.id}-label`,
...rest,
};
};

const getMenuProps: GetMenuProps = rest => {
return {
role: 'listbox',
'aria-labelledby': `${props.id}-label`,
id: `${props.id}-menu`,
...rest,
};
};

const getDropdownProps: GetDropdownProps = rest => {
return {
onMouseLeave() {
store.send('mouseleave', null);
},
...rest,
};
};

const getItemProps: GetItemProps<any, TMouseEvent> = providedProps => {
const { item, source, ...rest } = providedProps;

Expand Down Expand Up @@ -329,33 +355,14 @@ export function getPropGetters<TItem, TEvent, TMouseEvent, TKeyboardEvent>({
};
};

const getLabelProps: GetLabelProps = rest => {
return {
htmlFor: `${props.id}-input`,
id: `${props.id}-label`,
...rest,
};
};

const getMenuProps: GetMenuProps = rest => {
return {
role: 'listbox',
'aria-labelledby': `${props.id}-label`,
id: `${props.id}-menu`,
onMouseLeave() {
store.send('mouseleave', null);
},
...rest,
};
};

return {
getEnvironmentProps,
getRootProps,
getFormProps,
getInputProps,
getItemProps,
getLabelProps,
getInputProps,
getDropdownProps,
getMenuProps,
getItemProps,
};
}
39 changes: 23 additions & 16 deletions packages/autocomplete-core/src/types/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export interface AutocompleteAccessibilityGetters<
getEnvironmentProps: GetEnvironmentProps;
getRootProps: GetRootProps;
getFormProps: GetFormProps<TEvent>;
getInputProps: GetInputProps<TEvent, TMouseEvent, TKeyboardEvent>;
getItemProps: GetItemProps<TItem, TMouseEvent>;
getLabelProps: GetLabelProps;
getInputProps: GetInputProps<TEvent, TMouseEvent, TKeyboardEvent>;
getDropdownProps: GetDropdownProps;
getMenuProps: GetMenuProps;
getItemProps: GetItemProps<TItem, TMouseEvent>;
}

export type GetEnvironmentProps = (props: {
Expand Down Expand Up @@ -52,6 +53,13 @@ export type GetFormProps<TEvent = Event> = (props: {
onReset(event: TEvent): void;
};

export type GetLabelProps = (props?: {
[key: string]: unknown;
}) => {
htmlFor: string;
id: string;
};

export type GetInputProps<TEvent, TMouseEvent, TKeyboardEvent> = (props: {
[key: string]: unknown;
inputElement: HTMLInputElement;
Expand All @@ -75,30 +83,29 @@ export type GetInputProps<TEvent, TMouseEvent, TKeyboardEvent> = (props: {
onClick(event: TMouseEvent): void;
};

export type GetItemProps<TItem, TMouseEvent = MouseEvent> = (props: {
export type GetDropdownProps = (props?: {
[key: string]: unknown;
item: TItem;
source: AutocompleteSource<TItem>;
}) => {
id: string;
role: string;
'aria-selected': boolean;
onMouseMove(event: TMouseEvent): void;
onMouseDown(event: TMouseEvent): void;
onClick(event: TMouseEvent): void;
onMouseLeave(): void;
};

export type GetLabelProps = (props?: {
export type GetMenuProps = (props?: {
[key: string]: unknown;
}) => {
htmlFor: string;
role: string;
'aria-labelledby': string;
id: string;
};

export type GetMenuProps = (props?: {
export type GetItemProps<TItem, TMouseEvent = MouseEvent> = (props: {
[key: string]: unknown;
item: TItem;
source: AutocompleteSource<TItem>;
}) => {
role: string;
'aria-labelledby': string;
id: string;
role: string;
'aria-selected': boolean;
onMouseMove(event: TMouseEvent): void;
onMouseDown(event: TMouseEvent): void;
onClick(event: TMouseEvent): void;
};
3 changes: 2 additions & 1 deletion packages/autocomplete-react/src/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,9 @@ export function Autocomplete<TItem extends {}>(
suggestions={state.suggestions}
isOpen={state.isOpen}
status={state.status}
getItemProps={autocomplete.getItemProps}
getMenuProps={autocomplete.getMenuProps}
getDropdownProps={autocomplete.getDropdownProps}
getItemProps={autocomplete.getItemProps}
/>,
rendererProps.dropdownContainer
)}
Expand Down
7 changes: 5 additions & 2 deletions packages/autocomplete-react/src/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { reverseHighlightAlgoliaHit } from '@francoischalifour/autocomplete-pres

import {
AutocompleteState,
GetItemProps,
GetDropdownProps,
GetMenuProps,
GetItemProps,
} from '@francoischalifour/autocomplete-core';

interface DropdownProps {
isOpen: boolean;
status: string;
suggestions: AutocompleteState<any>['suggestions'];
getItemProps: GetItemProps<any, React.MouseEvent>;
getDropdownProps: GetDropdownProps;
getMenuProps: GetMenuProps;
getItemProps: GetItemProps<any, React.MouseEvent>;
dropdownRef: React.MutableRefObject<HTMLDivElement | null>;
}

Expand All @@ -29,6 +31,7 @@ export const Dropdown = (props: DropdownProps) => {
.join(' ')}
ref={props.dropdownRef}
hidden={!props.isOpen}
{...props.getDropdownProps()}
>
{props.isOpen && (
<div className="algolia-autocomplete-dropdown-container">
Expand Down

0 comments on commit 9b758ee

Please sign in to comment.