diff --git a/dist/formulate.esm.js b/dist/formulate.esm.js
index 51d2372..76bf251 100644
--- a/dist/formulate.esm.js
+++ b/dist/formulate.esm.js
@@ -1,6 +1,6 @@
import isUrl from 'is-url';
-import isPlainObject from 'is-plain-object';
import nanoid from 'nanoid';
+import isPlainObject from 'is-plain-object';
var library = {
// === SINGLE LINE TEXT STYLE INPUTS
@@ -97,9 +97,129 @@ var library = {
select: {
classification: 'select',
component: 'FormulateInputSelect'
+ },
+
+ // === FILE TYPE
+
+ file: {
+ classification: 'file',
+ component: 'FormulateInputFile'
+ },
+ image: {
+ classification: 'file',
+ component: 'FormulateInputFile'
}
};
+/**
+ * The file upload class holds and represents a file’s upload state durring
+ * the upload flow.
+ */
+var FileUpload = function FileUpload (fileList, context, options) {
+ this.fileList = fileList;
+ this.files = [];
+ this.options = options;
+ this.setFileList(fileList);
+ this.context = context;
+};
+
+/**
+ * Produce an array of files and alert the callback.
+ * @param {FileList}
+ */
+FileUpload.prototype.setFileList = function setFileList (fileList) {
+ for (var i = 0; i < fileList.length; i++) {
+ var file = fileList.item(i);
+ this.files.push({
+ progress: 0,
+ name: file.name || 'file-upload',
+ file: file,
+ uuid: nanoid()
+ });
+ }
+};
+
+/**
+ * Check if the file has an.
+ */
+FileUpload.prototype.hasUploader = function hasUploader () {
+ return !!this.context.uploader
+};
+
+FileUpload.prototype.uploaderIsAxios = function uploaderIsAxios () {
+ if (
+ this.hasUploader &&
+ typeof this.hasUploader.request === 'function' &&
+ typeof this.hasUploader.get === 'function' &&
+ typeof this.hasUploader.delete === 'function' &&
+ typeof this.hasUploader.post === 'function'
+ ) {
+ return true
+ }
+ return false
+};
+
+/**
+ * Get a new uploader function.
+ */
+FileUpload.prototype.getUploader = function getUploader () {
+ var ref;
+
+ var args = [], len = arguments.length;
+ while ( len-- ) args[ len ] = arguments[ len ];
+ if (this.uploaderIsAxios()) {
+ var formData = new FormData();
+ formData.append(this.context.name || 'file', args[0]);
+ return this.uploader.post(this.context.uploadUrl, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ },
+ onUploadProgress: function (progressEvent) {
+ args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total));
+ }
+ })
+ .catch(function (err) { return args[2](err); })
+ }
+ return (ref = this.context).uploader.apply(ref, args)
+};
+
+/**
+ * Perform the file upload.
+ */
+FileUpload.prototype.upload = function upload () {
+ var this$1 = this;
+
+ return new Promise(function (resolve, reject) {
+ if (!this$1.hasUploader) {
+ return reject(new Error('No uploader has been defined'))
+ }
+ Promise.all(this$1.files.map(function (file) {
+ return this$1.getUploader(
+ file.file,
+ function (progress) { file.progress = progress; },
+ function (error) { return reject(new Error(error)); },
+ this$1.options
+ )
+ }))
+ .then(function (results) { return resolve(results); })
+ .catch(function (err) { throw new Error(err) });
+ })
+};
+
+/**
+ * Get the files.
+ */
+FileUpload.prototype.getFileList = function getFileList () {
+ return this.fileList
+};
+
+/**
+ * Get the files.
+ */
+FileUpload.prototype.getFiles = function getFiles () {
+ return this.files
+};
+
/**
* Function to map over an object.
* @param {Object} obj An object to map over
@@ -389,19 +509,20 @@ var rules = {
/**
* Check the maximum value of a particular.
*/
- max: function (value, minimum) {
+ max: function (value, minimum, force) {
if ( minimum === void 0 ) minimum = 10;
return Promise.resolve((function () {
- minimum = Number(minimum);
- if (!isNaN(value)) {
- value = Number(value);
- return value <= minimum
- }
- if (typeof value === 'string') {
+ if (Array.isArray(value)) {
+ minimum = !isNaN(minimum) ? Number(minimum) : minimum;
return value.length <= minimum
}
- if (Array.isArray(value)) {
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ value = !isNaN(value) ? Number(value) : value;
+ return value <= minimum
+ }
+ if (typeof value === 'string' || (force === 'length')) {
+ value = !isNaN(value) ? value.toString() : value;
return value.length <= minimum
}
return false
@@ -416,6 +537,12 @@ var rules = {
while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ];
return Promise.resolve((function () {
+ if (files instanceof FileUpload) {
+ if (files.hasUploader()) {
+ return false
+ }
+ files = files.getFiles();
+ }
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
for (var i in files) {
if (!types.includes(files[i].type)) {
@@ -639,10 +766,14 @@ var en = {
var value = ref.value;
var args = ref.args;
- if (!isNaN(value)) {
- return (name + " must be less than " + (args[0]) + ".")
+ if (Array.isArray(value)) {
+ return ("You may only select " + (args[0]) + " " + name + ".")
}
- return (name + " must be less than " + (args[0]) + " characters long.")
+ var force = Array.isArray(args) && args[1] ? args[1] : false;
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return ((sentence(name)) + " must be less than " + (args[0]) + ".")
+ }
+ return ((sentence(name)) + " must be less than " + (args[0]) + " characters long.")
},
/**
@@ -653,10 +784,14 @@ var en = {
var value = ref.value;
var args = ref.args;
- if (!isNaN(value)) {
- return (name + " must be more than " + (args[0]) + ".")
+ if (Array.isArray(value)) {
+ return ("You must select at least " + (args[0]) + " " + name + ".")
}
- return (name + " must be more than " + (args[0]) + " characters long.")
+ var force = Array.isArray(args) && args[1] ? args[1] : false;
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return ((sentence(name)) + " must be more than " + (args[0]) + ".")
+ }
+ return ((sentence(name)) + " must be more than " + (args[0]) + " characters long.")
},
/**
@@ -697,6 +832,35 @@ var en = {
}
};
+/**
+ * A fake uploader used by default.
+ *
+ * @param {File} file
+ * @param {function} progress
+ * @param {function} error
+ * @param {object} options
+ */
+function fauxUploader (file, progress, error, options) {
+ return new Promise(function (resolve, reject) {
+ var totalTime = options.fauxUploaderDuration || 2000;
+ var start = performance.now();
+ var advance = function () { return setTimeout(function () {
+ var elapsed = performance.now() - start;
+ var currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100));
+ progress(currentProgress);
+ if (currentProgress >= 100) {
+ resolve({
+ url: 'http://via.placeholder.com/350x150.png',
+ name: file.name
+ });
+ } else {
+ advance();
+ }
+ }, 20); };
+ advance();
+ })
+}
+
/**
* For a single instance of an input, export all of the context needed to fully
* render that element.
@@ -713,7 +877,11 @@ var context = {
label: this.label,
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes,
- blurHandler: blurHandler.bind(this)},
+ blurHandler: blurHandler.bind(this),
+ showImage: this.showImage,
+ uploadUrl: this.uploadUrl,
+ uploader: this.uploader || this.$formulate.getUploader(),
+ immediateUpload: this.immediateUpload},
this.typeContext))
},
nameOrFallback: nameOrFallback,
@@ -1001,6 +1169,22 @@ var script = {
showErrors: {
type: Boolean,
default: false
+ },
+ showImage: {
+ type: Boolean,
+ default: true
+ },
+ uploadUrl: {
+ type: [String, Boolean],
+ default: false
+ },
+ uploader: {
+ type: [Function, Object, Boolean],
+ default: false
+ },
+ immediateUpload: {
+ type: Boolean,
+ default: true
}
},
data: function data () {
@@ -1989,6 +2173,219 @@ __vue_render__$5._withStripped = true;
//
var script$6 = {
+ name: 'FormulateFiles',
+ props: {
+ files: {
+ type: FileUpload,
+ required: true
+ }
+ },
+ computed: {
+ fileUploads: function fileUploads () {
+ return this.files.files || []
+ }
+ }
+};
+
+/* script */
+var __vue_script__$6 = script$6;
+
+/* template */
+var __vue_render__$6 = function() {
+ var _vm = this;
+ var _h = _vm.$createElement;
+ var _c = _vm._self._c || _h;
+ return _vm.fileUploads.length
+ ? _c(
+ "ul",
+ { staticClass: "formulate-files" },
+ _vm._l(_vm.fileUploads, function(file) {
+ return _c("li", { key: file.uuid, staticClass: "formulate-file" }, [
+ _c("span", {
+ staticClass: "formualte-file-name",
+ domProps: { textContent: _vm._s(file.name) }
+ }),
+ _vm._v(" "),
+ file.progress > 0 && file.progress < 100
+ ? _c("span", {
+ domProps: { textContent: _vm._s(file.progress + "%") }
+ })
+ : _vm._e()
+ ])
+ }),
+ 0
+ )
+ : _vm._e()
+};
+var __vue_staticRenderFns__$6 = [];
+__vue_render__$6._withStripped = true;
+
+ /* style */
+ var __vue_inject_styles__$6 = undefined;
+ /* scoped */
+ var __vue_scope_id__$6 = undefined;
+ /* module identifier */
+ var __vue_module_identifier__$6 = undefined;
+ /* functional template */
+ var __vue_is_functional_template__$6 = false;
+ /* style inject */
+
+ /* style inject SSR */
+
+ /* style inject shadow dom */
+
+
+
+ var FormulateFiles = normalizeComponent(
+ { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
+ __vue_inject_styles__$6,
+ __vue_script__$6,
+ __vue_scope_id__$6,
+ __vue_is_functional_template__$6,
+ __vue_module_identifier__$6,
+ false,
+ undefined,
+ undefined,
+ undefined
+ );
+
+//
+
+var script$7 = {
+ name: 'FormulateInputFile',
+ components: {
+ FormulateFiles: FormulateFiles
+ },
+ mixins: [FormulateInputMixin],
+ data: function data () {
+ return {
+ isOver: false
+ }
+ },
+ computed: {
+ hasFiles: function hasFiles () {
+ return (this.context.model instanceof FileUpload && this.context.model.files.length)
+ }
+ },
+ methods: {
+ handleFile: function handleFile () {
+ var input = this.$refs.file;
+ if (input.files.length) {
+ this.context.model = this.$formulate.createUpload(input.files, this.context);
+ }
+ if (this.context.immediateUpload && this.context.model instanceof FileUpload) {
+ this.context.model.upload();
+ }
+ },
+ handleDragOver: function handleDragOver (e) {
+ e.preventDefault();
+ this.isOver = true;
+ },
+ handleDragLeave: function handleDragLeave (e) {
+ e.preventDefault();
+ this.isOver = false;
+ }
+ }
+};
+
+/* script */
+var __vue_script__$7 = script$7;
+
+/* template */
+var __vue_render__$7 = function() {
+ var _vm = this;
+ var _h = _vm.$createElement;
+ var _c = _vm._self._c || _h;
+ return _c(
+ "div",
+ {
+ class:
+ "formulate-input-element formulate-input-element--" + _vm.context.type,
+ attrs: { "data-type": _vm.context.type, "data-has-files": _vm.hasFiles }
+ },
+ [
+ _c(
+ "div",
+ {
+ staticClass: "formulate-input-upload-area",
+ attrs: { "data-has-files": _vm.hasFiles }
+ },
+ [
+ _c(
+ "input",
+ _vm._b(
+ {
+ ref: "file",
+ attrs: { "data-is-drag-hover": _vm.isOver, type: "file" },
+ on: {
+ blur: _vm.context.blurHandler,
+ change: _vm.handleFile,
+ dragover: _vm.handleDragOver,
+ dragleave: _vm.handleDragLeave
+ }
+ },
+ "input",
+ _vm.attributes,
+ false
+ )
+ ),
+ _vm._v(" "),
+ _c("div", {
+ directives: [
+ {
+ name: "show",
+ rawName: "v-show",
+ value: !_vm.hasFiles,
+ expression: "!hasFiles"
+ }
+ ],
+ staticClass: "formulate-input-upload-area-mask"
+ }),
+ _vm._v(" "),
+ _vm.hasFiles
+ ? _c("FormulateFiles", { attrs: { files: _vm.context.model } })
+ : _vm._e()
+ ],
+ 1
+ )
+ ]
+ )
+};
+var __vue_staticRenderFns__$7 = [];
+__vue_render__$7._withStripped = true;
+
+ /* style */
+ var __vue_inject_styles__$7 = undefined;
+ /* scoped */
+ var __vue_scope_id__$7 = undefined;
+ /* module identifier */
+ var __vue_module_identifier__$7 = undefined;
+ /* functional template */
+ var __vue_is_functional_template__$7 = false;
+ /* style inject */
+
+ /* style inject SSR */
+
+ /* style inject shadow dom */
+
+
+
+ var FormulateInputFile = normalizeComponent(
+ { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
+ __vue_inject_styles__$7,
+ __vue_script__$7,
+ __vue_scope_id__$7,
+ __vue_is_functional_template__$7,
+ __vue_module_identifier__$7,
+ false,
+ undefined,
+ undefined,
+ undefined
+ );
+
+//
+
+var script$8 = {
name: 'FormulateInputSelect',
mixins: [FormulateInputMixin],
computed: {
@@ -2005,10 +2402,10 @@ var script$6 = {
};
/* script */
-var __vue_script__$6 = script$6;
+var __vue_script__$8 = script$8;
/* template */
-var __vue_render__$6 = function() {
+var __vue_render__$8 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2120,17 +2517,17 @@ var __vue_render__$6 = function() {
]
)
};
-var __vue_staticRenderFns__$6 = [];
-__vue_render__$6._withStripped = true;
+var __vue_staticRenderFns__$8 = [];
+__vue_render__$8._withStripped = true;
/* style */
- var __vue_inject_styles__$6 = undefined;
+ var __vue_inject_styles__$8 = undefined;
/* scoped */
- var __vue_scope_id__$6 = undefined;
+ var __vue_scope_id__$8 = undefined;
/* module identifier */
- var __vue_module_identifier__$6 = undefined;
+ var __vue_module_identifier__$8 = undefined;
/* functional template */
- var __vue_is_functional_template__$6 = false;
+ var __vue_is_functional_template__$8 = false;
/* style inject */
/* style inject SSR */
@@ -2140,12 +2537,12 @@ __vue_render__$6._withStripped = true;
var FormulateInputSelect = normalizeComponent(
- { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
- __vue_inject_styles__$6,
- __vue_script__$6,
- __vue_scope_id__$6,
- __vue_is_functional_template__$6,
- __vue_module_identifier__$6,
+ { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
+ __vue_inject_styles__$8,
+ __vue_script__$8,
+ __vue_scope_id__$8,
+ __vue_is_functional_template__$8,
+ __vue_module_identifier__$8,
false,
undefined,
undefined,
@@ -2154,16 +2551,16 @@ __vue_render__$6._withStripped = true;
//
-var script$7 = {
- name: 'FormulateInputText',
+var script$9 = {
+ name: 'FormulateInputSlider',
mixins: [FormulateInputMixin]
};
/* script */
-var __vue_script__$7 = script$7;
+var __vue_script__$9 = script$9;
/* template */
-var __vue_render__$7 = function() {
+var __vue_render__$9 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2284,17 +2681,17 @@ var __vue_render__$7 = function() {
]
)
};
-var __vue_staticRenderFns__$7 = [];
-__vue_render__$7._withStripped = true;
+var __vue_staticRenderFns__$9 = [];
+__vue_render__$9._withStripped = true;
/* style */
- var __vue_inject_styles__$7 = undefined;
+ var __vue_inject_styles__$9 = undefined;
/* scoped */
- var __vue_scope_id__$7 = undefined;
+ var __vue_scope_id__$9 = undefined;
/* module identifier */
- var __vue_module_identifier__$7 = undefined;
+ var __vue_module_identifier__$9 = undefined;
/* functional template */
- var __vue_is_functional_template__$7 = false;
+ var __vue_is_functional_template__$9 = false;
/* style inject */
/* style inject SSR */
@@ -2304,12 +2701,12 @@ __vue_render__$7._withStripped = true;
var FormulateInputSlider = normalizeComponent(
- { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
- __vue_inject_styles__$7,
- __vue_script__$7,
- __vue_scope_id__$7,
- __vue_is_functional_template__$7,
- __vue_module_identifier__$7,
+ { render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
+ __vue_inject_styles__$9,
+ __vue_script__$9,
+ __vue_scope_id__$9,
+ __vue_is_functional_template__$9,
+ __vue_module_identifier__$9,
false,
undefined,
undefined,
@@ -2318,16 +2715,16 @@ __vue_render__$7._withStripped = true;
//
-var script$8 = {
+var script$a = {
name: 'FormulateInputTextArea',
mixins: [FormulateInputMixin]
};
/* script */
-var __vue_script__$8 = script$8;
+var __vue_script__$a = script$a;
/* template */
-var __vue_render__$8 = function() {
+var __vue_render__$a = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2369,17 +2766,17 @@ var __vue_render__$8 = function() {
]
)
};
-var __vue_staticRenderFns__$8 = [];
-__vue_render__$8._withStripped = true;
+var __vue_staticRenderFns__$a = [];
+__vue_render__$a._withStripped = true;
/* style */
- var __vue_inject_styles__$8 = undefined;
+ var __vue_inject_styles__$a = undefined;
/* scoped */
- var __vue_scope_id__$8 = undefined;
+ var __vue_scope_id__$a = undefined;
/* module identifier */
- var __vue_module_identifier__$8 = undefined;
+ var __vue_module_identifier__$a = undefined;
/* functional template */
- var __vue_is_functional_template__$8 = false;
+ var __vue_is_functional_template__$a = false;
/* style inject */
/* style inject SSR */
@@ -2389,12 +2786,12 @@ __vue_render__$8._withStripped = true;
var FormulateInputTextArea = normalizeComponent(
- { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
- __vue_inject_styles__$8,
- __vue_script__$8,
- __vue_scope_id__$8,
- __vue_is_functional_template__$8,
- __vue_module_identifier__$8,
+ { render: __vue_render__$a, staticRenderFns: __vue_staticRenderFns__$a },
+ __vue_inject_styles__$a,
+ __vue_script__$a,
+ __vue_scope_id__$a,
+ __vue_is_functional_template__$a,
+ __vue_module_identifier__$a,
false,
undefined,
undefined,
@@ -2412,6 +2809,7 @@ var Formulate = function Formulate () {
FormulateInputErrors: FormulateInputErrors,
FormulateInputBox: FormulateInputBox,
FormulateInputText: FormulateInputText,
+ FormulateInputFile: FormulateInputFile,
FormulateInputGroup: FormulateInputGroup,
FormulateInputSelect: FormulateInputSelect,
FormulateInputSlider: FormulateInputSlider,
@@ -2420,6 +2818,7 @@ var Formulate = function Formulate () {
library: library,
rules: rules,
locale: 'en',
+ uploader: fauxUploader,
locales: {
en: en
}
@@ -2508,6 +2907,20 @@ Formulate.prototype.validationMessage = function validationMessage (rule, valida
return 'This field does not have a valid value'
};
+/**
+ * Get the file uploader.
+ */
+Formulate.prototype.getUploader = function getUploader () {
+ return this.options.uploader || false
+};
+
+/**
+ * Create a new instance of an upload.
+ */
+Formulate.prototype.createUpload = function createUpload (fileList, context) {
+ return new FileUpload(fileList, context, this.options)
+};
+
var Formulate$1 = new Formulate();
export default Formulate$1;
diff --git a/dist/formulate.min.js b/dist/formulate.min.js
index d32166f..dbc0489 100644
--- a/dist/formulate.min.js
+++ b/dist/formulate.min.js
@@ -1,9 +1,9 @@
-var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
+var Formulate = (function (exports, isUrl, nanoid, isPlainObject) {
'use strict';
isUrl = isUrl && isUrl.hasOwnProperty('default') ? isUrl['default'] : isUrl;
- isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
nanoid = nanoid && nanoid.hasOwnProperty('default') ? nanoid['default'] : nanoid;
+ isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
var library = {
// === SINGLE LINE TEXT STYLE INPUTS
@@ -100,9 +100,129 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
select: {
classification: 'select',
component: 'FormulateInputSelect'
+ },
+
+ // === FILE TYPE
+
+ file: {
+ classification: 'file',
+ component: 'FormulateInputFile'
+ },
+ image: {
+ classification: 'file',
+ component: 'FormulateInputFile'
}
};
+ /**
+ * The file upload class holds and represents a file’s upload state durring
+ * the upload flow.
+ */
+ var FileUpload = function FileUpload (fileList, context, options) {
+ this.fileList = fileList;
+ this.files = [];
+ this.options = options;
+ this.setFileList(fileList);
+ this.context = context;
+ };
+
+ /**
+ * Produce an array of files and alert the callback.
+ * @param {FileList}
+ */
+ FileUpload.prototype.setFileList = function setFileList (fileList) {
+ for (var i = 0; i < fileList.length; i++) {
+ var file = fileList.item(i);
+ this.files.push({
+ progress: 0,
+ name: file.name || 'file-upload',
+ file: file,
+ uuid: nanoid()
+ });
+ }
+ };
+
+ /**
+ * Check if the file has an.
+ */
+ FileUpload.prototype.hasUploader = function hasUploader () {
+ return !!this.context.uploader
+ };
+
+ FileUpload.prototype.uploaderIsAxios = function uploaderIsAxios () {
+ if (
+ this.hasUploader &&
+ typeof this.hasUploader.request === 'function' &&
+ typeof this.hasUploader.get === 'function' &&
+ typeof this.hasUploader.delete === 'function' &&
+ typeof this.hasUploader.post === 'function'
+ ) {
+ return true
+ }
+ return false
+ };
+
+ /**
+ * Get a new uploader function.
+ */
+ FileUpload.prototype.getUploader = function getUploader () {
+ var ref;
+
+ var args = [], len = arguments.length;
+ while ( len-- ) args[ len ] = arguments[ len ];
+ if (this.uploaderIsAxios()) {
+ var formData = new FormData();
+ formData.append(this.context.name || 'file', args[0]);
+ return this.uploader.post(this.context.uploadUrl, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ },
+ onUploadProgress: function (progressEvent) {
+ args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total));
+ }
+ })
+ .catch(function (err) { return args[2](err); })
+ }
+ return (ref = this.context).uploader.apply(ref, args)
+ };
+
+ /**
+ * Perform the file upload.
+ */
+ FileUpload.prototype.upload = function upload () {
+ var this$1 = this;
+
+ return new Promise(function (resolve, reject) {
+ if (!this$1.hasUploader) {
+ return reject(new Error('No uploader has been defined'))
+ }
+ Promise.all(this$1.files.map(function (file) {
+ return this$1.getUploader(
+ file.file,
+ function (progress) { file.progress = progress; },
+ function (error) { return reject(new Error(error)); },
+ this$1.options
+ )
+ }))
+ .then(function (results) { return resolve(results); })
+ .catch(function (err) { throw new Error(err) });
+ })
+ };
+
+ /**
+ * Get the files.
+ */
+ FileUpload.prototype.getFileList = function getFileList () {
+ return this.fileList
+ };
+
+ /**
+ * Get the files.
+ */
+ FileUpload.prototype.getFiles = function getFiles () {
+ return this.files
+ };
+
/**
* Function to map over an object.
* @param {Object} obj An object to map over
@@ -392,19 +512,20 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
/**
* Check the maximum value of a particular.
*/
- max: function (value, minimum) {
+ max: function (value, minimum, force) {
if ( minimum === void 0 ) minimum = 10;
return Promise.resolve((function () {
- minimum = Number(minimum);
- if (!isNaN(value)) {
- value = Number(value);
- return value <= minimum
- }
- if (typeof value === 'string') {
+ if (Array.isArray(value)) {
+ minimum = !isNaN(minimum) ? Number(minimum) : minimum;
return value.length <= minimum
}
- if (Array.isArray(value)) {
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ value = !isNaN(value) ? Number(value) : value;
+ return value <= minimum
+ }
+ if (typeof value === 'string' || (force === 'length')) {
+ value = !isNaN(value) ? value.toString() : value;
return value.length <= minimum
}
return false
@@ -419,6 +540,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ];
return Promise.resolve((function () {
+ if (files instanceof FileUpload) {
+ if (files.hasUploader()) {
+ return false
+ }
+ files = files.getFiles();
+ }
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
for (var i in files) {
if (!types.includes(files[i].type)) {
@@ -642,10 +769,14 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
var value = ref.value;
var args = ref.args;
- if (!isNaN(value)) {
- return (name + " must be less than " + (args[0]) + ".")
+ if (Array.isArray(value)) {
+ return ("You may only select " + (args[0]) + " " + name + ".")
}
- return (name + " must be less than " + (args[0]) + " characters long.")
+ var force = Array.isArray(args) && args[1] ? args[1] : false;
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return ((sentence(name)) + " must be less than " + (args[0]) + ".")
+ }
+ return ((sentence(name)) + " must be less than " + (args[0]) + " characters long.")
},
/**
@@ -656,10 +787,14 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
var value = ref.value;
var args = ref.args;
- if (!isNaN(value)) {
- return (name + " must be more than " + (args[0]) + ".")
+ if (Array.isArray(value)) {
+ return ("You must select at least " + (args[0]) + " " + name + ".")
}
- return (name + " must be more than " + (args[0]) + " characters long.")
+ var force = Array.isArray(args) && args[1] ? args[1] : false;
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return ((sentence(name)) + " must be more than " + (args[0]) + ".")
+ }
+ return ((sentence(name)) + " must be more than " + (args[0]) + " characters long.")
},
/**
@@ -700,6 +835,35 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
}
};
+ /**
+ * A fake uploader used by default.
+ *
+ * @param {File} file
+ * @param {function} progress
+ * @param {function} error
+ * @param {object} options
+ */
+ function fauxUploader (file, progress, error, options) {
+ return new Promise(function (resolve, reject) {
+ var totalTime = options.fauxUploaderDuration || 2000;
+ var start = performance.now();
+ var advance = function () { return setTimeout(function () {
+ var elapsed = performance.now() - start;
+ var currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100));
+ progress(currentProgress);
+ if (currentProgress >= 100) {
+ resolve({
+ url: 'http://via.placeholder.com/350x150.png',
+ name: file.name
+ });
+ } else {
+ advance();
+ }
+ }, 20); };
+ advance();
+ })
+ }
+
/**
* For a single instance of an input, export all of the context needed to fully
* render that element.
@@ -716,7 +880,11 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
label: this.label,
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes,
- blurHandler: blurHandler.bind(this)},
+ blurHandler: blurHandler.bind(this),
+ showImage: this.showImage,
+ uploadUrl: this.uploadUrl,
+ uploader: this.uploader || this.$formulate.getUploader(),
+ immediateUpload: this.immediateUpload},
this.typeContext))
},
nameOrFallback: nameOrFallback,
@@ -1004,6 +1172,22 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
showErrors: {
type: Boolean,
default: false
+ },
+ showImage: {
+ type: Boolean,
+ default: true
+ },
+ uploadUrl: {
+ type: [String, Boolean],
+ default: false
+ },
+ uploader: {
+ type: [Function, Object, Boolean],
+ default: false
+ },
+ immediateUpload: {
+ type: Boolean,
+ default: true
}
},
data: function data () {
@@ -1992,6 +2176,219 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
//
var script$6 = {
+ name: 'FormulateFiles',
+ props: {
+ files: {
+ type: FileUpload,
+ required: true
+ }
+ },
+ computed: {
+ fileUploads: function fileUploads () {
+ return this.files.files || []
+ }
+ }
+ };
+
+ /* script */
+ var __vue_script__$6 = script$6;
+
+ /* template */
+ var __vue_render__$6 = function() {
+ var _vm = this;
+ var _h = _vm.$createElement;
+ var _c = _vm._self._c || _h;
+ return _vm.fileUploads.length
+ ? _c(
+ "ul",
+ { staticClass: "formulate-files" },
+ _vm._l(_vm.fileUploads, function(file) {
+ return _c("li", { key: file.uuid, staticClass: "formulate-file" }, [
+ _c("span", {
+ staticClass: "formualte-file-name",
+ domProps: { textContent: _vm._s(file.name) }
+ }),
+ _vm._v(" "),
+ file.progress > 0 && file.progress < 100
+ ? _c("span", {
+ domProps: { textContent: _vm._s(file.progress + "%") }
+ })
+ : _vm._e()
+ ])
+ }),
+ 0
+ )
+ : _vm._e()
+ };
+ var __vue_staticRenderFns__$6 = [];
+ __vue_render__$6._withStripped = true;
+
+ /* style */
+ var __vue_inject_styles__$6 = undefined;
+ /* scoped */
+ var __vue_scope_id__$6 = undefined;
+ /* module identifier */
+ var __vue_module_identifier__$6 = undefined;
+ /* functional template */
+ var __vue_is_functional_template__$6 = false;
+ /* style inject */
+
+ /* style inject SSR */
+
+ /* style inject shadow dom */
+
+
+
+ var FormulateFiles = normalizeComponent(
+ { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
+ __vue_inject_styles__$6,
+ __vue_script__$6,
+ __vue_scope_id__$6,
+ __vue_is_functional_template__$6,
+ __vue_module_identifier__$6,
+ false,
+ undefined,
+ undefined,
+ undefined
+ );
+
+ //
+
+ var script$7 = {
+ name: 'FormulateInputFile',
+ components: {
+ FormulateFiles: FormulateFiles
+ },
+ mixins: [FormulateInputMixin],
+ data: function data () {
+ return {
+ isOver: false
+ }
+ },
+ computed: {
+ hasFiles: function hasFiles () {
+ return (this.context.model instanceof FileUpload && this.context.model.files.length)
+ }
+ },
+ methods: {
+ handleFile: function handleFile () {
+ var input = this.$refs.file;
+ if (input.files.length) {
+ this.context.model = this.$formulate.createUpload(input.files, this.context);
+ }
+ if (this.context.immediateUpload && this.context.model instanceof FileUpload) {
+ this.context.model.upload();
+ }
+ },
+ handleDragOver: function handleDragOver (e) {
+ e.preventDefault();
+ this.isOver = true;
+ },
+ handleDragLeave: function handleDragLeave (e) {
+ e.preventDefault();
+ this.isOver = false;
+ }
+ }
+ };
+
+ /* script */
+ var __vue_script__$7 = script$7;
+
+ /* template */
+ var __vue_render__$7 = function() {
+ var _vm = this;
+ var _h = _vm.$createElement;
+ var _c = _vm._self._c || _h;
+ return _c(
+ "div",
+ {
+ class:
+ "formulate-input-element formulate-input-element--" + _vm.context.type,
+ attrs: { "data-type": _vm.context.type, "data-has-files": _vm.hasFiles }
+ },
+ [
+ _c(
+ "div",
+ {
+ staticClass: "formulate-input-upload-area",
+ attrs: { "data-has-files": _vm.hasFiles }
+ },
+ [
+ _c(
+ "input",
+ _vm._b(
+ {
+ ref: "file",
+ attrs: { "data-is-drag-hover": _vm.isOver, type: "file" },
+ on: {
+ blur: _vm.context.blurHandler,
+ change: _vm.handleFile,
+ dragover: _vm.handleDragOver,
+ dragleave: _vm.handleDragLeave
+ }
+ },
+ "input",
+ _vm.attributes,
+ false
+ )
+ ),
+ _vm._v(" "),
+ _c("div", {
+ directives: [
+ {
+ name: "show",
+ rawName: "v-show",
+ value: !_vm.hasFiles,
+ expression: "!hasFiles"
+ }
+ ],
+ staticClass: "formulate-input-upload-area-mask"
+ }),
+ _vm._v(" "),
+ _vm.hasFiles
+ ? _c("FormulateFiles", { attrs: { files: _vm.context.model } })
+ : _vm._e()
+ ],
+ 1
+ )
+ ]
+ )
+ };
+ var __vue_staticRenderFns__$7 = [];
+ __vue_render__$7._withStripped = true;
+
+ /* style */
+ var __vue_inject_styles__$7 = undefined;
+ /* scoped */
+ var __vue_scope_id__$7 = undefined;
+ /* module identifier */
+ var __vue_module_identifier__$7 = undefined;
+ /* functional template */
+ var __vue_is_functional_template__$7 = false;
+ /* style inject */
+
+ /* style inject SSR */
+
+ /* style inject shadow dom */
+
+
+
+ var FormulateInputFile = normalizeComponent(
+ { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
+ __vue_inject_styles__$7,
+ __vue_script__$7,
+ __vue_scope_id__$7,
+ __vue_is_functional_template__$7,
+ __vue_module_identifier__$7,
+ false,
+ undefined,
+ undefined,
+ undefined
+ );
+
+ //
+
+ var script$8 = {
name: 'FormulateInputSelect',
mixins: [FormulateInputMixin],
computed: {
@@ -2008,10 +2405,10 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
};
/* script */
- var __vue_script__$6 = script$6;
+ var __vue_script__$8 = script$8;
/* template */
- var __vue_render__$6 = function() {
+ var __vue_render__$8 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2123,17 +2520,17 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
]
)
};
- var __vue_staticRenderFns__$6 = [];
- __vue_render__$6._withStripped = true;
+ var __vue_staticRenderFns__$8 = [];
+ __vue_render__$8._withStripped = true;
/* style */
- var __vue_inject_styles__$6 = undefined;
+ var __vue_inject_styles__$8 = undefined;
/* scoped */
- var __vue_scope_id__$6 = undefined;
+ var __vue_scope_id__$8 = undefined;
/* module identifier */
- var __vue_module_identifier__$6 = undefined;
+ var __vue_module_identifier__$8 = undefined;
/* functional template */
- var __vue_is_functional_template__$6 = false;
+ var __vue_is_functional_template__$8 = false;
/* style inject */
/* style inject SSR */
@@ -2143,12 +2540,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
var FormulateInputSelect = normalizeComponent(
- { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
- __vue_inject_styles__$6,
- __vue_script__$6,
- __vue_scope_id__$6,
- __vue_is_functional_template__$6,
- __vue_module_identifier__$6,
+ { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
+ __vue_inject_styles__$8,
+ __vue_script__$8,
+ __vue_scope_id__$8,
+ __vue_is_functional_template__$8,
+ __vue_module_identifier__$8,
false,
undefined,
undefined,
@@ -2157,16 +2554,16 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
//
- var script$7 = {
- name: 'FormulateInputText',
+ var script$9 = {
+ name: 'FormulateInputSlider',
mixins: [FormulateInputMixin]
};
/* script */
- var __vue_script__$7 = script$7;
+ var __vue_script__$9 = script$9;
/* template */
- var __vue_render__$7 = function() {
+ var __vue_render__$9 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2287,17 +2684,17 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
]
)
};
- var __vue_staticRenderFns__$7 = [];
- __vue_render__$7._withStripped = true;
+ var __vue_staticRenderFns__$9 = [];
+ __vue_render__$9._withStripped = true;
/* style */
- var __vue_inject_styles__$7 = undefined;
+ var __vue_inject_styles__$9 = undefined;
/* scoped */
- var __vue_scope_id__$7 = undefined;
+ var __vue_scope_id__$9 = undefined;
/* module identifier */
- var __vue_module_identifier__$7 = undefined;
+ var __vue_module_identifier__$9 = undefined;
/* functional template */
- var __vue_is_functional_template__$7 = false;
+ var __vue_is_functional_template__$9 = false;
/* style inject */
/* style inject SSR */
@@ -2307,12 +2704,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
var FormulateInputSlider = normalizeComponent(
- { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
- __vue_inject_styles__$7,
- __vue_script__$7,
- __vue_scope_id__$7,
- __vue_is_functional_template__$7,
- __vue_module_identifier__$7,
+ { render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
+ __vue_inject_styles__$9,
+ __vue_script__$9,
+ __vue_scope_id__$9,
+ __vue_is_functional_template__$9,
+ __vue_module_identifier__$9,
false,
undefined,
undefined,
@@ -2321,16 +2718,16 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
//
- var script$8 = {
+ var script$a = {
name: 'FormulateInputTextArea',
mixins: [FormulateInputMixin]
};
/* script */
- var __vue_script__$8 = script$8;
+ var __vue_script__$a = script$a;
/* template */
- var __vue_render__$8 = function() {
+ var __vue_render__$a = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2372,17 +2769,17 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
]
)
};
- var __vue_staticRenderFns__$8 = [];
- __vue_render__$8._withStripped = true;
+ var __vue_staticRenderFns__$a = [];
+ __vue_render__$a._withStripped = true;
/* style */
- var __vue_inject_styles__$8 = undefined;
+ var __vue_inject_styles__$a = undefined;
/* scoped */
- var __vue_scope_id__$8 = undefined;
+ var __vue_scope_id__$a = undefined;
/* module identifier */
- var __vue_module_identifier__$8 = undefined;
+ var __vue_module_identifier__$a = undefined;
/* functional template */
- var __vue_is_functional_template__$8 = false;
+ var __vue_is_functional_template__$a = false;
/* style inject */
/* style inject SSR */
@@ -2392,12 +2789,12 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
var FormulateInputTextArea = normalizeComponent(
- { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
- __vue_inject_styles__$8,
- __vue_script__$8,
- __vue_scope_id__$8,
- __vue_is_functional_template__$8,
- __vue_module_identifier__$8,
+ { render: __vue_render__$a, staticRenderFns: __vue_staticRenderFns__$a },
+ __vue_inject_styles__$a,
+ __vue_script__$a,
+ __vue_scope_id__$a,
+ __vue_is_functional_template__$a,
+ __vue_module_identifier__$a,
false,
undefined,
undefined,
@@ -2415,6 +2812,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
FormulateInputErrors: FormulateInputErrors,
FormulateInputBox: FormulateInputBox,
FormulateInputText: FormulateInputText,
+ FormulateInputFile: FormulateInputFile,
FormulateInputGroup: FormulateInputGroup,
FormulateInputSelect: FormulateInputSelect,
FormulateInputSlider: FormulateInputSlider,
@@ -2423,6 +2821,7 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
library: library,
rules: rules,
locale: 'en',
+ uploader: fauxUploader,
locales: {
en: en
}
@@ -2511,10 +2910,24 @@ var Formulate = (function (exports, isUrl, isPlainObject, nanoid) {
return 'This field does not have a valid value'
};
+ /**
+ * Get the file uploader.
+ */
+ Formulate.prototype.getUploader = function getUploader () {
+ return this.options.uploader || false
+ };
+
+ /**
+ * Create a new instance of an upload.
+ */
+ Formulate.prototype.createUpload = function createUpload (fileList, context) {
+ return new FileUpload(fileList, context, this.options)
+ };
+
var Formulate$1 = new Formulate();
exports.default = Formulate$1;
return exports;
-}({}, isUrl, isPlainObject, nanoid));
+}({}, isUrl, nanoid, isPlainObject));
diff --git a/dist/formulate.umd.js b/dist/formulate.umd.js
index bc698c8..2f1fb26 100644
--- a/dist/formulate.umd.js
+++ b/dist/formulate.umd.js
@@ -1,12 +1,12 @@
(function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('is-url'), require('is-plain-object'), require('nanoid')) :
- typeof define === 'function' && define.amd ? define(['exports', 'is-url', 'is-plain-object', 'nanoid'], factory) :
- (global = global || self, factory(global.Formulate = {}, global.isUrl, global.isPlainObject, global.nanoid));
-}(this, (function (exports, isUrl, isPlainObject, nanoid) { 'use strict';
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('is-url'), require('nanoid'), require('is-plain-object')) :
+ typeof define === 'function' && define.amd ? define(['exports', 'is-url', 'nanoid', 'is-plain-object'], factory) :
+ (global = global || self, factory(global.Formulate = {}, global.isUrl, global.nanoid, global.isPlainObject));
+}(this, (function (exports, isUrl, nanoid, isPlainObject) { 'use strict';
isUrl = isUrl && isUrl.hasOwnProperty('default') ? isUrl['default'] : isUrl;
- isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
nanoid = nanoid && nanoid.hasOwnProperty('default') ? nanoid['default'] : nanoid;
+ isPlainObject = isPlainObject && isPlainObject.hasOwnProperty('default') ? isPlainObject['default'] : isPlainObject;
var library = {
// === SINGLE LINE TEXT STYLE INPUTS
@@ -103,9 +103,129 @@
select: {
classification: 'select',
component: 'FormulateInputSelect'
+ },
+
+ // === FILE TYPE
+
+ file: {
+ classification: 'file',
+ component: 'FormulateInputFile'
+ },
+ image: {
+ classification: 'file',
+ component: 'FormulateInputFile'
}
};
+ /**
+ * The file upload class holds and represents a file’s upload state durring
+ * the upload flow.
+ */
+ var FileUpload = function FileUpload (fileList, context, options) {
+ this.fileList = fileList;
+ this.files = [];
+ this.options = options;
+ this.setFileList(fileList);
+ this.context = context;
+ };
+
+ /**
+ * Produce an array of files and alert the callback.
+ * @param {FileList}
+ */
+ FileUpload.prototype.setFileList = function setFileList (fileList) {
+ for (var i = 0; i < fileList.length; i++) {
+ var file = fileList.item(i);
+ this.files.push({
+ progress: 0,
+ name: file.name || 'file-upload',
+ file: file,
+ uuid: nanoid()
+ });
+ }
+ };
+
+ /**
+ * Check if the file has an.
+ */
+ FileUpload.prototype.hasUploader = function hasUploader () {
+ return !!this.context.uploader
+ };
+
+ FileUpload.prototype.uploaderIsAxios = function uploaderIsAxios () {
+ if (
+ this.hasUploader &&
+ typeof this.hasUploader.request === 'function' &&
+ typeof this.hasUploader.get === 'function' &&
+ typeof this.hasUploader.delete === 'function' &&
+ typeof this.hasUploader.post === 'function'
+ ) {
+ return true
+ }
+ return false
+ };
+
+ /**
+ * Get a new uploader function.
+ */
+ FileUpload.prototype.getUploader = function getUploader () {
+ var ref;
+
+ var args = [], len = arguments.length;
+ while ( len-- ) args[ len ] = arguments[ len ];
+ if (this.uploaderIsAxios()) {
+ var formData = new FormData();
+ formData.append(this.context.name || 'file', args[0]);
+ return this.uploader.post(this.context.uploadUrl, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ },
+ onUploadProgress: function (progressEvent) {
+ args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total));
+ }
+ })
+ .catch(function (err) { return args[2](err); })
+ }
+ return (ref = this.context).uploader.apply(ref, args)
+ };
+
+ /**
+ * Perform the file upload.
+ */
+ FileUpload.prototype.upload = function upload () {
+ var this$1 = this;
+
+ return new Promise(function (resolve, reject) {
+ if (!this$1.hasUploader) {
+ return reject(new Error('No uploader has been defined'))
+ }
+ Promise.all(this$1.files.map(function (file) {
+ return this$1.getUploader(
+ file.file,
+ function (progress) { file.progress = progress; },
+ function (error) { return reject(new Error(error)); },
+ this$1.options
+ )
+ }))
+ .then(function (results) { return resolve(results); })
+ .catch(function (err) { throw new Error(err) });
+ })
+ };
+
+ /**
+ * Get the files.
+ */
+ FileUpload.prototype.getFileList = function getFileList () {
+ return this.fileList
+ };
+
+ /**
+ * Get the files.
+ */
+ FileUpload.prototype.getFiles = function getFiles () {
+ return this.files
+ };
+
/**
* Function to map over an object.
* @param {Object} obj An object to map over
@@ -395,19 +515,20 @@
/**
* Check the maximum value of a particular.
*/
- max: function (value, minimum) {
+ max: function (value, minimum, force) {
if ( minimum === void 0 ) minimum = 10;
return Promise.resolve((function () {
- minimum = Number(minimum);
- if (!isNaN(value)) {
- value = Number(value);
- return value <= minimum
- }
- if (typeof value === 'string') {
+ if (Array.isArray(value)) {
+ minimum = !isNaN(minimum) ? Number(minimum) : minimum;
return value.length <= minimum
}
- if (Array.isArray(value)) {
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ value = !isNaN(value) ? Number(value) : value;
+ return value <= minimum
+ }
+ if (typeof value === 'string' || (force === 'length')) {
+ value = !isNaN(value) ? value.toString() : value;
return value.length <= minimum
}
return false
@@ -422,6 +543,12 @@
while ( len-- > 0 ) types[ len ] = arguments[ len + 1 ];
return Promise.resolve((function () {
+ if (files instanceof FileUpload) {
+ if (files.hasUploader()) {
+ return false
+ }
+ files = files.getFiles();
+ }
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
for (var i in files) {
if (!types.includes(files[i].type)) {
@@ -645,10 +772,14 @@
var value = ref.value;
var args = ref.args;
- if (!isNaN(value)) {
- return (name + " must be less than " + (args[0]) + ".")
+ if (Array.isArray(value)) {
+ return ("You may only select " + (args[0]) + " " + name + ".")
}
- return (name + " must be less than " + (args[0]) + " characters long.")
+ var force = Array.isArray(args) && args[1] ? args[1] : false;
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return ((sentence(name)) + " must be less than " + (args[0]) + ".")
+ }
+ return ((sentence(name)) + " must be less than " + (args[0]) + " characters long.")
},
/**
@@ -659,10 +790,14 @@
var value = ref.value;
var args = ref.args;
- if (!isNaN(value)) {
- return (name + " must be more than " + (args[0]) + ".")
+ if (Array.isArray(value)) {
+ return ("You must select at least " + (args[0]) + " " + name + ".")
}
- return (name + " must be more than " + (args[0]) + " characters long.")
+ var force = Array.isArray(args) && args[1] ? args[1] : false;
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return ((sentence(name)) + " must be more than " + (args[0]) + ".")
+ }
+ return ((sentence(name)) + " must be more than " + (args[0]) + " characters long.")
},
/**
@@ -703,6 +838,35 @@
}
};
+ /**
+ * A fake uploader used by default.
+ *
+ * @param {File} file
+ * @param {function} progress
+ * @param {function} error
+ * @param {object} options
+ */
+ function fauxUploader (file, progress, error, options) {
+ return new Promise(function (resolve, reject) {
+ var totalTime = options.fauxUploaderDuration || 2000;
+ var start = performance.now();
+ var advance = function () { return setTimeout(function () {
+ var elapsed = performance.now() - start;
+ var currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100));
+ progress(currentProgress);
+ if (currentProgress >= 100) {
+ resolve({
+ url: 'http://via.placeholder.com/350x150.png',
+ name: file.name
+ });
+ } else {
+ advance();
+ }
+ }, 20); };
+ advance();
+ })
+ }
+
/**
* For a single instance of an input, export all of the context needed to fully
* render that element.
@@ -719,7 +883,11 @@
label: this.label,
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes,
- blurHandler: blurHandler.bind(this)},
+ blurHandler: blurHandler.bind(this),
+ showImage: this.showImage,
+ uploadUrl: this.uploadUrl,
+ uploader: this.uploader || this.$formulate.getUploader(),
+ immediateUpload: this.immediateUpload},
this.typeContext))
},
nameOrFallback: nameOrFallback,
@@ -1007,6 +1175,22 @@
showErrors: {
type: Boolean,
default: false
+ },
+ showImage: {
+ type: Boolean,
+ default: true
+ },
+ uploadUrl: {
+ type: [String, Boolean],
+ default: false
+ },
+ uploader: {
+ type: [Function, Object, Boolean],
+ default: false
+ },
+ immediateUpload: {
+ type: Boolean,
+ default: true
}
},
data: function data () {
@@ -1995,6 +2179,219 @@
//
var script$6 = {
+ name: 'FormulateFiles',
+ props: {
+ files: {
+ type: FileUpload,
+ required: true
+ }
+ },
+ computed: {
+ fileUploads: function fileUploads () {
+ return this.files.files || []
+ }
+ }
+ };
+
+ /* script */
+ var __vue_script__$6 = script$6;
+
+ /* template */
+ var __vue_render__$6 = function() {
+ var _vm = this;
+ var _h = _vm.$createElement;
+ var _c = _vm._self._c || _h;
+ return _vm.fileUploads.length
+ ? _c(
+ "ul",
+ { staticClass: "formulate-files" },
+ _vm._l(_vm.fileUploads, function(file) {
+ return _c("li", { key: file.uuid, staticClass: "formulate-file" }, [
+ _c("span", {
+ staticClass: "formualte-file-name",
+ domProps: { textContent: _vm._s(file.name) }
+ }),
+ _vm._v(" "),
+ file.progress > 0 && file.progress < 100
+ ? _c("span", {
+ domProps: { textContent: _vm._s(file.progress + "%") }
+ })
+ : _vm._e()
+ ])
+ }),
+ 0
+ )
+ : _vm._e()
+ };
+ var __vue_staticRenderFns__$6 = [];
+ __vue_render__$6._withStripped = true;
+
+ /* style */
+ var __vue_inject_styles__$6 = undefined;
+ /* scoped */
+ var __vue_scope_id__$6 = undefined;
+ /* module identifier */
+ var __vue_module_identifier__$6 = undefined;
+ /* functional template */
+ var __vue_is_functional_template__$6 = false;
+ /* style inject */
+
+ /* style inject SSR */
+
+ /* style inject shadow dom */
+
+
+
+ var FormulateFiles = normalizeComponent(
+ { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
+ __vue_inject_styles__$6,
+ __vue_script__$6,
+ __vue_scope_id__$6,
+ __vue_is_functional_template__$6,
+ __vue_module_identifier__$6,
+ false,
+ undefined,
+ undefined,
+ undefined
+ );
+
+ //
+
+ var script$7 = {
+ name: 'FormulateInputFile',
+ components: {
+ FormulateFiles: FormulateFiles
+ },
+ mixins: [FormulateInputMixin],
+ data: function data () {
+ return {
+ isOver: false
+ }
+ },
+ computed: {
+ hasFiles: function hasFiles () {
+ return (this.context.model instanceof FileUpload && this.context.model.files.length)
+ }
+ },
+ methods: {
+ handleFile: function handleFile () {
+ var input = this.$refs.file;
+ if (input.files.length) {
+ this.context.model = this.$formulate.createUpload(input.files, this.context);
+ }
+ if (this.context.immediateUpload && this.context.model instanceof FileUpload) {
+ this.context.model.upload();
+ }
+ },
+ handleDragOver: function handleDragOver (e) {
+ e.preventDefault();
+ this.isOver = true;
+ },
+ handleDragLeave: function handleDragLeave (e) {
+ e.preventDefault();
+ this.isOver = false;
+ }
+ }
+ };
+
+ /* script */
+ var __vue_script__$7 = script$7;
+
+ /* template */
+ var __vue_render__$7 = function() {
+ var _vm = this;
+ var _h = _vm.$createElement;
+ var _c = _vm._self._c || _h;
+ return _c(
+ "div",
+ {
+ class:
+ "formulate-input-element formulate-input-element--" + _vm.context.type,
+ attrs: { "data-type": _vm.context.type, "data-has-files": _vm.hasFiles }
+ },
+ [
+ _c(
+ "div",
+ {
+ staticClass: "formulate-input-upload-area",
+ attrs: { "data-has-files": _vm.hasFiles }
+ },
+ [
+ _c(
+ "input",
+ _vm._b(
+ {
+ ref: "file",
+ attrs: { "data-is-drag-hover": _vm.isOver, type: "file" },
+ on: {
+ blur: _vm.context.blurHandler,
+ change: _vm.handleFile,
+ dragover: _vm.handleDragOver,
+ dragleave: _vm.handleDragLeave
+ }
+ },
+ "input",
+ _vm.attributes,
+ false
+ )
+ ),
+ _vm._v(" "),
+ _c("div", {
+ directives: [
+ {
+ name: "show",
+ rawName: "v-show",
+ value: !_vm.hasFiles,
+ expression: "!hasFiles"
+ }
+ ],
+ staticClass: "formulate-input-upload-area-mask"
+ }),
+ _vm._v(" "),
+ _vm.hasFiles
+ ? _c("FormulateFiles", { attrs: { files: _vm.context.model } })
+ : _vm._e()
+ ],
+ 1
+ )
+ ]
+ )
+ };
+ var __vue_staticRenderFns__$7 = [];
+ __vue_render__$7._withStripped = true;
+
+ /* style */
+ var __vue_inject_styles__$7 = undefined;
+ /* scoped */
+ var __vue_scope_id__$7 = undefined;
+ /* module identifier */
+ var __vue_module_identifier__$7 = undefined;
+ /* functional template */
+ var __vue_is_functional_template__$7 = false;
+ /* style inject */
+
+ /* style inject SSR */
+
+ /* style inject shadow dom */
+
+
+
+ var FormulateInputFile = normalizeComponent(
+ { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
+ __vue_inject_styles__$7,
+ __vue_script__$7,
+ __vue_scope_id__$7,
+ __vue_is_functional_template__$7,
+ __vue_module_identifier__$7,
+ false,
+ undefined,
+ undefined,
+ undefined
+ );
+
+ //
+
+ var script$8 = {
name: 'FormulateInputSelect',
mixins: [FormulateInputMixin],
computed: {
@@ -2011,10 +2408,10 @@
};
/* script */
- var __vue_script__$6 = script$6;
+ var __vue_script__$8 = script$8;
/* template */
- var __vue_render__$6 = function() {
+ var __vue_render__$8 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2126,17 +2523,17 @@
]
)
};
- var __vue_staticRenderFns__$6 = [];
- __vue_render__$6._withStripped = true;
+ var __vue_staticRenderFns__$8 = [];
+ __vue_render__$8._withStripped = true;
/* style */
- var __vue_inject_styles__$6 = undefined;
+ var __vue_inject_styles__$8 = undefined;
/* scoped */
- var __vue_scope_id__$6 = undefined;
+ var __vue_scope_id__$8 = undefined;
/* module identifier */
- var __vue_module_identifier__$6 = undefined;
+ var __vue_module_identifier__$8 = undefined;
/* functional template */
- var __vue_is_functional_template__$6 = false;
+ var __vue_is_functional_template__$8 = false;
/* style inject */
/* style inject SSR */
@@ -2146,12 +2543,12 @@
var FormulateInputSelect = normalizeComponent(
- { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
- __vue_inject_styles__$6,
- __vue_script__$6,
- __vue_scope_id__$6,
- __vue_is_functional_template__$6,
- __vue_module_identifier__$6,
+ { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
+ __vue_inject_styles__$8,
+ __vue_script__$8,
+ __vue_scope_id__$8,
+ __vue_is_functional_template__$8,
+ __vue_module_identifier__$8,
false,
undefined,
undefined,
@@ -2160,16 +2557,16 @@
//
- var script$7 = {
- name: 'FormulateInputText',
+ var script$9 = {
+ name: 'FormulateInputSlider',
mixins: [FormulateInputMixin]
};
/* script */
- var __vue_script__$7 = script$7;
+ var __vue_script__$9 = script$9;
/* template */
- var __vue_render__$7 = function() {
+ var __vue_render__$9 = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2290,17 +2687,17 @@
]
)
};
- var __vue_staticRenderFns__$7 = [];
- __vue_render__$7._withStripped = true;
+ var __vue_staticRenderFns__$9 = [];
+ __vue_render__$9._withStripped = true;
/* style */
- var __vue_inject_styles__$7 = undefined;
+ var __vue_inject_styles__$9 = undefined;
/* scoped */
- var __vue_scope_id__$7 = undefined;
+ var __vue_scope_id__$9 = undefined;
/* module identifier */
- var __vue_module_identifier__$7 = undefined;
+ var __vue_module_identifier__$9 = undefined;
/* functional template */
- var __vue_is_functional_template__$7 = false;
+ var __vue_is_functional_template__$9 = false;
/* style inject */
/* style inject SSR */
@@ -2310,12 +2707,12 @@
var FormulateInputSlider = normalizeComponent(
- { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
- __vue_inject_styles__$7,
- __vue_script__$7,
- __vue_scope_id__$7,
- __vue_is_functional_template__$7,
- __vue_module_identifier__$7,
+ { render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
+ __vue_inject_styles__$9,
+ __vue_script__$9,
+ __vue_scope_id__$9,
+ __vue_is_functional_template__$9,
+ __vue_module_identifier__$9,
false,
undefined,
undefined,
@@ -2324,16 +2721,16 @@
//
- var script$8 = {
+ var script$a = {
name: 'FormulateInputTextArea',
mixins: [FormulateInputMixin]
};
/* script */
- var __vue_script__$8 = script$8;
+ var __vue_script__$a = script$a;
/* template */
- var __vue_render__$8 = function() {
+ var __vue_render__$a = function() {
var _vm = this;
var _h = _vm.$createElement;
var _c = _vm._self._c || _h;
@@ -2375,17 +2772,17 @@
]
)
};
- var __vue_staticRenderFns__$8 = [];
- __vue_render__$8._withStripped = true;
+ var __vue_staticRenderFns__$a = [];
+ __vue_render__$a._withStripped = true;
/* style */
- var __vue_inject_styles__$8 = undefined;
+ var __vue_inject_styles__$a = undefined;
/* scoped */
- var __vue_scope_id__$8 = undefined;
+ var __vue_scope_id__$a = undefined;
/* module identifier */
- var __vue_module_identifier__$8 = undefined;
+ var __vue_module_identifier__$a = undefined;
/* functional template */
- var __vue_is_functional_template__$8 = false;
+ var __vue_is_functional_template__$a = false;
/* style inject */
/* style inject SSR */
@@ -2395,12 +2792,12 @@
var FormulateInputTextArea = normalizeComponent(
- { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
- __vue_inject_styles__$8,
- __vue_script__$8,
- __vue_scope_id__$8,
- __vue_is_functional_template__$8,
- __vue_module_identifier__$8,
+ { render: __vue_render__$a, staticRenderFns: __vue_staticRenderFns__$a },
+ __vue_inject_styles__$a,
+ __vue_script__$a,
+ __vue_scope_id__$a,
+ __vue_is_functional_template__$a,
+ __vue_module_identifier__$a,
false,
undefined,
undefined,
@@ -2418,6 +2815,7 @@
FormulateInputErrors: FormulateInputErrors,
FormulateInputBox: FormulateInputBox,
FormulateInputText: FormulateInputText,
+ FormulateInputFile: FormulateInputFile,
FormulateInputGroup: FormulateInputGroup,
FormulateInputSelect: FormulateInputSelect,
FormulateInputSlider: FormulateInputSlider,
@@ -2426,6 +2824,7 @@
library: library,
rules: rules,
locale: 'en',
+ uploader: fauxUploader,
locales: {
en: en
}
@@ -2514,6 +2913,20 @@
return 'This field does not have a valid value'
};
+ /**
+ * Get the file uploader.
+ */
+ Formulate.prototype.getUploader = function getUploader () {
+ return this.options.uploader || false
+ };
+
+ /**
+ * Create a new instance of an upload.
+ */
+ Formulate.prototype.createUpload = function createUpload (fileList, context) {
+ return new FileUpload(fileList, context, this.options)
+ };
+
var Formulate$1 = new Formulate();
exports.default = Formulate$1;
diff --git a/dist/snow.css b/dist/snow.css
index 5d1f918..4f9360b 100644
--- a/dist/snow.css
+++ b/dist/snow.css
@@ -40,12 +40,37 @@
padding: .75em;
display: block;
width: 100%;
- font-weight: 400; }
+ font-weight: 400;
+ line-height: 1.1em;
+ margin: 0; }
.formulate-input[data-classification='text'] input::placeholder {
color: #a8a8a8; }
.formulate-input[data-classification='text'] input:focus {
outline: 0;
border: 1px solid #41b883; }
+ .formulate-input[data-classification='text'] input[type="color"] {
+ height: 1.1em;
+ box-sizing: content-box; }
+ .formulate-input[data-classification='text'] input[type="color"]::-webkit-color-swatch-wrapper {
+ padding: 0 0 0 1.5em;
+ display: flex;
+ align-items: center;
+ background-image: url('data:image/svg+xml;utf8,');
+ background-repeat: no-repeat;
+ background-size: .9em .9em;
+ background-position: left .1em; }
+ .formulate-input[data-classification='text'] input[type="color"]::-webkit-color-swatch {
+ display: block;
+ height: 1em;
+ border-radius: .2em;
+ border: 0;
+ flex: auto; }
+ .formulate-input[data-classification='text'] input[type="color"]::-moz-color-swatch {
+ display: block;
+ height: 1em;
+ border-radius: .2em;
+ border: 0;
+ flex: auto; }
.formulate-input[data-classification='slider'] input {
appearance: none;
width: 100%;
@@ -96,7 +121,9 @@
padding: .75em;
display: block;
width: 100%;
- font-weight: 400; }
+ font-weight: 400;
+ line-height: 1.1em;
+ margin: 0; }
.formulate-input[data-classification='textarea'] textarea::placeholder {
color: #a8a8a8; }
.formulate-input[data-classification='textarea'] textarea:focus {
@@ -127,6 +154,8 @@
display: block;
width: 100%;
font-weight: 400;
+ line-height: 1.1em;
+ margin: 0;
padding-right: 2em; }
.formulate-input[data-classification='select'] select::placeholder {
color: #a8a8a8; }
@@ -174,7 +203,8 @@
.formulate-input[data-classification='box'] .formulate-input-element input[type="checkbox"]:checked ~ .formulate-input-element-decorator {
border-color: #41b883; }
.formulate-input[data-classification='box'] .formulate-input-element input[type="checkbox"]:checked ~ .formulate-input-element-decorator::before {
- background-image: url('data:image/svg+xml;utf8,'); }
+ background-color: #41b883;
+ mask-image: url('data:image/svg+xml;utf8,'); }
.formulate-input[data-classification='box'] .formulate-input-element input[type="radio"]:checked ~ .formulate-input-element-decorator {
border-color: #41b883; }
.formulate-input[data-classification='box'] .formulate-input-element input[type="radio"]:checked ~ .formulate-input-element-decorator::before {
@@ -187,3 +217,83 @@
margin-right: .5em; }
.formulate-input[data-classification="group"] > .formulate-input-wrapper > .formulate-input-label {
margin-bottom: .5em; }
+ .formulate-input[data-classification="file"] .formulate-input-upload-area {
+ width: 100%;
+ position: relative;
+ padding: 2em; }
+ .formulate-input[data-classification="file"] .formulate-input-upload-area[data-has-files] {
+ padding: 0; }
+ .formulate-input[data-classification="file"] .formulate-input-upload-area input {
+ cursor: pointer;
+ appearance: none;
+ opacity: 0;
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 5; }
+ .formulate-input[data-classification="file"] .formulate-input-upload-area-mask {
+ border-radius: .4em;
+ position: absolute;
+ pointer-events: none;
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ border: 2px dashed #a8a8a8;
+ z-index: 2; }
+ .formulate-input[data-classification="file"] .formulate-input-upload-area-mask::before {
+ content: '';
+ background-color: #a8a8a8;
+ mask-image: url('data:image/svg+xml;utf8,');
+ width: 2em;
+ height: 2em;
+ position: absolute;
+ pointer-events: none; }
+ .formulate-input[data-classification="file"] .formulate-input-upload-area input:focus ~ .formulate-input-upload-area-mask,
+ .formulate-input[data-classification="file"] .formulate-input-upload-area input:hover ~ .formulate-input-upload-area-mask,
+ .formulate-input[data-classification="file"] .formulate-input-upload-area input[data-is-drag-hover] ~ .formulate-input-upload-area-mask {
+ border-color: #41b883; }
+ .formulate-input[data-classification="file"] .formulate-input-upload-area input:focus ~ .formulate-input-upload-area-mask::before,
+ .formulate-input[data-classification="file"] .formulate-input-upload-area input:hover ~ .formulate-input-upload-area-mask::before,
+ .formulate-input[data-classification="file"] .formulate-input-upload-area input[data-is-drag-hover] ~ .formulate-input-upload-area-mask::before {
+ background-color: #41b883; }
+ .formulate-input[data-classification="file"] .formulate-files {
+ list-style-type: none;
+ margin: 0;
+ padding: 0; }
+ .formulate-input[data-classification="file"] .formulate-files li {
+ appearance: none;
+ border-radius: .3em;
+ border: 1px solid #cecece;
+ box-sizing: border-box;
+ background-color: transparent;
+ font-size: .9em;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ padding: .75em;
+ display: block;
+ width: 100%;
+ font-weight: 400;
+ line-height: 1.1em;
+ margin: 0;
+ display: block;
+ width: 100%;
+ display: flex;
+ justify-content: space-between; }
+ .formulate-input[data-classification="file"] .formulate-files li::placeholder {
+ color: #a8a8a8; }
+ .formulate-input[data-classification="file"] .formulate-files li:focus {
+ outline: 0;
+ border: 1px solid #41b883; }
+ .formulate-input[data-classification="file"] .formulate-files li ::-webkit-progress-bar {
+ appearance: none;
+ height: .5em;
+ border-radius: .5em;
+ overflow: hidden; }
diff --git a/dist/snow.min.css b/dist/snow.min.css
index b8e8664..8532588 100644
--- a/dist/snow.min.css
+++ b/dist/snow.min.css
@@ -1,2 +1,2 @@
-.formulate-input{margin-bottom:2em}.formulate-input .formulate-input-label{display:block;line-height:1.5;font-size:.9em;font-weight:600;margin-bottom:.1em}.formulate-input .formulate-input-element{max-width:20em;margin-bottom:.1em}.formulate-input .formulate-input-help{color:#6d6d6d;font-size:.7em;font-weight:400;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-errors{list-style-type:none;padding:0;margin:0}.formulate-input .formulate-input-error{color:#960505;font-size:.8em;font-weight:300;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-group-item{margin-bottom:.5em}.formulate-input:last-child{margin-bottom:0}.formulate-input[data-classification=text] input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400}.formulate-input[data-classification=text] input::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=slider] input{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;font-size:1em;padding:.5em 0}.formulate-input[data-classification=slider] input:focus{outline:0}.formulate-input[data-classification=slider] input::-webkit-slider-thumb{cursor:pointer;-webkit-appearance:none;appearance:none;width:1em;height:1em;border-radius:1em;background-color:#41b883;margin-top:calc(-.5em + 2px)}.formulate-input[data-classification=slider] input::-moz-range-thumb{cursor:pointer;-moz-appearance:none;appearance:none;width:1em;height:1em;border-radius:1em;background-color:#41b883;margin-top:calc(-.5em + 2px)}.formulate-input[data-classification=slider] input::-ms-thumb{cursor:pointer;appearance:none;width:1em;height:1em;border-radius:1em;background-color:#41b883;margin-top:calc(-.5em + 2px)}.formulate-input[data-classification=slider] input::-webkit-slider-runnable-track{-webkit-appearance:none;appearance:none;width:100%;height:4px;background-color:#efefef;border-radius:3px;margin:0;padding:0}.formulate-input[data-classification=textarea] textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400}.formulate-input[data-classification=textarea] textarea::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] .formulate-input-element{position:relative}.formulate-input[data-classification=select] .formulate-input-element:before{content:"";width:0;height:0;border-color:#cecece transparent transparent;border-style:solid;border-width:.3em .3em 0;top:50%;margin-top:-.1em;right:1em;position:absolute}.formulate-input[data-classification=select] select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;display:block;width:100%;font-weight:400;padding:.75em 2em .75em .75em}.formulate-input[data-classification=select] select::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] select[data-placeholder-selected]{color:#a8a8a8}.formulate-input[data-classification=box] .formulate-input-element,.formulate-input[data-classification=box] .formulate-input-wrapper{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.formulate-input[data-classification=box] .formulate-input-element{overflow:hidden}.formulate-input[data-classification=box] .formulate-input-element input{position:absolute;left:-999px}.formulate-input[data-classification=box] .formulate-input-element-decorator{display:block;width:1em;height:1em;border-radius:.25em;border:1px solid #cecece;position:relative}.formulate-input[data-classification=box] .formulate-input-element-decorator:before{content:"";display:block;background-size:contain;background-position:100%;width:calc(100% - .125em);height:calc(100% - .125em);box-sizing:border-box;position:absolute;top:.0625em;left:.0625em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator{border-radius:1em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator:before{border-radius:1em;width:calc(100% - .5em);height:calc(100% - .5em);top:.25em;left:.25em}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator:before{background-image:url('data:image/svg+xml;utf8,')}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator:before{background-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input:focus~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-label--after{margin-left:.5em}.formulate-input[data-classification=box] .formulate-input-label--before{margin-right:.5em}.formulate-input[data-classification=group]>.formulate-input-wrapper>.formulate-input-label{margin-bottom:.5em}
-/*# sourceMappingURL=data:application/json;base64,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QUNsQiwwREFDRSxTQUFVLENBQ1Ysd0JBQTJCLENBQzdCLCtFQUNFLGFBQWdCLENBSXBCLHNJQUZFLG1CQUFhLENBQWIsWUFBYSxDQUNiLHdCQUFtQixDQUFuQixrQkFJcUIsQ0FIdkIsbUVBQ0UsZUFFcUIsQ0FDckIseUVBQ0UsaUJBQWtCLENBQ2xCLFdBQWMsQ0FDaEIsNkVBQ0UsYUFBYyxDQUNkLFNBQVUsQ0FDVixVQUFXLENBQ1gsbUJBQW9CLENBQ3BCLHdCQUF5QixDQUN6QixpQkFBb0IsQ0FDcEIsb0ZBQ0UsVUFBVyxDQUNYLGFBQWMsQ0FDZCx1QkFBd0IsQ0FDeEIsd0JBQTBCLENBQzFCLHlCQUEwQixDQUMxQiwwQkFBMkIsQ0FDM0IscUJBQXNCLENBQ3RCLGlCQUFrQixDQUNsQixXQUFZLENBQ1osWUFBZSxDQUNuQix1SEFDRSxpQkFBb0IsQ0FDcEIsOEhBQ0UsaUJBQWtCLENBQ2xCLHVCQUF3QixDQUN4Qix3QkFBeUIsQ0FDekIsU0FBVSxDQUNWLFVBQWEsQ0FDakIsbUlBQ0Usb0JBQXVCLENBQ3ZCLDBJQUNFLGdSQUFtUixDQUN2UixnSUFDRSxvQkFBdUIsQ0FDdkIsdUlBQ0Usd0JBQTJCLENBQy9CLGtIQUNFLG9CQUF1QixDQUMzQix3RUFDRSxnQkFBbUIsQ0FDckIseUVBQ0UsaUJBQW9CLENBQ3RCLDRGQUNFLGtCQUFxQiIsImZpbGUiOiJzdGRpbiIsInNvdXJjZXNDb250ZW50IjpbIi5mb3JtdWxhdGUtaW5wdXQge1xuICBtYXJnaW4tYm90dG9tOiAyZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWxhYmVsIHtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBsaW5lLWhlaWdodDogMS41O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LXdlaWdodDogNjAwO1xuICAgIG1hcmdpbi1ib3R0b206IC4xZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQge1xuICAgIG1heC13aWR0aDogMjBlbTtcbiAgICBtYXJnaW4tYm90dG9tOiAuMWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXQgLmZvcm11bGF0ZS1pbnB1dC1oZWxwIHtcbiAgICBjb2xvcjogIzZkNmQ2ZDtcbiAgICBmb250LXNpemU6IC43ZW07XG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcbiAgICBsaW5lLWhlaWdodDogMS41O1xuICAgIG1hcmdpbi1ib3R0b206IC4yNWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXQgLmZvcm11bGF0ZS1pbnB1dC1lcnJvcnMge1xuICAgIGxpc3Qtc3R5bGUtdHlwZTogbm9uZTtcbiAgICBwYWRkaW5nOiAwO1xuICAgIG1hcmdpbjogMDsgfVxuICAuZm9ybXVsYXRlLWlucHV0IC5mb3JtdWxhdGUtaW5wdXQtZXJyb3Ige1xuICAgIGNvbG9yOiAjOTYwNTA1O1xuICAgIGZvbnQtc2l6ZTogLjhlbTtcbiAgICBmb250LXdlaWdodDogMzAwO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjU7XG4gICAgbWFyZ2luLWJvdHRvbTogLjI1ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWdyb3VwLWl0ZW0ge1xuICAgIG1hcmdpbi1ib3R0b206IC41ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dDpsYXN0LWNoaWxkIHtcbiAgICBtYXJnaW4tYm90dG9tOiAwOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0IHtcbiAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IC4zZW07XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCBcIlNlZ29lIFVJXCIsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiwgXCJBcHBsZSBDb2xvciBFbW9qaVwiLCBcIlNlZ29lIFVJIEVtb2ppXCIsIFwiU2Vnb2UgVUkgU3ltYm9sXCI7XG4gICAgcGFkZGluZzogLjc1ZW07XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC13ZWlnaHQ6IDQwMDsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0OjpwbGFjZWhvbGRlciB7XG4gICAgICBjb2xvcjogI2E4YThhODsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0OmZvY3VzIHtcbiAgICAgIG91dGxpbmU6IDA7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2xpZGVyJ10gaW5wdXQge1xuICAgIGFwcGVhcmFuY2U6IG5vbmU7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC1zaXplOiAxZW07XG4gICAgcGFkZGluZzogLjVlbSAwOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzbGlkZXInXSBpbnB1dDpmb2N1cyB7XG4gICAgICBvdXRsaW5lOiAwOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzbGlkZXInXSBpbnB1dDo6LXdlYmtpdC1zbGlkZXItdGh1bWIge1xuICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICAgIHdpZHRoOiAxZW07XG4gICAgICBoZWlnaHQ6IDFlbTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDFlbTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICM0MWI4ODM7XG4gICAgICBtYXJnaW4tdG9wOiBjYWxjKC0uNWVtICsgMnB4KTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2xpZGVyJ10gaW5wdXQ6Oi1tb3otcmFuZ2UtdGh1bWIge1xuICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICAgIHdpZHRoOiAxZW07XG4gICAgICBoZWlnaHQ6IDFlbTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDFlbTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICM0MWI4ODM7XG4gICAgICBtYXJnaW4tdG9wOiBjYWxjKC0uNWVtICsgMnB4KTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2xpZGVyJ10gaW5wdXQ6Oi1tcy10aHVtYiB7XG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgICAgd2lkdGg6IDFlbTtcbiAgICAgIGhlaWdodDogMWVtO1xuICAgICAgYm9yZGVyLXJhZGl1czogMWVtO1xuICAgICAgYmFja2dyb3VuZC1jb2xvcjogIzQxYjg4MztcbiAgICAgIG1hcmdpbi10b3A6IGNhbGMoLS41ZW0gKyAycHgpOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzbGlkZXInXSBpbnB1dDo6LXdlYmtpdC1zbGlkZXItcnVubmFibGUtdHJhY2sge1xuICAgICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICAgIHdpZHRoOiAxMDAlO1xuICAgICAgaGVpZ2h0OiA0cHg7XG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZWZlZmVmO1xuICAgICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgICAgbWFyZ2luOiAwO1xuICAgICAgcGFkZGluZzogMDsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHRhcmVhJ10gdGV4dGFyZWEge1xuICAgIGFwcGVhcmFuY2U6IG5vbmU7XG4gICAgYm9yZGVyLXJhZGl1czogLjNlbTtcbiAgICBib3JkZXI6IDFweCBzb2xpZCAjY2VjZWNlO1xuICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgZm9udC1zaXplOiAuOWVtO1xuICAgIGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsIFwiU2Vnb2UgVUlcIiwgUm9ib3RvLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmLCBcIkFwcGxlIENvbG9yIEVtb2ppXCIsIFwiU2Vnb2UgVUkgRW1vamlcIiwgXCJTZWdvZSBVSSBTeW1ib2xcIjtcbiAgICBwYWRkaW5nOiAuNzVlbTtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICB3aWR0aDogMTAwJTtcbiAgICBmb250LXdlaWdodDogNDAwOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSd0ZXh0YXJlYSddIHRleHRhcmVhOjpwbGFjZWhvbGRlciB7XG4gICAgICBjb2xvcjogI2E4YThhODsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dGFyZWEnXSB0ZXh0YXJlYTpmb2N1cyB7XG4gICAgICBvdXRsaW5lOiAwO1xuICAgICAgYm9yZGVyOiAxcHggc29saWQgIzQxYjg4MzsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzZWxlY3QnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQ6OmJlZm9yZSB7XG4gICAgICBjb250ZW50OiAnJztcbiAgICAgIHdpZHRoOiAwO1xuICAgICAgaGVpZ2h0OiAwO1xuICAgICAgYm9yZGVyOiAuM2VtIHNvbGlkIHRyYW5zcGFyZW50O1xuICAgICAgYm9yZGVyLXRvcC1jb2xvcjogI2NlY2VjZTtcbiAgICAgIGJvcmRlci1ib3R0b20td2lkdGg6IDA7XG4gICAgICB0b3A6IDUwJTtcbiAgICAgIG1hcmdpbi10b3A6IC0uMWVtO1xuICAgICAgcmlnaHQ6IDFlbTtcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIHNlbGVjdCB7XG4gICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICBib3JkZXItcmFkaXVzOiAuM2VtO1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNjZWNlY2U7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICBmb250LXNpemU6IC45ZW07XG4gICAgZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgXCJTZWdvZSBVSVwiLCBSb2JvdG8sIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYsIFwiQXBwbGUgQ29sb3IgRW1vamlcIiwgXCJTZWdvZSBVSSBFbW9qaVwiLCBcIlNlZ29lIFVJIFN5bWJvbFwiO1xuICAgIHBhZGRpbmc6IC43NWVtO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIGZvbnQtd2VpZ2h0OiA0MDA7XG4gICAgcGFkZGluZy1yaWdodDogMmVtOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzZWxlY3QnXSBzZWxlY3Q6OnBsYWNlaG9sZGVyIHtcbiAgICAgIGNvbG9yOiAjYThhOGE4OyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzZWxlY3QnXSBzZWxlY3Q6Zm9jdXMge1xuICAgICAgb3V0bGluZTogMDtcbiAgICAgIGJvcmRlcjogMXB4IHNvbGlkICM0MWI4ODM7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIHNlbGVjdFtkYXRhLXBsYWNlaG9sZGVyLXNlbGVjdGVkXSB7XG4gICAgICBjb2xvcjogI2E4YThhODsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtd3JhcHBlciB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IHtcbiAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0IHtcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgIGxlZnQ6IC05OTlweDsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvciB7XG4gICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgIHdpZHRoOiAxZW07XG4gICAgICBoZWlnaHQ6IDFlbTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IC4yNWVtO1xuICAgICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsgfVxuICAgICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yOjpiZWZvcmUge1xuICAgICAgICBjb250ZW50OiAnJztcbiAgICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICAgIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjtcbiAgICAgICAgYmFja2dyb3VuZC1wb3NpdGlvbjogcmlnaHQ7XG4gICAgICAgIHdpZHRoOiBjYWxjKDEwMCUgLSAuMTI1ZW0pO1xuICAgICAgICBoZWlnaHQ6IGNhbGMoMTAwJSAtIC4xMjVlbSk7XG4gICAgICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgdG9wOiAuMDYyNWVtO1xuICAgICAgICBsZWZ0OiAuMDYyNWVtOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnRbZGF0YS10eXBlPVwicmFkaW9cIl0gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvciB7XG4gICAgICBib3JkZXItcmFkaXVzOiAxZW07IH1cbiAgICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50W2RhdGEtdHlwZT1cInJhZGlvXCJdIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3I6OmJlZm9yZSB7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDFlbTtcbiAgICAgICAgd2lkdGg6IGNhbGMoMTAwJSAtIC41ZW0pO1xuICAgICAgICBoZWlnaHQ6IGNhbGMoMTAwJSAtIC41ZW0pO1xuICAgICAgICB0b3A6IC4yNWVtO1xuICAgICAgICBsZWZ0OiAuMjVlbTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0W3R5cGU9XCJjaGVja2JveFwiXTpjaGVja2VkIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvciB7XG4gICAgICBib3JkZXItY29sb3I6ICM0MWI4ODM7IH1cbiAgICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IGlucHV0W3R5cGU9XCJjaGVja2JveFwiXTpjaGVja2VkIH4gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvcjo6YmVmb3JlIHtcbiAgICAgICAgYmFja2dyb3VuZC1pbWFnZTogdXJsKCdkYXRhOmltYWdlL3N2Zyt4bWw7dXRmOCw8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB2aWV3Qm94PVwiMCAwIDEwMCAxMDBcIiBmaWxsPVwiJTIzNDFiODgzXCI+PHBhdGggZD1cIk04Ljc2LDU2LjJjLTYuMzgtNi4zNCwzLjI2LTE2LDkuNjQtOS42OUwzOCw2NS44OCw4MC41NiwyMy4yOWM2LjM4LTYuMzgsMTYuMDcsMy4zMiw5LjY5LDkuNjlMNDIuODQsODAuMzdhNi44Myw2LjgzLDAsMCwxLTkuNjUsMFpcIi8+PC9zdmc+Jyk7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dFt0eXBlPVwicmFkaW9cIl06Y2hlY2tlZCB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3Ige1xuICAgICAgYm9yZGVyLWNvbG9yOiAjNDFiODgzOyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dFt0eXBlPVwicmFkaW9cIl06Y2hlY2tlZCB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3I6OmJlZm9yZSB7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICM0MWI4ODM7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dDpmb2N1cyB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3Ige1xuICAgICAgYm9yZGVyLWNvbG9yOiAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1sYWJlbC0tYWZ0ZXIge1xuICAgIG1hcmdpbi1sZWZ0OiAuNWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1sYWJlbC0tYmVmb3JlIHtcbiAgICBtYXJnaW4tcmlnaHQ6IC41ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPVwiZ3JvdXBcIl0gPiAuZm9ybXVsYXRlLWlucHV0LXdyYXBwZXIgPiAuZm9ybXVsYXRlLWlucHV0LWxhYmVsIHtcbiAgICBtYXJnaW4tYm90dG9tOiAuNWVtOyB9XG4iXX0= */
\ No newline at end of file
+.formulate-input{margin-bottom:2em}.formulate-input .formulate-input-label{display:block;line-height:1.5;font-size:.9em;font-weight:600;margin-bottom:.1em}.formulate-input .formulate-input-element{max-width:20em;margin-bottom:.1em}.formulate-input .formulate-input-help{color:#6d6d6d;font-size:.7em;font-weight:400;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-errors{list-style-type:none;padding:0;margin:0}.formulate-input .formulate-input-error{color:#960505;font-size:.8em;font-weight:300;line-height:1.5;margin-bottom:.25em}.formulate-input .formulate-input-group-item{margin-bottom:.5em}.formulate-input:last-child{margin-bottom:0}.formulate-input[data-classification=text] input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400;line-height:1.1em;margin:0}.formulate-input[data-classification=text] input::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input::placeholder{color:#a8a8a8}.formulate-input[data-classification=text] input:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=text] input[type=color]{height:1.1em;box-sizing:content-box}.formulate-input[data-classification=text] input[type=color]::-webkit-color-swatch-wrapper{padding:0 0 0 1.5em;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;background-image:url('data:image/svg+xml;utf8,');background-repeat:no-repeat;background-size:.9em .9em;background-position:left .1em}.formulate-input[data-classification=text] input[type=color]::-webkit-color-swatch{display:block;height:1em;border-radius:.2em;border:0;-webkit-box-flex:1;flex:auto}.formulate-input[data-classification=text] input[type=color]::-moz-color-swatch{display:block;height:1em;border-radius:.2em;border:0;flex:auto}.formulate-input[data-classification=slider] input{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;font-size:1em;padding:.5em 0}.formulate-input[data-classification=slider] input:focus{outline:0}.formulate-input[data-classification=slider] input::-webkit-slider-thumb{cursor:pointer;-webkit-appearance:none;appearance:none;width:1em;height:1em;border-radius:1em;background-color:#41b883;margin-top:calc(-.5em + 2px)}.formulate-input[data-classification=slider] input::-moz-range-thumb{cursor:pointer;-moz-appearance:none;appearance:none;width:1em;height:1em;border-radius:1em;background-color:#41b883;margin-top:calc(-.5em + 2px)}.formulate-input[data-classification=slider] input::-ms-thumb{cursor:pointer;appearance:none;width:1em;height:1em;border-radius:1em;background-color:#41b883;margin-top:calc(-.5em + 2px)}.formulate-input[data-classification=slider] input::-webkit-slider-runnable-track{-webkit-appearance:none;appearance:none;width:100%;height:4px;background-color:#efefef;border-radius:3px;margin:0;padding:0}.formulate-input[data-classification=textarea] textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;display:block;width:100%;font-weight:400;line-height:1.1em;margin:0}.formulate-input[data-classification=textarea] textarea::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea::placeholder{color:#a8a8a8}.formulate-input[data-classification=textarea] textarea:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] .formulate-input-element{position:relative}.formulate-input[data-classification=select] .formulate-input-element:before{content:"";width:0;height:0;border-color:#cecece transparent transparent;border-style:solid;border-width:.3em .3em 0;top:50%;margin-top:-.1em;right:1em;position:absolute}.formulate-input[data-classification=select] select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;display:block;width:100%;font-weight:400;line-height:1.1em;margin:0;padding:.75em 2em .75em .75em}.formulate-input[data-classification=select] select::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select::placeholder{color:#a8a8a8}.formulate-input[data-classification=select] select:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=select] select[data-placeholder-selected]{color:#a8a8a8}.formulate-input[data-classification=box] .formulate-input-element,.formulate-input[data-classification=box] .formulate-input-wrapper{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.formulate-input[data-classification=box] .formulate-input-element{overflow:hidden}.formulate-input[data-classification=box] .formulate-input-element input{position:absolute;left:-999px}.formulate-input[data-classification=box] .formulate-input-element-decorator{display:block;width:1em;height:1em;border-radius:.25em;border:1px solid #cecece;position:relative}.formulate-input[data-classification=box] .formulate-input-element-decorator:before{content:"";display:block;background-size:contain;background-position:100%;width:calc(100% - .125em);height:calc(100% - .125em);box-sizing:border-box;position:absolute;top:.0625em;left:.0625em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator{border-radius:1em}.formulate-input[data-classification=box] .formulate-input-element[data-type=radio] .formulate-input-element-decorator:before{border-radius:1em;width:calc(100% - .5em);height:calc(100% - .5em);top:.25em;left:.25em}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=checkbox]:checked~.formulate-input-element-decorator:before{background-color:#41b883;-webkit-mask-image:url('data:image/svg+xml;utf8,');mask-image:url('data:image/svg+xml;utf8,')}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input[type=radio]:checked~.formulate-input-element-decorator:before{background-color:#41b883}.formulate-input[data-classification=box] .formulate-input-element input:focus~.formulate-input-element-decorator{border-color:#41b883}.formulate-input[data-classification=box] .formulate-input-label--after{margin-left:.5em}.formulate-input[data-classification=box] .formulate-input-label--before{margin-right:.5em}.formulate-input[data-classification=group]>.formulate-input-wrapper>.formulate-input-label{margin-bottom:.5em}.formulate-input[data-classification=file] .formulate-input-upload-area{width:100%;position:relative;padding:2em}.formulate-input[data-classification=file] .formulate-input-upload-area[data-has-files]{padding:0}.formulate-input[data-classification=file] .formulate-input-upload-area input{cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;opacity:0;position:absolute;left:0;right:0;bottom:0;top:0;width:100%;height:100%;z-index:5}.formulate-input[data-classification=file] .formulate-input-upload-area-mask{border-radius:.4em;pointer-events:none;position:absolute;display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;-webkit-box-align:center;align-items:center;left:0;right:0;top:0;bottom:0;border:2px dashed #a8a8a8;z-index:2}.formulate-input[data-classification=file] .formulate-input-upload-area-mask:before{content:"";background-color:#a8a8a8;-webkit-mask-image:url('data:image/svg+xml;utf8,');mask-image:url('data:image/svg+xml;utf8,');width:2em;height:2em;position:absolute;pointer-events:none}.formulate-input[data-classification=file] .formulate-input-upload-area input:focus~.formulate-input-upload-area-mask,.formulate-input[data-classification=file] .formulate-input-upload-area input:hover~.formulate-input-upload-area-mask,.formulate-input[data-classification=file] .formulate-input-upload-area input[data-is-drag-hover]~.formulate-input-upload-area-mask{border-color:#41b883}.formulate-input[data-classification=file] .formulate-input-upload-area input:focus~.formulate-input-upload-area-mask:before,.formulate-input[data-classification=file] .formulate-input-upload-area input:hover~.formulate-input-upload-area-mask:before,.formulate-input[data-classification=file] .formulate-input-upload-area input[data-is-drag-hover]~.formulate-input-upload-area-mask:before{background-color:#41b883}.formulate-input[data-classification=file] .formulate-files{list-style-type:none;margin:0;padding:0}.formulate-input[data-classification=file] .formulate-files li{-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.3em;border:1px solid #cecece;box-sizing:border-box;background-color:transparent;font-size:.9em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.75em;font-weight:400;line-height:1.1em;margin:0;display:block;width:100%;display:-webkit-box;display:flex;-webkit-box-pack:justify;justify-content:space-between}.formulate-input[data-classification=file] .formulate-files li::-webkit-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=file] .formulate-files li::-moz-placeholder{color:#a8a8a8}.formulate-input[data-classification=file] .formulate-files li:-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=file] .formulate-files li::-ms-input-placeholder{color:#a8a8a8}.formulate-input[data-classification=file] .formulate-files li::placeholder{color:#a8a8a8}.formulate-input[data-classification=file] .formulate-files li:focus{outline:0;border:1px solid #41b883}.formulate-input[data-classification=file] .formulate-files li ::-webkit-progress-bar{-webkit-appearance:none;appearance:none;height:.5em;border-radius:.5em;overflow:hidden}
+/*# sourceMappingURL=data:application/json;base64,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QUFnQixDQURsQixzRkFDRSxhQUFnQixDQURsQiw0RUFDRSxhQUFnQixDQUNsQixxRUFDRSxTQUFVLENBQ1Ysd0JBQTJCLENBQzdCLHNGQUNFLHVCQUFnQixDQUFoQixlQUFnQixDQUNoQixXQUFZLENBQ1osa0JBQW1CLENBQ25CLGVBQWtCIiwiZmlsZSI6InN0ZGluIiwic291cmNlc0NvbnRlbnQiOlsiLmZvcm11bGF0ZS1pbnB1dCB7XG4gIG1hcmdpbi1ib3R0b206IDJlbTsgfVxuICAuZm9ybXVsYXRlLWlucHV0IC5mb3JtdWxhdGUtaW5wdXQtbGFiZWwge1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjU7XG4gICAgZm9udC1zaXplOiAuOWVtO1xuICAgIGZvbnQtd2VpZ2h0OiA2MDA7XG4gICAgbWFyZ2luLWJvdHRvbTogLjFlbTsgfVxuICAuZm9ybXVsYXRlLWlucHV0IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCB7XG4gICAgbWF4LXdpZHRoOiAyMGVtO1xuICAgIG1hcmdpbi1ib3R0b206IC4xZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWhlbHAge1xuICAgIGNvbG9yOiAjNmQ2ZDZkO1xuICAgIGZvbnQtc2l6ZTogLjdlbTtcbiAgICBmb250LXdlaWdodDogNDAwO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjU7XG4gICAgbWFyZ2luLWJvdHRvbTogLjI1ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dCAuZm9ybXVsYXRlLWlucHV0LWVycm9ycyB7XG4gICAgbGlzdC1zdHlsZS10eXBlOiBub25lO1xuICAgIHBhZGRpbmc6IDA7XG4gICAgbWFyZ2luOiAwOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXQgLmZvcm11bGF0ZS1pbnB1dC1lcnJvciB7XG4gICAgY29sb3I6ICM5NjA1MDU7XG4gICAgZm9udC1zaXplOiAuOGVtO1xuICAgIGZvbnQtd2VpZ2h0OiAzMDA7XG4gICAgbGluZS1oZWlnaHQ6IDEuNTtcbiAgICBtYXJnaW4tYm90dG9tOiAuMjVlbTsgfVxuICAuZm9ybXVsYXRlLWlucHV0IC5mb3JtdWxhdGUtaW5wdXQtZ3JvdXAtaXRlbSB7XG4gICAgbWFyZ2luLWJvdHRvbTogLjVlbTsgfVxuICAuZm9ybXVsYXRlLWlucHV0Omxhc3QtY2hpbGQge1xuICAgIG1hcmdpbi1ib3R0b206IDA7IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSd0ZXh0J10gaW5wdXQge1xuICAgIGFwcGVhcmFuY2U6IG5vbmU7XG4gICAgYm9yZGVyLXJhZGl1czogLjNlbTtcbiAgICBib3JkZXI6IDFweCBzb2xpZCAjY2VjZWNlO1xuICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgZm9udC1zaXplOiAuOWVtO1xuICAgIGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsIFwiU2Vnb2UgVUlcIiwgUm9ib3RvLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmLCBcIkFwcGxlIENvbG9yIEVtb2ppXCIsIFwiU2Vnb2UgVUkgRW1vamlcIiwgXCJTZWdvZSBVSSBTeW1ib2xcIjtcbiAgICBwYWRkaW5nOiAuNzVlbTtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICB3aWR0aDogMTAwJTtcbiAgICBmb250LXdlaWdodDogNDAwO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjFlbTtcbiAgICBtYXJnaW46IDA7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHQnXSBpbnB1dDo6cGxhY2Vob2xkZXIge1xuICAgICAgY29sb3I6ICNhOGE4YTg7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHQnXSBpbnB1dDpmb2N1cyB7XG4gICAgICBvdXRsaW5lOiAwO1xuICAgICAgYm9yZGVyOiAxcHggc29saWQgIzQxYjg4MzsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHQnXSBpbnB1dFt0eXBlPVwiY29sb3JcIl0ge1xuICAgIGhlaWdodDogMS4xZW07XG4gICAgYm94LXNpemluZzogY29udGVudC1ib3g7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHQnXSBpbnB1dFt0eXBlPVwiY29sb3JcIl06Oi13ZWJraXQtY29sb3Itc3dhdGNoLXdyYXBwZXIge1xuICAgICAgcGFkZGluZzogMCAwIDAgMS41ZW07XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgIGJhY2tncm91bmQtaW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO3V0ZjgsPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCA3OS4xNyA3OS4xN1wiPjxwYXRoIGZpbGw9XCIlMjM2ZDZkNmRcIiBkPVwiTTQwLjgsMjIuOTJjLTMuNC0zLjQtNC43Ni04LjQ0LTEtMTIuMjRzOC44NC0yLjQ0LDEyLjI0LDFjNS01LDEwLjY5LTEzLjMzLDE4LjgxLTExLjMxYTExLDExLDAsMCwxLDcuNjIsMTQuMzRjLTEuMjYsMy40NS00LjYzLDYuMDYtNy4xNiw4LjU5LS45Mi45My0zLDIuMjYtMy40NiwzLjQ2LS40MiwxLDEuODIsMi42MywyLjM2LDRhOCw4LDAsMCwxLTEyLjQyLDkuMTljLS4yMS0uMTYtMS4zNS0xLjUxLTEuNTktMS41MXMtLjgzLjgzLTEsMUw0OS43MSw0NC45LDMyLjQzLDYyLjE4Yy0zLjM3LDMuMzgtNi42LDcuMTQtMTAuMjYsMTAuMjFhMTEsMTEsMCwwLDEtNC40OCwyLjI4Yy0xLjI1LjMtMy4xMS0uMjItNC4xOC4xOC0xLjI4LjQ4LTIuNDIsMi42NS0zLjY4LDMuNC02LjA1LDMuNjEtMTIuNjQtNC04LjQ2LTkuNTcuNzMtMSwyLjUzLTEuOTIsMy0zYTE0LjQ2LDE0LjQ2LDAsMCwwLS4wOS0yLjUyLDEwLjc1LDEwLjc1LDAsMCwxLDMuMTQtNi43N2MuOTItMSwxLjkzLTEuOTMsMi44OS0yLjlabTQuNC0xLjVjNC4xOSw0LDguMjQsOC4yNCwxMi4zNiwxMi4zNiwyLjA2LDIuMDYsNSw1LjU5LDgsMi42MSw0LjY1LTQuNjItNS02LjgtMi40Mi0xMC43OEM2Ni4zLDIwLjcsNzYuNCwxNi40OCw3NC44NCw5LjQ1LDczLjYyLDQsNjcuMTIsMi43OCw2My4yOSw2LjMyYy0yLjU1LDIuMzYtNC45Myw0Ljk0LTcuMzksNy40LS43OS43OC0xLjgsMi4yOC0yLjg4LDIuNzMtMi4xNC44OC0zLjQtMS42Mi00Ljc5LTIuNzctMi41OC0yLjE0LTYuODktLjgyLTYuNTMsM0M0MS44OSwxOC42OCw0My44NywyMC4wOSw0NS4yLDIxLjQyWm0tMS40NSw0LjQ0TDI3LjgyLDQxLjc5QzIyLDQ3LjU3LDE1Ljg5LDUzLjE0LDEwLjQxLDU5LjJhOC4yMyw4LjIzLDAsMCwwLTEuNDQsMmMtLjkzLDIsLjI1LDQuMTQtLjUsNlM0LjkyLDY5Ljk0LDQuMyw3MmEyLjM0LDIuMzQsMCwwLDAsMi41NiwzYzEuMTEtLjE3LDItMS4zMywyLjcxLTIuMDdhMTEuMTcsMTEuMTcsMCwwLDEsMi4wOC0yYzEuNjgtLjk0LDQsLjE3LDUuOTMtLjU3QzIwLDY5LjQxLDIyLDY2LjczLDIzLjc2LDY1TDM0LjQyLDU0LjMsNTMuMywzNS40MlpcIi8+PC9zdmc+Jyk7XG4gICAgICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xuICAgICAgYmFja2dyb3VuZC1zaXplOiAuOWVtIC45ZW07XG4gICAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiBsZWZ0IC4xZW07IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHQnXSBpbnB1dFt0eXBlPVwiY29sb3JcIl06Oi13ZWJraXQtY29sb3Itc3dhdGNoIHtcbiAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgaGVpZ2h0OiAxZW07XG4gICAgICBib3JkZXItcmFkaXVzOiAuMmVtO1xuICAgICAgYm9yZGVyOiAwO1xuICAgICAgZmxleDogYXV0bzsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0ndGV4dCddIGlucHV0W3R5cGU9XCJjb2xvclwiXTo6LW1vei1jb2xvci1zd2F0Y2gge1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICBoZWlnaHQ6IDFlbTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IC4yZW07XG4gICAgICBib3JkZXI6IDA7XG4gICAgICBmbGV4OiBhdXRvOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2xpZGVyJ10gaW5wdXQge1xuICAgIGFwcGVhcmFuY2U6IG5vbmU7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC1zaXplOiAxZW07XG4gICAgcGFkZGluZzogLjVlbSAwOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzbGlkZXInXSBpbnB1dDpmb2N1cyB7XG4gICAgICBvdXRsaW5lOiAwOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzbGlkZXInXSBpbnB1dDo6LXdlYmtpdC1zbGlkZXItdGh1bWIge1xuICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICAgIHdpZHRoOiAxZW07XG4gICAgICBoZWlnaHQ6IDFlbTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDFlbTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICM0MWI4ODM7XG4gICAgICBtYXJnaW4tdG9wOiBjYWxjKC0uNWVtICsgMnB4KTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2xpZGVyJ10gaW5wdXQ6Oi1tb3otcmFuZ2UtdGh1bWIge1xuICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICAgIHdpZHRoOiAxZW07XG4gICAgICBoZWlnaHQ6IDFlbTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDFlbTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICM0MWI4ODM7XG4gICAgICBtYXJnaW4tdG9wOiBjYWxjKC0uNWVtICsgMnB4KTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2xpZGVyJ10gaW5wdXQ6Oi1tcy10aHVtYiB7XG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgICAgd2lkdGg6IDFlbTtcbiAgICAgIGhlaWdodDogMWVtO1xuICAgICAgYm9yZGVyLXJhZGl1czogMWVtO1xuICAgICAgYmFja2dyb3VuZC1jb2xvcjogIzQxYjg4MztcbiAgICAgIG1hcmdpbi10b3A6IGNhbGMoLS41ZW0gKyAycHgpOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzbGlkZXInXSBpbnB1dDo6LXdlYmtpdC1zbGlkZXItcnVubmFibGUtdHJhY2sge1xuICAgICAgYXBwZWFyYW5jZTogbm9uZTtcbiAgICAgIHdpZHRoOiAxMDAlO1xuICAgICAgaGVpZ2h0OiA0cHg7XG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZWZlZmVmO1xuICAgICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgICAgbWFyZ2luOiAwO1xuICAgICAgcGFkZGluZzogMDsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHRhcmVhJ10gdGV4dGFyZWEge1xuICAgIGFwcGVhcmFuY2U6IG5vbmU7XG4gICAgYm9yZGVyLXJhZGl1czogLjNlbTtcbiAgICBib3JkZXI6IDFweCBzb2xpZCAjY2VjZWNlO1xuICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgZm9udC1zaXplOiAuOWVtO1xuICAgIGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsIFwiU2Vnb2UgVUlcIiwgUm9ib3RvLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmLCBcIkFwcGxlIENvbG9yIEVtb2ppXCIsIFwiU2Vnb2UgVUkgRW1vamlcIiwgXCJTZWdvZSBVSSBTeW1ib2xcIjtcbiAgICBwYWRkaW5nOiAuNzVlbTtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICB3aWR0aDogMTAwJTtcbiAgICBmb250LXdlaWdodDogNDAwO1xuICAgIGxpbmUtaGVpZ2h0OiAxLjFlbTtcbiAgICBtYXJnaW46IDA7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3RleHRhcmVhJ10gdGV4dGFyZWE6OnBsYWNlaG9sZGVyIHtcbiAgICAgIGNvbG9yOiAjYThhOGE4OyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSd0ZXh0YXJlYSddIHRleHRhcmVhOmZvY3VzIHtcbiAgICAgIG91dGxpbmU6IDA7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50IHtcbiAgICBwb3NpdGlvbjogcmVsYXRpdmU7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J3NlbGVjdCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudDo6YmVmb3JlIHtcbiAgICAgIGNvbnRlbnQ6ICcnO1xuICAgICAgd2lkdGg6IDA7XG4gICAgICBoZWlnaHQ6IDA7XG4gICAgICBib3JkZXI6IC4zZW0gc29saWQgdHJhbnNwYXJlbnQ7XG4gICAgICBib3JkZXItdG9wLWNvbG9yOiAjY2VjZWNlO1xuICAgICAgYm9yZGVyLWJvdHRvbS13aWR0aDogMDtcbiAgICAgIHRvcDogNTAlO1xuICAgICAgbWFyZ2luLXRvcDogLS4xZW07XG4gICAgICByaWdodDogMWVtO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gc2VsZWN0IHtcbiAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgIGJvcmRlci1yYWRpdXM6IC4zZW07XG4gICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgQmxpbmtNYWNTeXN0ZW1Gb250LCBcIlNlZ29lIFVJXCIsIFJvYm90bywgSGVsdmV0aWNhLCBBcmlhbCwgc2Fucy1zZXJpZiwgXCJBcHBsZSBDb2xvciBFbW9qaVwiLCBcIlNlZ29lIFVJIEVtb2ppXCIsIFwiU2Vnb2UgVUkgU3ltYm9sXCI7XG4gICAgcGFkZGluZzogLjc1ZW07XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC13ZWlnaHQ6IDQwMDtcbiAgICBsaW5lLWhlaWdodDogMS4xZW07XG4gICAgbWFyZ2luOiAwO1xuICAgIHBhZGRpbmctcmlnaHQ6IDJlbTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gc2VsZWN0OjpwbGFjZWhvbGRlciB7XG4gICAgICBjb2xvcjogI2E4YThhODsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nc2VsZWN0J10gc2VsZWN0OmZvY3VzIHtcbiAgICAgIG91dGxpbmU6IDA7XG4gICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdzZWxlY3QnXSBzZWxlY3RbZGF0YS1wbGFjZWhvbGRlci1zZWxlY3RlZF0ge1xuICAgICAgY29sb3I6ICNhOGE4YTg7IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPSdib3gnXSAuZm9ybXVsYXRlLWlucHV0LXdyYXBwZXIge1xuICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgYWxpZ24taXRlbXM6IGNlbnRlcjsgfVxuICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCB7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dCB7XG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICBsZWZ0OiAtOTk5cHg7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3Ige1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICB3aWR0aDogMWVtO1xuICAgICAgaGVpZ2h0OiAxZW07XG4gICAgICBib3JkZXItcmFkaXVzOiAuMjVlbTtcbiAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNjZWNlY2U7XG4gICAgICBwb3NpdGlvbjogcmVsYXRpdmU7IH1cbiAgICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50LWRlY29yYXRvcjo6YmVmb3JlIHtcbiAgICAgICAgY29udGVudDogJyc7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gICAgICAgIGJhY2tncm91bmQtcG9zaXRpb246IHJpZ2h0O1xuICAgICAgICB3aWR0aDogY2FsYygxMDAlIC0gLjEyNWVtKTtcbiAgICAgICAgaGVpZ2h0OiBjYWxjKDEwMCUgLSAuMTI1ZW0pO1xuICAgICAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICAgICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICAgIHRvcDogLjA2MjVlbTtcbiAgICAgICAgbGVmdDogLjA2MjVlbTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1lbGVtZW50W2RhdGEtdHlwZT1cInJhZGlvXCJdIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3Ige1xuICAgICAgYm9yZGVyLXJhZGl1czogMWVtOyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudFtkYXRhLXR5cGU9XCJyYWRpb1wiXSAuZm9ybXVsYXRlLWlucHV0LWVsZW1lbnQtZGVjb3JhdG9yOjpiZWZvcmUge1xuICAgICAgICBib3JkZXItcmFkaXVzOiAxZW07XG4gICAgICAgIHdpZHRoOiBjYWxjKDEwMCUgLSAuNWVtKTtcbiAgICAgICAgaGVpZ2h0OiBjYWxjKDEwMCUgLSAuNWVtKTtcbiAgICAgICAgdG9wOiAuMjVlbTtcbiAgICAgICAgbGVmdDogLjI1ZW07IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl06Y2hlY2tlZCB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3Ige1xuICAgICAgYm9yZGVyLWNvbG9yOiAjNDFiODgzOyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl06Y2hlY2tlZCB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3I6OmJlZm9yZSB7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICM0MWI4ODM7XG4gICAgICAgIG1hc2staW1hZ2U6IHVybCgnZGF0YTppbWFnZS9zdmcreG1sO3V0ZjgsPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCAxMDAgMTAwXCI+PHBhdGggZD1cIk04Ljc2LDU2LjJjLTYuMzgtNi4zNCwzLjI2LTE2LDkuNjQtOS42OUwzOCw2NS44OCw4MC41NiwyMy4yOWM2LjM4LTYuMzgsMTYuMDcsMy4zMiw5LjY5LDkuNjlMNDIuODQsODAuMzdhNi44Myw2LjgzLDAsMCwxLTkuNjUsMFpcIi8+PC9zdmc+Jyk7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dFt0eXBlPVwicmFkaW9cIl06Y2hlY2tlZCB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3Ige1xuICAgICAgYm9yZGVyLWNvbG9yOiAjNDFiODgzOyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dFt0eXBlPVwicmFkaW9cIl06Y2hlY2tlZCB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3I6OmJlZm9yZSB7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICM0MWI4ODM7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249J2JveCddIC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudCBpbnB1dDpmb2N1cyB+IC5mb3JtdWxhdGUtaW5wdXQtZWxlbWVudC1kZWNvcmF0b3Ige1xuICAgICAgYm9yZGVyLWNvbG9yOiAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1sYWJlbC0tYWZ0ZXIge1xuICAgIG1hcmdpbi1sZWZ0OiAuNWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj0nYm94J10gLmZvcm11bGF0ZS1pbnB1dC1sYWJlbC0tYmVmb3JlIHtcbiAgICBtYXJnaW4tcmlnaHQ6IC41ZW07IH1cbiAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPVwiZ3JvdXBcIl0gPiAuZm9ybXVsYXRlLWlucHV0LXdyYXBwZXIgPiAuZm9ybXVsYXRlLWlucHV0LWxhYmVsIHtcbiAgICBtYXJnaW4tYm90dG9tOiAuNWVtOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYSB7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIHBhZGRpbmc6IDJlbTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYVtkYXRhLWhhcy1maWxlc10ge1xuICAgICAgcGFkZGluZzogMDsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYSBpbnB1dCB7XG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICBhcHBlYXJhbmNlOiBub25lO1xuICAgICAgb3BhY2l0eTogMDtcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgIGxlZnQ6IDA7XG4gICAgICByaWdodDogMDtcbiAgICAgIGJvdHRvbTogMDtcbiAgICAgIHRvcDogMDtcbiAgICAgIHdpZHRoOiAxMDAlO1xuICAgICAgaGVpZ2h0OiAxMDAlO1xuICAgICAgei1pbmRleDogNTsgfVxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYS1tYXNrIHtcbiAgICAgIGJvcmRlci1yYWRpdXM6IC40ZW07XG4gICAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICBsZWZ0OiAwO1xuICAgICAgcmlnaHQ6IDA7XG4gICAgICB0b3A6IDA7XG4gICAgICBib3R0b206IDA7XG4gICAgICBib3JkZXI6IDJweCBkYXNoZWQgI2E4YThhODtcbiAgICAgIHotaW5kZXg6IDI7IH1cbiAgICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYS1tYXNrOjpiZWZvcmUge1xuICAgICAgICBjb250ZW50OiAnJztcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2E4YThhODtcbiAgICAgICAgbWFzay1pbWFnZTogdXJsKCdkYXRhOmltYWdlL3N2Zyt4bWw7dXRmOCw8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB2aWV3Qm94PVwiMCAwIDU4IDU4XCI+PHBhdGggZD1cIk0yOSw1OEEyOSwyOSwwLDEsMCwwLDI5LDI5LDI5LDAsMCwwLDI5LDU4Wk0yOSw0QTI1LDI1LDAsMSwxLDQsMjksMjUsMjUsMCwwLDEsMjksNFpcIi8+PHBvbHlnb24gcG9pbnRzPVwiMjcgMjIgMjcgNDQuNCAzMSA0NC40IDMxIDIyIDQxLjcgMzEuMSA0NC4zIDI4LjEgMjkgMTUgMTMuNyAyOC4xIDE2LjMgMzEuMSAyNyAyMlwiLz48L3N2Zz4nKTtcbiAgICAgICAgd2lkdGg6IDJlbTtcbiAgICAgICAgaGVpZ2h0OiAyZW07XG4gICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgcG9pbnRlci1ldmVudHM6IG5vbmU7IH1cbiAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249XCJmaWxlXCJdIC5mb3JtdWxhdGUtaW5wdXQtdXBsb2FkLWFyZWEgaW5wdXQ6Zm9jdXMgfiAuZm9ybXVsYXRlLWlucHV0LXVwbG9hZC1hcmVhLW1hc2ssXG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPVwiZmlsZVwiXSAuZm9ybXVsYXRlLWlucHV0LXVwbG9hZC1hcmVhIGlucHV0OmhvdmVyIH4gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYS1tYXNrLFxuICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYSBpbnB1dFtkYXRhLWlzLWRyYWctaG92ZXJdIH4gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYS1tYXNrIHtcbiAgICAgIGJvcmRlci1jb2xvcjogIzQxYjg4MzsgfVxuICAgICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPVwiZmlsZVwiXSAuZm9ybXVsYXRlLWlucHV0LXVwbG9hZC1hcmVhIGlucHV0OmZvY3VzIH4gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYS1tYXNrOjpiZWZvcmUsXG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249XCJmaWxlXCJdIC5mb3JtdWxhdGUtaW5wdXQtdXBsb2FkLWFyZWEgaW5wdXQ6aG92ZXIgfiAuZm9ybXVsYXRlLWlucHV0LXVwbG9hZC1hcmVhLW1hc2s6OmJlZm9yZSxcbiAgICAgIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYSBpbnB1dFtkYXRhLWlzLWRyYWctaG92ZXJdIH4gLmZvcm11bGF0ZS1pbnB1dC11cGxvYWQtYXJlYS1tYXNrOjpiZWZvcmUge1xuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjNDFiODgzOyB9XG4gIC5mb3JtdWxhdGUtaW5wdXRbZGF0YS1jbGFzc2lmaWNhdGlvbj1cImZpbGVcIl0gLmZvcm11bGF0ZS1maWxlcyB7XG4gICAgbGlzdC1zdHlsZS10eXBlOiBub25lO1xuICAgIG1hcmdpbjogMDtcbiAgICBwYWRkaW5nOiAwOyB9XG4gICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPVwiZmlsZVwiXSAuZm9ybXVsYXRlLWZpbGVzIGxpIHtcbiAgICAgIGFwcGVhcmFuY2U6IG5vbmU7XG4gICAgICBib3JkZXItcmFkaXVzOiAuM2VtO1xuICAgICAgYm9yZGVyOiAxcHggc29saWQgI2NlY2VjZTtcbiAgICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgICAgIGZvbnQtc2l6ZTogLjllbTtcbiAgICAgIGZvbnQtZmFtaWx5OiAtYXBwbGUtc3lzdGVtLCBCbGlua01hY1N5c3RlbUZvbnQsIFwiU2Vnb2UgVUlcIiwgUm9ib3RvLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmLCBcIkFwcGxlIENvbG9yIEVtb2ppXCIsIFwiU2Vnb2UgVUkgRW1vamlcIiwgXCJTZWdvZSBVSSBTeW1ib2xcIjtcbiAgICAgIHBhZGRpbmc6IC43NWVtO1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICB3aWR0aDogMTAwJTtcbiAgICAgIGZvbnQtd2VpZ2h0OiA0MDA7XG4gICAgICBsaW5lLWhlaWdodDogMS4xZW07XG4gICAgICBtYXJnaW46IDA7XG4gICAgICBkaXNwbGF5OiBibG9jaztcbiAgICAgIHdpZHRoOiAxMDAlO1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsgfVxuICAgICAgLmZvcm11bGF0ZS1pbnB1dFtkYXRhLWNsYXNzaWZpY2F0aW9uPVwiZmlsZVwiXSAuZm9ybXVsYXRlLWZpbGVzIGxpOjpwbGFjZWhvbGRlciB7XG4gICAgICAgIGNvbG9yOiAjYThhOGE4OyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249XCJmaWxlXCJdIC5mb3JtdWxhdGUtZmlsZXMgbGk6Zm9jdXMge1xuICAgICAgICBvdXRsaW5lOiAwO1xuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAjNDFiODgzOyB9XG4gICAgICAuZm9ybXVsYXRlLWlucHV0W2RhdGEtY2xhc3NpZmljYXRpb249XCJmaWxlXCJdIC5mb3JtdWxhdGUtZmlsZXMgbGkgOjotd2Via2l0LXByb2dyZXNzLWJhciB7XG4gICAgICAgIGFwcGVhcmFuY2U6IG5vbmU7XG4gICAgICAgIGhlaWdodDogLjVlbTtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogLjVlbTtcbiAgICAgICAgb3ZlcmZsb3c6IGhpZGRlbjsgfVxuIl19 */
\ No newline at end of file
diff --git a/src/FileUpload.js b/src/FileUpload.js
new file mode 100644
index 0000000..b13befe
--- /dev/null
+++ b/src/FileUpload.js
@@ -0,0 +1,113 @@
+import nanoid from 'nanoid'
+
+/**
+ * The file upload class holds and represents a file’s upload state durring
+ * the upload flow.
+ */
+class FileUpload {
+ /**
+ * Create a file upload object.
+ * @param {FileList} fileList
+ * @param {object} context
+ */
+ constructor (fileList, context, options) {
+ this.fileList = fileList
+ this.files = []
+ this.options = options
+ this.setFileList(fileList)
+ this.context = context
+ }
+
+ /**
+ * Produce an array of files and alert the callback.
+ * @param {FileList}
+ */
+ setFileList (fileList) {
+ for (let i = 0; i < fileList.length; i++) {
+ const file = fileList.item(i)
+ this.files.push({
+ progress: 0,
+ name: file.name || 'file-upload',
+ file: file,
+ uuid: nanoid()
+ })
+ }
+ }
+
+ /**
+ * Check if the file has an.
+ */
+ hasUploader () {
+ return !!this.context.uploader
+ }
+
+ uploaderIsAxios () {
+ if (
+ this.hasUploader &&
+ typeof this.hasUploader.request === 'function' &&
+ typeof this.hasUploader.get === 'function' &&
+ typeof this.hasUploader.delete === 'function' &&
+ typeof this.hasUploader.post === 'function'
+ ) {
+ return true
+ }
+ return false
+ }
+
+ /**
+ * Get a new uploader function.
+ */
+ getUploader (...args) {
+ if (this.uploaderIsAxios()) {
+ const formData = new FormData()
+ formData.append(this.context.name || 'file', args[0])
+ return this.uploader.post(this.context.uploadUrl, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ },
+ onUploadProgress: progressEvent => {
+ args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total))
+ }
+ })
+ .catch(err => args[2](err))
+ }
+ return this.context.uploader(...args)
+ }
+
+ /**
+ * Perform the file upload.
+ */
+ upload () {
+ return new Promise((resolve, reject) => {
+ if (!this.hasUploader) {
+ return reject(new Error('No uploader has been defined'))
+ }
+ Promise.all(this.files.map(file => {
+ return this.getUploader(
+ file.file,
+ (progress) => { file.progress = progress },
+ (error) => reject(new Error(error)),
+ this.options
+ )
+ }))
+ .then(results => resolve(results))
+ .catch(err => { throw new Error(err) })
+ })
+ }
+
+ /**
+ * Get the files.
+ */
+ getFileList () {
+ return this.fileList
+ }
+
+ /**
+ * Get the files.
+ */
+ getFiles () {
+ return this.files
+ }
+}
+
+export default FileUpload
diff --git a/src/Formulate.js b/src/Formulate.js
index 91f03e0..1fb38a1 100644
--- a/src/Formulate.js
+++ b/src/Formulate.js
@@ -1,13 +1,16 @@
import library from './libs/library'
import rules from './libs/rules'
import en from './locales/en'
+import FileUpload from './FileUpload'
import isPlainObject from 'is-plain-object'
+import fauxUploader from './libs/faux-uploader'
import FormulateInput from './FormulateInput.vue'
import FormulateForm from './FormulateForm.vue'
import FormulateInputErrors from './FormulateInputErrors.vue'
import FormulateInputGroup from './FormulateInputGroup.vue'
import FormulateInputBox from './inputs/FormulateInputBox.vue'
import FormulateInputText from './inputs/FormulateInputText.vue'
+import FormulateInputFile from './inputs/FormulateInputFile.vue'
import FormulateInputSelect from './inputs/FormulateInputSelect.vue'
import FormulateInputSlider from './inputs/FormulateInputSlider.vue'
import FormulateInputTextArea from './inputs/FormulateInputTextArea.vue'
@@ -27,6 +30,7 @@ class Formulate {
FormulateInputErrors,
FormulateInputBox,
FormulateInputText,
+ FormulateInputFile,
FormulateInputGroup,
FormulateInputSelect,
FormulateInputSlider,
@@ -35,6 +39,7 @@ class Formulate {
library,
rules,
locale: 'en',
+ uploader: fauxUploader,
locales: {
en
}
@@ -122,6 +127,20 @@ class Formulate {
}
return 'This field does not have a valid value'
}
+
+ /**
+ * Get the file uploader.
+ */
+ getUploader () {
+ return this.options.uploader || false
+ }
+
+ /**
+ * Create a new instance of an upload.
+ */
+ createUpload (fileList, context) {
+ return new FileUpload(fileList, context, this.options)
+ }
}
export default new Formulate()
diff --git a/src/FormulateFiles.vue b/src/FormulateFiles.vue
new file mode 100644
index 0000000..b7392d5
--- /dev/null
+++ b/src/FormulateFiles.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
diff --git a/src/FormulateInput.vue b/src/FormulateInput.vue
index ad24005..8f85a2a 100644
--- a/src/FormulateInput.vue
+++ b/src/FormulateInput.vue
@@ -136,6 +136,22 @@ export default {
showErrors: {
type: Boolean,
default: false
+ },
+ showImage: {
+ type: Boolean,
+ default: true
+ },
+ uploadUrl: {
+ type: [String, Boolean],
+ default: false
+ },
+ uploader: {
+ type: [Function, Object, Boolean],
+ default: false
+ },
+ immediateUpload: {
+ type: Boolean,
+ default: true
}
},
data () {
diff --git a/src/inputs/FormulateInputFile.vue b/src/inputs/FormulateInputFile.vue
new file mode 100644
index 0000000..078a2a9
--- /dev/null
+++ b/src/inputs/FormulateInputFile.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
diff --git a/src/inputs/FormulateInputSlider.vue b/src/inputs/FormulateInputSlider.vue
index 6cc3e68..8b61fd8 100644
--- a/src/inputs/FormulateInputSlider.vue
+++ b/src/inputs/FormulateInputSlider.vue
@@ -16,7 +16,7 @@
import FormulateInputMixin from '../FormulateInputMixin'
export default {
- name: 'FormulateInputText',
+ name: 'FormulateInputSlider',
mixins: [FormulateInputMixin]
}
diff --git a/src/libs/context.js b/src/libs/context.js
index b2ff591..d45aeb0 100644
--- a/src/libs/context.js
+++ b/src/libs/context.js
@@ -19,6 +19,10 @@ export default {
labelPosition: this.logicalLabelPosition,
attributes: this.elementAttributes,
blurHandler: blurHandler.bind(this),
+ showImage: this.showImage,
+ uploadUrl: this.uploadUrl,
+ uploader: this.uploader || this.$formulate.getUploader(),
+ immediateUpload: this.immediateUpload,
...this.typeContext
})
},
diff --git a/src/libs/faux-uploader.js b/src/libs/faux-uploader.js
new file mode 100644
index 0000000..672631c
--- /dev/null
+++ b/src/libs/faux-uploader.js
@@ -0,0 +1,28 @@
+/**
+ * A fake uploader used by default.
+ *
+ * @param {File} file
+ * @param {function} progress
+ * @param {function} error
+ * @param {object} options
+ */
+export default function (file, progress, error, options) {
+ return new Promise((resolve, reject) => {
+ const totalTime = options.fauxUploaderDuration || 2000
+ const start = performance.now()
+ const advance = () => setTimeout(() => {
+ const elapsed = performance.now() - start
+ const currentProgress = Math.min(100, Math.round(elapsed / totalTime * 100))
+ progress(currentProgress)
+ if (currentProgress >= 100) {
+ resolve({
+ url: 'http://via.placeholder.com/350x150.png',
+ name: file.name
+ })
+ } else {
+ advance()
+ }
+ }, 20)
+ advance()
+ })
+}
diff --git a/src/libs/library.js b/src/libs/library.js
index 8596ab8..5596885 100644
--- a/src/libs/library.js
+++ b/src/libs/library.js
@@ -93,5 +93,16 @@ export default {
select: {
classification: 'select',
component: 'FormulateInputSelect'
+ },
+
+ // === FILE TYPE
+
+ file: {
+ classification: 'file',
+ component: 'FormulateInputFile'
+ },
+ image: {
+ classification: 'file',
+ component: 'FormulateInputFile'
}
}
diff --git a/src/libs/rules.js b/src/libs/rules.js
index 7bb9567..4be177a 100644
--- a/src/libs/rules.js
+++ b/src/libs/rules.js
@@ -1,4 +1,5 @@
import isUrl from 'is-url'
+import FileUpload from '../FileUpload'
import { shallowEqualObjects, regexForFormat } from './utils'
/**
@@ -124,17 +125,18 @@ export default {
/**
* Check the maximum value of a particular.
*/
- max: function (value, minimum = 10) {
+ max: function (value, minimum = 10, force) {
return Promise.resolve((() => {
- minimum = Number(minimum)
- if (!isNaN(value)) {
- value = Number(value)
- return value <= minimum
- }
- if (typeof value === 'string') {
+ if (Array.isArray(value)) {
+ minimum = !isNaN(minimum) ? Number(minimum) : minimum
return value.length <= minimum
}
- if (Array.isArray(value)) {
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ value = !isNaN(value) ? Number(value) : value
+ return value <= minimum
+ }
+ if (typeof value === 'string' || (force === 'length')) {
+ value = !isNaN(value) ? value.toString() : value
return value.length <= minimum
}
return false
@@ -146,6 +148,12 @@ export default {
*/
mime: function (files, ...types) {
return Promise.resolve((() => {
+ if (files instanceof FileUpload) {
+ if (files.hasUploader()) {
+ return false
+ }
+ files = files.getFiles()
+ }
if (typeof window !== 'undefined' && typeof FileReader !== 'undefined' && typeof Blob !== 'undefined') {
for (const i in files) {
if (!types.includes(files[i].type)) {
diff --git a/src/locales/en.js b/src/locales/en.js
index 890d804..bbc3310 100644
--- a/src/locales/en.js
+++ b/src/locales/en.js
@@ -103,20 +103,28 @@ export default {
* The maximum value allowed.
*/
max: function ({ name, value, args }) {
- if (!isNaN(value)) {
- return `${name} must be less than ${args[0]}.`
+ if (Array.isArray(value)) {
+ return `You may only select ${args[0]} ${name}.`
}
- return `${name} must be less than ${args[0]} characters long.`
+ const force = Array.isArray(args) && args[1] ? args[1] : false
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return `${s(name)} must be less than ${args[0]}.`
+ }
+ return `${s(name)} must be less than ${args[0]} characters long.`
},
/**
* The maximum value allowed.
*/
min: function ({ name, value, args }) {
- if (!isNaN(value)) {
- return `${name} must be more than ${args[0]}.`
+ if (Array.isArray(value)) {
+ return `You must select at least ${args[0]} ${name}.`
}
- return `${name} must be more than ${args[0]} characters long.`
+ const force = Array.isArray(args) && args[1] ? args[1] : false
+ if ((!isNaN(value) && force !== 'length') || force === 'value') {
+ return `${s(name)} must be more than ${args[0]}.`
+ }
+ return `${s(name)} must be more than ${args[0]} characters long.`
},
/**
diff --git a/test/Formulate.test.js b/test/Formulate.test.js
index a0e6770..94d8dff 100644
--- a/test/Formulate.test.js
+++ b/test/Formulate.test.js
@@ -53,6 +53,7 @@ test('installs on vue instance', () => {
'FormulateInputErrors',
'FormulateInputBox',
'FormulateInputText',
+ 'FormulateInputFile',
'FormulateInputGroup',
'FormulateInputSelect',
'FormulateInputSlider',
diff --git a/test/rules.test.js b/test/rules.test.js
index 3679967..3e6bb91 100644
--- a/test/rules.test.js
+++ b/test/rules.test.js
@@ -331,11 +331,19 @@ describe('max', () => {
it('passes when a array length', async () => expect(await rules.max(Array(6), '6')).toBe(true))
+ it('passes when forced to validate on length', async () => expect(await rules.max(10, 3, 'length')).toBe(true))
+
+ it('passes when forced to validate string on value', async () => expect(await rules.max('b', 'e', 'value')).toBe(true))
+
it('fails when a array length', async () => expect(await rules.max(Array(6), '5')).toBe(false))
it('fails when a string length', async () => expect(await rules.max('bar', 2)).toBe(false))
it('fails when a number', async () => expect(await rules.max(10, '7')).toBe(false))
+
+ it('fails when a number', async () => expect(await rules.max(10, '7')).toBe(false))
+
+ it('fails when forced to validate on length', async () => expect(await rules.max(-10, '1', 'length')).toBe(false))
})
/**
diff --git a/themes/snow/_inputs.scss b/themes/snow/_inputs.scss
index b8b0a7d..ccde311 100644
--- a/themes/snow/_inputs.scss
+++ b/themes/snow/_inputs.scss
@@ -55,6 +55,37 @@
input {
@include baseinput;
}
+
+ input[type="color"] {
+ height: 1.1em;
+ box-sizing: content-box;
+
+ @mixin color-swatch {
+ display: block;
+ height: 1em;
+ border-radius: .2em;
+ border: 0;
+ flex: auto;
+ }
+
+ &::-webkit-color-swatch-wrapper {
+ padding: 0 0 0 1.5em;
+ display: flex;
+ align-items: center;
+ background-image: url('data:image/svg+xml;utf8,');
+ background-repeat: no-repeat;
+ background-size: .9em .9em;
+ background-position: left .1em;
+ }
+
+ &::-webkit-color-swatch {
+ @include color-swatch;
+ }
+
+ &::-moz-color-swatch {
+ @include color-swatch;
+ }
+ }
}
// Slider inputs
@@ -207,7 +238,8 @@
border-color: $formulate-green;
&::before {
- background-image: url('data:image/svg+xml;utf8,');
+ background-color: $formulate-green;
+ mask-image: url('data:image/svg+xml;utf8,');
}
}
}
@@ -245,4 +277,97 @@
}
}
}
+
+
+ // File inputs
+// -----------------------------------------------------------------------------
+
+ &[data-classification="file"] {
+ .formulate-input-upload-area {
+ width: 100%;
+ position: relative;
+ padding: 2em;
+
+ &[data-has-files] {
+ padding: 0;
+ }
+
+ input {
+ cursor: pointer;
+ appearance: none;
+ opacity: 0;
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 5;
+ }
+
+ &-mask {
+ border-radius: .4em;
+ position: absolute;
+ pointer-events: none;
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ border: 2px dashed $formulate-gray-dd;
+ z-index: 2;
+
+ &::before {
+ content: '';
+ background-color: $formulate-gray-dd;
+ mask-image: url('data:image/svg+xml;utf8,');
+ width: 2em;
+ height: 2em;
+ position: absolute;
+ pointer-events: none;
+ }
+ }
+
+ input:focus,
+ input:hover,
+ input[data-is-drag-hover] {
+ & ~ .formulate-input-upload-area-mask {
+ border-color: $formulate-green;
+
+ &::before {
+ background-color: $formulate-green;
+ }
+ }
+ }
+ }
+
+ .formulate-files {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+
+ li {
+ @include baseinput;
+ display: block;
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+
+ @mixin progress {
+ appearance: none;
+ height: .5em;
+ border-radius: .5em;
+ overflow: hidden;
+ }
+
+ ::-webkit-progress-bar {
+ @include progress;
+ }
+ }
+ }
+ }
}
diff --git a/themes/snow/_variables.scss b/themes/snow/_variables.scss
index 4b4ad35..80c6c7a 100644
--- a/themes/snow/_variables.scss
+++ b/themes/snow/_variables.scss
@@ -37,6 +37,8 @@ $formulate-yellow-l: #fff8d2;
display: block;
width: 100%;
font-weight: 400;
+ line-height: 1.1em;
+ margin: 0;
&::placeholder {
color: $formulate-gray-dd;