[design]: initialize design system

This commit is contained in:
41666 2019-05-20 00:57:55 -04:00
parent 6fb39d6c4d
commit b864df9393
No known key found for this signature in database
GPG key ID: BC51D07640DC10AF
14 changed files with 391 additions and 0 deletions

3
packages/roleypoly-design/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
lib
node_modules
*.log

View file

@ -0,0 +1,2 @@
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';

View file

@ -0,0 +1,8 @@
import { configure } from '@storybook/react'
const req = require.context('../src', true, /\.stor\bies|y\b\.[tj]sx?$/)
function loadStories() {
req.keys().forEach(req)
}
configure(loadStories, module)

View file

@ -0,0 +1,16 @@
module.exports = ({ config }) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
use: [
{
loader: require.resolve('awesome-typescript-loader'),
},
// Optional
{
loader: require.resolve('react-docgen-typescript-loader'),
},
],
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};

View file

@ -0,0 +1,9 @@
{
"processors": [
"stylelint-processor-styled-components"
],
"extends": [
"stylelint-config-recommended",
"stylelint-config-styled-components"
]
}

View file

@ -0,0 +1,42 @@
{
"private": true,
"name": "@roleypoly/design",
"version": "2.0.0",
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6",
"styled-components": "^4.2.0"
},
"files": [
"lib"
],
"devDependencies": {
"@babel/core": "^7.4.4",
"@storybook/addon-actions": "^5.0.11",
"@storybook/addon-info": "^5.0.11",
"@storybook/addon-knobs": "^5.0.11",
"@storybook/addon-links": "^5.0.11",
"@storybook/addons": "^5.0.11",
"@storybook/react": "^5.0.11",
"@types/jest": "^24.0.13",
"@types/node": "^12.0.2",
"@types/react": "^16.8.17",
"@types/react-dom": "^16.8.4",
"@types/storybook__addon-actions": "^3.4.2",
"@types/storybook__addon-knobs": "^5.0.0",
"@types/storybook__addon-links": "^3.3.4",
"@types/storybook__react": "^4.0.1",
"@types/styled-components": "4.1.8",
"awesome-typescript-loader": "^5.2.1",
"babel-loader": "^8.0.6",
"react-docgen-typescript-loader": "^3.1.0",
"stylelint": "^10.0.1",
"tslint": "^5.16.0",
"tslint-config-standard": "^8.0.1",
"typescript": "^3.4.5"
},
"scripts": {
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
}
}

View file

@ -0,0 +1,12 @@
import * as React from 'react'
import { storiesOf } from '@storybook/react'
import Button from './Button'
const s = storiesOf('Button', module)
s.add('Default', () => <Button>Example</Button>)
s.add('Disabled', () => <Button>Example</Button>)
s.add('Primary', () => <Button>Example</Button>)
s.add('Secondary', () => <Button>Example</Button>)
s.add('Loading', () => <Button>Example</Button>)

View file

@ -0,0 +1,10 @@
import * as React from 'react'
import {
StyledButton
} from './styled-components'
const Button = ({ children, ...rest }: { children: React.ReactChild | React.ReactChild[] }) => <StyledButton {...rest}>
{children}
</StyledButton>
export default Button

View file

@ -0,0 +1,5 @@
export { default as default } from './Button'
export {
StyledButton
} from './styled-components'

View file

@ -0,0 +1,58 @@
// import * as React from 'react'
import styled from 'styled-components'
export const StyledButton = styled.button`
/* reset some styles */
box-shadow: none;
appearance: none;
outline: none;
cursor: pointer;
background-color: rgba(0,0,0,0.1);
/* real styles */
position: relative;
transition: all 0.05s ease-in-out;
padding: 1em 1.4em;
font-weight: bold;
border: 1px solid rgba(0,0,0,0.1);
&::after {
content: "";
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
/* transparent by default */
background-color: transparent;
transition: background-color 0.05s ease-in-out;
/* put the overlay behind the text */
z-index: -1;
}
/* on hover, raise, brighten and shadow */
&:hover {
transform: translateY(-1px);
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
&::after {
background-color: rgba(255, 255, 255, 0.3);
}
}
/* on click, lower and darken */
&:active {
outline: none;
box-shadow: none;
border-color: rgba(0,0,0,0.2);
transform: translateY(0);
&::after {
background-color: rgba(0, 0, 0, 0.1);
}
}
`

View file

@ -0,0 +1,34 @@
/*
Copyright (c) 2018-2019 Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
export default function deepMerge (
target?: {},
...sources: Array<null | {}>
): {} {
target = target || {}
const len = sources.length
let obj
let value
for (let i = 0; i < len; i++) {
obj = sources[i] || {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
value = obj[key]
if (isCloneable(value)) {
target[key] = deepMerge(target[key] || {}, value)
} else {
target[key] = value
}
}
}
}
return target
}
/* eslint-disable-next-line flowtype/no-weak-types */
function isCloneable(obj: Object) {
return Array.isArray(obj) || {}.toString.call(obj) === '[object Object]'
}

View file

@ -0,0 +1,151 @@
/*
Copyright (c) 2018-2019 Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
import * as React from 'react'
import deepMerge from './deep-merge'
export type StyleOverrideT = {} | (({ }) => {} | undefined)
export type OverrideObjectT<T> = {
component?: React.ComponentType<T>,
props?: {},
style?: StyleOverrideT
}
export type OverrideT<T> = OverrideObjectT<T> | React.ComponentType<T>
export type OverridesT<T> = {
[x: string]: OverrideT<T>
}
/**
* Given an override argument, returns the component implementation override if it exists
*/
// eslint-disable-next-line flowtype/no-weak-types
export function getOverride (override: any): any {
// Check if override is OverrideObjectT
if (override && typeof override === 'object') {
// Remove this 'any' once this flow issue is fixed:
// https://github.com/facebook/flow/issues/6666
// eslint-disable-next-line flowtype/no-weak-types
return override.component
}
// Otherwise it must be a component type (function or class) or null/undefined
return override
}
/**
* Given an override argument, returns the override props that should be passed
* to the component when rendering it.
*/
export function getOverrideProps<T> (override?: OverrideT<T>) {
if (override && typeof override === 'object') {
return {
// $FlowFixMe
...override.props,
// $FlowFixMe
$style: override.style
}
}
return {}
}
/**
* Coerces an override argument into an override object
* (sometimes it is just an override component)
*/
export function toObjectOverride<T> (
override: OverrideT<T>
): OverrideObjectT<T> {
if (typeof override === 'function') {
return {
component: (override)
}
}
// Flow can't figure out that typeof 'function' above will
// catch React.StatelessFunctionalComponent
// (probably related to https://github.com/facebook/flow/issues/6666)
// eslint-disable-next-line flowtype/no-weak-types
return (((override || {}) as any) as OverrideObjectT<T>)
}
/**
* Get a convenient override array that will always have [component, props]
*/
/* eslint-disable flowtype/no-weak-types */
export function getOverrides (
override: any,
defaultComponent: React.ComponentType<any>
): [React.ComponentType<any>, {}] {
const component = getOverride(override) || defaultComponent
const props = getOverrideProps(override)
return [component, props]
}
/* eslint-enable flowtype/no-weak-types */
/**
* Merges two overrides objects this is useful if you want to inject your own
* overrides into a child component, but also accept further overrides from
* from upstream. See `mergeOverride` below.
*/
export function mergeOverrides<T> (
target: OverridesT<T> | undefined = {},
source: OverridesT<T> | undefined = {}
): OverridesT<T> {
const allIdentifiers = Object.keys({ ...target, ...source })
return allIdentifiers.reduce((acc, name) => {
acc[name] = mergeOverride(
toObjectOverride(target[name]),
toObjectOverride(source[name])
)
return acc
}, {})
}
/**
* Merges two override objects using the following behavior:
* - Component implementation from the source (parent) replaces target
* - Props and styles are both deep merged
*/
export function mergeOverride<T> (
target: OverrideObjectT<T>,
source: OverrideObjectT<T>
): OverrideObjectT<T> {
// Shallow merge should handle `component`
const merged = { ...target, ...source }
// Props just use deep merge
if (target.props && source.props) {
merged.props = deepMerge({}, target.props, source.props)
}
// Style overrides need special merging since they may be functions
if (target.style && source.style) {
merged.style = mergeStyleOverrides(target.style, source.style)
}
return merged
}
/**
* Since style overrides can be an object *or* a function, we need to handle
* the case that one of them is a function. We do this by returning a new
* function that deep merges the result of each style override
*/
export function mergeStyleOverrides (
target: StyleOverrideT,
source: StyleOverrideT
): StyleOverrideT {
// Simple case of both objects
if (typeof target === 'object' && typeof source === 'object') {
return deepMerge({}, target, source)
}
// At least one is a function, return a new composite function
return (...args) => {
return deepMerge(
{},
typeof target === 'function' ? target(...args) : target,
typeof source === 'function' ? source(...args) : source
)
}
}

View file

@ -0,0 +1,38 @@
{
"compilerOptions": {
"outDir": "./lib",
"module": "commonjs",
"target": "es2018",
"lib": [
"es5",
"es6",
"es7",
"es2017",
"dom"
],
"sourceMap": true,
"allowJs": false,
"jsx": "react",
"moduleResolution": "node",
"rootDirs": [
"src"
],
"baseUrl": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"declaration": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"exclude": [
"node_modules",
"build",
"scripts"
]
}

View file

@ -0,0 +1,3 @@
{
"extends": "tslint-config-standard"
}