vue3-dynamic-island 1.0.1

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/README.md ADDED
@@ -0,0 +1,269 @@
1
+ # Dynamic Island
2
+
3
+ A commercial-grade Dynamic Island notification component for Vue 3, inspired by Apple's Dynamic Island design.
4
+
5
+ ## Features
6
+
7
+ - 🎨 Apple-inspired Dynamic Island UI design
8
+ - 🚀 Global notification system with queue management
9
+ - 🎯 Multiple notification types (default, success, error, warning, info)
10
+ - 📦 Dynamic component embedding support
11
+ - 🎭 Multiple animation effects (fade, slide, zoom, bounce)
12
+ - 🔄 Auto-close and persistent modes
13
+ - 🖱️ Drag-and-drop functionality with position persistence
14
+ - 🔊 Sound notifications
15
+ - 🎨 Custom styling support
16
+ - 💾 localStorage position memory
17
+ - 📱 Responsive design
18
+ - 🎯 TypeScript support
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install dynamic-island
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### Basic Setup
29
+
30
+ ```vue
31
+ <script setup>
32
+ import { useDynamicIsland } from 'dynamic-island'
33
+
34
+ const island = useDynamicIsland()
35
+
36
+ const showNotification = () => {
37
+ island.success('Success', 'Operation completed successfully!')
38
+ }
39
+ </script>
40
+
41
+ <template>
42
+ <button @click="showNotification">Show Notification</button>
43
+ </template>
44
+ ```
45
+
46
+ ### Global Installation
47
+
48
+ ```vue
49
+ <script setup>
50
+ import { createApp } from 'vue'
51
+ import App from './App.vue'
52
+ import DynamicIsland from 'dynamic-island'
53
+
54
+ const app = createApp(App)
55
+ app.use(DynamicIsland)
56
+ app.mount('#app')
57
+ </script>
58
+ ```
59
+
60
+ ## API
61
+
62
+ ### useDynamicIsland()
63
+
64
+ Returns an object with the following methods:
65
+
66
+ #### show(options)
67
+
68
+ ```typescript
69
+ island.show({
70
+ type: 'success', // 'default' | 'success' | 'error' | 'warning' | 'info'
71
+ title: 'Notification Title',
72
+ subtitle: 'Optional subtitle',
73
+ icon: MyIconComponent, // Optional custom icon
74
+ showIcon: true, // Show/hide icon
75
+ showClose: true, // Show/hide close button
76
+ duration: 3000, // Auto-close duration (ms)
77
+ persistent: false, // Don't auto-close
78
+ animation: 'slide', // 'fade' | 'slide' | 'zoom' | 'bounce'
79
+ progress: 50, // Progress value (0-100)
80
+ showProgress: false, // Show progress bar
81
+ dynamicComponent: { // Embed custom component
82
+ component: MyComponent,
83
+ props: { /* props */ }
84
+ },
85
+ backgroundColor: '#ff0000', // Custom background color
86
+ textColor: '#ffffff', // Custom text color
87
+ soundEnabled: true, // Enable sound
88
+ soundUrl: '/sound.mp3', // Custom sound URL
89
+ memPosition: false, // Remember position
90
+ onClick: () => {}, // Click callback
91
+ onClose: () => {} // Close callback
92
+ })
93
+ ```
94
+
95
+ #### success(title, subtitle, options)
96
+
97
+ ```typescript
98
+ island.success('Success', 'Operation completed!')
99
+ ```
100
+
101
+ #### error(title, subtitle, options)
102
+
103
+ ```typescript
104
+ island.error('Error', 'Something went wrong!')
105
+ ```
106
+
107
+ #### warning(title, subtitle, options)
108
+
109
+ ```typescript
110
+ island.warning('Warning', 'Please check your input')
111
+ ```
112
+
113
+ #### info(title, subtitle, options)
114
+
115
+ ```typescript
116
+ island.info('Info', 'You have 3 new messages')
117
+ ```
118
+
119
+ #### close(id)
120
+
121
+ Close a specific notification by ID.
122
+
123
+ ```typescript
124
+ const notificationId = island.show({ title: 'Test' })
125
+ island.close(notificationId)
126
+ ```
127
+
128
+ #### clear()
129
+
130
+ Clear all notifications.
131
+
132
+ ```typescript
133
+ island.clear()
134
+ ```
135
+
136
+ #### clearQueue()
137
+
138
+ Clear the notification queue.
139
+
140
+ ```typescript
141
+ island.clearQueue()
142
+ ```
143
+
144
+ #### updateProgress(id, progress)
145
+
146
+ Update progress of a notification.
147
+
148
+ ```typescript
149
+ const notificationId = island.show({
150
+ title: 'Uploading',
151
+ showProgress: true,
152
+ progress: 0,
153
+ persistent: true
154
+ })
155
+
156
+ // Update progress
157
+ island.updateProgress(notificationId, 50)
158
+ ```
159
+
160
+ #### updateIsland(id, updates)
161
+
162
+ Update a notification's properties.
163
+
164
+ ```typescript
165
+ const notificationId = island.show({ title: 'Test' })
166
+ island.updateIsland(notificationId, { title: 'Updated' })
167
+ ```
168
+
169
+ #### setSoundEnabled(enabled)
170
+
171
+ Enable/disable sound notifications globally.
172
+
173
+ ```typescript
174
+ island.setSoundEnabled(false)
175
+ ```
176
+
177
+ ## Examples
178
+
179
+ ### Dynamic Component Embedding
180
+
181
+ ```vue
182
+ <script setup>
183
+ import { useDynamicIsland } from 'dynamic-island'
184
+ import MyForm from './MyForm.vue'
185
+
186
+ const island = useDynamicIsland()
187
+
188
+ const showForm = () => {
189
+ island.show({
190
+ type: 'info',
191
+ title: 'User Form',
192
+ subtitle: 'Please fill in your information',
193
+ persistent: true,
194
+ dynamicComponent: {
195
+ component: MyForm,
196
+ props: {
197
+ onSubmit: (data) => {
198
+ console.log('Form submitted:', data)
199
+ island.clear()
200
+ }
201
+ }
202
+ }
203
+ })
204
+ }
205
+ </script>
206
+ ```
207
+
208
+ ### Custom Styling
209
+
210
+ ```typescript
211
+ island.show({
212
+ title: 'Custom Style',
213
+ subtitle: 'Gradient background',
214
+ backgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
215
+ textColor: '#ffffff'
216
+ })
217
+ ```
218
+
219
+ ### Progress Bar
220
+
221
+ ```typescript
222
+ const notificationId = island.show({
223
+ type: 'info',
224
+ title: 'Processing',
225
+ subtitle: 'Please wait...',
226
+ showProgress: true,
227
+ progress: 0,
228
+ persistent: true
229
+ })
230
+
231
+ // Simulate progress
232
+ let progress = 0
233
+ const interval = setInterval(() => {
234
+ progress += 10
235
+ island.updateProgress(notificationId, progress)
236
+
237
+ if (progress >= 100) {
238
+ clearInterval(interval)
239
+ island.close(notificationId)
240
+ island.success('Complete', 'Operation finished!')
241
+ }
242
+ }, 500)
243
+ ```
244
+
245
+ ## Drag and Drop
246
+
247
+ - Click and drag the notification by the header area
248
+ - Position is automatically saved to localStorage
249
+ - Component stays within viewport boundaries
250
+ - 12px safety margin from screen edges
251
+
252
+ ## Browser Support
253
+
254
+ - Chrome (latest)
255
+ - Firefox (latest)
256
+ - Safari (latest)
257
+ - Edge (latest)
258
+
259
+ ## License
260
+
261
+ MIT
262
+
263
+ ## Author
264
+
265
+ Your Name
266
+
267
+ ## Contributing
268
+
269
+ Contributions are welcome! Please feel free to submit a Pull Request.
package/dist/index.js ADDED
@@ -0,0 +1,535 @@
1
+ import { ref as w, computed as H, defineComponent as AV, onUnmounted as uV, watch as j, openBlock as c, createBlock as T, Teleport as dV, createElementVNode as r, normalizeStyle as U, createVNode as mV, TransitionGroup as gV, withCtx as fV, createElementBlock as l, Fragment as hV, renderList as wV, unref as pV, normalizeClass as X, resolveDynamicComponent as z, toDisplayString as F, createCommentVNode as I, withModifiers as _, mergeProps as yV, nextTick as $ } from "vue";
2
+ const L = "dynamic-island-position", O = "dynamic-island-mem-position", SV = () => `island-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, xV = () => ({
3
+ x: Math.max(
4
+ 12,
5
+ Math.min(
6
+ window.innerWidth / 2 - 150,
7
+ window.innerWidth - 320 - 12 - 20
8
+ )
9
+ ),
10
+ y: Math.max(12, 20)
11
+ }), vV = () => {
12
+ try {
13
+ const V = localStorage.getItem(L);
14
+ if (V) {
15
+ const n = JSON.parse(V);
16
+ if (typeof n.x == "number" && typeof n.y == "number")
17
+ return {
18
+ x: Math.max(
19
+ 12,
20
+ Math.min(
21
+ n.x,
22
+ window.innerWidth - 320 - 12 - 20
23
+ )
24
+ ),
25
+ y: Math.max(
26
+ 12,
27
+ Math.min(
28
+ n.y,
29
+ window.innerHeight - 80 - 12
30
+ )
31
+ )
32
+ };
33
+ }
34
+ } catch {
35
+ console.warn("Failed to load position from localStorage");
36
+ }
37
+ return xV();
38
+ }, Z = (V) => {
39
+ try {
40
+ localStorage.setItem(L, JSON.stringify(V));
41
+ } catch {
42
+ console.warn("Failed to save position to localStorage");
43
+ }
44
+ }, f = w([]), C = w([]), D = w(vV()), eV = w(!0), J = 3, tV = H(() => f.value.length < J), oV = H(() => C.value.length > 0), nV = () => {
45
+ for (; tV.value && oV.value; ) {
46
+ const V = C.value.shift();
47
+ V && f.value.push(V);
48
+ }
49
+ }, MV = (V) => {
50
+ const n = {
51
+ id: V.id || SV(),
52
+ type: V.type || "default",
53
+ title: V.title,
54
+ subtitle: V.subtitle,
55
+ icon: V.icon,
56
+ showIcon: V.showIcon ?? !0,
57
+ showClose: V.showClose ?? !0,
58
+ duration: V.duration ?? 3e3,
59
+ persistent: V.persistent ?? !1,
60
+ animation: V.animation || "slide",
61
+ progress: V.progress,
62
+ showProgress: V.showProgress ?? !1,
63
+ dynamicComponent: V.dynamicComponent,
64
+ backgroundColor: V.backgroundColor,
65
+ textColor: V.textColor,
66
+ soundEnabled: V.soundEnabled ?? !0,
67
+ soundUrl: V.soundUrl,
68
+ onClick: V.onClick,
69
+ onClose: V.onClose,
70
+ createdAt: Date.now(),
71
+ memPosition: V.memPosition ?? !1
72
+ };
73
+ return f.value.length < J ? (f.value.push(n), n.memPosition && sV()) : C.value.push(n), n.id;
74
+ }, CV = (V) => {
75
+ var a;
76
+ const n = f.value.findIndex((s) => s.id === V);
77
+ if (n > -1) {
78
+ const s = f.value[n];
79
+ (a = s.onClose) == null || a.call(s), f.value.splice(n, 1), s.memPosition && DV(), nV();
80
+ }
81
+ }, EV = () => {
82
+ f.value.forEach((V) => {
83
+ var n;
84
+ (n = V.onClose) == null || n.call(V);
85
+ }), f.value = [], C.value = [];
86
+ }, IV = () => {
87
+ C.value = [];
88
+ }, kV = (V, n, a) => {
89
+ const y = n || 320, b = a || 80;
90
+ D.value = {
91
+ // X轴:确保组件完全在可视区内,右侧增加滚动条安全区
92
+ x: Math.max(
93
+ 12,
94
+ Math.min(
95
+ V.x,
96
+ window.innerWidth - y - 12 - 0
97
+ )
98
+ ),
99
+ // Y轴:确保组件完全在可视区内,底部保留safeArea
100
+ y: Math.max(
101
+ 12,
102
+ Math.min(V.y, window.innerHeight - b - 12)
103
+ )
104
+ }, Z(D.value);
105
+ }, sV = () => {
106
+ try {
107
+ const V = localStorage.getItem(L);
108
+ V && localStorage.setItem(O, V);
109
+ } catch {
110
+ console.warn("Failed to save mem_position to localStorage");
111
+ }
112
+ Z(D.value);
113
+ }, DV = () => {
114
+ try {
115
+ const V = localStorage.getItem(O);
116
+ if (V) {
117
+ const n = JSON.parse(V);
118
+ typeof n.x == "number" && typeof n.y == "number" && (Z(n), D.value = n);
119
+ }
120
+ localStorage.removeItem(O);
121
+ } catch {
122
+ console.warn("Failed to restore mem_position from localStorage");
123
+ }
124
+ }, bV = (V) => {
125
+ eV.value = V;
126
+ }, BV = (V, n) => {
127
+ const a = f.value.find((s) => s.id === V);
128
+ a && (a.progress = Math.max(0, Math.min(100, n)));
129
+ }, QV = (V, n) => {
130
+ const a = f.value.find((s) => s.id === V);
131
+ a && Object.assign(a, n);
132
+ }, aV = () => ({
133
+ visibleIslands: f,
134
+ queue: C,
135
+ position: D,
136
+ globalSoundEnabled: eV,
137
+ maxVisible: J,
138
+ hasVisibleSlots: tV,
139
+ hasQueuedItems: oV,
140
+ add: MV,
141
+ remove: CV,
142
+ clear: EV,
143
+ clearQueue: IV,
144
+ updatePosition: kV,
145
+ saveMemPosition: sV,
146
+ setGlobalSoundEnabled: bV,
147
+ updateProgress: BV,
148
+ updateIsland: QV,
149
+ processQueue: nV
150
+ }), k = new URL("data:audio/mpeg;base64,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knmSNGpnU/dT0H2qRZFHRWjpIqVTUk/UbPl0EAACA12sDZ4GHg2IgAVRmYZEBhYWmRVgY7ap03CGwg2WrWCcF/H5n3FO1kDVK9kZtyT2bldZDVm0ODaF48HWc6hUxnd95g7gvavsYtnFq+26brG+Mf/cHe7YrnWYOIW95pbE+Mbe/OrXti319W3rfrNbNLa+PSNcmNh8O7VMQU1FMy4xMDEgKGJldGEgMilVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkuQzzzkXQB3JAAgAADSDgAAEPlQswdceACAAANIKAAARVVVVVAAAADIgCAggAOfxoBIemFg8mQQ31cDAJOTXESjHwpTBAPa+JioCipTDQC1KueBgggGkFF0Y7AxAoDOgQASAhYV0NW8NXBcGDY2GqwyKQIgxFvBuwToNgUmThSGWFbENFy/NBW4hcg4pQighUmj6JSHO/JY8Tg7BQYuccYuYmSKkBSWXf47DBBRACYHeRckjIiw5xRJ0u0S7/yCJE0XCGFAg5FzcqLKRFiBGJdLqy6TJkRb/7kwRQnCDl83PGZuRQihOE+bkWMUVrLpFTIvE0iySJd//6aJfNyKEUNCfTrL5uRQnDQ3/+RUyLxeqSMS6RUyLxlSLxiXSZTEFNRTMuMTAxIChiZXRhIDIpVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZL0AB8h9yN52gAAAAA0gwAAAAAABpBwAACAAADSDgAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ==", import.meta.url).href, YV = {
151
+ default: k,
152
+ success: k,
153
+ error: k,
154
+ warning: k,
155
+ info: k
156
+ };
157
+ let G = null;
158
+ const RV = () => (G || (G = new (window.AudioContext || window.webkitAudioContext)()), G), M = (V, n, a = "sine") => {
159
+ try {
160
+ const s = RV(), A = s.createOscillator(), u = s.createGain();
161
+ A.connect(u), u.connect(s.destination), A.frequency.value = V, A.type = a, u.gain.setValueAtTime(0.3, s.currentTime), u.gain.exponentialRampToValueAtTime(
162
+ 0.01,
163
+ s.currentTime + n
164
+ ), A.start(s.currentTime), A.stop(s.currentTime + n);
165
+ } catch (s) {
166
+ console.warn("Failed to play sound:", s);
167
+ }
168
+ }, VV = (V) => {
169
+ switch (V) {
170
+ case "success":
171
+ M(880, 0.15), setTimeout(() => M(1100, 0.2), 100);
172
+ break;
173
+ case "error":
174
+ M(200, 0.3, "sawtooth");
175
+ break;
176
+ case "warning":
177
+ M(600, 0.2), setTimeout(() => M(500, 0.2), 150);
178
+ break;
179
+ case "info":
180
+ M(700, 0.15);
181
+ break;
182
+ }
183
+ }, NV = (V, n, a = !0) => {
184
+ if (!a) return;
185
+ const s = n || YV[V];
186
+ s ? new Audio(s).play().catch((u) => {
187
+ console.warn("Failed to play sound:", u), VV(V);
188
+ }) : VV(V);
189
+ }, TV = ["onClick"], UV = { class: "island-content" }, FV = {
190
+ key: 0,
191
+ class: "island-icon"
192
+ }, GV = { key: 1 }, OV = {
193
+ key: 1,
194
+ class: "island-icon default-icon"
195
+ }, HV = {
196
+ key: 0,
197
+ viewBox: "0 0 24 24",
198
+ fill: "none",
199
+ stroke: "currentColor",
200
+ "stroke-width": "2"
201
+ }, LV = {
202
+ key: 1,
203
+ viewBox: "0 0 24 24",
204
+ fill: "none",
205
+ stroke: "currentColor",
206
+ "stroke-width": "2"
207
+ }, ZV = {
208
+ key: 2,
209
+ viewBox: "0 0 24 24",
210
+ fill: "none",
211
+ stroke: "currentColor",
212
+ "stroke-width": "2"
213
+ }, JV = {
214
+ key: 3,
215
+ viewBox: "0 0 24 24",
216
+ fill: "none",
217
+ stroke: "currentColor",
218
+ "stroke-width": "2"
219
+ }, WV = {
220
+ key: 4,
221
+ viewBox: "0 0 24 24",
222
+ fill: "none",
223
+ stroke: "currentColor",
224
+ "stroke-width": "2"
225
+ }, PV = { class: "island-text" }, KV = { class: "island-title" }, qV = {
226
+ key: 0,
227
+ class: "island-subtitle"
228
+ }, jV = ["onClick"], XV = {
229
+ key: 0,
230
+ class: "island-progress"
231
+ }, zV = {
232
+ key: 1,
233
+ class: "island-dynamic-component"
234
+ }, _V = /* @__PURE__ */ AV({
235
+ __name: "DynamicIsland",
236
+ setup(V) {
237
+ const n = aV(), { visibleIslands: a, position: s, globalSoundEnabled: A } = n, u = w(null), p = w(!1), y = w({ x: 0, y: 0 }), b = H(() => ({
238
+ left: `${s.value.x}px`,
239
+ top: `${s.value.y}px`,
240
+ zIndex: 99999
241
+ })), W = (o) => {
242
+ const e = {};
243
+ return o.backgroundColor && (e.background = o.backgroundColor), o.textColor && (e.color = o.textColor), e;
244
+ }, P = (o) => {
245
+ const e = o.target;
246
+ e.closest(".island-close") || e.closest(".island-dynamic-component") || !e.closest(".island-header") || (p.value = !0, y.value = {
247
+ x: o.clientX - s.value.x,
248
+ y: o.clientY - s.value.y
249
+ }, document.addEventListener("mousemove", Q), document.addEventListener("mouseup", i));
250
+ }, Q = (o) => {
251
+ var x, v;
252
+ if (!p.value) return;
253
+ const e = 12, t = 20, m = ((x = u.value) == null ? void 0 : x.offsetWidth) || 320, B = ((v = u.value) == null ? void 0 : v.offsetHeight) || 80;
254
+ let h = o.clientX - y.value.x, E = o.clientY - y.value.y;
255
+ h = Math.max(
256
+ e,
257
+ Math.min(
258
+ h,
259
+ window.innerWidth - m - e - t
260
+ )
261
+ ), E = Math.max(
262
+ e,
263
+ Math.min(E, window.innerHeight - B - e)
264
+ ), n.updatePosition({ x: h, y: E }, m, B);
265
+ }, i = () => {
266
+ p.value = !1, document.removeEventListener("mousemove", Q), document.removeEventListener("mouseup", i);
267
+ }, d = (o) => {
268
+ var e;
269
+ p.value || (e = o.onClick) == null || e.call(o);
270
+ }, g = (o) => {
271
+ n.remove(o);
272
+ }, iV = (o, e) => {
273
+ lV("dynamic-island"), $(() => {
274
+ e();
275
+ });
276
+ }, rV = (o, e) => {
277
+ $(() => {
278
+ e();
279
+ });
280
+ }, S = /* @__PURE__ */ new Map(), cV = (o) => {
281
+ if (o.persistent || o.duration <= 0) return;
282
+ K(o.id);
283
+ const e = window.setTimeout(() => {
284
+ n.remove(o.id);
285
+ }, o.duration);
286
+ S.set(o.id, e);
287
+ }, K = (o) => {
288
+ const e = S.get(o);
289
+ e && (clearTimeout(e), S.delete(o));
290
+ };
291
+ uV(() => {
292
+ S.forEach((o) => clearTimeout(o)), S.clear();
293
+ }), j(
294
+ () => a.value.length,
295
+ () => {
296
+ a.value.forEach((o) => {
297
+ !o.persistent && o.duration > 0 && !S.has(o.id) && (cV(o), o.soundEnabled && A.value && NV(o.type, o.soundUrl, !0));
298
+ });
299
+ },
300
+ { immediate: !0 }
301
+ ), j(
302
+ a,
303
+ (o, e) => {
304
+ const t = new Set(o.map((m) => m.id));
305
+ new Set((e || []).map((m) => m.id)), e == null || e.forEach((m) => {
306
+ t.has(m.id) || K(m.id);
307
+ });
308
+ },
309
+ { deep: !0 }
310
+ );
311
+ function lV(o) {
312
+ const e = document.getElementById(o);
313
+ if (!e)
314
+ return console.warn(`ID为 ${o} 的DOM元素不存在`), null;
315
+ const t = e.getBoundingClientRect(), m = window.innerWidth || document.documentElement.clientWidth, B = window.innerHeight || document.documentElement.clientHeight, h = 12, E = 12, x = h, v = B - h, Y = h, R = m - h - E, q = t.top >= x && t.left >= Y && t.bottom <= v && t.right <= R;
316
+ if (!q) {
317
+ const N = {
318
+ // 垂直方向:贴合顶部安全区 / 贴合底部安全区 / 保持原位
319
+ top: t.top < x ? x : t.bottom > v ? v - t.height : t.top,
320
+ // 水平方向:贴合左侧安全区 / 贴合右侧安全区 / 保持原位
321
+ left: t.left < Y ? Y : t.right > R ? R - t.width : t.left
322
+ };
323
+ console.log("safePosition", N), e.style.position = "fixed", e.style.left = `${N.left}px`, console.log(`✅ 已调整ID为 ${o} 的DOM到视口内`, N);
324
+ }
325
+ return {
326
+ width: e.offsetWidth,
327
+ clientWidth: e.clientWidth,
328
+ position: {
329
+ top: t.top,
330
+ left: t.left,
331
+ right: t.right,
332
+ bottom: t.bottom,
333
+ x: t.x,
334
+ y: t.y
335
+ },
336
+ isInViewport: q,
337
+ // safePosition, // 你需要的:带安全区的目标位置
338
+ domRect: t
339
+ };
340
+ }
341
+ return (o, e) => (c(), T(dV, { to: "body" }, [
342
+ r("div", {
343
+ id: "dynamic-island",
344
+ ref_key: "containerRef",
345
+ ref: u,
346
+ class: "dynamic-island-container",
347
+ style: U(b.value),
348
+ onMousedown: P
349
+ }, [
350
+ mV(gV, {
351
+ name: "island",
352
+ tag: "div",
353
+ class: "island-list",
354
+ onEnter: iV,
355
+ onLeave: rV
356
+ }, {
357
+ default: fV(() => [
358
+ (c(!0), l(hV, null, wV(pV(a), (t) => (c(), l("div", {
359
+ key: t.id,
360
+ class: X(["dynamic-island", [
361
+ `island-${t.type}`,
362
+ `animation-${t.animation}`
363
+ ]]),
364
+ style: U(W(t)),
365
+ onClick: (m) => d(t)
366
+ }, [
367
+ r("div", UV, [
368
+ r("div", {
369
+ class: X(["island-header", { "draggable-area": !0 }])
370
+ }, [
371
+ t.showIcon && t.icon ? (c(), l("div", FV, [
372
+ typeof t.icon != "string" ? (c(), T(z(t.icon), { key: 0 })) : (c(), l("span", GV, F(t.icon), 1))
373
+ ])) : t.showIcon ? (c(), l("div", OV, [
374
+ t.type === "success" ? (c(), l("svg", HV, [...e[1] || (e[1] = [
375
+ r("path", { d: "M20 6L9 17l-5-5" }, null, -1)
376
+ ])])) : t.type === "error" ? (c(), l("svg", LV, [...e[2] || (e[2] = [
377
+ r("circle", {
378
+ cx: "12",
379
+ cy: "12",
380
+ r: "10"
381
+ }, null, -1),
382
+ r("path", { d: "M15 9l-6 6M9 9l6 6" }, null, -1)
383
+ ])])) : t.type === "warning" ? (c(), l("svg", ZV, [...e[3] || (e[3] = [
384
+ r("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" }, null, -1),
385
+ r("line", {
386
+ x1: "12",
387
+ y1: "9",
388
+ x2: "12",
389
+ y2: "13"
390
+ }, null, -1),
391
+ r("line", {
392
+ x1: "12",
393
+ y1: "17",
394
+ x2: "12.01",
395
+ y2: "17"
396
+ }, null, -1)
397
+ ])])) : t.type === "info" ? (c(), l("svg", JV, [...e[4] || (e[4] = [
398
+ r("circle", {
399
+ cx: "12",
400
+ cy: "12",
401
+ r: "10"
402
+ }, null, -1),
403
+ r("line", {
404
+ x1: "12",
405
+ y1: "16",
406
+ x2: "12",
407
+ y2: "12"
408
+ }, null, -1),
409
+ r("line", {
410
+ x1: "12",
411
+ y1: "8",
412
+ x2: "12.01",
413
+ y2: "8"
414
+ }, null, -1)
415
+ ])])) : (c(), l("svg", WV, [...e[5] || (e[5] = [
416
+ r("circle", {
417
+ cx: "12",
418
+ cy: "12",
419
+ r: "10"
420
+ }, null, -1),
421
+ r("line", {
422
+ x1: "12",
423
+ y1: "8",
424
+ x2: "12",
425
+ y2: "12"
426
+ }, null, -1),
427
+ r("line", {
428
+ x1: "12",
429
+ y1: "16",
430
+ x2: "12.01",
431
+ y2: "16"
432
+ }, null, -1)
433
+ ])]))
434
+ ])) : I("", !0),
435
+ r("div", PV, [
436
+ r("div", KV, F(t.title), 1),
437
+ t.subtitle ? (c(), l("div", qV, F(t.subtitle), 1)) : I("", !0)
438
+ ]),
439
+ t.showClose ? (c(), l("button", {
440
+ key: 2,
441
+ class: "island-close",
442
+ onClick: _((m) => g(t.id), ["stop"]),
443
+ onMousedown: e[0] || (e[0] = _(() => {
444
+ }, ["stop"]))
445
+ }, [...e[6] || (e[6] = [
446
+ r("svg", {
447
+ viewBox: "0 0 24 24",
448
+ fill: "none",
449
+ stroke: "currentColor",
450
+ "stroke-width": "2"
451
+ }, [
452
+ r("path", { d: "M18 6L6 18M6 6l12 12" })
453
+ ], -1)
454
+ ])], 40, jV)) : I("", !0)
455
+ ]),
456
+ t.showProgress && t.progress !== void 0 ? (c(), l("div", XV, [
457
+ r("div", {
458
+ class: "progress-bar",
459
+ style: U({ width: `${t.progress}%` })
460
+ }, null, 4)
461
+ ])) : I("", !0),
462
+ t.dynamicComponent ? (c(), l("div", zV, [
463
+ (c(), T(z(t.dynamicComponent.component), yV({ ref_for: !0 }, t.dynamicComponent.props), null, 16))
464
+ ])) : I("", !0)
465
+ ])
466
+ ], 14, TV))), 128))
467
+ ]),
468
+ _: 1
469
+ })
470
+ ], 36)
471
+ ]));
472
+ }
473
+ }), $V = (V, n) => {
474
+ const a = V.__vccOpts || V;
475
+ for (const [s, A] of n)
476
+ a[s] = A;
477
+ return a;
478
+ }, Ve = /* @__PURE__ */ $V(_V, [["__scopeId", "data-v-7c261bf3"]]), te = () => {
479
+ const V = aV();
480
+ return {
481
+ show: (i) => V.add(i),
482
+ success: (i, d, g) => V.add({
483
+ type: "success",
484
+ title: i,
485
+ subtitle: d,
486
+ ...g
487
+ }),
488
+ error: (i, d, g) => V.add({
489
+ type: "error",
490
+ title: i,
491
+ subtitle: d,
492
+ duration: (g == null ? void 0 : g.duration) ?? 8e3,
493
+ ...g
494
+ }),
495
+ warning: (i, d, g) => V.add({
496
+ type: "warning",
497
+ title: i,
498
+ subtitle: d,
499
+ ...g
500
+ }),
501
+ info: (i, d, g) => V.add({
502
+ type: "info",
503
+ title: i,
504
+ subtitle: d,
505
+ ...g
506
+ }),
507
+ close: (i) => {
508
+ console.log("close", i), V.remove(i);
509
+ },
510
+ clear: () => {
511
+ V.clear();
512
+ },
513
+ clearQueue: () => {
514
+ V.clearQueue();
515
+ },
516
+ updateProgress: (i, d) => {
517
+ V.updateProgress(i, d);
518
+ },
519
+ updateIsland: (i, d) => {
520
+ V.updateIsland(i, d);
521
+ },
522
+ setSoundEnabled: (i) => {
523
+ V.setGlobalSoundEnabled(i);
524
+ }
525
+ };
526
+ }, oe = {
527
+ install(V) {
528
+ V.component("DynamicIsland", Ve);
529
+ }
530
+ };
531
+ export {
532
+ Ve as DynamicIsland,
533
+ oe as default,
534
+ te as useDynamicIsland
535
+ };
@@ -0,0 +1 @@
1
+ (function(f,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(f=typeof globalThis<"u"?globalThis:f||self,e(f.Vue3DynamicIsland={},f.Vue))})(this,function(f,e){"use strict";var N=typeof document<"u"?document.currentScript:null;const D="dynamic-island-position",b="dynamic-island-mem-position",z=()=>`island-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,v=()=>({x:Math.max(12,Math.min(window.innerWidth/2-150,window.innerWidth-320-12-20)),y:Math.max(12,20)}),$=()=>{try{const V=localStorage.getItem(D);if(V){const a=JSON.parse(V);if(typeof a.x=="number"&&typeof a.y=="number")return{x:Math.max(12,Math.min(a.x,window.innerWidth-320-12-20)),y:Math.max(12,Math.min(a.y,window.innerHeight-80-12))}}}catch{console.warn("Failed to load position from localStorage")}return v()},Q=V=>{try{localStorage.setItem(D,JSON.stringify(V))}catch{console.warn("Failed to save position to localStorage")}},m=e.ref([]),p=e.ref([]),x=e.ref($()),O=e.ref(!0),R=3,L=e.computed(()=>m.value.length<R),H=e.computed(()=>p.value.length>0),Z=()=>{for(;L.value&&H.value;){const V=p.value.shift();V&&m.value.push(V)}},ee=V=>{const a={id:V.id||z(),type:V.type||"default",title:V.title,subtitle:V.subtitle,icon:V.icon,showIcon:V.showIcon??!0,showClose:V.showClose??!0,duration:V.duration??3e3,persistent:V.persistent??!1,animation:V.animation||"slide",progress:V.progress,showProgress:V.showProgress??!1,dynamicComponent:V.dynamicComponent,backgroundColor:V.backgroundColor,textColor:V.textColor,soundEnabled:V.soundEnabled??!0,soundUrl:V.soundUrl,onClick:V.onClick,onClose:V.onClose,createdAt:Date.now(),memPosition:V.memPosition??!1};return m.value.length<R?(m.value.push(a),a.memPosition&&J()):p.value.push(a),a.id},Ve=V=>{var r;const a=m.value.findIndex(s=>s.id===V);if(a>-1){const s=m.value[a];(r=s.onClose)==null||r.call(s),m.value.splice(a,1),s.memPosition&&ae(),Z()}},te=()=>{m.value.forEach(V=>{var a;(a=V.onClose)==null||a.call(V)}),m.value=[],p.value=[]},oe=()=>{p.value=[]},ne=(V,a,r)=>{const y=a||320,B=r||80;x.value={x:Math.max(12,Math.min(V.x,window.innerWidth-y-12-0)),y:Math.max(12,Math.min(V.y,window.innerHeight-B-12))},Q(x.value)},J=()=>{try{const V=localStorage.getItem(D);V&&localStorage.setItem(b,V)}catch{console.warn("Failed to save mem_position to localStorage")}Q(x.value)},ae=()=>{try{const V=localStorage.getItem(b);if(V){const a=JSON.parse(V);typeof a.x=="number"&&typeof a.y=="number"&&(Q(a),x.value=a)}localStorage.removeItem(b)}catch{console.warn("Failed to restore mem_position from localStorage")}},se=V=>{O.value=V},re=(V,a)=>{const r=m.value.find(s=>s.id===V);r&&(r.progress=Math.max(0,Math.min(100,a)))},ce=(V,a)=>{const r=m.value.find(s=>s.id===V);r&&Object.assign(r,a)},P=()=>({visibleIslands:m,queue:p,position:x,globalSoundEnabled:O,maxVisible:R,hasVisibleSlots:L,hasQueuedItems:H,add:ee,remove:Ve,clear:te,clearQueue:oe,updatePosition:ne,saveMemPosition:J,setGlobalSoundEnabled:se,updateProgress:re,updateIsland:ce,processQueue:Z}),C=new URL("data:audio/mpeg;base64,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knmSNGpnU/dT0H2qRZFHRWjpIqVTUk/UbPl0EAACA12sDZ4GHg2IgAVRmYZEBhYWmRVgY7ap03CGwg2WrWCcF/H5n3FO1kDVK9kZtyT2bldZDVm0ODaF48HWc6hUxnd95g7gvavsYtnFq+26brG+Mf/cHe7YrnWYOIW95pbE+Mbe/OrXti319W3rfrNbNLa+PSNcmNh8O7VMQU1FMy4xMDEgKGJldGEgMilVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+5JkuQzzzkXQB3JAAgAADSDgAAEPlQswdceACAAANIKAAARVVVVVAAAADIgCAggAOfxoBIemFg8mQQ31cDAJOTXESjHwpTBAPa+JioCipTDQC1KueBgggGkFF0Y7AxAoDOgQASAhYV0NW8NXBcGDY2GqwyKQIgxFvBuwToNgUmThSGWFbENFy/NBW4hcg4pQighUmj6JSHO/JY8Tg7BQYuccYuYmSKkBSWXf47DBBRACYHeRckjIiw5xRJ0u0S7/yCJE0XCGFAg5FzcqLKRFiBGJdLqy6TJkRb/7kwRQnCDl83PGZuRQihOE+bkWMUVrLpFTIvE0iySJd//6aJfNyKEUNCfTrL5uRQnDQ3/+RUyLxeqSMS6RUyLxlSLxiXSZTEFNRTMuMTAxIChiZXRhIDIpVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//uSZL0AB8h9yN52gAAAAA0gwAAAAAABpBwAACAAADSDgAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ==",typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:N&&N.tagName.toUpperCase()==="SCRIPT"&&N.src||new URL("index.umd.cjs",document.baseURI).href).href,le={default:C,success:C,error:C,warning:C,info:C};let Y=null;const ie=()=>(Y||(Y=new(window.AudioContext||window.webkitAudioContext)),Y),h=(V,a,r="sine")=>{try{const s=ie(),l=s.createOscillator(),i=s.createGain();l.connect(i),i.connect(s.destination),l.frequency.value=V,l.type=r,i.gain.setValueAtTime(.3,s.currentTime),i.gain.exponentialRampToValueAtTime(.01,s.currentTime+a),l.start(s.currentTime),l.stop(s.currentTime+a)}catch(s){console.warn("Failed to play sound:",s)}},W=V=>{switch(V){case"success":h(880,.15),setTimeout(()=>h(1100,.2),100);break;case"error":h(200,.3,"sawtooth");break;case"warning":h(600,.2),setTimeout(()=>h(500,.2),150);break;case"info":h(700,.15);break}},de=(V,a,r=!0)=>{if(!r)return;const s=a||le[V];s?new Audio(s).play().catch(i=>{console.warn("Failed to play sound:",i),W(V)}):W(V)},Ae=["onClick"],me={class:"island-content"},ue={key:0,class:"island-icon"},fe={key:1},ge={key:1,class:"island-icon default-icon"},pe={key:0,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},he={key:1,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},we={key:2,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},ye={key:3,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},Ee={key:4,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},Se={class:"island-text"},ke={class:"island-title"},xe={key:0,class:"island-subtitle"},Ce=["onClick"],Me={key:0,class:"island-progress"},Be={key:1,class:"island-dynamic-component"},K=((V,a)=>{const r=V.__vccOpts||V;for(const[s,l]of a)r[s]=l;return r})(e.defineComponent({__name:"DynamicIsland",setup(V){const a=P(),{visibleIslands:r,position:s,globalSoundEnabled:l}=a,i=e.ref(null),w=e.ref(!1),y=e.ref({x:0,y:0}),B=e.computed(()=>({left:`${s.value.x}px`,top:`${s.value.y}px`,zIndex:99999})),q=n=>{const t={};return n.backgroundColor&&(t.background=n.backgroundColor),n.textColor&&(t.color=n.textColor),t},j=n=>{const t=n.target;t.closest(".island-close")||t.closest(".island-dynamic-component")||!t.closest(".island-header")||(w.value=!0,y.value={x:n.clientX-s.value.x,y:n.clientY-s.value.y},document.addEventListener("mousemove",T),document.addEventListener("mouseup",c))},T=n=>{var S,k;if(!w.value)return;const t=12,o=20,A=((S=i.value)==null?void 0:S.offsetWidth)||320,I=((k=i.value)==null?void 0:k.offsetHeight)||80;let g=n.clientX-y.value.x,M=n.clientY-y.value.y;g=Math.max(t,Math.min(g,window.innerWidth-A-t-o)),M=Math.max(t,Math.min(M,window.innerHeight-I-t)),a.updatePosition({x:g,y:M},A,I)},c=()=>{w.value=!1,document.removeEventListener("mousemove",T),document.removeEventListener("mouseup",c)},d=n=>{var t;w.value||(t=n.onClick)==null||t.call(n)},u=n=>{a.remove(n)},De=(n,t)=>{Re("dynamic-island"),e.nextTick(()=>{t()})},be=(n,t)=>{e.nextTick(()=>{t()})},E=new Map,Qe=n=>{if(n.persistent||n.duration<=0)return;X(n.id);const t=window.setTimeout(()=>{a.remove(n.id)},n.duration);E.set(n.id,t)},X=n=>{const t=E.get(n);t&&(clearTimeout(t),E.delete(n))};e.onUnmounted(()=>{E.forEach(n=>clearTimeout(n)),E.clear()}),e.watch(()=>r.value.length,()=>{r.value.forEach(n=>{!n.persistent&&n.duration>0&&!E.has(n.id)&&(Qe(n),n.soundEnabled&&l.value&&de(n.type,n.soundUrl,!0))})},{immediate:!0}),e.watch(r,(n,t)=>{const o=new Set(n.map(A=>A.id));new Set((t||[]).map(A=>A.id)),t==null||t.forEach(A=>{o.has(A.id)||X(A.id)})},{deep:!0});function Re(n){const t=document.getElementById(n);if(!t)return console.warn(`ID为 ${n} 的DOM元素不存在`),null;const o=t.getBoundingClientRect(),A=window.innerWidth||document.documentElement.clientWidth,I=window.innerHeight||document.documentElement.clientHeight,g=12,M=12,S=g,k=I-g,U=g,F=A-g-M,_=o.top>=S&&o.left>=U&&o.bottom<=k&&o.right<=F;if(!_){const G={top:o.top<S?S:o.bottom>k?k-o.height:o.top,left:o.left<U?U:o.right>F?F-o.width:o.left};console.log("safePosition",G),t.style.position="fixed",t.style.left=`${G.left}px`,console.log(`✅ 已调整ID为 ${n} 的DOM到视口内`,G)}return{width:t.offsetWidth,clientWidth:t.clientWidth,position:{top:o.top,left:o.left,right:o.right,bottom:o.bottom,x:o.x,y:o.y},isInViewport:_,domRect:o}}return(n,t)=>(e.openBlock(),e.createBlock(e.Teleport,{to:"body"},[e.createElementVNode("div",{id:"dynamic-island",ref_key:"containerRef",ref:i,class:"dynamic-island-container",style:e.normalizeStyle(B.value),onMousedown:j},[e.createVNode(e.TransitionGroup,{name:"island",tag:"div",class:"island-list",onEnter:De,onLeave:be},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(r),o=>(e.openBlock(),e.createElementBlock("div",{key:o.id,class:e.normalizeClass(["dynamic-island",[`island-${o.type}`,`animation-${o.animation}`]]),style:e.normalizeStyle(q(o)),onClick:A=>d(o)},[e.createElementVNode("div",me,[e.createElementVNode("div",{class:e.normalizeClass(["island-header",{"draggable-area":!0}])},[o.showIcon&&o.icon?(e.openBlock(),e.createElementBlock("div",ue,[typeof o.icon!="string"?(e.openBlock(),e.createBlock(e.resolveDynamicComponent(o.icon),{key:0})):(e.openBlock(),e.createElementBlock("span",fe,e.toDisplayString(o.icon),1))])):o.showIcon?(e.openBlock(),e.createElementBlock("div",ge,[o.type==="success"?(e.openBlock(),e.createElementBlock("svg",pe,[...t[1]||(t[1]=[e.createElementVNode("path",{d:"M20 6L9 17l-5-5"},null,-1)])])):o.type==="error"?(e.openBlock(),e.createElementBlock("svg",he,[...t[2]||(t[2]=[e.createElementVNode("circle",{cx:"12",cy:"12",r:"10"},null,-1),e.createElementVNode("path",{d:"M15 9l-6 6M9 9l6 6"},null,-1)])])):o.type==="warning"?(e.openBlock(),e.createElementBlock("svg",we,[...t[3]||(t[3]=[e.createElementVNode("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"},null,-1),e.createElementVNode("line",{x1:"12",y1:"9",x2:"12",y2:"13"},null,-1),e.createElementVNode("line",{x1:"12",y1:"17",x2:"12.01",y2:"17"},null,-1)])])):o.type==="info"?(e.openBlock(),e.createElementBlock("svg",ye,[...t[4]||(t[4]=[e.createElementVNode("circle",{cx:"12",cy:"12",r:"10"},null,-1),e.createElementVNode("line",{x1:"12",y1:"16",x2:"12",y2:"12"},null,-1),e.createElementVNode("line",{x1:"12",y1:"8",x2:"12.01",y2:"8"},null,-1)])])):(e.openBlock(),e.createElementBlock("svg",Ee,[...t[5]||(t[5]=[e.createElementVNode("circle",{cx:"12",cy:"12",r:"10"},null,-1),e.createElementVNode("line",{x1:"12",y1:"8",x2:"12",y2:"12"},null,-1),e.createElementVNode("line",{x1:"12",y1:"16",x2:"12.01",y2:"16"},null,-1)])]))])):e.createCommentVNode("",!0),e.createElementVNode("div",Se,[e.createElementVNode("div",ke,e.toDisplayString(o.title),1),o.subtitle?(e.openBlock(),e.createElementBlock("div",xe,e.toDisplayString(o.subtitle),1)):e.createCommentVNode("",!0)]),o.showClose?(e.openBlock(),e.createElementBlock("button",{key:2,class:"island-close",onClick:e.withModifiers(A=>u(o.id),["stop"]),onMousedown:t[0]||(t[0]=e.withModifiers(()=>{},["stop"]))},[...t[6]||(t[6]=[e.createElementVNode("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"},[e.createElementVNode("path",{d:"M18 6L6 18M6 6l12 12"})],-1)])],40,Ce)):e.createCommentVNode("",!0)]),o.showProgress&&o.progress!==void 0?(e.openBlock(),e.createElementBlock("div",Me,[e.createElementVNode("div",{class:"progress-bar",style:e.normalizeStyle({width:`${o.progress}%`})},null,4)])):e.createCommentVNode("",!0),o.dynamicComponent?(e.openBlock(),e.createElementBlock("div",Be,[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(o.dynamicComponent.component),e.mergeProps({ref_for:!0},o.dynamicComponent.props),null,16))])):e.createCommentVNode("",!0)])],14,Ae))),128))]),_:1})],36)]))}}),[["__scopeId","data-v-7c261bf3"]]),Ie=()=>{const V=P();return{show:c=>V.add(c),success:(c,d,u)=>V.add({type:"success",title:c,subtitle:d,...u}),error:(c,d,u)=>V.add({type:"error",title:c,subtitle:d,duration:(u==null?void 0:u.duration)??8e3,...u}),warning:(c,d,u)=>V.add({type:"warning",title:c,subtitle:d,...u}),info:(c,d,u)=>V.add({type:"info",title:c,subtitle:d,...u}),close:c=>{console.log("close",c),V.remove(c)},clear:()=>{V.clear()},clearQueue:()=>{V.clearQueue()},updateProgress:(c,d)=>{V.updateProgress(c,d)},updateIsland:(c,d)=>{V.updateIsland(c,d)},setSoundEnabled:c=>{V.setGlobalSoundEnabled(c)}}},Ne={install(V){V.component("DynamicIsland",K)}};f.DynamicIsland=K,f.default=Ne,f.useDynamicIsland=Ie,Object.defineProperties(f,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .dynamic-island-container[data-v-7c261bf3]{position:fixed;pointer-events:auto}.island-list[data-v-7c261bf3]{display:flex;flex-direction:column;gap:8px}.dynamic-island[data-v-7c261bf3]{min-width:240px;max-width:320px;background:#000000d9;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-radius:10px;padding:10px 14px;box-shadow:0 6px 24px #00000059,0 0 0 1px #ffffff1a;color:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;transition:all .3s cubic-bezier(.4,0,.2,1);pointer-events:auto}.island-success[data-v-7c261bf3]{background:#22c55ee6}.island-error[data-v-7c261bf3]{background:#ef4444e6}.island-warning[data-v-7c261bf3]{background:#f59e0be6}.island-info[data-v-7c261bf3]{background:#3b82f6e6}.island-content[data-v-7c261bf3]{display:flex;flex-direction:column;gap:8px}.island-header[data-v-7c261bf3]{display:flex;align-items:center;gap:10px;cursor:grab}.island-header[data-v-7c261bf3]:active{cursor:grabbing}.island-icon[data-v-7c261bf3]{width:20px;height:20px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.island-icon svg[data-v-7c261bf3]{width:100%;height:100%}.default-icon[data-v-7c261bf3]{background:#fff3;border-radius:50%;padding:3px}.island-text[data-v-7c261bf3]{flex:1;min-width:0}.island-title[data-v-7c261bf3]{font-size:13px;font-weight:600;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.island-subtitle[data-v-7c261bf3]{font-size:11px;opacity:.85;margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.island-close[data-v-7c261bf3]{width:22px;height:22px;border:none;background:#ffffff26;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#fff;transition:all .2s ease;flex-shrink:0}.island-close[data-v-7c261bf3]:hover{background:#ffffff40;transform:scale(1.1)}.island-close svg[data-v-7c261bf3]{width:12px;height:12px}.island-progress[data-v-7c261bf3]{height:2px;background:#fff3;border-radius:2px;overflow:hidden}.progress-bar[data-v-7c261bf3]{height:100%;background:#fff;border-radius:2px;transition:width .3s ease}.island-dynamic-component[data-v-7c261bf3]{max-height:500px;overflow-y:auto}.island-dynamic-component[data-v-7c261bf3]::-webkit-scrollbar{width:6px;height:6px}.island-dynamic-component[data-v-7c261bf3]::-webkit-scrollbar-track{background:#ffffff1a;border-radius:5px}.island-dynamic-component[data-v-7c261bf3]::-webkit-scrollbar-thumb{background:#ffffff4d;border-radius:5px}.island-enter-active[data-v-7c261bf3],.island-leave-active[data-v-7c261bf3]{transition:all .4s cubic-bezier(.4,0,.2,1)}.island-enter-from[data-v-7c261bf3]{opacity:0;transform:translateY(-20px) scale(.9)}.island-leave-to[data-v-7c261bf3]{opacity:0;transform:translateY(-10px) scale(.95)}.animation-fade.island-enter-from[data-v-7c261bf3]{opacity:0}.animation-slide.island-enter-from[data-v-7c261bf3]{opacity:0;transform:translate(100px)}.animation-zoom.island-enter-from[data-v-7c261bf3]{opacity:0;transform:scale(.5)}.animation-bounce.island-enter-from[data-v-7c261bf3]{opacity:0;transform:translateY(-50px)}.animation-bounce.island-enter-active[data-v-7c261bf3]{animation:bounceIn-7c261bf3 .5s cubic-bezier(.68,-.55,.265,1.55)}@keyframes bounceIn-7c261bf3{0%{opacity:0;transform:translateY(-50px) scale(.3)}50%{transform:translateY(10px) scale(1.05)}70%{transform:translateY(-5px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}@media (max-width: 480px){.dynamic-island[data-v-7c261bf3]{min-width:calc(100vw - 24px);max-width:calc(100vw - 24px)}}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "vue3-dynamic-island",
3
+ "version": "1.0.1",
4
+ "description": "A commercial-grade Dynamic Island notification component for Vue 3",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./style.css": "./dist/index.css"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "keywords": [
20
+ "vue",
21
+ "vue3",
22
+ "notification",
23
+ "dynamic-island",
24
+ "toast",
25
+ "alert",
26
+ "component",
27
+ "typescript"
28
+ ],
29
+ "author": "piapia_",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://gitee.com/tender_only/dynamic-island"
34
+ },
35
+ "bugs": {
36
+ "url": "https://gitee.com/tender_only/dynamic-island/issues"
37
+ },
38
+ "homepage": "https://gitee.com/tender_only/dynamic-island",
39
+ "scripts": {
40
+ "dev": "vite",
41
+ "build": "vite build",
42
+ "preview": "vite preview",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "peerDependencies": {
46
+ "vue": "^3.0.0"
47
+ },
48
+ "devDependencies": {
49
+ "@vitejs/plugin-vue": "^5.0.3",
50
+ "typescript": "^5.3.3",
51
+ "vite": "^5.0.12"
52
+ }
53
+ }