init
This commit is contained in:
140
src/component/input/index.less
Normal file
140
src/component/input/index.less
Normal file
@@ -0,0 +1,140 @@
|
||||
:root {
|
||||
--input-border-radius: var(--global-border-radius);
|
||||
--input-border-color: var(--global-neutral-color-3);
|
||||
}
|
||||
|
||||
@input-lg: 44px;
|
||||
@input-md: 38px;
|
||||
@input-sm: 32px;
|
||||
@input-xs: 26px;
|
||||
|
||||
.set-size(@size) {
|
||||
& {
|
||||
height: @size;
|
||||
.layui-input {
|
||||
height: @size;
|
||||
line-height: @size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.layui-input {
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: var(--input-border-color);
|
||||
border-radius: var(--input-border-radius);
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.layui-input input{
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
padding-left: 10px;
|
||||
display: inline-block;
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.layui-input-append {
|
||||
background-color: #fafafa;
|
||||
border-left: 1px solid var(--input-border-color);
|
||||
display: flex;
|
||||
padding: 0 15px;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layui-input-prepend {
|
||||
background-color: #fafafa;
|
||||
border-right: 1px solid var(--input-border-color);
|
||||
display: flex;
|
||||
padding: 0 15px;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.layui-input-wrapper {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.layui-input:hover,
|
||||
.layui-input:focus-within {
|
||||
border-color: #d2d2d2;
|
||||
}
|
||||
|
||||
.layui-input-clear,
|
||||
.layui-input-prefix,
|
||||
.layui-input-suffix,
|
||||
.layui-input-password {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.layui-input-clear,
|
||||
.layui-input-password,
|
||||
.layui-input-prefix,
|
||||
.layui-input-suffix {
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.layui-input-has-prefix {
|
||||
input {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-input-clear,
|
||||
.layui-input-password {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.layui-input-clear:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.layui-input input::-webkit-input-placeholder {
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.layui-input input::-ms-reveal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layui-input-disabled {
|
||||
border-color: var(--input-border-color)!important;
|
||||
}
|
||||
|
||||
.layui-input-disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.layui-input-disabled,
|
||||
.layui-input-disabled * {
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
.layui-input{
|
||||
&[size="lg"] {
|
||||
.set-size(@input-lg);
|
||||
}
|
||||
&[size="md"] {
|
||||
.set-size(@input-md);
|
||||
}
|
||||
&[size="sm"] {
|
||||
.set-size(@input-sm);
|
||||
}
|
||||
&[size="xs"] {
|
||||
.set-size(@input-xs);
|
||||
}
|
||||
}
|
||||
5
src/component/input/index.ts
Normal file
5
src/component/input/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { withInstall, WithInstallType } from "../../utils";
|
||||
import Component from "./index.vue";
|
||||
|
||||
const component: WithInstallType<typeof Component> = withInstall(Component);
|
||||
export default component;
|
||||
206
src/component/input/index.vue
Normal file
206
src/component/input/index.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "LayInput",
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import "./index.less";
|
||||
import { LayIcon } from "@layui/icons-vue";
|
||||
import { computed, ref, useSlots, watch } from "vue";
|
||||
import PasswordIcon from "./svg/Password.vue";
|
||||
import UnPasswordIcon from "./svg/unPassword.vue";
|
||||
import { InputSize } from "./interface";
|
||||
|
||||
export interface InputProps {
|
||||
name?: string;
|
||||
type?: string;
|
||||
prefixIcon?: string;
|
||||
suffixIcon?: string;
|
||||
modelValue?: string | number | string[] | undefined;
|
||||
allowClear?: boolean;
|
||||
autocomplete?: string;
|
||||
placeholder?: string;
|
||||
autofocus?: boolean;
|
||||
disabled?: boolean;
|
||||
readonly?: boolean;
|
||||
password?: boolean;
|
||||
size?: InputSize;
|
||||
maxlength?: number;
|
||||
max?: number;
|
||||
min?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<InputProps>(), {
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
allowClear: false,
|
||||
autofocus: false,
|
||||
password: false,
|
||||
modelValue: "",
|
||||
size: "md",
|
||||
});
|
||||
|
||||
interface InputEmits {
|
||||
(e: "blur", event: Event): void;
|
||||
(e: "input", value: string): void;
|
||||
(e: "update:modelValue", value: string): void;
|
||||
(e: "change", value: string): void;
|
||||
(e: "focus", event: Event): void;
|
||||
(e: "clear"): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<InputEmits>();
|
||||
|
||||
const slots = useSlots();
|
||||
const type = ref(props.type);
|
||||
const currentValue = ref<string>(
|
||||
String(props.modelValue == null ? "" : props.modelValue)
|
||||
);
|
||||
const hasContent = computed(() => (props.modelValue as string)?.length > 0);
|
||||
const isPassword = computed(() => type.value == "password");
|
||||
const composing = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.type,
|
||||
() => {
|
||||
type.value = props.type;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
currentValue.value = String(
|
||||
props.modelValue == null ? "" : props.modelValue
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const onInput = function (event: Event) {
|
||||
const inputElement = event.target as HTMLInputElement;
|
||||
const value = inputElement.value;
|
||||
emit("input", value);
|
||||
if (composing.value) return;
|
||||
emit("update:modelValue", value);
|
||||
};
|
||||
|
||||
const onClear = () => {
|
||||
emit("update:modelValue", "");
|
||||
emit("clear");
|
||||
};
|
||||
|
||||
const onFocus = (event: Event) => {
|
||||
emit("focus", event);
|
||||
};
|
||||
|
||||
const onChange = (event: Event) => {
|
||||
const inputElement = event.target as HTMLInputElement;
|
||||
const value = inputElement.value;
|
||||
emit("change", value);
|
||||
};
|
||||
|
||||
const onBlur = (event: Event) => {
|
||||
if (props.type === "number") {
|
||||
onNumberBlur(event);
|
||||
}
|
||||
emit("blur", event);
|
||||
};
|
||||
|
||||
const onNumberBlur = (event: Event) => {
|
||||
let value = (event.target as HTMLInputElement).value;
|
||||
if (value === "") {
|
||||
value = props.min ? String(props.min) : "0";
|
||||
} else {
|
||||
if (props.max && props.max < Number(value)) value = props.max.toString();
|
||||
if (props.min && props.min > Number(value)) value = props.min.toString();
|
||||
}
|
||||
emit("update:modelValue", value);
|
||||
};
|
||||
|
||||
const onCompositionstart = () => {
|
||||
composing.value = true;
|
||||
};
|
||||
|
||||
const onCompositionend = (event: Event) => {
|
||||
composing.value = false;
|
||||
onInput(event);
|
||||
};
|
||||
|
||||
const classes = computed(() => {
|
||||
return {
|
||||
"layui-input-disabled": props.disabled,
|
||||
"layui-input-has-prefix": slots.prefix || props.prefixIcon,
|
||||
};
|
||||
});
|
||||
|
||||
const showPassword = () => {
|
||||
if (isPassword.value) {
|
||||
type.value = "text";
|
||||
} else {
|
||||
type.value = "password";
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layui-input" :class="classes" :size="size">
|
||||
<div class="layui-input-prepend" v-if="slots.prepend">
|
||||
<slot name="prepend"></slot>
|
||||
</div>
|
||||
<div class="layui-input-wrapper">
|
||||
<span class="layui-input-prefix" v-if="slots.prefix || props.prefixIcon">
|
||||
<slot name="prefix" v-if="slots.prefix"></slot>
|
||||
<lay-icon
|
||||
v-else
|
||||
:type="props.prefixIcon"
|
||||
class="layui-input-prefix-icon"
|
||||
></lay-icon>
|
||||
</span>
|
||||
<input
|
||||
:type="type"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:autofocus="autofocus"
|
||||
:autocomplete="autocomplete"
|
||||
:maxlength="maxlength"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:readonly="readonly"
|
||||
:value="currentValue"
|
||||
@input="onInput"
|
||||
@change="onChange"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
@compositionstart="onCompositionstart"
|
||||
@compositionend="onCompositionend"
|
||||
/>
|
||||
<span
|
||||
class="layui-input-password"
|
||||
@click="showPassword"
|
||||
v-if="password && hasContent"
|
||||
>
|
||||
<password-icon v-if="isPassword"></password-icon>
|
||||
<un-password-icon v-else></un-password-icon>
|
||||
</span>
|
||||
<span
|
||||
class="layui-input-clear"
|
||||
v-if="allowClear && hasContent && !disabled"
|
||||
>
|
||||
<lay-icon type="layui-icon-close-fill" @click.stop="onClear"></lay-icon>
|
||||
</span>
|
||||
<span class="layui-input-suffix" v-if="slots.suffix || props.suffixIcon">
|
||||
<slot name="suffix" v-if="slots.suffix"></slot>
|
||||
<lay-icon
|
||||
v-else
|
||||
:type="props.suffixIcon"
|
||||
class="layui-input-suffix-icon"
|
||||
></lay-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="layui-input-append" v-if="slots.append">
|
||||
<slot name="append"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
1
src/component/input/interface.ts
Normal file
1
src/component/input/interface.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type InputSize = "lg" | "md" | "sm" | "xs";
|
||||
19
src/component/input/svg/Password.vue
Normal file
19
src/component/input/svg/Password.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<svg
|
||||
focusable="false"
|
||||
class=""
|
||||
data-icon="eye-invisible"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
viewBox="64 64 896 896"
|
||||
>
|
||||
<path
|
||||
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
|
||||
></path>
|
||||
<path
|
||||
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
16
src/component/input/svg/unPassword.vue
Normal file
16
src/component/input/svg/unPassword.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<svg
|
||||
focusable="false"
|
||||
class=""
|
||||
data-icon="eye"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
viewBox="64 64 896 896"
|
||||
>
|
||||
<path
|
||||
d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"
|
||||
></path>
|
||||
</svg>
|
||||
</template>
|
||||
Reference in New Issue
Block a user