From 41d2cd8b9c7d27da3b15be975b2d84d397f8aff9 Mon Sep 17 00:00:00 2001 From: abdennour Date: Fri, 25 Nov 2016 15:59:50 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=8E=20=F0=9F=8C=8D=20=F0=9F=8C=8F=20in?= =?UTF-8?q?itial=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .babelrc | 3 +++ .gitignore | 3 +++ .npmignore | 2 ++ .travis.yml | 18 +++++++++++++ README.md | 15 +++++++++++ index.js | 1 + package.json | 51 +++++++++++++++++++++++++++++++++++ src/components/CSVDownload.js | 21 +++++++++++++++ src/components/CSVLink.js | 23 ++++++++++++++++ src/core.js | 26 ++++++++++++++++++ src/index.js | 5 ++++ src/metaProps.js | 13 +++++++++ 12 files changed, 181 insertions(+) create mode 100644 .babelrc create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 .travis.yml create mode 100644 README.md create mode 100644 index.js create mode 100644 package.json create mode 100644 src/components/CSVDownload.js create mode 100644 src/components/CSVLink.js create mode 100644 src/core.js create mode 100644 src/index.js create mode 100644 src/metaProps.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..9b7d435 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "stage-0", "react"] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d83aca0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +lib/ +node_modules/ +coverage/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..ea9bfd0 --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +src/ +test/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6cb7505 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +sudo: false + +language: node_js + +# cache: +# directories: +# - node_modules + +node_js: + - "6" + +branches: + only: + - master + +script: npm run test +after_success: + - npm run coveralls diff --git a/README.md b/README.md new file mode 100644 index 0000000..41a67ce --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Overview : + +```js +import {CSVLink} from 'react-csv'; + + +const csvData =[ + ['firstname', 'lastname', 'email'] , + ['Ahmed', 'Tomi' , 'ah@smthing.co.com'] , + ['Raed', 'Labes' , 'rl@smthing.co.com'] , + ['Yezzi','Min l3b', 'ymin@cocococo.com'] +]; +Download me + +``` diff --git a/index.js b/index.js new file mode 100644 index 0000000..66d1bc7 --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require(`lib/`); diff --git a/package.json b/package.json new file mode 100644 index 0000000..c391b7c --- /dev/null +++ b/package.json @@ -0,0 +1,51 @@ +{ + "name": "react-csv", + "version": "0.0.1", + "description": "Build CSV files on the fly basing on Array/literal object of data ", + "main": "index.js", + "scripts": { + "compile": "babel --presets es2015,stage-0 -d lib/ src/", + "prepublish": "npm run compile", + "test": "node_modules/.bin/_mocha test", + "test2": "node_modules/.bin/babel-node node_modules/.bin/babel-istanbul cover node_modules/.bin/_mocha -- test/*.js", + "coverage": "istanbul cover _mocha -- --ui bdd -R spec -t 5000;open ./coverage/lcov-report/index.html", + "cover": "node_modules/.bin/babel-node node_modules/.bin/babel-istanbul cover node_modules/.bin/_mocha", + "coveralls": "npm run cover -- --report lcovonly && cat ./coverage/lcov.info | coveralls" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/abdennour/react-csv.git" + }, + "keywords": [ + "csv", + "excel", + "react", + "file", + "IO", + "download", + "hyperlink", + "component", + "reuse", + "ES7", + "babel" + ], + "author": "Abdennour TOUMI ", + "license": "MIT", + "bugs": { + "url": "https://github.com/abdennour/react-csv/issues" + }, + "homepage": "https://github.com/abdennour/react-csv#readme", + "devDependencies": { + "babel-cli": "^6.18.0", + "babel-core": "^6.18.2", + "babel-polyfill": "^6.16.0", + "babel-preset-es2015": "^6.18.0", + "babel-preset-react": "^6.16.0", + "babel-preset-stage-0": "^6.16.0", + "enzyme": "^2.6.0", + "react": "^15.4.1" + }, + "dependencies": { + "x-object": "^1.0.10" + } +} diff --git a/src/components/CSVDownload.js b/src/components/CSVDownload.js new file mode 100644 index 0000000..ea26f4c --- /dev/null +++ b/src/components/CSVDownload.js @@ -0,0 +1,21 @@ +import React from 'react'; +import {buildURI} from '../core'; +import {defaultProps, PropTypes, PropsNotForwarded} from '../metaProps'; + +class CSVDownload extends React.Component { + constructor(props) { + super(props); + } + componentDidMount(){ + window.open(buildURI(this.props.data)); + } + + render(){ + return (null) + } +} + +CSVDownload.defaultProps = defaultProps; +CSVDownload.PropTypes = PropTypes; +CSVDownload.PropsNotForwarded = PropsNotForwarded; +export default CSVDownload; diff --git a/src/components/CSVLink.js b/src/components/CSVLink.js new file mode 100644 index 0000000..c4b2a2e --- /dev/null +++ b/src/components/CSVLink.js @@ -0,0 +1,23 @@ +import React from 'react'; +import {buildURI} from '../core'; +import {defaultProps, PropTypes, PropsNotForwarded} from '../metaProps'; + +class CSVLink extends React.Component { + constructor(props) { + super(props); + } + + + render(){ + return ( + + {this.props.children} + + ) + } +} +CSVLink.defaultProps = defaultProps; +CSVLink.PropTypes = PropTypes; +CSVLink.PropsNotForwarded = PropsNotForwarded; + +export default CSVLink; diff --git a/src/core.js b/src/core.js new file mode 100644 index 0000000..74a3da9 --- /dev/null +++ b/src/core.js @@ -0,0 +1,26 @@ +const isJsons = (array) => array.every(row => (typeof row === 'object' && !(row instanceof Array))) +const isArrays = (array) => array.every(row => Array.isArray(row)) + +const jsonsHeaders = (array) => Array.from( + array.map(json => Object.keys(json)) + .reduce((a, b) => new Set([...a, ...b]), []) +); +const jsons2arrays = (jsons, headers) => { + headers = headers || jsonsHeaders(jsons); + return [headers, ...array.map((object) => + headers.map((header) => + object[header] ? object[header] : ''))] +}; + +const joiner = (data) => data.map((row, index) => row.join(',')).join(`\n`); + +const arrays2csv = (data, headers) => joiner(headers ? [headers, ...data] : data); +const jsons2csv = (data, headers) => joiner(jsons2arrays(data, headers)) +const toCSV = (data, headers) => { + if(isJsons(data)) return jsons2csv(data, headers); + if(isArrays(data)) return jsons2csv(data, headers); + throw new TypeError(`Data should be an array of arrays OR array of objects `); +}; +export const buildURI = (data, headers) => encodeURI( +`data:text/csv;charset=utf-8,${toCSV(data, headers)}` +); diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..4354a30 --- /dev/null +++ b/src/index.js @@ -0,0 +1,5 @@ +import Download from './Download'; +import Link from './Link'; + +export const CSVDownload = Download; +export const CSVLink = Link; diff --git a/src/metaProps.js b/src/metaProps.js new file mode 100644 index 0000000..ee88c6d --- /dev/null +++ b/src/metaProps.js @@ -0,0 +1,13 @@ +import React from 'react'; +export const defaultProps = { + +}; + +export const PropTypes = { + data: React.PropTypes.array.isRequired, + headers: React.PropTypes.array +}; + +export const PropsNotForwarded = [ + `data` +];