Commit 46959b90 authored by Mickaël Bourgier's avatar Mickaël Bourgier
Browse files

🏷 Add Typescript support

parent 0433f1e6
......@@ -7,16 +7,16 @@ module.exports = {
[
'@babel/preset-env',
{
modules: test || cjs ? 'cjs' : false
}
modules: test || cjs ? 'cjs' : false,
},
],
'@babel/preset-react'
'@babel/preset-react',
],
plugins: ['@babel/plugin-proposal-class-properties', 'dev-expression'],
ignore: [
...(cjs || es ? [/demos\/.+\.js/] : []),
...(test ? [] : [/\.test\.js/])
]
...(test ? [] : [/\.test\.js/]),
],
};
......@@ -7,6 +7,7 @@ const formatPropType = (propType, depth = 0) => {
case 'arrayOf':
return `[ ${formatPropType(propType.value)}, ... ]`;
case 'bool':
case 'boolean':
return 'Boolean';
case 'element':
return 'Element';
......@@ -42,7 +43,7 @@ const formatPropType = (propType, depth = 0) => {
return propType.value.map((child) => formatPropType(child)).join(' | ');
}
return '???';
return propType.name.replace(/"/g, "'");
};
export default formatPropType;
const parse = require('react-docgen').parse;
const path = require('path');
const parseJs = require('react-docgen').parse;
const parseTs = require('react-docgen-typescript').withCustomConfig(
path.resolve(__dirname, '../../tsconfig.json')
).parse;
module.exports = function (source) {
this.cacheable && this.cacheable();
......@@ -6,9 +11,11 @@ module.exports = function (source) {
let value = {};
try {
value = parse(source, null, null, {
filename: this.resourcePath,
});
value = /\.tsx?$/.test(this.resourcePath)
? parseTs(this.resourcePath)[0]
: parseJs(source, null, null, {
filename: this.resourcePath,
});
} catch (e) {
// ignore exception
}
......
module.exports = {
coverageReporters: ['text-summary'],
moduleNameMapper: {
'^@webalt/react(.*)$': '<rootDir>/src/$1'
'^@webalt/react(.*)$': '<rootDir>/src/$1',
},
roots: ['<rootDir>/src'],
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect']
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
};
module.exports = {
singleQuote: true,
jsxSingleQuote: true
jsxSingleQuote: true,
};
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
import { withStyles } from '../styles';
import { ObjectOf } from '../types';
import styles from './Box.styles';
/**
* @summary Boîte stylisée en fonction des couleurs du thème
*/
class Box extends Component {
render() {
const {
classes,
className: classNameProps,
color,
component: Component = 'div',
disabled,
htmlDisabled,
interactive = false,
muted,
shadow = false,
shape = 'square',
theme,
transitions = true,
variant = 'plain',
...otherProps
} = this.props;
return (
<Component
className={classNames(
classes.root,
classes[`${color}Color`],
classes[`${variant}Variant`],
classes[`${shape}Shape`],
{
[classes.shadow]: shadow,
[classes.muted]: muted,
[classes.disabled]: disabled,
[classes.interactive]: interactive,
[classes.transitions]: interactive && transitions,
},
classNameProps
)}
disabled={htmlDisabled}
{...otherProps}
/>
);
}
}
Box.propTypes = {
export interface BoxProps {
/**
* Contenu du composant
*/
children: PropTypes.node,
children?: React.ReactNode;
/**
* Objet permettant de modifier les classes utilisées par le composant
*/
classes: PropTypes.object,
classes?: ObjectOf<string>;
/**
* Nom(s) de classe(s) CSS à inclure dans le composant racine
*/
className: PropTypes.string,
className?: string;
/**
* Couleur de la boîte
*/
color: PropTypes.oneOfType([
PropTypes.oneOf([
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
]),
PropTypes.string,
]),
color?:
| 'primary'
| 'secondary'
| 'success'
| 'danger'
| 'warning'
| 'info'
| 'light'
| 'dark'
| string;
/**
* Composant à utiliser en tant que composant racine
*
* @default 'div'
*/
component: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.object,
]),
component?: React.ElementType;
/**
* Désactive la boîte : elle perd sa couleur et devient grise
*
* @default false
*/
disabled: PropTypes.bool,
disabled?: boolean;
/**
* Permet de fournir la prop `disabled` à l'élément sous-jacent
*/
htmlDisabled: PropTypes.bool,
htmlDisabled?: boolean;
/**
* Active les effets sur les pseudo-classe `:hover`, `:focus` et `:active`
*
* @default false
*/
interactive: PropTypes.bool,
interactive?: boolean;
/**
* Rend la boîte muette : elle garde sa couleur mais devient peu visible
*
* @default false
*/
muted: PropTypes.bool,
muted?: boolean;
/**
* Ajoute une ombre
*
* @default false
*/
shadow: PropTypes.bool,
shadow?: boolean;
/**
* Forme de la boîte
*
* @default 'square'
*/
shape: PropTypes.oneOf(['circle', 'rounded', 'square']),
shape?: 'circle' | 'rounded' | 'square';
/** @ignore */
theme: PropTypes.object,
theme?: ObjectOf<string>;
/**
* Active ou non les transitions sur les propriétés qui changent avec les
* intéractions de l'utilisateur (uniquement utilisée en combinaison avec la
* prop `interactive`)
*
* @default true
*/
transitions: PropTypes.bool,
transitions?: boolean;
/**
* Variante de la boîte
*
* @default 'plain'
*/
variant: PropTypes.oneOf(['text', 'outline', 'plain', 'gradient']),
variant?: 'text' | 'outline' | 'plain' | 'gradient';
}
/**
* @summary Boîte stylisée en fonction des couleurs du thème
*/
export const Box = (props: BoxProps) => {
const {
classes,
className: classNameProps,
color,
component: Component = 'div',
disabled = false,
htmlDisabled,
interactive = false,
muted = false,
shadow = false,
shape = 'square',
theme,
transitions = true,
variant = 'plain',
...otherProps
} = props;
return (
<Component
className={classNames(
classes.root,
classes[`${color}Color`],
classes[`${variant}Variant`],
classes[`${shape}Shape`],
{
[classes.shadow]: shadow,
[classes.muted]: muted,
[classes.disabled]: disabled,
[classes.interactive]: interactive,
[classes.transitions]: interactive && transitions,
},
classNameProps
)}
disabled={htmlDisabled}
{...otherProps}
/>
);
};
export default withStyles(styles, { withTheme: true })(Box);
type ObjectOf<T> = { [key: string]: T };
export default ObjectOf;
export { default as ObjectOf } from './ObjectOf';
{
"compilerOptions": {
"baseUrl": "./",
"esModuleInterop": true,
"jsx": "react",
"paths": {
"@webalt/react/*": ["src/*"],
"__config/*": ["docs/config/*"],
"__src/*": ["docs/src/*"]
},
"sourceMap": true
}
}
......@@ -16,42 +16,47 @@ module.exports = {
[`app${production ? '.min' : ''}`]: path.resolve(
__dirname,
'docs/src/index.js'
)
),
}
: {
'react.webf': path.resolve(__dirname, 'src/index.js'),
...(production
? { 'react.webf.min': path.resolve(__dirname, 'src/index.js') }
: {})
: {}),
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, docs ? 'docs/dist' : 'dist'),
publicPath: '/'
publicPath: '/',
},
module: {
rules: [
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
loader: 'ts-loader',
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
cacheDirectory: true,
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
use: ['style-loader', 'css-loader'],
},
{
test: /\.html$/,
loader: 'html-loader'
}
]
loader: 'html-loader',
},
],
},
plugins: docs
......@@ -60,11 +65,11 @@ module.exports = {
alwaysWriteToDisk: true,
hash: true,
meta: {
viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no'
viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no',
},
template: path.resolve(__dirname, 'docs/static/index.html')
template: path.resolve(__dirname, 'docs/static/index.html'),
}),
new HtmlWebpackHarddiskPlugin()
new HtmlWebpackHarddiskPlugin(),
]
: [],
......@@ -72,8 +77,10 @@ module.exports = {
alias: {
'@webalt/react': path.resolve(__dirname, 'src'),
__config: path.resolve(__dirname, 'docs/config'),
__src: path.resolve(__dirname, 'docs/src')
}
__src: path.resolve(__dirname, 'docs/src'),
},
extensions: ['.js', '.ts', '.tsx'],
},
resolveLoader: {
......@@ -81,27 +88,27 @@ module.exports = {
'react-docgen': path.resolve(
__dirname,
'docs/webpack-loaders/react-docgen'
)
}
),
},
},
optimization: {
minimize: true,
minimizer: [
new UglifyJsPlugin({
include: /\.min\.js$/
})
]
include: /\.min\.js$/,
}),
],
},
devServer: {
contentBase: path.join(__dirname, 'docs/dist'),
compress: true,
historyApiFallback: {
index: 'index.html'
index: 'index.html',
},
host: '0.0.0.0'
host: '0.0.0.0',
},
devtool: production ? 'source-map' : 'cheap-module-eval-source-map'
devtool: production ? 'source-map' : 'cheap-module-eval-source-map',
};
......@@ -1266,14 +1266,14 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react-dom@*":
"@types/react-dom@*", "@types/react-dom@^16.9.7":
version "16.9.7"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.7.tgz#60844d48ce252d7b2dccf0c7bb937130e27c0cd2"
integrity sha512-GHTYhM8/OwUCf254WO5xqR/aqD3gC9kSTLpopWGpQLpnw23jk44RvMHsyUSEplvRJZdHxhJGMMLF0kCPYHPhQA==
dependencies:
"@types/react" "*"
"@types/react@*":
"@types/react@*", "@types/react@^16.9.34":
version "16.9.34"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349"
integrity sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow==
......@@ -2268,7 +2268,7 @@ caseless@~0.12.0:
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2:
chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
......@@ -3204,7 +3204,7 @@ enhanced-resolve@4.1.0:
memory-fs "^0.4.0"
tapable "^1.0.0"
enhanced-resolve@^4.1.0:
enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66"
integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==
......@@ -5600,7 +5600,7 @@ loader-utils@1.2.3:
emojis-list "^2.0.0"
json5 "^1.0.1"
loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
......@@ -5818,7 +5818,7 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
micromatch@^4.0.2:
micromatch@^4.0.0, micromatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
......@@ -6950,6 +6950,11 @@ react-codemirror2@^7.1.0:
resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-7.1.0.tgz#b874a275ad4f6f2ee5adb23b550c0f4b8b82776d"
integrity sha512-Rel0QbPnCTjHxgZYt6TkGw4icSZXNyONHb72a+1wWA+PlYJIvzFAv4pZlDPG0rpKpKmy4kSUlkoWgneH7w3A0g==
react-docgen-typescript@^1.16.4:
version "1.16.4"
resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-1.16.4.tgz#9a9674d25a02704c5e3dafa76f7ea928aca336a3"
integrity sha512-9NkfxDnLB+zYPRE4JBWoNc/JB0N1YWkZEq91al4F/e6BGMKHtAOESaEmrqdooxBLlxDhGKUGCXhPGJHHsG6bFQ==
react-docgen@^5.2.1:
version "5.3.0"
resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.3.0.tgz#9aabde5e69f1993c8ba839fd9a86696504654589"
......@@ -8406,6 +8411,17 @@ trough@^1.0.0:
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==
ts-loader@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.2.tgz#465bc904aea4c331e9550e7c7d75dd17a0b7c24c"
integrity sha512-DwpZFB67RoILQHx42dMjSgv2STpacsQu5X+GD/H9ocd8IhU0m8p3b/ZrIln2KmcucC6xep2PdEMEblpWT71euA==
dependencies:
chalk "^2.3.0"
enhanced-resolve "^4.0.0"
loader-utils "^1.0.2"
micromatch "^4.0.0"
semver "^6.0.0"
tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
version "1.11.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
......@@ -8482,6 +8498,11 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^3.8.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
ua-parser-js@^0.7.18:
version "0.7.21"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment