comkit-preact
Advanced tools
Comparing version
169
node/Form.js
@@ -9,24 +9,18 @@ 'use strict'; | ||
var _deepEqual = require('deep-equal'); | ||
var _deepEqual2 = _interopRequireDefault(_deepEqual); | ||
var _lodash = require('lodash'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
class Form extends _preact.Component { | ||
constructor(props) { | ||
super(props); | ||
constructor(...args) { | ||
super(...args); | ||
(0, _lodash.bindAll)(this, ['reset', 'registerInput', 'setAttribute', 'resetAttributes']); | ||
(0, _lodash.bindAll)(this, ['reset', 'registerField', 'onChange', 'onSubmit']); | ||
this.inputs = []; | ||
this.fields = []; | ||
this.state = this.getInitialState(); | ||
} | ||
this.attributes = props.attributes || {}; | ||
this.initialAttributes = Object.assign({}, this.attributes); | ||
this.state = { | ||
dirty: false, | ||
valid: this.validate() | ||
getInitialState(props = this.props) { | ||
return { | ||
dirty: [], | ||
errors: [] | ||
}; | ||
@@ -37,90 +31,114 @@ } | ||
return { | ||
initialAttributes: this.initialAttributes, | ||
setAttribute: this.setAttribute, | ||
registerInput: this.registerInput | ||
registerField: this.registerField, | ||
onChange: this.onChange | ||
}; | ||
} | ||
componentWillReceiveProps(props = {}) { | ||
this.resetAttributes(props.attributes); | ||
componentDidUpdate(prevProps) { | ||
if (prevProps.values !== this.props.values) { | ||
this.reset(); | ||
} | ||
} | ||
registerInput(component) { | ||
this.inputs.push(component); | ||
registerField(component) { | ||
this.fields.push(component); | ||
// check if any initial props are not null | ||
for (const prop in this.initialAttributes) { | ||
if (this.initialAttributes[prop]) { | ||
component.touch(); | ||
break; | ||
return () => { | ||
const index = this.fields.indexOf(component); | ||
this.fields.splice(index, 1); | ||
}; | ||
} | ||
onChange({ dirty, error, name, value }) { | ||
const state = {}; | ||
const wasPreviouslyDirty = this.state.dirty.includes(name); | ||
if (!dirty) { | ||
if (wasPreviouslyDirty) { | ||
state.dirty = this.state.dirty.filter(n => n !== name); | ||
} | ||
} else if (!wasPreviouslyDirty) { | ||
state.dirty = this.state.dirty.concat(name); | ||
} | ||
const name = component.props.name; | ||
const previousError = this.state.errors.find(arr => arr[0] === name); | ||
if (!this.attributes.hasOwnProperty(name)) { | ||
this.attributes[name] = this.initialAttributes[name] = null; | ||
if (!error) { | ||
if (previousError) { | ||
state.errors = this.state.errors.filter(arr => arr[0] !== name); | ||
} | ||
} else if (!previousError) { | ||
state.errors = this.state.errors.concat([[name, error]]); | ||
} else if (previousError && previousError[1] !== error) { | ||
state.errors = this.state.errors.filter(arr => arr[0] !== name).concat([[name, error]]); | ||
} | ||
return () => { | ||
const index = this.inputs.indexOf(component); | ||
this.setState(state); | ||
} | ||
delete this.inputs.splice(index, 1); | ||
}; | ||
isDirty() { | ||
return this.state.dirty.length !== 0; | ||
} | ||
setAttribute(attr, value) { | ||
// const filter = get(this.filters, attr); | ||
isValid() { | ||
return this.state.errors.length === 0; | ||
} | ||
// if (filter) value = filter(value); | ||
validate(focus = false, touch = false) { | ||
const errors = this.fields.reduce((result, field) => { | ||
const error = field.validate(); | ||
(0, _lodash.set)(this.attributes, attr, value); | ||
field.setState({ error }); | ||
// skip a tick to let form element state update (if this.validate is called | ||
// immediately, the child/form element component will not have updated it's | ||
// state... ie the error field could be wrong | ||
setTimeout(() => { | ||
this.setState({ | ||
dirty: !(0, _deepEqual2.default)(this.attributes, this.initialAttributes), | ||
valid: this.validate() | ||
}); | ||
}); | ||
} | ||
// focus first invalid element | ||
if (focus && result.length === 0 && error) { | ||
field.focus(); | ||
} | ||
resetAttributes(attrs, validate) { | ||
this.attributes = attrs || this.initialAttributes || {}; | ||
this.initialAttributes = Object.assign({}, this.attributes); | ||
// only touch invalid or filled elements when validating | ||
if (touch) { | ||
if (error || field.getValue() != null) { | ||
field.touch(); | ||
} else { | ||
field.untouch(); | ||
} | ||
} | ||
this.setState({ | ||
dirty: false, | ||
valid: this.validate() | ||
}); | ||
if (error) { | ||
result.push([field.name, error]); | ||
} | ||
return result; | ||
}, []); | ||
this.setState({ errors }); | ||
return errors.length === 0; | ||
} | ||
toJSON() { | ||
return Object.assign({}, this.attributes); | ||
} | ||
// TODO implement returning only changed values | ||
// ie compare with props.values | ||
return this.fields.reduce((json, field) => { | ||
const value = field.getValue(); | ||
validate(focus = false, touch = false) { | ||
// TODO maybe put this somewhere else | ||
if (touch) { | ||
this.inputs.forEach(input => input.touch()); | ||
} | ||
if (value != null) { | ||
(0, _lodash.set)(json, field.name, value); | ||
} | ||
return this.inputs.every(input => { | ||
const isValid = input.isValid(); | ||
if (!isValid && focus) input.focus(); | ||
return isValid; | ||
}); | ||
return json; | ||
}, {}); | ||
} | ||
reset() { | ||
this.resetAttributes(); | ||
this.fields.forEach(field => field.reset(true)); | ||
(0, _lodash.forEach)(this.inputs, input => input.reset()); | ||
this.setState(this.getInitialState()); | ||
} | ||
render({ children }) { | ||
render() { | ||
const { children } = this.props; | ||
return (0, _preact.h)( | ||
@@ -133,3 +151,8 @@ 'form', | ||
} | ||
Form.defaultProps = { | ||
values: {} | ||
}; | ||
exports.default = Form; | ||
module.exports = exports['default']; |
@@ -6,15 +6,15 @@ 'use strict'; | ||
}); | ||
exports.TextArea = exports.SingleCheckBox = exports.Pagination = exports.Message = exports.Input = exports.Form = exports.FormElement = exports.CheckBox = exports.CheckBoxGroup = undefined; | ||
exports.TextArea = exports.SingleCheckbox = exports.Pagination = exports.Message = exports.Input = exports.Form = exports.FormField = exports.Checkbox = exports.CheckboxGroup = undefined; | ||
var _CheckBoxGroup = require('./CheckBoxGroup'); | ||
var _CheckboxGroup = require('./CheckboxGroup'); | ||
var _CheckBoxGroup2 = _interopRequireDefault(_CheckBoxGroup); | ||
var _CheckboxGroup2 = _interopRequireDefault(_CheckboxGroup); | ||
var _CheckBox = require('./CheckBox'); | ||
var _Checkbox = require('./Checkbox'); | ||
var _CheckBox2 = _interopRequireDefault(_CheckBox); | ||
var _Checkbox2 = _interopRequireDefault(_Checkbox); | ||
var _FormElement = require('./FormElement'); | ||
var _FormField = require('./FormField'); | ||
var _FormElement2 = _interopRequireDefault(_FormElement); | ||
var _FormField2 = _interopRequireDefault(_FormField); | ||
@@ -37,5 +37,5 @@ var _Form = require('./Form'); | ||
var _SingleCheckBox = require('./SingleCheckBox'); | ||
var _SingleCheckbox = require('./SingleCheckbox'); | ||
var _SingleCheckBox2 = _interopRequireDefault(_SingleCheckBox); | ||
var _SingleCheckbox2 = _interopRequireDefault(_SingleCheckbox); | ||
@@ -49,5 +49,5 @@ var _TextArea = require('./TextArea'); | ||
exports.default = { | ||
CheckBoxGroup: _CheckBoxGroup2.default, | ||
CheckBox: _CheckBox2.default, | ||
FormElement: _FormElement2.default, | ||
CheckboxGroup: _CheckboxGroup2.default, | ||
Checkbox: _Checkbox2.default, | ||
FormField: _FormField2.default, | ||
Form: _Form2.default, | ||
@@ -57,8 +57,8 @@ Input: _Input2.default, | ||
Pagination: _Pagination2.default, | ||
SingleCheckBox: _SingleCheckBox2.default, | ||
SingleCheckbox: _SingleCheckbox2.default, | ||
TextArea: _TextArea2.default | ||
}; | ||
exports.CheckBoxGroup = _CheckBoxGroup2.default; | ||
exports.CheckBox = _CheckBox2.default; | ||
exports.FormElement = _FormElement2.default; | ||
exports.CheckboxGroup = _CheckboxGroup2.default; | ||
exports.Checkbox = _Checkbox2.default; | ||
exports.FormField = _FormField2.default; | ||
exports.Form = _Form2.default; | ||
@@ -68,3 +68,3 @@ exports.Input = _Input2.default; | ||
exports.Pagination = _Pagination2.default; | ||
exports.SingleCheckBox = _SingleCheckBox2.default; | ||
exports.SingleCheckbox = _SingleCheckbox2.default; | ||
exports.TextArea = _TextArea2.default; |
@@ -13,12 +13,13 @@ 'use strict'; | ||
var _lodash = require('lodash'); | ||
var _FormField = require('./FormField'); | ||
var _FormElement = require('./FormElement'); | ||
var _FormField2 = _interopRequireDefault(_FormField); | ||
var _FormElement2 = _interopRequireDefault(_FormElement); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
class Input extends _FormElement2.default { | ||
render({ required, type = 'text', disabled, placeholder }, state = {}, context) { | ||
class Input extends _FormField2.default { | ||
render() { | ||
const { type = 'text', disabled, placeholder } = this.props; | ||
const state = this.state; | ||
const classes = Object.assign({ | ||
@@ -28,8 +29,8 @@ 'field-container': true, | ||
empty: !state.value, | ||
filled: state.value, | ||
filled: !!state.value, | ||
dirty: state.dirty, | ||
focus: state.focus, | ||
invalid: state.error, | ||
invalid: !!state.error, | ||
touched: state.touched, | ||
valid: (!required || state.value) && !state.error | ||
valid: !state.error | ||
}); | ||
@@ -39,3 +40,3 @@ | ||
'div', | ||
{ 'class': (0, _classnames2.default)(classes) }, | ||
{ className: (0, _classnames2.default)(classes) }, | ||
(0, _preact.h)( | ||
@@ -47,7 +48,8 @@ 'label', | ||
(0, _preact.h)('input', { | ||
name: this.props.name, | ||
disabled: disabled, | ||
onBlur: this.onBlur, | ||
onChange: this.onChange, | ||
onInput: this.onChange, | ||
onFocus: this.onFocus, | ||
onInput: this.onChange, | ||
placeholder: placeholder, | ||
@@ -58,8 +60,8 @@ ref: input => { | ||
type: type, | ||
value: state.value | ||
value: state.value || '' | ||
}), | ||
(0, _preact.h)('label', { 'class': 'icon' }), | ||
(0, _preact.h)('label', { className: 'icon' }), | ||
state.error && (0, _preact.h)( | ||
'label', | ||
{ 'class': 'error' }, | ||
{ className: 'error' }, | ||
state.error | ||
@@ -70,3 +72,4 @@ ) | ||
} | ||
exports.default = Input; | ||
module.exports = exports['default']; |
@@ -1,2 +0,2 @@ | ||
"use strict"; | ||
'use strict'; | ||
@@ -7,18 +7,24 @@ Object.defineProperty(exports, "__esModule", { | ||
var _preact = require("preact"); | ||
var _preact = require('preact'); | ||
exports.default = props => (0, _preact.h)( | ||
"div", | ||
{ "class": `${props.type} message wrapper` }, | ||
var _classnames = require('classnames'); | ||
var _classnames2 = _interopRequireDefault(_classnames); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const Message = props => (0, _preact.h)( | ||
'div', | ||
{ className: (0, _classnames2.default)(props.type, 'message', 'wrapper') }, | ||
(0, _preact.h)( | ||
"div", | ||
{ "class": "container" }, | ||
'div', | ||
{ className: 'container' }, | ||
props.heading && (0, _preact.h)( | ||
"div", | ||
{ "class": "heading" }, | ||
'div', | ||
{ className: 'heading' }, | ||
props.heading | ||
), | ||
props.body && (0, _preact.h)( | ||
"div", | ||
{ "class": "body" }, | ||
'div', | ||
{ className: 'body' }, | ||
props.body | ||
@@ -29,2 +35,3 @@ ) | ||
module.exports = exports["default"]; | ||
exports.default = Message; | ||
module.exports = exports['default']; |
@@ -17,3 +17,3 @@ 'use strict'; | ||
exports.default = ({ totalCount, query, perPage }) => { | ||
const Pagination = ({ totalCount, query, perPage }) => { | ||
const path = window.location.pathname; | ||
@@ -62,10 +62,10 @@ | ||
'div', | ||
{ 'class': 'pagination' }, | ||
{ className: 'pagination' }, | ||
(0, _preact.h)( | ||
'div', | ||
{ 'class': 'results' }, | ||
{ className: 'results' }, | ||
'Showing items ', | ||
(0, _preact.h)( | ||
'span', | ||
{ 'class': 'first number' }, | ||
{ className: 'first number' }, | ||
firstIndex | ||
@@ -76,3 +76,3 @@ ), | ||
'span', | ||
{ 'class': 'last number' }, | ||
{ className: 'last number' }, | ||
lastIndex | ||
@@ -83,3 +83,3 @@ ), | ||
'span', | ||
{ 'class': 'total number' }, | ||
{ className: 'total number' }, | ||
totalCount | ||
@@ -93,6 +93,6 @@ ) | ||
'li', | ||
{ 'class': 'arrow' }, | ||
{ className: 'arrow' }, | ||
prev ? (0, _preact.h)( | ||
'a', | ||
{ href: path + prev.search, rel: 'prev', 'class': 'nav', title: 'F\xF6reg\xE5ende sida' }, | ||
{ href: path + prev.search, rel: 'prev', className: 'nav', title: 'F\xF6reg\xE5ende sida' }, | ||
'\xAB' | ||
@@ -107,6 +107,6 @@ ) : (0, _preact.h)( | ||
'li', | ||
{ 'class': page.current && 'current' }, | ||
{ className: page.current && 'current' }, | ||
(0, _preact.h)( | ||
'a', | ||
{ href: path + page.search, 'class': 'nav', rel: page.rel, title: `Sida ${number}` }, | ||
{ href: path + page.search, className: 'nav', rel: page.rel, title: `Sida ${number}` }, | ||
page.number | ||
@@ -117,6 +117,6 @@ ) | ||
'li', | ||
{ 'class': 'arrow' }, | ||
{ className: 'arrow' }, | ||
next ? (0, _preact.h)( | ||
'a', | ||
{ href: path + next.search, rel: 'next', 'class': 'nav', title: 'N\xE4sta sida' }, | ||
{ href: path + next.search, rel: 'next', className: 'nav', title: 'N\xE4sta sida' }, | ||
'\xBB' | ||
@@ -133,2 +133,3 @@ ) : (0, _preact.h)( | ||
exports.default = Pagination; | ||
module.exports = exports['default']; |
@@ -13,11 +13,9 @@ 'use strict'; | ||
var _lodash = require('lodash'); | ||
var _FormField = require('./FormField'); | ||
var _FormElement = require('./FormElement'); | ||
var _FormField2 = _interopRequireDefault(_FormField); | ||
var _FormElement2 = _interopRequireDefault(_FormElement); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
class TextArea extends _FormElement2.default { | ||
class TextArea extends _FormField2.default { | ||
onFocus(e) { | ||
@@ -28,24 +26,23 @@ this.setState({ | ||
}); | ||
if (document.documentElement.dataset.browser === 'IE11') { | ||
// make text area behave like input in IE (input fires both | ||
// focus and input when focusing input elements, but not textareas) | ||
this.setValue(e.target.value); | ||
} | ||
} | ||
render({ disabled, placeholder }, state = {}) { | ||
const classes = Object.assign({ | ||
render() { | ||
const { disabled, name, placeholder } = this.props; | ||
const state = this.state; | ||
const classes = { | ||
'field-container': true, | ||
cell: true, | ||
empty: !state.value, | ||
filled: state.value, | ||
filled: !!state.value, | ||
dirty: state.dirty, | ||
focus: state.focus, | ||
invalid: state.error, | ||
invalid: !!state.error, | ||
touched: state.touched, | ||
valid: state.value && !state.error | ||
}); | ||
valid: !state.error | ||
}; | ||
return (0, _preact.h)( | ||
'div', | ||
{ 'class': (0, _classnames2.default)(classes) }, | ||
{ className: (0, _classnames2.default)(classes) }, | ||
(0, _preact.h)( | ||
@@ -57,2 +54,3 @@ 'label', | ||
(0, _preact.h)('textarea', { | ||
name: name, | ||
disabled: disabled, | ||
@@ -62,3 +60,2 @@ onFocus: this.onFocus, | ||
onChange: this.onChange, | ||
onInput: this.onChange, | ||
placeholder: placeholder, | ||
@@ -68,6 +65,6 @@ ref: input => this.input = input, | ||
}), | ||
(0, _preact.h)('label', { 'class': 'icon' }), | ||
(0, _preact.h)('label', { className: 'icon' }), | ||
state.error && (0, _preact.h)( | ||
'label', | ||
{ 'class': 'error' }, | ||
{ className: 'error' }, | ||
state.error | ||
@@ -78,3 +75,4 @@ ) | ||
} | ||
exports.default = TextArea; | ||
module.exports = exports['default']; |
{ | ||
"name": "comkit-preact", | ||
"version": "0.2.1", | ||
"version": "0.3.0-alpha.1", | ||
"description": "Collection of Preact components", | ||
@@ -50,4 +50,11 @@ "main": "node/index.js", | ||
"eslint": "^3.19.0", | ||
"eslint-config-standard": "^10.2.1", | ||
"eslint-config-standard-preact": "^5.0.0", | ||
"eslint-plugin-import": "^2.3.0", | ||
"eslint-plugin-node": "^5.0.0", | ||
"eslint-plugin-promise": "^3.5.0", | ||
"eslint-plugin-react": "^7.0.1", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"rimraf": "^2.6.1" | ||
} | ||
} |
181
src/Form.jsx
@@ -1,116 +0,145 @@ | ||
import { h, Component } from 'preact'; | ||
import deepEqual from 'deep-equal'; | ||
import { set, get, omit, forEach, bindAll } from 'lowline'; | ||
import { h, Component } from 'preact' | ||
import { set, bindAll } from 'lowline' | ||
export default class Form extends Component { | ||
constructor(props) { | ||
super(props); | ||
class Form extends Component { | ||
constructor (...args) { | ||
super(...args) | ||
bindAll(this, ['reset', 'registerInput', 'setAttribute', 'resetAttributes']); | ||
bindAll(this, ['reset', 'registerField', 'onChange', 'onSubmit']) | ||
this.inputs = []; | ||
this.fields = [] | ||
this.state = this.getInitialState() | ||
} | ||
this.attributes = props.attributes || {}; | ||
this.initialAttributes = Object.assign({}, this.attributes); | ||
this.state = { | ||
dirty: false, | ||
valid: this.validate(), | ||
}; | ||
getInitialState (props = this.props) { | ||
return { | ||
dirty: [], | ||
errors: [] | ||
} | ||
} | ||
getChildContext() { | ||
getChildContext () { | ||
return { | ||
initialAttributes: this.initialAttributes, | ||
setAttribute: this.setAttribute, | ||
registerInput: this.registerInput, | ||
}; | ||
registerField: this.registerField, | ||
onChange: this.onChange | ||
} | ||
} | ||
componentWillReceiveProps(props = {}) { | ||
this.resetAttributes(props.attributes); | ||
componentDidUpdate (prevProps) { | ||
if (prevProps.values !== this.props.values) { | ||
this.reset() | ||
} | ||
} | ||
registerInput(component) { | ||
this.inputs.push(component); | ||
registerField (component) { | ||
this.fields.push(component) | ||
// check if any initial props are not null | ||
for (const prop in this.initialAttributes) { | ||
if (this.initialAttributes[prop]) { | ||
component.touch(); | ||
break; | ||
return () => { | ||
const index = this.fields.indexOf(component) | ||
this.fields.splice(index, 1) | ||
} | ||
} | ||
onChange ({ dirty, error, name, value }) { | ||
const state = {} | ||
const wasPreviouslyDirty = this.state.dirty.includes(name) | ||
if (!dirty) { | ||
if (wasPreviouslyDirty) { | ||
state.dirty = this.state.dirty.filter((n) => n !== name) | ||
} | ||
} else if (!wasPreviouslyDirty) { | ||
state.dirty = this.state.dirty.concat(name) | ||
} | ||
const name = component.props.name; | ||
const previousError = this.state.errors.find((arr) => arr[0] === name) | ||
if (!this.attributes.hasOwnProperty(name)) { | ||
this.attributes[name] = this.initialAttributes[name] = null; | ||
if (!error) { | ||
if (previousError) { | ||
state.errors = this.state.errors.filter((arr) => arr[0] !== name) | ||
} | ||
} else if (!previousError) { | ||
state.errors = this.state.errors.concat([[name, error]]) | ||
} else if (previousError && previousError[1] !== error) { | ||
state.errors = this.state.errors.filter((arr) => arr[0] !== name).concat([[name, error]]) | ||
} | ||
return () => { | ||
const index = this.inputs.indexOf(component); | ||
this.setState(state) | ||
} | ||
delete this.inputs.splice(index, 1); | ||
}; | ||
isDirty () { | ||
return this.state.dirty.length !== 0 | ||
} | ||
setAttribute(attr, value) { | ||
// const filter = get(this.filters, attr); | ||
isValid () { | ||
return this.state.errors.length === 0 | ||
} | ||
// if (filter) value = filter(value); | ||
validate (focus = false, touch = false) { | ||
const errors = this.fields.reduce((result, field) => { | ||
const error = field.validate() | ||
set(this.attributes, attr, value); | ||
field.setState({ error }) | ||
// skip a tick to let form element state update (if this.validate is called | ||
// immediately, the child/form element component will not have updated it's | ||
// state... ie the error field could be wrong | ||
setTimeout(() => { | ||
this.setState({ | ||
dirty: !deepEqual(this.attributes, this.initialAttributes), | ||
valid: this.validate(), | ||
}); | ||
}); | ||
} | ||
// focus first invalid element | ||
if (focus && result.length === 0 && error) { | ||
field.focus() | ||
} | ||
resetAttributes(attrs, validate) { | ||
this.attributes = attrs || this.initialAttributes || {}; | ||
this.initialAttributes = Object.assign({}, this.attributes); | ||
// only touch invalid or filled elements when validating | ||
if (touch) { | ||
if (error || field.getValue() != null) { | ||
field.touch() | ||
} else { | ||
field.untouch() | ||
} | ||
} | ||
this.setState({ | ||
dirty: false, | ||
valid: this.validate(), | ||
}); | ||
} | ||
if (error) { | ||
result.push([field.name, error]) | ||
} | ||
toJSON() { | ||
return Object.assign({}, this.attributes); | ||
return result | ||
}, []) | ||
this.setState({ errors }) | ||
return errors.length === 0 | ||
} | ||
validate(focus = false, touch = false) { | ||
// TODO maybe put this somewhere else | ||
if (touch) { | ||
this.inputs.forEach((input) => input.touch()); | ||
} | ||
toJSON () { | ||
// TODO implement returning only changed values | ||
// ie compare with props.values | ||
return this.fields.reduce((json, field) => { | ||
const value = field.getValue() | ||
return this.inputs.every((input) => { | ||
const isValid = input.isValid(); | ||
if (value != null) { | ||
set(json, field.name, value) | ||
} | ||
if (!isValid && focus) input.focus(); | ||
return isValid; | ||
}); | ||
return json | ||
}, {}) | ||
} | ||
reset() { | ||
this.resetAttributes(); | ||
reset () { | ||
this.fields.forEach((field) => field.reset(true)) | ||
forEach(this.inputs, (input) => input.reset()); | ||
this.setState(this.getInitialState()) | ||
} | ||
render({ children }) { | ||
render () { | ||
const { children } = this.props | ||
return ( | ||
<form>{children}</form> | ||
); | ||
) | ||
} | ||
} | ||
Form.defaultProps = { | ||
values: {} | ||
} | ||
export default Form |
@@ -1,15 +0,15 @@ | ||
import CheckBoxGroup from './CheckBoxGroup'; | ||
import CheckBox from './CheckBox'; | ||
import FormElement from './FormElement'; | ||
import Form from './Form'; | ||
import Input from './Input'; | ||
import Message from './Message'; | ||
import Pagination from './Pagination'; | ||
import SingleCheckBox from './SingleCheckBox'; | ||
import TextArea from './TextArea'; | ||
import CheckboxGroup from './CheckboxGroup' | ||
import Checkbox from './Checkbox' | ||
import FormField from './FormField' | ||
import Form from './Form' | ||
import Input from './Input' | ||
import Message from './Message' | ||
import Pagination from './Pagination' | ||
import SingleCheckbox from './SingleCheckbox' | ||
import TextArea from './TextArea' | ||
export default { | ||
CheckBoxGroup, | ||
CheckBox, | ||
FormElement, | ||
CheckboxGroup, | ||
Checkbox, | ||
FormField, | ||
Form, | ||
@@ -19,10 +19,10 @@ Input, | ||
Pagination, | ||
SingleCheckBox, | ||
TextArea, | ||
}; | ||
SingleCheckbox, | ||
TextArea | ||
} | ||
export { | ||
CheckBoxGroup, | ||
CheckBox, | ||
FormElement, | ||
CheckboxGroup, | ||
Checkbox, | ||
FormField, | ||
Form, | ||
@@ -32,4 +32,4 @@ Input, | ||
Pagination, | ||
SingleCheckBox, | ||
TextArea, | ||
}; | ||
SingleCheckbox, | ||
TextArea | ||
} |
@@ -1,9 +0,11 @@ | ||
import { h, Component } from 'preact'; | ||
import classNames from 'classnames'; | ||
import { omit } from 'lowline'; | ||
import { h } from 'preact' | ||
import classNames from 'classnames' | ||
import FormElement from './FormElement'; | ||
import FormField from './FormField' | ||
export default class Input extends FormElement { | ||
render({ required, type = 'text', disabled, placeholder }, state = {}, context) { | ||
class Input extends FormField { | ||
render () { | ||
const { type = 'text', disabled, placeholder } = this.props | ||
const state = this.state | ||
const classes = Object.assign({ | ||
@@ -13,29 +15,32 @@ 'field-container': true, | ||
empty: !state.value, | ||
filled: state.value, | ||
filled: !!state.value, | ||
dirty: state.dirty, | ||
focus: state.focus, | ||
invalid: state.error, | ||
invalid: !!state.error, | ||
touched: state.touched, | ||
valid: (!required || state.value) && !state.error, | ||
}); | ||
valid: !state.error | ||
}) | ||
return ( | ||
<div class={classNames(classes)}> | ||
<label className="placeholder">{placeholder}</label> | ||
<div className={classNames(classes)}> | ||
<label className='placeholder'>{placeholder}</label> | ||
<input | ||
name={this.props.name} | ||
disabled={disabled} | ||
onBlur={this.onBlur} | ||
onChange={this.onChange} | ||
onInput={this.onChange} | ||
onFocus={this.onFocus} | ||
onInput={this.onChange} | ||
placeholder={placeholder} | ||
ref={(input) => { this.input = input; }} | ||
ref={(input) => { this.input = input }} | ||
type={type} | ||
value={state.value} | ||
value={state.value || ''} | ||
/> | ||
<label class="icon" /> | ||
{state.error && <label class="error">{state.error}</label>} | ||
<label className='icon' /> | ||
{state.error && <label className='error'>{state.error}</label>} | ||
</div> | ||
); | ||
) | ||
} | ||
} | ||
export default Input |
@@ -1,10 +0,13 @@ | ||
import { h } from 'preact'; | ||
import { h } from 'preact' | ||
import classNames from 'classnames' | ||
export default (props) => ( | ||
<div class={`${props.type} message wrapper`}> | ||
<div class="container"> | ||
{props.heading && <div class="heading">{props.heading}</div>} | ||
{props.body && <div class="body">{props.body}</div>} | ||
const Message = (props) => ( | ||
<div className={classNames(props.type, 'message', 'wrapper')}> | ||
<div className='container'> | ||
{props.heading && <div className='heading'>{props.heading}</div>} | ||
{props.body && <div className='body'>{props.body}</div>} | ||
</div> | ||
</div> | ||
); | ||
) | ||
export default Message |
@@ -1,18 +0,18 @@ | ||
import { h } from 'preact'; | ||
import { omit } from 'lowline'; | ||
import { h } from 'preact' | ||
import { omit } from 'lowline' | ||
import qs from 'mini-qs' | ||
export default ({ totalCount, query, perPage }) => { | ||
const path = window.location.pathname; | ||
const Pagination = ({ totalCount, query, perPage }) => { | ||
const path = window.location.pathname | ||
const pages = []; | ||
query = window.location.search ? qs.parse(window.location.search.slice(1)) : {}; | ||
const page = +query.page || 0; | ||
const pages = [] | ||
query = window.location.search ? qs.parse(window.location.search.slice(1)) : {} | ||
const page = +query.page || 0 | ||
// page = +_.last(query.match(/(^|&)page=(\d+)/)) || 0, | ||
perPage = +query.limit || perPage; | ||
perPage = +query.limit || perPage | ||
// perPage = +_.last(query.match(/(^|&)limit=(\d+)/)) || context.get('perPage'), | ||
let search = ''; | ||
let number = 0; | ||
const end = perPage && totalCount / perPage; | ||
let search = '' | ||
let number = 0 | ||
const end = perPage && totalCount / perPage | ||
@@ -26,37 +26,37 @@ // remove page and empty params | ||
arr.map(encodeURIComponent).join('=') | ||
)).join('&'); | ||
)).join('&') | ||
if (query) { | ||
search = `?${query}`; | ||
query += '&'; | ||
search = `?${query}` | ||
query += '&' | ||
} | ||
while (number < end) { | ||
number += 1; | ||
pages.push({ search, number }); | ||
search = `?${query}page=${number}`; | ||
number += 1 | ||
pages.push({ search, number }) | ||
search = `?${query}page=${number}` | ||
} | ||
if (page < pages.length) { | ||
pages[page].current = true; | ||
pages[page].current = true | ||
} | ||
// min is for when totalCount is 0 | ||
const firstIndex = Math.min(page * perPage + 1, totalCount); | ||
const firstIndex = Math.min(page * perPage + 1, totalCount) | ||
// min is for last (not full) page | ||
const lastIndex = Math.min((page + 1) * perPage, totalCount); | ||
const prev = pages[page - 1]; | ||
const next = pages[page + 1]; | ||
const lastIndex = Math.min((page + 1) * perPage, totalCount) | ||
const prev = pages[page - 1] | ||
const next = pages[page + 1] | ||
return ( | ||
<div class="pagination"> | ||
<div class="results"> | ||
Showing items <span class="first number">{firstIndex}</span> - <span class="last number">{lastIndex}</span> out of <span class="total number">{totalCount}</span> | ||
<div className='pagination'> | ||
<div className='results'> | ||
Showing items <span className='first number'>{firstIndex}</span> - <span className='last number'>{lastIndex}</span> out of <span className='total number'>{totalCount}</span> | ||
</div> | ||
<ul> | ||
<li class="arrow"> | ||
<li className='arrow'> | ||
{prev | ||
? <a href={path + prev.search} rel="prev" class="nav" title="Föregående sida">«</a> | ||
: <a href="javascript:;" title="Föregående sida">«</a> | ||
? <a href={path + prev.search} rel='prev' className='nav' title='Föregående sida'>«</a> | ||
: <a href='javascript:;' title='Föregående sida'>«</a> | ||
} | ||
@@ -66,12 +66,11 @@ </li> | ||
{pages.map((page) => ( | ||
<li class={page.current && 'current'}> | ||
<a href={path + page.search} class="nav" rel={page.rel} title={`Sida ${number}`}>{page.number}</a> | ||
<li className={page.current && 'current'}> | ||
<a href={path + page.search} className='nav' rel={page.rel} title={`Sida ${number}`}>{page.number}</a> | ||
</li> | ||
))} | ||
<li class="arrow"> | ||
<li className='arrow'> | ||
{next | ||
? <a href={path + next.search} rel="next" class="nav" title="Nästa sida">»</a> | ||
: <a href="javascript:;" title="Nästa sida">»</a> | ||
? <a href={path + next.search} rel='next' className='nav' title='Nästa sida'>»</a> | ||
: <a href='javascript:;' title='Nästa sida'>»</a> | ||
} | ||
@@ -82,3 +81,5 @@ </li> | ||
); | ||
}; | ||
) | ||
} | ||
export default Pagination |
@@ -1,36 +0,36 @@ | ||
import { h, Component } from 'preact'; | ||
import classNames from 'classnames'; | ||
import { omit } from 'lowline'; | ||
import { h } from 'preact' | ||
import FormElement from './FormElement'; | ||
import classNames from 'classnames' | ||
export default class TextArea extends FormElement { | ||
onFocus(e) { | ||
import FormField from './FormField' | ||
class TextArea extends FormField { | ||
onFocus (e) { | ||
this.setState({ | ||
focus: true, | ||
touched: true, | ||
}); | ||
if (document.documentElement.dataset.browser === 'IE11') { | ||
// make text area behave like input in IE (input fires both | ||
// focus and input when focusing input elements, but not textareas) | ||
this.setValue(e.target.value); | ||
} | ||
touched: true | ||
}) | ||
} | ||
render({ disabled, placeholder }, state = {}) { | ||
const classes = Object.assign({ | ||
render () { | ||
const { disabled, name, placeholder } = this.props | ||
const state = this.state | ||
const classes = { | ||
'field-container': true, | ||
cell: true, | ||
empty: !state.value, | ||
filled: state.value, | ||
filled: !!state.value, | ||
dirty: state.dirty, | ||
focus: state.focus, | ||
invalid: state.error, | ||
invalid: !!state.error, | ||
touched: state.touched, | ||
valid: state.value && !state.error, | ||
}); | ||
valid: !state.error | ||
} | ||
return ( | ||
<div class={classNames(classes)}> | ||
<label className="placeholder">{placeholder}</label> | ||
<div className={classNames(classes)}> | ||
<label className='placeholder'>{placeholder}</label> | ||
<textarea | ||
name={name} | ||
disabled={disabled} | ||
@@ -40,3 +40,2 @@ onFocus={this.onFocus} | ||
onChange={this.onChange} | ||
onInput={this.onChange} | ||
placeholder={placeholder} | ||
@@ -46,7 +45,9 @@ ref={(input) => (this.input = input)} | ||
/> | ||
<label class="icon" /> | ||
{state.error && <label class="error">{state.error}</label>} | ||
<label className='icon' /> | ||
{state.error && <label className='error'>{state.error}</label>} | ||
</div> | ||
); | ||
) | ||
} | ||
} | ||
export default TextArea |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
40075
1.46%1270
8.09%17
70%1
Infinity%