@h-ai/ui 0.1.0-alpha.27 → 0.1.0-alpha.28
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/auto-import.d.ts +3 -0
- package/auto-import.js +3 -0
- package/dist/components/compounds/MessageBoxContainer.svelte +18 -0
- package/dist/components/compounds/MessageBoxContainer.svelte.d.ts +18 -0
- package/dist/components/compounds/MessageBoxDialog.svelte +193 -0
- package/dist/components/compounds/MessageBoxDialog.svelte.d.ts +7 -0
- package/dist/components/compounds/MessageContainer.svelte +200 -0
- package/dist/components/compounds/MessageContainer.svelte.d.ts +3 -0
- package/dist/components/compounds/Modal.svelte +0 -1
- package/dist/components/compounds/index.d.ts +3 -0
- package/dist/components/compounds/index.js +5 -0
- package/dist/components/scenes/app/ThemeColorPicker.svelte +7 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/message.svelte.d.ts +49 -0
- package/dist/message.svelte.js +77 -0
- package/dist/messagebox.svelte.d.ts +82 -0
- package/dist/messagebox.svelte.js +129 -0
- package/dist/messages/en-US.json +1 -0
- package/dist/messages/zh-CN.json +1 -0
- package/dist/types.d.ts +58 -0
- package/package.json +2 -2
package/auto-import.d.ts
CHANGED
|
@@ -57,6 +57,9 @@ declare global {
|
|
|
57
57
|
const Form: typeof import('@h-ai/ui')['Form']
|
|
58
58
|
const FormField: typeof import('@h-ai/ui')['FormField']
|
|
59
59
|
const InfiniteScroll: typeof import('@h-ai/ui')['InfiniteScroll']
|
|
60
|
+
const MessageContainer: typeof import('@h-ai/ui')['MessageContainer']
|
|
61
|
+
const MessageBoxContainer: typeof import('@h-ai/ui')['MessageBoxContainer']
|
|
62
|
+
const MessageBoxDialog: typeof import('@h-ai/ui')['MessageBoxDialog']
|
|
60
63
|
const Modal: typeof import('@h-ai/ui')['Modal']
|
|
61
64
|
const PageHeader: typeof import('@h-ai/ui')['PageHeader']
|
|
62
65
|
const Pagination: typeof import('@h-ai/ui')['Pagination']
|
package/auto-import.js
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
=============================================================================
|
|
3
|
+
@h-ai/ui - MessageBoxContainer 组件
|
|
4
|
+
=============================================================================
|
|
5
|
+
命令式弹框容器,渲染 messageBox store 中的所有弹框。
|
|
6
|
+
每个弹框由 MessageBoxDialog 独立管理 showModal()/close()。
|
|
7
|
+
|
|
8
|
+
使用 DaisyUI 样式 + tabler icon,不依赖 ElementUI。
|
|
9
|
+
=============================================================================
|
|
10
|
+
-->
|
|
11
|
+
<script lang='ts'>
|
|
12
|
+
import { messageBox } from '../../messagebox.svelte.js'
|
|
13
|
+
import MessageBoxDialog from './MessageBoxDialog.svelte'
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
{#each messageBox.items as item (item.id)}
|
|
17
|
+
<MessageBoxDialog {item} />
|
|
18
|
+
{/each}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const MessageBoxContainer: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type MessageBoxContainer = InstanceType<typeof MessageBoxContainer>;
|
|
18
|
+
export default MessageBoxContainer;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
单个 MessageBox 弹框,由 MessageBoxContainer 渲染。
|
|
3
|
+
内部使用原生 <dialog>.showModal() 进入浏览器 top layer。
|
|
4
|
+
行为对标 ElementUI MessageBox:
|
|
5
|
+
- 始终显示标题(默认"提示")和右上角关闭按钮;
|
|
6
|
+
- 遮罩层点击可通过 closeOnClickModal 配置。
|
|
7
|
+
-->
|
|
8
|
+
<script lang='ts'>
|
|
9
|
+
import type { MessageBoxItem } from '../../messagebox.svelte.js'
|
|
10
|
+
import { messageBox } from '../../messagebox.svelte.js'
|
|
11
|
+
import { uiM } from '../../messages.js'
|
|
12
|
+
import { cn } from '../../utils.js'
|
|
13
|
+
import Button from '../primitives/Button.svelte'
|
|
14
|
+
|
|
15
|
+
const { item }: { item: MessageBoxItem } = $props()
|
|
16
|
+
|
|
17
|
+
/** 图标类型到 tabler icon 的映射 */
|
|
18
|
+
const iconMap: Record<string, string> = {
|
|
19
|
+
info: 'icon-[tabler--info-circle]',
|
|
20
|
+
success: 'icon-[tabler--circle-check]',
|
|
21
|
+
warning: 'icon-[tabler--alert-triangle]',
|
|
22
|
+
error: 'icon-[tabler--circle-x]',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** 图标背景色映射 */
|
|
26
|
+
const iconBgMap: Record<string, string> = {
|
|
27
|
+
info: 'bg-info/15 text-info',
|
|
28
|
+
success: 'bg-success/15 text-success',
|
|
29
|
+
warning: 'bg-warning/15 text-warning',
|
|
30
|
+
error: 'bg-error/15 text-error',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let dialogEl: HTMLDialogElement | undefined = $state()
|
|
34
|
+
|
|
35
|
+
$effect(() => {
|
|
36
|
+
if (dialogEl && !dialogEl.open) {
|
|
37
|
+
dialogEl.showModal()
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
function handleBackdropClick(e: MouseEvent) {
|
|
42
|
+
if (e.target === e.currentTarget && item.closeOnClickModal) {
|
|
43
|
+
messageBox.handleClose(item)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<!-- 使用 hai-messagebox 而非 DaisyUI .modal,避免 ::backdrop 被隐藏 -->
|
|
49
|
+
<dialog
|
|
50
|
+
bind:this={dialogEl}
|
|
51
|
+
class='hai-messagebox'
|
|
52
|
+
oncancel={e => e.preventDefault()}
|
|
53
|
+
onclick={handleBackdropClick}
|
|
54
|
+
>
|
|
55
|
+
<div class='hai-messagebox__panel'>
|
|
56
|
+
<!-- 标题栏:始终显示,右侧关闭按钮 -->
|
|
57
|
+
<div class='hai-messagebox__header'>
|
|
58
|
+
<h3 class='font-bold text-lg'>{item.title}</h3>
|
|
59
|
+
<button
|
|
60
|
+
type='button'
|
|
61
|
+
class='hai-messagebox__close'
|
|
62
|
+
aria-label={uiM('common_close')}
|
|
63
|
+
onclick={() => messageBox.handleClose(item)}
|
|
64
|
+
>
|
|
65
|
+
<span class='icon-[tabler--x] size-5'></span>
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- 图标 + 消息内容同行 -->
|
|
70
|
+
<div class='hai-messagebox__body flex items-center gap-3'>
|
|
71
|
+
{#if item.iconType}
|
|
72
|
+
<span class={cn(
|
|
73
|
+
'inline-flex items-center justify-center rounded-full w-10 h-10 shrink-0',
|
|
74
|
+
iconBgMap[item.iconType] ?? iconBgMap.info,
|
|
75
|
+
)}>
|
|
76
|
+
<span class={cn(iconMap[item.iconType] ?? iconMap.info, 'size-5')}></span>
|
|
77
|
+
</span>
|
|
78
|
+
{/if}
|
|
79
|
+
<p class='flex-1 min-w-0 text-base-content/80 text-sm leading-relaxed'>{item.message}</p>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<!-- 操作按钮 -->
|
|
83
|
+
<div class='hai-messagebox__footer'>
|
|
84
|
+
{#if item.showCancel}
|
|
85
|
+
<Button
|
|
86
|
+
variant='ghost'
|
|
87
|
+
disabled={item.loading}
|
|
88
|
+
onclick={() => messageBox.handleCancel(item)}
|
|
89
|
+
>
|
|
90
|
+
{item.cancelText || uiM('confirm_cancel')}
|
|
91
|
+
</Button>
|
|
92
|
+
{/if}
|
|
93
|
+
<Button
|
|
94
|
+
variant={item.confirmVariant || 'primary'}
|
|
95
|
+
loading={item.loading}
|
|
96
|
+
disabled={item.loading}
|
|
97
|
+
onclick={() => messageBox.handleConfirm(item)}
|
|
98
|
+
>
|
|
99
|
+
{item.confirmText || uiM('confirm_ok')}
|
|
100
|
+
</Button>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</dialog>
|
|
104
|
+
|
|
105
|
+
<style>
|
|
106
|
+
dialog.hai-messagebox {
|
|
107
|
+
margin: 0;
|
|
108
|
+
padding: 0;
|
|
109
|
+
border: 0;
|
|
110
|
+
background: transparent;
|
|
111
|
+
outline: none;
|
|
112
|
+
overflow: visible;
|
|
113
|
+
position: fixed;
|
|
114
|
+
inset: 0;
|
|
115
|
+
width: 100%;
|
|
116
|
+
height: 100%;
|
|
117
|
+
display: grid;
|
|
118
|
+
place-items: center;
|
|
119
|
+
z-index: 999;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
dialog.hai-messagebox::backdrop {
|
|
123
|
+
background: color-mix(in srgb, var(--color-base-content) 25%, transparent);
|
|
124
|
+
backdrop-filter: blur(2px);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.hai-messagebox__panel {
|
|
128
|
+
position: relative;
|
|
129
|
+
width: min(100%, 28rem);
|
|
130
|
+
max-width: calc(100vw - 2rem);
|
|
131
|
+
max-height: calc(100vh - 4rem);
|
|
132
|
+
background: var(--color-base-100);
|
|
133
|
+
border-radius: 1rem;
|
|
134
|
+
padding: 1.5rem;
|
|
135
|
+
box-shadow: 0 25px 50px -12px oklch(0% 0 0 / 0.25);
|
|
136
|
+
animation: hai-msgbox-enter 0.22s cubic-bezier(0.16, 1, 0.3, 1);
|
|
137
|
+
overflow-y: auto;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.hai-messagebox__header {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
justify-content: space-between;
|
|
144
|
+
margin-bottom: 0.75rem;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.hai-messagebox__close {
|
|
148
|
+
display: inline-flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
width: 1.5rem;
|
|
152
|
+
height: 1.5rem;
|
|
153
|
+
color: color-mix(in srgb, var(--color-base-content) 45%, transparent);
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
border: none;
|
|
156
|
+
background: none;
|
|
157
|
+
padding: 0;
|
|
158
|
+
outline: none;
|
|
159
|
+
transition: color 160ms ease;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.hai-messagebox__close:hover {
|
|
163
|
+
color: var(--color-base-content);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.hai-messagebox__close:focus-visible {
|
|
167
|
+
outline: 2px solid color-mix(in srgb, var(--color-primary) 40%, transparent);
|
|
168
|
+
outline-offset: 2px;
|
|
169
|
+
border-radius: 2px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.hai-messagebox__body {
|
|
173
|
+
margin-bottom: 1rem;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.hai-messagebox__footer {
|
|
177
|
+
display: flex;
|
|
178
|
+
justify-content: flex-end;
|
|
179
|
+
gap: 0.5rem;
|
|
180
|
+
margin-top: 0.5rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@keyframes hai-msgbox-enter {
|
|
184
|
+
from {
|
|
185
|
+
opacity: 0;
|
|
186
|
+
transform: translateY(10px) scale(0.985);
|
|
187
|
+
}
|
|
188
|
+
to {
|
|
189
|
+
opacity: 1;
|
|
190
|
+
transform: translateY(0) scale(1);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MessageBoxItem } from '../../messagebox.svelte.js';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
item: MessageBoxItem;
|
|
4
|
+
};
|
|
5
|
+
declare const MessageBoxDialog: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
|
+
type MessageBoxDialog = ReturnType<typeof MessageBoxDialog>;
|
|
7
|
+
export default MessageBoxDialog;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
=============================================================================
|
|
3
|
+
@h-ai/ui - MessageContainer 组件
|
|
4
|
+
=============================================================================
|
|
5
|
+
轻量消息提示容器,渲染 message store 中的消息条目。
|
|
6
|
+
视觉风格:顶部居中、带类型图标、自动滑入滑出。
|
|
7
|
+
|
|
8
|
+
叠加策略与 ToastContainer 一致:
|
|
9
|
+
- 有打开的 modal dialog 时,寄宿到 dialog 内部(top layer);
|
|
10
|
+
- 否则寄宿到 <body> 以 popover 进入 top layer。
|
|
11
|
+
=============================================================================
|
|
12
|
+
-->
|
|
13
|
+
<script lang='ts'>
|
|
14
|
+
import { onMount } from 'svelte'
|
|
15
|
+
import { message } from '../../message.svelte.js'
|
|
16
|
+
import { cn } from '../../utils.js'
|
|
17
|
+
import IconButton from '../primitives/IconButton.svelte'
|
|
18
|
+
|
|
19
|
+
/** 图标类型到 tabler icon 的映射 */
|
|
20
|
+
const iconMap: Record<string, string> = {
|
|
21
|
+
info: 'icon-[tabler--info-circle]',
|
|
22
|
+
success: 'icon-[tabler--circle-check]',
|
|
23
|
+
warning: 'icon-[tabler--alert-triangle]',
|
|
24
|
+
error: 'icon-[tabler--circle-x]',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** 图标颜色映射 */
|
|
28
|
+
const iconColorMap: Record<string, string> = {
|
|
29
|
+
info: 'text-info',
|
|
30
|
+
success: 'text-success',
|
|
31
|
+
warning: 'text-warning',
|
|
32
|
+
error: 'text-error',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** 背景/边框映射 */
|
|
36
|
+
const bgMap: Record<string, string> = {
|
|
37
|
+
info: 'border-info/20 bg-info/5',
|
|
38
|
+
success: 'border-success/20 bg-success/5',
|
|
39
|
+
warning: 'border-warning/20 bg-warning/5',
|
|
40
|
+
error: 'border-error/20 bg-error/5',
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let layerElement: HTMLDivElement | undefined = $state()
|
|
44
|
+
|
|
45
|
+
const hasItems = $derived(message.items.length > 0)
|
|
46
|
+
|
|
47
|
+
/** 找到最顶层处于打开状态的原生 modal dialog。 */
|
|
48
|
+
function findTopModalDialog(): HTMLDialogElement | null {
|
|
49
|
+
if (typeof document === 'undefined')
|
|
50
|
+
return null
|
|
51
|
+
const dialogs = document.querySelectorAll<HTMLDialogElement>('dialog')
|
|
52
|
+
let top: HTMLDialogElement | null = null
|
|
53
|
+
for (const dialog of dialogs) {
|
|
54
|
+
if (dialog.open && typeof dialog.matches === 'function' && dialog.matches(':modal')) {
|
|
55
|
+
top = dialog
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return top
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function safeShowPopover(el: HTMLElement) {
|
|
62
|
+
try {
|
|
63
|
+
if (typeof el.showPopover === 'function' && el.isConnected && !el.matches(':popover-open')) {
|
|
64
|
+
el.showPopover()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch { /* 忽略异常 */ }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function safeHidePopover(el: HTMLElement) {
|
|
71
|
+
try {
|
|
72
|
+
if (typeof el.hidePopover === 'function' && el.matches(':popover-open')) {
|
|
73
|
+
el.hidePopover()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch { /* 忽略异常 */ }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function relocate() {
|
|
80
|
+
const el = layerElement
|
|
81
|
+
if (!el)
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
const modal = hasItems ? findTopModalDialog() : null
|
|
85
|
+
|
|
86
|
+
if (modal) {
|
|
87
|
+
safeHidePopover(el)
|
|
88
|
+
if (el.hasAttribute('popover'))
|
|
89
|
+
el.removeAttribute('popover')
|
|
90
|
+
if (el.parentElement !== modal)
|
|
91
|
+
modal.appendChild(el)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (el.parentElement !== document.body)
|
|
96
|
+
document.body.appendChild(el)
|
|
97
|
+
if (!el.hasAttribute('popover'))
|
|
98
|
+
el.setAttribute('popover', 'manual')
|
|
99
|
+
if (hasItems) {
|
|
100
|
+
safeShowPopover(el)
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
safeHidePopover(el)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
onMount(() => {
|
|
108
|
+
relocate()
|
|
109
|
+
const observer = new MutationObserver(() => relocate())
|
|
110
|
+
observer.observe(document.body, { subtree: true, attributes: true, attributeFilter: ['open'] })
|
|
111
|
+
return () => {
|
|
112
|
+
observer.disconnect()
|
|
113
|
+
const el = layerElement
|
|
114
|
+
if (el) {
|
|
115
|
+
safeHidePopover(el)
|
|
116
|
+
el.remove()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
$effect(() => {
|
|
122
|
+
void hasItems
|
|
123
|
+
relocate()
|
|
124
|
+
})
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<div bind:this={layerElement} popover='manual' class='hai-message-layer'>
|
|
128
|
+
<div class='hai-message-stack'>
|
|
129
|
+
{#each message.items as item (item.id)}
|
|
130
|
+
<div
|
|
131
|
+
class={cn(
|
|
132
|
+
'hai-message-item alert shadow-lg border',
|
|
133
|
+
bgMap[item.type] ?? bgMap.info,
|
|
134
|
+
)}
|
|
135
|
+
role='alert'
|
|
136
|
+
>
|
|
137
|
+
<span class={cn(iconMap[item.type] ?? iconMap.info, 'size-5 shrink-0', iconColorMap[item.type] ?? iconColorMap.info)}></span>
|
|
138
|
+
<span class='text-sm'>{item.message}</span>
|
|
139
|
+
{#if item.closable}
|
|
140
|
+
<IconButton
|
|
141
|
+
variant='ghost'
|
|
142
|
+
size='sm'
|
|
143
|
+
onclick={() => message.remove(item.id)}
|
|
144
|
+
ariaLabel='close'
|
|
145
|
+
>
|
|
146
|
+
✕
|
|
147
|
+
</IconButton>
|
|
148
|
+
{/if}
|
|
149
|
+
</div>
|
|
150
|
+
{/each}
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<style>
|
|
155
|
+
.hai-message-layer {
|
|
156
|
+
position: fixed;
|
|
157
|
+
inset: 0;
|
|
158
|
+
width: 100%;
|
|
159
|
+
height: 100%;
|
|
160
|
+
max-width: none;
|
|
161
|
+
max-height: none;
|
|
162
|
+
margin: 0;
|
|
163
|
+
padding: 0;
|
|
164
|
+
border: 0;
|
|
165
|
+
background: transparent;
|
|
166
|
+
overflow: visible;
|
|
167
|
+
pointer-events: none;
|
|
168
|
+
z-index: 9999;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.hai-message-stack {
|
|
172
|
+
position: absolute;
|
|
173
|
+
top: 1rem;
|
|
174
|
+
left: 50%;
|
|
175
|
+
transform: translateX(-50%);
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
align-items: center;
|
|
179
|
+
gap: 0.5rem;
|
|
180
|
+
pointer-events: auto;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.hai-message-item {
|
|
184
|
+
animation: hai-message-enter 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
|
185
|
+
min-width: 16rem;
|
|
186
|
+
max-width: 32rem;
|
|
187
|
+
white-space: nowrap;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@keyframes hai-message-enter {
|
|
191
|
+
from {
|
|
192
|
+
opacity: 0;
|
|
193
|
+
transform: translateY(-1rem);
|
|
194
|
+
}
|
|
195
|
+
to {
|
|
196
|
+
opacity: 1;
|
|
197
|
+
transform: translateY(0);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
</style>
|
|
@@ -25,6 +25,9 @@ export { default as Empty } from './Empty.svelte';
|
|
|
25
25
|
export { default as Form } from './Form.svelte';
|
|
26
26
|
export { default as FormField } from './FormField.svelte';
|
|
27
27
|
export { default as InfiniteScroll } from './InfiniteScroll.svelte';
|
|
28
|
+
export { default as MessageBoxContainer } from './MessageBoxContainer.svelte';
|
|
29
|
+
export { default as MessageBoxDialog } from './MessageBoxDialog.svelte';
|
|
30
|
+
export { default as MessageContainer } from './MessageContainer.svelte';
|
|
28
31
|
export { default as Modal } from './Modal.svelte';
|
|
29
32
|
export { default as PageHeader } from './PageHeader.svelte';
|
|
30
33
|
export { default as Pagination } from './Pagination.svelte';
|
|
@@ -33,6 +33,11 @@ export { default as Form } from './Form.svelte';
|
|
|
33
33
|
export { default as FormField } from './FormField.svelte';
|
|
34
34
|
// 无限滚动 / 上拉加载
|
|
35
35
|
export { default as InfiniteScroll } from './InfiniteScroll.svelte';
|
|
36
|
+
// MessageBox 命令式弹框(类似 ElementUI MessageBox)
|
|
37
|
+
export { default as MessageBoxContainer } from './MessageBoxContainer.svelte';
|
|
38
|
+
export { default as MessageBoxDialog } from './MessageBoxDialog.svelte';
|
|
39
|
+
// Message 轻量消息提示(类似 ElementUI Message)
|
|
40
|
+
export { default as MessageContainer } from './MessageContainer.svelte';
|
|
36
41
|
export { default as Modal } from './Modal.svelte';
|
|
37
42
|
// 页面头部
|
|
38
43
|
export { default as PageHeader } from './PageHeader.svelte';
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
}
|
|
98
98
|
</script>
|
|
99
99
|
|
|
100
|
-
<div class={cn('', className)}>
|
|
100
|
+
<div class={cn('theme-color-picker', className)}>
|
|
101
101
|
<div class='flex flex-wrap items-center gap-2'>
|
|
102
102
|
{#each normalizedPresets as preset (preset.value)}
|
|
103
103
|
<button
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
</div>
|
|
166
166
|
|
|
167
167
|
<style>
|
|
168
|
-
button {
|
|
168
|
+
.theme-color-picker button {
|
|
169
169
|
border-color: var(--soft-border, color-mix(in oklab, var(--color-base-content) 12%, transparent));
|
|
170
170
|
background: var(--soft-surface, var(--color-base-100));
|
|
171
171
|
color: var(--soft-text-body, var(--color-base-content));
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
font-weight: 500;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
button:hover:not(:disabled) {
|
|
176
|
+
.theme-color-picker button:hover:not(:disabled) {
|
|
177
177
|
border-color: color-mix(in oklab, var(--color-primary) 28%, var(--soft-border, transparent) 72%);
|
|
178
178
|
background: color-mix(
|
|
179
179
|
in oklab,
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
button[aria-pressed='true'] {
|
|
185
|
+
.theme-color-picker button[aria-pressed='true'] {
|
|
186
186
|
border-color: color-mix(in oklab, var(--color-primary) 42%, var(--soft-border, transparent) 58%);
|
|
187
187
|
background: color-mix(
|
|
188
188
|
in oklab,
|
|
@@ -192,14 +192,14 @@
|
|
|
192
192
|
color: var(--color-primary);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
button:focus,
|
|
196
|
-
button:focus-visible {
|
|
195
|
+
.theme-color-picker button:focus,
|
|
196
|
+
.theme-color-picker button:focus-visible {
|
|
197
197
|
outline: none;
|
|
198
198
|
border-color: color-mix(in oklab, var(--color-primary) 48%, var(--soft-border, transparent) 52%);
|
|
199
199
|
box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-primary) 12%, transparent 88%);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
button > span:first-child {
|
|
202
|
+
.theme-color-picker button > span:first-child {
|
|
203
203
|
border-color: color-mix(in oklab, var(--color-base-content) 10%, transparent 90%);
|
|
204
204
|
box-shadow: none;
|
|
205
205
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export * from './components/index.js';
|
|
8
8
|
export * from './i18n.svelte.js';
|
|
9
|
+
export * from './message.svelte.js';
|
|
10
|
+
export * from './messagebox.svelte.js';
|
|
9
11
|
export * from './theme-config.js';
|
|
10
12
|
export * from './toast.svelte.js';
|
|
11
13
|
export * from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
export * from './components/index.js';
|
|
9
9
|
// ─── i18n 国际化(Paraglide 辅助工具) ───
|
|
10
10
|
export * from './i18n.svelte.js';
|
|
11
|
+
// ─── Message 轻量消息提示(类似 ElementUI Message) ───
|
|
12
|
+
export * from './message.svelte.js';
|
|
13
|
+
// ─── MessageBox 命令式弹框(类似 ElementUI MessageBox) ───
|
|
14
|
+
export * from './messagebox.svelte.js';
|
|
11
15
|
// ─── 主题配置 ───
|
|
12
16
|
export * from './theme-config.js';
|
|
13
17
|
// ─── Toast 状态管理 ───
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @h-ai/ui — Message 状态管理
|
|
3
|
+
*
|
|
4
|
+
* 命令式轻量消息提示 API,类似 ElementUI Message。
|
|
5
|
+
* 与 Toast 类似但视觉风格不同:顶部居中滑入、带类型图标、可自动关闭。
|
|
6
|
+
* @module message.svelte
|
|
7
|
+
*/
|
|
8
|
+
import type { MessageOptions } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* 内部消息条目
|
|
11
|
+
*/
|
|
12
|
+
export interface MessageItem {
|
|
13
|
+
id: string;
|
|
14
|
+
message: string;
|
|
15
|
+
type: 'info' | 'success' | 'warning' | 'error';
|
|
16
|
+
duration: number;
|
|
17
|
+
closable: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Message 状态
|
|
21
|
+
*/
|
|
22
|
+
declare class MessageState {
|
|
23
|
+
items: MessageItem[];
|
|
24
|
+
private timers;
|
|
25
|
+
/**
|
|
26
|
+
* 添加消息
|
|
27
|
+
*/
|
|
28
|
+
add(options: MessageOptions | string): string;
|
|
29
|
+
/**
|
|
30
|
+
* 移除消息
|
|
31
|
+
*/
|
|
32
|
+
remove(id: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* 清空所有消息
|
|
35
|
+
*/
|
|
36
|
+
clear(): void;
|
|
37
|
+
/**
|
|
38
|
+
* 快捷方法
|
|
39
|
+
*/
|
|
40
|
+
info(message: string, duration?: number): string;
|
|
41
|
+
success(message: string, duration?: number): string;
|
|
42
|
+
warning(message: string, duration?: number): string;
|
|
43
|
+
error(message: string, duration?: number): string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Message 单例
|
|
47
|
+
*/
|
|
48
|
+
export declare const message: MessageState;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @h-ai/ui — Message 状态管理
|
|
3
|
+
*
|
|
4
|
+
* 命令式轻量消息提示 API,类似 ElementUI Message。
|
|
5
|
+
* 与 Toast 类似但视觉风格不同:顶部居中滑入、带类型图标、可自动关闭。
|
|
6
|
+
* @module message.svelte
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Message 状态
|
|
10
|
+
*/
|
|
11
|
+
class MessageState {
|
|
12
|
+
items = $state([]);
|
|
13
|
+
timers = new Map();
|
|
14
|
+
/**
|
|
15
|
+
* 添加消息
|
|
16
|
+
*/
|
|
17
|
+
add(options) {
|
|
18
|
+
const opts = typeof options === 'string' ? { message: options } : options;
|
|
19
|
+
const id = Math.random().toString(36).slice(2, 9);
|
|
20
|
+
const item = {
|
|
21
|
+
id,
|
|
22
|
+
message: opts.message,
|
|
23
|
+
type: opts.type ?? 'info',
|
|
24
|
+
duration: opts.duration ?? 3000,
|
|
25
|
+
closable: opts.closable ?? false,
|
|
26
|
+
};
|
|
27
|
+
this.items = [...this.items, item];
|
|
28
|
+
if (item.duration > 0) {
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
this.timers.delete(id);
|
|
31
|
+
this.remove(id);
|
|
32
|
+
}, item.duration);
|
|
33
|
+
this.timers.set(id, timer);
|
|
34
|
+
}
|
|
35
|
+
return id;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 移除消息
|
|
39
|
+
*/
|
|
40
|
+
remove(id) {
|
|
41
|
+
const timer = this.timers.get(id);
|
|
42
|
+
if (timer) {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
this.timers.delete(id);
|
|
45
|
+
}
|
|
46
|
+
this.items = this.items.filter(i => i.id !== id);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 清空所有消息
|
|
50
|
+
*/
|
|
51
|
+
clear() {
|
|
52
|
+
for (const timer of this.timers.values()) {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
}
|
|
55
|
+
this.timers.clear();
|
|
56
|
+
this.items = [];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 快捷方法
|
|
60
|
+
*/
|
|
61
|
+
info(message, duration) {
|
|
62
|
+
return this.add({ message, type: 'info', duration });
|
|
63
|
+
}
|
|
64
|
+
success(message, duration) {
|
|
65
|
+
return this.add({ message, type: 'success', duration });
|
|
66
|
+
}
|
|
67
|
+
warning(message, duration) {
|
|
68
|
+
return this.add({ message, type: 'warning', duration });
|
|
69
|
+
}
|
|
70
|
+
error(message, duration) {
|
|
71
|
+
return this.add({ message, type: 'error', duration });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Message 单例
|
|
76
|
+
*/
|
|
77
|
+
export const message = new MessageState();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @h-ai/ui — MessageBox 状态管理
|
|
3
|
+
*
|
|
4
|
+
* 命令式弹框 API,类似 ElementUI MessageBox。
|
|
5
|
+
* 调用 `messageBox.confirm(...)` 或 `messageBox.alert(...)` 返回 Promise<boolean>,
|
|
6
|
+
* 组件内部通过渲染 MessageBoxContainer 消费状态。
|
|
7
|
+
* @module messagebox.svelte
|
|
8
|
+
*/
|
|
9
|
+
import type { MessageBoxIconType, MessageBoxOptions } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* 内部弹框条目
|
|
12
|
+
*/
|
|
13
|
+
export interface MessageBoxItem {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
message: string;
|
|
17
|
+
type: 'confirm' | 'alert';
|
|
18
|
+
iconType: MessageBoxIconType;
|
|
19
|
+
confirmText: string;
|
|
20
|
+
cancelText: string;
|
|
21
|
+
confirmVariant: 'default' | 'primary' | 'warning' | 'error';
|
|
22
|
+
showCancel: boolean;
|
|
23
|
+
closeOnClickModal: boolean;
|
|
24
|
+
showClose: boolean;
|
|
25
|
+
loading: boolean;
|
|
26
|
+
/** 外部 resolve 回调 */
|
|
27
|
+
resolve: (value: boolean) => void;
|
|
28
|
+
/** 可选的 beforeClose 钩子 */
|
|
29
|
+
beforeClose?: MessageBoxOptions['beforeClose'];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* MessageBox 状态
|
|
33
|
+
*/
|
|
34
|
+
declare class MessageBoxState {
|
|
35
|
+
items: MessageBoxItem[];
|
|
36
|
+
private createItem;
|
|
37
|
+
/**
|
|
38
|
+
* 确认弹框(双按钮,返回 Promise<boolean>)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const ok = await messageBox.confirm({
|
|
43
|
+
* title: '提示',
|
|
44
|
+
* message: '确定要删除吗?',
|
|
45
|
+
* confirmText: '确定',
|
|
46
|
+
* cancelText: '取消',
|
|
47
|
+
* })
|
|
48
|
+
* if (ok) { ... }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
confirm(options: MessageBoxOptions | string): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* 提示弹框(单按钮,返回 Promise<boolean>)
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* await messageBox.alert({
|
|
58
|
+
* title: '提示',
|
|
59
|
+
* message: '操作成功',
|
|
60
|
+
* })
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
alert(options: MessageBoxOptions | string): Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* 内部方法:处理确认
|
|
66
|
+
*/
|
|
67
|
+
handleConfirm(item: MessageBoxItem): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* 内部方法:处理取消
|
|
70
|
+
*/
|
|
71
|
+
handleCancel(item: MessageBoxItem): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* 内部方法:处理关闭(点击关闭按钮或遮罩)
|
|
74
|
+
*/
|
|
75
|
+
handleClose(item: MessageBoxItem): Promise<void>;
|
|
76
|
+
private remove;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* MessageBox 单例
|
|
80
|
+
*/
|
|
81
|
+
export declare const messageBox: MessageBoxState;
|
|
82
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @h-ai/ui — MessageBox 状态管理
|
|
3
|
+
*
|
|
4
|
+
* 命令式弹框 API,类似 ElementUI MessageBox。
|
|
5
|
+
* 调用 `messageBox.confirm(...)` 或 `messageBox.alert(...)` 返回 Promise<boolean>,
|
|
6
|
+
* 组件内部通过渲染 MessageBoxContainer 消费状态。
|
|
7
|
+
* @module messagebox.svelte
|
|
8
|
+
*/
|
|
9
|
+
import { uiM } from './messages.js';
|
|
10
|
+
/**
|
|
11
|
+
* MessageBox 状态
|
|
12
|
+
*/
|
|
13
|
+
class MessageBoxState {
|
|
14
|
+
items = $state([]);
|
|
15
|
+
createItem(options) {
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
const id = Math.random().toString(36).slice(2, 9);
|
|
18
|
+
const isAlert = options.type === 'alert';
|
|
19
|
+
const item = {
|
|
20
|
+
id,
|
|
21
|
+
title: options.title ?? uiM('messagebox_title'),
|
|
22
|
+
message: options.message,
|
|
23
|
+
type: options.type ?? 'confirm',
|
|
24
|
+
iconType: options.iconType ?? (isAlert ? 'info' : 'warning'),
|
|
25
|
+
confirmText: options.confirmText ?? '',
|
|
26
|
+
cancelText: options.cancelText ?? '',
|
|
27
|
+
confirmVariant: options.confirmVariant ?? 'primary',
|
|
28
|
+
showCancel: options.showCancel ?? !isAlert,
|
|
29
|
+
closeOnClickModal: options.closeOnClickModal ?? true,
|
|
30
|
+
showClose: options.showClose ?? true,
|
|
31
|
+
loading: false,
|
|
32
|
+
resolve,
|
|
33
|
+
beforeClose: options.beforeClose,
|
|
34
|
+
};
|
|
35
|
+
this.items = [...this.items, item];
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 确认弹框(双按钮,返回 Promise<boolean>)
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const ok = await messageBox.confirm({
|
|
44
|
+
* title: '提示',
|
|
45
|
+
* message: '确定要删除吗?',
|
|
46
|
+
* confirmText: '确定',
|
|
47
|
+
* cancelText: '取消',
|
|
48
|
+
* })
|
|
49
|
+
* if (ok) { ... }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
confirm(options) {
|
|
53
|
+
const opts = typeof options === 'string' ? { message: options } : options;
|
|
54
|
+
return this.createItem({ type: 'confirm', ...opts });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 提示弹框(单按钮,返回 Promise<boolean>)
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* await messageBox.alert({
|
|
62
|
+
* title: '提示',
|
|
63
|
+
* message: '操作成功',
|
|
64
|
+
* })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
alert(options) {
|
|
68
|
+
const opts = typeof options === 'string' ? { message: options } : options;
|
|
69
|
+
return this.createItem({ type: 'alert', showCancel: false, ...opts });
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 内部方法:处理确认
|
|
73
|
+
*/
|
|
74
|
+
async handleConfirm(item) {
|
|
75
|
+
if (item.beforeClose) {
|
|
76
|
+
const canClose = await item.beforeClose('confirm', {
|
|
77
|
+
setLoading: (loading) => {
|
|
78
|
+
item.loading = loading;
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
if (canClose === false) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
this.remove(item.id);
|
|
86
|
+
item.resolve(true);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 内部方法:处理取消
|
|
90
|
+
*/
|
|
91
|
+
async handleCancel(item) {
|
|
92
|
+
if (item.beforeClose) {
|
|
93
|
+
const canClose = await item.beforeClose('cancel', {
|
|
94
|
+
setLoading: (loading) => {
|
|
95
|
+
item.loading = loading;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
if (canClose === false) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
this.remove(item.id);
|
|
103
|
+
item.resolve(false);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 内部方法:处理关闭(点击关闭按钮或遮罩)
|
|
107
|
+
*/
|
|
108
|
+
async handleClose(item) {
|
|
109
|
+
if (item.beforeClose) {
|
|
110
|
+
const canClose = await item.beforeClose('close', {
|
|
111
|
+
setLoading: (loading) => {
|
|
112
|
+
item.loading = loading;
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
if (canClose === false) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
this.remove(item.id);
|
|
120
|
+
item.resolve(false);
|
|
121
|
+
}
|
|
122
|
+
remove(id) {
|
|
123
|
+
this.items = this.items.filter(i => i.id !== id);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* MessageBox 单例
|
|
128
|
+
*/
|
|
129
|
+
export const messageBox = new MessageBoxState();
|
package/dist/messages/en-US.json
CHANGED
package/dist/messages/zh-CN.json
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -970,3 +970,61 @@ export interface PopoverProps {
|
|
|
970
970
|
/** 内容插槽 */
|
|
971
971
|
children?: Snippet;
|
|
972
972
|
}
|
|
973
|
+
/**
|
|
974
|
+
* MessageBox 类型
|
|
975
|
+
* - confirm: 双按钮(确认 / 取消)
|
|
976
|
+
* - alert: 单按钮(仅确认)
|
|
977
|
+
* - prompt: 带输入框的确认(预留)
|
|
978
|
+
*/
|
|
979
|
+
export type MessageBoxAction = 'confirm' | 'cancel' | 'close';
|
|
980
|
+
/**
|
|
981
|
+
* MessageBox 图标类型
|
|
982
|
+
*/
|
|
983
|
+
export type MessageBoxIconType = 'info' | 'success' | 'warning' | 'error';
|
|
984
|
+
/**
|
|
985
|
+
* MessageBox 配置项
|
|
986
|
+
*/
|
|
987
|
+
export interface MessageBoxOptions {
|
|
988
|
+
/** 标题 */
|
|
989
|
+
title?: string;
|
|
990
|
+
/** 消息内容(纯文本或 HTML 字符串) */
|
|
991
|
+
message: string;
|
|
992
|
+
/** 类型:confirm 双按钮 / alert 单按钮 */
|
|
993
|
+
type?: 'confirm' | 'alert';
|
|
994
|
+
/** 图标类型 */
|
|
995
|
+
iconType?: MessageBoxIconType;
|
|
996
|
+
/** 确认按钮文本 */
|
|
997
|
+
confirmText?: string;
|
|
998
|
+
/** 取消按钮文本 */
|
|
999
|
+
cancelText?: string;
|
|
1000
|
+
/** 确认按钮变体 */
|
|
1001
|
+
confirmVariant?: 'default' | 'primary' | 'warning' | 'error';
|
|
1002
|
+
/** 是否显示取消按钮(alert 模式下默认 false) */
|
|
1003
|
+
showCancel?: boolean;
|
|
1004
|
+
/** 点击遮罩是否关闭(默认 false,需要显式操作) */
|
|
1005
|
+
closeOnClickModal?: boolean;
|
|
1006
|
+
/** 是否显示右上角关闭按钮(默认 false) */
|
|
1007
|
+
showClose?: boolean;
|
|
1008
|
+
/** 确认前回调(返回 false 可阻止关闭) */
|
|
1009
|
+
beforeClose?: (action: MessageBoxAction, instance: MessageBoxInstance) => boolean | Promise<boolean>;
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* MessageBox 实例(供 beforeClose 回调使用)
|
|
1013
|
+
*/
|
|
1014
|
+
export interface MessageBoxInstance {
|
|
1015
|
+
/** 设置加载态 */
|
|
1016
|
+
setLoading: (loading: boolean) => void;
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Message 消息提示配置项
|
|
1020
|
+
*/
|
|
1021
|
+
export interface MessageOptions {
|
|
1022
|
+
/** 消息文本 */
|
|
1023
|
+
message: string;
|
|
1024
|
+
/** 类型 */
|
|
1025
|
+
type?: 'info' | 'success' | 'warning' | 'error';
|
|
1026
|
+
/** 显示时长(毫秒),0 表示不自动关闭 */
|
|
1027
|
+
duration?: number;
|
|
1028
|
+
/** 是否可手动关闭 */
|
|
1029
|
+
closable?: boolean;
|
|
1030
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.28",
|
|
5
5
|
"description": "Hai Framework UI component library for Svelte 5 Runes.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"svelte": "./dist/index.js",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"mermaid": "^11.12.0",
|
|
52
52
|
"shiki": "^4.0.2",
|
|
53
53
|
"tailwind-merge": "^3.5.0",
|
|
54
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
54
|
+
"@h-ai/core": "0.1.0-alpha.28"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@sveltejs/package": "^2.5.7",
|