@xlui/xux-ui 0.1.0 → 0.2.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
+ * Alert 警告提示组件
3
+ * 居中显示,支持自动关闭和手动关闭
4
+ */
5
+
6
+ interface AlertOptions {
7
+ title?: string
8
+ content: string
9
+ type?: 'success' | 'error' | 'warning' | 'info'
10
+ duration?: number // 自动关闭时间,毫秒。0 表示不自动关闭
11
+ closable?: boolean // 是否显示关闭按钮
12
+ }
13
+
14
+ export const xlAlert = () => {
15
+ // 创建 Alert 容器
16
+ const createAlertContainer = () => {
17
+ let container = document.getElementById('xl-alert-container')
18
+ if (!container) {
19
+ container = document.createElement('div')
20
+ container.id = 'xl-alert-container'
21
+ container.style.cssText = `
22
+ position: fixed;
23
+ top: 5%;
24
+ left: 50%;
25
+ transform: translate(-50%, -50%);
26
+ z-index: 10000;
27
+ display: flex;
28
+ flex-direction: column;
29
+ gap: 12px;
30
+ max-width: 90%;
31
+ width: 500px;
32
+ `
33
+ document.body.appendChild(container)
34
+ }
35
+ return container
36
+ }
37
+
38
+ // 获取类型对应的样式和图标
39
+ const getTypeStyles = (type: string) => {
40
+ const styles = {
41
+ success: {
42
+ bgColor: 'rgb(240, 253, 244)',
43
+ darkBgColor: 'rgb(20, 83, 45)',
44
+ borderColor: 'rgb(134, 239, 172)',
45
+ darkBorderColor: 'rgb(22, 101, 52)',
46
+ textColor: 'rgb(22, 101, 52)',
47
+ darkTextColor: 'rgb(187, 247, 208)',
48
+ iconColor: 'rgb(34, 197, 94)',
49
+ iconSvg: `<svg stroke="currentColor" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
50
+ <path d="M13 16h-1v-4h1m0-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path>
51
+ </svg>`
52
+ },
53
+ error: {
54
+ bgColor: 'rgb(254, 242, 242)',
55
+ darkBgColor: 'rgb(127, 29, 29)',
56
+ borderColor: 'rgb(252, 165, 165)',
57
+ darkBorderColor: 'rgb(153, 27, 27)',
58
+ textColor: 'rgb(153, 27, 27)',
59
+ darkTextColor: 'rgb(254, 202, 202)',
60
+ iconColor: 'rgb(239, 68, 68)',
61
+ iconSvg: `<svg stroke="currentColor" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
62
+ <path d="M13 16h-1v-4h1m0-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path>
63
+ </svg>`
64
+ },
65
+ warning: {
66
+ bgColor: 'rgb(254, 252, 232)',
67
+ darkBgColor: 'rgb(133, 77, 14)',
68
+ borderColor: 'rgb(253, 224, 71)',
69
+ darkBorderColor: 'rgb(161, 98, 7)',
70
+ textColor: 'rgb(133, 77, 14)',
71
+ darkTextColor: 'rgb(254, 240, 138)',
72
+ iconColor: 'rgb(234, 179, 8)',
73
+ iconSvg: `<svg stroke="currentColor" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
74
+ <path d="M13 16h-1v-4h1m0-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path>
75
+ </svg>`
76
+ },
77
+ info: {
78
+ bgColor: 'rgb(239, 246, 255)',
79
+ darkBgColor: 'rgb(30, 58, 138)',
80
+ borderColor: 'rgb(147, 197, 253)',
81
+ darkBorderColor: 'rgb(29, 78, 216)',
82
+ textColor: 'rgb(30, 64, 175)',
83
+ darkTextColor: 'rgb(191, 219, 254)',
84
+ iconColor: 'rgb(59, 130, 246)',
85
+ iconSvg: `<svg stroke="currentColor" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
86
+ <path d="M13 16h-1v-4h1m0-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path>
87
+ </svg>`
88
+ }
89
+ }
90
+ return styles[type as keyof typeof styles] || styles.info
91
+ }
92
+
93
+ // 检测暗色模式
94
+ const isDarkMode = () => {
95
+ return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
96
+ }
97
+
98
+ // 显示 Alert
99
+ const show = (options: AlertOptions) => {
100
+ const container = createAlertContainer()
101
+ const type = options.type || 'info'
102
+ const duration = options.duration !== undefined ? options.duration : 5000
103
+ const closable = options.closable !== undefined ? options.closable : true
104
+ const styles = getTypeStyles(type)
105
+ const dark = isDarkMode()
106
+
107
+ const alertId = `xl-alert-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
108
+
109
+ const alert = document.createElement('div')
110
+ alert.id = alertId
111
+ alert.setAttribute('role', 'alert')
112
+ alert.style.cssText = `
113
+ background-color: ${dark ? styles.darkBgColor : styles.bgColor};
114
+ border-left: 4px solid ${dark ? styles.darkBorderColor : styles.borderColor};
115
+ color: ${dark ? styles.darkTextColor : styles.textColor};
116
+ padding: 16px;
117
+ border-radius: 12px;
118
+ display: flex;
119
+ align-items: center;
120
+ transition: all 0.3s ease-in-out;
121
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
122
+ transform: scale(0.8);
123
+ opacity: 0;
124
+ position: relative;
125
+ `
126
+
127
+ // 创建内容
128
+ let innerHTML = `
129
+ <div style="color: ${styles.iconColor}; width: 20px; height: 20px; flex-shrink: 0; margin-right: 12px;">
130
+ ${styles.iconSvg}
131
+ </div>
132
+ <div style="flex: 1;">
133
+ ${options.title ? `<p style="font-weight: 600; font-size: 14px; margin-bottom: 4px;">${options.title}</p>` : ''}
134
+ <p style="font-size: ${options.title ? '13px' : '14px'}; font-weight: ${options.title ? '400' : '600'};">${options.content}</p>
135
+ </div>
136
+ `
137
+
138
+ // 添加关闭按钮
139
+ if (closable) {
140
+ innerHTML += `
141
+ <button
142
+ class="xl-alert-close"
143
+ style="
144
+ background: transparent;
145
+ border: none;
146
+ color: ${dark ? styles.darkTextColor : styles.textColor};
147
+ cursor: pointer;
148
+ padding: 4px;
149
+ margin-left: 8px;
150
+ display: flex;
151
+ align-items: center;
152
+ justify-content: center;
153
+ opacity: 0.6;
154
+ transition: opacity 0.2s;
155
+ width: 20px;
156
+ height: 20px;
157
+ flex-shrink: 0;
158
+ "
159
+ onmouseover="this.style.opacity='1'"
160
+ onmouseout="this.style.opacity='0.6'"
161
+ >
162
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
163
+ <line x1="18" y1="6" x2="6" y2="18"></line>
164
+ <line x1="6" y1="6" x2="18" y2="18"></line>
165
+ </svg>
166
+ </button>
167
+ `
168
+ }
169
+
170
+ alert.innerHTML = innerHTML
171
+
172
+ // 关闭函数
173
+ const close = () => {
174
+ alert.style.transform = 'scale(0.8)'
175
+ alert.style.opacity = '0'
176
+ setTimeout(() => {
177
+ if (alert.parentNode) {
178
+ container.removeChild(alert)
179
+ }
180
+ // 如果容器为空,移除容器
181
+ if (container.children.length === 0) {
182
+ document.body.removeChild(container)
183
+ }
184
+ }, 300)
185
+ }
186
+
187
+ // 添加关闭按钮事件
188
+ if (closable) {
189
+ const closeBtn = alert.querySelector('.xl-alert-close')
190
+ if (closeBtn) {
191
+ closeBtn.addEventListener('click', close)
192
+ }
193
+ }
194
+
195
+ container.appendChild(alert)
196
+
197
+ // 显示动画
198
+ setTimeout(() => {
199
+ alert.style.transform = 'scale(1)'
200
+ alert.style.opacity = '1'
201
+ }, 10)
202
+
203
+ // 自动关闭
204
+ if (duration > 0) {
205
+ setTimeout(close, duration)
206
+ }
207
+
208
+ return { close }
209
+ }
210
+
211
+ // 快捷方法
212
+ const success = (content: string, options?: Partial<AlertOptions>) => {
213
+ return show({ content, type: 'success', ...options })
214
+ }
215
+
216
+ const error = (content: string, options?: Partial<AlertOptions>) => {
217
+ return show({ content, type: 'error', ...options })
218
+ }
219
+
220
+ const warning = (content: string, options?: Partial<AlertOptions>) => {
221
+ return show({ content, type: 'warning', ...options })
222
+ }
223
+
224
+ const info = (content: string, options?: Partial<AlertOptions>) => {
225
+ return show({ content, type: 'info', ...options })
226
+ }
227
+
228
+ return {
229
+ show,
230
+ success,
231
+ error,
232
+ warning,
233
+ info
234
+ }
235
+ }
236
+
237
+ // 默认导出
238
+ export default xlAlert
package/src/index.ts CHANGED
@@ -12,9 +12,11 @@ export { default as XAccordion } from './components/Accordion/index.vue'
12
12
  export { default as XThumbnailContainer } from './components/ThumbnailContainer/index.vue'
13
13
  export { default as XSkeleton } from './components/Skeleton/index.vue'
14
14
  export { default as XModal } from './components/Modal/index.vue'
15
+ export { default as XTooltips } from './components/Tooltips/index.vue'
15
16
 
16
17
  // 导出 Composables
17
18
  export { xlMsg, default as useMsg } from './composables/Msg'
19
+ export { xlAlert, default as useAlert } from './composables/Alert'
18
20
 
19
21
  // 导出类型定义
20
22
  export type { Country, CountrySelectProps } from './components/CountrySelect/index.vue'
@@ -25,4 +27,5 @@ export type { AccordionItem, AccordionProps } from './components/Accordion/index
25
27
  export type { ThumbnailContainerProps } from './components/ThumbnailContainer/index.vue'
26
28
  export type { SkeletonProps } from './components/Skeleton/index.vue'
27
29
  export type { ModalProps } from './components/Modal/index.vue'
30
+ export type { TooltipsProps } from './components/Tooltips/index.vue'
28
31