u
This commit is contained in:
1 parent
14f9844430
commit
785bce1907
27 files changed
+1051
-175
No files matched your search
@@ -13,30 +13,48 @@ $default-color-hover: var(--ao-default-color-hover); // hover态
|
||||
$default-color-focus: var(--ao-default-color-focus); // focus态,包括鼠标和键盘
|
||||
$default-color-active: var(--ao-default-color-active); // 点击态
|
||||
$default-color-disabled: var(--ao-default-color-disabled); // 禁用态
|
||||
$default-color-light: var(--ao-default-color-light);
|
||||
$default-color-light-active: var(--ao-default-color-light-active);
|
||||
|
||||
// 基础颜色的扩展 用于 hover / 聚焦 / 禁用 / 点击 等状态
|
||||
$primary-color-hover: var(--ao-primary-color-hover); // hover态
|
||||
$primary-color-focus: var(--ao-primary-color-focus); // focus态,包括鼠标和键盘
|
||||
$primary-color-active: var(--ao-primary-color-active); // 点击态
|
||||
$primary-color-disabled: var(--ao-primary-color-disabled); // 禁用态
|
||||
$primary-color-light: var(--ao-primary-color-light);
|
||||
$primary-color-light-active: var(--ao-primary-color-light-active);
|
||||
|
||||
// 警告色扩展
|
||||
$warning-color-hover: var(--ao-warning-color-hover);
|
||||
$warning-color-focus: var(--ao-warning-color-focus);
|
||||
$warning-color-active: var(--ao-warning-color-active);
|
||||
$warning-color-disabled: var(--ao-warning-color-disabled);
|
||||
$warning-color-light: var(--ao-warning-color-light);
|
||||
$warning-color-light-active: var(--ao-warning-color-light-active);
|
||||
|
||||
// 失败/错误色扩展
|
||||
$danger-color-hover: var(--ao-danger-color-hover);
|
||||
$danger-color-focus: var(--ao-danger-color-focus);
|
||||
$danger-color-active: var(--ao-danger-color-active);
|
||||
$danger-color-disabled: var(--ao-danger-color-disabled);
|
||||
$danger-color-light: var(--ao-danger-color-light);
|
||||
$danger-color-light-active: var(--ao-danger-color-light-active);
|
||||
|
||||
// 成功色扩展
|
||||
$success-color-hover: var(--ao-success-color-hover);
|
||||
$success-color-focus: var(--ao-success-color-focus);
|
||||
$success-color-active: var(--ao-success-color-active);
|
||||
$success-color-disabled: var(--ao-success-color-disabled);
|
||||
$success-color-light: var(--ao-success-color-light);
|
||||
$success-color-light-active: var(--ao-success-color-light-active);
|
||||
|
||||
// 状态背景色
|
||||
$status-base-bg-color: var(--ao-status-base-bg-color);
|
||||
$status-anti-bg-color: var(--ao-status-anti-bg-color);
|
||||
$status-info-bg-color: var(--ao-status-info-bg-color);
|
||||
$status-success-bg-color: var(--ao-status-success-bg-color);
|
||||
$status-warning-bg-color: var(--ao-status-warning-bg-color);
|
||||
$status-danger-bg-color: var(--ao-status-danger-bg-color);
|
||||
|
||||
// 文本颜色
|
||||
$text-color-base: var(--ao-text-color-base); // 色彩-文字-主要
|
||||
|
||||
@@ -9,26 +9,43 @@
|
||||
--ao-default-color-focus: #505050;
|
||||
--ao-default-color-active: #5c5c5c;
|
||||
--ao-default-color-disabled: #2c2c2c;
|
||||
--ao-default-color-light: #f3f3f3;
|
||||
--ao-default-color-light-active: #ddd;
|
||||
|
||||
--ao-primary-color-hover: #2667d4;
|
||||
--ao-primary-color-focus: #173463;
|
||||
--ao-primary-color-active: #699ef5;
|
||||
--ao-primary-color-disabled: #143975;
|
||||
--ao-primary-color-light: #1b2f51;
|
||||
--ao-primary-color-light-active: #173463;
|
||||
|
||||
--ao-warning-color-hover: #a75d2b;
|
||||
--ao-warning-color-focus: #582f21;
|
||||
--ao-warning-color-active: #dc7633;
|
||||
--ao-warning-color-disabled: #733c23;
|
||||
--ao-warning-color-light: #4f2a1d;
|
||||
--ao-warning-color-light-active: #582f21;
|
||||
|
||||
--ao-danger-color-hover: #a03f46;
|
||||
--ao-danger-color-focus: #5e2a2d;
|
||||
--ao-danger-color-active: #de6670;
|
||||
--ao-danger-color-disabled: #703439;
|
||||
--ao-danger-color-light: #472324;
|
||||
--ao-danger-color-light-active: #5e2a2d;
|
||||
|
||||
--ao-success-color-hover: #0d7a55;
|
||||
--ao-success-color-focus: #1a4230;
|
||||
--ao-success-color-active: #43af8a;
|
||||
--ao-success-color-disabled: #17533d;
|
||||
--ao-success-color-light: #193a2a;
|
||||
--ao-success-color-light-active: #1a4230;
|
||||
|
||||
--ao-status-base-bg-color: #242424;
|
||||
--ao-status-anti-bg-color: #c6cacd; // 反色,用于tooltip默认背景色
|
||||
--ao-status-info-bg-color: #233448;
|
||||
--ao-status-success-bg-color: #253929;
|
||||
--ao-status-warning-bg-color: #453522;
|
||||
--ao-status-danger-bg-color: #442927;
|
||||
|
||||
--ao-text-color-base: rgba(255, 255, 255, 90%); /* 主要文字 */
|
||||
--ao-text-color-secondary: rgba(255, 255, 255, 55%); /* 次要文字 / 辅助信息 */
|
||||
@@ -60,10 +77,9 @@
|
||||
// 基础/下层 投影 hover 使用的组件包括:表格 /
|
||||
--ao-shadow-surface: 0 4px 6px rgba(0, 0, 0, 6%), 0 1px 10px rgba(0, 0, 0, 8%), 0 2px 4px rgba(0, 0, 0, 12%);
|
||||
// 中层投影 下拉 使用的组件包括:下拉菜单 / 气泡确认框 / 选择器 /
|
||||
--ao-shadow-popup: 0 8px 10px rgba(0, 0, 0, 12%), 0 3px 14px rgba(0, 0, 0, 10%), 0 5px 5px rgba(0, 0, 0, 16%);
|
||||
--ao-shadow-popup: 0 0 4px rgba(0, 0, 0, 0.04), 0 0 8px rgba(0, 0, 0, 0.03);
|
||||
// 上层投影(警示/弹窗)使用的组件包括:全局提示 / 消息通知
|
||||
--ao-shadow-overlay: 0 16px 24px rgba(0, 0, 0, 14%), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%);
|
||||
|
||||
--ao-shadow-overlay: inset 0 0 0 1px hsla(0, 0%, 100%, 0.1), 0 4px 14px rgba(0, 0, 0, 0.25);
|
||||
// 内投影
|
||||
--ao-shadow-inset-top: inset 0 0.5px 0 #5e5e5e;
|
||||
--ao-shadow-inset-right: inset 0.5px 0 0 #5e5e5e;
|
||||
|
||||
@@ -10,26 +10,43 @@
|
||||
--ao-default-color-focus: #cfcfcf;
|
||||
--ao-default-color-active: #ababab;
|
||||
--ao-default-color-disabled: #eeeeee;
|
||||
--ao-default-color-light: #f3f3f3;
|
||||
--ao-default-color-light-active: #ddd;
|
||||
|
||||
--ao-primary-color-hover: #366ef4;
|
||||
--ao-primary-color-focus: #d9e1ff;
|
||||
--ao-primary-color-active: #003cab;
|
||||
--ao-primary-color-disabled: #b5c7ff;
|
||||
--ao-primary-color-light: #f2f3ff;
|
||||
--ao-primary-color-light-active: #d9e1ff;
|
||||
|
||||
--ao-warning-color-hover: #fa9550;
|
||||
--ao-warning-color-focus: #ffd9c2;
|
||||
--ao-warning-color-active: #be5a00;
|
||||
--ao-warning-color-disabled: #ffb98c;
|
||||
--ao-warning-color-light: #fff1e9;
|
||||
--ao-warning-color-light-active: #ffd9c2;
|
||||
|
||||
--ao-danger-color-hover: #f6685d;
|
||||
--ao-danger-color-focus: #ffd8d2;
|
||||
--ao-danger-color-active: #ad352f;
|
||||
--ao-danger-color-disabled: #ffb9b0;
|
||||
--ao-danger-color-light: #fff0ed;
|
||||
--ao-danger-color-light-active: #ffd8d2;
|
||||
|
||||
--ao-success-color-hover: #56c08d;
|
||||
--ao-success-color-focus: #c6f3d7;
|
||||
--ao-success-color-active: #008858;
|
||||
--ao-success-color-disabled: #92dab2;
|
||||
--ao-success-color-light: #e3f9e9;
|
||||
--ao-success-color-light-active: #c6f3d7;
|
||||
|
||||
--ao-status-base-bg-color: #fff;
|
||||
--ao-status-anti-bg-color: #41464c; // 反色,用于tooltip默认背景色
|
||||
--ao-status-info-bg-color: #f2f3ff;
|
||||
--ao-status-success-bg-color: #ecf7ec;
|
||||
--ao-status-warning-bg-color: #fff8ea;
|
||||
--ao-status-danger-bg-color: #fef2ed;
|
||||
|
||||
--ao-text-color-base: rgba(0, 0, 0, 90%); /* 主要文字 */
|
||||
--ao-text-color-secondary: rgba(0, 0, 0, 60%); /* 次要文字 / 辅助信息 */
|
||||
@@ -61,13 +78,10 @@
|
||||
// 基础/下层 投影 hover 使用的组件包括:表格 /
|
||||
--ao-shadow-surface: 0 1px 10px rgba(0, 0, 0, 5%), 0 4px 5px rgba(0, 0, 0, 8%), 0 2px 4px -1px rgba(0, 0, 0, 12%);
|
||||
// 中层投影 下拉 使用的组件包括:下拉菜单 / 气泡确认框 / 选择器 /
|
||||
--ao-shadow-popup:
|
||||
0 3px 14px 2px rgba(0, 0, 0, 5%), 0 8px 10px 1px rgba(0, 0, 0, 6%), 0 5px 5px -3px rgba(0, 0, 0, 10%);
|
||||
// 上层投影(警示/弹窗)使用的组件包括:全局提示 / 消息通知
|
||||
--ao-shadow-overlay:
|
||||
0 6px 30px 5px rgba(0, 0, 0, 5%), 0 16px 24px 2px rgba(0, 0, 0, 4%), 0 8px 10px -5px rgba(0, 0, 0, 8%);
|
||||
--ao-shadow-popup: 0 0 4px rgba(0, 0, 0, 0.04), 0 0 8px rgba(0, 0, 0, 0.03);
|
||||
|
||||
// 内投影
|
||||
// 上层投影(警示/弹窗)使用的组件包括:全局提示 / 消息通知
|
||||
--ao-shadow-overlay: 0 0 1px rgba(0, 0, 0, 0.3), 0 4px 14px rgba(0, 0, 0, 0.1);
|
||||
--ao-shadow-inset-top: inset 0 0.5px 0 #dcdcdc;
|
||||
--ao-shadow-inset-right: inset 0.5px 0 0 #dcdcdc;
|
||||
--ao-shadow-inset-bottom: inset 0 -0.5px 0 #dcdcdc;
|
||||
|
||||
@@ -7,4 +7,7 @@ export { default as Input } from './input'
|
||||
export { default as Popconfirm } from './popconfirm'
|
||||
export { default as Popup } from './popup'
|
||||
export { default as Spin } from './spin'
|
||||
export { default as Tag } from './tag'
|
||||
export { default as TagGroup } from './tag-group'
|
||||
export { default as Textarea } from './textarea'
|
||||
export { default as Tooltip } from './tooltip'
|
||||
@@ -10,3 +10,6 @@
|
||||
@use './message/index.scss' as *;
|
||||
@use './notification/index.scss' as *;
|
||||
@use './drawer/index.scss' as *;
|
||||
@use './tooltip/index.scss' as *;
|
||||
@use './tag/index.scss' as *;
|
||||
@use './tag-group/index.scss' as *;
|
||||
@@ -21,6 +21,8 @@ function showMessageType(type: any) {
|
||||
message.success({
|
||||
message: `这里是 ${type} 提示`,
|
||||
type,
|
||||
duration: 0,
|
||||
theme: 'light',
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -76,6 +78,9 @@ function showMessageType(type: any) {
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<AButton status="primary" @click="showMessageType('default')">
|
||||
default
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showMessageType('info')">
|
||||
info
|
||||
</AButton>
|
||||
@@ -85,7 +90,7 @@ function showMessageType(type: any) {
|
||||
<AButton status="primary" @click="showMessageType('warning')">
|
||||
warning
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showMessageType('error')">
|
||||
<AButton status="primary" @click="showMessageType('danger')">
|
||||
error
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showMessageType('loading')">
|
||||
|
||||
@@ -47,22 +47,34 @@ $message-prefix: #{$prefix}-message;
|
||||
}
|
||||
|
||||
&-info {
|
||||
color: $primary-color;
|
||||
.#{$message-prefix}-icon {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
&-success {
|
||||
color: $success-color;
|
||||
.#{$message-prefix}-icon {
|
||||
color: $success-color;
|
||||
}
|
||||
}
|
||||
&-warning {
|
||||
color: $warning-color;
|
||||
.#{$message-prefix}-icon {
|
||||
color: $warning-color;
|
||||
}
|
||||
}
|
||||
&-error {
|
||||
color: $danger-color;
|
||||
&-danger {
|
||||
.#{$message-prefix}-icon {
|
||||
color: $danger-color;
|
||||
}
|
||||
}
|
||||
&-question {
|
||||
color: $primary-color;
|
||||
.#{$message-prefix}-icon {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
&-loading {
|
||||
color: $primary-color;
|
||||
.#{$message-prefix}-icon {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
&-placement {
|
||||
&-top {
|
||||
@@ -128,3 +140,27 @@ $message-prefix: #{$prefix}-message;
|
||||
}
|
||||
}
|
||||
}
|
||||
.#{$message-prefix}-theme-normal.#{$message-prefix} {
|
||||
background-color: $status-base-bg-color;
|
||||
}
|
||||
.#{$message-prefix}-theme-light.#{$message-prefix}-default {
|
||||
background-color: $status-base-bg-color;
|
||||
}
|
||||
.#{$message-prefix}-theme-light.#{$message-prefix}-info {
|
||||
background-color: $status-info-bg-color;
|
||||
}
|
||||
.#{$message-prefix}-theme-light.#{$message-prefix}-success {
|
||||
background-color: $status-success-bg-color;
|
||||
}
|
||||
.#{$message-prefix}-theme-light.#{$message-prefix}-warning {
|
||||
background-color: $status-warning-bg-color;
|
||||
}
|
||||
.#{$message-prefix}-theme-light.#{$message-prefix}-danger {
|
||||
background-color: $status-danger-bg-color;
|
||||
}
|
||||
.#{$message-prefix}-theme-light.#{$message-prefix}-loading {
|
||||
background-color: $status-info-bg-color;
|
||||
}
|
||||
.#{$message-prefix}-theme-light.#{$message-prefix}-question {
|
||||
background-color: $status-info-bg-color;
|
||||
}
|
||||
@@ -14,11 +14,13 @@ type Placement
|
||||
| 'bottom-end'
|
||||
| 'center'
|
||||
|
||||
type MessageType = 'info' | 'success' | 'warning' | 'error' | 'loading' | 'question'
|
||||
type MessageType = 'default' | 'info' | 'success' | 'warning' | 'danger' | 'loading' | 'question'
|
||||
type MessageTheme = 'normal' | 'light'
|
||||
|
||||
interface MessageOptions {
|
||||
message: string | VNode | (() => VNode)
|
||||
type?: MessageType
|
||||
theme?: MessageTheme
|
||||
placement?: Placement
|
||||
duration?: number
|
||||
showClose?: boolean
|
||||
@@ -30,10 +32,11 @@ interface MessageHandle {
|
||||
|
||||
interface MessageFn {
|
||||
(msg: string | MessageOptions): MessageHandle
|
||||
open: (msg: string | MessageOptions) => MessageHandle
|
||||
info: (msg: string | MessageOptions) => MessageHandle
|
||||
success: (msg: string | MessageOptions) => MessageHandle
|
||||
warning: (msg: string | MessageOptions) => MessageHandle
|
||||
error: (msg: string | MessageOptions) => MessageHandle
|
||||
danger: (msg: string | MessageOptions) => MessageHandle
|
||||
closeAll: () => void
|
||||
}
|
||||
|
||||
@@ -68,13 +71,13 @@ function getTransform(placement: Placement, hidden: boolean) {
|
||||
export function useMessage(): MessageFn {
|
||||
const createMessage = (
|
||||
msg: string | MessageOptions,
|
||||
defaultType: MessageType = 'info',
|
||||
defaultType: MessageType = 'default',
|
||||
): MessageHandle => {
|
||||
const opts: MessageOptions = typeof msg === 'string'
|
||||
? { message: msg, type: defaultType }
|
||||
: { ...msg, type: msg.type || defaultType }
|
||||
|
||||
const { message, type, placement = 'top', duration = 3000, showClose } = opts
|
||||
const { message, type, theme, placement = 'top', duration = 3000, showClose } = opts
|
||||
const container = getContainer(placement)
|
||||
let timer: number | undefined
|
||||
let handle: MessageHandle
|
||||
@@ -83,6 +86,7 @@ export function useMessage(): MessageFn {
|
||||
render() {
|
||||
return h(MessageItem, {
|
||||
type,
|
||||
theme,
|
||||
message,
|
||||
placement,
|
||||
showClose,
|
||||
@@ -140,10 +144,11 @@ export function useMessage(): MessageFn {
|
||||
}
|
||||
|
||||
const api = ((msg: string | MessageOptions) => createMessage(msg)) as MessageFn
|
||||
api.open = msg => createMessage(msg, 'default')
|
||||
api.info = msg => createMessage(msg, 'info')
|
||||
api.success = msg => createMessage(msg, 'success')
|
||||
api.warning = msg => createMessage(msg, 'warning')
|
||||
api.error = msg => createMessage(msg, 'error')
|
||||
api.danger = msg => createMessage(msg, 'danger')
|
||||
api.closeAll = () => {
|
||||
instances.slice().forEach(instance => instance.close())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ const prefixCls = getPrefixCls('message')
|
||||
export default defineComponent({
|
||||
name: 'MessageItem',
|
||||
props: {
|
||||
type: { type: String, default: 'info' },
|
||||
type: { type: String, default: 'default' },
|
||||
theme: { type: String, default: 'normal' },
|
||||
message: {
|
||||
type: [String, Object, Function] as unknown as () => string | VNode | (() => VNode),
|
||||
required: true,
|
||||
@@ -23,7 +24,7 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const iconMap: Record<string, string> = {
|
||||
success: 'ix:success-filled',
|
||||
error: 'ix:error-filled',
|
||||
danger: 'ix:error-filled',
|
||||
warning: 'ix:warning-filled',
|
||||
info: 'ix:info-filled',
|
||||
question: 'ix:question-filled',
|
||||
@@ -36,14 +37,16 @@ export default defineComponent({
|
||||
}
|
||||
return () => (
|
||||
<div
|
||||
class={`${prefixCls}`}
|
||||
class={`${prefixCls} ${prefixCls}-theme-${props.theme ?? 'normal'} ${prefixCls}-${props.type ?? 'default'}`}
|
||||
>
|
||||
<Icon
|
||||
icon={iconMap[props.type ?? 'info']}
|
||||
size={20}
|
||||
class={`${prefixCls}-icon ${prefixCls}-${props.type ?? 'info'}`}
|
||||
spin={props.type === 'loading'}
|
||||
/>
|
||||
{props.type !== 'default' && (
|
||||
<Icon
|
||||
icon={iconMap[props.type ?? 'info']}
|
||||
size={20}
|
||||
class={`${prefixCls}-icon`}
|
||||
spin={props.type === 'loading'}
|
||||
/>
|
||||
)}
|
||||
<span class={`${prefixCls}-message`}>
|
||||
{renderMessage(props.message)}
|
||||
</span>
|
||||
|
||||
@@ -1,59 +1,85 @@
|
||||
<script setup lang="ts">
|
||||
import { useNotification } from '@ao/ao-design'
|
||||
import { h } from 'vue'
|
||||
|
||||
const notification = useNotification()
|
||||
|
||||
function showCustomMessage() {
|
||||
function showNotification(placement: any) {
|
||||
notification.success({
|
||||
title: '自定义消息',
|
||||
message: () =>
|
||||
h('div', { style: { color: 'red', position: 'relative' } }, [
|
||||
h('p', {}, '这里是自定义内容,可以是任意 VNode'),
|
||||
h('strong', {}, '加粗文本'),
|
||||
// 右下角按钮容器
|
||||
h(
|
||||
'div',
|
||||
{
|
||||
style: {
|
||||
position: 'absolute',
|
||||
bottom: '4px',
|
||||
right: '4px',
|
||||
display: 'flex',
|
||||
gap: '4px',
|
||||
},
|
||||
},
|
||||
[
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
style: { fontSize: '12px', padding: '2px 6px' },
|
||||
onClick: () => alert('Button A clicked'),
|
||||
},
|
||||
'A',
|
||||
),
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
style: { fontSize: '12px', padding: '2px 6px' },
|
||||
onClick: () => alert('Button B clicked'),
|
||||
},
|
||||
'B',
|
||||
),
|
||||
],
|
||||
),
|
||||
]),
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
title: `这里是 ${placement} 标题`,
|
||||
message: `这里是 ${placement} 提示`,
|
||||
placement,
|
||||
})
|
||||
}
|
||||
function closeOne() {
|
||||
|
||||
}
|
||||
|
||||
function showNotificationType(type: any) {
|
||||
notification.success({
|
||||
theme: 'light',
|
||||
title: `这里是 ${type} 标题`,
|
||||
message: `这里是 ${type} 提示`,
|
||||
type,
|
||||
duration: 0,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="demo">
|
||||
<AButton status="primary" @click="showCustomMessage">
|
||||
自定义 h 函数消息
|
||||
</AButton>
|
||||
<div class="row">
|
||||
<AButton status="primary" @click="showNotification('top-start')">
|
||||
Top Start
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotification('top-end')">
|
||||
Top End
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<AButton status="primary" @click="showNotification('bottom-start')">
|
||||
Bottom Start
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotification('bottom-end')">
|
||||
Bottom End
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<AButton status="primary" @click="notification.closeAll">
|
||||
Close All
|
||||
</AButton>
|
||||
|
||||
<AButton
|
||||
status="primary" @click="closeOne"
|
||||
>
|
||||
Show No Close
|
||||
</AButton>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<AButton status="primary" @click="showNotificationType('default')">
|
||||
default
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotificationType('info')">
|
||||
info
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotificationType('success')">
|
||||
success
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotificationType('warning')">
|
||||
warning
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotificationType('danger')">
|
||||
error
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotificationType('loading')">
|
||||
loading
|
||||
</AButton>
|
||||
<AButton status="primary" @click="showNotificationType('question')">
|
||||
question
|
||||
</AButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -65,4 +91,9 @@ function showCustomMessage() {
|
||||
gap: 16px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -24,7 +24,6 @@ $notification-prefix: #{$prefix}-notification;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
background-color: #ecf7ec;
|
||||
|
||||
&-icon {
|
||||
text-align: center;
|
||||
@@ -47,8 +46,6 @@ $notification-prefix: #{$prefix}-notification;
|
||||
&-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
|
||||
small {
|
||||
margin: 0px 6px;
|
||||
font-size: 14px;
|
||||
@@ -76,26 +73,35 @@ $notification-prefix: #{$prefix}-notification;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
}
|
||||
|
||||
&-info {
|
||||
color: $primary-color;
|
||||
.#{$notification-prefix}-icon {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
&-success {
|
||||
color: $success-color;
|
||||
.#{$notification-prefix}-icon {
|
||||
color: $success-color;
|
||||
}
|
||||
}
|
||||
&-warning {
|
||||
color: $warning-color;
|
||||
.#{$notification-prefix}-icon {
|
||||
color: $warning-color;
|
||||
}
|
||||
}
|
||||
&-error {
|
||||
color: $danger-color;
|
||||
&-danger {
|
||||
.#{$notification-prefix}-icon {
|
||||
color: $danger-color;
|
||||
}
|
||||
}
|
||||
&-question {
|
||||
color: $primary-color;
|
||||
.#{$notification-prefix}-icon {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
&-loading {
|
||||
color: $primary-color;
|
||||
.#{$notification-prefix}-icon {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-placement {
|
||||
@@ -125,3 +131,27 @@ $notification-prefix: #{$prefix}-notification;
|
||||
}
|
||||
}
|
||||
}
|
||||
.#{$notification-prefix}-theme-normal.#{$notification-prefix} {
|
||||
background-color: $status-base-bg-color;
|
||||
}
|
||||
.#{$notification-prefix}-theme-light.#{$notification-prefix}-default {
|
||||
background-color: $status-base-bg-color;
|
||||
}
|
||||
.#{$notification-prefix}-theme-light.#{$notification-prefix}-info {
|
||||
background-color: $status-info-bg-color;
|
||||
}
|
||||
.#{$notification-prefix}-theme-light.#{$notification-prefix}-success {
|
||||
background-color: $status-success-bg-color;
|
||||
}
|
||||
.#{$notification-prefix}-theme-light.#{$notification-prefix}-warning {
|
||||
background-color: $status-warning-bg-color;
|
||||
}
|
||||
.#{$notification-prefix}-theme-light.#{$notification-prefix}-danger {
|
||||
background-color: $status-danger-bg-color;
|
||||
}
|
||||
.#{$notification-prefix}-theme-light.#{$notification-prefix}-loading {
|
||||
background-color: $status-info-bg-color;
|
||||
}
|
||||
.#{$notification-prefix}-theme-light.#{$notification-prefix}-question {
|
||||
background-color: $status-info-bg-color;
|
||||
}
|
||||
@@ -9,13 +9,14 @@ type Placement
|
||||
| 'bottom-start'
|
||||
| 'bottom-end'
|
||||
|
||||
type NotificationType = 'info' | 'success' | 'warning' | 'error' | 'loading' | 'question'
|
||||
type NotificationType = 'default' | 'info' | 'success' | 'warning' | 'danger' | 'loading' | 'question'
|
||||
type NotificationTheme = 'normal' | 'light'
|
||||
|
||||
interface NotificationOptions {
|
||||
message: string | VNode | (() => VNode)
|
||||
|
||||
title: string
|
||||
subTitle?: string
|
||||
theme?: NotificationTheme
|
||||
type?: NotificationType
|
||||
placement?: Placement
|
||||
duration?: number
|
||||
@@ -28,10 +29,11 @@ interface NotificationHandle {
|
||||
|
||||
interface MessageFn {
|
||||
(msg: NotificationOptions): NotificationHandle
|
||||
open: (msg: NotificationOptions) => NotificationHandle
|
||||
info: (msg: NotificationOptions) => NotificationHandle
|
||||
success: (msg: NotificationOptions) => NotificationHandle
|
||||
warning: (msg: NotificationOptions) => NotificationHandle
|
||||
error: (msg: NotificationOptions) => NotificationHandle
|
||||
danger: (msg: NotificationOptions) => NotificationHandle
|
||||
closeAll: () => void
|
||||
}
|
||||
|
||||
@@ -65,9 +67,9 @@ function getTransform(placement: Placement, hidden: boolean) {
|
||||
export function useNotification(): MessageFn {
|
||||
const createNotification = (
|
||||
opts: NotificationOptions,
|
||||
defaultType: NotificationType = 'info',
|
||||
defaultType: NotificationType = 'default',
|
||||
): NotificationHandle => {
|
||||
const { message, title, subTitle, type = defaultType, placement = 'top-end', duration = 3000, showClose } = opts
|
||||
const { message, title, subTitle, type = defaultType, theme, placement = 'top-end', duration = 3000, showClose } = opts
|
||||
|
||||
const container = getContainer(placement)
|
||||
let timer: number | undefined
|
||||
@@ -77,6 +79,7 @@ export function useNotification(): MessageFn {
|
||||
render() {
|
||||
return h(MessageItem, {
|
||||
type,
|
||||
theme,
|
||||
title,
|
||||
subTitle,
|
||||
message,
|
||||
@@ -136,10 +139,11 @@ export function useNotification(): MessageFn {
|
||||
}
|
||||
|
||||
const api = ((msg: NotificationOptions) => createNotification(msg)) as MessageFn
|
||||
api.open = msg => createNotification(msg, 'default')
|
||||
api.info = msg => createNotification(msg, 'info')
|
||||
api.success = msg => createNotification(msg, 'success')
|
||||
api.warning = msg => createNotification(msg, 'warning')
|
||||
api.error = msg => createNotification(msg, 'error')
|
||||
api.danger = msg => createNotification(msg, 'danger')
|
||||
api.closeAll = () => {
|
||||
instances.slice().forEach(instance => instance.close())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@ const prefixCls = getPrefixCls('notification')
|
||||
export default defineComponent({
|
||||
name: 'NotificationItem',
|
||||
props: {
|
||||
type: { type: String, default: 'info' },
|
||||
type: { type: String, default: 'default' },
|
||||
theme: { type: String, default: 'normal' },
|
||||
title: { type: String, required: true },
|
||||
message: {
|
||||
type: [String, Object, Function] as unknown as () => string | VNode | (() => VNode),
|
||||
@@ -25,7 +26,7 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const iconMap: Record<string, string> = {
|
||||
success: 'ix:success-filled',
|
||||
error: 'ix:error-filled',
|
||||
danger: 'ix:error-filled',
|
||||
warning: 'ix:warning-filled',
|
||||
info: 'ix:info-filled',
|
||||
question: 'ix:question-filled',
|
||||
@@ -38,15 +39,16 @@ export default defineComponent({
|
||||
}
|
||||
return () => (
|
||||
<div
|
||||
class={`${prefixCls}`}
|
||||
class={`${prefixCls} ${prefixCls}-theme-${props.theme ?? 'normal'} ${prefixCls}-${props.type ?? 'info'}`}
|
||||
>
|
||||
<Icon
|
||||
icon={iconMap[props.type ?? 'info']}
|
||||
size={22}
|
||||
class={`${prefixCls}-icon ${prefixCls}-${props.type ?? 'info'}`}
|
||||
spin={props.type === 'loading'}
|
||||
/>
|
||||
|
||||
{props.type !== 'default' && (
|
||||
<Icon
|
||||
icon={iconMap[props.type ?? 'info']}
|
||||
size={22}
|
||||
class={`${prefixCls}-icon`}
|
||||
spin={props.type === 'loading'}
|
||||
/>
|
||||
)}
|
||||
<div class={`${prefixCls}-main`}>
|
||||
<div class={`${prefixCls}-title-wrapper`}>
|
||||
<span class={`${prefixCls}-title`}>
|
||||
|
||||
@@ -23,14 +23,16 @@ $popup-prefix: '#{$prefix}-popup';
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: $bg-color-container;
|
||||
background-color: $bg-color-container;
|
||||
transform: rotate(45deg);
|
||||
transform-origin: center;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
// 上方弹出,箭头在底部
|
||||
&[data-popup-placement^='top'] > &-arrow {
|
||||
bottom: -4px;
|
||||
|
||||
@@ -53,11 +53,11 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
popupClass: {
|
||||
class: {
|
||||
type: [String, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
popupStyle: {
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
@@ -65,6 +65,8 @@ export default defineComponent({
|
||||
type: [String, Object, Function] as unknown as () => string | VNode | (() => VNode),
|
||||
default: '',
|
||||
},
|
||||
showDelay: { type: Number, default: 0 },
|
||||
hideDelay: { type: Number, default: 0 },
|
||||
},
|
||||
emits: ['update:visible'],
|
||||
setup(props, { slots, emit }) {
|
||||
@@ -75,6 +77,10 @@ export default defineComponent({
|
||||
const arrowRef = ref<HTMLElement | null>(null) // 箭头引用
|
||||
const localVisible = ref(props.visible)
|
||||
const hasRendered = ref(props.visible)
|
||||
// 定时器
|
||||
let showTimer: number | null = null
|
||||
let hideTimer: number | null = null
|
||||
|
||||
let cleanup: (() => void) | null = null
|
||||
|
||||
const { floatingStyles, middlewareData, placement, update } = useFloating(
|
||||
@@ -135,43 +141,65 @@ export default defineComponent({
|
||||
floatEl.style.width = `${triggerEl.offsetWidth}px`
|
||||
}
|
||||
|
||||
const clearTimers = () => {
|
||||
if (showTimer) {
|
||||
clearTimeout(showTimer)
|
||||
showTimer = null
|
||||
}
|
||||
if (hideTimer) {
|
||||
clearTimeout(hideTimer)
|
||||
hideTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
const showPopup = async () => {
|
||||
if (!hasRendered.value)
|
||||
hasRendered.value = true
|
||||
await nextTick()
|
||||
clearTimers()
|
||||
showTimer = window.setTimeout(async () => {
|
||||
if (!hasRendered.value)
|
||||
hasRendered.value = true
|
||||
await nextTick()
|
||||
|
||||
fitFloatingWidth()
|
||||
localVisible.value = true
|
||||
|
||||
setupAutoUpdate()
|
||||
emit('update:visible', true)
|
||||
fitFloatingWidth()
|
||||
localVisible.value = true
|
||||
setupAutoUpdate()
|
||||
emit('update:visible', true)
|
||||
}, props.showDelay)
|
||||
}
|
||||
|
||||
const hidePopup = async () => {
|
||||
localVisible.value = false
|
||||
|
||||
clearAutoUpdate()
|
||||
emit('update:visible', false)
|
||||
clearTimers()
|
||||
hideTimer = window.setTimeout(() => {
|
||||
localVisible.value = false
|
||||
clearAutoUpdate()
|
||||
emit('update:visible', false)
|
||||
}, props.hideDelay)
|
||||
}
|
||||
|
||||
const togglePopup = async () => {
|
||||
clearTimers()
|
||||
|
||||
if (!hasRendered.value)
|
||||
hasRendered.value = true
|
||||
await nextTick()
|
||||
|
||||
fitFloatingWidth()
|
||||
|
||||
localVisible.value = !localVisible.value
|
||||
await nextTick()
|
||||
|
||||
if (localVisible.value) {
|
||||
setupAutoUpdate()
|
||||
if (!localVisible.value) {
|
||||
// 需要显示
|
||||
showTimer = window.setTimeout(async () => {
|
||||
localVisible.value = true
|
||||
await nextTick()
|
||||
setupAutoUpdate()
|
||||
emit('update:visible', true)
|
||||
}, props.showDelay)
|
||||
}
|
||||
else {
|
||||
clearAutoUpdate()
|
||||
// 需要隐藏
|
||||
hideTimer = window.setTimeout(() => {
|
||||
localVisible.value = false
|
||||
clearAutoUpdate()
|
||||
emit('update:visible', false)
|
||||
}, props.hideDelay)
|
||||
}
|
||||
|
||||
emit('update:visible', localVisible.value)
|
||||
}
|
||||
|
||||
// 事件绑定
|
||||
@@ -306,11 +334,11 @@ export default defineComponent({
|
||||
<div
|
||||
v-show={localVisible.value}
|
||||
ref={floatingRef}
|
||||
class={[prefixCls, props.popupClass]}
|
||||
class={[prefixCls, props.class]}
|
||||
style={{
|
||||
...floatingStyles.value,
|
||||
position: 'absolute',
|
||||
...props.popupStyle,
|
||||
...props.style,
|
||||
}}
|
||||
data-popup-placement={placement.value}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
@use '../_styles/_variables.scss' as *;
|
||||
@use 'sass:color';
|
||||
|
||||
$tag-prefix: '#{$prefix}-tag';
|
||||
|
||||
$tag-group-prefix: '#{$prefix}-tag-group';
|
||||
|
||||
.#{$tag-group-prefix} {
|
||||
> .#{$tag-prefix}:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import type { PropType, VNode } from 'vue'
|
||||
import { cloneVNode, defineComponent, ref } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
import Tag from '../tag/index'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TagGroup',
|
||||
props: {
|
||||
modelValue: { type: Array as PropType<(string | number)[]>, default: () => [] },
|
||||
multiple: { type: Boolean, default: true },
|
||||
options: {
|
||||
type: Array as PropType<Array<{ label: string, value: string | number }>>,
|
||||
default: () => [],
|
||||
},
|
||||
checkedProps: {
|
||||
type: Object as PropType<{
|
||||
type?: string
|
||||
status?: string
|
||||
}>,
|
||||
default: () => ({
|
||||
type: 'solid',
|
||||
status: 'primary',
|
||||
}),
|
||||
},
|
||||
uncheckedProps: {
|
||||
type: Object as PropType<{
|
||||
type?: string
|
||||
status?: string
|
||||
}>,
|
||||
default: () => ({
|
||||
type: 'solid',
|
||||
status: 'default',
|
||||
}),
|
||||
},
|
||||
class: {
|
||||
type: [String, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
emits: [],
|
||||
setup(props, { slots }) {
|
||||
const prefixCls = getPrefixCls('tag-group')
|
||||
const selectedValues = ref([...props.modelValue])
|
||||
|
||||
const renderSlotTags = () => {
|
||||
const slotNodes = slots.default?.() || []
|
||||
return slotNodes.map((vnode: VNode) => {
|
||||
// 判断是否是 Tag 组件
|
||||
if (vnode.type === Tag) {
|
||||
const value = (vnode.props as any)?.value
|
||||
const checked = selectedValues.value.includes(value)
|
||||
return cloneVNode(vnode, {
|
||||
checked,
|
||||
'type': checked ? props.checkedProps.type : props.uncheckedProps.type,
|
||||
'status': checked ? props.checkedProps.status : props.uncheckedProps.status,
|
||||
'onUpdate:checked': (val: boolean) => handleTagClick(value, val),
|
||||
})
|
||||
}
|
||||
return vnode
|
||||
})
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div class={[prefixCls, props.class]} style={{ ...props.style }}>
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,121 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="demo">
|
||||
<div class="row">
|
||||
<ATag size="small">
|
||||
small
|
||||
</ATag>
|
||||
<ATag size="medium">
|
||||
medium
|
||||
</ATag>
|
||||
<ATag size="large">
|
||||
large
|
||||
</ATag>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<ATag shape="round">
|
||||
round
|
||||
</ATag>
|
||||
<ATag shape="mark">
|
||||
mark
|
||||
</ATag>
|
||||
<ATag shape="square">
|
||||
square
|
||||
</ATag>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<ATag type="solid">
|
||||
solid
|
||||
</ATag>
|
||||
<ATag type="light">
|
||||
light
|
||||
</ATag>
|
||||
<ATag type="outline">
|
||||
outline
|
||||
</ATag>
|
||||
<ATag type="outline-light">
|
||||
outline-light
|
||||
</ATag>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<ATag type="solid" status="primary">
|
||||
solid
|
||||
</ATag>
|
||||
<ATag type="light" status="primary">
|
||||
light
|
||||
</ATag>
|
||||
<ATag type="outline" status="primary">
|
||||
outline
|
||||
</ATag>
|
||||
<ATag type="outline-light" status="primary">
|
||||
outline-light
|
||||
</ATag>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<ATag type="solid" status="danger">
|
||||
solid
|
||||
</ATag>
|
||||
<ATag type="light" status="danger">
|
||||
light
|
||||
</ATag>
|
||||
<ATag type="outline" status="danger">
|
||||
outline
|
||||
</ATag>
|
||||
<ATag type="outline-light" status="danger">
|
||||
outline-light
|
||||
</ATag>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<ATag type="solid" status="warning">
|
||||
solid
|
||||
</ATag>
|
||||
<ATag type="light" status="warning">
|
||||
light
|
||||
</ATag>
|
||||
<ATag type="outline" status="warning">
|
||||
outline
|
||||
</ATag>
|
||||
<ATag type="outline-light" status="warning">
|
||||
outline-light
|
||||
</ATag>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<ATag type="solid" status="success">
|
||||
solid
|
||||
</ATag>
|
||||
<ATag type="light" status="success">
|
||||
light
|
||||
</ATag>
|
||||
<ATag type="outline" status="success">
|
||||
outline
|
||||
</ATag>
|
||||
<ATag type="outline-light" status="success">
|
||||
outline-light
|
||||
</ATag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.demo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,157 @@
|
||||
@use '../_styles/_variables.scss' as *;
|
||||
@use 'sass:color';
|
||||
|
||||
$tag-prefix: '#{$prefix}-tag';
|
||||
|
||||
.#{$tag-prefix} {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
border-radius: $border-color;
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
|
||||
&-size-large {
|
||||
padding: 0 8px;
|
||||
height: 24px;
|
||||
font-size: 13px;
|
||||
}
|
||||
&-size-medium {
|
||||
padding: 0 6px;
|
||||
height: 22px;
|
||||
font-size: 12px;
|
||||
}
|
||||
&-size-small {
|
||||
padding: 0 4px;
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
&-shape-round {
|
||||
border-radius: 12px;
|
||||
}
|
||||
&-shape-mark {
|
||||
border-radius: 0px 12px 12px 0;
|
||||
}
|
||||
&-icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
&-close {
|
||||
margin-left: 4px;
|
||||
cursor: pointer;
|
||||
transition: filter 0.2s cubic-bezier(0.38, 0, 0.24, 1);
|
||||
|
||||
color: currentColor;
|
||||
filter: brightness(1.2); /* 比父色亮 20% */
|
||||
|
||||
&:hover {
|
||||
filter: brightness(0.8); /* 比父色暗 20% */
|
||||
}
|
||||
}
|
||||
|
||||
&-type-solid {
|
||||
&.#{$tag-prefix}-status-default {
|
||||
color: $text-color-base;
|
||||
background-color: $default-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-primary {
|
||||
color: $text-color-anti;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-success {
|
||||
color: $text-color-anti;
|
||||
background-color: $success-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-warning {
|
||||
color: $text-color-anti;
|
||||
background-color: $warning-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-danger {
|
||||
color: $text-color-anti;
|
||||
background-color: $danger-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-type-light {
|
||||
&.#{$tag-prefix}-status-default {
|
||||
color: $text-color-base;
|
||||
background-color: $default-color-light;
|
||||
}
|
||||
&.#{$tag-prefix}-status-primary {
|
||||
color: $primary-color;
|
||||
background-color: $primary-color-light;
|
||||
}
|
||||
&.#{$tag-prefix}-status-success {
|
||||
color: $success-color;
|
||||
background-color: $success-color-light;
|
||||
}
|
||||
&.#{$tag-prefix}-status-warning {
|
||||
color: $warning-color;
|
||||
background-color: $warning-color-light;
|
||||
}
|
||||
&.#{$tag-prefix}-status-danger {
|
||||
color: $danger-color;
|
||||
background-color: $danger-color-light;
|
||||
}
|
||||
}
|
||||
|
||||
&-type-outline {
|
||||
&.#{$tag-prefix}-status-default {
|
||||
color: $text-color-base;
|
||||
background-color: transparent;
|
||||
border-color: $default-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-primary {
|
||||
color: $primary-color;
|
||||
background-color: transparent;
|
||||
border-color: $primary-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-success {
|
||||
color: $success-color;
|
||||
background-color: transparent;
|
||||
border-color: $success-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-warning {
|
||||
color: $warning-color;
|
||||
background-color: transparent;
|
||||
border-color: $warning-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-danger {
|
||||
color: $danger-color;
|
||||
background-color: transparent;
|
||||
border-color: $danger-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-type-outline-light {
|
||||
&.#{$tag-prefix}-status-default {
|
||||
color: $text-color-base;
|
||||
background-color: $default-color-light;
|
||||
border-color: $default-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-primary {
|
||||
color: $primary-color;
|
||||
background-color: $primary-color-light;
|
||||
border-color: $primary-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-success {
|
||||
color: $success-color;
|
||||
background-color: $success-color-light;
|
||||
border-color: $success-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-warning {
|
||||
color: $warning-color;
|
||||
background-color: $warning-color-light;
|
||||
border-color: $warning-color;
|
||||
}
|
||||
&.#{$tag-prefix}-status-danger {
|
||||
color: $danger-color;
|
||||
background-color: $danger-color-light;
|
||||
border-color: $danger-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import type { PropType } from 'vue'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
import Icon from '../icon/index'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Tag',
|
||||
props: {
|
||||
shape: {
|
||||
type: String as PropType<'square' | 'round' | 'mark'>,
|
||||
default: 'square',
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'small' | 'medium' | 'large'>,
|
||||
default: 'medium',
|
||||
},
|
||||
type: {
|
||||
type: String as () => 'solid' | 'light' | 'outline' | 'outline-light',
|
||||
default: 'solid',
|
||||
},
|
||||
status: {
|
||||
type: String as () => 'primary' | 'danger' | 'warning' | 'success' | 'default',
|
||||
default: 'default',
|
||||
},
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
class: {
|
||||
type: [String, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
emits: ['click', 'close'],
|
||||
setup(props, { slots, emit }) {
|
||||
const prefixCls = getPrefixCls('tag')
|
||||
const visible = ref(true)
|
||||
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
emit('click', event)
|
||||
}
|
||||
|
||||
const handleClose = (event: MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
visible.value = false // 点击关闭隐藏 Tag
|
||||
emit('close', event)
|
||||
}
|
||||
|
||||
return () =>
|
||||
visible.value && (
|
||||
<div
|
||||
class={[
|
||||
prefixCls,
|
||||
`${prefixCls}-size-${props.size}`,
|
||||
`${prefixCls}-shape-${props.shape}`,
|
||||
`${prefixCls}-type-${props.type}`,
|
||||
`${prefixCls}-status-${props.status}`,
|
||||
props.class,
|
||||
]}
|
||||
style={{ ...props.style }}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{props.icon && <Icon icon={props.icon} class={`${prefixCls}-icon`} />}
|
||||
<span>{slots.default?.()}</span>
|
||||
{!props.disabled && props.showClose && (
|
||||
<Icon icon="ix:close" class={`${prefixCls}-close`} onClick={handleClose} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="demo">
|
||||
<div class="row">
|
||||
<ATooltip trigger="click" type="default" content="defaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefaultdefault">
|
||||
<AButton status="primary">
|
||||
default
|
||||
</AButton>
|
||||
</ATooltip>
|
||||
<ATooltip trigger="click" type="anti" content="anti">
|
||||
<AButton status="primary">
|
||||
anti
|
||||
</AButton>
|
||||
</ATooltip>
|
||||
<ATooltip trigger="click" type="info" content="info">
|
||||
<AButton status="primary">
|
||||
info
|
||||
</AButton>
|
||||
</ATooltip>
|
||||
<ATooltip trigger="click" type="success" content="success">
|
||||
<AButton status="primary">
|
||||
success
|
||||
</AButton>
|
||||
</ATooltip>
|
||||
<ATooltip trigger="click" type="danger" content="danger">
|
||||
<AButton status="primary">
|
||||
danger
|
||||
</AButton>
|
||||
</ATooltip>
|
||||
<ATooltip trigger="click" type="warning" content="warning">
|
||||
<AButton status="primary">
|
||||
warning
|
||||
</AButton>
|
||||
</ATooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.demo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,88 @@
|
||||
@use '../_styles/_variables.scss' as *;
|
||||
@use 'sass:color';
|
||||
$popup-prefix: '#{$prefix}-popup';
|
||||
$tooltip-prefix: '#{$prefix}-tooltip';
|
||||
|
||||
.#{$tooltip-prefix} {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: $text-color-base;
|
||||
|
||||
&-wrapper {
|
||||
background-color: $status-base-bg-color;
|
||||
padding: 4px 8px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
background-color: $status-base-bg-color;
|
||||
}
|
||||
|
||||
&-default {
|
||||
.#{$tooltip-prefix}-wrapper {
|
||||
background-color: $status-base-bg-color;
|
||||
color: $text-color-base;
|
||||
}
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
background-color: $status-base-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-anti {
|
||||
.#{$tooltip-prefix}-wrapper {
|
||||
background-color: $status-anti-bg-color;
|
||||
color: $text-color-anti;
|
||||
}
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
background-color: $status-anti-bg-color;
|
||||
}
|
||||
}
|
||||
&-info {
|
||||
.#{$tooltip-prefix}-wrapper {
|
||||
background-color: $status-info-bg-color;
|
||||
color: $text-color-base;
|
||||
}
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
background-color: $status-info-bg-color;
|
||||
}
|
||||
}
|
||||
&-success {
|
||||
.#{$tooltip-prefix}-wrapper {
|
||||
background-color: $status-success-bg-color;
|
||||
color: $text-color-base;
|
||||
}
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
background-color: $status-success-bg-color;
|
||||
}
|
||||
}
|
||||
&-danger {
|
||||
.#{$tooltip-prefix}-wrapper {
|
||||
background-color: $status-danger-bg-color;
|
||||
color: $text-color-base;
|
||||
}
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
background-color: $status-danger-bg-color;
|
||||
}
|
||||
}
|
||||
&-warning {
|
||||
.#{$tooltip-prefix}-wrapper {
|
||||
background-color: $status-warning-bg-color;
|
||||
color: $text-color-base;
|
||||
}
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
background-color: $status-warning-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-anti.#{$tooltip-prefix},
|
||||
&-info.#{$tooltip-prefix},
|
||||
&-success.#{$tooltip-prefix},
|
||||
&-danger.#{$tooltip-prefix},
|
||||
&-warning.#{$tooltip-prefix} {
|
||||
box-shadow: none;
|
||||
|
||||
.#{$popup-prefix}-arrow::before {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import type { PropType, VNode } from 'vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { getPrefixCls } from '../_utils/getPrefixCls'
|
||||
import Popup from '../popup/index'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Tooltip',
|
||||
props: {
|
||||
type: {
|
||||
type: String as PropType<'default' | 'anti' | 'info' | 'success' | 'danger' | 'warning'>,
|
||||
default: 'default',
|
||||
},
|
||||
placement: {
|
||||
type: String as PropType<
|
||||
'top' | 'bottom' | 'left' | 'right'
|
||||
| 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end'
|
||||
| 'left-start' | 'left-end' | 'right-start' | 'right-end'
|
||||
>,
|
||||
default: 'top',
|
||||
},
|
||||
trigger: {
|
||||
type: [String, Array] as PropType<
|
||||
'hover' | 'click' | 'focus' | 'contextMenu' | Array<'hover' | 'click' | 'focus' | 'contextMenu'>
|
||||
>,
|
||||
default: 'hover',
|
||||
},
|
||||
showArrow: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
autoFitPopupMinWidth: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
autoFitPopupWidth: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
destroyOnClose: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
content: {
|
||||
type: [String, Object, Function] as unknown as () => string | VNode | (() => VNode),
|
||||
default: '',
|
||||
},
|
||||
showDelay: { type: Number, default: 0 },
|
||||
hideDelay: { type: Number, default: 0 },
|
||||
class: {
|
||||
type: [String, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
style: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
maxWidth: {
|
||||
type: [Number, String] as PropType<number | string>,
|
||||
default: '200px',
|
||||
},
|
||||
},
|
||||
emits: [],
|
||||
setup(props, { slots }) {
|
||||
const prefixCls = getPrefixCls('tooltip')
|
||||
|
||||
const renderContent = (content: string | VNode | (() => VNode)) => {
|
||||
if (typeof content === 'function')
|
||||
return content()
|
||||
if (typeof content === 'string') {
|
||||
return <div class={`${prefixCls}-content`}>{content}</div>
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
const renderTooltip = () => {
|
||||
return (
|
||||
<div
|
||||
class={[`${prefixCls}-wrapper`, props.class]}
|
||||
style={{
|
||||
maxWidth: props.maxWidth,
|
||||
...props.style,
|
||||
}}
|
||||
>
|
||||
{slots.content ? slots.content() : renderContent(props.content)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return () => (
|
||||
<Popup
|
||||
trigger={props.trigger}
|
||||
placement={props.placement}
|
||||
showArrow={props.showArrow}
|
||||
autoFitPopupMinWidth={props.autoFitPopupMinWidth}
|
||||
autoFitPopupWidth={props.autoFitPopupWidth}
|
||||
destroyOnClose={props.destroyOnClose}
|
||||
content={renderTooltip}
|
||||
showDelay={props.showDelay}
|
||||
hideDelay={props.hideDelay}
|
||||
class={`${prefixCls} ${prefixCls}-${props.type}`}
|
||||
>
|
||||
{{
|
||||
default: () => slots.default?.(),
|
||||
}}
|
||||
</Popup>
|
||||
)
|
||||
},
|
||||
})
|
||||
Reference in new issue
Block a user