Skip to content

Commit

Permalink
InputControl: Improve type annotations and stories (#40119)
Browse files Browse the repository at this point in the history
* Fix inaccuracy in readme for `value` prop

* Properly export `InputControl` component for TS extraction

* Fix placement of `FlexProps` type

`InputControl` itself does not accept `Flex` props. Only `InputBase` does.

* Add descriptions from readmes into types.ts

* Convert stories

* Convert stories to TS

* Update changelog

* Keep type unions inside types.ts

* Add description and default for `isFocus` prop
  • Loading branch information
mirka authored Apr 12, 2022
1 parent 7183f04 commit b523364
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 78 deletions.
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Update `BorderControl` and `BorderBoxControl` to allow the passing of custom class names to popovers ([#39753](https://github.com/WordPress/gutenberg/pull/39753)).
- `ToggleGroupControl`: Reintroduce backdrop animation ([#40021](https://github.com/WordPress/gutenberg/pull/40021)).
- `Card`: Adjust border radius effective size ([#40032](https://github.com/WordPress/gutenberg/pull/40032)).
- `InputControl`: Improved TypeScript type annotations ([#40119](https://github.com/WordPress/gutenberg/pull/40119)).

### Internal

Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/input-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,5 @@ Type of the input element to render. Defaults to "text".

The current value of the input.

- Type: `String | Number`
- Required: Yes
- Type: `String`
- Required: No
25 changes: 22 additions & 3 deletions packages/components/src/input-control/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function useUniqueId( idProp?: string ) {
return idProp || id;
}

export function InputControl(
export function UnforwardedInputControl(
{
__unstableStateReducer: stateReducer = ( state ) => state,
__unstableInputWidth,
Expand Down Expand Up @@ -88,6 +88,25 @@ export function InputControl(
);
}

const ForwardedComponent = forwardRef( InputControl );
/**
* InputControl components let users enter and edit text. This is an experimental component
* intended to (in time) merge with or replace `TextControl`.
*
* @example
* import { __experimentalInputControl as InputControl } from '@wordpress/components';
* import { useState } from '@wordpress/compose';
*
* const Example = () => {
* const [ value, setValue ] = useState( '' );
*
* return (
* <InputControl
* value={ value }
* onChange={ ( nextValue ) => setValue( nextValue ) }
* />
* );
* };
*/
export const InputControl = forwardRef( UnforwardedInputControl );

export default ForwardedComponent;
export default InputControl;
71 changes: 0 additions & 71 deletions packages/components/src/input-control/stories/index.js

This file was deleted.

63 changes: 63 additions & 0 deletions packages/components/src/input-control/stories/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* External dependencies
*/
import type { ComponentMeta, ComponentStory } from '@storybook/react';

/**
* Internal dependencies
*/
import InputControl from '..';

const meta: ComponentMeta< typeof InputControl > = {
title: 'Components (Experimental)/InputControl',
component: InputControl,
argTypes: {
__unstableInputWidth: { control: { type: 'text' } },
__unstableStateReducer: { control: { type: null } },
onChange: { control: { type: null } },
prefix: { control: { type: null } },
suffix: { control: { type: null } },
type: { control: { type: 'text' } },
},
parameters: {
controls: { expanded: true },
docs: { source: { state: 'open' } },
},
};
export default meta;

const Template: ComponentStory< typeof InputControl > = ( args ) => (
<InputControl { ...args } />
);

export const Default = Template.bind( {} );
Default.args = {
label: 'Value',
placeholder: 'Placeholder',
value: '',
};

export const WithPrefix = Template.bind( {} );
WithPrefix.args = {
...Default.args,
prefix: <span style={ { paddingLeft: 8 } }>@</span>,
};

export const WithSuffix = Template.bind( {} );
WithSuffix.args = {
...Default.args,
suffix: <button style={ { marginRight: 4 } }>Send</button>,
};

export const WithSideLabel = Template.bind( {} );
WithSideLabel.args = {
...Default.args,
labelPosition: 'side',
};

export const WithEdgeLabel = Template.bind( {} );
WithEdgeLabel.args = {
...Default.args,
__unstableInputWidth: '20em',
labelPosition: 'edge',
};
75 changes: 73 additions & 2 deletions packages/components/src/input-control/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ import type {
ChangeEvent,
SyntheticEvent,
PointerEvent,
HTMLInputTypeAttribute,
} from 'react';
import type { useDrag } from '@use-gesture/react';

/**
* Internal dependencies
*/
import type { StateReducer } from './reducer/state';
import type { FlexProps } from '../flex/types';
import type { WordPressComponentProps } from '../ui/context';
import type { FlexProps } from '../flex/types';

export type LabelPosition = 'top' | 'bottom' | 'side' | 'edge';

Expand All @@ -27,9 +28,31 @@ export type Size = 'default' | 'small' | '__unstable-large';

interface BaseProps {
__unstableInputWidth?: CSSProperties[ 'width' ];
/**
* If true, the label will only be visible to screen readers.
*
* @default false
*/
hideLabelFromVision?: boolean;
/**
* Whether the component should be in a focused state.
* Used to coordinate focus states when the actual focused element and the component handling
* visual focus are separate.
*
* @default false
*/
isFocused: boolean;
/**
* The position of the label.
*
* @default 'top'
*/
labelPosition?: LabelPosition;
/**
* Adjusts the size of the input.
*
* @default 'default'
*/
size?: Size;
}

Expand All @@ -39,35 +62,83 @@ export type InputChangeCallback<
> = ( nextValue: string | undefined, extra: { event: E } & P ) => void;

export interface InputFieldProps extends BaseProps {
/**
* Determines the drag axis.
*
* @default 'n'
*/
dragDirection?: DragDirection;
/**
* If `isDragEnabled` is true, this controls the amount of `px` to have been dragged before
* the drag gesture is actually triggered.
*
* @default 10
*/
dragThreshold?: number;
/**
* If true, enables mouse drag gestures.
*
* @default false
*/
isDragEnabled?: boolean;
/**
* If true, the `ENTER` key press is required in order to trigger an `onChange`.
* If enabled, a change is also triggered when tabbing away (`onBlur`).
*
* @default false
*/
isPressEnterToChange?: boolean;
/**
* A function that receives the value of the input.
*/
onChange?: InputChangeCallback;
onValidate?: (
nextValue: string,
event?: SyntheticEvent< HTMLInputElement >
) => void;
setIsFocused: ( isFocused: boolean ) => void;
stateReducer?: StateReducer;
/**
* The current value of the input.
*/
value?: string;
onDragEnd?: ( dragProps: DragProps ) => void;
onDragStart?: ( dragProps: DragProps ) => void;
onDrag?: ( dragProps: DragProps ) => void;
/**
* Type of the input element to render.
*
* @default 'text'
*/
type?: HTMLInputTypeAttribute;
}

export interface InputBaseProps extends BaseProps, FlexProps {
children: ReactNode;
/**
* Renders an element on the left side of the input.
*/
prefix?: ReactNode;
/**
* Renders an element on the right side of the input.
*/
suffix?: ReactNode;
/**
* If true, the `input` will be disabled.
*
* @default false
*/
disabled?: boolean;
className?: string;
id?: string;
/**
* If this property is added, a label will be generated using label property as the content.
*/
label?: ReactNode;
}

export interface InputControlProps
extends Omit< InputBaseProps, 'children' | 'isFocused' >,
extends Omit< InputBaseProps, 'children' | 'isFocused' | keyof FlexProps >,
/**
* The `prefix` prop in `WordPressComponentProps< InputFieldProps, 'input', false >` comes from the
* `HTMLInputAttributes` and clashes with the one from `InputBaseProps`. So we have to omit it from
Expand Down

0 comments on commit b523364

Please sign in to comment.