diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 000000000..1b1569ade
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,7 @@
+.idea/
+*.css
+*.opts
+*.scss
+*.snap
+*.svg
+node_modules/**
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 000000000..3b91d121e
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,146 @@
+env:
+ browser: true
+ node: true
+ es6: true
+ jest: true
+
+globals:
+ $: true
+
+parser: 'babel-eslint'
+
+#extends: 'react-app'
+
+plugins:
+ - ie11
+ - jsx-a11y
+ - loosely-restrict-imports
+ - react
+
+rules:
+ #brace-style: 2
+ camelcase: 2
+ comma-dangle: [2, 'never']
+ comma-spacing: 2
+ comma-style: [2, 'last']
+ #compat/compat: 2
+ default-case: 2
+ dot-notation: 2
+ eol-last: 2
+ #eqeqeq: 2
+ guard-for-in: 2
+ handle-callback-err: 2
+ ie11/no-collection-args: 2
+ ie11/no-for-in-const: 2
+ ie11/no-weak-collections: 2
+ #indent: [2, 4, {"SwitchCase": 1}]
+ jsx-a11y/accessible-emoji: 2
+ jsx-a11y/alt-text: 2
+ #jsx-a11y/anchor-has-content: 2
+ #jsx-a11y/anchor-is-valid: 2
+ jsx-a11y/aria-activedescendant-has-tabindex: 2
+ jsx-a11y/aria-props: 2
+ jsx-a11y/aria-proptypes: 2
+ #jsx-a11y/aria-role: 2
+ jsx-a11y/aria-unsupported-elements: 2
+ #jsx-a11y/click-events-have-key-events: 2
+ jsx-a11y/heading-has-content: 2
+ jsx-a11y/html-has-lang: 2
+ jsx-a11y/iframe-has-title: 2
+ jsx-a11y/img-redundant-alt: 2
+ #jsx-a11y/interactive-supports-focus: 2
+ jsx-a11y/label-has-for: [2, {'allowChildren': true, 'required': {'every': [ 'id' ]}}]
+ jsx-a11y/media-has-caption: 2
+ jsx-a11y/mouse-events-have-key-events: 2
+ jsx-a11y/no-access-key: 2
+ jsx-a11y/no-autofocus: 2
+ jsx-a11y/no-distracting-elements: 2
+ jsx-a11y/no-interactive-element-to-noninteractive-role: 2
+ #jsx-a11y/no-noninteractive-element-interactions: 2
+ #jsx-a11y/no-noninteractive-element-to-interactive-role: [2, { ul: ['tablist', 'menu']}]
+ jsx-a11y/no-noninteractive-tabindex: 2
+ #jsx-a11y/no-onchange: 2
+ jsx-a11y/no-redundant-roles: 2
+ #jsx-a11y/no-static-element-interactions: 2
+ jsx-a11y/role-has-required-aria-props: 2
+ #jsx-a11y/role-supports-aria-props: 2
+ jsx-a11y/scope: 2
+ jsx-a11y/tabindex-no-positive: 2
+ jsx-quotes: [ 2, prefer-single ]
+ key-spacing: 2
+ keyword-spacing: [2, { 'before': true }]
+ loosely-restrict-imports/loosely-restrict-imports: [2, '.jsx']
+ new-cap: 2
+ no-cond-assign: 2
+ #no-console: 2
+ no-constant-condition: 2
+ no-control-regex: 2
+ no-debugger: 2
+ no-dupe-args: 2
+ no-dupe-keys: 2
+ no-duplicate-case: 2
+ no-empty-character-class: 2
+ #no-empty: 2
+ no-ex-assign: 2
+ no-extra-bind: 2
+ no-extra-boolean-cast: 0
+ no-extra-parens: 0
+ no-extra-semi: 2
+ no-fallthrough: 2
+ no-floating-decimal: 2
+ no-func-assign: 2
+ no-inner-declarations: 2
+ no-invalid-regexp: 2
+ no-irregular-whitespace: 2
+ no-loop-func: 2
+ no-mixed-spaces-and-tabs: 2
+ no-multi-spaces: 2
+ no-negated-in-lhs: 2
+ #no-nested-ternary: 2
+ no-obj-calls: 2
+ no-regex-spaces: 2
+ #no-shadow: 2
+ no-spaced-func: 2
+ #no-sparse-arrays: 2
+ no-trailing-spaces: 2
+ no-undef: 2
+ #no-undefined: 2
+ no-underscore-dangle: 0
+ no-unreachable: 2
+ #no-unused-vars: [2, { ignoreRestSiblings: true }]
+ quote-props: [2, 'as-needed', { 'keywords': true, 'unnecessary': false }]
+ quotes: [2, 'single']
+ #radix: 2
+ react/display-name: 2
+ react/jsx-boolean-value: 2
+ react/jsx-closing-bracket-location: [2, 'after-props']
+ react/jsx-equals-spacing: [2, 'never']
+ react/jsx-indent: 2
+ react/jsx-indent-props: 2
+ react/jsx-max-props-per-line: [2, { "maximum": 2 }]
+ react/jsx-no-undef: 2
+ react/jsx-tag-spacing: [2, { "beforeSelfClosing": "always" }]
+ #react/jsx-sort-props: 2
+ react/jsx-uses-react: 2
+ react/jsx-uses-vars: 2
+ react/jsx-wrap-multilines: 2
+ react/no-did-mount-set-state: 2
+ react/no-did-update-set-state: 2
+ #react/no-multi-comp: 2
+ react/no-unknown-property: 2
+ #react/prop-types: 2
+ #react/react-in-jsx-scope: 2
+ react/self-closing-comp: 2
+ react/sort-prop-types: [2, { 'callbacksLast' : true, 'ignoreCase' : true, 'requiredFirst' : true, } ]
+ semi-spacing: 2
+ semi: 2
+ #sort-imports: [2, { 'ignoreCase': true, 'ignoreMemberSort': false, 'memberSyntaxSortOrder': ['none', 'single', 'multiple', 'all'] }]
+ space-before-blocks: 2
+ space-before-function-paren: [2, 'never']
+ space-infix-ops: 2
+ spaced-comment: [0, 'always', { exceptions: ['-']}]
+ strict: [2, 'global']
+ #use-isnan: 2
+ #valid-jsdoc: [2, { prefer: { 'return': 'returns'}}]
+ #valid-typeof: 2
+ wrap-iife: [2, 'any']
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 000000000..1c6340a8e
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,5 @@
+/node-modules
+/scripts
+/src
+/config
+/ci-scripts
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 8d19c3d69..9ad645049 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,11 +8,14 @@ branches:
only:
- develop
- "/^feature\\/.*$/"
+ - "/^fix\\/.*$/"
jobs:
include:
- - stage: "Fundamental-react build"
+ - stage: "Fundamental-react: Lint"
+ script: npm run lint
+ - stage: "Fundamental-react: Test"
name: "Unit tests"
- script: "./ci-scripts/unit-tests.sh"
+ script: npm run test:coverage
notifications:
email:
on_failure: always
diff --git a/README.md b/README.md
index ac341ccd2..92748ad8d 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,21 @@
-# Fundamental-react
-React.JS components for [SAP Fiori Fundamentals](https://github.com/SAP/fundamental)
-- [Playground](https://sap.github.io/fundamental-react/)
-- [npm package fundamental-react](https://www.npmjs.com/package/fundamental-react)
-- [](https://travis-ci.org/SAP/fundamental-react)
-- [GitHub repo of Angular implementation of SAP Fiori Fundamentals](https://github.com/SAP/fundamental-ngx)
-- [GitHub repo of Vue implementation of SAP Fiori Fundamentals](https://github.com/SAP/fundamental-vue)
+Fundamental-react is a set of [React.JS](https://reactjs.org/) components implementation of [SAP Fiori Fundamentals library](https://sap.github.io/fundamental/).
+
+**[Component Documentation](https://sap.github.io/fundamental-react/)**
+
+## Current Version
+
+```
+0.0.8-beta
+```
+
+## Build Status
+[](https://travis-ci.org/SAP/fundamental-react)
## Description
-Fundamental-react is a set of [React](https://reactjs.org/) components implementation of [SAP Fiori Fundamentals library](https://sap.github.io/fundamental/). SAP Fiori Fundamentals library is a Design System and HTML/CSS Component Library used to build modern Product User Experiences with the SAP look and feel. This will allow you to stay/use React for your application and get SAP look and feel.
-Fundamental-react is an open source library and it is open for contribution as long as you follow certain [rules/guidelines](./CONTRIBUTING.md).
+Fundamental-react is a set of [React.JS](https://reactjs.org/) components implementation of [SAP Fiori Fundamentals library](https://sap.github.io/fundamental/). SAP Fiori Fundamentals library is a Design System and HTML/CSS Component Library used to build modern Product User Experiences with the SAP look and feel. This will allow you to stay/use React for your application and get SAP look and feel.
+
## Requirements
@@ -19,9 +24,43 @@ https://www.npmjs.com/get-npm
Some prior knowledge of React is required for using this library.
-## Available Scripts (Associated with Create React App)
+# Getting started
+
+## Install
+
+To download and use this library, you first need to install the node package manager - [npm](https://www.npmjs.com/get-npm).
+
+1. Install Fiori Fundamentals:
+
+`npm install --save fiori-fundamentals`
+
+2. Install Fundamental-react:
+
+`npm install --save fundamental-react`
+
+[npm package for fundamental-react](https://www.npmjs.com/package/fundamental-react)
+
+3. Include the Fiori Fundamentals CSS in your React application. In your App.css or App.scss file include the following lines:
+
+```
+$fd-icons-path: "~fiori-fundamentals/scss/icons/";
+$fd-fonts-path: "~fiori-fundamentals/scss/fonts/";
+@import '../node_modules/fiori-fundamentals/scss/all.scss';
+```
+
+You can now use the [Component Documentation](https://sap.github.io/fundamental-react/) to browse the components currently available with Fundamental Vue. To use a Fundamental-react component, paste the desired code snippet from the Component Documentation and configure it as necessarry:
+
+
+ ...
+
+
+
+ ...
+
+
+## Available Scripts
-#### `npm start`
+`npm start`
Runs the app in the development mode.
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
@@ -29,43 +68,29 @@ Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will automatically reload on changes.
Lint errors are shown in the console.
-#### `npm test`
+`npm test`
Launches the test runner in the interactive watch mode.
-#### `npm test -- --coverage`
+`npm test -- --coverage`
Launches the test runner and display code coverage report.
-#### `npm test -- --coverage --watch`
+`npm test -- --coverage --watch`
Launches the test runner and display code coverage report and interactive watch mode.
-#### `npm run build`
+`npm run build`
Builds the app for production to the `build` folder.
-## Download and Installation
-
-#### 1. Download Fiori Fundamentals:
-
-`npm install --save fiori-fundamentals`
-
-#### 2. Include the Fiori Fundamentals CSS in your React application. In your App.css or App.scss file include the following lines:
-
-```
-$fd-icons-path: "~fiori-fundamentals/scss/icons/";
-$fd-fonts-path: "~fiori-fundamentals/scss/fonts/";
-@import '../node_modules/fiori-fundamentals/scss/all.scss';
-```
-
## Known Issues
-Click [here](https://github.com/SAP/fundamental-react/issues) to view the current issues.
+There are no known major issues.
## How to obtain support
-If you encounter an issue, you can [create a ticket](https://github.com/SAP/fundamental-react/issues)
+If you encounter an issue, you can [create a ticket](https://github.com/SAP/fundamental-react/issues/new)
## Contributing
@@ -75,3 +100,8 @@ If you want to contribute, please check the [CONTRIBUTING.md](./CONTRIBUTING.md)
Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.
This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the [LICENSE file](https://github.com/SAP/fundamental-react/blob/master/LICENSE.txt)
+
+## Similar Projects
+- [GitHub repo of Angular implementation of SAP Fiori Fundamentals](https://github.com/SAP/fundamental-ngx)
+- [GitHub repo of Vue implementation of SAP Fiori Fundamentals](https://github.com/SAP/fundamental-vue)
+
diff --git a/config/env.js b/config/env.js
new file mode 100644
index 000000000..b0344c5a8
--- /dev/null
+++ b/config/env.js
@@ -0,0 +1,93 @@
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const paths = require('./paths');
+
+// Make sure that including paths.js after env.js will read .env variables.
+delete require.cache[require.resolve('./paths')];
+
+const NODE_ENV = process.env.NODE_ENV;
+if (!NODE_ENV) {
+ throw new Error(
+ 'The NODE_ENV environment variable is required but was not specified.'
+ );
+}
+
+// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
+var dotenvFiles = [
+ `${paths.dotenv}.${NODE_ENV}.local`,
+ `${paths.dotenv}.${NODE_ENV}`,
+ // Don't include `.env.local` for `test` environment
+ // since normally you expect tests to produce the same
+ // results for everyone
+ NODE_ENV !== 'test' && `${paths.dotenv}.local`,
+ paths.dotenv,
+].filter(Boolean);
+
+// Load environment variables from .env* files. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set. Variable expansion is supported in .env files.
+// https://github.com/motdotla/dotenv
+// https://github.com/motdotla/dotenv-expand
+dotenvFiles.forEach(dotenvFile => {
+ if (fs.existsSync(dotenvFile)) {
+ require('dotenv-expand')(
+ require('dotenv').config({
+ path: dotenvFile,
+ })
+ );
+ }
+});
+
+// We support resolving modules according to `NODE_PATH`.
+// This lets you use absolute paths in imports inside large monorepos:
+// https://github.com/facebook/create-react-app/issues/253.
+// It works similar to `NODE_PATH` in Node itself:
+// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
+// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
+// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
+// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
+// We also resolve them to make sure all tools using them work consistently.
+const appDirectory = fs.realpathSync(process.cwd());
+process.env.NODE_PATH = (process.env.NODE_PATH || '')
+ .split(path.delimiter)
+ .filter(folder => folder && !path.isAbsolute(folder))
+ .map(folder => path.resolve(appDirectory, folder))
+ .join(path.delimiter);
+
+// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
+// injected into the application via DefinePlugin in Webpack configuration.
+const REACT_APP = /^REACT_APP_/i;
+
+function getClientEnvironment(publicUrl) {
+ const raw = Object.keys(process.env)
+ .filter(key => REACT_APP.test(key))
+ .reduce(
+ (env, key) => {
+ env[key] = process.env[key];
+ return env;
+ },
+ {
+ // Useful for determining whether we’re running in production mode.
+ // Most importantly, it switches React into the correct mode.
+ NODE_ENV: process.env.NODE_ENV || 'development',
+ // Useful for resolving the correct path to static assets in `public`.
+ // For example,
.
+ // This should only be used as an escape hatch. Normally you would put
+ // images into the `src` and `import` them in code to get their paths.
+ PUBLIC_URL: publicUrl,
+ }
+ );
+ // Stringify all values so we can feed into Webpack DefinePlugin
+ const stringified = {
+ 'process.env': Object.keys(raw).reduce((env, key) => {
+ env[key] = JSON.stringify(raw[key]);
+ return env;
+ }, {}),
+ };
+
+ return { raw, stringified };
+}
+
+module.exports = getClientEnvironment;
diff --git a/config/jest/cssTransform.js b/config/jest/cssTransform.js
new file mode 100644
index 000000000..8f6511481
--- /dev/null
+++ b/config/jest/cssTransform.js
@@ -0,0 +1,14 @@
+'use strict';
+
+// This is a custom Jest transformer turning style imports into empty objects.
+// http://facebook.github.io/jest/docs/en/webpack.html
+
+module.exports = {
+ process() {
+ return 'module.exports = {};';
+ },
+ getCacheKey() {
+ // The output is always the same.
+ return 'cssTransform';
+ },
+};
diff --git a/config/jest/fileTransform.js b/config/jest/fileTransform.js
new file mode 100644
index 000000000..07010e33a
--- /dev/null
+++ b/config/jest/fileTransform.js
@@ -0,0 +1,30 @@
+'use strict';
+
+const path = require('path');
+
+// This is a custom Jest transformer turning file imports into filenames.
+// http://facebook.github.io/jest/docs/en/webpack.html
+
+module.exports = {
+ process(src, filename) {
+ const assetFilename = JSON.stringify(path.basename(filename));
+
+ if (filename.match(/\.svg$/)) {
+ return `module.exports = {
+ __esModule: true,
+ default: ${assetFilename},
+ ReactComponent: (props) => ({
+ $$typeof: Symbol.for('react.element'),
+ type: 'svg',
+ ref: null,
+ key: null,
+ props: Object.assign({}, props, {
+ children: ${assetFilename}
+ })
+ }),
+ };`;
+ }
+
+ return `module.exports = ${assetFilename};`;
+ },
+};
diff --git a/config/paths.js b/config/paths.js
new file mode 100644
index 000000000..c24b4dd1f
--- /dev/null
+++ b/config/paths.js
@@ -0,0 +1,89 @@
+'use strict';
+
+const path = require('path');
+const fs = require('fs');
+const url = require('url');
+
+// Make sure any symlinks in the project folder are resolved:
+// https://github.com/facebook/create-react-app/issues/637
+const appDirectory = fs.realpathSync(process.cwd());
+const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
+
+const envPublicUrl = process.env.PUBLIC_URL;
+
+function ensureSlash(inputPath, needsSlash) {
+ const hasSlash = inputPath.endsWith('/');
+ if (hasSlash && !needsSlash) {
+ return inputPath.substr(0, inputPath.length - 1);
+ } else if (!hasSlash && needsSlash) {
+ return `${inputPath}/`;
+ } else {
+ return inputPath;
+ }
+}
+
+const getPublicUrl = appPackageJson =>
+ envPublicUrl || require(appPackageJson).homepage;
+
+// We use `PUBLIC_URL` environment variable or "homepage" field to infer
+// "public path" at which the app is served.
+// Webpack needs to know it to put the right