@aquiferre/ui-kit 0.1.5 → 0.1.6

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,79 @@
1
+ <template>
2
+ <Teleport to="body">
3
+ <Transition name="fade">
4
+ <div v-if="visible" class="dialog-overlay">
5
+ <div class="fixed inset-0 bg-bg-overlay" @click="onOverlayClick" />
6
+ <div class="panel-glass dialog" :class="[sizeClass, customClass]">
7
+ <div v-if="title" class="flex items-center justify-between px-6 py-4 border-b border-border-primary">
8
+ <h3 class="text-lg font-medium text-text-primary">{{ title }}</h3>
9
+ <button
10
+ v-if="closable"
11
+ class="text-text-tertiary hover:text-text-primary text-2xl leading-none"
12
+ @click="close"
13
+ >&times;</button>
14
+ </div>
15
+ <div class="px-6 py-4">
16
+ <slot />
17
+ </div>
18
+ <div v-if="$slots.footer" class="px-6 py-4 border-t border-border-primary bg-bg-secondary/50 rounded-b-2xl">
19
+ <slot name="footer" />
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </Transition>
24
+ </Teleport>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { computed } from 'vue'
29
+
30
+ const props = withDefaults(defineProps<{
31
+ visible: boolean
32
+ title?: string
33
+ size?: 'sm' | 'md' | 'lg' | 'xl'
34
+ closable?: boolean
35
+ maskClosable?: boolean
36
+ customClass?: string
37
+ }>(), {
38
+ closable: true,
39
+ maskClosable: true,
40
+ size: 'md',
41
+ })
42
+
43
+ const emit = defineEmits<{
44
+ 'update:visible': [value: boolean]
45
+ close: []
46
+ }>()
47
+
48
+ const sizeClass = computed(() => {
49
+ const map: Record<string, string> = {
50
+ sm: 'max-w-sm',
51
+ md: 'max-w-lg',
52
+ lg: 'max-w-2xl',
53
+ xl: 'max-w-4xl',
54
+ }
55
+ return map[props.size] || 'max-w-lg'
56
+ })
57
+
58
+ function close() {
59
+ emit('update:visible', false)
60
+ emit('close')
61
+ }
62
+
63
+ function onOverlayClick() {
64
+ if (props.maskClosable) {
65
+ close()
66
+ }
67
+ }
68
+ </script>
69
+
70
+ <style scoped>
71
+ .fade-enter-active,
72
+ .fade-leave-active {
73
+ transition: opacity 0.2s ease;
74
+ }
75
+ .fade-enter-from,
76
+ .fade-leave-to {
77
+ opacity: 0;
78
+ }
79
+ </style>
@@ -1,4 +1,4 @@
1
- import { ref } from 'vue'
1
+ import { ref, type Ref } from 'vue'
2
2
  import type { ToastType } from '../types'
3
3
 
4
4
  interface ToastItem {
@@ -7,20 +7,38 @@ interface ToastItem {
7
7
  message: string
8
8
  }
9
9
 
10
- const toasts = ref<ToastItem[]>([])
11
- let nextId = 0
10
+ // 在全局对象上存储 toast 状态,确保模块重复加载时也能共享状态
11
+ function getGlobalToasts(): Ref<ToastItem[]> {
12
+ const w = window as any
13
+ if (!w.__TOAST_STATE__) {
14
+ w.__TOAST_STATE__ = ref<ToastItem[]>([])
15
+ }
16
+ return w.__TOAST_STATE__
17
+ }
18
+
19
+ function getGlobalNextId(): { value: number } {
20
+ const w = window as any
21
+ if (!w.__TOAST_NEXT_ID__) {
22
+ w.__TOAST_NEXT_ID__ = { value: 0 }
23
+ }
24
+ return w.__TOAST_NEXT_ID__
25
+ }
12
26
 
13
27
  function add(type: ToastType, message: string) {
14
- const id = nextId++
28
+ const toasts = getGlobalToasts()
29
+ const nextId = getGlobalNextId()
30
+ const id = nextId.value++
15
31
  toasts.value.push({ id, type, message })
16
32
  setTimeout(() => remove(id), 3000)
17
33
  }
18
34
 
19
35
  function remove(id: number) {
36
+ const toasts = getGlobalToasts()
20
37
  toasts.value = toasts.value.filter(t => t.id !== id)
21
38
  }
22
39
 
23
40
  export function useToast() {
41
+ const toasts = getGlobalToasts()
24
42
  return {
25
43
  toasts,
26
44
  success: (msg: string) => add('success', msg),
package/index.ts CHANGED
@@ -6,6 +6,7 @@ export { default as SearchInput } from './components/SearchInput.vue'
6
6
  export { default as FilterDropdown } from './components/FilterDropdown.vue'
7
7
  export { default as FormDialog } from './components/FormDialog.vue'
8
8
  export { default as ConfirmDialog } from './components/ConfirmDialog.vue'
9
+ export { default as Modal } from './components/Modal.vue'
9
10
  export { default as Toast } from './components/Toast.vue'
10
11
  export { default as StatusTag } from './components/StatusTag.vue'
11
12
  export { default as FileUploader } from './components/FileUploader.vue'
package/package.json CHANGED
@@ -1,17 +1,22 @@
1
1
  {
2
2
  "name": "@aquiferre/ui-kit",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "exports": {
8
8
  ".": "./index.ts"
9
9
  },
10
- "files": ["*.ts", "*.vue", "components/**/*.vue", "composables/**/*.ts"],
10
+ "files": [
11
+ "*.ts",
12
+ "*.vue",
13
+ "components/**/*.vue",
14
+ "composables/**/*.ts"
15
+ ],
11
16
  "peerDependencies": {
12
- "vue": ">=3.0.0",
17
+ "@aquiferre/theme-kit": ">=0.1.0",
13
18
  "pinia": ">=2.0.0",
14
- "@aquiferre/theme-kit": ">=0.1.0"
19
+ "vue": ">=3.0.0"
15
20
  },
16
21
  "publishConfig": {
17
22
  "access": "public"