diff --git a/.gitignore b/.gitignore
index 29013a1..89b38ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@ node_modules
# testing
coverage/
test/__snapshots__
-.jest-test-results.json
+
# production
/build
@@ -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
diff --git a/README.md b/README.md
index cbf59b6..7fa45ff 100644
--- a/README.md
+++ b/README.md
@@ -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`:
@@ -19,7 +19,7 @@ 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.
@@ -27,7 +27,7 @@ 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:
@@ -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
```
diff --git a/components/Button/Button.stories.tsx b/components/Button/Button.stories.tsx
index c6984b0..a12e88d 100644
--- a/components/Button/Button.stories.tsx
+++ b/components/Button/Button.stories.tsx
@@ -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 = ;
- specs(() => require('./Button.test.tsx') && 'Button');
- return story;
+storiesOf('Button', module).add('should display text', () => {
+ return ;
});
diff --git a/components/Dialog/Dialog.md b/components/Dialog/Dialog.md
new file mode 100644
index 0000000..99fed3a
--- /dev/null
+++ b/components/Dialog/Dialog.md
@@ -0,0 +1,13 @@
+TODO - add description
+
+#### < Component > Types
+
+```jsx
+TODO;
+```
+
+#### < Component > Sizes
+
+```jsx
+TODO;
+```
diff --git a/components/Dialog/Dialog.scss b/components/Dialog/Dialog.scss
new file mode 100644
index 0000000..a07ce74
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/components/Dialog/Dialog.stories.tsx b/components/Dialog/Dialog.stories.tsx
new file mode 100644
index 0000000..f9eec31
--- /dev/null
+++ b/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 = Some modal content!;
+ return ;
+});
diff --git a/components/Dialog/Dialog.test.tsx b/components/Dialog/Dialog.test.tsx
new file mode 100644
index 0000000..9927178
--- /dev/null
+++ b/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(
+
+ );
+ expect(mounted.find('span').get(0).props.children).toEqual(content);
+ });
+});
diff --git a/components/Dialog/Dialog.tsx b/components/Dialog/Dialog.tsx
new file mode 100644
index 0000000..7780709
--- /dev/null
+++ b/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 {
+ 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 (
+
+
+ {this.props.title && }
+ {this.props.children}
+
+
+ Close
+
+
+
+
+ );
+ }
+}
+
+export interface DialogHeaderProps {
+ title: string;
+}
+
+export function DialogHeader(props: DialogHeaderProps) {
+ return (
+
+
{props.title}
+
+ );
+}
+
+export interface DialogContentProps {
+ children: JSX.Element;
+}
+
+export function DialogContent(props: DialogContentProps) {
+ return (
+
+ );
+}
+
+export interface DialogButtonsProps {
+ children: JSX.Element;
+}
+
+export function DialogButtons(props: DialogButtonsProps) {
+ return {props.children}
;
+}
diff --git a/components/Dialog/README.md b/components/Dialog/README.md
new file mode 100644
index 0000000..40a2b87
--- /dev/null
+++ b/components/Dialog/README.md
@@ -0,0 +1,3 @@
+# Your component
+
+This is < component > documentation
diff --git a/components/Dialog/package.json b/components/Dialog/package.json
new file mode 100644
index 0000000..6642815
--- /dev/null
+++ b/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"
+ }
+}
diff --git a/components/Dialog/tsconfig.json b/components/Dialog/tsconfig.json
new file mode 100644
index 0000000..63b5082
--- /dev/null
+++ b/components/Dialog/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../../tsconfig.json"
+}
diff --git a/components/Input/Input.stories.tsx b/components/Input/Input.stories.tsx
index 8cb0502..c27db8c 100644
--- a/components/Input/Input.stories.tsx
+++ b/components/Input/Input.stories.tsx
@@ -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 console.log('')} />;
+storiesOf('Input', module).add('should display an input', () => {
+ return ;
});
diff --git a/components/Input/Input.test.tsx b/components/Input/Input.test.tsx
index a99b363..1ab0436 100644
--- a/components/Input/Input.test.tsx
+++ b/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( 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.simulate('change', { target: { value: 'changed value.' } });
+ expect(input.length).toBe(1);
});
});
diff --git a/components/Input/Input.tsx b/components/Input/Input.tsx
index 9318976..8481922 100644
--- a/components/Input/Input.tsx
+++ b/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 (
- onChange(e.target.value)} />
+ {
+ if (onChange) {
+ onChange(e.target.value);
+ }
+ }}
+ />
);
}
diff --git a/components/Input/package.json b/components/Input/package.json
index 59d144b..76c2580 100644
--- a/components/Input/package.json
+++ b/components/Input/package.json
@@ -18,6 +18,7 @@
"access": "public"
},
"dependencies": {
+ "@jdl2/css-util": "^2.0.0-alpha.9",
"prop-types": "*",
"react": "*",
"react-addons-css-transition-group": "*",
diff --git a/css/index.scss b/css/index.scss
index 4fa7a43..6d1e486 100644
--- a/css/index.scss
+++ b/css/index.scss
@@ -4,6 +4,7 @@
@import '../components/Button/Button.scss';
@import '../components/Table/Table.scss';
@import '../components/Input/Input.scss';
+@import '../components/Dialog/Dialog.scss';
.clickable {
cursor: pointer;
diff --git a/jdl-component-creator.js b/jdl-component-creator.js
index 41af46a..841a44a 100755
--- a/jdl-component-creator.js
+++ b/jdl-component-creator.js
@@ -6,7 +6,7 @@ const TEMPLATE_CHOICE_NAME = 'template-choice';
const COMPONENT_NAME = 'component-name';
const filePrefixesToNotModify = ['README', 'package', 'tsconfig'];
-const templateChoices = fs.readdirSync(`${__dirname}/components/templates`);
+const templateChoices = fs.readdirSync(`${__dirname}/templates`);
const questions = [
{
@@ -29,7 +29,7 @@ const questions = [
inquirer.prompt(questions).then(answers => {
const templateChoice = answers[TEMPLATE_CHOICE_NAME];
const componentChoice = answers[COMPONENT_NAME];
- const templatePath = `${__dirname}/components/templates/${templateChoice}`;
+ const templatePath = `${__dirname}/templates/${templateChoice}`;
fs.mkdirSync(`${__dirname}/components/${componentChoice}`);
diff --git a/templates/base/index.stories.tsx b/templates/base/index.stories.tsx
index 4019b90..ca06bf6 100644
--- a/templates/base/index.stories.tsx
+++ b/templates/base/index.stories.tsx
@@ -4,12 +4,9 @@
// 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 = ;
-// specs(() => require('./Button.test.tsx') && 'Button');
// return story;
// });
diff --git a/templates/base/index.test.tsx b/templates/base/index.test.tsx
index 9173e0e..c9566ad 100644
--- a/templates/base/index.test.tsx
+++ b/templates/base/index.test.tsx
@@ -1,9 +1,10 @@
-import * as React from 'react';
-import * as Enzyme from 'enzyme';
-
// TODO rewrite for your component
+
+// import * as React from 'react';
+// import * as Enzyme from 'enzyme';
+
describe('Component', () => {
- it('should create and render a button with text', () => {
+ it('should ...', () => {
expect(true).toBe(true);
});
});