little-dizzy 2.2.0 → 2.4.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.
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Message 全局消息提示服务
3
+ *
4
+ * 使用方法:
5
+ * import { message } from '@/components/message.js'
6
+ *
7
+ * message.success('操作成功')
8
+ * message.error('操作失败')
9
+ * message.warning('警告信息')
10
+ * message.info('提示信息')
11
+ *
12
+ * // 带配置
13
+ * message.success('操作成功', { duration: 5000, closable: true })
14
+ */
15
+
16
+ import { createApp, h, ref } from 'vue'
17
+ import Message from './Message.vue'
18
+
19
+ let messageInstance = null
20
+ let messageContainer = null
21
+
22
+ // Initialize message instance
23
+ const initMessage = () => {
24
+ if (messageInstance) return messageInstance
25
+
26
+ messageContainer = document.createElement('div')
27
+ messageContainer.id = 'ld-message-container'
28
+ document.body.appendChild(messageContainer)
29
+
30
+ const app = createApp({
31
+ setup () {
32
+ const messageRef = ref(null)
33
+ return () => h(Message, { ref: messageRef })
34
+ }
35
+ })
36
+
37
+ const vm = app.mount(messageContainer)
38
+ messageInstance = vm.$el.__vueParentComponent?.exposed || vm.$el.parentNode?.__vueParentComponent?.subTree?.component?.exposed
39
+
40
+ // Wait for next tick to get the exposed methods
41
+ return new Promise((resolve) => {
42
+ setTimeout(() => {
43
+ const container = document.querySelector('#ld-message-container')
44
+ if (container) {
45
+ const vueInstance = container._vnode?.component?.subTree?.component?.exposed
46
+ if (vueInstance) {
47
+ messageInstance = vueInstance
48
+ resolve(messageInstance)
49
+ }
50
+ }
51
+ }, 0)
52
+ })
53
+ }
54
+
55
+ // Create a simpler implementation using reactive state
56
+ const messages = ref([])
57
+ let messageId = 0
58
+
59
+ const typeClasses = {
60
+ success: 'ld-message--success',
61
+ warning: 'ld-message--warning',
62
+ error: 'ld-message--error',
63
+ info: 'ld-message--info'
64
+ }
65
+
66
+ const createMessageElement = (options) => {
67
+ const id = ++messageId
68
+ const type = options.type || 'info'
69
+ const content = options.content || ''
70
+ const duration = options.duration ?? 3000
71
+ const closable = options.closable ?? false
72
+
73
+ // Create message element
74
+ const msgEl = document.createElement('div')
75
+ msgEl.className = `ld-message ld-message--${type}`
76
+ msgEl.setAttribute('data-id', id)
77
+
78
+ // Icon SVGs
79
+ const icons = {
80
+ success: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
81
+ <path d="M20 6L9 17l-5-5" stroke-linecap="round" stroke-linejoin="round"/>
82
+ </svg>`,
83
+ warning: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="currentColor">
84
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
85
+ </svg>`,
86
+ error: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
87
+ <circle cx="12" cy="12" r="10"/>
88
+ <path d="M15 9l-6 6M9 9l6 6" stroke-linecap="round"/>
89
+ </svg>`,
90
+ info: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="currentColor">
91
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
92
+ </svg>`
93
+ }
94
+
95
+ let html = `${icons[type]}<span class="ld-message-content">${content}</span>`
96
+
97
+ if (closable) {
98
+ html += `<button class="ld-message-close" onclick="window.__ldMessageClose(${id})">
99
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
100
+ <path d="M18 6L6 18M6 6l12 12"/>
101
+ </svg>
102
+ </button>`
103
+ }
104
+
105
+ msgEl.innerHTML = html
106
+
107
+ return { id, element: msgEl, duration }
108
+ }
109
+
110
+ // Ensure container exists
111
+ const ensureContainer = () => {
112
+ let container = document.getElementById('ld-message-root')
113
+ if (!container) {
114
+ container = document.createElement('div')
115
+ container.id = 'ld-message-root'
116
+ document.body.appendChild(container)
117
+
118
+ // Add styles
119
+ const style = document.createElement('style')
120
+ style.textContent = `
121
+ #ld-message-root {
122
+ position: fixed;
123
+ top: 16px;
124
+ left: 50%;
125
+ transform: translateX(-50%);
126
+ z-index: 9999;
127
+ display: flex;
128
+ flex-direction: column;
129
+ align-items: center;
130
+ gap: 12px;
131
+ pointer-events: none;
132
+ }
133
+ .ld-message {
134
+ pointer-events: auto;
135
+ display: flex;
136
+ align-items: center;
137
+ gap: 12px;
138
+ padding: 12px 20px;
139
+ border-radius: 8px;
140
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
141
+ backdrop-filter: blur(8px);
142
+ animation: ldMessageIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
143
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
144
+ font-size: 14px;
145
+ font-weight: 500;
146
+ }
147
+ .ld-message.ld-message--closing {
148
+ animation: ldMessageOut 0.2s ease-in forwards;
149
+ }
150
+ .ld-message--success { background: rgba(16, 185, 129, 0.95); color: white; }
151
+ .ld-message--warning { background: rgba(245, 158, 11, 0.95); color: white; }
152
+ .ld-message--error { background: rgba(239, 68, 68, 0.95); color: white; }
153
+ .ld-message--info { background: rgba(14, 165, 233, 0.95); color: white; }
154
+ .ld-message-icon { width: 20px; height: 20px; flex-shrink: 0; }
155
+ .ld-message-content { white-space: nowrap; }
156
+ .ld-message-close {
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: center;
160
+ width: 20px;
161
+ height: 20px;
162
+ margin-left: 4px;
163
+ padding: 0;
164
+ border: none;
165
+ background: transparent;
166
+ color: currentColor;
167
+ cursor: pointer;
168
+ border-radius: 50%;
169
+ transition: background 0.2s;
170
+ }
171
+ .ld-message-close:hover { background: rgba(255,255,255,0.2); }
172
+ .ld-message-close svg { width: 14px; height: 14px; }
173
+ @keyframes ldMessageIn {
174
+ from { opacity: 0; transform: translateY(-20px) scale(0.9); }
175
+ to { opacity: 1; transform: translateY(0) scale(1); }
176
+ }
177
+ @keyframes ldMessageOut {
178
+ from { opacity: 1; transform: translateY(0) scale(1); }
179
+ to { opacity: 0; transform: translateY(-10px) scale(0.95); }
180
+ }
181
+ `
182
+ document.head.appendChild(style)
183
+ }
184
+ return container
185
+ }
186
+
187
+ // Close message
188
+ const closeMessage = (id) => {
189
+ const container = document.getElementById('ld-message-root')
190
+ if (!container) return
191
+
192
+ const msgEl = container.querySelector(`[data-id="${id}"]`)
193
+ if (msgEl) {
194
+ msgEl.classList.add('ld-message--closing')
195
+ setTimeout(() => {
196
+ msgEl.remove()
197
+ }, 200)
198
+ }
199
+ }
200
+
201
+ // Expose close function globally
202
+ if (typeof window !== 'undefined') {
203
+ window.__ldMessageClose = closeMessage
204
+ }
205
+
206
+ // Show message
207
+ const showMessage = (options) => {
208
+ const container = ensureContainer()
209
+ const { id, element, duration } = createMessageElement(options)
210
+
211
+ container.appendChild(element)
212
+
213
+ if (duration > 0) {
214
+ setTimeout(() => {
215
+ closeMessage(id)
216
+ }, duration)
217
+ }
218
+
219
+ return id
220
+ }
221
+
222
+ // Export message API
223
+ export const message = {
224
+ success: (content, options = {}) => showMessage({ ...options, type: 'success', content }),
225
+ warning: (content, options = {}) => showMessage({ ...options, type: 'warning', content }),
226
+ error: (content, options = {}) => showMessage({ ...options, type: 'error', content }),
227
+ info: (content, options = {}) => showMessage({ ...options, type: 'info', content }),
228
+ close: closeMessage,
229
+ closeAll: () => {
230
+ const container = document.getElementById('ld-message-root')
231
+ if (container) {
232
+ container.innerHTML = ''
233
+ }
234
+ }
235
+ }
236
+
237
+ export default message
238
+
package/src/index.js CHANGED
@@ -23,6 +23,8 @@
23
23
  import Button from './components/Button.vue'
24
24
  import Card from './components/Card.vue'
25
25
  import Modal from './components/Modal.vue'
26
+ import Message from './components/Message.vue'
27
+ import { message } from './components/message.js'
26
28
 
27
29
  // 导入自定义组件(由 Demo 上传生成)
28
30
  import { customComponents } from './components/custom/index.js'
@@ -35,6 +37,7 @@ const components = {
35
37
  Button,
36
38
  Card,
37
39
  Modal,
40
+ Message,
38
41
  ...customComponents
39
42
  }
40
43
 
@@ -44,6 +47,11 @@ const install = (app, options = {}) => {
44
47
  Object.entries(components).forEach(([name, component]) => {
45
48
  app.component(options.prefix ? `${options.prefix}${name}` : name, component)
46
49
  })
50
+
51
+ // 挂载 message 到全局属性
52
+ app.config.globalProperties.$message = message
53
+ // 同时提供 provide 方式
54
+ app.provide('message', message)
47
55
  }
48
56
 
49
57
  // 导出代码片段相关
@@ -53,7 +61,7 @@ export const registerSnippets = snippetsModule.registerSnippets
53
61
  export const getSnippet = snippetsModule.getSnippet
54
62
 
55
63
  // 导出内置组件(按需引入)
56
- export { Button, Card, Modal }
64
+ export { Button, Card, Modal, Message, message }
57
65
 
58
66
  // 重新导出自定义组件
59
67
  export * from './components/custom/index.js'
@@ -7,16 +7,18 @@
7
7
  import buttonSnippet from './button.js'
8
8
  import cardSnippet from './card.js'
9
9
  import modalSnippet from './modal.js'
10
+ import messageSnippet from './message.js'
10
11
 
11
12
  // 所有预设代码片段
12
13
  export const presetSnippets = [
13
14
  buttonSnippet,
14
15
  cardSnippet,
15
- modalSnippet
16
+ modalSnippet,
17
+ messageSnippet
16
18
  ]
17
19
 
18
20
  // 单独导出
19
- export { buttonSnippet, cardSnippet, modalSnippet }
21
+ export { buttonSnippet, cardSnippet, modalSnippet, messageSnippet }
20
22
 
21
23
  export default presetSnippets
22
24
 
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Message 消息提示组件示例代码
3
+ */
4
+ export default {
5
+ name: 'Message',
6
+ type: 'vue',
7
+ label: 'Message 消息提示',
8
+ code: `<template>
9
+ <div class="message-demo">
10
+ <Button type="success" @click="showSuccess">成功提示</Button>
11
+ <Button type="warning" @click="showWarning">警告提示</Button>
12
+ <Button type="danger" @click="showError">错误提示</Button>
13
+ <Button type="info" @click="showInfo">信息提示</Button>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup>
18
+ import { Button, message } from 'little-dizzy'
19
+
20
+ const showSuccess = () => {
21
+ message.success('操作成功!')
22
+ }
23
+
24
+ const showWarning = () => {
25
+ message.warning('请注意!')
26
+ }
27
+
28
+ const showError = () => {
29
+ message.error('操作失败!')
30
+ }
31
+
32
+ const showInfo = () => {
33
+ message.info('这是一条提示信息', { duration: 5000, closable: true })
34
+ }
35
+ </script>
36
+
37
+ <style scoped>
38
+ .message-demo {
39
+ display: flex;
40
+ gap: 12px;
41
+ flex-wrap: wrap;
42
+ }
43
+ </style>`
44
+ }
45
+
@@ -34,6 +34,14 @@ $shadow-lg: 0 6px 20px rgba(0, 0, 0, 0.2);
34
34
  margin: 0;
35
35
  padding: 0;
36
36
  box-sizing: border-box;
37
+
38
+ // 隐藏滚动条(保持滚动功能)
39
+ scrollbar-width: none; // Firefox
40
+ -ms-overflow-style: none; // IE/Edge
41
+
42
+ &::-webkit-scrollbar {
43
+ display: none; // Chrome/Safari/Opera
44
+ }
37
45
  }
38
46
 
39
47
  body {
@@ -0,0 +1 @@
1
+ @import "tailwindcss";