diff --git a/.gitignore b/.gitignore index c406da7..6276a62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules yarn.lock -dist +build diff --git a/.travis.yml b/.travis.yml index e0cc348..f3fa8cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: node_js node_js: + - '10' - '8' - - '6' diff --git a/package.json b/package.json index f23d6be..3fe5105 100644 --- a/package.json +++ b/package.json @@ -9,18 +9,18 @@ "email": "vdemedes@gmail.com", "url": "github.com/vadimdemedes" }, - "main": "dist/index.js", + "main": "build/index.js", "engines": { - "node": ">=6" + "node": ">=8" }, "scripts": { "pretest": "npm run build", "test": "xo && ava", - "build": "babel src --out-dir=dist", - "prepublish": "npm run build" + "build": "babel src --out-dir=build", + "prepare": "npm run build" }, "files": [ - "dist" + "build" ], "keywords": [ "ink", @@ -32,62 +32,38 @@ "jsx", "react" ], - "peerDependencies": { - "ink": "^0.5.0" - }, "dependencies": { "cli-spinners": "^1.0.0", - "object.omit": "^2.0.1", "prop-types": "^15.5.10" }, "devDependencies": { - "ava": "^0.20.0", - "babel-cli": "^6.24.1", - "babel-plugin-transform-react-jsx": "^6.24.1", + "@babel/cli": "^7.2.3", + "@babel/core": "^7.3.3", + "@babel/plugin-proposal-class-properties": "^7.3.3", + "@babel/preset-react": "^7.0.0", + "ava": "*", + "babel-eslint": "^10.0.1", + "delay": "^4.1.0", "eslint-config-xo-react": "^0.13.0", "eslint-plugin-react": "^7.1.0", - "ink": "^0.5.0", + "ink": "^2.0.0", + "react": "^16.8.2", "sinon": "^2.3.6", - "xo": "^0.18.2" + "xo": "*" }, "babel": { "plugins": [ - [ - "transform-react-jsx", - { - "pragma": "h", - "useBuiltIns": true - } - ] + "@babel/plugin-proposal-class-properties" + ], + "presets": [ + "@ava/stage-4", + "@babel/preset-react" ] }, - "ava": { - "babel": { - "presets": [ - "@ava/stage-4" - ], - "plugins": [ - [ - "transform-react-jsx", - { - "pragma": "h", - "useBuiltIns": true - } - ] - ] - } - }, "xo": { + "parser": "babel-eslint", "extends": [ "xo-react" - ], - "rules": { - "react/no-unused-prop-types": 1 - }, - "settings": { - "react": { - "pragma": "h" - } - } + ] } } diff --git a/readme.md b/readme.md index df3c4db..3bc6a4c 100644 --- a/readme.md +++ b/readme.md @@ -13,13 +13,14 @@ $ npm install ink-spinner ## Usage ```js -const {h, render} = require('ink'); -const Spinner = require('ink-spinner'); +import React from 'react'; +import {render, Color} from 'ink'; +import Spinner from 'ink-spinner'; render(( -
- Loading -
+ + {' '}Loading + )); ``` @@ -28,8 +29,6 @@ render(( ## Props -All props except the own ones listed below are passed as-is to ``, which means you can easily apply any color, without wrapping `` in `` manually. - ### type Type: `string`
diff --git a/src/index.js b/src/index.js index 649a219..8839a06 100644 --- a/src/index.js +++ b/src/index.js @@ -1,39 +1,33 @@ -'use strict'; - -const {h, Color, Component} = require('ink'); -const PropTypes = require('prop-types'); -const spinners = require('cli-spinners'); -const omit = require('object.omit'); - -class Spinner extends Component { - constructor(props) { - super(props); - - this.state = { - frame: 0 - }; +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import {Box} from 'ink'; +import spinners from 'cli-spinners'; + +export default class Spinner extends Component { + static propTypes = { + type: PropTypes.string + } - this.switchFrame = this.switchFrame.bind(this); + static defaultProps = { + type: 'dots' } - getSpinner() { - return spinners[this.props.type] || spinners.dots; + state = { + frame: 0 } - render(props, {frame}) { - const colorProps = omit(props, 'type'); + render() { const spinner = this.getSpinner(); return ( - - {spinner.frames[frame]} - + + {spinner.frames[this.state.frame]} + ); } componentDidMount() { const spinner = this.getSpinner(); - this.timer = setInterval(this.switchFrame, spinner.interval); } @@ -41,9 +35,12 @@ class Spinner extends Component { clearInterval(this.timer); } - switchFrame() { - const {frame} = this.state; + getSpinner() { + return spinners[this.props.type] || spinners.dots; + } + switchFrame = () => { + const {frame} = this.state; const spinner = this.getSpinner(); const isLastFrame = frame === spinner.frames.length - 1; const nextFrame = isLastFrame ? 0 : frame + 1; @@ -53,13 +50,3 @@ class Spinner extends Component { }); } } - -Spinner.propTypes = { - type: PropTypes.string -}; - -Spinner.defaultProps = { - type: 'dots' -}; - -module.exports = Spinner; diff --git a/test.js b/test.js index 754e203..79437ad 100644 --- a/test.js +++ b/test.js @@ -1,62 +1,36 @@ -import {h, build, Color} from 'ink'; -import renderToString from 'ink/lib/render-to-string'; -import {stub} from 'sinon'; +import EventEmitter from 'events'; +import React from 'react'; +import {render} from 'ink'; +import {spy} from 'sinon'; import spinners from 'cli-spinners'; import test from 'ava'; +import delay from 'delay'; import Spinner from '.'; -test('render', t => { - let component; +test('render spinner', async t => { + const stdout = { + columns: 100, + write: spy() + }; - function setRef(ref) { - component = ref; - } + const stdin = new EventEmitter(); + stdin.setRawMode = () => {}; + stdin.setEncoding = () => {}; + stdin.pause = () => {}; const spinner = spinners.dots; - let tree; + const app = render(, { + stdout, + stdin, + debug: true + }); - for (let frame = 0; frame < spinner.frames.length; frame++) { - tree = build(, tree); - t.is(renderToString(tree), spinner.frames[frame]); + await delay(spinner.frames.length * spinner.interval); + app.unmount(); - component.setState({ - frame: frame + 1 - }); - } -}); - -test('pass props to ', t => { - const spinner = spinners.dots; - - const actual = build(); - const expected = build({spinner.frames[0]}); - - t.is(renderToString(actual), renderToString(expected)); -}); - -test('spin', t => { - stub(Spinner.prototype, 'setState'); - - let component; - - function setRef(ref) { - component = ref; - } - - build(); - - const spinner = spinners.dots; - - let frame = 1; - let i = 0; - - while (i < spinner.frames.length * 2) { - component.switchFrame(); - - t.deepEqual(component.setState.getCall(i).args[0], {frame}); - component.state = {frame}; + const allFrames = stdout.write.args.map(args => args[0]); + const frames = [...new Set(allFrames)]; - frame = frame === spinner.frames.length - 1 ? 0 : frame + 1; - i++; - } + t.deepEqual(frames, spinner.frames); + t.pass(); });