wshisbadboy-ui-lib 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/my-ui-lib.es.js +590 -0
- package/dist/my-ui-lib.umd.js +1 -0
- package/dist/wshisbadboy-ui-lib.css +1 -0
- package/package.json +48 -0
- package/src/components/Alert/Alert.vue +169 -0
- package/src/components/Alert/index.js +7 -0
- package/src/components/Button/Button.vue +183 -0
- package/src/components/Button/index.js +7 -0
- package/src/components/Collapse/Collapse.vue +62 -0
- package/src/components/Collapse/CollapseItem.vue +176 -0
- package/src/components/Collapse/index.js +12 -0
- package/src/components/Message/Message.vue +159 -0
- package/src/components/Message/MessageList.vue +62 -0
- package/src/components/Message/index.js +16 -0
- package/src/components/Message/message.js +35 -0
- package/src/index.js +17 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<transition name="my-message-fade" @after-leave="$emit('destroy')">
|
|
3
|
+
<div
|
|
4
|
+
v-if="visible"
|
|
5
|
+
:class="['my-message', `my-message--${type}`]"
|
|
6
|
+
role="alert"
|
|
7
|
+
>
|
|
8
|
+
<span class="my-message__icon">
|
|
9
|
+
<svg v-if="type === 'success'" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
10
|
+
<path d="M22 11.08V12a10 10 0 11-5.93-9.14" />
|
|
11
|
+
<polyline points="22 4 12 14.01 9 11.01" />
|
|
12
|
+
</svg>
|
|
13
|
+
<svg v-else-if="type === 'warning'" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
14
|
+
<path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
|
|
15
|
+
<line x1="12" y1="9" x2="12" y2="13" />
|
|
16
|
+
<line x1="12" y1="17" x2="12.01" y2="17" />
|
|
17
|
+
</svg>
|
|
18
|
+
<svg v-else-if="type === 'error'" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
19
|
+
<circle cx="12" cy="12" r="10" />
|
|
20
|
+
<line x1="15" y1="9" x2="9" y2="15" />
|
|
21
|
+
<line x1="9" y1="9" x2="15" y2="15" />
|
|
22
|
+
</svg>
|
|
23
|
+
<svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
24
|
+
<circle cx="12" cy="12" r="10" />
|
|
25
|
+
<line x1="12" y1="16" x2="12" y2="12" />
|
|
26
|
+
<line x1="12" y1="8" x2="12.01" y2="8" />
|
|
27
|
+
</svg>
|
|
28
|
+
</span>
|
|
29
|
+
<span v-if="isStringMessage" class="my-message__text">{{ message }}</span>
|
|
30
|
+
<component :is="message" v-else class="my-message__text" />
|
|
31
|
+
<button v-if="showClose" class="my-message__close" @click="close" aria-label="关闭">
|
|
32
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
33
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
34
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
35
|
+
</svg>
|
|
36
|
+
</button>
|
|
37
|
+
</div>
|
|
38
|
+
</transition>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script>
|
|
42
|
+
export default {
|
|
43
|
+
name: 'MyMessage',
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<script setup>
|
|
48
|
+
import { ref, onMounted, computed } from 'vue'
|
|
49
|
+
|
|
50
|
+
const props = defineProps({
|
|
51
|
+
type: {
|
|
52
|
+
type: String,
|
|
53
|
+
default: 'info',
|
|
54
|
+
},
|
|
55
|
+
message: { type: [String, Function], default: '' },
|
|
56
|
+
duration: { type: Number, default: 3000 },
|
|
57
|
+
showClose: { type: Boolean, default: false },
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const emit = defineEmits(['destroy'])
|
|
61
|
+
|
|
62
|
+
const visible = ref(true)
|
|
63
|
+
let timer = null
|
|
64
|
+
|
|
65
|
+
const isStringMessage = computed(() => typeof props.message === 'string')
|
|
66
|
+
|
|
67
|
+
function close() {
|
|
68
|
+
visible.value = false
|
|
69
|
+
if (timer) clearTimeout(timer)
|
|
70
|
+
emit('destroy')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function startTimer() {
|
|
74
|
+
if (props.duration > 0) {
|
|
75
|
+
timer = setTimeout(() => {
|
|
76
|
+
visible.value = false
|
|
77
|
+
}, props.duration)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
onMounted(() => {
|
|
82
|
+
startTimer()
|
|
83
|
+
})
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<style>
|
|
87
|
+
.my-message {
|
|
88
|
+
display: inline-flex;
|
|
89
|
+
align-items: center;
|
|
90
|
+
gap: 8px;
|
|
91
|
+
padding: 10px 16px;
|
|
92
|
+
border-radius: 8px;
|
|
93
|
+
font-size: 14px;
|
|
94
|
+
line-height: 1.5;
|
|
95
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
96
|
+
pointer-events: auto;
|
|
97
|
+
background: #fff;
|
|
98
|
+
border: 1px solid var(--my-border, #e5e7eb);
|
|
99
|
+
color: var(--my-text, #1f2937);
|
|
100
|
+
min-width: 200px;
|
|
101
|
+
max-width: 420px;
|
|
102
|
+
margin-bottom: 8px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.my-message--info { border-left: 3px solid #3b82f6; }
|
|
106
|
+
.my-message--success { border-left: 3px solid #22c55e; }
|
|
107
|
+
.my-message--warning { border-left: 3px solid #f59e0b; }
|
|
108
|
+
.my-message--error { border-left: 3px solid #ef4444; }
|
|
109
|
+
|
|
110
|
+
.my-message__icon {
|
|
111
|
+
display: inline-flex;
|
|
112
|
+
flex-shrink: 0;
|
|
113
|
+
color: var(--my-text-muted, #9ca3af);
|
|
114
|
+
}
|
|
115
|
+
.my-message--info .my-message__icon { color: #3b82f6; }
|
|
116
|
+
.my-message--success .my-message__icon { color: #22c55e; }
|
|
117
|
+
.my-message--warning .my-message__icon { color: #f59e0b; }
|
|
118
|
+
.my-message--error .my-message__icon { color: #ef4444; }
|
|
119
|
+
|
|
120
|
+
.my-message__text {
|
|
121
|
+
flex: 1;
|
|
122
|
+
word-break: break-word;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.my-message__close {
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
flex-shrink: 0;
|
|
130
|
+
width: 18px;
|
|
131
|
+
height: 18px;
|
|
132
|
+
border: none;
|
|
133
|
+
background: transparent;
|
|
134
|
+
color: inherit;
|
|
135
|
+
opacity: 0.5;
|
|
136
|
+
cursor: pointer;
|
|
137
|
+
border-radius: 4px;
|
|
138
|
+
padding: 0;
|
|
139
|
+
}
|
|
140
|
+
.my-message__close:hover {
|
|
141
|
+
opacity: 1;
|
|
142
|
+
background-color: rgba(0, 0, 0, 0.06);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.my-message-fade-enter-active {
|
|
146
|
+
transition: all 0.25s ease;
|
|
147
|
+
}
|
|
148
|
+
.my-message-fade-leave-active {
|
|
149
|
+
transition: all 0.2s ease;
|
|
150
|
+
}
|
|
151
|
+
.my-message-fade-enter-from {
|
|
152
|
+
opacity: 0;
|
|
153
|
+
transform: translateY(-12px);
|
|
154
|
+
}
|
|
155
|
+
.my-message-fade-leave-to {
|
|
156
|
+
opacity: 0;
|
|
157
|
+
transform: translateY(-8px);
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="my-message-container">
|
|
3
|
+
<MyMessage
|
|
4
|
+
v-for="(item, i) in messages"
|
|
5
|
+
:key="item.id"
|
|
6
|
+
:type="item.type"
|
|
7
|
+
:message="item.message"
|
|
8
|
+
:duration="item.duration"
|
|
9
|
+
:show-close="item.showClose"
|
|
10
|
+
@destroy="remove(item.id)"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script setup>
|
|
16
|
+
import { ref } from 'vue'
|
|
17
|
+
import MyMessage from './Message.vue'
|
|
18
|
+
|
|
19
|
+
const messages = ref([])
|
|
20
|
+
let seed = 0
|
|
21
|
+
|
|
22
|
+
function add(options) {
|
|
23
|
+
const id = ++seed
|
|
24
|
+
const msg = {
|
|
25
|
+
id,
|
|
26
|
+
type: options.type || 'info',
|
|
27
|
+
message: options.message || '',
|
|
28
|
+
duration: options.duration ?? 3000,
|
|
29
|
+
showClose: options.showClose ?? false,
|
|
30
|
+
}
|
|
31
|
+
messages.value.push(msg)
|
|
32
|
+
if (msg.duration > 0) {
|
|
33
|
+
setTimeout(() => remove(id), msg.duration + 300)
|
|
34
|
+
}
|
|
35
|
+
return id
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function remove(id) {
|
|
39
|
+
const idx = messages.value.findIndex((m) => m.id === id)
|
|
40
|
+
if (idx > -1) messages.value.splice(idx, 1)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function clear() {
|
|
44
|
+
messages.value = []
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
defineExpose({ add, remove, clear })
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<style>
|
|
51
|
+
.my-message-container {
|
|
52
|
+
position: fixed;
|
|
53
|
+
top: 20px;
|
|
54
|
+
left: 50%;
|
|
55
|
+
transform: translateX(-50%);
|
|
56
|
+
z-index: 9999;
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
align-items: center;
|
|
60
|
+
pointer-events: none;
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Message from './message.js'
|
|
2
|
+
import MessageComponent from './Message.vue'
|
|
3
|
+
|
|
4
|
+
MessageComponent.install = (app) => {
|
|
5
|
+
app.component(MessageComponent.name, MessageComponent)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// 将命令式方法挂到组件上,方便 import { Message } from '...' 使用
|
|
9
|
+
MessageComponent.success = Message.success
|
|
10
|
+
MessageComponent.error = Message.error
|
|
11
|
+
MessageComponent.warning = Message.warning
|
|
12
|
+
MessageComponent.info = Message.info
|
|
13
|
+
MessageComponent.closeAll = Message.closeAll
|
|
14
|
+
|
|
15
|
+
export { MessageComponent as Message }
|
|
16
|
+
export default MessageComponent
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import MessageList from './MessageList.vue'
|
|
3
|
+
|
|
4
|
+
let instance = null
|
|
5
|
+
|
|
6
|
+
function getInstance() {
|
|
7
|
+
if (instance) return instance
|
|
8
|
+
|
|
9
|
+
const container = document.createElement('div')
|
|
10
|
+
document.body.appendChild(container)
|
|
11
|
+
const app = createApp(MessageList)
|
|
12
|
+
instance = app.mount(container)
|
|
13
|
+
|
|
14
|
+
return instance
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function show(options) {
|
|
18
|
+
const opts = typeof options === 'string'
|
|
19
|
+
? { message: options, type: 'info' }
|
|
20
|
+
: options
|
|
21
|
+
return getInstance().add(opts)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const Message = (options) => show(options)
|
|
25
|
+
|
|
26
|
+
Message.info = (message, duration) => show({ message, type: 'info', duration })
|
|
27
|
+
Message.success = (message, duration) => show({ message, type: 'success', duration })
|
|
28
|
+
Message.warning = (message, duration) => show({ message, type: 'warning', duration })
|
|
29
|
+
Message.error = (message, duration) => show({ message, type: 'error', duration })
|
|
30
|
+
|
|
31
|
+
Message.closeAll = () => {
|
|
32
|
+
if (instance) instance.clear()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default Message
|
package/src/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Button from './components/Button/Button.vue'
|
|
2
|
+
import { Collapse, CollapseItem } from './components/Collapse'
|
|
3
|
+
import Alert from './components/Alert/Alert.vue'
|
|
4
|
+
import { Message } from './components/Message'
|
|
5
|
+
|
|
6
|
+
export { Button, Collapse, CollapseItem, Alert, Message }
|
|
7
|
+
|
|
8
|
+
const components = [Button, Collapse, CollapseItem, Alert, Message]
|
|
9
|
+
|
|
10
|
+
const install = (app) => {
|
|
11
|
+
components.forEach((component) => {
|
|
12
|
+
app.component(component.name, component)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default { install }
|
|
17
|
+
export { install }
|