@ticatec/uniface-element 0.2.0 → 0.2.2

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.
Files changed (209) hide show
  1. package/README.md +320 -1
  2. package/README_CN.md +392 -0
  3. package/dist/accordion/Accordion.svelte +1 -1
  4. package/dist/action-bar/ActionBar.svelte +7 -1
  5. package/dist/attachment-files/FileRender.svelte +1 -1
  6. package/dist/attachment-files/FileUploadBar.svelte +7 -6
  7. package/dist/attachment-files/FileUploadPanel.svelte +2 -2
  8. package/dist/base-calendar/DateContext.js +5 -4
  9. package/dist/base-calendar/YearPickupPanel.svelte +4 -4
  10. package/dist/card/Card.svelte +1 -1
  11. package/dist/card/Card.svelte.d.ts +1 -1
  12. package/dist/cascade-options-select/CascadeOptionSelect.svelte +2 -3
  13. package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +46 -1
  14. package/dist/cascade-options-select/CascadePanel.svelte +1 -1
  15. package/dist/checkbox/CheckBox.svelte +1 -1
  16. package/dist/color-picker/ColorPicker.svelte +9 -9
  17. package/dist/color-picker/ColorPicker.svelte.d.ts +0 -2
  18. package/dist/color-picker/ColorPickerPanel.svelte +11 -15
  19. package/dist/color-picker/ColorPickerPanel.svelte.d.ts +1 -1
  20. package/dist/common/CommonPicker.svelte +2 -2
  21. package/dist/common/CommonPicker.svelte.d.ts +1 -1
  22. package/dist/common/MouseClickHandler.d.ts +1 -1
  23. package/dist/common/Popover.svelte +28 -6
  24. package/dist/common/Popover.svelte.d.ts +9 -3
  25. package/dist/common/uniface-utils.js +6 -4
  26. package/dist/common-editor/CommonEditor.svelte +1 -1
  27. package/dist/common-editor/CommonEditor.svelte.d.ts +1 -1
  28. package/dist/common-editor/NumberInput.svelte +1 -1
  29. package/dist/common-editor/NumberInput.svelte.d.ts +1 -1
  30. package/dist/concise-data-table/ConciseListTable.svelte +7 -2
  31. package/dist/concise-data-table/ConciseListTable.svelte.d.ts +1 -0
  32. package/dist/concise-data-table/DataRow.svelte +1 -1
  33. package/dist/concise-data-table/TableOptions.d.ts +1 -1
  34. package/dist/data-table/DataTable.svelte +1 -1
  35. package/dist/data-table/parts/ActionsPanel.svelte +4 -3
  36. package/dist/data-table/parts/ActionsRow.svelte +3 -3
  37. package/dist/data-table/parts/ContentPanel.svelte +3 -2
  38. package/dist/data-table/parts/FixedColumnsPanel.svelte +0 -1
  39. package/dist/data-table/parts/FixedColumnsPanel.svelte.d.ts +1 -2
  40. package/dist/data-table/parts/FixedHeaderPanel.svelte +2 -2
  41. package/dist/data-table/parts/FixedRow.svelte +2 -1
  42. package/dist/data-table/parts/FixedRow.svelte.d.ts +1 -1
  43. package/dist/data-table/parts/HrefCell.svelte +23 -2
  44. package/dist/data-table/parts/PopupMenu.svelte +25 -2
  45. package/dist/data-table/parts/PopupMenu.svelte.d.ts +8 -1
  46. package/dist/date-picker/DatePicker.svelte +0 -1
  47. package/dist/date-picker/DateTimePicker.svelte +3 -3
  48. package/dist/date-picker/ScrollBar.svelte +4 -7
  49. package/dist/date-range/DateRangeEditor.svelte +1 -1
  50. package/dist/dialog/CommonDialog.svelte +8 -5
  51. package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
  52. package/dist/dialog/Dialog.svelte +37 -12
  53. package/dist/dialog/Dialog.svelte.d.ts +4 -3
  54. package/dist/dialog/DialogBoard.svelte +11 -8
  55. package/dist/dialog/DialogWrapper.svelte +10 -0
  56. package/dist/{common-editor/DateInput.svelte.d.ts → dialog/DialogWrapper.svelte.d.ts} +6 -13
  57. package/dist/dialog/Dialogs.js +1 -1
  58. package/dist/dialog/ModalResult.d.ts +5 -0
  59. package/dist/dialog/ModalResult.js +5 -0
  60. package/dist/drawer/Drawer.svelte +1 -1
  61. package/dist/form-field/FormField.svelte +2 -1
  62. package/dist/form-field/FormField.svelte.d.ts +1 -0
  63. package/dist/form-panel/flex-row-form/FormContainer.svelte +1 -1
  64. package/dist/form-panel/grid-form/EmptyCell.svelte +8 -7
  65. package/dist/form-panel/grid-form/EmptyCell.svelte.d.ts +2 -2
  66. package/dist/form-panel/grid-form/GridField.svelte +1 -1
  67. package/dist/i18nRes/i18nRes.d.ts +2 -0
  68. package/dist/i18nRes/i18nRes.js +44 -0
  69. package/dist/i18nRes/index.d.ts +2 -0
  70. package/dist/i18nRes/index.js +2 -0
  71. package/dist/image-files/ImageFilesField.svelte +1 -1
  72. package/dist/indicator/IndicatorBoard.svelte +1 -1
  73. package/dist/inline-cell-editor/InvalidEditor.svelte +1 -0
  74. package/dist/input-options-select/InputOptionsSelect.svelte +6 -6
  75. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +1 -1
  76. package/dist/layout/flex/FlexBlock.svelte +1 -1
  77. package/dist/lookup-editor/LookupEditor.svelte +1 -1
  78. package/dist/memo-editor/MemoEditor.svelte +2 -2
  79. package/dist/message-box/IMessageBox.d.ts +2 -4
  80. package/dist/message-box/IMessageBox.js +4 -6
  81. package/dist/message-box/MessageBoxBoard.svelte +1 -3
  82. package/dist/options-multi-select/OptionsMultiSelect.svelte +1 -1
  83. package/dist/prompts-text-editor/PromptsTextEditor.svelte +2 -2
  84. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +1 -1
  85. package/dist/property-editor/PropertyEditor.svelte +3 -3
  86. package/dist/text-editor/PasswordEditor.svelte +1 -1
  87. package/dist/transfer/Transfer.svelte +17 -12
  88. package/dist/transfer/Transfer.svelte.d.ts +0 -1
  89. package/dist/unit-number-editor/UnitNumberEditor.svelte +2 -2
  90. package/docs/buttons/cn/ActionBar.md +459 -0
  91. package/docs/buttons/cn/Button.md +228 -0
  92. package/docs/buttons/cn/IconButton.md +294 -0
  93. package/docs/buttons/cn/README.md +600 -0
  94. package/docs/buttons/cn/TextButton.md +163 -0
  95. package/docs/buttons/en/ActionBar.md +459 -0
  96. package/docs/buttons/en/Button.md +228 -0
  97. package/docs/buttons/en/IconButton.md +294 -0
  98. package/docs/buttons/en/README.md +600 -0
  99. package/docs/buttons/en/TextButton.md +163 -0
  100. package/docs/containers/cn/accordion.md +622 -0
  101. package/docs/containers/cn/box.md +445 -0
  102. package/docs/containers/cn/card.md +404 -0
  103. package/docs/containers/cn/page.md +576 -0
  104. package/docs/containers/cn/tabs.md +686 -0
  105. package/docs/containers/en/accordion.md +622 -0
  106. package/docs/containers/en/box.md +445 -0
  107. package/docs/containers/en/card.md +404 -0
  108. package/docs/containers/en/page.md +576 -0
  109. package/docs/containers/en/tabs.md +686 -0
  110. package/docs/data-display/cn/concise-data-table.md +731 -0
  111. package/docs/data-display/cn/listbox.md +786 -0
  112. package/docs/data-display/cn/treeview.md +863 -0
  113. package/docs/data-display/en/concise-data-table.md +732 -0
  114. package/docs/data-display/en/listbox.md +786 -0
  115. package/docs/data-display/en/treeview.md +863 -0
  116. package/docs/data-table/cn/README.md +596 -0
  117. package/docs/data-table/en/README.md +596 -0
  118. package/docs/dialog/cn/README.md +767 -0
  119. package/docs/dialog/en/README.md +767 -0
  120. package/docs/form/cn/README.md +847 -0
  121. package/docs/form/en/README.md +847 -0
  122. package/docs/form-components/cn/README.md +495 -0
  123. package/docs/form-components/cn/attachmentfilesfield.md +757 -0
  124. package/docs/form-components/cn/cascade-options-select.md +374 -0
  125. package/docs/form-components/cn/checkbox.md +58 -0
  126. package/docs/form-components/cn/date-picker.md +138 -0
  127. package/docs/form-components/cn/datetime-picker.md +228 -0
  128. package/docs/form-components/cn/group-checkbox.md +405 -0
  129. package/docs/form-components/cn/group-radiobox.md +525 -0
  130. package/docs/form-components/cn/imagefilesfield.md +651 -0
  131. package/docs/form-components/cn/input-options-select.md +250 -0
  132. package/docs/form-components/cn/lookup-editor.md +406 -0
  133. package/docs/form-components/cn/memoeditor.md +409 -0
  134. package/docs/form-components/cn/number-editor.md +261 -0
  135. package/docs/form-components/cn/options-multi-select.md +177 -0
  136. package/docs/form-components/cn/options-select.md +83 -0
  137. package/docs/form-components/cn/passwordeditor.md +538 -0
  138. package/docs/form-components/cn/prompts-text-editor.md +241 -0
  139. package/docs/form-components/cn/radiobutton.md +84 -0
  140. package/docs/form-components/cn/switch.md +178 -0
  141. package/docs/form-components/cn/text-editor.md +142 -0
  142. package/docs/form-components/cn/time-editor.md +159 -0
  143. package/docs/form-components/cn/unit-number-editor.md +164 -0
  144. package/docs/form-components/en/README.md +463 -0
  145. package/docs/form-components/en/attachmentfilesfield.md +757 -0
  146. package/docs/form-components/en/cascade-options-select.md +358 -0
  147. package/docs/form-components/en/checkbox.md +59 -0
  148. package/docs/form-components/en/date-picker.md +138 -0
  149. package/docs/form-components/en/datetime-picker.md +228 -0
  150. package/docs/form-components/en/group-checkbox.md +395 -0
  151. package/docs/form-components/en/group-radiobox.md +498 -0
  152. package/docs/form-components/en/imagefilesfield.md +651 -0
  153. package/docs/form-components/en/input-options-select.md +239 -0
  154. package/docs/form-components/en/lookup-editor.md +389 -0
  155. package/docs/form-components/en/memoeditor.md +409 -0
  156. package/docs/form-components/en/number-editor.md +249 -0
  157. package/docs/form-components/en/options-multi-select.md +177 -0
  158. package/docs/form-components/en/options-select.md +83 -0
  159. package/docs/form-components/en/passwordeditor.md +538 -0
  160. package/docs/form-components/en/prompts-text-editor.md +241 -0
  161. package/docs/form-components/en/radiobutton.md +84 -0
  162. package/docs/form-components/en/switch.md +180 -0
  163. package/docs/form-components/en/text-editor.md +142 -0
  164. package/docs/form-components/en/time-editor.md +159 -0
  165. package/docs/form-components/en/unit-number-editor.md +164 -0
  166. package/docs/form-layout/cn/criteria-field.md +652 -0
  167. package/docs/form-layout/cn/flex-form.md +454 -0
  168. package/docs/form-layout/cn/flex-row-form.md +542 -0
  169. package/docs/form-layout/cn/form-field.md +923 -0
  170. package/docs/form-layout/cn/grid-form.md +676 -0
  171. package/docs/form-layout/en/criteria-field.md +652 -0
  172. package/docs/form-layout/en/flex-form.md +454 -0
  173. package/docs/form-layout/en/flex-row-form.md +542 -0
  174. package/docs/form-layout/en/form-field.md +923 -0
  175. package/docs/form-layout/en/grid-form.md +676 -0
  176. package/docs/global/cn/README.md +534 -0
  177. package/docs/global/en/README.md +534 -0
  178. package/docs/layout/cn/classiclayout.md +460 -0
  179. package/docs/layout/cn/headerlayout.md +524 -0
  180. package/docs/layout/cn/sidebarlayout.md +263 -0
  181. package/docs/layout/en/classiclayout.md +951 -0
  182. package/docs/layout/en/headerlayout.md +524 -0
  183. package/docs/layout/en/sidebarlayout.md +262 -0
  184. package/docs/misc/cn/README.md +1217 -0
  185. package/docs/misc/en/README.md +1217 -0
  186. package/docs/navigation/cn/breadcrumb.md +291 -0
  187. package/docs/navigation/cn/navigator.md +322 -0
  188. package/docs/navigation/cn/navigatormenu.md +512 -0
  189. package/docs/navigation/cn/progressbar.md +199 -0
  190. package/docs/navigation/cn/progressstepbar.md +299 -0
  191. package/docs/navigation/en/breadcrumb.md +291 -0
  192. package/docs/navigation/en/navigator.md +322 -0
  193. package/docs/navigation/en/navigatormenu.md +512 -0
  194. package/docs/navigation/en/progressbar.md +199 -0
  195. package/docs/navigation/en/progressstepbar.md +299 -0
  196. package/docs/search-filters/cn/daterange.md +1156 -0
  197. package/docs/search-filters/cn/numberrange.md +688 -0
  198. package/docs/search-filters/cn/searchbox.md +1582 -0
  199. package/docs/search-filters/en/daterange.md +1156 -0
  200. package/docs/search-filters/en/numberrange.md +688 -0
  201. package/docs/search-filters/en/searchbox.md +1582 -0
  202. package/package.json +53 -13
  203. package/dist/common-editor/DateInput.svelte +0 -27
  204. package/dist/i18n_resources/index.d.ts +0 -3
  205. package/dist/i18n_resources/index.js +0 -3
  206. /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.d.ts +0 -0
  207. /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.js +0 -0
  208. /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.d.ts +0 -0
  209. /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.js +0 -0
@@ -0,0 +1,767 @@
1
+ # 对话框系统
2
+
3
+ Uniface Element 对话框系统为 Svelte 应用程序提供了全面的模态对话框解决方案。它包括全局对话框管理、内置对话框组件和灵活的自定义选项。
4
+
5
+ ## 目录
6
+
7
+ - [架构概述](#架构概述)
8
+ - [DialogBoard - 全局对话框管理器](#dialogboard---全局对话框管理器)
9
+ - [内置对话框组件](#内置对话框组件)
10
+ - [创建自定义对话框](#创建自定义对话框)
11
+ - [API 参考](#api-参考)
12
+ - [高级用法](#高级用法)
13
+ - [最佳实践](#最佳实践)
14
+
15
+ ## 架构概述
16
+
17
+ 对话框系统由几个相互关联的组件组成:
18
+
19
+ - **DialogBoard**: 处理对话框生命周期的全局对话框管理器
20
+ - **Dialog**: 具有标准 UI 元素的基础对话框组件
21
+ - **CommonDialog**: 为常见用例预配置的对话框
22
+ - **IDialog**: 全局对话框访问的 TypeScript 接口
23
+ - **Dialogs Store**: 管理对话框状态的 Svelte store
24
+
25
+ ```mermaid
26
+ graph TD
27
+ A[DialogBoard] --> B[Dialogs Store]
28
+ A --> C[Dialog Components]
29
+ C --> D[Dialog.svelte]
30
+ C --> E[CommonDialog.svelte]
31
+ F[Custom Components] --> A
32
+ G[window.Dialog.showModal] --> A
33
+ ```
34
+
35
+ ## DialogBoard - 全局对话框管理器
36
+
37
+ `DialogBoard` 组件管理应用程序中的所有模态对话框,并通过 `window.Dialog` API 提供全局访问。
38
+
39
+ ### 设置
40
+
41
+ 在根布局中包含 `DialogBoard`:
42
+
43
+ ```svelte
44
+ <!-- +layout.svelte 或 app.html -->
45
+ <script lang="ts">
46
+ import { DialogBoard } from "@ticatec/uniface-element/DialogBoard";
47
+ </script>
48
+
49
+ <!-- 您的应用程序内容 -->
50
+ <main>
51
+ <slot />
52
+ </main>
53
+
54
+ <!-- 全局对话框管理器 -->
55
+ <DialogBoard />
56
+ ```
57
+
58
+ ### 全局 API
59
+
60
+ 一旦 `DialogBoard` 挂载,您就可以全局访问对话框系统:
61
+
62
+ ```typescript
63
+ // 将任何 Svelte 组件作为模态对话框打开
64
+ window.Dialog.showModal(MyComponent, {
65
+ // 传递给组件的属性
66
+ title: "我的对话框",
67
+ data: someData,
68
+ onSave: (result) => {
69
+ console.log("已保存:", result);
70
+ }
71
+ });
72
+ ```
73
+
74
+ ### TypeScript 支持
75
+
76
+ 添加全局类型声明:
77
+
78
+ ```typescript
79
+ // src/app.d.ts
80
+ import type { IDialog } from '@ticatec/uniface-element';
81
+
82
+ declare global {
83
+ interface Window {
84
+ Dialog: IDialog;
85
+ }
86
+ }
87
+ ```
88
+
89
+ ## 内置对话框组件
90
+
91
+ ### Dialog 组件
92
+
93
+ 基础 `Dialog` 组件提供标准的对话框功能:
94
+
95
+ ```svelte
96
+ <script lang="ts">
97
+ import Dialog from '@ticatec/uniface-element/Dialog';
98
+ import type { ButtonActions } from '@ticatec/uniface-element';
99
+
100
+ let modalResult = null;
101
+
102
+ const actions: ButtonActions = [
103
+ {
104
+ label: "保存",
105
+ type: "primary",
106
+ handler: async () => {
107
+ // 执行保存操作
108
+ await saveData();
109
+ return true; // 返回 true 自动关闭对话框
110
+ }
111
+ }
112
+ ];
113
+
114
+ const onClose = (result) => {
115
+ console.log("对话框关闭,结果:", result);
116
+ };
117
+ </script>
118
+
119
+ <Dialog
120
+ title="我的对话框"
121
+ width="500px"
122
+ height="400px"
123
+ bind:modalResult
124
+ {actions}
125
+ {onClose}
126
+ >
127
+ <!-- 对话框内容 -->
128
+ <p>这是对话框内容。</p>
129
+ </Dialog>
130
+ ```
131
+
132
+ #### Dialog 属性
133
+
134
+ | 属性 | 类型 | 描述 |
135
+ |------|------|------|
136
+ | `title` | `string` | 对话框标题 |
137
+ | `width` | `string` | 对话框宽度(CSS 值) |
138
+ | `height` | `string` | 对话框高度(CSS 值) |
139
+ | `actions` | `ButtonActions` | 操作按钮数组 |
140
+ | `closeConfirm` | `DialogCloseConfirm` | 关闭确认函数 |
141
+ | `content$style` | `string` | 内容区域的自定义样式 |
142
+ | `modalResult` | `ModalResult` | 程序化关闭的结果绑定 |
143
+ | `onClose` | `OnClose` | 对话框关闭时的回调 |
144
+
145
+ ### CommonDialog 组件
146
+
147
+ `CommonDialog` 是为典型用例预配置的对话框:
148
+
149
+ ```svelte
150
+ <script lang="ts">
151
+ import CommonDialog, ModalResult from '@ticatec/uniface-element/CommonDialog, ModalResult';
152
+
153
+ export let user: any;
154
+ export let onSave: (user: any) => void;
155
+
156
+ let modalResult = null;
157
+ let enableConfirm = true;
158
+
159
+ const confirmHandler = async () => {
160
+ try {
161
+ await onSave(user);
162
+ return true; // 返回 true 自动关闭
163
+ } catch (error) {
164
+ console.error("保存失败:", error);
165
+ return false; // 出错时保持对话框打开
166
+ }
167
+ };
168
+
169
+ const onClose = (result) => {
170
+ if (result === ModalResult.Ok) {
171
+ console.log("用户保存成功");
172
+ }
173
+ };
174
+ </script>
175
+
176
+ <CommonDialog
177
+ title="编辑用户"
178
+ width="600px"
179
+ height="500px"
180
+ bind:modalResult
181
+ bind:enableConfirm
182
+ {confirmHandler}
183
+ confirmText="保存更改"
184
+ {onClose}
185
+ >
186
+ <div class="form-content">
187
+ <label>
188
+ 姓名:
189
+ <input bind:value={user.name} />
190
+ </label>
191
+ <label>
192
+ 邮箱:
193
+ <input bind:value={user.email} type="email" />
194
+ </label>
195
+ </div>
196
+ </CommonDialog>
197
+
198
+ <style>
199
+ .form-content {
200
+ display: flex;
201
+ flex-direction: column;
202
+ gap: 16px;
203
+ }
204
+
205
+ label {
206
+ display: flex;
207
+ flex-direction: column;
208
+ gap: 4px;
209
+ }
210
+
211
+ input {
212
+ padding: 8px;
213
+ border: 1px solid #ccc;
214
+ border-radius: 4px;
215
+ }
216
+ </style>
217
+ ```
218
+
219
+ #### CommonDialog 属性
220
+
221
+ | 属性 | 类型 | 描述 |
222
+ |------|------|------|
223
+ | `title` | `string` | 对话框标题 |
224
+ | `width` | `string` | 对话框宽度 |
225
+ | `height` | `string` | 对话框高度 |
226
+ | `closeConfirm` | `DialogCloseConfirm` | 关闭确认函数 |
227
+ | `content$style` | `string` | 内容区域自定义样式 |
228
+ | `modalResult` | `ModalResult` | 结果绑定 |
229
+ | `enableConfirm` | `boolean` | 启用/禁用确认按钮 |
230
+ | `confirmHandler` | `() => Promise<boolean>` | 确认按钮处理器 |
231
+ | `confirmText` | `string` | 自定义确认按钮文本 |
232
+ | `onClose` | `OnClose` | 关闭回调 |
233
+
234
+ ## 创建自定义对话框
235
+
236
+ ### 方法 1: 使用全局对话框 API
237
+
238
+ ```svelte
239
+ <!-- UserEditDialog.svelte -->
240
+ <script lang="ts">
241
+ import { getContext } from 'svelte';
242
+ import CommonDialog, ModalResult from '@ticatec/uniface-element/CommonDialog, ModalResult';
243
+
244
+ export let user: any;
245
+ export let onSave: (user: any) => Promise<void>;
246
+
247
+ // 从上下文获取关闭函数
248
+ const closeDialog = getContext('closeDialog');
249
+
250
+ let saving = false;
251
+ let formData = { ...user };
252
+ let enableConfirm = true;
253
+
254
+ const handleSave = async () => {
255
+ if (saving) return false;
256
+
257
+ saving = true;
258
+ try {
259
+ await onSave(formData);
260
+ return true; // 成功时自动关闭
261
+ } catch (error) {
262
+ console.error('保存失败:', error);
263
+ return false; // 出错时保持打开
264
+ } finally {
265
+ saving = false;
266
+ }
267
+ };
268
+ </script>
269
+
270
+ <CommonDialog
271
+ title="编辑用户"
272
+ width="600px"
273
+ height="400px"
274
+ bind:enableConfirm
275
+ confirmHandler={handleSave}
276
+ confirmText={saving ? "保存中..." : "保存更改"}
277
+ >
278
+ <form class="user-form">
279
+ <div class="field">
280
+ <label for="name">姓名:</label>
281
+ <input id="name" bind:value={formData.name} required />
282
+ </div>
283
+
284
+ <div class="field">
285
+ <label for="email">邮箱:</label>
286
+ <input id="email" type="email" bind:value={formData.email} required />
287
+ </div>
288
+
289
+ <div class="field">
290
+ <label for="role">角色:</label>
291
+ <select id="role" bind:value={formData.role}>
292
+ <option value="user">普通用户</option>
293
+ <option value="admin">管理员</option>
294
+ <option value="moderator">协调员</option>
295
+ </select>
296
+ </div>
297
+ </form>
298
+ </CommonDialog>
299
+
300
+ <style>
301
+ .user-form {
302
+ display: flex;
303
+ flex-direction: column;
304
+ gap: 16px;
305
+ padding: 20px;
306
+ }
307
+
308
+ .field {
309
+ display: flex;
310
+ flex-direction: column;
311
+ gap: 4px;
312
+ }
313
+
314
+ label {
315
+ font-weight: 500;
316
+ color: #374151;
317
+ }
318
+
319
+ input, select {
320
+ padding: 8px 12px;
321
+ border: 1px solid #d1d5db;
322
+ border-radius: 6px;
323
+ font-size: 14px;
324
+ }
325
+
326
+ input:focus, select:focus {
327
+ outline: none;
328
+ border-color: #3b82f6;
329
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
330
+ }
331
+ </style>
332
+ ```
333
+
334
+ ### 方法 2: 自定义模态组件
335
+
336
+ ```svelte
337
+ <!-- ConfirmationDialog.svelte -->
338
+ <script lang="ts">
339
+ import { createEventDispatcher } from 'svelte';
340
+ import Button from '@ticatec/uniface-element/Button';
341
+
342
+ export let title = "确认操作";
343
+ export let message = "您确定要继续吗?";
344
+ export let confirmText = "确认";
345
+ export let cancelText = "取消";
346
+ export let danger = false;
347
+
348
+ const dispatch = createEventDispatcher();
349
+
350
+ const handleConfirm = () => {
351
+ dispatch('confirm');
352
+ };
353
+
354
+ const handleCancel = () => {
355
+ dispatch('cancel');
356
+ };
357
+
358
+ // 处理背景点击
359
+ const handleBackdrop = (e) => {
360
+ if (e.target === e.currentTarget) {
361
+ handleCancel();
362
+ }
363
+ };
364
+ </script>
365
+
366
+ <div class="modal-backdrop" on:click={handleBackdrop}>
367
+ <div class="confirmation-dialog" role="dialog" aria-labelledby="dialog-title">
368
+ <div class="dialog-header">
369
+ <h2 id="dialog-title">{title}</h2>
370
+ </div>
371
+
372
+ <div class="dialog-body">
373
+ <p>{message}</p>
374
+ </div>
375
+
376
+ <div class="dialog-footer">
377
+ <Button
378
+ label={cancelText}
379
+ type="secondary"
380
+ onClick={handleCancel}
381
+ />
382
+ <Button
383
+ label={confirmText}
384
+ type={danger ? "third" : "primary"}
385
+ onClick={handleConfirm}
386
+ />
387
+ </div>
388
+ </div>
389
+ </div>
390
+
391
+ <style>
392
+ .modal-backdrop {
393
+ position: fixed;
394
+ top: 0;
395
+ left: 0;
396
+ width: 100%;
397
+ height: 100%;
398
+ background: rgba(0, 0, 0, 0.5);
399
+ display: flex;
400
+ align-items: center;
401
+ justify-content: center;
402
+ z-index: 1000;
403
+ }
404
+
405
+ .confirmation-dialog {
406
+ background: white;
407
+ border-radius: 8px;
408
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
409
+ max-width: 400px;
410
+ width: 90%;
411
+ max-height: 90vh;
412
+ overflow: hidden;
413
+ }
414
+
415
+ .dialog-header {
416
+ padding: 20px 20px 0;
417
+ }
418
+
419
+ .dialog-header h2 {
420
+ margin: 0;
421
+ font-size: 1.25rem;
422
+ color: #374151;
423
+ }
424
+
425
+ .dialog-body {
426
+ padding: 16px 20px;
427
+ }
428
+
429
+ .dialog-body p {
430
+ margin: 0;
431
+ color: #6b7280;
432
+ line-height: 1.5;
433
+ }
434
+
435
+ .dialog-footer {
436
+ padding: 16px 20px 20px;
437
+ display: flex;
438
+ justify-content: flex-end;
439
+ gap: 12px;
440
+ }
441
+ </style>
442
+ ```
443
+
444
+ ## 高级用法
445
+
446
+ ### 带表单验证的对话框
447
+
448
+ ```svelte
449
+ <script lang="ts">
450
+ import CommonDialog from '@ticatec/uniface-element/CommonDialog';
451
+
452
+ export let product: any;
453
+ export let onSave: (product: any) => Promise<void>;
454
+
455
+ let formData = { ...product };
456
+ let errors = {};
457
+ let saving = false;
458
+
459
+ $: enableConfirm = isFormValid(formData) && !saving;
460
+
461
+ const isFormValid = (data) => {
462
+ const newErrors = {};
463
+
464
+ if (!data.name?.trim()) {
465
+ newErrors.name = "产品名称是必填项";
466
+ }
467
+
468
+ if (!data.price || data.price <= 0) {
469
+ newErrors.price = "价格必须大于 0";
470
+ }
471
+
472
+ if (!data.category) {
473
+ newErrors.category = "必须选择分类";
474
+ }
475
+
476
+ errors = newErrors;
477
+ return Object.keys(newErrors).length === 0;
478
+ };
479
+
480
+ const handleSave = async () => {
481
+ if (!isFormValid(formData) || saving) {
482
+ return false;
483
+ }
484
+
485
+ saving = true;
486
+ try {
487
+ await onSave(formData);
488
+ return true;
489
+ } catch (error) {
490
+ console.error('保存失败:', error);
491
+ return false;
492
+ } finally {
493
+ saving = false;
494
+ }
495
+ };
496
+ </script>
497
+
498
+ <CommonDialog
499
+ title="编辑产品"
500
+ width="700px"
501
+ height="600px"
502
+ bind:enableConfirm
503
+ confirmHandler={handleSave}
504
+ confirmText={saving ? "保存中..." : "保存产品"}
505
+ >
506
+ <form class="product-form">
507
+ <div class="field">
508
+ <label for="name">产品名称 *</label>
509
+ <input
510
+ id="name"
511
+ bind:value={formData.name}
512
+ class:error={errors.name}
513
+ placeholder="输入产品名称"
514
+ />
515
+ {#if errors.name}
516
+ <span class="error-text">{errors.name}</span>
517
+ {/if}
518
+ </div>
519
+
520
+ <div class="field">
521
+ <label for="price">价格 *</label>
522
+ <input
523
+ id="price"
524
+ type="number"
525
+ min="0"
526
+ step="0.01"
527
+ bind:value={formData.price}
528
+ class:error={errors.price}
529
+ placeholder="0.00"
530
+ />
531
+ {#if errors.price}
532
+ <span class="error-text">{errors.price}</span>
533
+ {/if}
534
+ </div>
535
+
536
+ <div class="field">
537
+ <label for="category">分类 *</label>
538
+ <select
539
+ id="category"
540
+ bind:value={formData.category}
541
+ class:error={errors.category}
542
+ >
543
+ <option value="">选择分类</option>
544
+ <option value="electronics">电子产品</option>
545
+ <option value="clothing">服装</option>
546
+ <option value="books">图书</option>
547
+ <option value="home">家居园艺</option>
548
+ </select>
549
+ {#if errors.category}
550
+ <span class="error-text">{errors.category}</span>
551
+ {/if}
552
+ </div>
553
+
554
+ <div class="field">
555
+ <label for="description">描述</label>
556
+ <textarea
557
+ id="description"
558
+ bind:value={formData.description}
559
+ placeholder="产品描述(可选)"
560
+ rows="4"
561
+ ></textarea>
562
+ </div>
563
+ </form>
564
+ </CommonDialog>
565
+
566
+ <style>
567
+ .product-form {
568
+ padding: 20px;
569
+ display: flex;
570
+ flex-direction: column;
571
+ gap: 16px;
572
+ }
573
+
574
+ .field {
575
+ display: flex;
576
+ flex-direction: column;
577
+ gap: 4px;
578
+ }
579
+
580
+ label {
581
+ font-weight: 500;
582
+ color: #374151;
583
+ font-size: 14px;
584
+ }
585
+
586
+ input, select, textarea {
587
+ padding: 8px 12px;
588
+ border: 1px solid #d1d5db;
589
+ border-radius: 6px;
590
+ font-size: 14px;
591
+ transition: border-color 0.2s, box-shadow 0.2s;
592
+ }
593
+
594
+ input:focus, select:focus, textarea:focus {
595
+ outline: none;
596
+ border-color: #3b82f6;
597
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
598
+ }
599
+
600
+ input.error, select.error, textarea.error {
601
+ border-color: #ef4444;
602
+ }
603
+
604
+ .error-text {
605
+ color: #ef4444;
606
+ font-size: 12px;
607
+ margin-top: 2px;
608
+ }
609
+
610
+ textarea {
611
+ resize: vertical;
612
+ min-height: 80px;
613
+ }
614
+ </style>
615
+ ```
616
+
617
+ ## API 参考
618
+
619
+ ### 全局对话框接口
620
+
621
+ ```typescript
622
+ interface IDialog {
623
+ showModal<T>(component: any, props?: T): void;
624
+ }
625
+ ```
626
+
627
+ ### ModalResult 枚举
628
+
629
+ ```typescript
630
+ enum ModalResult {
631
+ None = 0,
632
+ Ok = 1,
633
+ Cancel = 2,
634
+ Abort = 3,
635
+ Retry = 4,
636
+ Ignore = 5,
637
+ Yes = 6,
638
+ No = 7
639
+ }
640
+ ```
641
+
642
+ ### 事件处理器
643
+
644
+ ```typescript
645
+ type OnClose = (result: ModalResult) => void;
646
+ type DialogCloseConfirm = () => Promise<boolean>;
647
+ type ConfirmHandler = () => Promise<boolean>;
648
+ ```
649
+
650
+ ## 最佳实践
651
+
652
+ ### 1. 使用适当的对话框大小
653
+
654
+ ```svelte
655
+ <!-- 小型确认对话框 -->
656
+ <CommonDialog width="400px" height="200px">
657
+
658
+ <!-- 表单对话框 -->
659
+ <CommonDialog width="600px" height="500px">
660
+
661
+ <!-- 大型内容对话框 -->
662
+ <CommonDialog width="800px" height="700px">
663
+ ```
664
+
665
+ ### 2. 处理加载状态
666
+
667
+ ```svelte
668
+ <script>
669
+ let saving = false;
670
+ let enableConfirm = true;
671
+
672
+ const handleSave = async () => {
673
+ saving = true;
674
+ enableConfirm = false;
675
+
676
+ try {
677
+ await saveData();
678
+ return true; // 关闭对话框
679
+ } catch (error) {
680
+ // 处理错误,保持对话框打开
681
+ return false;
682
+ } finally {
683
+ saving = false;
684
+ enableConfirm = true;
685
+ }
686
+ };
687
+ </script>
688
+
689
+ <CommonDialog
690
+ bind:enableConfirm
691
+ confirmHandler={handleSave}
692
+ confirmText={saving ? "保存中..." : "保存"}
693
+ >
694
+ ```
695
+
696
+ ### 3. 实现适当的验证
697
+
698
+ ```svelte
699
+ <script>
700
+ let formData = { name: '', email: '' };
701
+ let errors = {};
702
+
703
+ $: enableConfirm = isValid(formData);
704
+
705
+ const isValid = (data) => {
706
+ return data.name.trim() &&
707
+ data.email.trim() &&
708
+ data.email.includes('@');
709
+ };
710
+ </script>
711
+ ```
712
+
713
+ ### 4. 使用上下文处理复杂对话框
714
+
715
+ ```svelte
716
+ <script>
717
+ import { setContext } from 'svelte';
718
+
719
+ // 为子组件提供辅助函数
720
+ setContext('showNotification', (message) => {
721
+ // 显示通知
722
+ });
723
+
724
+ setContext('closeDialog', () => {
725
+ modalResult = ModalResult.Cancel;
726
+ });
727
+ </script>
728
+ ```
729
+
730
+ ### 5. 键盘导航支持
731
+
732
+ ```svelte
733
+ <script>
734
+ import { onMount } from 'svelte';
735
+
736
+ onMount(() => {
737
+ const handleKeydown = (e) => {
738
+ if (e.key === 'Escape') {
739
+ handleCancel();
740
+ } else if (e.key === 'Enter' && e.ctrlKey) {
741
+ handleConfirm();
742
+ }
743
+ };
744
+
745
+ document.addEventListener('keydown', handleKeydown);
746
+
747
+ return () => {
748
+ document.removeEventListener('keydown', handleKeydown);
749
+ };
750
+ });
751
+ </script>
752
+ ```
753
+
754
+ ## 无障碍访问注意事项
755
+
756
+ - 始终提供适当的 `aria-labelledby` 和 `role="dialog"` 属性
757
+ - 确保键盘导航正常工作(Tab、Enter、Escape)
758
+ - 焦点管理 - 焦点应该被限制在对话框内
759
+ - 为必填字段提供清晰的视觉指示器
760
+ - 在对话框内容中使用语义化HTML元素
761
+ - 确保所有文本和交互元素有足够的颜色对比度
762
+
763
+ ## 浏览器支持
764
+
765
+ - 需要支持 ES2020+ 的现代浏览器
766
+ - 布局需要 CSS Grid 和 Flexbox 支持
767
+ - 反应式存储需要 JavaScript Proxy 支持