Some checks failed
🚀 Deploy - Demo / deployment (push) Has been cancelled
- 웹훅 URL을 https://admin.youtooplay.com/webhook로 변경 - Nginx 리버스 프록시 설정 파일 추가 - 배포 가이드 업데이트
1184 lines
36 KiB
JavaScript
1184 lines
36 KiB
JavaScript
import { ref, createVNode, computed, mergeProps, Fragment, withDirectives, resolveDirective, cloneVNode, shallowRef, watch, provide, toRef, markRaw, vShow, nextTick, inject, unref } from 'vue';
|
|
import { g as genericComponent, p as propsFactory, a as useRender, o as forwardRefs, aQ as Intersect, n as useProxiedModel, aK as filterInputAttrs, m as makeComponentProps, aM as consoleWarn, aL as getCurrentInstanceName, ai as useDensity, f as useDimension, F as provideTheme, E as useRtl, a5 as getUid, i as isOn, aP as pick, aA as MaybeTransition, $ as useLoader, ak as useRounded, a0 as useBackgroundColor, at as useTextColor, aO as nullifyTransforms, av as animate, aw as standardEasing, j as convertToUnit, a1 as LoaderSlot, y as VDefaultsProvider, aR as callEvent, K as makeThemeProps, a2 as EventProp, N as makeRoundedProps, Y as makeLoaderProps, I as IconValue, aN as only, P as makeDensityProps, k as makeDimensionProps, l as useLocale, w as wrapInArray, e as getCurrentInstance, h as useToggleScope, q as makeTransitionProps, s as VIcon } from './server.mjs';
|
|
import { a as VExpandXTransition, c as VSlideYTransition } from './index-BNHdF426.mjs';
|
|
|
|
const makeVLabelProps = propsFactory({
|
|
text: String,
|
|
onClick: EventProp(),
|
|
...makeComponentProps(),
|
|
...makeThemeProps()
|
|
}, "VLabel");
|
|
const VLabel = genericComponent()({
|
|
name: "VLabel",
|
|
props: makeVLabelProps(),
|
|
setup(props, _ref) {
|
|
let {
|
|
slots
|
|
} = _ref;
|
|
useRender(() => {
|
|
var _a;
|
|
return createVNode("label", {
|
|
"class": ["v-label", {
|
|
"v-label--clickable": !!props.onClick
|
|
}, props.class],
|
|
"style": props.style,
|
|
"onClick": props.onClick
|
|
}, [props.text, (_a = slots.default) == null ? void 0 : _a.call(slots)]);
|
|
});
|
|
return {};
|
|
}
|
|
});
|
|
function useInputIcon(props) {
|
|
const {
|
|
t
|
|
} = useLocale();
|
|
function InputIcon(_ref) {
|
|
var _a;
|
|
let {
|
|
name
|
|
} = _ref;
|
|
const localeKey = {
|
|
prepend: "prependAction",
|
|
prependInner: "prependAction",
|
|
append: "appendAction",
|
|
appendInner: "appendAction",
|
|
clear: "clear"
|
|
}[name];
|
|
const listener = props[`onClick:${name}`];
|
|
const label = listener && localeKey ? t(`$vuetify.input.${localeKey}`, (_a = props.label) != null ? _a : "") : void 0;
|
|
return createVNode(VIcon, {
|
|
"icon": props[`${name}Icon`],
|
|
"aria-label": label,
|
|
"onClick": listener
|
|
}, null);
|
|
}
|
|
return {
|
|
InputIcon
|
|
};
|
|
}
|
|
const makeVMessagesProps = propsFactory({
|
|
active: Boolean,
|
|
color: String,
|
|
messages: {
|
|
type: [Array, String],
|
|
default: () => []
|
|
},
|
|
...makeComponentProps(),
|
|
...makeTransitionProps({
|
|
transition: {
|
|
component: VSlideYTransition,
|
|
leaveAbsolute: true,
|
|
group: true
|
|
}
|
|
})
|
|
}, "VMessages");
|
|
const VMessages = genericComponent()({
|
|
name: "VMessages",
|
|
props: makeVMessagesProps(),
|
|
setup(props, _ref) {
|
|
let {
|
|
slots
|
|
} = _ref;
|
|
const messages = computed(() => wrapInArray(props.messages));
|
|
const {
|
|
textColorClasses,
|
|
textColorStyles
|
|
} = useTextColor(computed(() => props.color));
|
|
useRender(() => createVNode(MaybeTransition, {
|
|
"transition": props.transition,
|
|
"tag": "div",
|
|
"class": ["v-messages", textColorClasses.value, props.class],
|
|
"style": [textColorStyles.value, props.style],
|
|
"role": "alert",
|
|
"aria-live": "polite"
|
|
}, {
|
|
default: () => [props.active && messages.value.map((message, i) => createVNode("div", {
|
|
"class": "v-messages__message",
|
|
"key": `${i}-${messages.value}`
|
|
}, [slots.message ? slots.message({
|
|
message
|
|
}) : message]))]
|
|
}));
|
|
return {};
|
|
}
|
|
});
|
|
const makeFocusProps = propsFactory({
|
|
focused: Boolean,
|
|
"onUpdate:focused": EventProp()
|
|
}, "focus");
|
|
function useFocus(props) {
|
|
let name = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : getCurrentInstanceName();
|
|
const isFocused = useProxiedModel(props, "focused");
|
|
const focusClasses = computed(() => {
|
|
return {
|
|
[`${name}--focused`]: isFocused.value
|
|
};
|
|
});
|
|
function focus() {
|
|
isFocused.value = true;
|
|
}
|
|
function blur() {
|
|
isFocused.value = false;
|
|
}
|
|
return {
|
|
focusClasses,
|
|
isFocused,
|
|
focus,
|
|
blur
|
|
};
|
|
}
|
|
const FormKey = Symbol.for("vuetify:form");
|
|
const makeFormProps = propsFactory({
|
|
disabled: Boolean,
|
|
fastFail: Boolean,
|
|
readonly: Boolean,
|
|
modelValue: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
validateOn: {
|
|
type: String,
|
|
default: "input"
|
|
}
|
|
}, "form");
|
|
function createForm(props) {
|
|
const model = useProxiedModel(props, "modelValue");
|
|
const isDisabled = computed(() => props.disabled);
|
|
const isReadonly = computed(() => props.readonly);
|
|
const isValidating = shallowRef(false);
|
|
const items = ref([]);
|
|
const errors = ref([]);
|
|
async function validate() {
|
|
const results = [];
|
|
let valid = true;
|
|
errors.value = [];
|
|
isValidating.value = true;
|
|
for (const item of items.value) {
|
|
const itemErrorMessages = await item.validate();
|
|
if (itemErrorMessages.length > 0) {
|
|
valid = false;
|
|
results.push({
|
|
id: item.id,
|
|
errorMessages: itemErrorMessages
|
|
});
|
|
}
|
|
if (!valid && props.fastFail) break;
|
|
}
|
|
errors.value = results;
|
|
isValidating.value = false;
|
|
return {
|
|
valid,
|
|
errors: errors.value
|
|
};
|
|
}
|
|
function reset() {
|
|
items.value.forEach((item) => item.reset());
|
|
}
|
|
function resetValidation() {
|
|
items.value.forEach((item) => item.resetValidation());
|
|
}
|
|
watch(items, () => {
|
|
let valid = 0;
|
|
let invalid = 0;
|
|
const results = [];
|
|
for (const item of items.value) {
|
|
if (item.isValid === false) {
|
|
invalid++;
|
|
results.push({
|
|
id: item.id,
|
|
errorMessages: item.errorMessages
|
|
});
|
|
} else if (item.isValid === true) valid++;
|
|
}
|
|
errors.value = results;
|
|
model.value = invalid > 0 ? false : valid === items.value.length ? true : null;
|
|
}, {
|
|
deep: true,
|
|
flush: "post"
|
|
});
|
|
provide(FormKey, {
|
|
register: (_ref) => {
|
|
let {
|
|
id,
|
|
vm,
|
|
validate: validate2,
|
|
reset: reset2,
|
|
resetValidation: resetValidation2
|
|
} = _ref;
|
|
if (items.value.some((item) => item.id === id)) {
|
|
consoleWarn(`Duplicate input name "${id}"`);
|
|
}
|
|
items.value.push({
|
|
id,
|
|
validate: validate2,
|
|
reset: reset2,
|
|
resetValidation: resetValidation2,
|
|
vm: markRaw(vm),
|
|
isValid: null,
|
|
errorMessages: []
|
|
});
|
|
},
|
|
unregister: (id) => {
|
|
items.value = items.value.filter((item) => {
|
|
return item.id !== id;
|
|
});
|
|
},
|
|
update: (id, isValid, errorMessages) => {
|
|
const found = items.value.find((item) => item.id === id);
|
|
if (!found) return;
|
|
found.isValid = isValid;
|
|
found.errorMessages = errorMessages;
|
|
},
|
|
isDisabled,
|
|
isReadonly,
|
|
isValidating,
|
|
isValid: model,
|
|
items,
|
|
validateOn: toRef(props, "validateOn")
|
|
});
|
|
return {
|
|
errors,
|
|
isDisabled,
|
|
isReadonly,
|
|
isValidating,
|
|
isValid: model,
|
|
items,
|
|
validate,
|
|
reset,
|
|
resetValidation
|
|
};
|
|
}
|
|
function useForm(props) {
|
|
const form = inject(FormKey, null);
|
|
return {
|
|
...form,
|
|
isReadonly: computed(() => {
|
|
var _a;
|
|
return !!((_a = props == null ? void 0 : props.readonly) != null ? _a : form == null ? void 0 : form.isReadonly.value);
|
|
}),
|
|
isDisabled: computed(() => {
|
|
var _a;
|
|
return !!((_a = props == null ? void 0 : props.disabled) != null ? _a : form == null ? void 0 : form.isDisabled.value);
|
|
})
|
|
};
|
|
}
|
|
const makeValidationProps = propsFactory({
|
|
disabled: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
error: Boolean,
|
|
errorMessages: {
|
|
type: [Array, String],
|
|
default: () => []
|
|
},
|
|
maxErrors: {
|
|
type: [Number, String],
|
|
default: 1
|
|
},
|
|
name: String,
|
|
label: String,
|
|
readonly: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
rules: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
modelValue: null,
|
|
validateOn: String,
|
|
validationValue: null,
|
|
...makeFocusProps()
|
|
}, "validation");
|
|
function useValidation(props) {
|
|
let name = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : getCurrentInstanceName();
|
|
let id = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : getUid();
|
|
const model = useProxiedModel(props, "modelValue");
|
|
const validationModel = computed(() => props.validationValue === void 0 ? model.value : props.validationValue);
|
|
const form = useForm(props);
|
|
const internalErrorMessages = ref([]);
|
|
const isPristine = shallowRef(true);
|
|
const isDirty = computed(() => !!(wrapInArray(model.value === "" ? null : model.value).length || wrapInArray(validationModel.value === "" ? null : validationModel.value).length));
|
|
const errorMessages = computed(() => {
|
|
var _a;
|
|
return ((_a = props.errorMessages) == null ? void 0 : _a.length) ? wrapInArray(props.errorMessages).concat(internalErrorMessages.value).slice(0, Math.max(0, +props.maxErrors)) : internalErrorMessages.value;
|
|
});
|
|
const validateOn = computed(() => {
|
|
var _a2, _b;
|
|
var _a;
|
|
let value = ((_a2 = props.validateOn) != null ? _a2 : (_a = form.validateOn) == null ? void 0 : _a.value) || "input";
|
|
if (value === "lazy") value = "input lazy";
|
|
if (value === "eager") value = "input eager";
|
|
const set = new Set((_b = value == null ? void 0 : value.split(" ")) != null ? _b : []);
|
|
return {
|
|
input: set.has("input"),
|
|
blur: set.has("blur") || set.has("input") || set.has("invalid-input"),
|
|
invalidInput: set.has("invalid-input"),
|
|
lazy: set.has("lazy"),
|
|
eager: set.has("eager")
|
|
};
|
|
});
|
|
const isValid = computed(() => {
|
|
var _a;
|
|
if (props.error || ((_a = props.errorMessages) == null ? void 0 : _a.length)) return false;
|
|
if (!props.rules.length) return true;
|
|
if (isPristine.value) {
|
|
return internalErrorMessages.value.length || validateOn.value.lazy ? null : true;
|
|
} else {
|
|
return !internalErrorMessages.value.length;
|
|
}
|
|
});
|
|
const isValidating = shallowRef(false);
|
|
const validationClasses = computed(() => {
|
|
return {
|
|
[`${name}--error`]: isValid.value === false,
|
|
[`${name}--dirty`]: isDirty.value,
|
|
[`${name}--disabled`]: form.isDisabled.value,
|
|
[`${name}--readonly`]: form.isReadonly.value
|
|
};
|
|
});
|
|
getCurrentInstance("validation");
|
|
const uid = computed(() => {
|
|
var _a;
|
|
return (_a = props.name) != null ? _a : unref(id);
|
|
});
|
|
useToggleScope(() => validateOn.value.input || validateOn.value.invalidInput && isValid.value === false, () => {
|
|
watch(validationModel, () => {
|
|
if (validationModel.value != null) {
|
|
validate();
|
|
} else if (props.focused) {
|
|
const unwatch = watch(() => props.focused, (val) => {
|
|
if (!val) validate();
|
|
unwatch();
|
|
});
|
|
}
|
|
});
|
|
});
|
|
useToggleScope(() => validateOn.value.blur, () => {
|
|
watch(() => props.focused, (val) => {
|
|
if (!val) validate();
|
|
});
|
|
});
|
|
watch([isValid, errorMessages], () => {
|
|
var _a;
|
|
(_a = form.update) == null ? void 0 : _a.call(form, uid.value, isValid.value, errorMessages.value);
|
|
});
|
|
async function reset() {
|
|
model.value = null;
|
|
await nextTick();
|
|
await resetValidation();
|
|
}
|
|
async function resetValidation() {
|
|
isPristine.value = true;
|
|
if (!validateOn.value.lazy) {
|
|
await validate(!validateOn.value.eager);
|
|
} else {
|
|
internalErrorMessages.value = [];
|
|
}
|
|
}
|
|
async function validate() {
|
|
var _a;
|
|
let silent = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
|
|
const results = [];
|
|
isValidating.value = true;
|
|
for (const rule of props.rules) {
|
|
if (results.length >= +((_a = props.maxErrors) != null ? _a : 1)) {
|
|
break;
|
|
}
|
|
const handler = typeof rule === "function" ? rule : () => rule;
|
|
const result = await handler(validationModel.value);
|
|
if (result === true) continue;
|
|
if (result !== false && typeof result !== "string") {
|
|
console.warn(`${result} is not a valid value. Rule functions must return boolean true or a string.`);
|
|
continue;
|
|
}
|
|
results.push(result || "");
|
|
}
|
|
internalErrorMessages.value = results;
|
|
isValidating.value = false;
|
|
isPristine.value = silent;
|
|
return internalErrorMessages.value;
|
|
}
|
|
return {
|
|
errorMessages,
|
|
isDirty,
|
|
isDisabled: form.isDisabled,
|
|
isReadonly: form.isReadonly,
|
|
isPristine,
|
|
isValid,
|
|
isValidating,
|
|
reset,
|
|
resetValidation,
|
|
validate,
|
|
validationClasses
|
|
};
|
|
}
|
|
const makeVInputProps = propsFactory({
|
|
id: String,
|
|
appendIcon: IconValue,
|
|
centerAffix: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
prependIcon: IconValue,
|
|
hideDetails: [Boolean, String],
|
|
hideSpinButtons: Boolean,
|
|
hint: String,
|
|
persistentHint: Boolean,
|
|
messages: {
|
|
type: [Array, String],
|
|
default: () => []
|
|
},
|
|
direction: {
|
|
type: String,
|
|
default: "horizontal",
|
|
validator: (v) => ["horizontal", "vertical"].includes(v)
|
|
},
|
|
"onClick:prepend": EventProp(),
|
|
"onClick:append": EventProp(),
|
|
...makeComponentProps(),
|
|
...makeDensityProps(),
|
|
...only(makeDimensionProps(), ["maxWidth", "minWidth", "width"]),
|
|
...makeThemeProps(),
|
|
...makeValidationProps()
|
|
}, "VInput");
|
|
const VInput = genericComponent()({
|
|
name: "VInput",
|
|
props: {
|
|
...makeVInputProps()
|
|
},
|
|
emits: {
|
|
"update:modelValue": (value) => true
|
|
},
|
|
setup(props, _ref) {
|
|
let {
|
|
attrs,
|
|
slots,
|
|
emit
|
|
} = _ref;
|
|
const {
|
|
densityClasses
|
|
} = useDensity(props);
|
|
const {
|
|
dimensionStyles
|
|
} = useDimension(props);
|
|
const {
|
|
themeClasses
|
|
} = provideTheme(props);
|
|
const {
|
|
rtlClasses
|
|
} = useRtl();
|
|
const {
|
|
InputIcon
|
|
} = useInputIcon(props);
|
|
const uid = getUid();
|
|
const id = computed(() => props.id || `input-${uid}`);
|
|
const messagesId = computed(() => `${id.value}-messages`);
|
|
const {
|
|
errorMessages,
|
|
isDirty,
|
|
isDisabled,
|
|
isReadonly,
|
|
isPristine,
|
|
isValid,
|
|
isValidating,
|
|
reset,
|
|
resetValidation,
|
|
validate,
|
|
validationClasses
|
|
} = useValidation(props, "v-input", id);
|
|
const slotProps = computed(() => ({
|
|
id,
|
|
messagesId,
|
|
isDirty,
|
|
isDisabled,
|
|
isReadonly,
|
|
isPristine,
|
|
isValid,
|
|
isValidating,
|
|
reset,
|
|
resetValidation,
|
|
validate
|
|
}));
|
|
const messages = computed(() => {
|
|
var _a;
|
|
if (((_a = props.errorMessages) == null ? void 0 : _a.length) || !isPristine.value && errorMessages.value.length) {
|
|
return errorMessages.value;
|
|
} else if (props.hint && (props.persistentHint || props.focused)) {
|
|
return props.hint;
|
|
} else {
|
|
return props.messages;
|
|
}
|
|
});
|
|
useRender(() => {
|
|
var _a, _b, _c, _d;
|
|
const hasPrepend = !!(slots.prepend || props.prependIcon);
|
|
const hasAppend = !!(slots.append || props.appendIcon);
|
|
const hasMessages = messages.value.length > 0;
|
|
const hasDetails = !props.hideDetails || props.hideDetails === "auto" && (hasMessages || !!slots.details);
|
|
return createVNode("div", {
|
|
"class": ["v-input", `v-input--${props.direction}`, {
|
|
"v-input--center-affix": props.centerAffix,
|
|
"v-input--hide-spin-buttons": props.hideSpinButtons
|
|
}, densityClasses.value, themeClasses.value, rtlClasses.value, validationClasses.value, props.class],
|
|
"style": [dimensionStyles.value, props.style]
|
|
}, [hasPrepend && createVNode("div", {
|
|
"key": "prepend",
|
|
"class": "v-input__prepend"
|
|
}, [(_a = slots.prepend) == null ? void 0 : _a.call(slots, slotProps.value), props.prependIcon && createVNode(InputIcon, {
|
|
"key": "prepend-icon",
|
|
"name": "prepend"
|
|
}, null)]), slots.default && createVNode("div", {
|
|
"class": "v-input__control"
|
|
}, [(_b = slots.default) == null ? void 0 : _b.call(slots, slotProps.value)]), hasAppend && createVNode("div", {
|
|
"key": "append",
|
|
"class": "v-input__append"
|
|
}, [props.appendIcon && createVNode(InputIcon, {
|
|
"key": "append-icon",
|
|
"name": "append"
|
|
}, null), (_c = slots.append) == null ? void 0 : _c.call(slots, slotProps.value)]), hasDetails && createVNode("div", {
|
|
"class": "v-input__details"
|
|
}, [createVNode(VMessages, {
|
|
"id": messagesId.value,
|
|
"active": hasMessages,
|
|
"messages": messages.value
|
|
}, {
|
|
message: slots.message
|
|
}), (_d = slots.details) == null ? void 0 : _d.call(slots, slotProps.value)])]);
|
|
});
|
|
return {
|
|
reset,
|
|
resetValidation,
|
|
validate,
|
|
isValid,
|
|
errorMessages
|
|
};
|
|
}
|
|
});
|
|
const makeVFormProps = propsFactory({
|
|
...makeComponentProps(),
|
|
...makeFormProps()
|
|
}, "VForm");
|
|
const VForm = genericComponent()({
|
|
name: "VForm",
|
|
props: makeVFormProps(),
|
|
emits: {
|
|
"update:modelValue": (val) => true,
|
|
submit: (e) => true
|
|
},
|
|
setup(props, _ref) {
|
|
let {
|
|
slots,
|
|
emit
|
|
} = _ref;
|
|
const form = createForm(props);
|
|
const formRef = ref();
|
|
function onReset(e) {
|
|
e.preventDefault();
|
|
form.reset();
|
|
}
|
|
function onSubmit(_e) {
|
|
const e = _e;
|
|
const ready = form.validate();
|
|
e.then = ready.then.bind(ready);
|
|
e.catch = ready.catch.bind(ready);
|
|
e.finally = ready.finally.bind(ready);
|
|
emit("submit", e);
|
|
if (!e.defaultPrevented) {
|
|
ready.then((_ref2) => {
|
|
var _a;
|
|
let {
|
|
valid
|
|
} = _ref2;
|
|
if (valid) {
|
|
(_a = formRef.value) == null ? void 0 : _a.submit();
|
|
}
|
|
});
|
|
}
|
|
e.preventDefault();
|
|
}
|
|
useRender(() => {
|
|
var _a;
|
|
return createVNode("form", {
|
|
"ref": formRef,
|
|
"class": ["v-form", props.class],
|
|
"style": props.style,
|
|
"novalidate": true,
|
|
"onReset": onReset,
|
|
"onSubmit": onSubmit
|
|
}, [(_a = slots.default) == null ? void 0 : _a.call(slots, form)]);
|
|
});
|
|
return forwardRefs(form, formRef);
|
|
}
|
|
});
|
|
const makeVCounterProps = propsFactory({
|
|
active: Boolean,
|
|
disabled: Boolean,
|
|
max: [Number, String],
|
|
value: {
|
|
type: [Number, String],
|
|
default: 0
|
|
},
|
|
...makeComponentProps(),
|
|
...makeTransitionProps({
|
|
transition: {
|
|
component: VSlideYTransition
|
|
}
|
|
})
|
|
}, "VCounter");
|
|
const VCounter = genericComponent()({
|
|
name: "VCounter",
|
|
functional: true,
|
|
props: makeVCounterProps(),
|
|
setup(props, _ref) {
|
|
let {
|
|
slots
|
|
} = _ref;
|
|
const counter = computed(() => {
|
|
return props.max ? `${props.value} / ${props.max}` : String(props.value);
|
|
});
|
|
useRender(() => createVNode(MaybeTransition, {
|
|
"transition": props.transition
|
|
}, {
|
|
default: () => [withDirectives(createVNode("div", {
|
|
"class": ["v-counter", {
|
|
"text-error": props.max && !props.disabled && parseFloat(props.value) > parseFloat(props.max)
|
|
}, props.class],
|
|
"style": props.style
|
|
}, [slots.default ? slots.default({
|
|
counter: counter.value,
|
|
max: props.max,
|
|
value: props.value
|
|
}) : counter.value]), [[vShow, props.active]])]
|
|
}));
|
|
return {};
|
|
}
|
|
});
|
|
const makeVFieldLabelProps = propsFactory({
|
|
floating: Boolean,
|
|
...makeComponentProps()
|
|
}, "VFieldLabel");
|
|
const VFieldLabel = genericComponent()({
|
|
name: "VFieldLabel",
|
|
props: makeVFieldLabelProps(),
|
|
setup(props, _ref) {
|
|
let {
|
|
slots
|
|
} = _ref;
|
|
useRender(() => createVNode(VLabel, {
|
|
"class": ["v-field-label", {
|
|
"v-field-label--floating": props.floating
|
|
}, props.class],
|
|
"style": props.style,
|
|
"aria-hidden": props.floating || void 0
|
|
}, slots));
|
|
return {};
|
|
}
|
|
});
|
|
const allowedVariants = ["underlined", "outlined", "filled", "solo", "solo-inverted", "solo-filled", "plain"];
|
|
const makeVFieldProps = propsFactory({
|
|
appendInnerIcon: IconValue,
|
|
bgColor: String,
|
|
clearable: Boolean,
|
|
clearIcon: {
|
|
type: IconValue,
|
|
default: "$clear"
|
|
},
|
|
active: Boolean,
|
|
centerAffix: {
|
|
type: Boolean,
|
|
default: void 0
|
|
},
|
|
color: String,
|
|
baseColor: String,
|
|
dirty: Boolean,
|
|
disabled: {
|
|
type: Boolean,
|
|
default: null
|
|
},
|
|
error: Boolean,
|
|
flat: Boolean,
|
|
label: String,
|
|
persistentClear: Boolean,
|
|
prependInnerIcon: IconValue,
|
|
reverse: Boolean,
|
|
singleLine: Boolean,
|
|
variant: {
|
|
type: String,
|
|
default: "filled",
|
|
validator: (v) => allowedVariants.includes(v)
|
|
},
|
|
"onClick:clear": EventProp(),
|
|
"onClick:appendInner": EventProp(),
|
|
"onClick:prependInner": EventProp(),
|
|
...makeComponentProps(),
|
|
...makeLoaderProps(),
|
|
...makeRoundedProps(),
|
|
...makeThemeProps()
|
|
}, "VField");
|
|
const VField = genericComponent()({
|
|
name: "VField",
|
|
inheritAttrs: false,
|
|
props: {
|
|
id: String,
|
|
...makeFocusProps(),
|
|
...makeVFieldProps()
|
|
},
|
|
emits: {
|
|
"update:focused": (focused) => true,
|
|
"update:modelValue": (value) => true
|
|
},
|
|
setup(props, _ref) {
|
|
let {
|
|
attrs,
|
|
emit,
|
|
slots
|
|
} = _ref;
|
|
const {
|
|
themeClasses
|
|
} = provideTheme(props);
|
|
const {
|
|
loaderClasses
|
|
} = useLoader(props);
|
|
const {
|
|
focusClasses,
|
|
isFocused,
|
|
focus,
|
|
blur
|
|
} = useFocus(props);
|
|
const {
|
|
InputIcon
|
|
} = useInputIcon(props);
|
|
const {
|
|
roundedClasses
|
|
} = useRounded(props);
|
|
const {
|
|
rtlClasses
|
|
} = useRtl();
|
|
const isActive = computed(() => props.dirty || props.active);
|
|
const hasLabel = computed(() => !props.singleLine && !!(props.label || slots.label));
|
|
const uid = getUid();
|
|
const id = computed(() => props.id || `input-${uid}`);
|
|
const messagesId = computed(() => `${id.value}-messages`);
|
|
const labelRef = ref();
|
|
const floatingLabelRef = ref();
|
|
const controlRef = ref();
|
|
const isPlainOrUnderlined = computed(() => ["plain", "underlined"].includes(props.variant));
|
|
const {
|
|
backgroundColorClasses,
|
|
backgroundColorStyles
|
|
} = useBackgroundColor(toRef(props, "bgColor"));
|
|
const {
|
|
textColorClasses,
|
|
textColorStyles
|
|
} = useTextColor(computed(() => {
|
|
return props.error || props.disabled ? void 0 : isActive.value && isFocused.value ? props.color : props.baseColor;
|
|
}));
|
|
watch(isActive, (val) => {
|
|
if (hasLabel.value) {
|
|
const el = labelRef.value.$el;
|
|
const targetEl = floatingLabelRef.value.$el;
|
|
requestAnimationFrame(() => {
|
|
const rect = nullifyTransforms(el);
|
|
const targetRect = targetEl.getBoundingClientRect();
|
|
const x = targetRect.x - rect.x;
|
|
const y = targetRect.y - rect.y - (rect.height / 2 - targetRect.height / 2);
|
|
const targetWidth = targetRect.width / 0.75;
|
|
const width = Math.abs(targetWidth - rect.width) > 1 ? {
|
|
maxWidth: convertToUnit(targetWidth)
|
|
} : void 0;
|
|
const style = getComputedStyle(el);
|
|
const targetStyle = getComputedStyle(targetEl);
|
|
const duration = parseFloat(style.transitionDuration) * 1e3 || 150;
|
|
const scale = parseFloat(targetStyle.getPropertyValue("--v-field-label-scale"));
|
|
const color = targetStyle.getPropertyValue("color");
|
|
el.style.visibility = "visible";
|
|
targetEl.style.visibility = "hidden";
|
|
animate(el, {
|
|
transform: `translate(${x}px, ${y}px) scale(${scale})`,
|
|
color,
|
|
...width
|
|
}, {
|
|
duration,
|
|
easing: standardEasing,
|
|
direction: val ? "normal" : "reverse"
|
|
}).finished.then(() => {
|
|
el.style.removeProperty("visibility");
|
|
targetEl.style.removeProperty("visibility");
|
|
});
|
|
});
|
|
}
|
|
}, {
|
|
flush: "post"
|
|
});
|
|
const slotProps = computed(() => ({
|
|
isActive,
|
|
isFocused,
|
|
controlRef,
|
|
blur,
|
|
focus
|
|
}));
|
|
function onClick(e) {
|
|
if (e.target !== (void 0).activeElement) {
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
function onKeydownClear(e) {
|
|
var _a;
|
|
if (e.key !== "Enter" && e.key !== " ") return;
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
(_a = props["onClick:clear"]) == null ? void 0 : _a.call(props, new MouseEvent("click"));
|
|
}
|
|
useRender(() => {
|
|
var _a2;
|
|
var _a, _b, _c;
|
|
const isOutlined = props.variant === "outlined";
|
|
const hasPrepend = !!(slots["prepend-inner"] || props.prependInnerIcon);
|
|
const hasClear = !!(props.clearable || slots.clear);
|
|
const hasAppend = !!(slots["append-inner"] || props.appendInnerIcon || hasClear);
|
|
const label = () => slots.label ? slots.label({
|
|
...slotProps.value,
|
|
label: props.label,
|
|
props: {
|
|
for: id.value
|
|
}
|
|
}) : props.label;
|
|
return createVNode("div", mergeProps({
|
|
"class": ["v-field", {
|
|
"v-field--active": isActive.value,
|
|
"v-field--appended": hasAppend,
|
|
"v-field--center-affix": (_a2 = props.centerAffix) != null ? _a2 : !isPlainOrUnderlined.value,
|
|
"v-field--disabled": props.disabled,
|
|
"v-field--dirty": props.dirty,
|
|
"v-field--error": props.error,
|
|
"v-field--flat": props.flat,
|
|
"v-field--has-background": !!props.bgColor,
|
|
"v-field--persistent-clear": props.persistentClear,
|
|
"v-field--prepended": hasPrepend,
|
|
"v-field--reverse": props.reverse,
|
|
"v-field--single-line": props.singleLine,
|
|
"v-field--no-label": !label(),
|
|
[`v-field--variant-${props.variant}`]: true
|
|
}, themeClasses.value, backgroundColorClasses.value, focusClasses.value, loaderClasses.value, roundedClasses.value, rtlClasses.value, props.class],
|
|
"style": [backgroundColorStyles.value, props.style],
|
|
"onClick": onClick
|
|
}, attrs), [createVNode("div", {
|
|
"class": "v-field__overlay"
|
|
}, null), createVNode(LoaderSlot, {
|
|
"name": "v-field",
|
|
"active": !!props.loading,
|
|
"color": props.error ? "error" : typeof props.loading === "string" ? props.loading : props.color
|
|
}, {
|
|
default: slots.loader
|
|
}), hasPrepend && createVNode("div", {
|
|
"key": "prepend",
|
|
"class": "v-field__prepend-inner"
|
|
}, [props.prependInnerIcon && createVNode(InputIcon, {
|
|
"key": "prepend-icon",
|
|
"name": "prependInner"
|
|
}, null), (_a = slots["prepend-inner"]) == null ? void 0 : _a.call(slots, slotProps.value)]), createVNode("div", {
|
|
"class": "v-field__field",
|
|
"data-no-activator": ""
|
|
}, [["filled", "solo", "solo-inverted", "solo-filled"].includes(props.variant) && hasLabel.value && createVNode(VFieldLabel, {
|
|
"key": "floating-label",
|
|
"ref": floatingLabelRef,
|
|
"class": [textColorClasses.value],
|
|
"floating": true,
|
|
"for": id.value,
|
|
"style": textColorStyles.value
|
|
}, {
|
|
default: () => [label()]
|
|
}), hasLabel.value && createVNode(VFieldLabel, {
|
|
"key": "label",
|
|
"ref": labelRef,
|
|
"for": id.value
|
|
}, {
|
|
default: () => [label()]
|
|
}), (_b = slots.default) == null ? void 0 : _b.call(slots, {
|
|
...slotProps.value,
|
|
props: {
|
|
id: id.value,
|
|
class: "v-field__input",
|
|
"aria-describedby": messagesId.value
|
|
},
|
|
focus,
|
|
blur
|
|
})]), hasClear && createVNode(VExpandXTransition, {
|
|
"key": "clear"
|
|
}, {
|
|
default: () => [withDirectives(createVNode("div", {
|
|
"class": "v-field__clearable",
|
|
"onMousedown": (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
}, [createVNode(VDefaultsProvider, {
|
|
"defaults": {
|
|
VIcon: {
|
|
icon: props.clearIcon
|
|
}
|
|
}
|
|
}, {
|
|
default: () => [slots.clear ? slots.clear({
|
|
...slotProps.value,
|
|
props: {
|
|
onKeydown: onKeydownClear,
|
|
onFocus: focus,
|
|
onBlur: blur,
|
|
onClick: props["onClick:clear"]
|
|
}
|
|
}) : createVNode(InputIcon, {
|
|
"name": "clear",
|
|
"onKeydown": onKeydownClear,
|
|
"onFocus": focus,
|
|
"onBlur": blur
|
|
}, null)]
|
|
})]), [[vShow, props.dirty]])]
|
|
}), hasAppend && createVNode("div", {
|
|
"key": "append",
|
|
"class": "v-field__append-inner"
|
|
}, [(_c = slots["append-inner"]) == null ? void 0 : _c.call(slots, slotProps.value), props.appendInnerIcon && createVNode(InputIcon, {
|
|
"key": "append-icon",
|
|
"name": "appendInner"
|
|
}, null)]), createVNode("div", {
|
|
"class": ["v-field__outline", textColorClasses.value],
|
|
"style": textColorStyles.value
|
|
}, [isOutlined && createVNode(Fragment, null, [createVNode("div", {
|
|
"class": "v-field__outline__start"
|
|
}, null), hasLabel.value && createVNode("div", {
|
|
"class": "v-field__outline__notch"
|
|
}, [createVNode(VFieldLabel, {
|
|
"ref": floatingLabelRef,
|
|
"floating": true,
|
|
"for": id.value
|
|
}, {
|
|
default: () => [label()]
|
|
})]), createVNode("div", {
|
|
"class": "v-field__outline__end"
|
|
}, null)]), isPlainOrUnderlined.value && hasLabel.value && createVNode(VFieldLabel, {
|
|
"ref": floatingLabelRef,
|
|
"floating": true,
|
|
"for": id.value
|
|
}, {
|
|
default: () => [label()]
|
|
})])]);
|
|
});
|
|
return {
|
|
controlRef
|
|
};
|
|
}
|
|
});
|
|
function filterFieldProps(attrs) {
|
|
const keys = Object.keys(VField.props).filter((k) => !isOn(k) && k !== "class" && k !== "style");
|
|
return pick(attrs, keys);
|
|
}
|
|
const activeTypes = ["color", "file", "time", "date", "datetime-local", "week", "month"];
|
|
const makeVTextFieldProps = propsFactory({
|
|
autofocus: Boolean,
|
|
counter: [Boolean, Number, String],
|
|
counterValue: [Number, Function],
|
|
prefix: String,
|
|
placeholder: String,
|
|
persistentPlaceholder: Boolean,
|
|
persistentCounter: Boolean,
|
|
suffix: String,
|
|
role: String,
|
|
type: {
|
|
type: String,
|
|
default: "text"
|
|
},
|
|
modelModifiers: Object,
|
|
...makeVInputProps(),
|
|
...makeVFieldProps()
|
|
}, "VTextField");
|
|
const VTextField = genericComponent()({
|
|
name: "VTextField",
|
|
directives: {
|
|
Intersect
|
|
},
|
|
inheritAttrs: false,
|
|
props: makeVTextFieldProps(),
|
|
emits: {
|
|
"click:control": (e) => true,
|
|
"mousedown:control": (e) => true,
|
|
"update:focused": (focused) => true,
|
|
"update:modelValue": (val) => true
|
|
},
|
|
setup(props, _ref) {
|
|
let {
|
|
attrs,
|
|
emit,
|
|
slots
|
|
} = _ref;
|
|
const model = useProxiedModel(props, "modelValue");
|
|
const {
|
|
isFocused,
|
|
focus,
|
|
blur
|
|
} = useFocus(props);
|
|
const counterValue = computed(() => {
|
|
var _a;
|
|
return typeof props.counterValue === "function" ? props.counterValue(model.value) : typeof props.counterValue === "number" ? props.counterValue : ((_a = model.value) != null ? _a : "").toString().length;
|
|
});
|
|
const max = computed(() => {
|
|
if (attrs.maxlength) return attrs.maxlength;
|
|
if (!props.counter || typeof props.counter !== "number" && typeof props.counter !== "string") return void 0;
|
|
return props.counter;
|
|
});
|
|
const isPlainOrUnderlined = computed(() => ["plain", "underlined"].includes(props.variant));
|
|
function onIntersect(isIntersecting, entries) {
|
|
var _a, _b;
|
|
if (!props.autofocus || !isIntersecting) return;
|
|
(_b = (_a = entries[0].target) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
|
|
}
|
|
const vInputRef = ref();
|
|
const vFieldRef = ref();
|
|
const inputRef = ref();
|
|
const isActive = computed(() => activeTypes.includes(props.type) || props.persistentPlaceholder || isFocused.value || props.active);
|
|
function onFocus() {
|
|
var _a;
|
|
if (inputRef.value !== (void 0).activeElement) {
|
|
(_a = inputRef.value) == null ? void 0 : _a.focus();
|
|
}
|
|
if (!isFocused.value) focus();
|
|
}
|
|
function onControlMousedown(e) {
|
|
emit("mousedown:control", e);
|
|
if (e.target === inputRef.value) return;
|
|
onFocus();
|
|
e.preventDefault();
|
|
}
|
|
function onControlClick(e) {
|
|
onFocus();
|
|
emit("click:control", e);
|
|
}
|
|
function onClear(e) {
|
|
e.stopPropagation();
|
|
onFocus();
|
|
nextTick(() => {
|
|
model.value = null;
|
|
callEvent(props["onClick:clear"], e);
|
|
});
|
|
}
|
|
function onInput(e) {
|
|
var _a;
|
|
const el = e.target;
|
|
model.value = el.value;
|
|
if (((_a = props.modelModifiers) == null ? void 0 : _a.trim) && ["text", "search", "password", "tel", "url"].includes(props.type)) {
|
|
const caretPosition = [el.selectionStart, el.selectionEnd];
|
|
nextTick(() => {
|
|
el.selectionStart = caretPosition[0];
|
|
el.selectionEnd = caretPosition[1];
|
|
});
|
|
}
|
|
}
|
|
useRender(() => {
|
|
const hasCounter = !!(slots.counter || props.counter !== false && props.counter != null);
|
|
const hasDetails = !!(hasCounter || slots.details);
|
|
const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
|
|
const {
|
|
modelValue: _,
|
|
...inputProps
|
|
} = VInput.filterProps(props);
|
|
const fieldProps = filterFieldProps(props);
|
|
return createVNode(VInput, mergeProps({
|
|
"ref": vInputRef,
|
|
"modelValue": model.value,
|
|
"onUpdate:modelValue": ($event) => model.value = $event,
|
|
"class": ["v-text-field", {
|
|
"v-text-field--prefixed": props.prefix,
|
|
"v-text-field--suffixed": props.suffix,
|
|
"v-input--plain-underlined": isPlainOrUnderlined.value
|
|
}, props.class],
|
|
"style": props.style
|
|
}, rootAttrs, inputProps, {
|
|
"centerAffix": !isPlainOrUnderlined.value,
|
|
"focused": isFocused.value
|
|
}), {
|
|
...slots,
|
|
default: (_ref2) => {
|
|
let {
|
|
id,
|
|
isDisabled,
|
|
isDirty,
|
|
isReadonly,
|
|
isValid
|
|
} = _ref2;
|
|
return createVNode(VField, mergeProps({
|
|
"ref": vFieldRef,
|
|
"onMousedown": onControlMousedown,
|
|
"onClick": onControlClick,
|
|
"onClick:clear": onClear,
|
|
"onClick:prependInner": props["onClick:prependInner"],
|
|
"onClick:appendInner": props["onClick:appendInner"],
|
|
"role": props.role
|
|
}, fieldProps, {
|
|
"id": id.value,
|
|
"active": isActive.value || isDirty.value,
|
|
"dirty": isDirty.value || props.dirty,
|
|
"disabled": isDisabled.value,
|
|
"focused": isFocused.value,
|
|
"error": isValid.value === false
|
|
}), {
|
|
...slots,
|
|
default: (_ref3) => {
|
|
let {
|
|
props: {
|
|
class: fieldClass,
|
|
...slotProps
|
|
}
|
|
} = _ref3;
|
|
const inputNode = withDirectives(createVNode("input", mergeProps({
|
|
"ref": inputRef,
|
|
"value": model.value,
|
|
"onInput": onInput,
|
|
"autofocus": props.autofocus,
|
|
"readonly": isReadonly.value,
|
|
"disabled": isDisabled.value,
|
|
"name": props.name,
|
|
"placeholder": props.placeholder,
|
|
"size": 1,
|
|
"type": props.type,
|
|
"onFocus": onFocus,
|
|
"onBlur": blur
|
|
}, slotProps, inputAttrs), null), [[resolveDirective("intersect"), {
|
|
handler: onIntersect
|
|
}, null, {
|
|
once: true
|
|
}]]);
|
|
return createVNode(Fragment, null, [props.prefix && createVNode("span", {
|
|
"class": "v-text-field__prefix"
|
|
}, [createVNode("span", {
|
|
"class": "v-text-field__prefix__text"
|
|
}, [props.prefix])]), slots.default ? createVNode("div", {
|
|
"class": fieldClass,
|
|
"data-no-activator": ""
|
|
}, [slots.default(), inputNode]) : cloneVNode(inputNode, {
|
|
class: fieldClass
|
|
}), props.suffix && createVNode("span", {
|
|
"class": "v-text-field__suffix"
|
|
}, [createVNode("span", {
|
|
"class": "v-text-field__suffix__text"
|
|
}, [props.suffix])])]);
|
|
}
|
|
});
|
|
},
|
|
details: hasDetails ? (slotProps) => {
|
|
var _a;
|
|
return createVNode(Fragment, null, [(_a = slots.details) == null ? void 0 : _a.call(slots, slotProps), hasCounter && createVNode(Fragment, null, [createVNode("span", null, null), createVNode(VCounter, {
|
|
"active": props.persistentCounter || isFocused.value,
|
|
"value": counterValue.value,
|
|
"max": max.value,
|
|
"disabled": props.disabled
|
|
}, slots.counter)])]);
|
|
} : void 0
|
|
});
|
|
});
|
|
return forwardRefs({}, vInputRef, vFieldRef, inputRef);
|
|
}
|
|
});
|
|
|
|
export { VForm as V, VTextField as a, VLabel as b, useFocus as c, VInput as d, makeVInputProps as e, makeVTextFieldProps as m, useForm as u };
|