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

Card: migrate to TypeScript #42941

Merged
merged 21 commits into from
Aug 23, 2022
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
2 changes: 2 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@
- `Modal`: use `KeyboardEvent.code` instead of deprecated `KeyboardEvent.keyCode`. improve unit tests ([#43429](https://github.com/WordPress/gutenberg/pull/43429/)).
- `FocalPointPicker`: use `KeyboardEvent.code`, partially refactor tests to modern RTL and `user-event` ([#43441](https://github.com/WordPress/gutenberg/pull/43441/)).
- `CustomGradientPicker`: use `KeyboardEvent.code` instead of `KeyboardEvent.keyCode` ([#43437](https://github.com/WordPress/gutenberg/pull/43437/)).
- `Card`: Convert to TypeScript ([#42941](https://github.com/WordPress/gutenberg/pull/42941)).
- `NavigableContainer`: Refactor away from `_.omit()` ([#43474](https://github.com/WordPress/gutenberg/pull/43474/)).
- `Notice`: Refactor away from `_.omit()` ([#43474](https://github.com/WordPress/gutenberg/pull/43474/)).
- `Snackbar`: Refactor away from `_.omit()` ([#43474](https://github.com/WordPress/gutenberg/pull/43474/)).
- `UnitControl`: Refactor away from `_.omit()` ([#43474](https://github.com/WordPress/gutenberg/pull/43474/)).
- `BottomSheet`: Refactor away from `_.omit()` ([#43474](https://github.com/WordPress/gutenberg/pull/43474/)).

### Experimental

- `FormTokenField`: add `__experimentalAutoSelectFirstMatch` prop to auto select the first matching suggestion on typing ([#42527](https://github.com/WordPress/gutenberg/pull/42527/)).

## 19.17.0 (2022-08-10)
Expand Down
20 changes: 10 additions & 10 deletions packages/components/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ function Example(

A couple of good examples of how hooks are used for composition are:

- the `Card` component, which builds on top of the `Surface` component by [calling the `useSurface` hook inside its own hook](/packages/components/src/card/card/hook.js);
- the `HStack` component, which builds on top of the `Flex` component and [calls the `useFlex` hook inside its own hook](/packages/components/src/h-stack/hook.js).
- the `Card` component, which builds on top of the `Surface` component by [calling the `useSurface` hook inside its own hook](/packages/components/src/card/card/hook.ts);
ciampo marked this conversation as resolved.
Show resolved Hide resolved
- the `HStack` component, which builds on top of the `Flex` component and [calls the `useFlex` hook inside its own hook](/packages/components/src/h-stack/hook.tsx).

<!-- ## API Consinstency

Expand Down Expand Up @@ -262,7 +262,7 @@ An example of how this is used can be found in the [`Card` component family](/pa

```jsx
//=========================================================================
// Simplified snippet from `packages/components/src/card/card/hook.js`
// Simplified snippet from `packages/components/src/card/card/hook.ts`
//=========================================================================
import { useContextSystem } from '../../ui/context';

Expand All @@ -276,7 +276,7 @@ export function useCard( props ) {
}

//=========================================================================
// Simplified snippet from `packages/components/src/card/card/component.js`
// Simplified snippet from `packages/components/src/card/card/component.ts`
ciampo marked this conversation as resolved.
Show resolved Hide resolved
//=========================================================================
import { contextConnect, ContextSystemProvider } from '../../ui/context';

Expand All @@ -301,7 +301,7 @@ function Card( props, forwardedRef ) {
}, [ isBorderless, size ] );

return (
{ /* Write additional values to the Context System */ }
/* Write additional values to the Context System */
<ContextSystemProvider value={ contextProviderValue }>
{ /* [...] */ }
</ContextSystemProvider>
Expand All @@ -313,7 +313,7 @@ const ConnectedCard = contextConnect( Card, 'Card' );
export default ConnectedCard;

//=========================================================================
// Simplified snippet from `packages/components/src/card/card-body/hook.js`
// Simplified snippet from `packages/components/src/card/card-body/hook.ts`
//=========================================================================
import { useContextSystem } from '../../ui/context';

Expand Down Expand Up @@ -364,7 +364,7 @@ Primary.args = {

A great tool to use when writing stories is the [Storybook Controls addon](https://storybook.js.org/addons/@storybook/addon-controls). Ideally props should be exposed by using this addon, which provides a graphical UI to interact dynamically with the component without needing to write code. Avoid using [Knobs](https://storybook.js.org/addons/@storybook/addon-knobs) for new stories, as this addon is deprecated.

The default value of each control should coincide with the default value of the props (i.e. it should be `undefined` if a prop is not required). A story should, therefore, also explicitly show how values from the Context System are applied to (sub)components. A good example of how this may look like is the [`Card` story](https://wordpress.github.io/gutenberg/?path=/story/components-card--default) (code [here](/packages/components/src/card/stories/index.js)).
The default value of each control should coincide with the default value of the props (i.e. it should be `undefined` if a prop is not required). A story should, therefore, also explicitly show how values from the Context System are applied to (sub)components. A good example of how this may look like is the [`Card` story](https://wordpress.github.io/gutenberg/?path=/story/components-card--default) (code [here](/packages/components/src/card/stories/index.tsx)).

Storybook can be started on a local machine by running `npm run storybook:dev`. Alternatively, the components' catalogue (up to date with the latest code on `trunk`) can be found at [wordpress.github.io/gutenberg/](https://wordpress.github.io/gutenberg/).

Expand Down Expand Up @@ -516,7 +516,7 @@ Given a component folder (e.g. `packages/components/src/unit-control`):
5. Extend existing components’ props if possible, especially when a component internally forwards its props to another component in the package.
6. If the component forwards its `...restProps` to an underlying element/component, you should use the `WordPressComponentProps` type for the component's props:

```jsx
```tsx
import type { WordPressComponentProps } from '../ui/context';
import type { ComponentOwnProps } from './types';

Expand All @@ -533,7 +533,7 @@ Given a component folder (e.g. `packages/components/src/unit-control`):

7. If the component doesn't forwards its ref yet, wrap the component in a `forwardRed` call. Alternatively, if you want to take advantage of the [Context system](#context-system), you can use the `contextConnect` utility function (which also takes care of adding ref forwarding)

```jsx
```tsx
// With `forwardRef`
import type { ForwardedRef } from 'react';
import { forwardRef } from '@wordpress/element';
Expand All @@ -554,7 +554,7 @@ Given a component folder (e.g. `packages/components/src/unit-control`):
export default MyComponent;
```

```jsx
```tsx
// With `contextConnect`
import type { ForwardedRef } from 'react';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
/**
* External dependencies
*/
import type { ForwardedRef } from 'react';

/**
* Internal dependencies
*/
import { contextConnect } from '../../ui/context';
import { contextConnect, WordPressComponentProps } from '../../ui/context';
import { Scrollable } from '../../scrollable';
import { View } from '../../view';
import { useCardBody } from './hook';
import type { BodyProps } from '../types';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../types').BodyProps, 'div'>} props
* @param {import('react').ForwardedRef<any>} forwardedRef
*/
function CardBody( props, forwardedRef ) {
function UnconnectedCardBody(
props: WordPressComponentProps< BodyProps, 'div' >,
forwardedRef: ForwardedRef< any >
) {
const { isScrollable, ...otherProps } = useCardBody( props );

if ( isScrollable ) {
Expand All @@ -24,7 +29,6 @@ function CardBody( props, forwardedRef ) {
* `CardBody` renders an optional content area for a `Card`.
* Multiple `CardBody` components can be used within `Card` if needed.
*
* @example
* ```jsx
* import { Card, CardBody } from `@wordpress/components`;
*
Expand All @@ -35,6 +39,6 @@ function CardBody( props, forwardedRef ) {
* </Card>
* ```
*/
const ConnectedCardBody = contextConnect( CardBody, 'CardBody' );
export const CardBody = contextConnect( UnconnectedCardBody, 'CardBody' );

export default ConnectedCardBody;
export default CardBody;
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useContextSystem } from '../../ui/context';
import { useContextSystem, WordPressComponentProps } from '../../ui/context';
import * as styles from '../styles';
import { useCx } from '../../utils/hooks/use-cx';
import type { BodyProps } from '../types';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../types').BodyProps, 'div'>} props
*/
export function useCardBody( props ) {
export function useCardBody(
props: WordPressComponentProps< BodyProps, 'div' >
) {
const {
className,
isScrollable = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
/**
* Internal dependencies
* External dependencies
*/
import { contextConnect } from '../../ui/context';
import { Divider } from '../../divider';
import { useCardDivider } from './hook';
import type { ForwardedRef } from 'react';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../../divider').DividerProps, 'hr', false>} props
* @param {import('react').ForwardedRef<any>} forwardedRef
* Internal dependencies
*/
function CardDivider( props, forwardedRef ) {
import { contextConnect, WordPressComponentProps } from '../../ui/context';
import { Divider, DividerProps } from '../../divider';
import { useCardDivider } from './hook';

function UnconnectedCardDivider(
props: WordPressComponentProps< DividerProps, 'hr', false >,
forwardedRef: ForwardedRef< any >
) {
const dividerProps = useCardDivider( props );

return <Divider { ...dividerProps } ref={ forwardedRef } />;
Expand All @@ -19,7 +23,6 @@ function CardDivider( props, forwardedRef ) {
* `CardDivider` renders an optional divider within a `Card`.
* It is typically used to divide multiple `CardBody` components from each other.
*
* @example
* ```jsx
* import { Card, CardBody, CardDivider } from `@wordpress/components`;
*
Expand All @@ -30,6 +33,9 @@ function CardDivider( props, forwardedRef ) {
* </Card>
* ```
*/
const ConnectedCardDivider = contextConnect( CardDivider, 'CardDivider' );
export const CardDivider = contextConnect(
UnconnectedCardDivider,
'CardDivider'
);

export default ConnectedCardDivider;
export default CardDivider;
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useContextSystem } from '../../ui/context';
import { useContextSystem, WordPressComponentProps } from '../../ui/context';
import * as styles from '../styles';
import { useCx } from '../../utils/hooks/use-cx';
import type { DividerProps } from '../../divider';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../../divider').DividerProps, 'hr', false>} props
*/
export function useCardDivider( props ) {
export function useCardDivider(
props: WordPressComponentProps< DividerProps, 'hr', false >
) {
const { className, ...otherProps } = useContextSystem(
props,
'CardDivider'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
/**
* External dependencies
*/
import type { ForwardedRef } from 'react';

/**
* Internal dependencies
*/
import { contextConnect } from '../../ui/context';
import { contextConnect, WordPressComponentProps } from '../../ui/context';
import { Flex } from '../../flex';
import { useCardFooter } from './hook';
import type { FooterProps } from '../types';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../types').FooterProps, 'div'>} props
* @param {import('react').ForwardedRef<any>} forwardedRef
*/
function CardFooter( props, forwardedRef ) {
function UnconnectedCardFooter(
props: WordPressComponentProps< FooterProps, 'div' >,
forwardedRef: ForwardedRef< any >
) {
const footerProps = useCardFooter( props );

return <Flex { ...footerProps } ref={ forwardedRef } />;
Expand All @@ -18,7 +23,6 @@ function CardFooter( props, forwardedRef ) {
/**
* `CardFooter` renders an optional footer within a `Card`.
*
* @example
* ```jsx
* import { Card, CardBody, CardFooter } from `@wordpress/components`;
*
Expand All @@ -28,6 +32,6 @@ function CardFooter( props, forwardedRef ) {
* </Card>
* ```
*/
const ConnectedCardFooter = contextConnect( CardFooter, 'CardFooter' );
export const CardFooter = contextConnect( UnconnectedCardFooter, 'CardFooter' );

export default ConnectedCardFooter;
export default CardFooter;
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useContextSystem } from '../../ui/context';
import { useContextSystem, WordPressComponentProps } from '../../ui/context';
import * as styles from '../styles';
import { useCx } from '../../utils/hooks/use-cx';
import type { FooterProps } from '../types';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../types').FooterProps, 'div'>} props
*/
export function useCardFooter( props ) {
export function useCardFooter(
props: WordPressComponentProps< FooterProps, 'div' >
) {
const {
className,
justify,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
/**
* External dependencies
*/
import type { ForwardedRef } from 'react';

/**
* Internal dependencies
*/
import { contextConnect } from '../../ui/context';
import { contextConnect, WordPressComponentProps } from '../../ui/context';
import { Flex } from '../../flex';
import { useCardHeader } from './hook';
import type { HeaderProps } from '../types';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../types').HeaderProps, 'div'>} props
* @param {import('react').ForwardedRef<any>} forwardedRef
*/
function CardHeader( props, forwardedRef ) {
function UnconnectedCardHeader(
props: WordPressComponentProps< HeaderProps, 'div' >,
forwardedRef: ForwardedRef< any >
) {
const headerProps = useCardHeader( props );

return <Flex { ...headerProps } ref={ forwardedRef } />;
Expand All @@ -18,7 +23,6 @@ function CardHeader( props, forwardedRef ) {
/**
* `CardHeader` renders an optional header within a `Card`.
*
* @example
* ```jsx
* import { Card, CardBody, CardHeader } from `@wordpress/components`;
*
Expand All @@ -28,6 +32,6 @@ function CardHeader( props, forwardedRef ) {
* </Card>
* ```
*/
const ConnectedCardHeader = contextConnect( CardHeader, 'CardHeader' );
export const CardHeader = contextConnect( UnconnectedCardHeader, 'CardHeader' );

export default ConnectedCardHeader;
export default CardHeader;
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useContextSystem } from '../../ui/context';
import { useContextSystem, WordPressComponentProps } from '../../ui/context';
import * as styles from '../styles';
import { useCx } from '../../utils/hooks/use-cx';
import type { HeaderProps } from '../types';

/**
* @param {import('../../ui/context').WordPressComponentProps<import('../types').HeaderProps, 'div'>} props
*/
export function useCardHeader( props ) {
export function useCardHeader(
props: WordPressComponentProps< HeaderProps, 'div' >
) {
const {
className,
isBorderless = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
/**
* External dependencies
*/
import type { ForwardedRef } from 'react';

/**
* Internal dependencies
*/
import { contextConnect } from '../../ui/context';
import { contextConnect, WordPressComponentProps } from '../../ui/context';
import { View } from '../../view';
import { useCardMedia } from './hook';
import type { MediaProps } from '../types';

/**
* @param {import('../../ui/context').WordPressComponentProps<{ children: import('react').ReactNode }, 'div'>} props
* @param {import('react').ForwardedRef<any>} forwardedRef
*/
function CardMedia( props, forwardedRef ) {
function UnconnectedCardMedia(
props: WordPressComponentProps< MediaProps, 'div' >,
forwardedRef: ForwardedRef< any >
) {
const cardMediaProps = useCardMedia( props );

return <View { ...cardMediaProps } ref={ forwardedRef } />;
Expand All @@ -32,6 +37,6 @@ function CardMedia( props, forwardedRef ) {
* );
* ```
*/
const ConnectedCardMedia = contextConnect( CardMedia, 'CardMedia' );
export const CardMedia = contextConnect( UnconnectedCardMedia, 'CardMedia' );

export default ConnectedCardMedia;
export default CardMedia;
Loading