From 890237fac116a6a04bf250b9d6fb602c9c305ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Wed, 27 Apr 2022 00:33:14 +0200 Subject: [PATCH 1/6] TextControl: Covert component to TypeScript --- packages/components/src/text-control/index.js | 72 ---------------- .../components/src/text-control/index.tsx | 83 +++++++++++++++++++ .../src/text-control/stories/index.js | 46 ---------- .../src/text-control/stories/index.tsx | 61 ++++++++++++++ packages/components/src/text-control/types.ts | 34 ++++++++ packages/components/tsconfig.json | 3 +- 6 files changed, 180 insertions(+), 119 deletions(-) delete mode 100644 packages/components/src/text-control/index.js create mode 100644 packages/components/src/text-control/index.tsx delete mode 100644 packages/components/src/text-control/stories/index.js create mode 100644 packages/components/src/text-control/stories/index.tsx create mode 100644 packages/components/src/text-control/types.ts diff --git a/packages/components/src/text-control/index.js b/packages/components/src/text-control/index.js deleted file mode 100644 index b0b9f806f18fe6..00000000000000 --- a/packages/components/src/text-control/index.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * WordPress dependencies - */ -import { useInstanceId } from '@wordpress/compose'; -import { forwardRef } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import BaseControl from '../base-control'; - -/** - * @typedef OwnProps - * @property {string} label Label for the control. - * @property {boolean} [hideLabelFromVision] Whether to accessibly hide the label. - * @property {string} value Value of the input. - * @property {string} [help] Optional help text for the control. - * @property {string} [className] Classname passed to BaseControl wrapper - * @property {(value: string) => void} onChange Handle changes. - * @property {string} [type='text'] Type of the input. - */ - -/** @typedef {OwnProps & import('react').ComponentProps<'input'>} Props */ - -/** - * - * @param {Props} props Props - * @param {import('react').ForwardedRef} ref - */ -function TextControl( - { - label, - hideLabelFromVision, - value, - help, - className, - onChange, - type = 'text', - ...props - }, - ref -) { - const instanceId = useInstanceId( TextControl ); - const id = `inspector-text-control-${ instanceId }`; - const onChangeValue = ( - /** @type {import('react').ChangeEvent} */ - event - ) => onChange( event.target.value ); - - return ( - - - - ); -} - -export default forwardRef( TextControl ); diff --git a/packages/components/src/text-control/index.tsx b/packages/components/src/text-control/index.tsx new file mode 100644 index 00000000000000..7758f8b23f5289 --- /dev/null +++ b/packages/components/src/text-control/index.tsx @@ -0,0 +1,83 @@ +/** + * External dependencies + */ +import type { ChangeEvent, ForwardedRef } from 'react'; + +/** + * WordPress dependencies + */ +import { useInstanceId } from '@wordpress/compose'; +import { forwardRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import BaseControl from '../base-control'; +import type { TextControlProps } from './types'; + +export function UnforwardedTextControl( + props: TextControlProps, + ref: ForwardedRef< HTMLInputElement > +) { + const { + label, + hideLabelFromVision, + value, + help, + className, + onChange, + type = 'text', + ...additionalProps + } = props; + const instanceId = useInstanceId( TextControl ); + const id = `inspector-text-control-${ instanceId }`; + const onChangeValue = ( event: ChangeEvent< HTMLInputElement > ) => + onChange( event.target.value ); + + return ( + + + + ); +} + +/** + * TextControl components let users enter and edit text. + * + * + * @example + * ```jsx + * import { TextControl } from '@wordpress/components'; + * import { useState } from '@wordpress/element'; + * + * const MyTextControl = () => { + * const [ className, setClassName ] = useState( '' ); + * + * return ( + * setClassName( value ) } + * /> + * ); + * }; + * ``` + */ +export const TextControl = forwardRef( UnforwardedTextControl ); + +export default TextControl; diff --git a/packages/components/src/text-control/stories/index.js b/packages/components/src/text-control/stories/index.js deleted file mode 100644 index e381fd36be57a7..00000000000000 --- a/packages/components/src/text-control/stories/index.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * External dependencies - */ -import { boolean, text } from '@storybook/addon-knobs'; - -/** - * WordPress dependencies - */ -import { useState } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import TextControl from '../'; - -export default { - title: 'Components/TextControl', - component: TextControl, - parameters: { - knobs: { disable: false }, - }, -}; - -const TextControlWithState = ( props ) => { - const [ value, setValue ] = useState(); - - return ; -}; - -export const _default = () => { - const label = text( 'Label', 'Label Text' ); - const hideLabelFromVision = boolean( 'Hide Label From Vision', false ); - const help = text( 'Help Text', 'Help text to explain the input.' ); - const type = text( 'Input Type', 'text' ); - const className = text( 'Class Name', '' ); - - return ( - - ); -}; diff --git a/packages/components/src/text-control/stories/index.tsx b/packages/components/src/text-control/stories/index.tsx new file mode 100644 index 00000000000000..1a1a819eaa68b2 --- /dev/null +++ b/packages/components/src/text-control/stories/index.tsx @@ -0,0 +1,61 @@ +/** + * External dependencies + */ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import TextControl from '..'; + +const meta: ComponentMeta< typeof TextControl > = { + component: TextControl, + title: 'Components/TextControl', + argTypes: { + onChange: { + action: 'onChange', + control: { type: null }, + }, + value: { + control: { type: null }, + }, + }, + parameters: { + controls: { + expanded: true, + }, + docs: { source: { state: 'open' } }, + }, +}; +export default meta; + +const DefaultTemplate: ComponentStory< typeof TextControl > = ( { + ...args +} ) => { + const [ value, setValue ] = useState( '' ); + + return ( + { + setValue( v ); + } } + /> + ); +}; + +export const Default: ComponentStory< + typeof TextControl +> = DefaultTemplate.bind( {} ); +Default.args = { + label: 'Label Text', + hideLabelFromVision: false, + help: 'Help text to explain the input.', + type: 'text', +}; diff --git a/packages/components/src/text-control/types.ts b/packages/components/src/text-control/types.ts new file mode 100644 index 00000000000000..71f6d822c4f2b7 --- /dev/null +++ b/packages/components/src/text-control/types.ts @@ -0,0 +1,34 @@ +/** + * External dependencies + */ +import type { HTMLInputTypeAttribute } from 'react'; + +/** + * Internal dependencies + */ +import type { BaseControlProps } from '../base-control/types'; +import type { WordPressComponentProps } from '../ui/context'; + +export type TextControlProps = WordPressComponentProps< + Pick< + BaseControlProps, + 'className' | 'hideLabelFromVision' | 'help' | 'label' + > & { + /** + * A function that receives the value of the input. + */ + onChange: ( value: string ) => void; + /** + * The current value of the input. + */ + value: string | number; + /** + * Type of the input element to render. Defaults to "text". + * + * @default text + */ + type?: HTMLInputTypeAttribute; + }, + 'input', + false +>; diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 8f8b6c412715d0..8ed3f765309818 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -8,7 +8,7 @@ "gutenberg-test-env", "jest", "@testing-library/jest-dom", - "snapshot-diff", + "snapshot-diff" ], // Some errors in Reakit types with TypeScript 4.3 // Remove the following line when they've been addressed. @@ -77,6 +77,7 @@ "src/spinner/**/*", "src/surface/**/*", "src/text/**/*", + "src/text-control/**/*", "src/tip/**/*", "src/toggle-group-control/**/*", "src/tools-panel/**/*", From ef3a12e808d57229ee15b0ecb8d44f0b228dcafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Wed, 27 Apr 2022 00:44:49 +0200 Subject: [PATCH 2/6] Don't export unforwarded component --- packages/components/src/text-control/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/text-control/index.tsx b/packages/components/src/text-control/index.tsx index 7758f8b23f5289..1ff2325f087818 100644 --- a/packages/components/src/text-control/index.tsx +++ b/packages/components/src/text-control/index.tsx @@ -15,7 +15,7 @@ import { forwardRef } from '@wordpress/element'; import BaseControl from '../base-control'; import type { TextControlProps } from './types'; -export function UnforwardedTextControl( +function UnforwardedTextControl( props: TextControlProps, ref: ForwardedRef< HTMLInputElement > ) { From fd4032cc0f65606f7f4810b67f1af91a1b92fbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Thu, 28 Apr 2022 16:14:08 +0200 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: Marco Ciampini --- packages/components/src/text-control/stories/index.tsx | 10 +++++++--- packages/components/src/text-control/types.ts | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/components/src/text-control/stories/index.tsx b/packages/components/src/text-control/stories/index.tsx index 1a1a819eaa68b2..24313c5c6ad152 100644 --- a/packages/components/src/text-control/stories/index.tsx +++ b/packages/components/src/text-control/stories/index.tsx @@ -53,9 +53,13 @@ const DefaultTemplate: ComponentStory< typeof TextControl > = ( { export const Default: ComponentStory< typeof TextControl > = DefaultTemplate.bind( {} ); -Default.args = { +Default.args = {}; + +export const WithLabelAndHelpText: ComponentStory< + typeof TextControl +> = DefaultTemplate.bind( {} ); +WithLabelAndHelpText.args = { + ...Default.args, label: 'Label Text', - hideLabelFromVision: false, help: 'Help text to explain the input.', - type: 'text', }; diff --git a/packages/components/src/text-control/types.ts b/packages/components/src/text-control/types.ts index 71f6d822c4f2b7..6748c00b80d27b 100644 --- a/packages/components/src/text-control/types.ts +++ b/packages/components/src/text-control/types.ts @@ -25,7 +25,7 @@ export type TextControlProps = WordPressComponentProps< /** * Type of the input element to render. Defaults to "text". * - * @default text + * @default 'text' */ type?: HTMLInputTypeAttribute; }, From e5fe71c2dea4946527b64ecd856b50f0cd7eef55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Thu, 28 Apr 2022 16:22:23 +0200 Subject: [PATCH 4/6] Move WordPressComponentProps to the component --- .../components/src/text-control/index.tsx | 3 +- packages/components/src/text-control/types.ts | 43 ++++++++----------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/packages/components/src/text-control/index.tsx b/packages/components/src/text-control/index.tsx index 1ff2325f087818..7634e751d19ecb 100644 --- a/packages/components/src/text-control/index.tsx +++ b/packages/components/src/text-control/index.tsx @@ -13,10 +13,11 @@ import { forwardRef } from '@wordpress/element'; * Internal dependencies */ import BaseControl from '../base-control'; +import type { WordPressComponentProps } from '../ui/context'; import type { TextControlProps } from './types'; function UnforwardedTextControl( - props: TextControlProps, + props: WordPressComponentProps< TextControlProps, 'input', false >, ref: ForwardedRef< HTMLInputElement > ) { const { diff --git a/packages/components/src/text-control/types.ts b/packages/components/src/text-control/types.ts index 6748c00b80d27b..669751154c3605 100644 --- a/packages/components/src/text-control/types.ts +++ b/packages/components/src/text-control/types.ts @@ -7,28 +7,23 @@ import type { HTMLInputTypeAttribute } from 'react'; * Internal dependencies */ import type { BaseControlProps } from '../base-control/types'; -import type { WordPressComponentProps } from '../ui/context'; -export type TextControlProps = WordPressComponentProps< - Pick< - BaseControlProps, - 'className' | 'hideLabelFromVision' | 'help' | 'label' - > & { - /** - * A function that receives the value of the input. - */ - onChange: ( value: string ) => void; - /** - * The current value of the input. - */ - value: string | number; - /** - * Type of the input element to render. Defaults to "text". - * - * @default 'text' - */ - type?: HTMLInputTypeAttribute; - }, - 'input', - false ->; +export type TextControlProps = Pick< + BaseControlProps, + 'className' | 'hideLabelFromVision' | 'help' | 'label' +> & { + /** + * A function that receives the value of the input. + */ + onChange: ( value: string ) => void; + /** + * The current value of the input. + */ + value: string | number; + /** + * Type of the input element to render. Defaults to "text". + * + * @default 'text' + */ + type?: HTMLInputTypeAttribute; +}; From 166745881d8b78bef0c7a1d55fbe3c9ef9b02d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Thu, 28 Apr 2022 16:59:04 +0200 Subject: [PATCH 5/6] Update CHANGELOG.md --- packages/components/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 2d132c096efc8c..c6c764d31dbae4 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -7,6 +7,10 @@ - `InputControl`: Add `__next36pxDefaultSize` flag for larger default size ([#40622](https://github.com/WordPress/gutenberg/pull/40622)). - `UnitControl`: Add `__next36pxDefaultSize` flag for larger default size ([#40627](https://github.com/WordPress/gutenberg/pull/40627)). +### Internal + +- `TextControl`: Convert to TypeScript ([#40633](https://github.com/WordPress/gutenberg/pull/40633)). + ## 19.9.0 (2022-04-21) ### Bug Fix From e30a8ddf2e7abf6548bf3b71d0d4df7ddf66f280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petter=20Walb=C3=B8=20Johnsg=C3=A5rd?= Date: Thu, 28 Apr 2022 20:42:00 +0200 Subject: [PATCH 6/6] Update storybook - Remove control on onChange. Storybook hides on* by default. - Add onChange to trigger action --- packages/components/src/text-control/stories/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/src/text-control/stories/index.tsx b/packages/components/src/text-control/stories/index.tsx index 24313c5c6ad152..4ff047eca45586 100644 --- a/packages/components/src/text-control/stories/index.tsx +++ b/packages/components/src/text-control/stories/index.tsx @@ -19,7 +19,6 @@ const meta: ComponentMeta< typeof TextControl > = { argTypes: { onChange: { action: 'onChange', - control: { type: null }, }, value: { control: { type: null }, @@ -35,6 +34,7 @@ const meta: ComponentMeta< typeof TextControl > = { export default meta; const DefaultTemplate: ComponentStory< typeof TextControl > = ( { + onChange, ...args } ) => { const [ value, setValue ] = useState( '' ); @@ -45,6 +45,7 @@ const DefaultTemplate: ComponentStory< typeof TextControl > = ( { value={ value } onChange={ ( v ) => { setValue( v ); + onChange( v ); } } /> );