1
0
mirror of synced 2024-11-22 05:16:05 +03:00

Adds support for plugin architecture

This commit is contained in:
Justin Schroeder 2020-02-27 14:47:24 -05:00
parent c31e896b86
commit c0ffcab79f
8 changed files with 183 additions and 21 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3
dist/snow.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@
},
"scripts": {
"build": "npm run build:umd & npm run build:es & npm run build:unpkg & npm run build:css",
"build:css": "node-sass themes/snow/snow.scss dist/snow.css && postcss --use autoprefixer -b '> 2%' < dist/snow.css | postcss --use cssnano > dist/snow.min.css",
"build:css": "node-sass themes/snow/snow.scss dist/snow.css && postcss --use autoprefixer -b '> 2%' < dist/snow.css | postcss --no-map --use cssnano > dist/snow.min.css",
"build:umd": "rollup --config build/rollup.config.js --format umd --file dist/formulate.umd.js",
"build:es": "rollup --config build/rollup.config.js --format es --file dist/formulate.esm.js",
"build:unpkg": "rollup --config build/rollup.config.js --format iife --file dist/formulate.min.js",

View File

@ -24,6 +24,7 @@ class Formulate {
* Instantiate our base options.
*/
constructor () {
this.options = {}
this.defaults = {
components: {
FormulateForm,
@ -43,6 +44,7 @@ class Formulate {
locale: 'en',
uploader: fauxUploader,
uploadJustCompleteDuration: 1000,
plugins: [],
locales: {
en
}
@ -54,32 +56,54 @@ class Formulate {
*/
install (Vue, options) {
Vue.prototype.$formulate = this
this.options = this.extend(this.defaults, options || {})
this.options = this.merge(this.defaults, options || {})
if (Array.isArray(this.options.plugins) && this.options.plugins.length) {
this.options.plugins
.forEach(plugin => (typeof plugin === 'function') ? plugin(this) : null)
}
for (var componentName in this.options.components) {
Vue.component(componentName, this.options.components[componentName])
}
Object.freeze(this)
}
/**
* Create a new object by copying properties of base and extendWith.
* @param {Object} base
* Given a set of options, apply them to the pre-existing options.
* @param {Object} extendWith
*/
extend (base, extendWith) {
extend (extendWith) {
if (typeof extendWith === 'object') {
this.options = this.merge(this.options, extendWith)
return this
}
throw new Error(`VueFormulate extend() should be passed an object (was ${typeof extendWith})`)
}
/**
* Create a new object by copying properties of base and mergeWith.
* Note: arrays don't overwrite - they push
*
* @param {Object} base
* @param {Object} mergeWith
* @param {boolean} concatArrays
*/
merge (base, mergeWith, concatArrays = true) {
var merged = {}
for (var key in base) {
if (extendWith.hasOwnProperty(key)) {
merged[key] = isPlainObject(extendWith[key]) && isPlainObject(base[key])
? this.extend(base[key], extendWith[key])
: extendWith[key]
if (mergeWith.hasOwnProperty(key)) {
if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) {
merged[key] = this.merge(base[key], mergeWith[key], concatArrays)
} else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) {
merged[key] = base[key].concat(mergeWith[key])
} else {
merged[key] = mergeWith[key]
}
} else {
merged[key] = base[key]
}
}
for (var prop in extendWith) {
for (var prop in mergeWith) {
if (!merged.hasOwnProperty(prop)) {
merged[prop] = extendWith[prop]
merged[prop] = mergeWith[prop]
}
}
return merged

View File

@ -1,6 +1,6 @@
import Formulate from '../src/Formulate.js'
test('can extend simple object', () => {
test('can merge simple object', () => {
let a = {
optionA: true,
optionB: '1234'
@ -8,14 +8,27 @@ test('can extend simple object', () => {
let b = {
optionA: false
}
expect(Formulate.extend(a, b)).toEqual({
expect(Formulate.merge(a, b)).toEqual({
optionA: false,
optionB: '1234'
})
})
test('can add to simple array', () => {
let a = {
optionA: true,
optionB: ['first', 'second']
}
let b = {
optionB: ['third']
}
expect(Formulate.merge(a, b, true)).toEqual({
optionA: true,
optionB: ['first', 'second', 'third']
})
})
test('can extend recursively', () => {
test('can merge recursively', () => {
let a = {
optionA: true,
optionC: {
@ -33,7 +46,7 @@ test('can extend recursively', () => {
second: '789',
}
}
expect(Formulate.extend(a, b)).toEqual({
expect(Formulate.merge(a, b)).toEqual({
optionA: true,
optionC: {
first: '1234',
@ -69,3 +82,20 @@ test('installs on vue instance', () => {
expect(Vue.prototype.$formulate).toBe(Formulate)
expect(registry).toEqual(components)
})
test('can extend instance in a plugin', () => {
function Vue () {}
Vue.component = function (name, instance) {}
const plugin = function (i) {
i.extend({
rules: {
testRule: () => false
}
})
}
Formulate.install(Vue, {
plugins: [ plugin ]
})
expect(typeof Vue.prototype.$formulate.options.rules.testRule).toBe('function')
})

View File

@ -0,0 +1,109 @@
// Formulate inputs
// -----------------------------------------------------------------------------
.formulate-input {
// global wrapper styles
.formulate-input-label {
// global label styles
}
.formulate-input-element {
// Global field-level wrapper styles
}
.formulate-input-help {
// Global help text styles
}
.formulate-input-errors {
// Global error message list wrapper
}
.formulate-input-error,
.formulate-file-upload-error {
// Error message styles
}
.formulate-input-group-item {
// Group of items (like list of checkboxes) wrapper
}
// Text inputs
// -----------------------------------------------------------------------------
&[data-classification='text'] {
input {
// Style all text-like input elements
}
}
// Slider inputs
// -----------------------------------------------------------------------------
&[data-classification='slider'] {
input {
// Style range inputs
}
}
// Textarea inputs
// -----------------------------------------------------------------------------
&[data-classification='textarea'] {
textarea {
// Style textareas
}
}
// Button inputs
// -----------------------------------------------------------------------------
&[data-classification='button'] {
button {
// Style button inputs
}
}
// Select lists
// -----------------------------------------------------------------------------
&[data-classification='select'] {
select {
// Style select lists
}
}
// Box inputs
// -----------------------------------------------------------------------------
&[data-classification='box'] {
.formulate-input-element {
// Box input (checkbox and radio) wrapper (might want flex here)
input {
// Style box element itself
}
}
}
// File inputs
// -----------------------------------------------------------------------------
&[data-classification="file"] {
.formulate-input-upload-area {
input {
// The actual upload element
}
}
}
// Image uploads
// -----------------------------------------------------------------------------
[data-type="image"] {
// image uploads
}
}