Adding Form component

This commit is contained in:
Jeff Avallone 2018-02-13 21:23:49 -05:00
parent 597cce4566
commit b83f5cd34d
7 changed files with 300 additions and 9 deletions

View File

@ -1,6 +1,33 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Message rendering 1`] = `
<React.Fragment>
<Translate(Form)
downloadUrls={
Array [
Object {
"filename": "image.svg",
"label": "Download SVG",
"type": "image/svg+xml",
"url": "#svg",
},
Object {
"filename": "image.png",
"label": "Download PNG",
"type": "image/png",
"url": "#png",
},
]
}
onSubmit={[Function]}
permalinkUrl="#permalink"
syntaxes={
Object {
"js": "JavaScript",
"pcre": "PCRE",
}
}
/>
<Message
heading="React App"
>
@ -8,4 +35,5 @@ exports[`Message rendering 1`] = `
Placeholder app content
</p>
</Message>
</React.Fragment>
`;

View File

@ -1,11 +1,29 @@
import React from 'react';
import Form from 'components/Form';
import Message from 'components/Message';
const App = () => (
const syntaxes = {
js: 'JavaScript',
pcre: 'PCRE'
};
const downloadUrls = [
{ url: '#svg', filename: 'image.svg', type: 'image/svg+xml', label: 'Download SVG' },
{ url: '#png', filename: 'image.png', type: 'image/png', label: 'Download PNG' }
];
const handleSubmit = ({ expr, syntax}) => console.log(syntax, expr); // eslint-disable-line no-console
const App = () => <React.Fragment>
<Form
syntaxes={ syntaxes }
downloadUrls={ downloadUrls }
permalinkUrl="#permalink"
onSubmit={ handleSubmit }/>
<Message heading="React App">
<p>Placeholder app content</p>
</Message>
);
</React.Fragment>;
export default App;

View File

@ -0,0 +1,46 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Form rendering 1`] = `
<div
className="form"
>
<form
onSubmit={[Function]}
>
<textarea
autoFocus={true}
onKeyPress={[Function]}
placeholder="translate(Enter regular expression to display)"
/>
<button
type="submit"
>
<Trans>
Display
</Trans>
</button>
<div
className="select"
>
<select>
<option
key="js"
value="js"
>
Javascript
</option>
<option
key="pcre"
value="pcre"
>
PCRE
</option>
</select>
<SvgMock />
</div>
<ul
className="inline with-separator actions"
/>
</form>
</div>
`;

View File

@ -0,0 +1,94 @@
import React from 'react';
import PropTypes from 'prop-types';
import { translate, Trans } from 'react-i18next';
import DownloadIcon from 'feather-icons/dist/icons/download.svg';
import LinkIcon from 'feather-icons/dist/icons/link.svg';
import ExpandIcon from 'feather-icons/dist/icons/chevrons-down.svg';
import style from './style.css';
class Form extends React.Component {
handleSubmit = event => {
event.preventDefault();
this.props.onSubmit.call(this, {
expr: this.textarea.value,
syntax: this.syntax.value
});
}
handleKeyPress = event => {
if (event.charCode === 13 && event.shiftKey) {
this.handleSubmit(event);
}
}
textareaRef = textarea => this.textarea = textarea
syntaxRef = syntax => this.syntax = syntax
permalinkAction() {
const { permalinkUrl } = this.props;
if (!permalinkUrl) {
return;
}
return <li>
<a href={ permalinkUrl }><LinkIcon/><Trans>Permalink</Trans></a>
</li>;
}
downloadActions() {
const { downloadUrls } = this.props;
if (!downloadUrls) {
return;
}
return downloadUrls.map(({ url, filename, type, label }, i) => <li key={ i }>
<a href={ url } download={ filename } type={ type }>
<DownloadIcon/>{ label }
</a>
</li>);
}
render() {
const { syntaxes, t } = this.props;
return <div className={ style.form }>
<form onSubmit={ this.handleSubmit }>
<textarea
ref={ this.textareaRef }
onKeyPress={ this.handleKeyPress }
autoFocus
placeholder={ t('Enter regular expression to display') }></textarea>
<button type="submit"><Trans>Display</Trans></button>
<div className={ style.select }>
<select ref={ this.syntaxRef }>
{ Object.keys(syntaxes).map(id => (
<option value={ id } key={ id }>{ syntaxes[id] }</option>
)) }
</select>
<ExpandIcon/>
</div>
<ul className={ ['inline', 'with-separator', style.actions].join(' ') }>
{ this.downloadActions() }
{ this.permalinkAction() }
</ul>
</form>
</div>;
}
}
Form.propTypes = {
syntaxes: PropTypes.object,
onSubmit: PropTypes.func,
permalinkUrl: PropTypes.string,
downloadUrls: PropTypes.array,
t: PropTypes.func
};
export default translate()(Form);
export { Form };

View File

@ -0,0 +1,75 @@
@import url('../../globals.css');
:root {
--control-gradient: var(--color-green) var(--gradient-green);
--select-height: 2.8rem;
--select-width: 12rem;
}
.form {
margin: var(--spacing-margin) 0;
& textarea {
display: block;
font-size: inherit;
line-height: 1.5em;
border: 0 none;
outline: none;
background: var(--color-tan);
padding: 0 1rem;
margin-bottom: var(--spacing-margin);
width: 100% !important; /* "!important" to prevent user changing width */
box-sizing: border-box;
font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
}
& textarea::placeholder {
color: var(--color-brown);
}
& button {
font-size: inherit;
font-weight: bold;
line-height: 2.8rem;
width: 10rem;
border: 0 none;
background: var(--control-gradient);
cursor: pointer;
padding: 0;
margin-right: 1rem;
}
}
.actions {
float: right;
& svg {
height: 1em;
vertical-align: middle;
}
}
.select {
position: relative;
vertical-align: bottom;
display: inline-block;
height: var(--select-height);
width: var(--select-width);
background: var(--control-gradient);
overflow: hidden;
& select {
background: transparent;
border: 0 none;
font-size: inherit;
height: var(--select-height);
width: calc(var(--select-width) + 2rem);
}
& svg {
position: absolute;
top: calc((var(--select-height) - 24px) / 2);
right: 0;
pointer-events: none;
}
}

View File

@ -0,0 +1,27 @@
import React from 'react';
import { shallow } from 'enzyme';
import { Form } from 'components/Form';
import translate from '__mocks__/translate';
const syntaxes = {
js: 'Javascript',
pcre: 'PCRE'
};
describe('Form', () => {
test('rendering', () => {
const component = shallow(
<Form t={ translate } syntaxes={ syntaxes }/>
);
expect(component).toMatchSnapshot();
});
test('rendering with download URLs');
test('rendering with permalink URL');
test('submitting form');
test('submitting form with Shift+Enter');
});

View File

@ -1,7 +1,10 @@
404 Page Not Found: "404: Page Not Found"
An error has occurred: An error has occurred
Created by <1>Jeff Avallone</1>: Created by <1>Jeff Avallone</1>
Display: Display
Enter regular expression to display: Enter regular expression to display
Generated images licensed: "Generated images licensed: <1><0></0></1>"
Permalink: Permalink
Source on GitHub: Source on GitHub
The page you have requested could not be found: The page you have requested could not be found
This error has been logged: This error has been logged. You may also <1>fill out a report</1>.