u
This commit is contained in:
1 parent
261a263180
commit
de2351e1b2
10 files changed
+269
-119
No files matched your search
@@ -3,3 +3,4 @@ export { default as Button } from './button'
|
|||||||
export { default as Icon } from './icon'
|
export { default as Icon } from './icon'
|
||||||
export { default as Input } from './input'
|
export { default as Input } from './input'
|
||||||
export { default as Spin } from './spin'
|
export { default as Spin } from './spin'
|
||||||
|
export { default as Textarea } from './textarea'
|
||||||
@@ -6,27 +6,16 @@ import './index.scss'
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AIcon',
|
name: 'AIcon',
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
props: {
|
||||||
icon: { type: String as PropType<string>, required: true },
|
icon: { type: String as PropType<string>, required: true },
|
||||||
size: { type: Number, default: 16 },
|
size: { type: Number, default: 16 },
|
||||||
color: { type: String, default: 'currentColor' },
|
color: { type: String, default: 'currentColor' },
|
||||||
spin: { type: Boolean, default: false },
|
spin: { type: Boolean, default: false },
|
||||||
rotate: { type: Number, default: 360 },
|
rotate: { type: Number, default: 360 },
|
||||||
onClick: Function as PropType<(e: MouseEvent) => void>, // 明确 MouseEvent 类型
|
|
||||||
},
|
},
|
||||||
setup(props, { attrs }) {
|
setup(props) {
|
||||||
const prefixCls = getPrefixCls('icon')
|
const prefixCls = getPrefixCls('icon')
|
||||||
|
|
||||||
// 安全调用 onClick
|
|
||||||
const handleClick = (e: MouseEvent) => {
|
|
||||||
props.onClick?.(e)
|
|
||||||
// 如果 attrs 上也传了 onClick,做类型断言
|
|
||||||
if (attrs.onClick) {
|
|
||||||
(attrs.onClick as (e: MouseEvent) => void)(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<i
|
<i
|
||||||
class={props.spin ? `${prefixCls}-spin` : ''}
|
class={props.spin ? `${prefixCls}-spin` : ''}
|
||||||
@@ -37,10 +26,8 @@ export default defineComponent({
|
|||||||
'color': props.color,
|
'color': props.color,
|
||||||
'--rotate-angle': `${props.rotate}deg`,
|
'--rotate-angle': `${props.rotate}deg`,
|
||||||
}}
|
}}
|
||||||
onClick={handleClick}
|
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
{...attrs}
|
|
||||||
icon={props.icon}
|
icon={props.icon}
|
||||||
width={props.size}
|
width={props.size}
|
||||||
height={props.size}
|
height={props.size}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@use './button/index.scss' as *;
|
@use './button/index.scss' as *;
|
||||||
@use './input/index.scss' as *;
|
@use './input/index.scss' as *;
|
||||||
|
@use './textarea/index.scss' as *;
|
||||||
|
|
||||||
input,
|
input,
|
||||||
button,
|
button,
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<!-- 内层保留原来的布局 -->
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 300px;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<AInput size="small" placeholder="Small 输入框" password />
|
||||||
|
|
||||||
|
<AInput
|
||||||
|
size="medium"
|
||||||
|
placeholder="Medium 输入框"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AInput
|
||||||
|
size="large"
|
||||||
|
placeholder="Large 输入框"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AInput
|
||||||
|
size="small"
|
||||||
|
placeholder="Large 输入框"
|
||||||
|
prepend="http"
|
||||||
|
append=".com"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AInput
|
||||||
|
size="medium"
|
||||||
|
placeholder="Large 输入框"
|
||||||
|
prepend="http"
|
||||||
|
append=".com"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AInput
|
||||||
|
size="large"
|
||||||
|
placeholder="Large 输入框"
|
||||||
|
prepend="http"
|
||||||
|
append=".com"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -3,16 +3,81 @@
|
|||||||
|
|
||||||
$input-prefix: #{$prefix}-input;
|
$input-prefix: #{$prefix}-input;
|
||||||
|
|
||||||
|
.#{$input-prefix}-adornment {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
&.#{$input-prefix}-size {
|
||||||
|
&-small {
|
||||||
|
height: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-medium {
|
||||||
|
height: 28px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-large {
|
||||||
|
height: 32px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$input-prefix}-adornment-prepend,
|
||||||
|
.#{$input-prefix}-adornment-append {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
color: rgba(0, 0, 0, 0.9);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
|
||||||
|
span {
|
||||||
|
white-space: nowrap;
|
||||||
|
word-break: keep-all;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$input-prefix}-adornment-prepend {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$input-prefix}-adornment-append {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$input-prefix}-wrapper {
|
||||||
|
border-radius: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :first-child {
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :last-child {
|
||||||
|
border-top-right-radius: 2px;
|
||||||
|
border-bottom-right-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.#{$input-prefix}-wrapper {
|
.#{$input-prefix}-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
|
|
||||||
|
z-index: 2;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 2px;
|
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
|
||||||
transition:
|
transition:
|
||||||
border cubic-bezier(0.38, 0, 0.24, 1) 0.2s,
|
border cubic-bezier(0.38, 0, 0.24, 1) 0.2s,
|
||||||
box-shadow cubic-bezier(0.38, 0, 0.24, 1) 0.2s,
|
box-shadow cubic-bezier(0.38, 0, 0.24, 1) 0.2s,
|
||||||
@@ -45,23 +110,6 @@ $input-prefix: #{$prefix}-input;
|
|||||||
box-shadow: $input-focus-shadow;
|
box-shadow: $input-focus-shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.#{$input-prefix}-size {
|
|
||||||
&-small {
|
|
||||||
height: 24px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-medium {
|
|
||||||
height: 28px;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-large {
|
|
||||||
height: 32px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.#{$input-prefix}-align {
|
.#{$input-prefix}-align {
|
||||||
&-left {
|
&-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@@ -119,7 +167,6 @@ $input-prefix: #{$prefix}-input;
|
|||||||
.#{$input-prefix}-clear {
|
.#{$input-prefix}-clear {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: color 0.2s;
|
transition: color 0.2s;
|
||||||
margin-left: 4px;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: red !important;
|
color: red !important;
|
||||||
@@ -132,14 +179,7 @@ $input-prefix: #{$prefix}-input;
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.#{$input-prefix}-password-toggle {
|
.#{$input-prefix}-password {
|
||||||
display: inline-flex;
|
cursor: pointer !important;
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-left: 4px;
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import { getPrefixCls } from '../_utils/getPrefixCls'
|
|||||||
import Icon from '../icon'
|
import Icon from '../icon'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'AInput',
|
name: 'Input',
|
||||||
props: {
|
props: {
|
||||||
modelValue: String,
|
modelValue: String,
|
||||||
size: {
|
size: {
|
||||||
@@ -24,6 +24,8 @@ export default defineComponent({
|
|||||||
showCount: Boolean,
|
showCount: Boolean,
|
||||||
maxlength: Number,
|
maxlength: Number,
|
||||||
password: Boolean,
|
password: Boolean,
|
||||||
|
prepend: String,
|
||||||
|
append: String,
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
setup(props, { slots, emit }) {
|
setup(props, { slots, emit }) {
|
||||||
@@ -51,65 +53,89 @@ export default defineComponent({
|
|||||||
return showPassword.value ? 'text' : 'password'
|
return showPassword.value ? 'text' : 'password'
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => (
|
const inputWrapper = () => {
|
||||||
<div
|
return (
|
||||||
class={[
|
<div
|
||||||
`${prefixCls}-wrapper`,
|
class={[
|
||||||
`${prefixCls}-size-${props.size}`,
|
`${prefixCls}-wrapper`,
|
||||||
props.disabled && `${prefixCls}-disabled`,
|
props.disabled && `${prefixCls}-disabled`,
|
||||||
props.readonly && `${prefixCls}-readonly`,
|
props.readonly && `${prefixCls}-readonly`,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{(slots.prefix || props.prefixIcon) && (
|
{(slots.prefix || props.prefixIcon) && (
|
||||||
<div class={`${prefixCls}-prefix`}>
|
<div class={`${prefixCls}-prefix`}>
|
||||||
{slots.prefix?.() ?? <Icon icon={props.prefixIcon!} size={14} />}
|
{slots.prefix?.() ?? <Icon icon={props.prefixIcon!} size={14} />}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<input
|
<input
|
||||||
class={`${prefixCls}-input ${prefixCls}-align-${props.align}`}
|
class={`${prefixCls}-input ${prefixCls}-align-${props.align}`}
|
||||||
type={inputType.value}
|
type={inputType.value}
|
||||||
value={inputValue.value}
|
value={inputValue.value}
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
readonly={props.readonly}
|
readonly={props.readonly}
|
||||||
onInput={(e: Event) => updateValue((e.target as HTMLInputElement).value)}
|
onInput={(e: Event) => updateValue((e.target as HTMLInputElement).value)}
|
||||||
/>
|
|
||||||
|
|
||||||
{props.clearable && inputValue.value && !props.disabled && !props.readonly && (
|
|
||||||
<Icon
|
|
||||||
icon="streamline:interface-delete-circle-button-delete-remove-add-circle-buttons"
|
|
||||||
class={`${prefixCls}-clear`}
|
|
||||||
onClick={() => updateValue('')}
|
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 密码切换图标 */}
|
{props.clearable && inputValue.value && !props.disabled && !props.readonly && (
|
||||||
{props.password && (
|
<span
|
||||||
<div class={`${prefixCls}-password-toggle`}>
|
class={`${prefixCls}-suffix`}
|
||||||
<Icon
|
onClick={() => updateValue('')}
|
||||||
icon="mdi:eye"
|
>
|
||||||
class={{ hidden: showPassword.value }}
|
<Icon
|
||||||
onClick={() => (showPassword.value = true)}
|
class={`${prefixCls}-clear`}
|
||||||
/>
|
icon="material-symbols:cancel-outline-rounded"
|
||||||
<Icon
|
/>
|
||||||
icon="mdi:eye-off"
|
</span>
|
||||||
class={{ hidden: !showPassword.value }}
|
|
||||||
onClick={() => (showPassword.value = false)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(slots.suffix || props.suffixIcon) && !props.password && (
|
)}
|
||||||
<div class={`${prefixCls}-suffix`}>
|
|
||||||
{slots.suffix?.() ?? <Icon icon={props.suffixIcon!} size={14} />}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{props.showCount && (
|
{/* 密码切换图标 */}
|
||||||
<span class={`${prefixCls}-count`}>{countText.value}</span>
|
{props.password && (
|
||||||
)}
|
<span
|
||||||
</div>
|
class={`${prefixCls}-suffix`}
|
||||||
)
|
onClick={() => (showPassword.value = !showPassword.value)}
|
||||||
|
>
|
||||||
|
<Icon icon={showPassword.value ? 'mage:eye-off' : 'mage:eye'} class={`${prefixCls}-password`} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(slots.suffix || props.suffixIcon) && !props.password && (
|
||||||
|
<div class={`${prefixCls}-suffix`}>
|
||||||
|
{slots.suffix?.() ?? <Icon icon={props.suffixIcon!} size={14} />}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{props.showCount && (
|
||||||
|
<span class={`${prefixCls}-count`}>{countText.value}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
return (
|
||||||
|
<div class={`${prefixCls}-adornment ${prefixCls}-size-${props.size}`}>
|
||||||
|
{props.prepend || slots.prepend
|
||||||
|
? (
|
||||||
|
<div class={`${prefixCls}-adornment-prepend`}>
|
||||||
|
{slots.prepend?.() ?? (props.prepend && <span>{props.prepend}</span>)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{inputWrapper()}
|
||||||
|
|
||||||
|
{props.append || slots.append
|
||||||
|
? (
|
||||||
|
<div class={`${prefixCls}-adornment-append`}>
|
||||||
|
{slots.append?.() ?? (props.append && <span>{props.append}</span>)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
@use '../_styles/theme/index' as *;
|
||||||
|
@use 'sass:color';
|
||||||
|
|
||||||
|
$textarea-prefix: #{$prefix}-textarea;
|
||||||
|
|
||||||
|
.#{$textarea-prefix}-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $input-hover-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
border-color: $input-focus-color;
|
||||||
|
box-shadow: $input-focus-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$textarea-prefix}-inner {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 80px; // 可根据需要
|
||||||
|
padding: 8px; // 内边距
|
||||||
|
border: none; // 去掉默认边框
|
||||||
|
outline: none;
|
||||||
|
resize: vertical;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import type { PropType } from 'vue'
|
||||||
|
import { computed, defineComponent, ref } from 'vue'
|
||||||
|
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Textarea',
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
setup() {
|
||||||
|
const prefixCls = getPrefixCls('input')
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
return (
|
||||||
|
<div class={`${prefixCls}-wrapper`}>
|
||||||
|
<textarea class={`${prefixCls}-inner`} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NButton, NInput } from 'naive-ui'
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -23,25 +22,7 @@ import { NButton, NInput } from 'naive-ui'
|
|||||||
width: 300px;
|
width: 300px;
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<AButton icon="solar:map-point-search-linear">
|
<ATextarea />
|
||||||
ABC
|
|
||||||
</AButton>
|
|
||||||
<AButton icon="solar:map-point-search-linear" />
|
|
||||||
<AInput size="small" placeholder="Small 输入框" password />
|
|
||||||
|
|
||||||
<AInput
|
|
||||||
size="medium"
|
|
||||||
placeholder="Medium 输入框"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AInput
|
|
||||||
size="large"
|
|
||||||
placeholder="Large 输入框"
|
|
||||||
suffix-icon="solar:map-point-search-linear"
|
|
||||||
>
|
|
||||||
<template #prefix />
|
|
||||||
</AInput>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -15,5 +15,6 @@ declare module 'vue' {
|
|||||||
ALoading: typeof import('@ao/ao-design')['Loading']
|
ALoading: typeof import('@ao/ao-design')['Loading']
|
||||||
ALoding: typeof import('@ao/ao-design')['Loding']
|
ALoding: typeof import('@ao/ao-design')['Loding']
|
||||||
ASpin: typeof import('@ao/ao-design')['Spin']
|
ASpin: typeof import('@ao/ao-design')['Spin']
|
||||||
|
ATextarea: typeof import('@ao/ao-design')['Textarea']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user