Skip to content

Commit

Permalink
components: InputControl to TypeScript (#33696)
Browse files Browse the repository at this point in the history
* components: InputControl to TypeScript

* Add back event to onChange

* Fix on validate and remove todo

* Remove cast and allow undefined values

* Add explanatory comment for omitting prefix

* Use currentTarget

* components: Convert Select to TypeScript (#33784)

* Convert Select to TypeScript

* Stop spreading props into InputBase and add all HTML attributes for select

* Remove need for `omit`

* Remove unused import

* Consistently use currentTarget

* Require isFocused props
  • Loading branch information
sarayourfriend authored Aug 6, 2021
1 parent 10f2ec1 commit 14d80aa
Show file tree
Hide file tree
Showing 18 changed files with 469 additions and 194 deletions.
2 changes: 1 addition & 1 deletion packages/components/src/base-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
* That element should be passed as a child.
* @property {import('react').ReactNode} help If this property is added, a help text will be
* generated using help property as the content.
* @property {import('react').ReactNode} label If this property is added, a label will be generated
* @property {import('react').ReactNode} [label] If this property is added, a label will be generated
* using label property as the content.
* @property {boolean} [hideLabelFromVision] If true, the label will only be visible to screen readers.
* @property {string} [className] The class that will be added with "components-base-control" to the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/
import { noop } from 'lodash';
import classNames from 'classnames';
// eslint-disable-next-line no-restricted-imports
import type { Ref } from 'react';

/**
* WordPress dependencies
Expand All @@ -15,8 +17,9 @@ import { useState, forwardRef } from '@wordpress/element';
*/
import InputBase from './input-base';
import InputField from './input-field';
import type { InputControlProps } from './types';

function useUniqueId( idProp ) {
function useUniqueId( idProp?: string ) {
const instanceId = useInstanceId( InputControl );
const id = `inspector-input-control-${ instanceId }`;

Expand All @@ -42,8 +45,8 @@ export function InputControl(
suffix,
value,
...props
},
ref
}: InputControlProps,
ref: Ref< HTMLInputElement >
) {
const [ isFocused, setIsFocused ] = useState( false );

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* External dependencies
*/
// eslint-disable-next-line no-restricted-imports
import type { Ref } from 'react';

/**
* WordPress dependencies
*/
Expand All @@ -16,17 +22,18 @@ import {
Suffix,
LabelWrapper,
} from './styles/input-control-styles';
import type { InputBaseProps, LabelPosition } from './types';

function useUniqueId( idProp ) {
function useUniqueId( idProp?: string ) {
const instanceId = useInstanceId( InputBase );
const id = `input-base-control-${ instanceId }`;

return idProp || id;
}

// Adapter to map props for the new ui/flex compopnent.
function getUIFlexProps( { labelPosition } ) {
const props = {};
function getUIFlexProps( labelPosition?: LabelPosition ) {
const props: { direction?: string; gap?: number; justify?: string } = {};
switch ( labelPosition ) {
case 'top':
props.direction = 'column';
Expand Down Expand Up @@ -59,21 +66,21 @@ export function InputBase(
size = 'default',
suffix,
...props
},
ref
}: InputBaseProps,
ref: Ref< HTMLDivElement >
) {
const id = useUniqueId( idProp );
const hideLabel = hideLabelFromVision || ! label;

return (
// @ts-expect-error The `direction` prop from Flex (FlexDirection) conflicts with legacy SVGAttributes `direction` (string) that come from React intrinsic prop definitions
<Root
{ ...props }
{ ...getUIFlexProps( { labelPosition } ) }
{ ...getUIFlexProps( labelPosition ) }
className={ className }
isFocused={ isFocused }
labelPosition={ labelPosition }
ref={ ref }
__unstableVersion="next"
>
<LabelWrapper>
<Label
Expand All @@ -91,7 +98,6 @@ export function InputBase(
className="components-input-control__container"
disabled={ disabled }
hideLabel={ hideLabel }
isFocused={ isFocused }
labelPosition={ labelPosition }
>
{ prefix && (
Expand All @@ -105,13 +111,7 @@ export function InputBase(
{ suffix }
</Suffix>
) }
<Backdrop
aria-hidden="true"
disabled={ disabled }
isFocused={ isFocused }
label={ label }
size={ size }
/>
<Backdrop disabled={ disabled } isFocused={ isFocused } />
</Container>
</Root>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
*/
import { noop } from 'lodash';
import { useDrag } from 'react-use-gesture';
// eslint-disable-next-line no-restricted-imports
import type {
SyntheticEvent,
ChangeEvent,
KeyboardEvent,
PointerEvent,
FocusEvent,
Ref,
MouseEvent,
} from 'react';

/**
* WordPress dependencies
Expand All @@ -12,11 +22,13 @@ import { UP, DOWN, ENTER } from '@wordpress/keycodes';
/**
* Internal dependencies
*/
import type { PolymorphicComponentProps } from '../ui/context';
import { useDragCursor } from './utils';
import { Input } from './styles/input-control-styles';
import { useInputControlStateReducer } from './state';
import { useInputControlStateReducer } from './reducer/reducer';
import { isValueEmpty } from '../utils/values';
import { useUpdateEffect } from '../utils';
import type { InputFieldProps } from './types';

function InputField(
{
Expand All @@ -37,12 +49,12 @@ function InputField(
onValidate = noop,
size = 'default',
setIsFocused,
stateReducer = ( state ) => state,
stateReducer = ( state: any ) => state,
value: valueProp,
type,
...props
},
ref
}: PolymorphicComponentProps< InputFieldProps, 'input', false >,
ref: Ref< HTMLInputElement >
) {
const {
// State
Expand Down Expand Up @@ -82,14 +94,16 @@ function InputField(
return;
}
if ( ! isFocused && ! wasDirtyOnBlur.current ) {
update( valueProp );
update( valueProp, _event as SyntheticEvent );
} else if ( ! isDirty ) {
onChange( value, { event: _event } );
onChange( value, {
event: _event as ChangeEvent< HTMLInputElement >,
} );
wasDirtyOnBlur.current = false;
}
}, [ value, isDirty, isFocused, valueProp ] );

const handleOnBlur = ( event ) => {
const handleOnBlur = ( event: FocusEvent< HTMLInputElement > ) => {
onBlur( event );
setIsFocused( false );

Expand All @@ -102,23 +116,23 @@ function InputField(
if ( ! isValueEmpty( value ) ) {
handleOnCommit( event );
} else {
reset( valueProp );
reset( valueProp, event );
}
}
};

const handleOnFocus = ( event ) => {
const handleOnFocus = ( event: FocusEvent< HTMLInputElement > ) => {
onFocus( event );
setIsFocused( true );
};

const handleOnChange = ( event ) => {
const handleOnChange = ( event: ChangeEvent< HTMLInputElement > ) => {
const nextValue = event.target.value;
change( nextValue, event );
};

const handleOnCommit = ( event ) => {
const nextValue = event.target.value;
const handleOnCommit = ( event: SyntheticEvent< HTMLInputElement > ) => {
const nextValue = event.currentTarget.value;

try {
onValidate( nextValue, event );
Expand All @@ -128,7 +142,7 @@ function InputField(
}
};

const handleOnKeyDown = ( event ) => {
const handleOnKeyDown = ( event: KeyboardEvent< HTMLInputElement > ) => {
const { keyCode } = event;
onKeyDown( event );

Expand All @@ -152,7 +166,7 @@ function InputField(
}
};

const dragGestureProps = useDrag(
const dragGestureProps = useDrag< PointerEvent< HTMLInputElement > >(
( dragProps ) => {
const { distance, dragging, event } = dragProps;
// The event is persisted to prevent errors in components using this
Expand Down Expand Up @@ -193,10 +207,13 @@ function InputField(
*/
let handleOnMouseDown;
if ( type === 'number' ) {
handleOnMouseDown = ( event ) => {
handleOnMouseDown = ( event: MouseEvent< HTMLInputElement > ) => {
props.onMouseDown?.( event );
if ( event.target !== event.target.ownerDocument.activeElement ) {
event.target.focus();
if (
event.currentTarget !==
event.currentTarget.ownerDocument.activeElement
) {
event.currentTarget.focus();
}
};
}
Expand All @@ -216,7 +233,7 @@ function InputField(
onKeyDown={ handleOnKeyDown }
onMouseDown={ handleOnMouseDown }
ref={ ref }
size={ size }
inputSize={ size }
value={ value }
type={ type }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
*/
import { VisuallyHidden } from '../visually-hidden';
import { Label as BaseLabel } from './styles/input-control-styles';
import type { PolymorphicComponentProps } from '../ui/context';
import type { InputControlLabelProps } from './types';

export default function Label( {
children,
hideLabelFromVision,
htmlFor,
...props
} ) {
}: PolymorphicComponentProps< InputControlLabelProps, 'label', false > ) {
if ( ! children ) return null;

if ( hideLabelFromVision ) {
Expand Down
66 changes: 66 additions & 0 deletions packages/components/src/input-control/reducer/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* External dependencies
*/
// eslint-disable-next-line no-restricted-imports
import type { SyntheticEvent } from 'react';

/**
* Internal dependencies
*/
import type { DragProps } from '../types';

export const CHANGE = 'CHANGE';
export const COMMIT = 'COMMIT';
export const DRAG_END = 'DRAG_END';
export const DRAG_START = 'DRAG_START';
export const DRAG = 'DRAG';
export const INVALIDATE = 'INVALIDATE';
export const PRESS_DOWN = 'PRESS_DOWN';
export const PRESS_ENTER = 'PRESS_ENTER';
export const PRESS_UP = 'PRESS_UP';
export const RESET = 'RESET';
export const UPDATE = 'UPDATE';

interface EventPayload {
event?: SyntheticEvent;
}

interface Action< Type, ExtraPayload = {} > {
type: Type;
payload: EventPayload & ExtraPayload;
}

interface ValuePayload {
value: string;
}

export type ChangeAction = Action< typeof CHANGE, ValuePayload >;
export type CommitAction = Action< typeof COMMIT, ValuePayload >;
export type PressUpAction = Action< typeof PRESS_UP >;
export type PressDownAction = Action< typeof PRESS_DOWN >;
export type PressEnterAction = Action< typeof PRESS_ENTER >;
export type DragStartAction = Action< typeof DRAG_START, DragProps >;
export type DragEndAction = Action< typeof DRAG_END, DragProps >;
export type DragAction = Action< typeof DRAG, DragProps >;
export type ResetAction = Action< typeof RESET, Partial< ValuePayload > >;
export type UpdateAction = Action< typeof UPDATE, ValuePayload >;
export type InvalidateAction = Action<
typeof INVALIDATE,
{ error: Error | null }
>;

export type ChangeEventAction =
| ChangeAction
| ResetAction
| CommitAction
| UpdateAction;

export type DragEventAction = DragStartAction | DragEndAction | DragAction;

export type KeyEventAction = PressDownAction | PressUpAction | PressEnterAction;

export type InputAction =
| ChangeEventAction
| KeyEventAction
| DragEventAction
| InvalidateAction;
Loading

0 comments on commit 14d80aa

Please sign in to comment.