Adding Form component
This commit is contained in:
parent
597cce4566
commit
b83f5cd34d
@ -1,6 +1,33 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Message rendering 1`] = `
|
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
|
<Message
|
||||||
heading="React App"
|
heading="React App"
|
||||||
>
|
>
|
||||||
@ -8,4 +35,5 @@ exports[`Message rendering 1`] = `
|
|||||||
Placeholder app content
|
Placeholder app content
|
||||||
</p>
|
</p>
|
||||||
</Message>
|
</Message>
|
||||||
|
</React.Fragment>
|
||||||
`;
|
`;
|
||||||
|
@ -1,11 +1,29 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import Form from 'components/Form';
|
||||||
import Message from 'components/Message';
|
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">
|
<Message heading="React App">
|
||||||
<p>Placeholder app content</p>
|
<p>Placeholder app content</p>
|
||||||
</Message>
|
</Message>
|
||||||
);
|
</React.Fragment>;
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
46
src/components/Form/__snapshots__/test.js.snap
Normal file
46
src/components/Form/__snapshots__/test.js.snap
Normal 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>
|
||||||
|
`;
|
94
src/components/Form/index.js
Normal file
94
src/components/Form/index.js
Normal 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 };
|
75
src/components/Form/style.css
Normal file
75
src/components/Form/style.css
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
27
src/components/Form/test.js
Normal file
27
src/components/Form/test.js
Normal 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');
|
||||||
|
});
|
@ -1,7 +1,10 @@
|
|||||||
404 Page Not Found: "404: Page Not Found"
|
404 Page Not Found: "404: Page Not Found"
|
||||||
An error has occurred: An error has occurred
|
An error has occurred: An error has occurred
|
||||||
Created by <1>Jeff Avallone</1>: Created by <1>Jeff Avallone</1>
|
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>"
|
Generated images licensed: "Generated images licensed: <1><0></0></1>"
|
||||||
|
Permalink: Permalink
|
||||||
Source on GitHub: Source on GitHub
|
Source on GitHub: Source on GitHub
|
||||||
The page you have requested could not be found: The page you have requested could not be found
|
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>.
|
This error has been logged: This error has been logged. You may also <1>fill out a report</1>.
|
||||||
|
Loading…
Reference in New Issue
Block a user