first commit

This commit is contained in:
2024-07-15 11:28:08 +02:00
commit f52d538ea5
21891 changed files with 6161164 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,254 @@
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const Checkbox = {
name: 'cx-vui-checkbox',
template: '#cx-vui-checkbox',
mixins: [ checkConditions ],
props: {
returnType: {
validator ( value ) {
return oneOf( value, [ 'array', 'object', 'single' ] );
},
default: 'object'
},
value: {
default: ''
},
disabled: {
type: Boolean,
default: false
},
name: {
type: String
},
optionsList: {
type: Array,
default() {
return [];
}
},
returnTrue: {
type: [ Boolean, String, Number ],
default: true,
},
returnFalse: {
type: [ Boolean, String, Number ],
default: false,
},
elementId: {
type: String
},
conditions: {
type: Array,
default() {
return [];
}
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
currentValues: this.value,
currentId: this.elementId,
optionInFocus: null,
};
},
watch: {
value( val ) {
this.setCurrentValues( val );
},
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
},
computed: {
inputType() {
if ( 'array' === this.returnType ) {
return 'checkbox';
} else {
return 'hidden';
}
},
},
methods: {
inputValue( optionValue ) {
if ( 'checkbox' === this.inputType ) {
return this.returnTrue;
} else {
if ( this.isChecked( optionValue ) ) {
return this.returnTrue;
} else {
return this.returnFalse;
}
}
},
isChecked( optionValue ) {
if ( ! this.currentValues ) {
return false;
}
switch ( this.returnType ) {
case 'single':
return optionValue === this.currentValues;
case 'array':
return oneOf( optionValue, this.currentValues );
case 'object':
if ( ! this.currentValues[ optionValue ] ) {
return false;
} else {
if ( this.currentValues[ optionValue ] === this.returnTrue ) {
return true;
} else {
return false;
}
}
break;
};
},
handleEnter( event ) {
this.$emit( 'on-enter', event );
},
handleClick( event ) {
this.$emit( 'on-click', event );
},
handleFocus( event, value ) {
if ( this.disabled ) {
return;
}
this.optionInFocus = value;
this.$emit( 'on-focus', event, value );
},
handleBlur ( event, value ) {
if ( this.disabled ) {
return;
}
if ( value === this.optionInFocus ) {
this.optionInFocus = null;
}
this.$emit( 'on-blur', event, value );
},
handleParentFocus() {
if ( this.disabled ) {
return;
}
if ( null === this.optionInFocus && this.optionsList.length ) {
this.optionInFocus = this.optionsList[0].value;
}
},
handleInput ( event, value ) {
if ( this.disabled ) {
return;
}
this.updateValueState( value );
this.$emit( 'input', this.currentValues );
this.$emit( 'on-change', event );
},
isOptionInFocus( value ) {
return value === this.optionInFocus;
},
updateValueState( value ) {
switch ( this.returnType ) {
case 'single':
if ( value !== this.currentValues ) {
this.currentValues = value;
}
break;
case 'array':
if ( ! oneOf( value, this.currentValues ) ) {
this.currentValues.push( value );
} else {
this.currentValues.splice( this.currentValues.indexOf( value ), 1 );
}
break;
case 'object':
if ( ! this.currentValues[ value ] ) {
this.$set( this.currentValues, value, this.returnTrue );
} else {
if ( this.currentValues[ value ] === this.returnTrue ) {
this.$set( this.currentValues, value, this.returnFalse );
} else {
this.$set( this.currentValues, value, this.returnTrue );
}
}
break;
}
},
setCurrentValues( value ) {
switch ( this.returnType ) {
case 'single':
if ( value !== this.currentValues ) {
this.currentValues = value;
}
break;
case 'array':
case 'object':
this.currentValues = value;
break;
};
},
},
};
export default Checkbox;

View File

@@ -0,0 +1,433 @@
import { oneOf, arraysEqual } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
import { directive as clickOutside } from 'v-click-outside-x';
const FilterableSelect = {
name: 'cx-vui-f-select',
template: '#cx-vui-f-select',
mixins: [ checkConditions ],
directives: { clickOutside },
props: {
value: {
type: [String, Number, Array],
default: ''
},
placeholder: {
type: String,
default: ''
},
optionsList: {
type: Array,
default: function() {
return [];
}
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
name: {
type: String
},
error: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
elementId: {
type: String
},
autocomplete: {
validator (value) {
return oneOf( value, ['on', 'off'] );
},
default: 'off'
},
conditions: {
type: Array,
default: function() {
return [];
}
},
remote: {
type: Boolean,
default: false
},
remoteCallback: {
type: Function
},
remoteTrigger: {
type: Number,
default: 3
},
remoteTriggerMessage: {
type: String,
default: 'Please enter %d char(s) to start search'
},
notFoundMeassge: {
type: String,
default: 'There is no items find matching this query'
},
loadingMessage: {
type: String,
default: 'Loading...'
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
options: this.optionsList,
currentValues: this.value,
currentId: this.elementId,
selectedOptions: [],
query: '',
inFocus: false,
optionInFocus: false,
loading: false,
loaded: false,
};
},
watch: {
value( newValue, oldValue ) {
if ( this.multiple ) {
if ( arraysEqual( newValue, oldValue ) ) {
return;
}
} else {
if ( newValue === oldValue ) {
return;
}
}
this.storeValues( newValue );
},
optionsList( options ) {
this.setOptions( options );
},
},
created() {
if ( ! this.currentValues ) {
this.currentValues = [];
} else if ( 'object' !== typeof this.currentValues ) {
if ( '[object Array]' === Object.prototype.toString.call( this.currentValues ) ) {
} else {
this.currentValues = [ this.currentValues ];
}
}
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
if ( this.remote && this.remoteCallback && this.currentValues.length ) {
this.remoteUpdateSelected();
} else if ( this.currentValues.length ) {
this.options.forEach( option => {
if ( oneOf( option.value, this.currentValues ) ) {
this.selectedOptions.push( option );
}
} );
}
},
computed: {
filteredOptions() {
if ( ! this.query ) {
return this.options;
} else {
return this.options.filter( option => {
if ( this.remote ) {
return true;
} else {
return option.label.includes( this.query ) || option.value.includes( this.query );
}
});
}
},
parsedRemoteTriggerMessage() {
return this.remoteTriggerMessage.replace( /\%d/g, this.charsDiff );
},
charsDiff() {
let queryLength = 0;
if ( this.query ) {
queryLength = this.query.length
}
return this.remoteTrigger - queryLength;
},
},
methods: {
remoteUpdateSelected() {
this.loading = true;
const promise = this.remoteCallback( this.query, this.currentValues );
if ( promise && promise.then ) {
promise.then( options => {
if ( options ) {
this.selectedOptions = options;
this.loaded = true;
this.loading = false;
}
} );
}
},
setValues( values ) {
values = values || [];
this.selectedOptions = [];
this.currentValues = [];
this.storeValues( values );
},
handleFocus( event ) {
this.inFocus = true;
this.$emit( 'on-focus', event );
},
handleOptionsNav( event ) {
// next
if ( 'ArrowUp' === event.key || 'Tab' === event.key ) {
this.navigateOptions( -1 );
}
// prev
if ( 'ArrowDown' === event.key ) {
this.navigateOptions( 1 );
}
},
navigateOptions( direction ) {
if ( false === this.optionInFocus ) {
this.optionInFocus = -1;
}
let index = this.optionInFocus + direction;
let maxLength = this.options.length - 1;
if ( maxLength < 0 ) {
maxLength = 0;
}
if ( index < 0 ) {
index = 0;
} else if ( index > maxLength ) {
index = maxLength;
}
this.optionInFocus = index;
},
onClickOutside( event ) {
if ( this.inFocus ) {
this.inFocus = false;
this.$emit( 'on-blur', event );
}
},
handleInput( event ) {
let value = event.target.value;
this.query = value;
this.$emit( 'input', this.currentValues );
this.$emit( 'on-change', event );
if ( ! this.inFocus ) {
this.inFocus = true;
}
if ( this.remote && this.remoteCallback && this.charsDiff <= 0 && ! this.loading && ! this.loaded ) {
this.loading = true;
const promise = this.remoteCallback( this.query, [] );
if ( promise && promise.then ) {
promise.then( options => {
if ( options ) {
this.options = options;
this.loaded = true;
this.loading = false;
}
} );
}
} else if ( this.remote && this.remoteCallback && this.loaded && this.charsDiff > 0 ) {
this.resetRemoteOptions();
}
},
handleEnter() {
if ( false === this.optionInFocus || ! this.options[ this.optionInFocus ] ) {
return;
}
let value = this.options[ this.optionInFocus ].value;
this.handleResultClick( value );
},
handleResultClick( value ) {
if ( oneOf( value, this.currentValues ) ) {
this.removeValue( value );
} else {
this.storeValues( value );
}
this.$emit( 'input', this.currentValues );
this.$emit( 'on-change', this.currentValues );
this.inFocus = false;
this.optionInFocus = false;
this.query = '';
if ( this.remote && this.remoteCallback && this.loaded ) {
this.resetRemoteOptions();
}
},
resetRemoteOptions() {
this.options = [];
this.loaded = false;
},
removeValue( value ) {
this.currentValues.splice( this.currentValues.indexOf( value ), 1 );
this.removeFromSelected( value );
},
removeFromSelected( value ) {
this.selectedOptions.forEach( ( option, index ) => {
if ( option.value === value ) {
this.selectedOptions.splice( index, 1 );
}
} );
},
pushToSelected( value, single ) {
this.options.forEach( option => {
if ( option.value === value ) {
if ( ! single ) {
this.selectedOptions.push( option );
} else {
this.selectedOptions = [ option ];
}
}
} );
},
storeValues( value ) {
if ( oneOf( value, this.currentValues ) ) {
return;
}
if ( this.multiple ) {
if ( 'object' === typeof value ) {
if ( '[object Array]' === Object.prototype.toString.call( value ) ) {
value.forEach( singleVal => {
if ( ! oneOf( singleVal, this.currentValues ) ) {
this.currentValues.push( singleVal );
this.pushToSelected( singleVal );
}
} );
} else {
this.currentValues.push( value );
this.pushToSelected( value );
}
} else {
this.currentValues.push( value );
this.pushToSelected( value );
}
} else {
if ( 'object' === typeof value ) {
if ( '[object Array]' === Object.prototype.toString.call( value ) ) {
this.currentValues = value;
value.forEach( singleVal => {
this.pushToSelected( singleVal, true );
} );
} else {
this.currentValues = [ value ];
this.pushToSelected( value, true );
}
} else {
this.currentValues = [ value ];
this.pushToSelected( value, true );
}
}
},
setOptions( options ) {
this.options = options;
},
isOptionSelected( option ) {
if ( ! this.currentValues ) {
return false;
}
return oneOf( option.value, this.currentValues );
},
},
};
export default FilterableSelect;

View File

@@ -0,0 +1,193 @@
import { directive as clickOutside } from 'v-click-outside-x';
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const Iconpicker = {
name: 'cx-vui-iconpicker',
template: '#cx-vui-iconpicker',
mixins: [ checkConditions ],
directives: { clickOutside },
props: {
value: {
type: [String],
default: ''
},
size: {
validator (value) {
return oneOf( value, [ 'small', 'large', 'default', 'fullwidth' ] );
},
default: 'default'
},
placeholder: {
type: String,
default: ''
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
name: {
type: String
},
autofocus: {
type: Boolean,
default: false
},
elementId: {
type: String
},
autocomplete: {
validator (value) {
return oneOf(value, ['on', 'off']);
},
default: 'off'
},
conditions: {
type: Array,
default: function() {
return [];
}
},
iconBase: {
type: String,
default: '',
},
iconPrefix: {
type: String,
default: '',
},
icons: {
type: Array,
default: function() {
return [];
}
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
currentValue: this.value,
currentId: this.elementId,
filterQuery: '',
panelActive: false,
prefixedIcons: [],
};
},
watch: {
value( val ) {
this.setCurrentValue( val );
},
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
this.icons.forEach( icon => {
this.prefixedIcons.push( this.iconPrefix + icon )
} );
},
computed: {
filteredIcons() {
if ( ! this.filterQuery ) {
return this.prefixedIcons;
} else {
return this.prefixedIcons.filter( icon => {
return icon.includes( this.filterQuery );
});
}
},
},
methods: {
handleEnter( event ) {
this.$emit( 'on-enter', event );
},
handleKeydown( event ) {
this.$emit( 'on-keydown', event );
},
handleKeypress( event ) {
this.$emit( 'on-keypress', event );
},
handleKeyup( event ) {
this.$emit( 'on-keyup', event );
},
handleFocus( event ) {
this.panelActive = true;
this.$emit( 'on-focus', event );
},
handleBlur( event ) {
this.$emit( 'on-blur', event );
},
seclectIcon( icon ) {
this.$emit( 'input', icon );
this.setCurrentValue( icon );
this.$emit( 'on-change', icon );
this.closePanel();
},
handleInput( event ) {
let value = event.target.value;
this.filterQuery = value;
this.$emit( 'input', value );
this.setCurrentValue( value );
this.$emit( 'on-change', event );
},
handleChange ( event ) {
this.$emit( 'on-input-change', event );
},
setCurrentValue ( value ) {
if ( value === this.currentValue ) {
return;
}
this.currentValue = value;
},
onClickOutside( event ) {
this.closePanel();
},
closePanel() {
if ( this.panelActive ) {
this.panelActive = false;
this.filterQuery = '';
this.$emit( 'on-panel-closed' );
}
}
},
};
export default Iconpicker;

View File

@@ -0,0 +1,154 @@
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const Input = {
name: 'cx-vui-input',
template: '#cx-vui-input',
mixins: [ checkConditions ],
props: {
type: {
validator ( value ) {
return oneOf(value, ['text', 'textarea', 'password', 'url', 'email', 'date', 'number', 'tel']);
},
default: 'text'
},
value: {
type: [String, Number],
default: ''
},
size: {
validator (value) {
return oneOf( value, [ 'small', 'large', 'default', 'fullwidth' ] );
},
default: 'default'
},
placeholder: {
type: String,
default: ''
},
maxlength: {
type: Number
},
disabled: {
type: Boolean,
default: false
},
error: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
name: {
type: String
},
autofocus: {
type: Boolean,
default: false
},
autocomplete: {
validator (value) {
return oneOf(value, ['on', 'off']);
},
default: 'off'
},
elementId: {
type: String
},
conditions: {
type: Array,
default: function() {
return [];
}
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
currentValue: this.value,
currentId: this.elementId,
};
},
watch: {
value( val ) {
this.setCurrentValue( val );
},
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
},
computed: {
controlClasses() {
var classesList = [ 'cx-vui-input' ]
classesList.push( 'size-' + this.size );
if ( this.error ) {
classesList.push( 'has-error' );
}
return classesList;
},
},
methods: {
handleEnter( event ) {
this.$emit( 'on-enter', event );
},
handleKeydown( event ) {
this.$emit( 'on-keydown', event );
},
handleKeypress( event ) {
this.$emit( 'on-keypress', event );
},
handleKeyup ( event ) {
this.$emit( 'on-keyup', event );
},
handleFocus ( event ) {
this.$emit( 'on-focus', event );
},
handleBlur ( event ) {
this.$emit( 'on-blur', event );
},
handleInput ( event ) {
let value = event.target.value;
this.$emit( 'input', value );
this.setCurrentValue( value );
this.$emit( 'on-change', event );
},
handleChange ( event ) {
this.$emit( 'on-input-change', event );
},
setCurrentValue ( value ) {
if ( value === this.currentValue ) {
return;
}
this.currentValue = value;
},
},
};
export default Input;

View File

@@ -0,0 +1,124 @@
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const Radio = {
name: 'cx-vui-radio',
template: '#cx-vui-radio',
mixins: [ checkConditions ],
props: {
value: {
default: ''
},
disabled: {
type: Boolean,
default: false
},
name: {
type: String
},
optionsList: {
type: Array,
default() {
return [];
}
},
elementId: {
type: String
},
conditions: {
type: Array,
default() {
return [];
}
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
currentValue: this.value,
currentId: this.elementId,
optionInFocus: null,
};
},
watch: {
value( val ) {
this.setCurrentValue( val );
},
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
},
methods: {
handleEnter( event ) {
this.$emit( 'on-enter', event );
},
handleClick( event ) {
this.$emit( 'on-click', event );
},
handleFocus( event, value ) {
if ( this.disabled ) {
return;
}
this.optionInFocus = value;
this.$emit( 'on-focus', event, value );
},
handleBlur ( event, value ) {
if ( this.disabled ) {
return;
}
if ( value === this.optionInFocus ) {
this.optionInFocus = null;
}
this.$emit( 'on-blur', event, value );
},
handleInput ( event, value ) {
if ( this.disabled ) {
return;
}
this.setCurrentValue( value );
this.$emit( 'input', this.currentValue );
this.$emit( 'on-change', event );
},
isOptionInFocus( value ) {
return value === this.optionInFocus;
},
setCurrentValue( value ) {
if ( value !== this.currentValue ) {
this.currentValue = value;
}
},
},
};
export default Radio;

View File

@@ -0,0 +1,195 @@
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const SelectPlain = {
name: 'cx-vui-select',
template: '#cx-vui-select',
mixins: [ checkConditions ],
props: {
value: {
type: [String, Number, Array],
default: ''
},
size: {
validator (value) {
return oneOf( value, [ 'small', 'large', 'default', 'fullwidth' ] );
},
default: 'default'
},
placeholder: {
type: String,
default: ''
},
optionsList: {
type: Array,
default: function() {
return [];
}
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
name: {
type: String
},
multiple: {
type: Boolean,
default: false
},
elementId: {
type: String
},
conditions: {
type: Array,
default: function() {
return [];
}
},
remote: {
type: Boolean,
default: false
},
remoteCallback: {
type: Function
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
options: this.optionsList,
currentValue: this.value,
currentId: this.elementId,
};
},
watch: {
value( val ) {
this.storeCurrentValue( val );
},
optionsList( options ) {
this.setOptions( options );
},
},
created() {
if ( this.multiple ) {
if ( this.currentValue && 'object' !== typeof this.currentValue ) {
this.currentValue = [ this.currentValue ];
}
} else {
if ( this.currentValue && 'object' === typeof this.currentValue ) {
this.currentValue = this.currentValue[0];
}
}
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
if ( this.remote && this.remoteCallback ) {
const promise = this.remoteCallback();
if ( promise && promise.then ) {
promise.then( options => {
if ( options ) {
this.options = options;
}
} );
}
}
},
methods: {
controlClasses() {
var classesList = [ 'cx-vui-select' ]
classesList.push( 'size-' + this.size );
return classesList;
},
handleFocus ( event ) {
this.$emit( 'on-focus', event );
},
handleBlur ( event ) {
this.$emit( 'on-blur', event );
},
handleInput() {
this.$emit( 'input', this.currentValue );
this.$emit( 'on-change', event );
},
storeCurrentValue( value ) {
if ( this.multiple ) {
if ( oneOf( value, this.currentValue ) ) {
return;
}
if ( 'object' === typeof value ) {
if ( '[object Array]' === Object.prototype.toString.call( value ) ) {
this.currentValues.concat( value );
} else {
this.currentValues.push( value );
}
} else {
this.currentValue.push( value );
}
} else {
if ( value === this.currentValue ) {
return;
}
this.currentValue = value;
}
},
setOptions( options ) {
this.options = options;
},
isOptionSelected( option ) {
if ( ! this.currentValue ) {
return false;
}
if ( this.multiple ) {
return oneOf( option.value, this.currentValue );
} else {
return option.value === this.currentValue;
}
},
},
};
export default SelectPlain;

View File

@@ -0,0 +1,134 @@
import { checkConditions } from '../../mixins/check-conditions';
const Switcher = {
name: 'cx-vui-switcher',
template: '#cx-vui-switcher',
mixins: [ checkConditions ],
props: {
value: {
type: [String, Number, Boolean],
default: ''
},
disabled: {
type: Boolean,
default: false
},
name: {
type: String
},
elementId: {
type: String
},
conditions: {
type: Array,
default: function() {
return [];
}
},
returnTrue: {
type: [String, Number, Boolean],
default: true,
},
returnFalse: {
type: [String, Number, Boolean],
default: '',
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
currentValue: this.value,
currentId: this.elementId,
isOn: false,
inFocus: false,
};
},
watch: {
value( val ) {
this.setCurrentValue( val );
if ( val === this.returnTrue ) {
this.isOn = true;
} else {
this.isOn = false;
}
},
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
if ( this.value === this.returnTrue ) {
this.isOn = true;
}
},
methods: {
handleEnter( event ) {
this.$emit( 'on-enter', event );
this.switchState();
this.inFocus = true;
},
handleFocus ( event ) {
this.inFocus = true;
this.$emit( 'on-focus', event );
},
handleBlur ( event ) {
this.inFocus = false;
this.$emit( 'on-blur', event );
},
switchState () {
let value;
this.isOn = ! this.isOn;
if ( this.isOn ) {
value = this.returnTrue;
} else {
value = this.returnFalse;
}
this.$emit( 'input', value );
this.setCurrentValue( value );
this.$emit( 'on-change', event );
this.inFocus = false;
},
handleChange ( event ) {
this.$emit( 'on-input-change', event );
},
setCurrentValue ( value ) {
if ( value === this.currentValue ) {
return;
}
this.currentValue = value;
},
},
};
export default Switcher;

View File

@@ -0,0 +1,138 @@
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const Input = {
name: 'cx-vui-textarea',
template: '#cx-vui-textarea',
mixins: [ checkConditions ],
props: {
value: {
type: [String, Number],
default: ''
},
size: {
validator (value) {
return oneOf( value, [ 'small', 'large', 'default', 'fullwidth' ] );
},
default: 'default'
},
placeholder: {
type: String,
default: ''
},
rows: {
type: Number
},
disabled: {
type: Boolean,
default: false
},
error: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
name: {
type: String
},
elementId: {
type: String
},
conditions: {
type: Array,
default: function() {
return [];
}
},
// Wrapper related props (should be passed into wrapper component)
preventWrap: {
type: Boolean,
default: false
},
label: {
type: String
},
description: {
type: String
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
},
data() {
return {
currentValue: this.value,
currentId: this.elementId,
};
},
watch: {
value( val ) {
this.setCurrentValue( val );
},
},
mounted() {
if ( ! this.currentId && this.name ) {
this.currentId = 'cx_' + this.name;
}
},
computed: {
controlClasses() {
var classesList = [ 'cx-vui-textarea' ]
classesList.push( 'size-' + this.size );
if ( this.error ) {
classesList.push( 'has-error' );
}
return classesList;
},
},
methods: {
handleEnter( event ) {
this.$emit( 'on-enter', event );
},
handleKeydown( event ) {
this.$emit( 'on-keydown', event );
},
handleKeypress( event ) {
this.$emit( 'on-keypress', event );
},
handleKeyup ( event ) {
this.$emit( 'on-keyup', event );
},
handleFocus ( event ) {
this.$emit( 'on-focus', event );
},
handleBlur ( event ) {
this.$emit( 'on-blur', event );
},
handleInput ( event ) {
let value = event.target.value;
this.$emit( 'input', value );
this.setCurrentValue( value );
this.$emit( 'on-change', event );
},
handleChange ( event ) {
this.$emit( 'on-input-change', event );
},
setCurrentValue ( value ) {
if ( value === this.currentValue ) {
return;
}
this.currentValue = value;
},
},
};
export default Input;

View File

@@ -0,0 +1,121 @@
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const Button = {
name: 'cx-vui-button',
template: '#cx-vui-button',
mixins: [ checkConditions ],
props: {
type: {
validator ( value ) {
return oneOf( value, [ 'button', 'submit', 'reset' ] );
},
default: 'button'
},
buttonStyle: {
validator ( value ) {
return oneOf( value, [ 'default', 'accent', 'link-accent', 'link-error' ] );
},
default: 'default'
},
size: {
validator ( value ) {
return oneOf( value, [ 'default', 'mini', 'link' ] );
},
default: 'default'
},
disabled: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
customCss: {
type: String,
},
url: {
type: String,
},
target: {
type: String,
},
tagName: {
validator( value ) {
return oneOf( value, [ 'a', 'button' ] );
},
default: 'button'
},
elementId: {
type: String
},
conditions: {
type: Array,
default() {
return [];
}
},
},
data() {
return {
baseClass: 'cx-vui-button',
};
},
computed: {
classesList() {
let classesList = [
this.baseClass,
this.baseClass + '--style-' + this.buttonStyle,
this.baseClass + '--size-' + this.size,
];
if ( this.loading ) {
classesList.push( this.baseClass + '--loading' );
}
if ( this.disabled ) {
classesList.push( this.baseClass + '--disabled' );
}
if ( this.customCss ) {
classesList.push( this.customCss );
}
return classesList;
},
tagAtts() {
let atts = {};
if ( 'a' === this.tagName ) {
if ( this.url ) {
atts.href = this.url;
}
if ( this.target ) {
atts.target = this.target;
}
} else {
atts.type = this.type;
}
return atts;
}
},
methods: {
handleClick() {
if ( this.loading || this.disabled ) {
return;
}
this.$emit( 'click', event );
}
},
};
export default Button;

View File

@@ -0,0 +1,53 @@
import { checkConditions } from '../../mixins/check-conditions';
const Collapse = {
name: 'cx-vui-collapse',
template: '#cx-vui-collapse',
mixins: [ checkConditions ],
props: {
collapsed: {
type: Boolean,
default: false
},
conditions: {
type: Array,
default() {
return [];
}
},
},
data() {
return {
state: '',
};
},
mounted() {
if ( this.collapsed ) {
this.state = 'collapsed';
}
},
computed: {
iconArrow() {
if ( 'collapsed' === this.state ) {
return 'dashicons-arrow-right-alt2';
} else {
return 'dashicons-arrow-down-alt2';
}
},
},
methods: {
switchState() {
if ( 'collapsed' === this.state ) {
this.state = '';
} else {
this.state = 'collapsed';
}
this.$emit( 'state-switched', this.state );
},
},
};
export default Collapse;

View File

@@ -0,0 +1,52 @@
import { wrapperClasses } from '../../mixins/wrapper-classes';
import { checkConditions } from '../../mixins/check-conditions';
const ComponentWrapper = {
name: 'cx-vui-component-wrapper',
template: '#cx-vui-component-wrapper',
mixins: [ wrapperClasses, checkConditions ],
props: {
elementId: {
type: String
},
label: {
type: String
},
description: {
type: String
},
preventWrap: {
type: Boolean,
default: false
},
wrapperCss: {
type: Array,
default: function() {
return [];
}
},
conditions: {
type: Array,
default() {
return [];
}
},
},
computed: {
wrapperClassesRaw() {
let classesList = [ 'cx-vui-component-raw' ];
if ( this.wrapperCss ) {
this.wrapperCss.forEach( className => {
classesList.push( className );
} );
}
return classesList;
}
}
};
export default ComponentWrapper;

View File

@@ -0,0 +1,18 @@
const ListTableHeading = {
name: 'cx-vui-list-table-heading',
template: '#cx-vui-list-table-heading',
props: {
slots: {
type: Array,
default() {
return [];
}
},
className: {
type: String,
default: '',
},
},
};
export default ListTableHeading;

View File

@@ -0,0 +1,27 @@
import { checkConditions } from '../../mixins/check-conditions';
const ListTableItem = {
name: 'cx-vui-list-table-item',
template: '#cx-vui-list-table-item',
mixins: [ checkConditions ],
props: {
slots: {
type: Array,
default() {
return [];
}
},
conditions: {
type: Array,
default() {
return [];
}
},
className: {
type: String,
default: '',
},
},
};
export default ListTableItem;

View File

@@ -0,0 +1,25 @@
import { checkConditions } from '../../mixins/check-conditions';
const ListTable = {
name: 'cx-vui-list-table',
template: '#cx-vui-list-table',
mixins: [ checkConditions ],
props: {
conditions: {
type: Array,
default() {
return [];
}
},
isEmpty: {
type: Boolean,
default: false,
},
emptyMessage: {
type: String,
default: '',
},
},
};
export default ListTable;

View File

@@ -0,0 +1,72 @@
const NoticeComponent = {
name: 'cx-vui-notice',
template: '#cx-vui-notice',
data: function() {
return {
stack: {},
destroyQueue: {},
}
},
methods: {
addToStack: function( item, itemID ) {
var self = this;
var destroyTimeout = setTimeout( function() {
self.destroyItem( itemID );
}, item.duration );
self.$set( self.stack, itemID, item );
self.$set( self.destroyQueue, itemID, destroyTimeout );
},
destroyItem: function( itemID ) {
this.$delete( this.stack, itemID );
if ( this.destroyQueue[ itemID ] ) {
clearTimeout( this.destroyQueue[ itemID ] );
this.$delete( this.destroyQueue, itemID );
}
},
destroyAll: function() {
for ( var itemID in this.destroyQueue ) {
console.log( this.destroyQueue[ itemID ] );
clearTimeout( this.destroyQueue[ itemID ] );
}
this.stack = {};
this.destroyQueue = {};
},
getIcon: function( type ) {
var icon;
switch ( type ) {
case 'success':
icon = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6.38498 12.0188L13.5962 4.80751L12.4695 3.64319L6.38498 9.7277L3.53052 6.87324L2.40376 8L6.38498 12.0188ZM2.32864 2.3662C3.9061 0.788732 5.79656 0 8 0C10.2034 0 12.0814 0.788732 13.6338 2.3662C15.2113 3.91862 16 5.79656 16 8C16 10.2034 15.2113 12.0939 13.6338 13.6714C12.0814 15.2238 10.2034 16 8 16C5.79656 16 3.9061 15.2238 2.32864 13.6714C0.776213 12.0939 0 10.2034 0 8C0 5.79656 0.776213 3.91862 2.32864 2.3662Z"/></svg>';
break;
case 'error':
icon = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.71489 10.1136V6.71605H7.28511V10.1136H8.71489ZM8.71489 13.4716V11.7728H7.28511V13.4716H8.71489ZM0 16L8 0L16 16H0Z"/></svg>';
break;
default:
icon = '<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.78873 5.59624V3.98122H7.21127V5.59624H8.78873ZM8.78873 12.0188V7.21127H7.21127V12.0188H8.78873ZM2.32864 2.3662C3.9061 0.788732 5.79656 0 8 0C10.2034 0 12.0814 0.788732 13.6338 2.3662C15.2113 3.91862 16 5.79656 16 8C16 10.2034 15.2113 12.0939 13.6338 13.6714C12.0814 15.2238 10.2034 16 8 16C5.79656 16 3.9061 15.2238 2.32864 13.6714C0.776213 12.0939 0 10.2034 0 8C0 5.79656 0.776213 3.91862 2.32864 2.3662Z"/></svg>';
break;
}
return icon;
}
},
};
export default NoticeComponent;

View File

@@ -0,0 +1,51 @@
import NoticeComponent from './notice-component';
const CXNotice = {
instance: null,
stack: {},
newInstance: function() {
var NoticeComponentClass = Vue.extend( NoticeComponent );
this.instance = new NoticeComponentClass({
propsData: { type: 'primary' }
});
this.instance.$mount();
document.body.appendChild( this.instance.$el );
},
getRandId: function() {
// Generates random string with 10 characters length
return Math.random().toString( 36 ).substring( 2, 7 ) + Math.random().toString( 36 ).substring( 2, 7 );
},
add: function( options, id ) {
id = id || this.getRandId();
if ( ! this.instance ) {
this.newInstance();
}
options.duration = options.duration || 4500;
options.type = options.type || 'info';
this.instance.addToStack( options, id );
},
close: function( id ) {
if ( id ) {
id = id.toString();
if ( this.instance ) {
this.instance.destroyItem( id );
}
} else {
return false;
}
},
closeAll: function() {
this.instance.destroyAll();
},
};
export default CXNotice;

View File

@@ -0,0 +1,183 @@
import { oneOf } from '../../utils/assist';
import { checkConditions } from '../../mixins/check-conditions';
const Pagination = {
name: 'cx-vui-pagination',
template: '#cx-vui-pagination',
mixins: [ checkConditions ],
props: {
current: {
type: Number,
default: 1
},
total: {
type: Number,
default: 0
},
pageSize: {
type: Number,
default: 10
},
prevText: {
type: String,
default: ''
},
nextText: {
type: String,
default: ''
},
customCss: {
type: String,
default: ''
},
elementId: {
type: String,
default: ''
},
conditions: {
type: Array,
default() {
return [];
}
},
},
data() {
return {
baseClass: 'cx-vui-pagination',
currentPage: this.current,
currentPageSize: this.pageSize
};
},
watch: {
total ( val ) {
let maxPage = Math.ceil( val / this.currentPageSize );
if ( maxPage < this.currentPage ) {
this.currentPage = ( maxPage === 0 ? 1 : maxPage );
}
},
current ( val ) {
this.currentPage = val;
},
pageSize ( val ) {
this.currentPageSize = val;
}
},
computed: {
classesList() {
let classesList = [
this.baseClass,
];
if ( this.customCss ) {
classesList.push( this.customCss );
}
return classesList;
},
prevClasses () {
return [
`${this.baseClass}-item`,
`${this.baseClass}-prev`,
{
[`${this.baseClass}-disabled`]: this.currentPage === 1 || false,
[`${this.baseClass}-custom-text`]: this.prevText !== ''
}
];
},
nextClasses () {
return [
`${this.baseClass}-item`,
`${this.baseClass}-next`,
{
[`${this.baseClass}-disabled`]: this.currentPage === this.allPages || false,
[`${this.baseClass}-custom-text`]: this.nextText !== ''
}
];
},
firstPageClasses () {
return [
`${this.baseClass}-item`,
{
[`${this.baseClass}-item-active`]: this.currentPage === 1
}
];
},
lastPageClasses () {
return [
`${this.baseClass}-item`,
{
[`${this.baseClass}-item-active`]: this.currentPage === this.allPages
}
];
},
allPages () {
const allPage = Math.ceil( this.total / this.currentPageSize );
return ( allPage === 0 ) ? 1 : allPage;
},
},
methods: {
changePage ( page ) {
if ( this.currentPage !== page ) {
this.currentPage = page;
this.$emit( 'update:current', page );
this.$emit( 'on-change', page );
}
},
prev () {
const current = this.currentPage;
if ( current <= 1 ) {
return false;
}
this.changePage( current - 1 );
},
next () {
const current = this.currentPage;
if ( current >= this.allPages ) {
return false;
}
this.changePage(current + 1);
},
fastPrev () {
const page = this.currentPage - 5;
if ( page > 0 ) {
this.changePage( page );
} else {
this.changePage( 1 );
}
},
fastNext () {
const page = this.currentPage + 5;
if ( page > this.allPages ) {
this.changePage( this.allPages );
} else {
this.changePage( page );
}
},
},
};
export default Pagination;

View File

@@ -0,0 +1,78 @@
const Popup = {
name: 'cx-vui-popup',
template: '#cx-vui-popup',
props: {
value: {
type: Boolean,
default: false,
},
overlay: {
type: Boolean,
default: true,
},
close: {
type: Boolean,
default: true,
},
showOk: {
type: Boolean,
default: true,
},
showCancel: {
type: Boolean,
default: true,
},
header: {
type: Boolean,
default: true,
},
footer: {
type: Boolean,
default: true,
},
okLabel: {
type: String,
default: 'OK',
},
cancelLabel: {
type: String,
default: 'Cancel',
},
bodyWidth: {
type: String,
default: 'auto',
},
},
data() {
return {
currentValue: this.value,
};
},
watch: {
value( val ) {
this.setCurrentValue( val );
}
},
methods: {
handleCancel() {
this.setCurrentValue( false );
this.$emit( 'input', false );
this.$emit( 'on-cancel' );
},
handleOk() {
this.setCurrentValue( false );
this.$emit( 'input', false );
this.$emit( 'on-ok' );
},
setCurrentValue( value ) {
if ( this.currentValue === value ) {
return;
}
this.currentValue = value;
},
},
};
export default Popup;

View File

@@ -0,0 +1,55 @@
import { ElementMixin, HandleDirective } from 'vue-slicksort';
const RepeaterItem = {
name: 'cx-vui-repeater-item',
template: '#cx-vui-repeater-item',
mixins: [ ElementMixin ],
directives: { handle: HandleDirective },
props: {
title: {
type: String,
},
subtitle: {
type: String,
},
collapsed: {
type: Boolean,
default: true,
},
index: {
type: Number,
},
customCss: {
type: String,
}
},
data() {
return {
fieldData: this.field,
isCollapsed: this.collapsed,
showConfirmTip: false,
};
},
computed: {
customCssClass() {
return this.customCss;
},
},
methods: {
handleCopy() {
this.$emit( 'clone-item', this.index );
},
handleDelete() {
this.showConfirmTip = true;
},
confrimDeletion() {
this.showConfirmTip = false;
this.$emit( 'delete-item', this.index );
},
cancelDeletion() {
this.showConfirmTip = false;
},
},
};
export default RepeaterItem;

View File

@@ -0,0 +1,53 @@
import { ContainerMixin } from 'vue-slicksort';
import { checkConditions } from '../../mixins/check-conditions';
const Repeater = {
name: 'cx-vui-repeater',
template: '#cx-vui-repeater',
mixins: [ ContainerMixin, checkConditions ],
props: {
buttonLabel: {
type: String,
},
buttonStyle: {
type: String,
default: 'accent',
},
buttonSize: {
type: String,
default: 'default',
},
value: {
type: Array,
default() {
return [];
}
},
distance: {
type: Number,
default: 20,
},
useDragHandle: {
type: Boolean,
default: true,
},
conditions: {
type: Array,
default() {
return [];
}
},
},
data() {
return {
inFocus: false,
}
},
methods: {
handleClick( event ) {
this.$emit( 'add-new-item', event );
},
},
};
export default Repeater;

View File

@@ -0,0 +1,27 @@
const TabsPanel = {
name: 'cx-vui-tabs-panel',
template: '#cx-vui-tabs-panel',
props: {
tab: {
type: String,
default: ''
},
name: {
type: String,
default: ''
},
label: {
type: String,
default: ''
},
},
data() {
return {
show: false,
};
},
methods: {
},
};
export default TabsPanel;

View File

@@ -0,0 +1,94 @@
import { checkConditions } from '../../mixins/check-conditions';
import { oneOf } from '../../utils/assist';
const Tabs = {
name: 'cx-vui-tabs',
template: '#cx-vui-tabs',
mixins: [ checkConditions ],
props: {
value: {
type: [ String, Number ],
default: ''
},
name: {
type: String,
default: ''
},
invert: {
type: Boolean,
default: false,
},
inPanel: {
type: Boolean,
default: false,
},
layout: {
validator( value ) {
return oneOf( value, [ 'horizontal', 'vertical' ] );
},
default: 'horizontal',
},
conditions: {
type: Array,
default() {
return [];
}
},
},
data() {
return {
navList: [],
activeTab: this.value,
}
},
mounted() {
const tabs = this.getTabs();
this.navList = tabs;
if ( ! this.activeTab ) {
this.activeTab = tabs[0].name;
}
this.updateState();
},
methods: {
isActive( name ) {
return ( name === this.activeTab );
},
onTabClick( tab ) {
this.activeTab = tab;
this.$emit( 'input', this.activeTab );
this.updateState();
},
updateState() {
const tabs = this.getTabs();
this.navList = tabs;
tabs.forEach( tab => {
tab.show = this.activeTab === tab.name;
} );
},
getTabs() {
const allTabs = this.$children.filter( item => {
return 'cx-vui-tabs-panel' === item.$options.name;
} );
const tabs = [];
allTabs.forEach( item => {
if ( item.tab && this.name ) {
if ( item.tab === this.name ) {
tabs.push( item );
}
} else {
tabs.push( item );
}
});
return tabs;
},
},
};
export default Tabs;

View File

@@ -0,0 +1,7 @@
const Title = {
name: 'cx-vui-title',
template: '#cx-vui-title',
props: {},
};
export default Title;

View File

@@ -0,0 +1,50 @@
import Title from './components/layout/title';
import Collapse from './components/layout/collapse';
import ComponentWrapper from './components/layout/component-wrapper';
import Button from './components/layout/button';
import Repeater from './components/layout/repeater';
import RepeaterItem from './components/layout/repeater-item';
import Popup from './components/layout/popup';
import ListTable from './components/layout/list-table';
import ListTableItem from './components/layout/list-table-item';
import ListTableHeading from './components/layout/list-table-heading';
import Tabs from './components/layout/tabs';
import TabsPanel from './components/layout/tabs-panel';
import Pagination from './components/layout/pagination';
import CXNotice from './components/layout/notice';
import Input from './components/form/input';
import Textarea from './components/form/textarea';
import Switcher from './components/form/switcher';
import Iconpicker from './components/form/iconpicker';
import SelectPlain from './components/form/select';
import FilterableSelect from './components/form/f-select';
import Checkbox from './components/form/checkbox';
import Radio from './components/form/radio';
import './../scss/cx-vue-ui.scss';
Vue.component( Title.name, Title );
Vue.component( Collapse.name, Collapse );
Vue.component( ComponentWrapper.name, ComponentWrapper );
Vue.component( Button.name, Button );
Vue.component( Repeater.name, Repeater );
Vue.component( RepeaterItem.name, RepeaterItem );
Vue.component( Popup.name, Popup );
Vue.component( ListTable.name, ListTable );
Vue.component( ListTableItem.name, ListTableItem );
Vue.component( ListTableHeading.name, ListTableHeading );
Vue.component( Tabs.name, Tabs );
Vue.component( TabsPanel.name, TabsPanel );
Vue.component( Pagination.name, Pagination );
Vue.component( Input.name, Input );
Vue.component( Textarea.name, Textarea );
Vue.component( Switcher.name, Switcher );
Vue.component( Iconpicker.name, Iconpicker );
Vue.component( SelectPlain.name, SelectPlain );
Vue.component( FilterableSelect.name, FilterableSelect );
Vue.component( Checkbox.name, Checkbox );
Vue.component( Radio.name, Radio );
Vue.prototype.$CXNotice = CXNotice;

View File

@@ -0,0 +1,91 @@
import { oneOf } from '../utils/assist';
export const checkConditions = {
methods: {
isVisible() {
if ( ! this.conditions.length ) {
return true
} else {
let conditionsMet = [];
let operator = 'AND';
let conditionsLength = this.conditions.length;
for ( var i = 0; i < this.conditions.length; i++) {
if ( this.conditions[ i ].operator ) {
operator = this.conditions[ i ].operator;
conditionsLength--;
continue;
}
switch ( this.conditions[ i ].compare ) {
case 'equal':
if ( this.conditions[ i ].input === this.conditions[ i ].value ) {
conditionsMet.push( this.conditions[ i ].value );
}
break;
case 'not_equal':
if ( this.conditions[ i ].input !== this.conditions[ i ].value ) {
conditionsMet.push( this.conditions[ i ].value );
}
break;
case 'in':
if ( oneOf( this.conditions[ i ].input, this.conditions[ i ].value ) ) {
conditionsMet.push( this.conditions[ i ].value );
}
break;
case 'not_in':
if ( ! oneOf( this.conditions[ i ].input, this.conditions[ i ].value ) ) {
conditionsMet.push( this.conditions[ i ].value );
}
break;
case 'contains':
if ( oneOf( this.conditions[ i ].value, this.conditions[ i ].input ) ) {
conditionsMet.push( this.conditions[ i ].value );
}
break;
case 'not_contains':
if ( ! oneOf( this.conditions[ i ].value, this.conditions[ i ].input ) ) {
conditionsMet.push( this.conditions[ i ].value );
}
break;
}
};
switch ( operator ) {
case 'AND':
return conditionsMet.length === conditionsLength;
case 'OR':
if ( conditionsMet.length ) {
return true;
} else {
return false;
}
}
}
},
}
}

View File

@@ -0,0 +1,17 @@
export const wrapperClasses = {
methods: {
wrapperClasses() {
var wrapperClassesList = [ 'cx-vui-component' ];
if ( this.wrapperCss.length ) {
this.wrapperCss.forEach( className => {
wrapperClassesList.push( 'cx-vui-component--' + className );
} );
}
return wrapperClassesList;
},
}
}

View File

@@ -0,0 +1,27 @@
export function oneOf ( value, validList ) {
for ( let i = 0; i < validList.length; i++ ) {
if ( value == validList[ i ] ) {
return true;
}
}
return false;
}
export function arraysEqual( arr1, arr2 ) {
if ( arr1.length !== arr2.length ) {
return false;
}
for ( var i = arr1.length; i--; ) {
if ( arr1[i] !== arr2[i] ) {
return false;
}
}
return true;
}

View File

@@ -0,0 +1,56 @@
.cx-vui-component {
display: flex;
padding: 20px;
font-family: $font_family;
+ .cx-vui-component {
border-top: 1px solid $color__border-in-panel;
}
&--equalwidth {
justify-content: space-between;
.cx-vui-component__meta {
max-width: 49%;
flex: 0 0 49%;
+ .cx-vui-component__control {
max-width: 49%;
flex: 0 0 49%;
}
}
}
&--vertical-fullwidth {
flex-direction: column;
padding-left: 0;
padding-right: 0;
.cx-vui-component__meta {
padding: 0 0 20px;
margin: 0 0 25px;
border-bottom: 1px solid $color__border-in-panel;
}
.cx-vui-component__label {
padding: 0 0 5px;
}
}
&--fullwidth-control {
.cx-vui-component__control {
max-width: 100%;
flex: 0 0 100%;
}
}
&__meta {
display: flex;
flex-direction: column;
align-items: flex-start;
}
&__label {
display: block;
font-size: 15px;
line-height: 20px;
color: $color__heading;
font-weight: 500;
}
&__desc {
font-size: 13px;
line-height: 17px;
color: $color__text;
padding: 0 0 4px;
}
}

View File

@@ -0,0 +1,38 @@
.cx-vui-text {
font-size: 13px;
line-height: 20px;
color: $color__text;
padding: 15px 0;
font-family: $font_family;
}
.cx-vui-hr {
display: block;
width: 100%;
height: 0;
border-top: 1px solid $color__border-off-panel;
margin: 30px 0;
}
.cx-vui-notice {
padding: 20px;
color: $color__text;
font-size: 15px;
line-height: 23px;
&--error {
background: $color__error-light;
}
&--success {
background: $color__success-light;
}
}
.cx-vui-inline-notice {
font-weight: bold;
&--error {
color: $color__error;
}
&--success {
color: $color__success;
}
}

View File

@@ -0,0 +1,13 @@
.cx-vui-panel {
background: $color__bg-panel;
box-shadow: 0px 2px 6px rgba( 35, 40, 45, 0.07 );
border-radius: 6px;
margin-bottom: 30px;
font-family: $font_family;
}
.cx-vui-inner-panel {
background: $color__bg-canvas;
border-radius: 4px;
padding: 30px;
}

View File

@@ -0,0 +1,67 @@
.cx-vui-popup {
position: fixed;
z-index: 999;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
&__overlay {
background: $color__heading;
opacity: .5;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
}
&__body {
background: $color__bg-panel;
box-shadow: 0px 2px 6px rgba( 35, 40, 45, 0.07 );
border-radius: 6px;
font-family: $font_family;
position: relative;
z-index: 2;
padding: 30px 40px 40px;
}
&__header {
padding: 0 0 10px;
}
&__content {
font-size: 13px;
line-height: 20px;
color: $color__text;
p {
font-size: 13px;
line-height: 20px;
color: $color__text;
margin: 0;
padding: 0 0 20px;
}
}
&__footer {
padding: 20px 0 0;
display: flex;
align-items: center;
.cx-vui-button + .cx-vui-button {
margin: 0 0 0 10px;
}
}
&__close {
position: absolute;
right: 12px;
top: 15px;
cursor: pointer;
path {
fill: $color__border-off-panel;
}
&:hover {
path {
fill: $color__text;
}
}
}
}

View File

@@ -0,0 +1,19 @@
.cs-vui-title,
.wrap .cs-vui-title {
font-weight: 500;
font-size: 24px;
line-height: 37px;
color: $color__heading;
padding: 0 0 20px;
margin: 0;
font-family: $font_family;
}
.cx-vui-subtitle {
font-weight: 500;
font-size: 18px;
line-height: 27px;
color: $color__heading;
padding: 0;
margin: 0;
font-family: $font_family;
}

View File

@@ -0,0 +1,25 @@
.cx-vui-tooltip {
background: $color__heading;
box-shadow: 0px 1px 4px rgba(35, 40, 45, 0.24);
border-radius: 3px;
padding: 5px 15px;
font-size: 12px;
line-height: 15px;
color: #fff;
bottom: 100%;
position: absolute;
margin: 0 0 10px;
text-align: center;
&:after {
top: 100%;
left: 50%;
margin: 0 0 0 -4px;
width: 0;
height: 0;
border-style: solid;
border-width: 4px 4px 0 4px;
border-color: $color__heading transparent transparent transparent;
content: "";
position: absolute;
}
}

View File

@@ -0,0 +1,167 @@
.cx-vui-button {
cursor: pointer;
display: inline-block;
padding: 0;
margin: 0;
border: none;
box-shadow: 0px 4px 4px rgba(35, 40, 45, 0.24);
border-radius: 4px;
transition: all 150ms linear;
font-weight: 500;
font-family: $font_family;
outline: none;
position: relative;
box-sizing: border-box;
text-decoration: none;
&__content {
display: flex;
justify-content: center;
align-items: center;
.cx-vui-button--loading & {
opacity: 0;
}
}
&--style {
&-default {
background: $color__bg-input;
color: $color__accent;
&:hover {
box-shadow: none;
color: $color__accent;
background: $color__bg-input-hover;
}
}
&-accent {
background: $color__accent;
color: #fff;
&:hover {
box-shadow: none;
color: #fff;
background: $color__accent-hover;
}
}
&-default-border {
border: 1px solid $color__border-off-panel;
background: transparent;
color: $color__text;
box-shadow: none;
&:hover {
border: 1px solid $color__border-off-panel;
color: $color__text;
background: #f3f5f6;
}
}
&-accent-border {
border: 1px solid $color__accent;
background: transparent;
color: $color__accent;
box-shadow: none;
&:hover {
border: 1px solid $color__accent-hover;
color: $color__accent-hover;
background: #f3f5f6;
}
}
&-link-accent {
color: $color__accent;
background: none;
box-shadow: none;
path {
fill: $color__accent;
}
&:hover {
color: $color__accent-hover;
path {
fill: $color__accent-hover;
}
}
}
&-link-error {
color: $color__error;
background: none;
box-shadow: none;
path {
fill: $color__error;
}
&:hover {
color: $color__error;
}
}
}
&--size {
&-default {
font-size: 15px;
line-height: 21px;
padding: 12px 25px 13px;
.cx-vui-button__content {
.dashicons {
margin: 0 5px 0 -8px;
}
span + .dashicons {
margin: -8px 0 0 5px;
}
}
}
&-link {
font-size: 15px;
line-height: 18px;
.cx-vui-button__content {
svg {
margin: 0 5px 1px 0;
}
span + svg {
margin: 0 0 1px 5px;
}
}
}
&-mini {
font-size: 13px;
line-height: 19px;
padding: 6px 14px 7px;
.cx-vui-button__content {
.dashicons {
margin: 0 4px 0 -5px;
}
span + .dashicons {
margin: -5px 0 0 4px;
}
}
}
}
&--disabled {
cursor: default;
opacity: .3;
pointer-events: none;
}
&--loading {
cursor: default;
}
&__loader {
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
.loader-icon {
animation: spin 1200ms infinite linear;
path {
fill: currentColor;
}
}
@keyframes spin {
from {
transform:rotate(0deg);
}
to {
transform:rotate(360deg);
}
}
}
&.fullwidth {
width: 100%;
}
}

View File

@@ -0,0 +1,48 @@
.cx-vui-checkbox {
display: inline-flex;
align-items: center;
margin: 0 0 10px;
&--disabled {
pointer-events: none;
}
.cx-vui-checkgroup--single-item & {
margin: 0;
}
&__check {
box-sizing: border-box;
width: 18px;
height: 18px;
border-radius: 4px;
border: 2px solid $color__text;
margin: -1px 10px 0 0;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
&--focused {
border-color: $color__accent-border;
}
&--checked {
border-color: $color__accent;
background: $color__accent;
path {
fill: #fff;
}
}
&--disabled {
pointer-events: none;
opacity: .5;
cursor: default;
}
}
&__label {
color: $color__text;
cursor: pointer;
.cx-vui-checkbox--disabled & {
cursor: default;
}
}
&__input[type="checkbox"] {
display: none;
}
}

View File

@@ -0,0 +1,21 @@
.cx-vui-collapse {
border-bottom: 1px solid $color__border-off-panel;
&:last-child {
border-bottom: none;
}
&__heading {
display: flex;
padding: 20px 0;
align-items: center;
cursor: pointer;
&-icon {
font-size: 18px;
margin: 0 5px 0 0;
}
}
&__content {
.cx-vui-collapse--collapsed & {
display: none;
}
}
}

View File

@@ -0,0 +1,93 @@
.cx-vui-f-select {
&__select-tag {
display: none;
}
&__input {
&.cx-vui-input {
&--in-focus {
box-shadow: 0 0 0 2px $color__accent-border inset;
background: #fff;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
}
&__control {
position: relative;
}
&__results {
top: 100%;
left: 0;
right: 0;
z-index: 999;
position: absolute;
border: 1px solid $color__accent-border;
box-sizing: border-box;
box-shadow: 0px 4px 20px rgba(35, 40, 45, 0.24);
border-radius: 0px 0px 4px 4px;
background: $color__bg-panel;
padding: 10px 0;
margin: -1px 0 0 0;
&-message,
&-loading {
padding: 0 10px;
color: $color__text;
}
}
&__result {
color: $color__text;
font-size: 13px;
line-height: 17px;
padding: 3px 12px 4px;
cursor: pointer;
transition: all 150ms linear;
&.is-selected {
background: $color__accent-lighter;
}
&:hover,
&.in-focus {
color: #fff;
background: $color__accent;
}
}
&__selected {
display: flex;
flex-wrap: wrap;
&-not-empty {
margin: 0 0 15px;
}
&-option {
padding: 5px 11px 5px 5px;
display: flex;
align-items: center;
background: $color__accent-lighter;
cursor: pointer;
color: $color__text;
margin: 0 5px 5px 0;
white-space: nowrap;
&-icon {
width: 22px;
height: 22px;
background: $color__bg-panel;
border-radius: 1px;
transition: all 150ms liear;
margin: 0 6px 0 0;
display: flex;
align-items: center;
justify-content: center;
path {
transition: all 150ms liear;
fill: $color__text;
}
}
&:hover {
.cx-vui-f-select__selected-option-icon {
background: $color__accent;
path {
fill: #fff;
}
}
}
}
}
}

View File

@@ -0,0 +1,100 @@
.cx-vui-iconpicker {
position: relative;
&__fieldgroup {
display: flex;
}
&__input {
flex: 1 0 auto;
}
&__preview {
width: 32px;
height: 32px;
flex: 0 0 32px;
display: flex;
align-items: center;
justify-content: center;
background: $color__bg-input;
border-radius: 4px;
margin: 0 5px 0 0;
}
&__canvas {
position: absolute;
top: 100%;
left: 0;
right: 0;
margin: 20px 0 0 0;
box-shadow: 0px 4px 20px rgba(35, 40, 45, 0.24);
border-radius: 4px;
border: 1px solid $color__accent-border;
background: $color__bg-panel;
z-index: 999;
max-width: 100%;
width: 311px;
&-content {
padding: 10px;
border-radius: 4px;
max-height: 312px;
overflow-y: scroll;
}
&:before {
position: absolute;
left: 9px;
top: -7px;
width: 0;
height: 0;
border-style: solid;
border-width: 0 7px 7px 7px;
border-color: transparent transparent $color__accent-border transparent;
content: "";
z-index: 1;
}
&:after {
position: absolute;
left: 10px;
top: -6px;
width: 0;
height: 0;
border-style: solid;
border-width: 0 6px 6px 6px;
z-index: 2;
border-color: transparent transparent $color__bg-panel transparent;
content: "";
}
&-list {
display: flex;
flex-wrap: wrap;
margin: 6px -3px;
}
&-icon {
width: 48px;
height: 48px;
margin: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid $color__border-in-panel;
transition: all 150ms linear;
i {
color: $color__text;
}
&--selected {
border-color: $color__accent-border;
background: $color__accent-lighter;
i {
color: $color__accent;
}
}
&:hover,
&:focus {
background: $color__accent;
border-color: $color__accent;
i {
color: #fff;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
input.cx-vui-input {
@include input();
}

View File

@@ -0,0 +1,56 @@
.cx-vue-list-table {
background: #fff;
box-shadow: 0px 2px 6px rgba(35, 40, 45, 0.07);
border-radius: 6px;
font-family: $font_family;
&__items {
&.is-empty {
padding: 16px 20px 17px;
text-align: center;
color: $color__text;
font-size: 13px;
line-height: 16px;
}
}
}
.list-table-heading,
.list-table-item,
.list-table-footer {
display: flex;
align-items: center;
justify-content: flex-start;
&__cell {
padding: 16px 20px 14px;
text-align: left;
box-sizing: border-box;
}
}
.list-table-heading {
border-bottom: 1px solid $color__border-in-panel;
.cx-vue-list-table__footer & {
border-bottom: none;
border-top: 1px solid $color__border-in-panel;
}
&__cell {
font-size: 15px;
line-height: 20px;
color: $color__heading;
font-weight: 500;
}
}
.list-table-item {
color: $color__text;
&:nth-child( odd ) {
background: $color__bg-canvas;
}
&__cell {
font-size: 13px;
line-height: 16px;
}
&:first-child {
border-top: none;
}
}

View File

@@ -0,0 +1,86 @@
.cx-vui-notices {
position: fixed;
right: 20px;
top: 52px;
}
.cx-vui-notice {
background: #fff;
padding: 20px;
margin: 0 0 20px;
transition: all 250ms ease;
display: flex;
align-items: flex-start;
box-shadow: 0px 2px 6px rgba(35, 40, 45, 0.07);
min-width: 250px;
max-width: 450px;
box-sizing: border-box;
background: #fff;
border-radius: 4px;
font-size: 15px;
line-height: 23px;
color: $color__text;
&__icon {
width: 24px;
height: 24px;
overflow: hidden;
flex: 0 0 24px;
margin: 0 15px 0 0;
svg {
width: 100%;
height: auto;
}
&--info {
path {
fill: $color__accent;
}
}
&--success {
path {
fill: $color__success;
}
}
&--error {
path {
fill: $color__error;
}
}
}
&__title {
font-weight: 500;
color: $color__heading;
}
&__content {
flex: 1 1 auto;
}
&__close {
width: 16px;
height: 16px;
flex: 0 0 16px;
margin: -2px 0 0 10px;
cursor: pointer;
box-sizing: border-box;
padding: 2px;
svg {
width: 12px;
height: 12px;
}
path {
fill: $color__border-off-panel;
}
&:hover {
path {
fill: $color__heading;
}
}
}
}
.cx-vui-notices-enter, .cx-vui-notices-leave-to {
opacity: 0;
transform: translateX( 30px );
}
.cx-vui-notices-leave-active {
position: absolute;
}

View File

@@ -0,0 +1,47 @@
.cx-vui-pagination {
&-items {
display: flex;
justify-content: flex-start;
align-items: center;
}
&-item {
display: flex;
justify-content: center;
align-items: center;
width: 32px;
height: 32px;
margin: 0 3px;
padding: 4px 8px;
position: relative;
text-decoration: none;
border: 1px solid #E8E8E8;
border-radius: 2px;
text-shadow: none;
font-weight: 600;
font-size: 13px;
line-height: normal;
color: #7B7E81;
background: transparent;
cursor: pointer;
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
&-active {
color: $color__accent;
border: 1px solid $color__accent;
}
}
&-disabled {
cursor: not-allowed;
opacity: .5;
}
}

View File

@@ -0,0 +1,55 @@
.cx-vui-radio {
display: inline-flex;
align-items: center;
margin: 0 0 10px;
&--disabled {
pointer-events: none;
}
.cx-vui-radiogroup--single-item & {
margin: 0;
}
&__input {
visibility: hidden;
position: absolute;
left: -999em;
}
&__mark {
box-sizing: border-box;
width: 18px;
height: 18px;
border-radius: 100%;
border: 2px solid $color__text;
margin: 0 10px 0 0;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
&:before {
content: "";
width: 10px;
height: 10px;
border-radius: 100%;
}
&--focused {
border-color: $color__accent-border;
}
&--checked {
border-color: $color__accent;
&:before {
background: $color__accent;
}
}
&--disabled {
pointer-events: none;
opacity: .5;
cursor: default;
}
}
&__label {
color: $color__text;
cursor: pointer;
.cx-vui-radio--disabled & {
cursor: default;
}
}
}

View File

@@ -0,0 +1,114 @@
.cx-vui-repeater {
&__actions {
display: flex;
align-items: center;
}
&__tip {
color: $color__text;
margin: 0 0 0 20px;
}
.cx-vui-collapse__content > & {
margin-bottom: 25px;
}
}
.cx-vui-repeater-item {
&__handle {
cursor: n-resize;
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
margin: -12px 0 -10px -16px;
svg {
line {
stroke: $color__border-off-panel;
}
}
}
&__heading {
display: flex;
border-bottom: 1px solid $color__border-in-panel;
padding: 18px 20px 16px;
align-items: center;
justify-content: space-between;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
&--is-collpased {
border-bottom: none;
}
&-start {
display: flex;
align-items: center;
cursor: pointer;
}
&-end {
display: flex;
align-items: center;
}
}
&__title,
&__subtitle {
font-size: 15px;
line-height: 17px;
}
&__title {
font-weight: 500;
color: $color__accent;
margin: 0 10px 0 0;
}
&__subtitle {
font-style: italic;
color: $color__text;
}
&__collapse {
margin: 0 8px 0 0;
&--is-collpased {
margin: 0 8px 4px 0;
transform: rotate( -90deg );
}
path {
fill: $color__accent;
}
}
&__content {
&--is-collpased {
display: none;
}
}
&__copy,
&__clean {
cursor: pointer;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 0 0 10px;
position: relative;
.cx-vui-tooltip {
width: 80px;
}
path {
transition: all 150ms linear;
fill: $color__text;
}
&:hover {
path {
fill: $color__accent;
}
}
}
&__confrim-del,
&__cancel-del {
text-decoration: underline;
}
&__confrim-del {
color: $color__error;
}
}

View File

@@ -0,0 +1,6 @@
// .wp-admin is required to rewrite default WP select styles
.wp-admin .cx-vui-select {
@include input();
height: auto;
-webkit-appearance:none;
}

View File

@@ -0,0 +1,44 @@
$color__switcher-panel-off: #ECECEC;
$color__switcher-panel-on: $color__accent-light;
$color__switcher-trigger-off: #fff;
$color__switcher-trigger-on: $color__accent;
.cx-vui-switcher {
width: 36px;
position: relative;
cursor: pointer;
padding: 3px 0;
&__panel {
width: 100%;
height: 12px;
border-radius: 6px;
background: $color__switcher-panel-off;
transition: all 150ms linear;
.cx-vui-switcher--on & {
background: $color__switcher-panel-on;
}
}
&__trigger {
width: 18px;
height: 18px;
left: 0;
top: 50%;
margin-top: -9px;
box-shadow: 0px 1px 4px rgba(35, 40, 45, 0.24);
transition: all 150ms linear;
background: $color__switcher-trigger-off;
border-radius: 100%;
position: absolute;
.cx-vui-switcher--on & {
background: $color__switcher-trigger-on;
left: calc( 100% - 18px );
}
.cx-vui-switcher--in-focus & {
box-shadow: 0px 1px 4px rgba(35, 40, 45, 0.24), 0 0 0 9px rgba(166,167,168, .2);
}
.cx-vui-switcher--on.cx-vui-switcher--in-focus & {
box-shadow: 0px 1px 4px rgba(35, 40, 45, 0.24), 0 0 0 9px rgba(0,124,186, .2);
}
}
}

View File

@@ -0,0 +1,72 @@
.cx-vui-tabs {
&.cx-vui-tabs--layout-vertical {
display: flex;
align-items: stretch;
}
&__nav {
background: $color__bg-canvas;
.cx-vui-tabs--layout-vertical & {
width: 20%;
flex: 0 0 20%;
max-width: 220px;
padding: 0 0 40px;
}
.cx-vui-tabs--layout-horizontal & {
display: flex;
padding: 0 40px;
}
.cx-vui-tabs--invert & {
background: $color__bg-panel;
}
&-item {
cursor: pointer;
padding: 14px 20px;
font-weight: 500;
font-size: 15px;
line-height: 20px;
color: $color__heading;
border: 1px solid transparent;
.cx-vui-tabs--layout-vertical & {
border-bottom: 1px solid $color__border-off-panel;
}
&:hover {
color: $color__accent;
}
.cx-vui-tabs:not(.cx-vui-tabs--in-panel) & {
border-top: none;
}
&--active {
color: $color__accent;
position: relative;
z-index: 3;
background: $color__bg-panel;
.cx-vui-tabs--layout-horizontal & {
border: 1px solid $color__border-off-panel;
border-bottom: none;
}
.cx-vui-tabs--in-panel & {
border-radius: 4px 4px 0 0;
}
.cx-vui-tabs--invert & {
background: $color__bg-canvas;
}
}
}
}
&__content {
padding: 40px;
.cx-vui-tabs--invert & {
background: $color__bg-canvas;
}
.cx-vui-tabs--layout-horizontal & {
border-top: 1px solid $color__border-off-panel;
margin: -1px 0 0 0;
}
.cx-vui-tabs--layout-vertical & {
flex: 1 1 auto;
border-left: 1px solid $color__border-off-panel;
margin: 0 0 0 -1px;
padding: 15px 40px;
}
}
}

View File

@@ -0,0 +1,4 @@
textarea.cx-vui-textarea {
@include input();
resize: vertical;
}

View File

@@ -0,0 +1,27 @@
@import "variables/colors";
@import "variables/fonts";
@import "mixins/input";
@import "common/component-wrapper";
@import "common/panels";
@import "common/titles";
@import "common/copy";
@import "common/tooltip";
@import "common/popup";
@import "components/collapse";
@import "components/input";
@import "components/textarea";
@import "components/switcher";
@import "components/iconpicker";
@import "components/select";
@import "components/f-select";
@import "components/button";
@import "components/repeater";
@import "components/checkbox";
@import "components/radio";
@import "components/list-table";
@import "components/tabs";
@import "components/pagination";
@import "components/notice";

View File

@@ -0,0 +1,25 @@
@mixin input() {
font-size: 13px;
line-height: 20px;
border-radius: 4px;
background-color: $color__bg-input;
border: none;
color: $color__text;
padding: 6px 12px;
box-shadow: none;
outline: none;
box-sizing: border-box;
margin: 0;
&:focus {
box-shadow: 0 0 0 2px $color__accent-border inset;
background-color: #fff;
color: $color__heading;
}
&.has-error {
box-shadow: 0 0 0 2px $color__error-border inset;
color: $color__error;
}
&.size-fullwidth {
width: 100%;
}
}

View File

@@ -0,0 +1,25 @@
$color__text: #7B7E81;
$color__heading: #23282D;
$color__accent: #007CBA;
$color__accent-hover: #066EA2;
$color__accent-border: #80BDDC;
$color__accent-light: #CCE5F1;
$color__accent-lighter: #EDF6FA;
$color__error: #C92C2C;
$color__error-border: #E49595;
$color__error-light: #FBF0F0;
$color__success: #46B450;
$color__success-light: #E9F6EA;
$color__border-in-panel: #ECECEC;
$color__border-off-panel: #DCDCDD;
$color__border-contrtol: #7B7E81;
$color__bg-panel: #fff;
$color__bg-canvas: #f5f5f5;
$color__bg-input: #f4f4f5;
$color__bg-input-hover: #ECECEC;

View File

@@ -0,0 +1 @@
$font_family: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;