Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine react-final-form input typings to be optional #41

Merged
merged 2 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ This is a set of TypeScript typings for the [Stripes](https://github.com/folio-o

`react-final-form` support is currently experimental. Stripes has form fields which can optionally be controlled via react-final-form or left uncontrolled. However, in RFF, [FieldRenderProps](https://github.com/final-form/react-final-form/blob/09ccc607b3e8843addd7cbde7a84a82866587000/typescript/index.d.ts#L43-L50) are defined problematically:

- `input` and `meta` are **required**, whereas Stripes should have them be optional, meaning we cannot require them;
- `input` and `meta` are **required**, whereas Stripes should have them be optional (for non-RFF use), meaning we cannot require them;
- the `<Field>` definition requires the `component` to require `input` and `meta`, meaning we cannot leave them optional; and
- the props also allow any other prop to be passed through and overwrites their types as `any`, erasing any specific component typings.

With this current situation, there's not too much we can do to make everyone happy. Therefore, this aspect of the typings is experimental and may change in the future.
With this current situation, there's not too much we can do to make everyone happy. Therefore, **this aspect of the typings is experimental and may change in the future**.

Currently, the recommended way to use Stripes components in react-final-form without sacrificing typings is via the render prop or as a child:

```tsx
```jsx
ncovercash marked this conversation as resolved.
Show resolved Hide resolved
import { Field } from 'react-final-form';
import { TextField } from '@folio/stripes/components';

Expand All @@ -30,7 +30,6 @@ import { TextField } from '@folio/stripes/components';
name="foo"
render={({ input, meta }) => (
<TextField
// pass RFF props only; with the `[otherProp: string]: any;` in `FieldRenderProps`, doing a spread suppresses any warnings for missing props
input={input}
meta={meta}
// other TextField specific props
Expand All @@ -44,7 +43,6 @@ import { TextField } from '@folio/stripes/components';
<Field name="foo">
{({ input, meta }) => (
<TextField
// pass RFF props only; with the `[otherProp: string]: any;` in `FieldRenderProps`, doing a spread suppresses any warnings for missing props
input={input}
meta={meta}
// other TextField specific props
Expand Down
12 changes: 4 additions & 8 deletions components/lib/Checkbox/Checkbox.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import {
RefObject,
} from 'react';

export interface CheckboxProps
extends AriaAttributes,
InputHTMLAttributes<HTMLInputElement> {
export interface CheckboxProps extends AriaAttributes, InputHTMLAttributes<HTMLInputElement> {
/** If the field should automatically focus on mount */
autoFocus?: boolean;
/** If the checkbox is checked */
Expand All @@ -34,9 +32,7 @@ export interface CheckboxProps
/** Add a class to the inner input */
innerClass?: string;
/** Reference to the inner input */
inputRef?:
| RefObject<HTMLInputElement>
| ((node: HTMLInputElement | null) => void);
inputRef?: RefObject<HTMLInputElement> | ((node: HTMLInputElement | null) => void);
/** The checkbox's label */
label?: string;
/** Add a class to the label */
Expand All @@ -61,8 +57,8 @@ export interface CheckboxProps
warning?: string | ReactNode;

// TODO: reference react-final-form FieldRenderProps<boolean | string[]>
input: any;
meta: any;
input?: any;
meta?: any;
}

/**
Expand Down
12 changes: 3 additions & 9 deletions components/lib/Datepicker/Datepicker.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { Moment } from 'moment';
import Popper from 'popper.js';
import {
AriaAttributes,
Component,
FocusEventHandler,
ReactNode,
RefObject,
} from 'react';
import { AriaAttributes, Component, FocusEventHandler, ReactNode, RefObject } from 'react';
import { Merge } from 'type-fest';
import { TextFieldProps } from '../TextField';

Expand Down Expand Up @@ -72,8 +66,8 @@ export interface DatepickerProps extends AriaAttributes {
outputFormatter?: (date: Moment) => string;

// TODO: reference react-final-form FieldRenderProps<string>
input: any;
meta: any;
input?: any;
meta?: any;
}

/**
Expand Down
30 changes: 10 additions & 20 deletions components/lib/MultiSelection/MultiSelection.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ export interface MultiSelectionDefaultOptionType<ValueType = never> {
* Props each action may accept
* @see https://github.com/folio-org/stripes-components/tree/master/lib/MultiSelection#actions
*/
export interface MultiSelectionActionItemProps<
OptionType = MultiSelectionDefaultOptionType
> {
export interface MultiSelectionActionItemProps<OptionType = MultiSelectionDefaultOptionType> {
/** The search term */
filterValue: string;
/** If this search was an exact match */
Expand All @@ -24,9 +22,7 @@ export interface MultiSelectionActionItemProps<
renderedItems: ReadonlyArray<OptionType>;
}

export interface MultiSelectionProps<
OptionType = MultiSelectionDefaultOptionType
> {
export interface MultiSelectionProps<OptionType = MultiSelectionDefaultOptionType> {
/**
* Custom actions, such as a "New" row
* @see https://github.com/folio-org/stripes-components/tree/master/lib/MultiSelection#actions
Expand Down Expand Up @@ -59,13 +55,10 @@ export interface MultiSelectionProps<
/** A custom filter function, either directly gives results or does something async */
filter?: (
filterText: string | undefined,
list: OptionType[]
list: OptionType[],
) => { renderedItems: OptionType[]; exactMatch?: boolean } | Promise<void>;
/** A custom formatter to render each option */
formatter?: (props: {
option: OptionType;
searchTerm: string | undefined;
}) => ReactNode;
formatter?: (props: { option: OptionType; searchTerm: string | undefined }) => ReactNode;
/** Adds a custom ID to the control */
id?: string;
/** If true, adds valid styles to the field */
Expand Down Expand Up @@ -95,16 +88,13 @@ export interface MultiSelectionProps<
/** The selected objects */
value?: OptionType[];
/** Same as {@link formatter}, `formatter` should probably be used instead. */
valueFormatter?: (
option: OptionType,
searchTerm: string | undefined
) => ReactNode;
valueFormatter?: (option: OptionType, searchTerm: string | undefined) => ReactNode;
/** Inline feedback for the user indicating a validation warning */
warning?: ReactNode;

// TODO: reference react-final-form FieldRenderProps<OptionType[]>
input: any;
meta: any;
input?: any;
meta?: any;
}

/**
Expand All @@ -127,6 +117,6 @@ export interface MultiSelectionProps<
* dataOptions={optionList}
* />
*/
export default class MultiSelection<
OptionType = MultiSelectionDefaultOptionType
> extends Component<MultiSelectionProps<OptionType>> {}
export default class MultiSelection<OptionType = MultiSelectionDefaultOptionType> extends Component<
MultiSelectionProps<OptionType>
> {}
8 changes: 3 additions & 5 deletions components/lib/RadioButton/RadioButton.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import {
InputHTMLAttributes,
} from 'react';

export interface RadioButtonProps
extends AriaAttributes,
InputHTMLAttributes<HTMLInputElement> {
export interface RadioButtonProps extends AriaAttributes, InputHTMLAttributes<HTMLInputElement> {
/** If the field should automatically focus on mount */
autoFocus?: boolean;
/** If the radio button is centered */
Expand Down Expand Up @@ -54,8 +52,8 @@ export interface RadioButtonProps
warning?: string;

// TODO: reference react-final-form FieldRenderProps<boolean | string[]>
input: any;
meta: any;
input?: any;
meta?: any;
}

/**
Expand Down
8 changes: 3 additions & 5 deletions components/lib/Select/Select.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export interface SelectBaseProps<ValueType> {
warning?: ReactNode;

// TODO: reference react-final-form FieldRenderProps<OptionType[]>
input: any;
meta: any;
input?: any;
meta?: any;
}

export type SelectProps<ValueType> = RequireExactlyOne<
Expand Down Expand Up @@ -91,6 +91,4 @@ export type SelectProps<ValueType> = RequireExactlyOne<
* ]}
* />
*/
export default class Select<ValueType = never> extends Component<
SelectProps<ValueType>
> {}
export default class Select<ValueType = never> extends Component<SelectProps<ValueType>> {}
10 changes: 5 additions & 5 deletions components/lib/TextField/TextField.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ export interface TextFieldProps<FieldType extends string | number = string>
warning?: ReactNode;

// TODO: reference react-final-form FieldRenderProps<string|number>
input: any;
meta: any;
input?: any;
meta?: any;
}

/**
Expand All @@ -112,6 +112,6 @@ export interface TextFieldProps<FieldType extends string | number = string>
* onChange={this.handleChange}
* />
*/
export default class TextField<
Type extends string | number = string
> extends Component<TextFieldProps<Type>> {}
export default class TextField<Type extends string | number = string> extends Component<
TextFieldProps<Type>
> {}
11 changes: 6 additions & 5 deletions components/lib/Timepicker/Timepicker.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import Popper from 'popper.js';
import { AriaAttributes, ComponentType, ReactNode, RefObject } from 'react';
import { FieldRenderProps } from 'react-final-form';
import { IntlShape } from 'react-intl';

export interface TimepickerProps
extends AriaAttributes,
FieldRenderProps<string> {
export interface TimepickerProps extends AriaAttributes {
/** If the field should auto-focus on mount */
autoFocus?: boolean;
/** Disables the input field */
Expand Down Expand Up @@ -36,7 +33,7 @@ export interface TimepickerProps
value: string | undefined,
timezone: string,
timeFormat: string,
intl: IntlShape
intl: IntlShape,
) => string;
/** Where the overlay should be placed in relation to the field */
placement?: Popper.Placement;
Expand All @@ -54,6 +51,10 @@ export interface TimepickerProps
usePortal?: boolean;
/** The field's value */
value?: string;

// TODO: reference react-final-form FieldRenderProps<string>
input?: any;
meta?: any;
}

/**
Expand Down
Loading