Skip to content
Permalink
Browse files

fix(website): composable do-dont, add anchor examples (#81)

* fix(website): composable do-dont, add anchor examples

* feat(website): aspect ratio component, adjust image size to be 4:3

* feat(website): regex shorthand

* feat(website): revert yarn lock, change do title props

* feat(website): add missing do title

* fix(website): callout component extends boxprops

* fix(website): updated yarn lock file

* fix(website): set node version

* fix(website): update circle node config

* fix(website): remove jsx import from aspect ration component

* fix(website): aspect ratio error changes, use absolute in do dont

* fix(website): fix aspect ration typescript error

* fix(website): remove box, use div

* feat(aspect-ratio): aspect-ratio to core utils

* fix(website): swap aspect-ratio in anchor doc page

* fix(website): add assets file-system, change image path in anchor doc

* fix(website): refactor do/dont, update anchor and button doc

* fix(aspect-ratio): add story and test

* fix(aspect-ratio): fix lint error

* fix(aspect-ratio): change prop name

* fix(website): change aspect-ratio prop in do-dont
  • Loading branch information...
richbachman committed Sep 11, 2019
1 parent 924b0a5 commit a799f1b4cf5b8552d3c1bf13b6882a9235ccb4d3
@@ -0,0 +1,19 @@
import * as React from 'react';
import {mount} from 'enzyme';
import {AspectRatio} from '../src';

describe('AspectRatio', () => {
it('should render a 4:3 aspect ratio div', () => {
const wrapper = mount(
<AspectRatio ratio="4:3">
<p>This is the AspectRatio utility.</p>
</AspectRatio>
);
expect(
wrapper
.find('div')
.first()
.props().style.paddingBottom
).toBe('75%');
});
});
@@ -0,0 +1,43 @@
{
"name": "@twilio-paste/aspect-ratio",
"version": "0.1.0",
"category": "layout",
"status": "alpha",
"description": "",
"author": "Twilio Inc.",
"license": "MIT",
"main:dev": "src/index.tsx",
"main": "dist/index.js",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"files": [
"dist"
],
"scripts": {
"build": "yarn clean && yarn compile",
"build:dev": "yarn clean && yarn compile:dev",
"clean": "rm -rf ./dist && rm -rf tsconfig.build.tsbuildinfo && rm -rf .rpt2_cache",
"compile": "rollup -c --environment NODE_ENV:production",
"compile:dev": "rollup -c --environment NODE_ENV:development",
"prepublishOnly": "yarn build",
"type-check": "tsc --noEmit"
},
"peerDependencies": {
"@emotion/styled": "^10.0.10",
"@twilio-paste/absolute": "^0.1.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"styled-system": "^4.1.0"
},
"devDependencies": {
"@twilio-paste/absolute": "^0.1.0",
"rollup": "^1.16.2",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.0.1",
"rollup-plugin-node-resolve": "^5.1.0",
"rollup-plugin-terser": "^5.0.0",
"rollup-plugin-typescript2": "^0.21.2",
"typescript": "^3.5.2"
}
}
@@ -0,0 +1,34 @@
import typescript from 'rollup-plugin-typescript2';
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import {terser} from 'rollup-plugin-terser';
import pkg from './package.json';

export default {
input: pkg['main:dev'],
output: [
{
file: pkg.main,
format: 'cjs',
},
{
file: pkg.module,
format: 'es',
},
],
external: [...Object.keys(pkg.peerDependencies || {})],
plugins: [
resolve(),
commonjs(),
typescript({
clean: true,
typescript: require('typescript'),
tsconfig: './tsconfig.build.json',
}),
babel({
exclude: 'node_modules/**',
}),
process.env.NODE_ENV === 'production' ? terser() : null,
],
};
@@ -0,0 +1,47 @@
import * as React from 'react';
import styled from '@emotion/styled';
import {Absolute} from '@twilio-paste/absolute';

interface AspectRatioProps {
ratio: string;
children: NonNullable<React.ReactNode>;
}

const RATIO_REGEX = /^(\d+:\d*)$/;

const isCorrectPattern = (ratio: string): boolean => RATIO_REGEX.test(ratio);

const handlePropValidation = ({ratio}: AspectRatioProps): void => {
const hasRatio = ratio != null && ratio !== '';

if (!hasRatio) {
throw new Error(`[Paste: AspectRatio] Missing 'ratio' prop.`);
}

if (!isCorrectPattern(ratio)) {
throw new Error(`[Paste: AspectRatio] 'ratio' is invalid. Use a colon separated number pattern (4:3).`);
}
};

const AspectRatioContainer = styled.div`
position: relative;
`;

const AspectRatio: React.FC<AspectRatioProps> = props => {
handlePropValidation(props);

const aspectArray = props.ratio.split(':').map(Number);
const aspectPercent = (aspectArray[1] / aspectArray[0]) * 100;

return (
<AspectRatioContainer style={{paddingBottom: `${aspectPercent}%`}}>
<Absolute>{props.children}</Absolute>
</AspectRatioContainer>
);
};

AspectRatio.defaultProps = {
ratio: '4:3',
};

export {AspectRatio};
@@ -0,0 +1,24 @@
import * as React from 'react';
import {storiesOf} from '@storybook/react';
import {withKnobs, text} from '@storybook/addon-knobs';
import {Box} from '@twilio-paste/box';
import {Absolute} from '@twilio-paste/absolute';
import {AspectRatio} from '../src';

storiesOf('Utilities|Aspect Ratio', module)
.addDecorator(withKnobs)
.add('Default', () => {
return (
<Box
padding="space30"
maxWidth="size40"
borderColor="colorBorderLight"
borderStyle="solid"
borderWidth="borderWidth10"
>
<AspectRatio ratio={text('ratio', '4:3')}>
<Absolute backgroundColor="colorBackgroundBrand" />
</AspectRatio>
</Box>
);
});
@@ -0,0 +1,15 @@
{
"extends": "../../../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": [
"src/**/*"
],
"references": [
{
"path": "../absolute"
}
]
}
@@ -0,0 +1,4 @@
{
"extends": "../../../../tsconfig.json",
"include": ["src/**/*"]
}
@@ -30,6 +30,13 @@ module.exports = {
],
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'assets',
path: `${__dirname}/src/assets`,
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
@@ -22,6 +22,7 @@
"@mdx-js/react": "^1.0.23",
"@mdx-js/tag": "^0.20.3",
"@twilio-paste/anchor": "^0.1.4",
"@twilio-paste/aspect-ratio": "^0.1.0",
"@twilio-paste/box": "^0.3.0",
"@twilio-paste/button": "^0.2.0",
"@twilio-paste/heading": "^0.3.3",
Binary file not shown.
@@ -1,6 +1,8 @@
import * as React from 'react';
import styled from '@emotion/styled';
import {themeGet} from 'styled-system';
import {AspectRatio} from '@twilio-paste/aspect-ratio';
import {Absolute} from '@twilio-paste/absolute';
import {Box} from '@twilio-paste/box';
import {Text} from '@twilio-paste/text';

@@ -12,70 +14,81 @@ const StyledWrapper = styled(Box)`

interface DoDontProps {
children: React.ReactNode;
do: boolean;
}

const DoDont: React.FC<DoDontProps> = props => {
return (
<StyledWrapper marginTop="space90" marginBottom="space90">
<StyledWrapper marginTop="space90" marginBottom="space130">
{props.children}
</StyledWrapper>
);
};

interface ExampleProps {
children: React.ReactNode;
const Center = styled(Absolute)`
display: flex;
align-items: center;
justify-content: center;
`;

interface DoProps {
body: string;
center: boolean;
children: NonNullable<React.ReactNode>;
do: boolean;
image?: string;
title: string;
}

const StyledExampleWraper: React.FC<ExampleProps> = styled(Box)`
border-top: ${(props: ExampleProps) =>
props.do
? `${themeGet('borderWidths.borderWidth20')(props)} solid #23bf6e`
: `${themeGet('borderWidths.borderWidth20')(props)} solid #ce241a`};
`;

const StyledExampleImg: React.FC<ExampleProps> = styled(Box)`
border: ${themeGet('borderWidths.borderWidth10')} solid #ccd2dc;
border-top: 0;
const Item: React.FC<DoProps> = ({center = false, ...props}) => {
let preview = props.children;

img {
display: block;
width: 100%;
if (center) {
preview = <Center>{props.children}</Center>;
}
`;

const Example: React.FC<ExampleProps> = props => {
const hasImage = props.image;
return (
<StyledExampleWraper {...props}>
{hasImage ? (
<StyledExampleImg {...props}>
<img src={props.image} alt="" />
</StyledExampleImg>
) : null}
<Box marginTop="space50">
<div>
<Box
borderStyle="solid"
borderTopWidth="borderWidth10"
borderRightWidth="borderWidth10"
borderBottomWidth="borderWidth0"
borderLeftWidth="borderWidth10"
borderColor="colorBorderLight"
display={props.children == null ? 'none' : 'block'}
>
<AspectRatio ratio="4:3">{preview}</AspectRatio>
</Box>
<Box
pt="space50"
borderStyle="solid"
borderTopWidth="borderWidth20"
borderRightWidth="borderWidth0"
borderBottomWidth="borderWidth0"
borderLeftWidth="borderWidth0"
borderColor={props.do ? 'colorBorderSuccess' : 'colorBorderError'}
>
<Text
as="h5"
fontSize="fontSize20"
fontWeight="fontWeightSemibold"
lineHeight="lineHeight40"
marginBottom="space40"
>
{props.do ? 'Do' : `Don't`}
{props.title}
</Text>
{props.children}
<Text>{props.body}</Text>
</Box>
</StyledExampleWraper>
</div>
);
};

const Do: React.FC<ExampleProps> = props => {
return <Example do {...props} />;
const Do: React.FC<DoProps> = props => {
return <Item {...props} do />;
};

const Dont: React.FC<ExampleProps> = props => {
return <Example do={false} {...props} />;
const Dont: React.FC<DoProps> = props => {
return <Item {...props} do={false} />;
};

export {DoDont, Do, Dont};
@@ -5,12 +5,13 @@ description: The anchor can be used to hyperlink to another URL. It accepts both
---

import {graphql} from 'gatsby';
import Img from 'gatsby-image';
import {Anchor} from '@twilio-paste/anchor';
import {Box} from '@twilio-paste/box';
import Changelog from '@twilio-paste/anchor/CHANGELOG.md';
import {DoDont, Do, Dont} from '../../../components/DoDont';
import {SidebarCategoryRoutes} from '../../../constants';
import {P} from '../../../components/Typography.tsx';
import Changelog from '@twilio-paste/anchor/CHANGELOG.md';

export const pageQuery = graphql`
{
@@ -24,6 +25,13 @@ export const pageQuery = graphql`
}
}
}
file(sourceInstanceName: {eq: "assets"}, relativePath: {eq: "images/anchor-dont-1@4x.png"}) {
childImageSharp {
fluid(maxWidth: 500) {
...GatsbyImageSharpFluid
}
}
}
}
`;
@@ -93,21 +101,17 @@ This is done for security purposes. Even though the target and rel are set by de
You can use an anchor to navigate the user to another webpage.
<DoDont>
<Do>
Anchors should only be used to link to another page, app, or another website.
<Do title="Do" body="Anchors should only be used to link to another page, app, or another website." center>
<Anchor href="https://paste.twilio.design">Go to API documentation</Anchor>
</Do>
<Dont>
Don’t use an anchor where a button makes more sense, i.e., closing a modal.
<Dont title="Don't" body="Don’t use an anchor where a button makes more sense, i.e., closing a modal.">
<Img fluid={props.data.file.childImageSharp.fluid} />
</Dont>
</DoDont>
<DoDont>
<Do>
Anchors should only include text.
</Do>
<Dont>
Don’t use an icon in place of or with anchor text.
</Dont>
<Do title="Do" body="Anchors should only include text." preview={false} />
<Dont title="Don't" body="Don’t use an icon in place of or with anchor text." preview={false} />
</DoDont>
</content>

1 comment on commit a799f1b

@now

This comment has been minimized.

Please sign in to comment.
You can’t perform that action at this time.