commit
56ef1edcfe
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
@ -0,0 +1,88 @@
|
|||||||
|
# Tiny Components - Validator
|
||||||
|
|
||||||
|
Created with [Riot.js](https://riot.js.org)
|
||||||
|
|
||||||
|
Validate Form or a Single Form-Field, Error Messages can be show just in time
|
||||||
|
or after Submit entire Form.
|
||||||
|
|
||||||
|
For Validation this Component uses [Validate.js](https://validatejs.org/)
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @tiny-components/validator --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## You can use it like this
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
<form class="form" onsubmit={ (event) => ( state.validator.submit(event) ) }>>
|
||||||
|
<div class="field">
|
||||||
|
<label>
|
||||||
|
email
|
||||||
|
<input type="email" name="email" onkeyup={ (event) => { state.validator.handle(event, 'email') }} />
|
||||||
|
</label>
|
||||||
|
<field-error errors={ state.validator.errors('email') } ></field-error>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>
|
||||||
|
password
|
||||||
|
<input type="password" name="email" onkeyup={ (event) => { state.validator.handle(event, 'password') }} />
|
||||||
|
</label>
|
||||||
|
<field-error errors={ state.validator.errors('password') } ></field-error>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Send</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Validator from './validator.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
state: {
|
||||||
|
validator: { }
|
||||||
|
},
|
||||||
|
|
||||||
|
onBeforeMount() {
|
||||||
|
// creating formValidator
|
||||||
|
this.state.validator = new FormValidator(this.$('.form'), {
|
||||||
|
'email': {
|
||||||
|
'presence': true,
|
||||||
|
'email': true
|
||||||
|
},
|
||||||
|
'password': {
|
||||||
|
'presence': true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// adding on success
|
||||||
|
this.state.validator.onSuccess((event, data) => {
|
||||||
|
this.handleSuccess(event, data)
|
||||||
|
})
|
||||||
|
|
||||||
|
// adding on error
|
||||||
|
this.state.validator.onError((event, errors, data) => {
|
||||||
|
this.handleError(event, errors, data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleSuccess(event, data)
|
||||||
|
{
|
||||||
|
event.preventDefault()
|
||||||
|
this.update()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleError(event, errors, data)
|
||||||
|
{
|
||||||
|
this.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
@ -0,0 +1,2 @@
|
|||||||
|
[install.scopes]
|
||||||
|
"@tiny-components" = "https://gitea.node001.net/api/packages/tiny-components/npm/"
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,73 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Tiny Components | Field Upload</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||||
|
<link href="/css/styles.css" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header class="header">
|
||||||
|
<div class="bar">
|
||||||
|
<div class="bar__start">
|
||||||
|
<h1 class="m-top-4 m-bottom-4 h4">
|
||||||
|
@tiny-components/upload
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="bar__main justify-end">
|
||||||
|
<a class="button button--small m-left-sm-3 m-bottom-0" href="https://git.node001.net/tiny-components/upload" rel="noopener" target="_blank">
|
||||||
|
Gitea
|
||||||
|
<svg class="m-left-3 icon fill-text" aria-hidden="true">
|
||||||
|
<use xlink:href="symbol-defs.svg#icon-gitea"></use>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="grid">
|
||||||
|
<div class="col-12">
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
Upload
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<form class="form-html" novalidate method="post">
|
||||||
|
<div class="field-group">
|
||||||
|
<tiny-field-upload label="Select File" name="file" multiple></tiny-field-upload>
|
||||||
|
<field-error name="file"></field-error>
|
||||||
|
</div>
|
||||||
|
<button class="button" type="submit" disabled>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
Upload / Max
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<form class="form-html" novalidate method="post">
|
||||||
|
<div class="field-group">
|
||||||
|
<tiny-field-upload label="Select File" name="file" max="2" multiple></tiny-field-upload>
|
||||||
|
<field-error name="file"></field-error>
|
||||||
|
</div>
|
||||||
|
<button class="button" type="submit" disabled>
|
||||||
|
Send
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
|||||||
|
(self.webpackChunk_tiny_components_upload=self.webpackChunk_tiny_components_upload||[]).push([[654],{874:()=>{}}]);
|
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@tiny-components/upload",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Upload Field for Riotjs",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:node001-net/tiny-components/upload.git"
|
||||||
|
},
|
||||||
|
"author": "Björn Hase",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tiny-components/plain-ui": "^0.6.0",
|
||||||
|
"riot": "^9.4.10"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@riotjs/compiler": "^9.0.7",
|
||||||
|
"@riotjs/webpack-loader": "^9.0.1",
|
||||||
|
"@tiny-components/webpack": "^0.2.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --mode production --config webpack.config.js",
|
||||||
|
"build-dev": "webpack --mode development --config webpack.config.js"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import * as riot from 'riot'
|
||||||
|
|
||||||
|
import FieldUpload from './fieldUpload.riot'
|
||||||
|
|
||||||
|
riot.register('tiny-field-upload', FieldUpload)
|
||||||
|
riot.mount('tiny-field-upload')
|
@ -0,0 +1,3 @@
|
|||||||
|
@import
|
||||||
|
'../node_modules/@tiny-components/plain-ui/src/scss/plain-ui',
|
||||||
|
'fieldUpload.scss';
|
@ -0,0 +1,140 @@
|
|||||||
|
<tiny-field-upload>
|
||||||
|
<div class="tiny-field-upload">
|
||||||
|
<input type="file" class="tiny-field-upload__field" multiple={ props.multiple !== undefined } onchange={ (event) => { handleSelectFile(event) } } />
|
||||||
|
<button class="button button--info" type="button" onclick={ (event) => { handleOpenFileManager(event) } } disabled={ state.disabled }>
|
||||||
|
<svg class="icon fill-text-contrast" aria-hidden="true">
|
||||||
|
<use xlink:href="/symbol-defs.svg#icon-upload"></use>
|
||||||
|
</svg>
|
||||||
|
{ props.label }
|
||||||
|
</button>
|
||||||
|
<div class="tiny-field-upload__files">
|
||||||
|
<div class="tiny-field-upload__files-item" each={ file in state.files }>
|
||||||
|
<div class="panel">
|
||||||
|
<div class="bar">
|
||||||
|
<div class="bar__start"></div>
|
||||||
|
<div class="bar__main">{ file.name }</div>
|
||||||
|
<div class="bar__end">
|
||||||
|
<button type="button" class="button button--transparent tiny-field-upload__files-remove" onclick={ (event) => { handleRemoveFile(event, file) } }>
|
||||||
|
<svg class="icon fill-text-contrast" aria-hidden="true">
|
||||||
|
<use xlink:href="/symbol-defs.svg#icon-delete"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel__body">
|
||||||
|
<input type="file" name="{ props.name }[]" />
|
||||||
|
<img class="tiny-field-upload__files-media" src={ addSrc(file) } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
state:
|
||||||
|
{
|
||||||
|
files: [],
|
||||||
|
field: undefined,
|
||||||
|
disabled: false
|
||||||
|
},
|
||||||
|
|
||||||
|
onMounted()
|
||||||
|
{
|
||||||
|
// getting field for getting files
|
||||||
|
this.field = this.$('.tiny-field-upload__field')
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* after update
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onUpdated(props, state) {
|
||||||
|
|
||||||
|
// getting elements
|
||||||
|
const elements = this.$$('.tiny-field-upload__item input')
|
||||||
|
|
||||||
|
let index = 0
|
||||||
|
|
||||||
|
// adding for each element a file-input
|
||||||
|
if (elements.length > 0) {
|
||||||
|
for (const element of elements) {
|
||||||
|
const dataTransfer = new DataTransfer()
|
||||||
|
|
||||||
|
// adding to each input field a file form files
|
||||||
|
dataTransfer.items.add(state.files[index++]);
|
||||||
|
element.files = dataTransfer.files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getting file and parse it for img-element
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
addSrc(file) {
|
||||||
|
return URL.createObjectURL(file)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* open file manager by button click on field-element
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleOpenFileManager(event)
|
||||||
|
{
|
||||||
|
this.field.click()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove file from files
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleRemoveFile(event, file)
|
||||||
|
{
|
||||||
|
const index = this.state.files.indexOf(file)
|
||||||
|
this.state.files.splice(index, 1)
|
||||||
|
|
||||||
|
this.validateMax()
|
||||||
|
this.update()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
handleSelectFile(event)
|
||||||
|
{
|
||||||
|
let index = 0
|
||||||
|
|
||||||
|
for (const file of event.target.files) {
|
||||||
|
if (!this.props.max || (this.props.max && (((index++) + 1) <= this.props.max))) {
|
||||||
|
this.state.files.push(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.validateMax()
|
||||||
|
this.update()
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
validateMax()
|
||||||
|
{
|
||||||
|
this.state.disabled = false
|
||||||
|
|
||||||
|
if (this.props.max && (this.state.files.length >= this.props.max)) {
|
||||||
|
this.state.disabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</tiny-field-upload>
|
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
.tiny-field-upload {
|
||||||
|
|
||||||
|
// hide all file inputs
|
||||||
|
input[type="file"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__files {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 0 -0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__files-item {
|
||||||
|
width: calc(25% - 1em);
|
||||||
|
margin: 0 0.5em 1em;
|
||||||
|
|
||||||
|
img.tiny-field-upload__files-media {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel__body {
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
const tinyComponentsWebpack = require('@tiny-components/webpack')
|
||||||
|
const riotRules = require('@tiny-components/webpack/rules/riot')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
module.exports = tinyComponentsWebpack({
|
||||||
|
index: [
|
||||||
|
'./src/example.js'
|
||||||
|
],
|
||||||
|
styles: [
|
||||||
|
'./src/example.scss'
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
publicPath: '/example/',
|
||||||
|
destination: path.resolve(process.cwd(), 'example'),
|
||||||
|
rules: [ riotRules ],
|
||||||
|
svg: {
|
||||||
|
src: [
|
||||||
|
'node_modules/@tiny-components/plain-ui/src/icons/mono-icons/svg/*.svg'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
purge: {
|
||||||
|
src: path.join(__dirname, './**')
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in new issue