Skip to content

Commit

Permalink
refactor(collapsible panel): migrate to TS (#2008)
Browse files Browse the repository at this point in the history
* refactor(collapsible-panel): change filetypes to TS

* refactor(collapsible-panel): add some types (temp commit)

* refactor(collapsible-panel): fully migrate to TS, fix test

* refactor(collapsible-panel): add changeset

* refactor(collapsible-panel): generate readme

* refactor(collapsible-panel): format files

* refactor(collapsible-panel): implement refactor feedback

* refactor(collapsible-panel): implement extract defaultProps to a variable
  • Loading branch information
Rhotimee authored Oct 29, 2021
1 parent 721bab8 commit 537e696
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 198 deletions.
5 changes: 5 additions & 0 deletions .changeset/collapsible-motion-update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@commercetools-uikit/collapsible-motion': patch
---

Update types for props
5 changes: 5 additions & 0 deletions .changeset/witty-dolls-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@commercetools-uikit/collapsible-panel': patch
---

Migrate to Typescript
3 changes: 1 addition & 2 deletions packages/components/collapsible-motion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ export default Example;
### Signature `children`

```ts
({ isOpen, containerStyles, toggle, registerContentNode }: TRenderFunction) =>
ReactNode;
(options: TRenderFunctionOptions) => ReactNode;
```

### Signature `onToggle`
Expand Down
19 changes: 13 additions & 6 deletions packages/components/collapsible-motion/src/collapsible-motion.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { useRef, useEffect, useCallback, ReactNode } from 'react';
import {
useRef,
useEffect,
useCallback,
ReactNode,
CSSProperties,
LegacyRef,
} from 'react';
import { warning } from '@commercetools-uikit/utils';
import { keyframes, ClassNames } from '@emotion/react';

Expand All @@ -11,13 +18,13 @@ type TContainerStyles = {
visibility?: string;
name?: string;
animation?: string;
};
} & CSSProperties;

type TRenderFunctionOptions = {
isOpen: boolean;
containerStyles: TContainerStyles;
toggle: () => void;
registerContentNode: ReactNode;
registerContentNode: TNodeRefObject;
};

export type TCollapsibleMotionProps = {
Expand Down Expand Up @@ -74,7 +81,7 @@ const createClosingAnimation = (height: number, minHeight = 0) =>

type TNodeRefObject = {
clientHeight: number;
};
} & LegacyRef<HTMLDivElement>;

const useToggleAnimation = (
isOpen: boolean,
Expand Down Expand Up @@ -159,7 +166,7 @@ const ControlledCollapsibleMotion = (props: TCollapsibleMotionProps) => {
...animationStyle,
},
toggle: animationToggle as () => void,
registerContentNode,
registerContentNode: registerContentNode as TNodeRefObject,
});
}}
</ClassNames>
Expand Down Expand Up @@ -199,7 +206,7 @@ const UncontrolledCollapsibleMotion = (props: TCollapsibleMotionProps) => {
...animationStyle,
},
toggle: animationToggle as () => void,
registerContentNode,
registerContentNode: registerContentNode as TNodeRefObject,
});
}}
</ClassNames>
Expand Down
48 changes: 28 additions & 20 deletions packages/components/collapsible-panel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,34 @@ export default Example;

## Properties

| Props | Type | Required | Default | Description |
| ------------------------- | ----------------------------------------------------------------------------------------- | :------: | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `string` | | `uniqueId()` | An unique id for the panel header, which will also be used to generate a prefixed id for the panel content section.&#xA;<br/>&#xA;Read about `getPanelContentId` below for more about this. |
| `header` | `node` || | The title being rendered at top left of the panel |
| `secondaryHeader` | `node` | | | A secondary header for the panel (only pass if needed) |
| `description` | `string` | | | If passed will be shown below the title as more information regarding the panel |
| `className` | `string` | | | |
| `isSticky` | `bool` | | | Makes the panel's header sticky in regards to the page's scroll |
| `headerControls` | `node` | | | Controls at the top right part of the panel |
| `isDisabled` | `bool` | | `false` | Disables the panel and all interactions with it |
| `children` | `node` | | | The actual content rendered inside the panel |
| `tone` | `enum`<br/>Possible values:<br/>`'urgent', 'primary'` | | | |
| `theme` | `enum`<br/>Possible values:<br/>`'dark', 'light'` | | `'dark'` | The main color combination of the for the panel header and container |
| `condensed` | `bool` | | `false` | Whenever `true` the headers and content itself&#xA;will consume less space in that to the borders are smaller and everything has less padding |
| `hideExpansionControls` | `bool` | | | Controls the visibility of the expansion controls on the left |
| `headerControlsAlignment` | `enum`<br/>Possible values:<br/>`'left', 'right'` | | `'right'` | |
| `isDefaultClosed` | `custom` | | | Indicates if the panel's content should be collapsed or shown by default.&#xA;<br />&#xA;Updates to this value are not respected. Only used for **uncontrolled** mode (when no`onToggle` is passed.) |
| `isClosed` | `bool` | | | Indicates if the panel's content should be collapsed or shown.&#xA;<br />&#xA;Component becomes \*_controlled_ when this is passed. |
| `onToggle` | `custom` | | | function to be triggered whenever the user clicks the top area to collapse the panel's content&#xA;<br />&#xA;Becomes required when `isClosed` is passed.&#xA;<br />&#xA;Signature: `() => void` |
| `horizontalConstraint` | `enum`<br/>Possible values:<br/>`6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 'scale', 'auto'` | | `'scale'` | Horizontal size limit of the input fields. |
| Props | Type | Required | Default | Description |
| ------------------------- | -------------------------------------------------------------------------------------------- | :------: | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `string` | | `uniqueId()` | An unique id for the panel header, which will also be used to generate a prefixed id for the panel content section.&#xA;<br/>&#xA;Read about `getPanelContentId` below for more about this. |
| `header` | `ReactNode` || | The title being rendered at top left of the panel |
| `secondaryHeader` | `ReactNode` | | | A secondary header for the panel (only pass if needed) |
| `description` | `string` | | | If passed will be shown below the title as more information regarding the panel |
| `className` | `string` | | | |
| `isSticky` | `boolean` | | | Makes the panel's header sticky in regards to the page's scroll |
| `headerControls` | `ReactNode` | | | Controls at the top right part of the panel |
| `isDisabled` | `boolean` | | `false` | Disables the panel and all interactions with it |
| `children` | `ReactNode` | | | The actual content rendered inside the panel |
| `tone` | `union`<br/>Possible values:<br/>`'urgent' , 'primary'` | | | |
| `theme` | `union`<br/>Possible values:<br/>`'dark' , 'light'` | | `'dark'` | The main color combination of the for the panel header and container |
| `condensed` | `boolean` | | `false` | Whenever `true` the headers and content itself&#xA;will consume less space in that to the borders are smaller and everything has less padding |
| `hideExpansionControls` | `boolean` | | | Controls the visibility of the expansion controls on the left |
| `headerControlsAlignment` | `union`<br/>Possible values:<br/>`'left' , 'right'` | | `'right'` | |
| `isDefaultClosed` | `boolean` | | | Indicates if the panel's content should be collapsed or shown by default.&#xA;<br />&#xA;Updates to this value are not respected. Only used for **uncontrolled** mode (when no`onToggle` is passed.) |
| `isClosed` | `boolean` | | | Indicates if the panel's content should be collapsed or shown.&#xA;<br />&#xA;Component becomes \*_controlled_ when this is passed. |
| `onToggle` | `Function`<br/>[See signature.](#signature-onToggle) | | | function to be triggered whenever the user clicks the top area to collapse the panel's content&#xA;<br />&#xA;Becomes required when `isClosed` is passed.&#xA;<br />&#xA;Signature: `() => void` |
| `horizontalConstraint` | `union`<br/>Possible values:<br/>`, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 'scale', 'auto'` | | `'scale'` | Horizontal size limit of the input fields. |

## Signatures

### Signature `onToggle`

```ts
() => void
```

## Where to use

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import PropTypes from 'prop-types';
import { ReactNode } from 'react';
import Text from '@commercetools-uikit/text';

const CollapsiblePanelHeader = (props) => (
type TCollapsiblePanelHeader = {
children: ReactNode;
};
const CollapsiblePanelHeader = (props: TCollapsiblePanelHeader) => (
<Text.Subheadline as="h4" isBold={true} truncate={true}>
{props.children}
</Text.Subheadline>
);

CollapsiblePanelHeader.displayName = 'CollapsiblePanelHeader';
CollapsiblePanelHeader.propTypes = {
children: PropTypes.node.isRequired,
};

export default CollapsiblePanelHeader;
30 changes: 17 additions & 13 deletions packages/components/collapsible-panel/src/collapsible-panel.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import PropTypes from 'prop-types';
import { warning } from '@commercetools-uikit/utils';
import { screen, render } from '../../../../test/test-utils';
import CollapsiblePanel from './collapsible-panel';

Expand All @@ -10,6 +11,11 @@ HeaderControls.propTypes = {
onClick: PropTypes.func,
};

jest.mock('@commercetools-uikit/utils', () => ({
...jest.requireActual('@commercetools-uikit/utils'),
warning: jest.fn(),
}));

it('should smoke', () => {
render(<CollapsiblePanel header="Header">Children</CollapsiblePanel>);
expect(screen.getByText('Header')).toBeInTheDocument();
Expand Down Expand Up @@ -86,14 +92,12 @@ describe('when isDefaultClosed and isClosed are passed', () => {
Children
</CollapsiblePanel>
);
expect(console.error).toHaveBeenCalledWith(
expect.stringMatching(/Warning/),
'prop',
expect.stringMatching(/Invalid prop `isDefaultClosed` supplied to (.*)/),
expect.any(String)

expect(warning).toHaveBeenCalledWith(
expect.any(Boolean),
expect.stringMatching(/Invalid prop `isDefaultClosed` supplied to (.*)/i)
);
});
/* eslint-enable no-console */
});

describe('when onToggle is provided without isClosed', () => {
Expand All @@ -112,14 +116,11 @@ describe('when onToggle is provided without isClosed', () => {
Children
</CollapsiblePanel>
);
expect(console.error).toHaveBeenCalledWith(
expect.stringMatching(/Warning/),
'prop',
expect.stringMatching(/Invalid prop `onToggle` supplied to (.*)/),
expect.any(String)
expect(warning).toHaveBeenCalledWith(
expect.any(Boolean),
expect.stringMatching(/Invalid prop `onToggle` supplied to (.*)/i)
);
});
/* eslint-enable no-console */
});

it('should call "onToggle" when header is clicked', () => {
Expand Down Expand Up @@ -193,7 +194,10 @@ describe('aria attributes', () => {
};
};
it('should have a valid aria-controls correspondence', () => {
const { getPanelHeader, getPanelContent } = renderPanel({ id: 'test-id' });
const { getPanelHeader, getPanelContent } = renderPanel({
id: 'test-id',
isClosed: false,
});

const panelContentId = CollapsiblePanel.getPanelContentId('test-id');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { customProperties as vars } from '@commercetools-uikit/design-system';
import type { TCollapsiblePanel } from './collapsible-panel';

function getThemeStyle(theme) {
function getThemeStyle(theme?: TCollapsiblePanel['theme']) {
if (theme === 'light') {
return css`
background-color: ${vars.colorSurface};
Expand All @@ -13,7 +14,13 @@ function getThemeStyle(theme) {
`;
}

const getHeaderContainerStyles = (props, isOpen) => {
const getHeaderContainerStyles = (
props: Pick<
TCollapsiblePanel,
'headerControlsAlignment' | 'condensed' | 'isDisabled' | 'isSticky'
>,
isOpen: boolean
) => {
const baseStyles = css`
position: relative;
border-top-left-radius: ${vars.borderRadius6};
Expand Down
Loading

1 comment on commit 537e696

@vercel
Copy link

@vercel vercel bot commented on 537e696 Oct 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.