Skip to content

Commit

Permalink
types cleanup and abstractions
Browse files Browse the repository at this point in the history
  • Loading branch information
dimitropoulos committed Feb 19, 2020
1 parent 79a0c88 commit 11902a4
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 52 deletions.
44 changes: 24 additions & 20 deletions src/components/combo_box/combo_box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import React, {
Component,
Ref,
FocusEventHandler,
KeyboardEvent,
createRef,
RefObject,
KeyboardEventHandler,
} from 'react';
import classNames from 'classnames';

Expand Down Expand Up @@ -38,6 +38,8 @@ import {
EuiComboBoxOptionsListPosition,
EuiComboBoxSingleSelectionShape,
} from './index';
import { UpdatePositionHandler, OptionHandler } from './types';
import { RefCallback } from '../common';

type DrillProps<T> = Pick<
EuiComboBoxOptionsListProps<T>,
Expand All @@ -51,7 +53,7 @@ export interface EuiComboBoxProps<T> extends DrillProps<T> {
compressed: boolean;
fullWidth: boolean;
id?: string;
inputRef?: RefObject<HTMLInputElement>;
inputRef?: RefCallback<HTMLInputElement>;
isClearable: boolean;
isDisabled?: boolean;
isInvalid?: boolean;
Expand All @@ -60,7 +62,7 @@ export interface EuiComboBoxProps<T> extends DrillProps<T> {
onBlur?: FocusEventHandler<HTMLDivElement>;
onChange?: (options: Array<EuiComboBoxOptionOption<T>>) => void;
onFocus?: FocusEventHandler<HTMLDivElement>;
onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;
onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
onSearchChange?: (searchValue: string, hasMatchingOptions?: boolean) => void;
placeholder?: string;
rowHeight?: number;
Expand Down Expand Up @@ -116,7 +118,7 @@ export class EuiComboBox<T> extends Component<

// Refs
comboBoxRef = createRef<HTMLDivElement>();
autoSizeInput = createRef<HTMLInputElement>();
autoSizeInputRef = createRef<HTMLInputElement>();
searchInputRef = createRef<HTMLInputElement>();
listRef = createRef<HTMLInputElement>();
toggleButtonRef = createRef<HTMLButtonElement | HTMLSpanElement>();
Expand All @@ -135,8 +137,8 @@ export class EuiComboBox<T> extends Component<
});
};

updateListPosition = (
listElement: RefObject<HTMLDivElement> | undefined = this.state.listElement
updatePosition: UpdatePositionHandler = (
listElement = this.state.listElement
) => {
if (!this._isMounted) {
return;
Expand Down Expand Up @@ -370,7 +372,7 @@ export class EuiComboBox<T> extends Component<
*/
const relatedTarget = (event.relatedTarget ||
// @ts-ignore need to add window global override
event.explicitOriginalTarget) as (EventTarget | null);
event.explicitOriginalTarget) as (Node | null);

const focusedInOptionsList =
relatedTarget &&
Expand Down Expand Up @@ -398,7 +400,7 @@ export class EuiComboBox<T> extends Component<
}
};

onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
onKeyDown: KeyboardEventHandler<HTMLDivElement> = event => {
switch (event.keyCode) {
case comboBoxKeyCodes.UP:
event.preventDefault();
Expand Down Expand Up @@ -457,11 +459,11 @@ export class EuiComboBox<T> extends Component<
}
};

onOptionEnterKey = (option: EuiComboBoxOptionOption<T>) => {
onOptionEnterKey: OptionHandler<T> = option => {
this.onAddOption(option);
};

onOptionClick = (option: EuiComboBoxOptionOption<T>) => {
onOptionClick: OptionHandler<T> = option => {
this.onAddOption(option);
};

Expand Down Expand Up @@ -501,7 +503,7 @@ export class EuiComboBox<T> extends Component<
}
};

onRemoveOption = (removedOption: EuiComboBoxOptionOption<T>) => {
onRemoveOption: OptionHandler<T> = removedOption => {
const { onChange, selectedOptions } = this.props;
if (onChange) {
onChange(selectedOptions.filter(option => option !== removedOption));
Expand Down Expand Up @@ -585,6 +587,10 @@ export class EuiComboBox<T> extends Component<
);
}

/*
NOTE_TO_SELF(dimitri): this is actually fine but the types are written with readonly for pedantic reasons... might need to @ts-ignore, unfortunately
*/
// @ts-ignore STILL_INVESTIGATING(dimitri)
this.comboBoxRef.current = node;

if (this.comboBoxRef.current) {
Expand All @@ -599,7 +605,7 @@ export class EuiComboBox<T> extends Component<
}
};

optionRef = (index: number, node: RefObject<HTMLDivElement>) => {
optionRef: EuiComboBoxOptionsListProps<T>['optionRef'] = (index, node) => {
this.optionsRefs[index] = node;
};

Expand All @@ -608,11 +614,9 @@ export class EuiComboBox<T> extends Component<

// TODO: This will need to be called once the actual stylesheet loads.
setTimeout(() => {
if (this.autoSizeInput.current) {
/*
NOTE_TO_SELF(dimitri): this either needs an issue (I couldn't find one) or needs to be removed.
*/
this.autoSizeInputcopyInputStyles() = null;
if (this.autoSizeInputRef.current) {
// @ts-ignore https://github.com/DefinitelyTyped/DefinitelyTyped/pull/42467
this.autoSizeInputRef.current.copyInputStyles();
}
}, 100);
}
Expand Down Expand Up @@ -798,7 +802,7 @@ export class EuiComboBox<T> extends Component<
scrollToIndex={activeOptionIndex}
searchValue={searchValue}
selectedOptions={selectedOptions}
updatePosition={this.updateListPosition}
updatePosition={this.updatePosition}
width={width}
/>
</EuiPortal>
Expand Down Expand Up @@ -827,7 +831,7 @@ export class EuiComboBox<T> extends Component<
ref={this.ownRef}
role="combobox">
<EuiComboBoxInput
autoSizeInputRef={this.autoSizeInput}
autoSizeInputRef={this.autoSizeInputRef}
compressed={compressed}
focusedOptionId={
this.hasActiveOption()
Expand Down Expand Up @@ -856,7 +860,7 @@ export class EuiComboBox<T> extends Component<
selectedOptions={selectedOptions}
singleSelection={singleSelection}
toggleButtonRef={this.toggleButtonRef}
updatePosition={this.updateListPosition}
updatePosition={this.updatePosition}
value={value}
/>

Expand Down
20 changes: 13 additions & 7 deletions src/components/combo_box/combo_box_input/combo_box_input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { EuiComboBoxPill } from './combo_box_pill';
import { htmlIdGenerator } from '../../../services';
import { EuiComboBoxOptionOption, EuiComboBoxSingleSelectionShape } from '..';
import { EuiFormControlLayoutIconsProps } from '../../form/form_control_layout/form_control_layout_icons';
import { UpdatePositionHandler, OptionHandler, RefCallback } from '../types';

const makeId = htmlIdGenerator();

Expand All @@ -18,7 +19,7 @@ export interface EuiComboBoxInputProps<T> {
fullWidth?: boolean;
hasSelectedOptions: boolean;
id?: string;
inputRef?: RefObject<HTMLInputElement>;
inputRef?: RefCallback<HTMLInputElement>;
isDisabled?: boolean;
isListOpen: boolean;
noIcon: boolean;
Expand All @@ -29,14 +30,14 @@ export interface EuiComboBoxInputProps<T> {
onCloseListClick: () => void;
onFocus: FocusEventHandler<HTMLInputElement>;
onOpenListClick: () => void;
onRemoveOption?: (option: EuiComboBoxOptionOption<T>) => void;
onRemoveOption?: OptionHandler<T>;
placeholder?: string;
rootId: ReturnType<typeof htmlIdGenerator>;
searchValue: string;
selectedOptions?: Array<EuiComboBoxOptionOption<T>>;
singleSelection?: boolean | EuiComboBoxSingleSelectionShape;
toggleButtonRef?: RefObject<HTMLButtonElement | HTMLSpanElement>;
updatePosition: (listElement?: RefObject<HTMLDivElement> | undefined) => void;
updatePosition: UpdatePositionHandler;
value?: string;
}

Expand Down Expand Up @@ -126,15 +127,13 @@ export class EuiComboBoxInput<T> extends Component<
isDisabled || singleSelection || onClick
? undefined
: onRemoveOption;
const pillOnClick = onClick || (() => {});

return (
<EuiComboBoxPill
option={option}
onClose={pillOnClose}
key={label.toLowerCase()}
color={color}
onClick={pillOnClick}
onClick={onClick}
onClickAriaLabel={onClick ? 'Change' : undefined}
asPlainText={asPlainText}
{...rest}>
Expand Down Expand Up @@ -208,6 +207,7 @@ export class EuiComboBoxInput<T> extends Component<
As I understand it, a `RefObject`, which is what `toggleButtonRef` is, should be accepted, as it is with the `ref` property itself.
*/
// @ts-ignore STILL_INVESTIGATING(dimitri)
icon = {
'aria-label': isListOpen
? 'Close list of options'
Expand Down Expand Up @@ -257,7 +257,13 @@ export class EuiComboBoxInput<T> extends Component<
}
}}
onFocus={this.onFocus}
ref={autoSizeInputRef}
ref={
/*
NOTE_TO_SELF(dimitri): If anyone has a better solution to this problem, I'm all ears :)
*/
autoSizeInputRef as (RefObject<AutosizeInput> &
RefObject<HTMLInputElement>)
}
role="textbox"
style={{ fontSize: 14 }}
value={searchValue}
Expand Down
22 changes: 14 additions & 8 deletions src/components/combo_box/combo_box_input/combo_box_pill.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import React, { AriaAttributes, Component } from 'react';
import React, { AriaAttributes, Component, MouseEventHandler } from 'react';
import classNames from 'classnames';

import { EuiBadge } from '../../badge';
import { EuiI18n } from '../../i18n';
import { EuiComboBoxOptionOption } from '..';
import { OptionHandler } from '../types';

export interface EuiComboBoxPillProps<T> {
interface EuiComboBoxPillProps<T> {
asPlainText?: boolean;
children?: string;
className?: string;
color?: string;
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
onClick?: MouseEventHandler<HTMLButtonElement>;
onClickAriaLabel?: AriaAttributes['aria-label'];
onClose?: (option: EuiComboBoxOptionOption<T>) => void;
onClose?: OptionHandler<T>;
option: EuiComboBoxOptionOption<T>;
}

Expand Down Expand Up @@ -47,6 +48,13 @@ export class EuiComboBoxPill<T> extends Component<EuiComboBoxPillProps<T>> {
},
className
);
const onClickProps =
onClick && onClickAriaLabel
? {
onClick,
onClickAriaLabel,
}
: {};

if (onClose) {
return (
Expand All @@ -63,9 +71,8 @@ export class EuiComboBoxPill<T> extends Component<EuiComboBoxPillProps<T>> {
iconOnClickAriaLabel={removeSelection}
iconSide="right"
iconType="cross"
onClick={onClick}
onClickAriaLabel={onClickAriaLabel}
title={children}
{...onClickProps}
{...rest}>
{children}
</EuiBadge>
Expand All @@ -88,8 +95,7 @@ export class EuiComboBoxPill<T> extends Component<EuiComboBoxPillProps<T>> {
color={color}
title={children}
{...rest}
onClick={onClick}
onClickAriaLabel={onClickAriaLabel}>
{...onClickProps}>
{children}
</EuiBadge>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import React, { Component, KeyboardEvent, ReactNode } from 'react';
import React, { Component, ReactNode, KeyboardEventHandler } from 'react';
import classNames from 'classnames';

import { ENTER, SPACE } from '../../../services/key_codes';
import { RefCallback } from '../../common';
import { EuiComboBoxOptionOption } from '../index';
import { OptionHandler, RefCallback } from '../types';

export interface EuiComboBoxOptionProps<T> {
children?: ReactNode;
className?: string;
disabled?: boolean;
isFocused: boolean;
onClick: (option: EuiComboBoxOptionOption<T>) => void;
onEnterKey: (option: EuiComboBoxOptionOption<T>) => void;
onClick: OptionHandler<T>;
onEnterKey: OptionHandler<T>;
option: EuiComboBoxOptionOption<T>;
optionRef?: RefCallback<HTMLButtonElement>;
}
Expand All @@ -27,7 +27,7 @@ export class EuiComboBoxOption<T> extends Component<EuiComboBoxOptionProps<T>> {
onClick(option);
};

onKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {
onKeyDown: KeyboardEventHandler<HTMLButtonElement> = event => {
if (event.keyCode === ENTER || event.keyCode === SPACE) {
event.preventDefault();
event.stopPropagation();
Expand Down
Loading

0 comments on commit 11902a4

Please sign in to comment.