@vue-interface/form-control
Version:
An abstract form control Vue mixin.
621 lines (620 loc) • 15.8 kB
JavaScript
import { Shadowable as m } from "@vue-interface/shadowable";
import { isPlainObject as F, isNil as p, kebabCase as o, isObject as k } from "lodash-es";
import { defineComponent as l, computed as A, openBlock as y, createElementBlock as g, Fragment as v, renderList as b, unref as u, renderSlot as C, normalizeProps as $, guardReactiveProps as S } from "vue";
const n = {};
function a(...t) {
if (!t.length)
return n;
const [e, s] = t;
return typeof e == "string" ? typeof n[e] < "u" ? n[e] : s : Array.isArray(e) ? e.reduce((r, i) => Object.assign(r, {
//@ts-ignore
[i]: n[i]
}), {}) : Object.assign(n, ...t);
}
const j = /* @__PURE__ */ l({
__name: "FormControlErrors",
props: {
error: null,
errors: null,
name: null,
id: null
},
setup(t) {
const e = t, s = String((e == null ? void 0 : e.id) || (e == null ? void 0 : e.name)), r = A(() => e.error ? /* @__PURE__ */ new Map(
[[s, [e.error]]]
) : F(e.errors) ? new Map(
Object.entries(e.errors)
) : Array.isArray(e.errors) ? /* @__PURE__ */ new Map(
[[s, e.errors]]
) : /* @__PURE__ */ new Map());
return (i, c) => (y(!0), g(v, null, b(u(r).get(u(s)), (E) => C(i.$slots, "default", $(S({ key: u(s), error: E })))), 256));
}
}), z = /* @__PURE__ */ l({
__name: "FormControlFeedback",
props: {
feedback: null
},
setup(t) {
return (e, s) => (y(!0), g(v, null, b([].concat(t.feedback), (r) => C(e.$slots, "default", $(S({ feedback: r })))), 256));
}
});
function d(t, e, s = "-") {
const r = String(e).replace(new RegExp(`^${t}${s}?`), "");
return [
o(r),
t
].filter((i) => !!i).join(s);
}
const V = l({
components: {
FormControlErrors: j,
FormControlFeedback: z
},
directives: {
bindEvents: {
created(t, e) {
var s, r;
(r = (s = e.instance) == null ? void 0 : s.bindEvents) == null || r.call(s, t);
}
}
},
mixins: [
m
],
inheritAttrs: !1,
props: {
/**
* Show type activity indicator.
*/
activity: {
type: Boolean,
default: !1
},
/**
* Animate floating labels inside the input.
*/
animated: {
type: Boolean,
default: () => a("animated", !1)
},
/**
* An inline field validation error.
*/
error: {
type: [String, Array, Boolean],
default: void 0
},
/**
* An inline field validation errors passed as object with key/value
* pairs. If errors passed as an object, the form name will be used for
* the key.
*/
errors: {
type: [Array, Object, Boolean],
default: void 0
},
/**
* Some feedback to add to the field once the field is successfully
* valid.
*/
feedback: {
type: [String, Array],
default: void 0
},
/**
* The primary class assigned to the form control.
*/
formControlClass: {
type: [Array, Object, String],
default: () => a("controlClass", "form-control")
},
/**
* Add form-group wrapper to input.
*/
group: {
type: Boolean,
default: () => a("group", !0)
},
/**
* Some instructions to appear under the field label.
*/
helpText: {
type: [Number, String],
default: void 0
},
/**
* The activity indicator type.
*/
indicator: {
type: [Object, String, Boolean],
default: () => a("indicator", "spinner")
},
/**
* The activity indicator size.
*/
indicatorSize: {
type: String,
default: void 0
},
/**
* Force the input to be invalid.
*/
invalid: Boolean,
/**
* The value of label element. If no value, no label will appear.
*/
label: {
type: [Number, String],
default: void 0
},
/**
* The default label class assigned to the label element.
*/
labelClass: {
type: [Object, String],
default: () => a("labelClass", "form-label")
},
/**
* The model default value.
*/
modelValue: {
type: [String, Number, Boolean, Array, Object],
default: () => {
}
},
/**
* Should the control look like plaintext.
*/
plaintext: Boolean,
/**
* The size of the form control.
*/
size: {
type: String,
default: void 0
},
/**
* Force the input to be valid.
*/
valid: Boolean
},
emits: [
"focus",
"blur",
"change",
"click",
"keypress",
"keyup",
"keydown",
"progress",
"paste",
"update:modelValue"
],
data() {
return {
currentValue: void 0,
hasChanged: !1,
hasFocus: !1,
isDirty: this
};
},
computed: {
model: {
get() {
return this.getModelValue();
},
set(t) {
this.setModelValue(t);
}
},
id() {
return this.$attrs.id || Math.random().toString(36).slice(2);
},
isEmpty() {
return p(this.model);
},
isInvalid() {
return !!(this.invalid || this.error || this.errors && (Array.isArray(this.errors) ? this.errors.length : this.errors[this.$attrs.id || this.$attrs.name]));
},
isValid() {
return !!(this.valid || this.feedback);
},
componentName() {
return this.$options.name;
},
controlClass() {
return this.formControlClass;
},
controlAttributes() {
const t = Object.assign({}, this.$attrs, {
id: this.id,
class: this.controlClasses
});
return delete t.value, t;
},
controlClasses() {
return Object.assign({
[this.controlClass]: !!this.controlClass,
[this.controlSizeClass]: !!this.controlSizeClass,
[this.plaintextClass]: this.plaintext,
"form-control-icon": !!this.$slots.icon,
"is-valid": this.isValid,
"is-invalid": this.isInvalid
}, this.shadowableClass);
},
controlSizeClass() {
return d(this.size, this.controlClass);
},
formGroupClasses() {
return Object.assign({
animated: this.animated,
"form-group": this.group,
"has-activity": this.activity,
"has-changed": this.hasChanged,
"has-focus": this.hasFocus,
"has-icon": !!this.$slots.icon,
"is-dirty": this.isDirty,
"is-empty": this.isEmpty,
"is-invalid": this.isInvalid,
"is-valid": this.isValid,
[this.$attrs.class]: !!this.$attrs.class,
[this.size && d(this.size, "form-group")]: !!this.size,
[this.size && d(this.size, this.componentName)]: !!this.size
}, !!this.componentName && {
[o(this.componentName)]: !0
});
},
plaintextClass() {
return "form-control-plaintext";
}
},
created() {
this.currentValue = this.$attrs.value, this.isDirty = !p(this.model);
},
methods: {
bindEvents(t) {
for (const e of this.$options.emits)
t.addEventListener(e, (s) => {
this.$emit(e, s);
});
t.addEventListener("focus", () => {
this.isDirty = !0, this.hasFocus = !0;
}), t.addEventListener("blur", () => {
this.hasFocus = !1;
});
},
blur() {
var t;
(t = this.$refs.field) == null || t.blur();
},
focus() {
var t;
(t = this.$refs.field) == null || t.focus();
},
getFieldErrors() {
let t = this.error || this.errors;
return this.errors && !Array.isArray(this.errors) && (t = this.errors[this.$attrs.name || this.$attrs.id]), !t || Array.isArray(t) || k(t) ? t : [t];
},
getModelValue() {
return this.modelValue === void 0 ? this.currentValue : this.modelValue;
},
setModelValue(t) {
this.hasChanged = !0, this.currentValue = t, this.$emit("update:modelValue", t);
}
}
});
function h(t, e, s = "-") {
const r = String(e).replace(new RegExp(`^${t}${s}?`), "");
return [
o(r),
t
].filter((i) => !!i).join(s);
}
function f(t) {
return !Array.isArray(t) && typeof t == "object";
}
const N = l({
directives: {
bindEvents: {
beforeMount(t, e) {
var s, r;
(r = (s = e.instance) == null ? void 0 : s.bindEvents) == null || r.call(s, t);
}
}
},
mixins: [
m
],
inheritAttrs: !1,
props: {
modelValue: {
default: void 0
},
/**
* Show type activity indicator.
*/
activity: {
type: Boolean,
default: !1
},
/**
* Animate floating labels inside the input.
*/
animated: {
type: Boolean,
default: () => a("animated", !1)
},
/**
* An array of event names that correlate with callback functions.
*/
nativeEvents: {
type: Array,
default() {
return ["focus", "blur", "change", "click", "keypress", "keyup", "keydown", "progress", "paste"];
}
},
/**
* The default class name assigned to the control element.
*/
defaultControlClass: {
type: String,
default: () => a("defaultControlClass", "form-control")
},
/**
* An inline field validation error.
*/
error: {
type: [String, Array, Boolean],
default: void 0
},
/**
* An inline field validation errors passed as object with key/value
* pairs. If errors passed as an object, the form name will be used for
* the key.
*/
errors: {
type: [Array, Object, Boolean],
default() {
return {};
}
},
/**
* Some feedback to add to the field once the field is successfully
* valid.
*/
feedback: {
type: [String, Array],
default: void 0
},
/**
* Add form-group wrapper to input.
*/
group: {
type: Boolean,
default: () => a("group", !0)
},
/**
* Some instructions to appear under the field label.
*/
helpText: {
type: [Number, String],
default: void 0
},
/**
* Hide the label for browsers, but leave it for screen readers.
*/
hideLabel: Boolean,
/**
* The activity indicator type.
*/
indicator: {
type: [String, Boolean],
default: () => a("indicator", "spinner")
},
/**
* The activity indicator size.
*/
indicatorSize: {
type: String,
default: void 0
},
/**
* Display the form field inline.
*/
inline: Boolean,
/**
* The invalid property.
*/
invalid: Boolean,
/**
* The value of label element. If no value, no label will appear.
*/
label: {
type: [Number, String],
default: void 0
},
/**
* The default label class assigned to the label element.
*/
labelClass: {
type: [Object, String],
default: () => a("labelClass", "form-label")
},
/**
* Should the control look like a pill.
*/
pill: Boolean,
/**
* Should the control look like plaintext.
*/
plaintext: Boolean,
/**
* The size of the form control.
*/
size: {
type: String,
default: void 0
},
/**
* Additional margin/padding classes for fine control of spacing.
*/
spacing: {
type: String,
default: void 0
},
/**
* The valid property.
*/
valid: Boolean
},
emits: [
"blur",
"change",
"click",
"focus",
"keydown",
"keypress",
"keyup",
"update:modelValue"
],
data() {
return {
defaultEmpty: !1,
hasChanged: !1,
hasFocus: !1,
isEmpty: !0
};
},
computed: {
id() {
return this.$attrs.id || this.$attrs.name || (Math.random() + 1).toString(36).substring(7);
},
componentName() {
return this.$options.name;
},
controlAttributes() {
return Object.fromEntries(
Object.entries(this.$attrs).concat([
["id", this.id],
["class", this.controlClasses],
["value", this.modelValue]
])
);
},
controlClass() {
return this.defaultControlClass;
},
controlSizeClass() {
return h(this.size, this.controlClass);
},
formGroupClasses() {
return Object.assign({
[this.size && h(this.size, this.componentName)]: !!this.size,
animated: this.animated,
"default-empty": this.defaultEmpty,
"form-group": this.group,
[this.size && h(this.size, "form-group")]: !!this.size,
"has-activity": this.activity,
"has-changed": this.hasChanged,
"has-focus": this.hasFocus,
"has-icon": !!this.$slots.icon,
"is-empty": this.isEmpty,
"is-invalid": !!(this.invalid || this.invalidFeedback),
"is-valid": !!(this.valid || this.validFeedback),
[this.$attrs.class]: !!this.$attrs.class,
[this.$attrs.id]: !!this.$attrs.id
}, !!this.componentName && {
[o(this.componentName)]: !0
});
},
controlClasses() {
return Object.assign({
[this.controlClass]: !!this.controlClass,
[this.controlSizeClass]: !!this.controlSizeClass,
"form-control-icon": !!this.$slots.icon,
"is-valid": !!(this.valid || this.validFeedback),
"is-invalid": !!(this.invalid || this.invalidFeedback),
[this.pillClasses]: this.pill,
[this.plaintextClass]: this.plaintext,
[this.spacing]: !!this.spacing
}, this.shadowableClass);
},
hasDefaultSlot() {
return !!this.$slots.default;
},
invalidFeedback() {
if (this.error === "")
return null;
if (this.error)
return this.error;
const t = this.getFieldErrors();
return Array.isArray(t) ? t.filter((e) => e && typeof e == "string").join("<br>") : t;
},
pillClasses() {
return "rounded rounded-pill";
},
plaintextClass() {
return "form-control-plaintext";
},
validFeedback() {
return Array.isArray(this.feedback) ? this.feedback.join("<br>") : this.feedback;
}
},
watch: {
hasFocus() {
this.shouldChangeOnFocus() && (this.hasChanged = !0);
},
defaultEmpty() {
this.hasChanged = !0;
}
},
methods: {
bindEvents(t, e) {
var r;
e || (e = this.onInput);
const s = t instanceof HTMLSelectElement ? (r = t.querySelectorAll("option")) == null ? void 0 : r[t.selectedIndex] : null;
s && (t.value = s == null ? void 0 : s.value), t.value && e(t.value), this.hasChanged = !!t.value, this.isEmpty = !t.value, t.addEventListener("focus", () => {
this.hasFocus = !0;
}), t.addEventListener("blur", () => {
this.hasFocus = !1;
}), t.addEventListener("input", () => {
this.isEmpty = !1, this.hasChanged = !0;
}), t.addEventListener(
t.tagName === "SELECT" ? "change" : "input",
() => e(t.value)
), this.nativeEvents.forEach((i) => {
t.addEventListener(i, (c) => {
this.$emit(i, c);
});
});
},
blur() {
this.getInputField() && this.getInputField().blur();
},
focus() {
this.getInputField() && this.getInputField().focus();
},
getInputField() {
return this.$el.querySelector(
".form-control, input, select, textarea"
);
},
getFieldErrors() {
let t = this.error || this.errors;
return this.errors && f(this.errors) && (t = this.errors[this.$attrs.name || this.$attrs.id]), !t || Array.isArray(t) || f(t) ? t : [t];
},
shouldChangeOnFocus() {
return !this.getInputField().readOnly;
},
onInput(t) {
this.$emit("update:modelValue", t);
}
}
});
export {
V as FormControl,
j as FormControlErrors,
N as FormControlLegacy,
a as config
};
//# sourceMappingURL=form-control.js.map