Skip to content

Commit

Permalink
Rebuild for TypeScript (#514)
Browse files Browse the repository at this point in the history
* Typescript-ify.

* Add TS to build process.

* Fix build script.

* Remove proptypes.

* Timeout should use the return type of setTimeout, as it could be NodeJS.Timeout in node, or number in the browser.

* Check for existing instance before checking for instance.target.

* Fixed createInstance Element warning.

* Fixed createInstance element warning (2)

* Clean up package.json.

* Remove prop-types from rollup config.
  • Loading branch information
johnrom committed Jul 26, 2021
1 parent 78a5be6 commit 565d2c0
Show file tree
Hide file tree
Showing 12 changed files with 345 additions and 232 deletions.
9 changes: 6 additions & 3 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"plugins": ["@babel/plugin-proposal-class-properties"],
"presets": [
["@babel/preset-env", { "modules": false }],
"@babel/preset-react"
"@babel/preset-react",
"@babel/preset-typescript"
],
"plugins": ["@babel/plugin-proposal-class-properties"],
"env": {
"test": {
"plugins": ["@babel/plugin-proposal-class-properties"],
"presets": [["@babel/preset-env", { "targets": { "node": "current" } }]]
"presets": [
["@babel/preset-env", { "targets": { "node": "current" } }]
]
}
}
}
85 changes: 0 additions & 85 deletions index.d.ts

This file was deleted.

14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@
"homepage": "https://react-countup.now.sh",
"main": "build",
"files": [
"build",
"index.d.ts"
"build"
],
"typings": "index.d.ts",
"typings": "build/index.d.ts",
"scripts": {
"build": "rollup -c",
"build": "rollup -c && tsc --emitDeclarationOnly --noEmit false --project src/tsconfig.json --outDir build",
"prepublishOnly": "yarn build",
"test": "jest"
},
Expand All @@ -34,16 +33,18 @@
},
"dependencies": {
"countup.js": "^2.0.7",
"prop-types": "^15.7.2",
"warning": "^4.0.3"
},
"devDependencies": {
"@babel/core": "7.14.6",
"@babel/plugin-proposal-class-properties": "7.14.5",
"@babel/preset-env": "7.14.7",
"@babel/preset-react": "7.14.5",
"@babel/preset-typescript": "^7.14.5",
"@rollup/plugin-node-resolve": "^13.0.2",
"@testing-library/react": "12.0.0",
"@testing-library/react-hooks": "7.0.1",
"@types/warning": "^3.0.0",
"babel-jest": "27.0.6",
"jest": "27.0.6",
"prettier": "2.3.2",
Expand All @@ -53,6 +54,7 @@
"react-dom": "17.0.2",
"react-test-renderer": "17.0.2",
"rollup": "2.52.4",
"rollup-plugin-babel": "4.4.0"
"rollup-plugin-babel": "4.4.0",
"typescript": "^4.3.5"
}
}
9 changes: 7 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import babel from 'rollup-plugin-babel';
import resolve from '@rollup/plugin-node-resolve';

const extensions = ['.js', '.jsx', '.ts', '.tsx'];

export default {
input: 'src/index.js',
input: 'src/index.ts',
output: {
file: 'build/index.js',
format: 'cjs',
},
plugins: [
resolve({ extensions }),
babel({
exclude: 'node_modules/**',
extensions,
}),
],
external: ['countup.js', 'prop-types', 'react', 'react-dom', 'warning'],
external: ['countup.js', 'react', 'react-dom', 'warning'],
};
80 changes: 35 additions & 45 deletions src/CountUp.js → src/CountUp.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import React, { Component, CSSProperties } from 'react';
import warning from 'warning';
import { createCountUpInstance } from './common';
import { CountUp as CountUpJs } from 'countup.js';
import { CallbackProps, CommonProps, RenderCounterProps } from './types';

export interface CountUpProps extends CommonProps, CallbackProps {
className?: string;
redraw?: boolean;
preserveValue?: boolean;
children?: (props: RenderCounterProps) => React.ReactNode;
style?: CSSProperties;
}

class CountUp extends Component {
static propTypes = {
decimal: PropTypes.string,
decimals: PropTypes.number,
delay: PropTypes.number,
easingFn: PropTypes.func,
end: PropTypes.number.isRequired,
formattingFn: PropTypes.func,
onEnd: PropTypes.func,
onStart: PropTypes.func,
prefix: PropTypes.string,
redraw: PropTypes.bool,
separator: PropTypes.string,
start: PropTypes.number,
startOnMount: PropTypes.bool,
suffix: PropTypes.string,
style: PropTypes.object,
useEasing: PropTypes.bool,
preserveValue: PropTypes.bool,
};
class CountUp extends Component<CountUpProps> {
private instance: CountUpJs | undefined;
private timeoutId: ReturnType<typeof setTimeout> | undefined;

static defaultProps = {
decimal: '.',
Expand Down Expand Up @@ -58,7 +50,7 @@ class CountUp extends Component {
this.start();
}

checkProps = (updatedProps) => {
checkProps = (updatedProps: CountUpProps) => {
const {
start,
suffix,
Expand Down Expand Up @@ -86,20 +78,20 @@ class CountUp extends Component {
return hasPropsChanged || redraw;
};

shouldComponentUpdate(nextProps) {
shouldComponentUpdate(nextProps: CountUpProps) {
const { end } = this.props;
return this.checkProps(nextProps) || end !== nextProps.end;
}

componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: CountUpProps) {
// If duration, suffix, prefix, separator or start has changed
// there's no way to update the values.
// So we need to re-create the CountUp instance in order to
// restart it.
const { end, preserveValue } = this.props;

if (this.checkProps(prevProps)) {
this.instance.reset();
this.instance?.reset();
this.instance = this.createInstance();
this.start();
}
Expand All @@ -108,17 +100,18 @@ class CountUp extends Component {
// end value.
if (end !== prevProps.end) {
if (!preserveValue) {
this.instance.reset();
this.instance?.reset();
}
this.instance.update(end);
this.instance?.update(end);
}
}

componentWillUnmount() {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
if (this.instance.target) {
// instance.target is incorrectly marked private by typescript
if (this.instance && (this.instance as any).target) {
this.instance.reset();
}
}
Expand All @@ -127,11 +120,8 @@ class CountUp extends Component {
if (typeof this.props.children === 'function') {
// Warn when user didn't use containerRef at all
warning(
this.containerRef.current &&
(this.containerRef.current instanceof HTMLElement ||
this.containerRef.current instanceof SVGTextElement ||
this.containerRef.current instanceof SVGTSpanElement),
`Couldn't find attached element to hook the CountUp instance into! Try to attach "containerRef" from the render prop to a an HTMLElement, eg. <span ref={containerRef} />.`,
this.containerRef.current instanceof Element,
`Couldn't find attached element to hook the CountUp instance into! Try to attach "containerRef" from the render prop to a an Element, eg. <span ref={containerRef} />.`,
);
}
return createCountUpInstance(this.containerRef.current, this.props);
Expand All @@ -141,18 +131,18 @@ class CountUp extends Component {
const { reset, restart: start, update } = this;
const { onPauseResume } = this.props;

this.instance.pauseResume();
this.instance?.pauseResume();

onPauseResume({ reset, start, update });
onPauseResume?.({ reset, start, update });
};

reset = () => {
const { pauseResume, restart: start, update } = this;
const { onReset } = this.props;

this.instance.reset();
this.instance?.reset();

onReset({ pauseResume, start, update });
onReset?.({ pauseResume, start, update });
};

restart = () => {
Expand All @@ -164,28 +154,28 @@ class CountUp extends Component {
const { pauseResume, reset, restart: start, update } = this;
const { delay, onEnd, onStart } = this.props;
const run = () =>
this.instance.start(() => onEnd({ pauseResume, reset, start, update }));
this.instance?.start(() => onEnd?.({ pauseResume, reset, start, update }));

// Delay start if delay prop is properly set
if (delay > 0) {
if (delay && delay > 0) {
this.timeoutId = setTimeout(run, delay * 1000);
} else {
run();
}

onStart({ pauseResume, reset, update });
onStart?.({ pauseResume, reset, update });
};

update = (newEnd) => {
update = (newEnd: string | number) => {
const { pauseResume, reset, restart: start } = this;
const { onUpdate } = this.props;

this.instance.update(newEnd);
this.instance?.update(newEnd);

onUpdate({ pauseResume, reset, start });
onUpdate?.({ pauseResume, reset, start });
};

containerRef = React.createRef();
containerRef = React.createRef<any>();

render() {
const { children, className, style } = this.props;
Expand Down
5 changes: 4 additions & 1 deletion src/common.js → src/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { CountUp } from 'countup.js';
import { CountUpProps } from './CountUp';
import { useCountUpProps } from './useCountUp';

export const createCountUpInstance = (el, props) => {
export const createCountUpInstance = (el: string | HTMLElement | HTMLInputElement, props: useCountUpProps | CountUpProps) => {
const {
decimal,
decimals,
Expand All @@ -15,6 +17,7 @@ export const createCountUpInstance = (el, props) => {
suffix,
useEasing,
} = props;

return new CountUp(el, end, {
startVal: start,
duration,
Expand Down
File renamed without changes.
24 changes: 24 additions & 0 deletions src/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {/* Basic Options */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
"jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
"noEmit": true, /* Do not emit outputs. */

/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
"strictNullChecks": true, /* Enable strict null checks. */
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */

/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */

"esModuleInterop": true,
}
}
Loading

0 comments on commit 565d2c0

Please sign in to comment.