Skip to content
This repository has been archived by the owner on Feb 27, 2020. It is now read-only.

Commit

Permalink
Additional components (#188)
Browse files Browse the repository at this point in the history
* Updating readme, storybook will no longer embedd jest results for the time being

* Removing test specs from button

* Updating input to use css props and have a test

* Fix component creator script and add Dialog component

* Add dialog component styles and deps

* Update template info

* adding templates dir to ignore

* Fixing name on Dialog package and adding intial test

* additional test for input
  • Loading branch information
lausena committed Jul 3, 2018
1 parent 8f595b8 commit 6f008a4
Show file tree
Hide file tree
Showing 19 changed files with 307 additions and 37 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Expand Up @@ -6,7 +6,7 @@ node_modules
# testing
coverage/
test/__snapshots__
.jest-test-results.json


# production
/build
Expand Down Expand Up @@ -35,6 +35,10 @@ components/**/*.d.ts
components/**/*.js
components/**/*.map

templates/**/*.d.ts
templates/**/*.js
templates/**/*.map

utils/**/*.d.ts
utils/**/*.js
utils/**/*.map
Expand Down
10 changes: 3 additions & 7 deletions README.md
Expand Up @@ -4,7 +4,7 @@ For end-user documentation, visit: http://jenkinsci.github.io/jenkins-design-lan

The Jenkins Design Language is a React component library with associated assets and styles available to use with [Jenkins Blue Ocean](https://github.com/jenkinsci/blueocean-plugin) and extensions, as well as any other project you may choose to use this library with.

## Building
### Building

This uses `lerna` to build, but needs some specific options, so they're baked into the `package.json`:

Expand All @@ -19,15 +19,15 @@ npm run bootstrap
npm run clean
```

## Generating a new Component
### Generating a new Component

This will provide options for generating a new component within the /components.

```
$ npm run generate
```

## Storybook
### Storybook

React Storybook is an easy way to develop components with real-time feedback, run in the browser. To run Storybook, just run:

Expand All @@ -37,10 +37,6 @@ npm start

Then go to: http://localhost:9001/

### Tests within storybook

Storybook may embed test results from Jest tests. For an example, see: [Button.stories.tsx](./components/Button/Button.stories.tsx#L11). In particular, note the fact that you must return the name of the suite, e.g. `require('./Button.test') && 'Button'`.

### Testing Components

```
Expand Down
10 changes: 2 additions & 8 deletions components/Button/Button.stories.tsx
Expand Up @@ -2,12 +2,6 @@ import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { Button } from './Button';

declare var specs: any;

const stories = storiesOf('Button', module);

stories.add('should display text', () => {
const story = <Button>some-text</Button>;
specs(() => require('./Button.test.tsx') && 'Button');
return story;
storiesOf('Button', module).add('should display text', () => {
return <Button>some-text</Button>;
});
13 changes: 13 additions & 0 deletions components/Dialog/Dialog.md
@@ -0,0 +1,13 @@
TODO - add description

#### < Component > Types

```jsx
TODO;
```

#### < Component > Sizes

```jsx
TODO;
```
77 changes: 77 additions & 0 deletions components/Dialog/Dialog.scss
@@ -0,0 +1,77 @@
$dialog-spacing: 32px;
$dialog-border-radius: 3px;
$dialog-box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.5);
$dialog-background: rgb(255, 255, 255);
$dialog-overlay-background: rgba(0, 0, 0, 0.25);
$dialog-header-height: 80px;
$dialog-header-border-radius: 3px;
$dialog-header-background: #4a90e2;
$dialog-header-color: #ffffff;
$dialog-content-height: 564px;

.Dialog {
position: absolute;
box-shadow: $dialog-box-shadow;
background: $dialog-background;
border-radius: $dialog-border-radius;
border: none;
max-width: 95%;
max-height: 90%;
}

.Dialog-Overlay {
position: fixed;
background: $dialog-overlay-background;
z-index: $zindex-dialog;
left: 0;
top: 0;
bottom: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
}

.Dialog-header {
display: flex;
align-items: center;
width: 100%;
height: $dialog-header-height;
flex-shrink: 0;
color: $dialog-header-color;
background: $dialog-header-background;
border-top-left-radius: $dialog-header-border-radius;
border-top-right-radius: $dialog-header-border-radius;
padding: 0 $dialog-spacing;

> h3 {
font-size: 24px;
}
}

.Dialog-content-scroll {
overflow: auto;
flex-shrink: 1;

.Dialog--medium-size & {
max-width: $dialog-content-height;
}
}

.Dialog-content-margin {
margin: $dialog-spacing;
margin-bottom: $dialog-spacing / 2;
}

.Dialog-button-bar {
padding: 0 $dialog-spacing;
margin: $dialog-spacing / 2 0 $dialog-spacing;
display: flex;
width: 100%;
justify-content: flex-start;
flex-shrink: 0;

& > button + button {
margin-left: 0.5em;
}
}
10 changes: 10 additions & 0 deletions components/Dialog/Dialog.stories.tsx
@@ -0,0 +1,10 @@
import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { Dialog } from './Dialog';

const stories = storiesOf('Dialog', module);

stories.add('should display a modal', () => {
let content = <span>Some modal content!</span>;
return <Dialog>{content}</Dialog>;
});
15 changes: 15 additions & 0 deletions components/Dialog/Dialog.test.tsx
@@ -0,0 +1,15 @@
import * as React from 'react';
import * as Enzyme from 'enzyme';
import { Dialog } from './Dialog';

describe('Dialog', () => {
it('should render a dialog with content', () => {
const content = 'testing with some content';
const mounted = Enzyme.mount(
<Dialog>
<span>{content}</span>
</Dialog>
);
expect(mounted.find('span').get(0).props.children).toEqual(content);
});
});
95 changes: 95 additions & 0 deletions components/Dialog/Dialog.tsx
@@ -0,0 +1,95 @@
import * as React from 'react';
import * as ReactModal from 'react-modal';
import * as classNames from 'classnames';

export interface DialogProps {
readonly title?: string;
readonly className?: string;
readonly onDismiss?: () => void;
readonly shouldCloseOnEsc?: boolean;
children: JSX.Element;
}

export interface DialogState {
readonly showModal: boolean;
}

export class Dialog extends React.Component<DialogProps, DialogState> {
constructor(props: DialogProps) {
super(props);

this.state = { showModal: true };
this.handleCloseModal = this.handleCloseModal.bind(this);
}

handleCloseModal() {
this.setState({
...this.state,
showModal: false,
});

if (this.props.onDismiss) {
this.props.onDismiss();
}
}

render() {
const shouldCloseOnEsc = this.props.hasOwnProperty('shouldCloseOnEsc')
? this.props.shouldCloseOnEsc
: true;

const defaultProps = {
className: classNames('Dialog', this.props.className),
overlayClassName: 'Dialog-Overlay',
onRequestClose: this.handleCloseModal,
isOpen: this.state.showModal,
shouldCloseOnEsc,
};

return (
<div>
<ReactModal {...defaultProps} ariaHideApp={false}>
{this.props.title && <DialogHeader title={this.props.title} />}
<DialogContent>{this.props.children}</DialogContent>
<DialogButtons>
<div className="Button" onClick={this.handleCloseModal}>
Close
</div>
</DialogButtons>
</ReactModal>
</div>
);
}
}

export interface DialogHeaderProps {
title: string;
}

export function DialogHeader(props: DialogHeaderProps) {
return (
<div className="Dialog-header">
<h3>{props.title}</h3>
</div>
);
}

export interface DialogContentProps {
children: JSX.Element;
}

export function DialogContent(props: DialogContentProps) {
return (
<div className="Dialog-content-scroll">
<div className="Dialog-content-margin">{props.children}</div>
</div>
);
}

export interface DialogButtonsProps {
children: JSX.Element;
}

export function DialogButtons(props: DialogButtonsProps) {
return <div className="Dialog-button-bar">{props.children}</div>;
}
3 changes: 3 additions & 0 deletions components/Dialog/README.md
@@ -0,0 +1,3 @@
# Your component

This is < component > documentation
43 changes: 43 additions & 0 deletions components/Dialog/package.json
@@ -0,0 +1,43 @@
{
"name": "@jdl2/dialog",
"version": "0.0.1",
"main": "./Dialog",
"scripts": {
"build": "tsc",
"test": "jest"
},
"files": [
"*.js",
"*.d.ts",
"*.d.map",
"*.scss"
],
"dependencies": {
"prop-types": "*",
"react": "*",
"react-addons-css-transition-group": "*",
"react-dom": "*"
},
"devDependencies": {
"@storybook/addon-jest": "^3.4.8",
"@types/classnames": "^2.2.4",
"@types/enzyme": "^3.1.9",
"@types/react": "*",
"@types/react-addons-css-transition-group": "*",
"@types/react-dom": "*",
"@types/react-modal": "^3.1.2",
"@types/react-test-renderer": "^16.0.1",
"@types/react-transition-group": "*",
"classnames": "^2.2.6",
"enzyme": "^3.3.0",
"jest": "^22.4.2",
"jest-storybook-facade": "0.0.8",
"react-modal": "^3.4.5",
"react-test-renderer": "^16.4.1",
"storybook-addon-specifications": "^2.1.2",
"typescript": "*"
},
"jest": {
"preset": "typewebjest/jest-preset.json"
}
}
3 changes: 3 additions & 0 deletions components/Dialog/tsconfig.json
@@ -0,0 +1,3 @@
{
"extends": "../../tsconfig.json"
}
5 changes: 2 additions & 3 deletions components/Input/Input.stories.tsx
Expand Up @@ -2,7 +2,6 @@ import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { Input } from './Input';

storiesOf('Input', module)
.add('should display an input', () => {
return <Input onChange={() => console.log('')} />;
storiesOf('Input', module).add('should display an input', () => {
return <Input />;
});
18 changes: 13 additions & 5 deletions components/Input/Input.test.tsx
@@ -1,9 +1,17 @@
describe('Description: ', () => {
it('should contain 3 items', () => {
expect(3).toBe(3);
import * as React from 'react';
import * as Enzyme from 'enzyme';
import { Input } from './Input';

describe('Input: ', () => {
it('should display correct input', () => {
const input = Enzyme.mount(<Input onChange={e => console.log(e)} />);
input.simulate('change', { target: { value: 'changed value.' } });
expect(input.length).toBe(1);
});

it('should work fine', () => {
expect(true).toBe(true);
it('should display an input without onchange set', () => {
const input = Enzyme.mount(<Input />);
input.simulate('change', { target: { value: 'changed value.' } });
expect(input.length).toBe(1);
});
});
18 changes: 14 additions & 4 deletions components/Input/Input.tsx
@@ -1,11 +1,21 @@
import * as React from 'react';
import { css, CssProps } from '@jdl2/css-util';

export interface InputProps {
onChange: (value: string) => void;
export interface InputProps extends CssProps {
onChange?: (value: string) => void;
}

export function Input({ onChange }: InputProps) {
export function Input(props: InputProps) {
const { onChange } = props;
return (
<input className="input input-error" type="text" onChange={e => onChange(e.target.value)} />
<input
className={css(props, 'input input-error')}
type="text"
onChange={e => {
if (onChange) {
onChange(e.target.value);
}
}}
/>
);
}

0 comments on commit 6f008a4

Please sign in to comment.