Skip to content

Commit

Permalink
BaseControl: Migrate to TypeScript (#39468)
Browse files Browse the repository at this point in the history
* BaseControl: Change file extensions to typescript

* Convert types

* Update stories

* Clarify `id` description

* Make ids in stories unique

* Remove mentions of hard-coded class names

* Add changelog entry

* Update snapshots

* Remove unnecessary comment for `children` prop

* Require `children` prop

This matches the readme and common-sense usage of this component

* Revert "Remove unnecessary comment for `children` prop"

This reverts commit 6e59dbe480f162683504cdb3c4fa691e6e43d0d6.

# Conflicts:
#	packages/components/src/base-control/types.ts

* Simplify className/children props

* Disable `children` control

* Simplify BaseControl type and rely more on inference

Without this, the docgen is confused and fails to mark `children` as required

* Fixup changelog entry position
  • Loading branch information
mirka committed Mar 23, 2022
1 parent 8deda3f commit c3a49ad
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 218 deletions.
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Internal

- `BaseControl`: Convert to TypeScript ([#39468](https://github.com/WordPress/gutenberg/pull/39468)).

## 19.7.0 (2022-03-23)

### Enhancements
Expand Down
22 changes: 11 additions & 11 deletions packages/components/src/base-control/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# BaseControl

BaseControl component is used to generate labels and help text for components handling user inputs.
`BaseControl` is a component used to generate labels and help text for components handling user inputs.

## Usage

Render a BaseControl for a textarea input:
Render a `BaseControl` for a textarea input:

```jsx
import { BaseControl } from '@wordpress/components';

// The `id` prop is necessary to accessibly associate the label with the textarea
const MyBaseControl = () => (
<BaseControl id="textarea-1" label="Text" help="Enter some text" __nextHasNoMarginBottom={ true }>
<textarea id="textarea-1" />
Expand All @@ -22,10 +23,10 @@ The component accepts the following props:

### id

The id of the element to which labels and help text are being generated. That element should be passed as a child.
The HTML `id` of the element (passed in as a child to `BaseControl`) to which labels and help text are being generated. This is necessary to accessibly associate the label with that element.

- Type: `String`
- Required: Yes
- Required: No

### label

Expand All @@ -50,8 +51,7 @@ If this property is added, a help text will be generated using help property as

### className

The class that will be added with "components-base-control" to the classes of the wrapper div.
If no className is passed only components-base-control is used.
Any other classes to add to the wrapper div.

- Type: `String`
- Required: No
Expand All @@ -73,16 +73,17 @@ Start opting into the new margin-free styles that will become the default in a f

## BaseControl.VisualLabel

`BaseControl.VisualLabel` component is used to render a purely visual label inside a `BaseControl` component.
It should only be used in cases where the children being rendered inside BaseControl are already properly labeled, e.g., a button, but we want an additional visual label for that section equivalent to the labels BaseControl would otherwise use if the label prop was passed.
`BaseControl.VisualLabel` is used to render a purely visual label inside a `BaseControl` component.

It should only be used in cases where the children being rendered inside BaseControl are already accessibly labeled, e.g., a button, but we want an additional visual label for that section equivalent to the labels `BaseControl` would otherwise use if the `label` prop was passed.

## Usage

```jsx
import { BaseControl } from '@wordpress/components';

const MyBaseControl = () => (
<BaseControl help="Pressing the Select an author button will open a modal that allows an advanced mechanism for author selection">
<BaseControl help="This button is already accessibly labeled.">
<BaseControl.VisualLabel>Author</BaseControl.VisualLabel>
<Button>Select an author</Button>
</BaseControl>
Expand All @@ -93,8 +94,7 @@ const MyBaseControl = () => (

#### className

The class that will be added with `components-base-control__label` to the classes of the wrapper div.
If no className is passed only `components-base-control__label` is used.
Any other classes to add to the wrapper div.

- Type: `String`
- Required: No
Expand Down
118 changes: 0 additions & 118 deletions packages/components/src/base-control/index.js

This file was deleted.

124 changes: 124 additions & 0 deletions packages/components/src/base-control/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import type { FunctionComponent } from 'react';

/**
* Internal dependencies
*/
import { VisuallyHidden } from '../visually-hidden';
import type { BaseControlProps, BaseControlVisualLabelProps } from './types';
import {
Wrapper,
StyledField,
StyledLabel,
StyledHelp,
StyledVisualLabel,
} from './styles/base-control-styles';

/**
* `BaseControl` is a component used to generate labels and help text for components handling user inputs.
*
* @example
* // Render a `BaseControl` for a textarea input
* import { BaseControl } from '@wordpress/components';
*
* // The `id` prop is necessary to accessibly associate the label with the textarea
* const MyBaseControl = () => (
* <BaseControl id="textarea-1" label="Text" help="Enter some text" __nextHasNoMarginBottom={ true }>
* <textarea id="textarea-1" />
* </BaseControl>
* );
*/
export const BaseControl = ( {
__nextHasNoMarginBottom = false,
id,
label,
hideLabelFromVision = false,
help,
className,
children,
}: BaseControlProps ) => {
return (
<Wrapper
className={ classnames( 'components-base-control', className ) }
>
<StyledField
className="components-base-control__field"
// TODO: Official deprecation for this should start after all internal usages have been migrated
__nextHasNoMarginBottom={ __nextHasNoMarginBottom }
>
{ label &&
id &&
( hideLabelFromVision ? (
<VisuallyHidden as="label" htmlFor={ id }>
{ label }
</VisuallyHidden>
) : (
<StyledLabel
className="components-base-control__label"
htmlFor={ id }
>
{ label }
</StyledLabel>
) ) }
{ label &&
! id &&
( hideLabelFromVision ? (
<VisuallyHidden as="label">{ label }</VisuallyHidden>
) : (
<BaseControl.VisualLabel>
{ label }
</BaseControl.VisualLabel>
) ) }
{ children }
</StyledField>
{ !! help && (
<StyledHelp
id={ id ? id + '__help' : undefined }
className="components-base-control__help"
__nextHasNoMarginBottom={ __nextHasNoMarginBottom }
>
{ help }
</StyledHelp>
) }
</Wrapper>
);
};

/**
* `BaseControl.VisualLabel` is used to render a purely visual label inside a `BaseControl` component.
*
* It should only be used in cases where the children being rendered inside `BaseControl` are already accessibly labeled,
* e.g., a button, but we want an additional visual label for that section equivalent to the labels `BaseControl` would
* otherwise use if the `label` prop was passed.
*
* @example
* import { BaseControl } from '@wordpress/components';
*
* const MyBaseControl = () => (
* <BaseControl help="This button is already accessibly labeled.">
* <BaseControl.VisualLabel>Author</BaseControl.VisualLabel>
* <Button>Select an author</Button>
* </BaseControl>
* );
*/
export const VisualLabel: FunctionComponent< BaseControlVisualLabelProps > = ( {
className,
children,
} ) => {
return (
<StyledVisualLabel
className={ classnames(
'components-base-control__label',
className
) }
>
{ children }
</StyledVisualLabel>
);
};
BaseControl.VisualLabel = VisualLabel;

export default BaseControl;
Loading

0 comments on commit c3a49ad

Please sign in to comment.