Includes support for slider values, custom validation rules and messages
This commit is contained in:
parent
95abd4e58d
commit
c31e896b86
@ -1,6 +1,7 @@
|
||||
import commonjs from 'rollup-plugin-commonjs' // Convert CommonJS modules to ES6
|
||||
import vue from 'rollup-plugin-vue' // Handle .vue SFC files
|
||||
import buble from 'rollup-plugin-buble' // Transpile/polyfill with reasonable browser support
|
||||
import { terser } from 'rollup-plugin-terser'
|
||||
|
||||
export default {
|
||||
input: 'src/Formulate.js', // Path relative to package.json
|
||||
@ -23,6 +24,7 @@ export default {
|
||||
}),
|
||||
buble({
|
||||
objectAssign: 'Object.assign'
|
||||
}) // Transpile to ES5
|
||||
}), // Transpile to ES5,
|
||||
terser()
|
||||
]
|
||||
}
|
||||
|
3366
dist/formulate.esm.js
vendored
3366
dist/formulate.esm.js
vendored
File diff suppressed because one or more lines are too long
3373
dist/formulate.min.js
vendored
3373
dist/formulate.min.js
vendored
File diff suppressed because one or more lines are too long
3376
dist/formulate.umd.js
vendored
3376
dist/formulate.umd.js
vendored
File diff suppressed because one or more lines are too long
28
dist/snow.css
vendored
28
dist/snow.css
vendored
@ -49,6 +49,22 @@
|
||||
.formulate-input[data-classification='text'] input:focus {
|
||||
outline: 0;
|
||||
border: 1px solid #41b883; }
|
||||
.formulate-input[data-classification='text'] .formulate-input-element--search {
|
||||
position: relative; }
|
||||
.formulate-input[data-classification='text'] .formulate-input-element--search::before {
|
||||
content: '';
|
||||
width: 2em;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72.99 72.9"><path fill="%236d6d6d" d="M71.77,66,53.87,48.1A29.94,29.94,0,1,0,30,60a29.52,29.52,0,0,0,18.1-6.1l18,17.8A4,4,0,0,0,69,72.9a4.18,4.18,0,0,0,2.9-1.2A4.09,4.09,0,0,0,71.77,66ZM30.07,51.9a21.9,21.9,0,1,1,15.5-37.4A21.37,21.37,0,0,1,52,30a22,22,0,0,1-6.4,15.5A21.54,21.54,0,0,1,30.07,51.9Z"/></svg>');
|
||||
background-size: 1em 1em;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
pointer-events: none; }
|
||||
.formulate-input[data-classification='text'] .formulate-input-element--search input {
|
||||
padding-left: 2em; }
|
||||
.formulate-input[data-classification='text'] input[type="color"] {
|
||||
height: 1.1em;
|
||||
box-sizing: content-box; }
|
||||
@ -72,6 +88,18 @@
|
||||
border-radius: .2em;
|
||||
border: 0;
|
||||
flex: auto; }
|
||||
.formulate-input[data-classification='slider'] .formulate-input-element--range {
|
||||
display: flex;
|
||||
align-items: center; }
|
||||
.formulate-input[data-classification='slider'] .formulate-input-element-range-value {
|
||||
font-size: .9em;
|
||||
line-height: 1;
|
||||
margin-left: .5em;
|
||||
background-color: #efefef;
|
||||
padding: .25em .3em;
|
||||
border-radius: .25em;
|
||||
color: #6d6d6d;
|
||||
font-variant-numeric: tabular-nums; }
|
||||
.formulate-input[data-classification='slider'] input {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
|
4
dist/snow.min.css
vendored
4
dist/snow.min.css
vendored
File diff suppressed because one or more lines are too long
76
package-lock.json
generated
76
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@braid/vue-formulate",
|
||||
"version": "2.0.0-alpha.1",
|
||||
"version": "2.0.0-alpha.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -8,7 +8,6 @@
|
||||
"version": "7.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
|
||||
"integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.0.0"
|
||||
}
|
||||
@ -1541,7 +1540,6 @@
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
|
||||
"integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.0.0",
|
||||
"esutils": "^2.0.2",
|
||||
@ -3334,7 +3332,6 @@
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
@ -4260,8 +4257,7 @@
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"cache-base": {
|
||||
"version": "1.0.1",
|
||||
@ -4398,7 +4394,6 @@
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
@ -4686,7 +4681,6 @@
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
@ -4694,8 +4688,7 @@
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"color-string": {
|
||||
"version": "1.5.3",
|
||||
@ -4719,8 +4712,7 @@
|
||||
"commander": {
|
||||
"version": "2.20.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz",
|
||||
"integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg=="
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.3.0",
|
||||
@ -5570,8 +5562,7 @@
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"escodegen": {
|
||||
"version": "1.12.0",
|
||||
@ -5891,14 +5882,12 @@
|
||||
"estree-walker": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
|
||||
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
|
||||
},
|
||||
"exec-sh": {
|
||||
"version": "0.3.2",
|
||||
@ -7167,8 +7156,7 @@
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.0",
|
||||
@ -8362,7 +8350,6 @@
|
||||
"version": "24.9.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
|
||||
"integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"merge-stream": "^2.0.0",
|
||||
"supports-color": "^6.1.0"
|
||||
@ -8372,7 +8359,6 @@
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
@ -8408,8 +8394,7 @@
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.13.1",
|
||||
@ -8967,8 +8952,7 @@
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
|
||||
},
|
||||
"merge2": {
|
||||
"version": "1.3.0",
|
||||
@ -11497,6 +11481,18 @@
|
||||
"rollup-pluginutils": "^2.8.1"
|
||||
}
|
||||
},
|
||||
"rollup-plugin-terser": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.2.0.tgz",
|
||||
"integrity": "sha512-jQI+nYhtDBc9HFRBz8iGttQg7li9klmzR62RG2W2nN6hJ/FI2K2ItYQ7kJ7/zn+vs+BP1AEccmVRjRN989I+Nw==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.5.5",
|
||||
"jest-worker": "^24.9.0",
|
||||
"rollup-pluginutils": "^2.8.2",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"terser": "^4.6.2"
|
||||
}
|
||||
},
|
||||
"rollup-plugin-vue": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/rollup-plugin-vue/-/rollup-plugin-vue-5.1.6.tgz",
|
||||
@ -11526,7 +11522,6 @@
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
|
||||
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estree-walker": "^0.6.1"
|
||||
}
|
||||
@ -11847,6 +11842,11 @@
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
|
||||
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ=="
|
||||
},
|
||||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
@ -12131,7 +12131,6 @@
|
||||
"version": "0.5.13",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
|
||||
"integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
@ -12140,8 +12139,7 @@
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -12446,7 +12444,6 @@
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
@ -12535,6 +12532,23 @@
|
||||
"inherits": "2"
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "4.6.4",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.4.tgz",
|
||||
"integrity": "sha512-5fqgBPLgVHZ/fVvqRhhUp9YUiGXhFJ9ZkrZWD9vQtFBR4QIGTnbsb+/kKqSqfgp3WnBwGWAFnedGTtmX1YTn0w==",
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.6.1",
|
||||
"source-map-support": "~0.5.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"test-exclude": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@braid/vue-formulate",
|
||||
"version": "2.0.0-alpha.2",
|
||||
"version": "2.0.0-alpha.3",
|
||||
"description": "The easiest way to build forms in Vue.",
|
||||
"main": "dist/formulate.umd.js",
|
||||
"module": "dist/formulate.esm.js",
|
||||
@ -82,6 +82,7 @@
|
||||
"clone-deep": "^4.0.1",
|
||||
"is-plain-object": "^3.0.0",
|
||||
"is-url": "^1.2.4",
|
||||
"nanoid": "^2.1.11"
|
||||
"nanoid": "^2.1.11",
|
||||
"rollup-plugin-terser": "^5.2.0"
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +111,8 @@ class Formulate {
|
||||
* Get validation rules.
|
||||
* @return {object} object of validation functions
|
||||
*/
|
||||
rules () {
|
||||
return this.options.rules
|
||||
rules (rules = {}) {
|
||||
return { ...this.options.rules, ...rules }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,6 +161,18 @@ export default {
|
||||
preventWindowDrops: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showValue: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
validationMessages: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
validationRules: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@ -220,27 +232,43 @@ export default {
|
||||
}
|
||||
},
|
||||
performValidation () {
|
||||
const rules = parseRules(this.validation, this.$formulate.rules())
|
||||
const rules = parseRules(this.validation, this.$formulate.rules(this.validationRules))
|
||||
this.pendingValidation = Promise.all(
|
||||
rules.map(([rule, args]) => {
|
||||
return rule({
|
||||
var res = rule({
|
||||
value: this.context.model,
|
||||
getFormValues: this.getFormValues.bind(this),
|
||||
name: this.context.name
|
||||
}, ...args)
|
||||
.then(res => res ? false : this.$formulate.validationMessage(rule.name, {
|
||||
args,
|
||||
name: this.mergedValidationName,
|
||||
value: this.context.model,
|
||||
vm: this,
|
||||
formValues: this.getFormValues()
|
||||
}))
|
||||
res = (res instanceof Promise) ? res : Promise.resolve(res)
|
||||
return res.then(res => res ? false : this.getValidationMessage(rule, args))
|
||||
})
|
||||
)
|
||||
.then(result => result.filter(result => result))
|
||||
.then(errorMessages => { this.validationErrors = errorMessages })
|
||||
return this.pendingValidation
|
||||
},
|
||||
getValidationMessage (rule, args) {
|
||||
return this.getValidationFunction(rule)({
|
||||
args,
|
||||
name: this.mergedValidationName,
|
||||
value: this.context.model,
|
||||
vm: this,
|
||||
formValues: this.getFormValues()
|
||||
})
|
||||
},
|
||||
getValidationFunction (rule) {
|
||||
const ruleName = rule.name.substr(0, 1) === '_' ? rule.name.substr(1) : rule.name
|
||||
if (this.validationMessages && typeof this.validationMessages === 'object' && typeof this.validationMessages[ruleName] !== 'undefined') {
|
||||
switch (typeof this.validationMessages[ruleName]) {
|
||||
case 'function':
|
||||
return this.validationMessages[ruleName]
|
||||
case 'string':
|
||||
return () => this.validationMessages[ruleName]
|
||||
}
|
||||
}
|
||||
return (context) => this.$formulate.validationMessage(rule.name, context)
|
||||
},
|
||||
hasValidationErrors () {
|
||||
return new Promise(resolve => {
|
||||
this.$nextTick(() => {
|
||||
|
@ -9,6 +9,11 @@
|
||||
v-bind="attributes"
|
||||
@blur="context.blurHandler"
|
||||
>
|
||||
<div
|
||||
v-if="context.showValue"
|
||||
class="formulate-input-element-range-value"
|
||||
v-text="context.model"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -53,14 +53,14 @@ function typeContext () {
|
||||
optionGroups: this.optionGroups ? map(this.optionGroups, (k, v) => createOptionList.call(this, v)) : false,
|
||||
placeholder: this.$attrs.placeholder || false
|
||||
}
|
||||
case 'group':
|
||||
case 'slider':
|
||||
return { showValue: !!this.showValue }
|
||||
default:
|
||||
if (this.options) {
|
||||
return {
|
||||
options: createOptionList.call(this, this.options)
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
@ -156,16 +156,15 @@ describe('FormulateForm', () => {
|
||||
expect(wrapper.emitted('submit-raw')[0][0]).toBeInstanceOf(FormSubmission)
|
||||
})
|
||||
|
||||
// it('resolves hasValidationErrors to true', async () => {
|
||||
// const wrapper = mount(FormulateForm, {
|
||||
// slots: { default: '<FormulateInput type="text" validation="required" name="testinput" />' }
|
||||
// })
|
||||
// wrapper.find('form').trigger('submit')
|
||||
// await flushPromises()
|
||||
// const submission = wrapper.emitted('submit-raw')[0][0]
|
||||
// expect(await submission.hasValidationErrors()).toBe(true)
|
||||
// })
|
||||
|
||||
it('resolves hasValidationErrors to true', async () => {
|
||||
const wrapper = mount(FormulateForm, {
|
||||
slots: { default: '<FormulateInput type="text" validation="required" name="testinput" />' }
|
||||
})
|
||||
wrapper.find('form').trigger('submit')
|
||||
await flushPromises()
|
||||
const submission = wrapper.emitted('submit-raw')[0][0]
|
||||
expect(await submission.hasValidationErrors()).toBe(true)
|
||||
})
|
||||
|
||||
it('resolves submitted form values to an object', async () => {
|
||||
const wrapper = mount(FormulateForm, {
|
||||
|
120
test/FormulateInput.test.js
Normal file
120
test/FormulateInput.test.js
Normal file
@ -0,0 +1,120 @@
|
||||
import Vue from 'vue'
|
||||
import flushPromises from 'flush-promises'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import Formulate from '../src/Formulate.js'
|
||||
import FormulateInput from '@/FormulateInput.vue'
|
||||
import FormulateInputBox from '@/inputs/FormulateInputBox.vue'
|
||||
|
||||
const globalRule = jest.fn((context) => { return false })
|
||||
|
||||
Vue.use(Formulate, {
|
||||
locales: {
|
||||
en: {
|
||||
email: ({ value }) => `Super invalid email: ${value}`
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
globalRule
|
||||
},
|
||||
library: {
|
||||
special: {
|
||||
classification: 'box',
|
||||
component: 'FormulateInputBox'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
describe('FormulateInput', () => {
|
||||
it('allows custom field-rule level validation strings', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'text',
|
||||
validation: 'required|in:abcdef',
|
||||
validationMessages: {in: 'the value was different than expected'},
|
||||
errorBehavior: 'live',
|
||||
value: 'other value'
|
||||
} })
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.formulate-input-error').text()).toBe('the value was different than expected')
|
||||
})
|
||||
|
||||
it('allows custom field-rule level validation functions', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'text',
|
||||
validation: 'required|in:abcdef',
|
||||
validationMessages: { in: ({ value }) => `The string ${value} is not correct.` },
|
||||
errorBehavior: 'live',
|
||||
value: 'other value'
|
||||
} })
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.formulate-input-error').text()).toBe('The string other value is not correct.')
|
||||
})
|
||||
|
||||
it('uses globally overridden validation messages', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'text',
|
||||
validation: 'required|email',
|
||||
errorBehavior: 'live',
|
||||
value: 'wrong email'
|
||||
} })
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.formulate-input-error').text()).toBe('Super invalid email: wrong email')
|
||||
})
|
||||
|
||||
it('uses custom async validation rules on defined on the field', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'text',
|
||||
validation: 'required|foobar',
|
||||
validationMessages: {
|
||||
foobar: 'failed the foobar check'
|
||||
},
|
||||
validationRules: {
|
||||
foobar: async ({ value }) => value === 'foo'
|
||||
},
|
||||
validation: 'required|foobar',
|
||||
errorBehavior: 'live',
|
||||
value: 'bar'
|
||||
} })
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.formulate-input-error').text()).toBe('failed the foobar check')
|
||||
})
|
||||
|
||||
it('uses custom sync validation rules on defined on the field', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'text',
|
||||
validation: 'required|foobar',
|
||||
validationMessages: {
|
||||
foobar: 'failed the foobar check'
|
||||
},
|
||||
validationRules: {
|
||||
foobar: ({ value }) => value === 'foo'
|
||||
},
|
||||
validation: 'required|foobar',
|
||||
errorBehavior: 'live',
|
||||
value: 'bar'
|
||||
} })
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.formulate-input-error').text()).toBe('failed the foobar check')
|
||||
})
|
||||
|
||||
it('uses global custom validation rules', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'text',
|
||||
validation: 'required|globalRule',
|
||||
errorBehavior: 'live',
|
||||
value: 'bar'
|
||||
} })
|
||||
await flushPromises()
|
||||
expect(globalRule.mock.calls.length).toBe(1)
|
||||
})
|
||||
|
||||
it('can extend its standard library of inputs', async () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: {
|
||||
type: 'special',
|
||||
validation: 'required',
|
||||
errorBehavior: 'live',
|
||||
value: 'bar'
|
||||
} })
|
||||
await flushPromises()
|
||||
expect(wrapper.contains(FormulateInputBox)).toBe(true)
|
||||
})
|
||||
})
|
@ -15,4 +15,14 @@ describe('FormulateInputSlider', () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: { type: 'range' } })
|
||||
expect(wrapper.contains(FormulateInputSlider)).toBe(true)
|
||||
})
|
||||
|
||||
it('does not show value if the show-value prop is not set', () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: { type: 'range', value: '15', min: '0', max: '100' } })
|
||||
expect(wrapper.find('.formulate-input-element-range-value').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('renders the value when type is "range" and show-value prop is set', () => {
|
||||
const wrapper = mount(FormulateInput, { propsData: { type: 'range', showValue: 'true', value: '15', min: '0', max: '100' } })
|
||||
expect(wrapper.find('.formulate-input-element-range-value').text()).toBe('15')
|
||||
})
|
||||
})
|
||||
|
@ -20,5 +20,5 @@ module.exports = {
|
||||
collectCoverageFrom: [
|
||||
"src/*.{js,vue}",
|
||||
],
|
||||
verbose: true
|
||||
// verbose: true
|
||||
}
|
||||
|
@ -57,6 +57,27 @@
|
||||
@include baseinput;
|
||||
}
|
||||
|
||||
.formulate-input-element--search {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 2em;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72.99 72.9"><path fill="%23#{str-slice("#{$formulate-gray-ddd}", 2)}" d="M71.77,66,53.87,48.1A29.94,29.94,0,1,0,30,60a29.52,29.52,0,0,0,18.1-6.1l18,17.8A4,4,0,0,0,69,72.9a4.18,4.18,0,0,0,2.9-1.2A4.09,4.09,0,0,0,71.77,66ZM30.07,51.9a21.9,21.9,0,1,1,15.5-37.4A21.37,21.37,0,0,1,52,30a22,22,0,0,1-6.4,15.5A21.54,21.54,0,0,1,30.07,51.9Z"/></svg>');
|
||||
background-size: 1em 1em;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
input {
|
||||
padding-left: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="color"] {
|
||||
height: 1.1em;
|
||||
box-sizing: content-box;
|
||||
@ -93,6 +114,22 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
&[data-classification='slider'] {
|
||||
.formulate-input-element--range {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.formulate-input-element-range-value {
|
||||
font-size: .9em;
|
||||
line-height: 1;
|
||||
margin-left: .5em;
|
||||
background-color: $formulate-gray;
|
||||
padding: .25em .3em;
|
||||
border-radius: .25em;
|
||||
color: $formulate-gray-ddd;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
input {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
|
Loading…
x
Reference in New Issue
Block a user