Skip to content

Commit

Permalink
Merge pull request #322 from Souptik2001/refactor/counter-component-t…
Browse files Browse the repository at this point in the history
…o-ts

Migrate `Counter` component to TS
  • Loading branch information
fabiankaegy authored May 14, 2024
2 parents 9c1511c + 90075ae commit 3612e21
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 45 deletions.
91 changes: 55 additions & 36 deletions components/counter/index.js → components/counter/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { forwardRef } from '@wordpress/element';
import PropTypes from 'prop-types';
import cx from 'classnames';
import styled from '@emotion/styled';
import { StyledComponentContext } from '../styled-components-context';
import { ForwardRefExoticComponent, PropsWithoutRef, RefAttributes, FC } from 'react';

const StyledSvg = styled('svg')`
transform: rotate(-90deg);
Expand Down Expand Up @@ -56,8 +56,16 @@ const StyledCounter = styled('div')`
font-variant-numeric: tabular-nums;
`;

const CircularProgressBar = (props) => {
const { percentage } = props;
interface CircularProgressBarProps {
/**
* Percentage elapsed.
*/
percentage: number;
}

const CircularProgressBar: FC<CircularProgressBarProps> = ({
percentage
}) => {
const radius = 90;
const circumference = 2 * Math.PI * radius;

Expand Down Expand Up @@ -139,38 +147,49 @@ const CircularProgressBar = (props) => {
);
};

/**
* Counter
*
* @description display character count and limit.
*
* @returns <Counter />
*/
const Counter = forwardRef((props, ref) => {
const { count, limit } = props;
const percentage = (count / limit) * 100;
return (
<StyledComponentContext cacheKey="tenup-component-counter">
<StyledCounter
className={cx('tenup--block-components__character-count', {
'is-over-limit': count > limit,
})}
{...props}
ref={ref}
>
<div className="tenup--block-components__character-count__label">
<span className="tenup--block-components__character-count__count">{count}</span>{' '}
/{' '}
<span className="tenup--block-components__character-count__limit">{limit}</span>
</div>
<CircularProgressBar percentage={percentage} />
</StyledCounter>
</StyledComponentContext>
);
});

CircularProgressBar.propTypes = {
percentage: PropTypes.number.isRequired,
};
interface CounterProps {
/**
* Current count.
*/
count: number;

/**
* Max limit.
*/
limit: number;

/**
* Rest of the props.
*/
[key: string]: unknown;
}

const Counter: ForwardRefExoticComponent<PropsWithoutRef<CounterProps> & RefAttributes<HTMLDivElement>> = forwardRef<HTMLDivElement, CounterProps>(
({
count,
limit,
...rest
}, ref ) => {
const percentage = (count / limit) * 100;
return (
<StyledComponentContext cacheKey="tenup-component-counter">
<StyledCounter
className={cx('tenup--block-components__character-count', {
'is-over-limit': count > limit,
})}
ref={ref}
{...rest}
>
<div className="tenup--block-components__character-count__label">
<span className="tenup--block-components__character-count__count">{count}</span>{' '}
/{' '}
<span className="tenup--block-components__character-count__limit">{limit}</span>
</div>
<CircularProgressBar percentage={percentage} />
</StyledCounter>
</StyledComponentContext>
);
}
);

export { CircularProgressBar, Counter };
42 changes: 42 additions & 0 deletions components/counter/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Counter

The `Counter` component let's you use circular progress bar with two props - `count` and `limit`.

This also exposes another component named `CircularProgressBar`, which can be used when we don't want the text annotation and just the SVG illustration.

## Usage

```js
import { Counter, CircularProgressBar } from '@10up/block-components';

function MyComponent( props ) {

return (
<>
<Counter
count={text.length}
limit={20}
/>

<CircularProgressBar
percentage={(text.length / 20) * 100}
/>
</>
);
}
```

## Props

#### Counter

| Name | Type | Default | isRequired | Description |
| ---------------- | ---------- | ---------- | --------------------- | ---------------------------------------------------------------------- |
| `count` | `number` | - | `Yes` | Current count of the counter. |
| `limit` | `number` | - | `Yes` | Max limit of the counter. |

#### CircularProgressBar

| Name | Type | Default | isRequired | Description |
| ---------------- | ---------- | ---------- | --------------------- | ---------------------------------------------------------------------- |
| `percentage` | `number` | - | `Yes` | Elapsed percentage of the timer. |
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,24 @@ import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import { useRefEffect, useInstanceId } from '@wordpress/compose';
import { useState } from '@wordpress/element';
import propTypes from 'prop-types';

export const StyledComponentContext = (props) => {
const { children, cacheKey } = props;
const fallbackKey = useInstanceId(StyledComponentContext);
interface StyledComponentContextProps {
/**
* Children.
*/
children: React.ReactNode;

/**
* Cache key.
*/
cacheKey: string;
}

export const StyledComponentContext: React.FC<StyledComponentContextProps> = ({
children,
cacheKey,
}) => {
const fallbackKey = `${useInstanceId(StyledComponentContext)}`;

const defaultCache = createCache({
key: cacheKey || fallbackKey,
Expand Down Expand Up @@ -37,8 +50,3 @@ export const StyledComponentContext = (props) => {
</>
);
};

StyledComponentContext.propTypes = {
children: propTypes.node.isRequired,
cacheKey: propTypes.string.isRequired,
};
14 changes: 14 additions & 0 deletions example/src/blocks/counter-example/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"apiVersion": 2,
"name": "example/counter",
"title": "Counter Example",
"description": "Example Block to show the Counter in usage",
"icon": "smiley",
"category": "common",
"example": {},
"supports": {
"html": false
},
"variations": [],
"editorScript": "file:./index.js"
}
59 changes: 59 additions & 0 deletions example/src/blocks/counter-example/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { __ } from '@wordpress/i18n';
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
import { PanelBody, Placeholder, TextControl } from '@wordpress/components';

import { Counter } from '@10up/block-components';
import { useState } from '@wordpress/element';

export const BlockEdit = () => {
const blockProps = useBlockProps();

const [ text, setText ] = useState( '' );

return (
<>
<InspectorControls>
<PanelBody title={__('Counter', 'example')}>
<TextControl
label="Text"
help="Enter some text"
value={ text }
onChange={
( value ) => {
if ( value.length > 20 ) {
return;
}
setText( value );
}
}
/>
<Counter
count={text.length}
limit={20}
/>
</PanelBody>
</InspectorControls>
<div {...blockProps}>
<Placeholder label={__('Counter', 'example')} instructions={__('Counter component example', 'example')}>
<TextControl
label="Text"
help="Enter some text"
value={ text }
onChange={
( value ) => {
if ( value.length > 20 ) {
return;
}
setText( value );
}
}
/>
<Counter
count={text.length}
limit={20}
/>
</Placeholder>
</div>
</>
)
}
8 changes: 8 additions & 0 deletions example/src/blocks/counter-example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { registerBlockType } from '@wordpress/blocks';
import metadata from './block.json';
import { BlockEdit } from './edit';

registerBlockType( metadata, {
edit: BlockEdit,
save: () => null
} );

0 comments on commit 3612e21

Please sign in to comment.