@inkline/inkline
Version:
Inkline is the Vue.js UI/UX Library built for creating your next design system
211 lines (192 loc) • 5.46 kB
text/typescript
import { defineComponent } from 'vue';
import {
getValueByPath,
setValueByPath,
setValuesAlongPath,
clone,
uid
} from '@inkline/inkline/helpers';
import {
colorVariantClass,
defaultPropValue,
sizePropValidator,
FormComponentMixin
} from '@inkline/inkline/mixins';
import { validate } from '@inkline/inkline/validation';
import { Classes, InputElementEvent } from '@inkline/inkline/types';
/**
* Slot for default card content
* @name default
* @kind slot
*/
const componentName = 'IForm';
export default defineComponent({
name: componentName,
mixins: [
FormComponentMixin
],
provide () {
return {
form: this
};
},
inheritAttrs: false,
props: {
/**
* The color variant of the form
* @type light | dark
* @default light
* @name color
*/
color: {
type: String,
default: ''
},
/**
* The disabled state of the form
* @type Boolean
* @default false
* @name disabled
*/
disabled: {
type: Boolean,
default: false
},
/**
* Display the form as inline
* @type Boolean
* @default false
* @name inline
*/
inline: {
type: Boolean,
default: false
},
/**
* The loading state of the form
* @type Boolean
* @default false
* @name loading
*/
loading: {
type: Boolean,
default: false
},
/**
* The unique identifier of the form
* @type String
* @default uid()
* @name name
*/
name: {
type: String,
default () {
return uid('form');
}
},
/**
* Used to set the form schema
* @type Boolean
* @default false
* @name modelValue
*/
modelValue: {
type: Object,
default: () => null
},
/**
* The readonly state of the form
* @type Boolean
* @default false
* @name readonly
*/
readonly: {
type: Boolean,
default: false
},
/**
* The size variant of the form
* @type sm | md | lg
* @default md
* @name size
*/
size: {
type: String,
default: defaultPropValue<string>(componentName, 'size'),
validator: sizePropValidator
}
},
emits: [
/**
* Event emitted for setting the modelValue schema
* @event update:modelValue
*/
'update:modelValue',
/**
* Event emitted for submitting the form
* @event submit
*/
'submit'
],
computed: {
classes (): Classes {
return {
...colorVariantClass(this),
[`-${this.size}`]: Boolean(this.size),
'-disabled': this.isDisabled,
'-readonly': this.isReadonly,
'-inline': this.inline
};
},
schema (): any {
if (this.modelValue) {
return this.modelValue;
}
return getValueByPath((this as any).formGroup.schema || (this as any).form.schema || {}, this.name);
}
},
methods: {
onBlur (name: string, event: InputElementEvent) {
this.parent.onBlur?.(this.name ? `${this.name}.${name}` : name, event);
if (this.modelValue) {
let schema = clone(this.modelValue);
schema = setValuesAlongPath(schema, name, { untouched: false, touched: true });
if (this.shouldValidate(name, 'blur')) {
schema = validate(schema);
}
this.$emit('update:modelValue', schema);
}
},
onInput (name: string, value: any) {
this.parent.onInput?.(this.name ? `${this.name}.${name}` : name, value);
if (this.modelValue) {
let schema = this.modelValue;
schema = setValueByPath(schema, name, 'value', value);
schema = setValuesAlongPath(schema, name, { pristine: false, dirty: true });
if (this.shouldValidate(name, 'input')) {
schema = validate(schema);
}
this.$emit('update:modelValue', schema);
}
},
onSubmit (event: InputElementEvent) {
event.preventDefault();
if (this.modelValue) {
let schema = clone(this.modelValue);
schema = validate(schema);
this.$emit('update:modelValue', schema);
if (schema.invalid) {
return;
}
}
this.$emit('submit', event);
},
shouldValidate (path: string, eventName: string): boolean {
const targetSchema = getValueByPath(this.modelValue, path);
const events = targetSchema.validateOn
? [].concat(targetSchema.validateOn)
: this.$inkline.options.validateOn;
return events!.includes(eventName);
}
}
});