@ticatec/uniface-element 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/accordion/README.md +169 -0
  2. package/dist/accordion/README_CN.md +176 -0
  3. package/dist/action-bar/README.md +275 -0
  4. package/dist/action-bar/README_CN.md +285 -0
  5. package/dist/app-layout/README.md +374 -0
  6. package/dist/app-layout/README_CN.md +381 -0
  7. package/dist/app-top-bar/README.md +357 -0
  8. package/dist/app-top-bar/README_CN.md +365 -0
  9. package/dist/attachment-files/AttachmentFilesField.svelte +67 -1
  10. package/dist/attachment-files/AttachmentFilesField.svelte.d.ts +8 -1
  11. package/dist/base-calendar/CalendarBase.svelte +0 -3
  12. package/dist/box/README.md +385 -0
  13. package/dist/box/README_CN.md +393 -0
  14. package/dist/breadcrumbs/README.md +442 -0
  15. package/dist/breadcrumbs/README_CN.md +442 -0
  16. package/dist/button/Button.svelte +27 -7
  17. package/dist/button/Button.svelte.d.ts +3 -1
  18. package/dist/button/IconButton.svelte +26 -6
  19. package/dist/button/IconButton.svelte.d.ts +3 -1
  20. package/dist/button/IconButton_README.md +513 -0
  21. package/dist/button/IconButton_README_CN.md +513 -0
  22. package/dist/button/README.md +428 -0
  23. package/dist/button/README_CN.md +428 -0
  24. package/dist/button/TextButton.svelte +26 -6
  25. package/dist/button/TextButton.svelte.d.ts +3 -1
  26. package/dist/button/TextButton_README.md +571 -0
  27. package/dist/button/TextButton_README_CN.md +571 -0
  28. package/dist/card/README.md +666 -0
  29. package/dist/card/README_CN.md +666 -0
  30. package/dist/cascade-options-select/CascadeOptionSelect.svelte +43 -7
  31. package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +3 -4
  32. package/dist/cascade-options-select/README.md +663 -2
  33. package/dist/cascade-options-select/README_CN.md +664 -0
  34. package/dist/checkbox/CheckBox.svelte +20 -6
  35. package/dist/checkbox/CheckBox.svelte.d.ts +4 -2
  36. package/dist/checkbox/README.md +562 -0
  37. package/dist/checkbox/README_CN.md +727 -0
  38. package/dist/common-editor/NumberInput.svelte +39 -26
  39. package/dist/common-editor/NumberInput.svelte.d.ts +5 -1
  40. package/dist/concise-data-table/ConciseListTable.svelte +133 -36
  41. package/dist/concise-data-table/ConciseListTable.svelte.d.ts +8 -1
  42. package/dist/concise-data-table/DataCell.svelte +5 -6
  43. package/dist/concise-data-table/DataRow.svelte +22 -2
  44. package/dist/concise-data-table/DataRow.svelte.d.ts +1 -0
  45. package/dist/concise-data-table/README.md +606 -0
  46. package/dist/concise-data-table/README_CN.md +611 -0
  47. package/dist/context-menu/ContextMenu.svelte +138 -21
  48. package/dist/context-menu/ContextMenu.svelte.d.ts +5 -0
  49. package/dist/context-menu/ContextMenuItem.d.ts +20 -4
  50. package/dist/context-menu/README.md +551 -0
  51. package/dist/context-menu/README_CN.md +551 -0
  52. package/dist/criteria-field/CriteriaField.svelte +3 -5
  53. package/dist/criteria-field/README.md +532 -0
  54. package/dist/criteria-field/README_CN.md +532 -0
  55. package/dist/data-table/README.md +712 -0
  56. package/dist/data-table/README_CN.md +712 -0
  57. package/dist/date-picker/DatePicker.svelte +44 -7
  58. package/dist/date-picker/DatePicker.svelte.d.ts +3 -4
  59. package/dist/date-picker/DateTimePicker.svelte +32 -8
  60. package/dist/date-picker/DateTimePicker.svelte.d.ts +3 -4
  61. package/dist/date-picker/README.md +326 -0
  62. package/dist/date-picker/README_CN.md +316 -0
  63. package/dist/date-picker/ScrollBar.svelte +18 -8
  64. package/dist/date-picker/ScrollBar.svelte.d.ts +1 -1
  65. package/dist/date-picker/TimePanel.svelte +5 -5
  66. package/dist/date-picker/TimePanel.svelte.d.ts +1 -1
  67. package/dist/date-range/README.md +374 -0
  68. package/dist/date-range/README_CN.md +374 -0
  69. package/dist/dialog/README.md +596 -0
  70. package/dist/dialog/README_CN.md +596 -0
  71. package/dist/drawer/README.md +679 -1
  72. package/dist/drawer/README_CN.md +679 -0
  73. package/dist/group-box/group-check-box/GroupCheckBox.svelte +62 -5
  74. package/dist/group-box/group-check-box/GroupCheckBox.svelte.d.ts +7 -2
  75. package/dist/group-box/group-check-box/README.md +749 -0
  76. package/dist/group-box/group-check-box/README_CN.md +750 -0
  77. package/dist/group-box/group-radio-box/GroupRadioBox.svelte +69 -4
  78. package/dist/group-box/group-radio-box/GroupRadioBox.svelte.d.ts +8 -2
  79. package/dist/group-box/group-radio-box/README.md +920 -0
  80. package/dist/group-box/group-radio-box/README_CN.md +920 -0
  81. package/dist/image-files/README.md +1346 -0
  82. package/dist/image-files/README_CN.md +1346 -0
  83. package/dist/input-options-select/InputOptionsSelect.svelte +161 -65
  84. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +4 -1
  85. package/dist/lib/forwardAllEvents.d.ts +3 -0
  86. package/dist/lib/forwardAllEvents.js +24 -0
  87. package/dist/list-box/README.md +579 -0
  88. package/dist/list-box/README_CN.md +682 -0
  89. package/dist/lookup-editor/LookupEditor.svelte +15 -3
  90. package/dist/lookup-editor/LookupEditor.svelte.d.ts +3 -4
  91. package/dist/lookup-editor/README.md +684 -0
  92. package/dist/lookup-editor/README_CN.md +684 -0
  93. package/dist/memo-editor/MemoEditor.svelte +77 -27
  94. package/dist/memo-editor/MemoEditor.svelte.d.ts +6 -3
  95. package/dist/memo-editor/README.md +819 -0
  96. package/dist/memo-editor/README_CN.md +819 -0
  97. package/dist/message-box/README.md +398 -0
  98. package/dist/message-box/README_CN.md +398 -0
  99. package/dist/number-editor/NumberEditor.svelte +2 -2
  100. package/dist/number-editor/NumberEditor.svelte.d.ts +1 -1
  101. package/dist/number-editor/README.md +353 -22
  102. package/dist/number-editor/README_CN.md +357 -0
  103. package/dist/number-range/README.md +443 -0
  104. package/dist/number-range/README_CN.md +443 -0
  105. package/dist/options-multi-select/OptionsMultiSelect.svelte +87 -12
  106. package/dist/options-multi-select/OptionsMultiSelect.svelte.d.ts +3 -1
  107. package/dist/options-multi-select/README.md +480 -0
  108. package/dist/options-multi-select/README_CN.md +480 -0
  109. package/dist/options-select/OptionsSelect.svelte +36 -5
  110. package/dist/options-select/OptionsSelect.svelte.d.ts +3 -4
  111. package/dist/options-select/README.md +632 -0
  112. package/dist/options-select/README_CN.md +632 -0
  113. package/dist/page/README.md +605 -0
  114. package/dist/page/README_CN.md +605 -0
  115. package/dist/pagination/README.md +946 -0
  116. package/dist/pagination/README_CN.md +946 -0
  117. package/dist/pagination-panel/README.md +1075 -0
  118. package/dist/pagination-panel/README_CN.md +1075 -0
  119. package/dist/popup-hint/README.md +841 -0
  120. package/dist/popup-hint/README_CN.md +840 -0
  121. package/dist/progress-bar/README.md +242 -0
  122. package/dist/progress-bar/README_CN.md +242 -0
  123. package/dist/progress-step-bar/README.md +316 -0
  124. package/dist/progress-step-bar/README_CN.md +316 -0
  125. package/dist/prompts-text-editor/PromptsTextEditor.svelte +6 -3
  126. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +3 -1
  127. package/dist/prompts-text-editor/README.md +329 -0
  128. package/dist/prompts-text-editor/README_CN.md +329 -0
  129. package/dist/property-editor/README.md +969 -0
  130. package/dist/property-editor/README_CN.md +969 -0
  131. package/dist/radio-button/README.md +372 -0
  132. package/dist/radio-button/README_CN.md +372 -0
  133. package/dist/radio-button/RadioButton.svelte +32 -3
  134. package/dist/radio-button/RadioButton.svelte.d.ts +12 -1
  135. package/dist/search-box/README.md +425 -0
  136. package/dist/search-box/README_CN.md +424 -0
  137. package/dist/search-box/SearchBox.svelte +22 -6
  138. package/dist/search-box/SearchBox.svelte.d.ts +4 -1
  139. package/dist/tabs/README.md +919 -0
  140. package/dist/tabs/README_CN.md +920 -0
  141. package/dist/tag/README.md +922 -0
  142. package/dist/tag/README_CN.md +922 -0
  143. package/dist/text-editor/PasswordEditor.svelte +17 -2
  144. package/dist/text-editor/PasswordEditor.svelte.d.ts +3 -3
  145. package/dist/text-editor/PasswordEditor_README.md +551 -0
  146. package/dist/text-editor/PasswordEditor_README_CN.md +551 -0
  147. package/dist/text-editor/README.md +466 -0
  148. package/dist/text-editor/README_CN.md +466 -0
  149. package/dist/text-editor/TextEditor.svelte +51 -19
  150. package/dist/text-editor/TextEditor.svelte.d.ts +0 -1
  151. package/dist/time-editor/README.md +498 -24
  152. package/dist/time-editor/README_CN.md +498 -0
  153. package/dist/time-editor/TimeEditor.svelte +7 -3
  154. package/dist/time-editor/TimeEditor.svelte.d.ts +3 -1
  155. package/dist/toast/README.md +667 -0
  156. package/dist/toast/README_CN.md +667 -0
  157. package/dist/transfer/README.md +795 -0
  158. package/dist/transfer/Transfer.svelte +6 -4
  159. package/dist/transfer/Transfer.svelte.d.ts +3 -1
  160. package/dist/tree-view/README.md +761 -0
  161. package/dist/tree-view/README_CN.md +761 -0
  162. package/dist/tree-view/TreeView.svelte +5 -3
  163. package/dist/tree-view/TreeView.svelte.d.ts +3 -1
  164. package/dist/unit-number-editor/README.md +546 -20
  165. package/dist/unit-number-editor/README_CN.md +525 -0
  166. package/dist/unit-number-editor/UnitNumberEditor.svelte +62 -8
  167. package/dist/unit-number-editor/UnitNumberEditor.svelte.d.ts +5 -1
  168. package/docs/form-field/cn/README_CN.md +364 -0
  169. package/docs/form-field/en/README.md +364 -0
  170. package/docs/form-panel/flex-form/cn/README_CN.md +586 -0
  171. package/docs/form-panel/flex-form/en/README.md +586 -0
  172. package/docs/form-panel/flex-row-form/cn/README_CN.md +787 -0
  173. package/docs/form-panel/flex-row-form/en/README.md +787 -0
  174. package/docs/form-panel/grid-form/en/README.md +744 -0
  175. package/package.json +1 -1
  176. package/dist/drawer/README-CN.md +0 -1
@@ -0,0 +1,920 @@
1
+ # Tabs 标签页组件
2
+
3
+ 一个灵活的标签页导航组件,支持水平滚动、可关闭标签页和自定义渲染。功能包括自动溢出处理、平滑滚动动画和标签页刷新功能。非常适合文档界面、仪表板和多面板应用。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @ticatec/uniface-element
9
+ ```
10
+
11
+ ## 导入
12
+
13
+ ```typescript
14
+ import Tabs, { type TabActionHandler, type TabCloseHandler, type TabRender } from "@ticatec/uniface-element/Tabs";
15
+ ```
16
+
17
+ ## 基本用法
18
+
19
+ ```svelte
20
+ <script>
21
+ import Tabs from "@ticatec/uniface-element/Tabs";
22
+
23
+ let tabs = [
24
+ { text: "首页" },
25
+ { text: "产品" },
26
+ { text: "服务" },
27
+ { text: "关于" },
28
+ { text: "联系我们" }
29
+ ];
30
+
31
+ let activeTab = tabs[0];
32
+ </script>
33
+
34
+ <Tabs {tabs} bind:activeTab>
35
+ <div class="tab-content">
36
+ <h2>{activeTab.text}</h2>
37
+ <p>{activeTab.text} 标签页的内容</p>
38
+ </div>
39
+ </Tabs>
40
+ ```
41
+
42
+ ## 属性
43
+
44
+ | 属性 | 类型 | 默认值 | 描述 |
45
+ |------|------|---------|-------------|
46
+ | `tabs` | `Array<any>` | `[]` | 标签页对象数组 |
47
+ | `activeTab` | `any` | `null` | 当前激活的标签页对象 |
48
+ | `textField` | `string` | `"text"` | 标签页显示文本的字段名称 |
49
+ | `simple` | `boolean` | `false` | 是否使用简约样式 |
50
+ | `closable` | `boolean \| TabActionHandler` | `false` | 标签页是否可关闭 |
51
+ | `scrollStep` | `number` | `100` | 滚动步长(像素) |
52
+ | `tabRender` | `TabRender` | `null` | 自定义标签页渲染组件 |
53
+ | `reloadHandler` | `TabActionHandler` | `null` | 标签页刷新动作的处理函数 |
54
+ | `closeHandler` | `TabCloseHandler` | `null` | 标签页关闭动作的处理函数 |
55
+ | `style` | `string` | `""` | 附加 CSS 样式 |
56
+ | `class` | `string` | `""` | CSS 类名 |
57
+
58
+ ## 类型定义
59
+
60
+ ### TabActionHandler
61
+ ```typescript
62
+ type TabActionHandler = (tab: any) => void;
63
+ ```
64
+
65
+ ### TabCloseHandler
66
+ ```typescript
67
+ type TabCloseHandler = (tab: any) => Promise<boolean>;
68
+ ```
69
+
70
+ ### TabRender
71
+ ```typescript
72
+ type TabRender = (tab: any) => any;
73
+ ```
74
+
75
+ ## 示例
76
+
77
+ ### 基本标签页导航
78
+
79
+ ```svelte
80
+ <script>
81
+ import Tabs from "@ticatec/uniface-element/Tabs";
82
+
83
+ let navigationTabs = [
84
+ { id: 1, text: "仪表板", icon: "dashboard" },
85
+ { id: 2, text: "分析", icon: "analytics" },
86
+ { id: 3, text: "报告", icon: "reports" },
87
+ { id: 4, text: "设置", icon: "settings" }
88
+ ];
89
+
90
+ let currentTab = navigationTabs[0];
91
+ </script>
92
+
93
+ <div class="app-container">
94
+ <Tabs tabs={navigationTabs} bind:activeTab={currentTab} style="height: 400px;">
95
+ {#if currentTab.id === 1}
96
+ <div class="dashboard">
97
+ <h2>📊 仪表板</h2>
98
+ <p>欢迎体验您的仪表板概览</p>
99
+ <div class="stats">
100
+ <div class="stat">用户数: 1,234</div>
101
+ <div class="stat">收入: ¥12,345</div>
102
+ <div class="stat">订单数: 567</div>
103
+ </div>
104
+ </div>
105
+ {:else if currentTab.id === 2}
106
+ <div class="analytics">
107
+ <h2>📈 分析</h2>
108
+ <p>查看您的性能指标</p>
109
+ <div class="charts">
110
+ <div class="chart">月增长: +15%</div>
111
+ <div class="chart">转化率: 3.2%</div>
112
+ </div>
113
+ </div>
114
+ {:else if currentTab.id === 3}
115
+ <div class="reports">
116
+ <h2>📋 报告</h2>
117
+ <p>生成和查看报告</p>
118
+ <button>生成月度报告</button>
119
+ <button>导出数据</button>
120
+ </div>
121
+ {:else if currentTab.id === 4}
122
+ <div class="settings">
123
+ <h2>⚙️ 设置</h2>
124
+ <p>配置您的偏好设置</p>
125
+ <label><input type="checkbox"> 电子邮件通知</label>
126
+ <label><input type="checkbox"> 深色模式</label>
127
+ </div>
128
+ {/if}
129
+ </Tabs>
130
+ </div>
131
+
132
+ <style>
133
+ .app-container {
134
+ max-width: 800px;
135
+ margin: 20px auto;
136
+ border: 1px solid #ddd;
137
+ border-radius: 8px;
138
+ }
139
+
140
+ .dashboard, .analytics, .reports, .settings {
141
+ padding: 20px;
142
+ }
143
+
144
+ .stats, .charts {
145
+ display: grid;
146
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
147
+ gap: 16px;
148
+ margin-top: 16px;
149
+ }
150
+
151
+ .stat, .chart {
152
+ padding: 12px;
153
+ background: #f8f9fa;
154
+ border-radius: 4px;
155
+ text-align: center;
156
+ }
157
+
158
+ .reports button {
159
+ margin: 8px 8px 8px 0;
160
+ padding: 8px 16px;
161
+ border: none;
162
+ background: #007bff;
163
+ color: white;
164
+ border-radius: 4px;
165
+ cursor: pointer;
166
+ }
167
+
168
+ .settings label {
169
+ display: block;
170
+ margin: 8px 0;
171
+ }
172
+ </style>
173
+ ```
174
+
175
+ ### 简约标签页
176
+
177
+ ```svelte
178
+ <script>
179
+ import Tabs from "@ticatec/uniface-element/Tabs";
180
+
181
+ let documentTabs = [
182
+ { text: "简介" },
183
+ { text: "入门指南" },
184
+ { text: "API 参考" },
185
+ { text: "示例" }
186
+ ];
187
+
188
+ let currentDoc = documentTabs[0];
189
+ </script>
190
+
191
+ <div class="docs-container">
192
+ <Tabs tabs={documentTabs} bind:activeTab={currentDoc} simple style="height: 300px;">
193
+ <div class="doc-content">
194
+ {#if currentDoc.text === "简介"}
195
+ <h3>简介</h3>
196
+ <p>欢迎体验我们的全面文档。本指南将帮助您快速上手我们的平台并充分利用其功能。</p>
197
+ {:else if currentDoc.text === "入门指南"}
198
+ <h3>入门指南</h3>
199
+ <ol>
200
+ <li>创建账户</li>
201
+ <li>验证您的电子邮件</li>
202
+ <li>完善您的个人资料</li>
203
+ <li>开始使用平台</li>
204
+ </ol>
205
+ {:else if currentDoc.text === "API 参考"}
206
+ <h3>API 参考</h3>
207
+ <p>完整的 API 文档,包括端点、参数和示例。</p>
208
+ <code>GET /api/users</code>
209
+ {:else if currentDoc.text === "示例"}
210
+ <h3>示例</h3>
211
+ <p>实用示例和代码片段,帮助您实现常见用例。</p>
212
+ {/if}
213
+ </div>
214
+ </Tabs>
215
+ </div>
216
+
217
+ <style>
218
+ .docs-container {
219
+ max-width: 600px;
220
+ margin: 20px auto;
221
+ }
222
+
223
+ .doc-content {
224
+ padding: 20px;
225
+ background: #f8f9fa;
226
+ }
227
+
228
+ .doc-content h3 {
229
+ margin-top: 0;
230
+ color: #333;
231
+ }
232
+
233
+ .doc-content code {
234
+ background: #e9ecef;
235
+ padding: 4px 8px;
236
+ border-radius: 4px;
237
+ font-family: monospace;
238
+ }
239
+
240
+ .doc-content ol {
241
+ padding-left: 20px;
242
+ }
243
+
244
+ .doc-content li {
245
+ margin: 8px 0;
246
+ }
247
+ </style>
248
+ ```
249
+
250
+ ### 可关闭标签页
251
+
252
+ ```svelte
253
+ <script>
254
+ import Tabs from "@ticatec/uniface-element/Tabs";
255
+
256
+ let browserTabs = [
257
+ { id: 1, text: "百度", url: "https://www.baidu.com", modified: false },
258
+ { id: 2, text: "GitHub", url: "https://github.com", modified: true },
259
+ { id: 3, text: "知乎", url: "https://www.zhihu.com", modified: false },
260
+ { id: 4, text: "MDN 文档", url: "https://developer.mozilla.org", modified: false }
261
+ ];
262
+
263
+ let activeTab = browserTabs[0];
264
+
265
+ async function handleTabClose(tab) {
266
+ if (tab.modified) {
267
+ const confirmed = confirm(`"${tab.text}" 有未保存的更改。是否仍要关闭?`);
268
+ if (!confirmed) return false;
269
+ }
270
+
271
+ console.log(`关闭标签页:${tab.text}`);
272
+ browserTabs = browserTabs.filter(t => t.id !== tab.id);
273
+ return true;
274
+ }
275
+
276
+ function addNewTab() {
277
+ const newId = Math.max(...browserTabs.map(t => t.id)) + 1;
278
+ const newTab = {
279
+ id: newId,
280
+ text: "新标签页",
281
+ url: "about:blank",
282
+ modified: false
283
+ };
284
+
285
+ browserTabs = [...browserTabs, newTab];
286
+ activeTab = newTab;
287
+ }
288
+ </script>
289
+
290
+ <div class="browser-container">
291
+ <div class="browser-header">
292
+ <Tabs
293
+ tabs={browserTabs}
294
+ bind:activeTab
295
+ closable={true}
296
+ closeHandler={handleTabClose}
297
+ style="height: 350px;"
298
+ >
299
+ <div class="page-content">
300
+ <div class="address-bar">
301
+ <span>🔒 {activeTab.url}</span>
302
+ </div>
303
+ <div class="page-body">
304
+ <h2>{activeTab.text}</h2>
305
+ <p>这是 {activeTab.text} 的内容</p>
306
+ {#if activeTab.modified}
307
+ <p class="modified">⚠️ 此页面有未保存的更改</p>
308
+ {/if}
309
+ <button on:click={() => activeTab.modified = !activeTab.modified}>
310
+ {activeTab.modified ? '标记为已保存' : '进行更改'}
311
+ </button>
312
+ </div>
313
+ </div>
314
+ </Tabs>
315
+ <button class="new-tab-btn" on:click={addNewTab}>+</button>
316
+ </div>
317
+ </div>
318
+
319
+ <style>
320
+ .browser-container {
321
+ max-width: 900px;
322
+ margin: 20px auto;
323
+ border: 1px solid #ddd;
324
+ border-radius: 8px;
325
+ overflow: hidden;
326
+ }
327
+
328
+ .browser-header {
329
+ display: flex;
330
+ align-items: stretch;
331
+ }
332
+
333
+ .new-tab-btn {
334
+ width: 40px;
335
+ border: none;
336
+ background: #f8f9fa;
337
+ cursor: pointer;
338
+ font-size: 18px;
339
+ border-left: 1px solid #ddd;
340
+ }
341
+
342
+ .new-tab-btn:hover {
343
+ background: #e9ecef;
344
+ }
345
+
346
+ .page-content {
347
+ padding: 0;
348
+ height: 100%;
349
+ display: flex;
350
+ flex-direction: column;
351
+ }
352
+
353
+ .address-bar {
354
+ padding: 8px 16px;
355
+ background: #f8f9fa;
356
+ border-bottom: 1px solid #ddd;
357
+ font-family: monospace;
358
+ font-size: 14px;
359
+ }
360
+
361
+ .page-body {
362
+ padding: 20px;
363
+ flex: 1;
364
+ }
365
+
366
+ .modified {
367
+ color: #dc3545;
368
+ font-weight: 500;
369
+ }
370
+
371
+ button {
372
+ margin-top: 12px;
373
+ padding: 8px 16px;
374
+ border: 1px solid #007bff;
375
+ background: white;
376
+ color: #007bff;
377
+ border-radius: 4px;
378
+ cursor: pointer;
379
+ }
380
+
381
+ button:hover {
382
+ background: #007bff;
383
+ color: white;
384
+ }
385
+ </style>
386
+ ```
387
+
388
+ ### 带刷新功能的标签页
389
+
390
+ ```svelte
391
+ <script>
392
+ import Tabs from "@ticatec/uniface-element/Tabs";
393
+
394
+ let dataTabs = [
395
+ { id: 1, text: "销售数据", lastUpdated: "2 分钟前", loading: false },
396
+ { id: 2, text: "用户分析", lastUpdated: "5 分钟前", loading: false },
397
+ { id: 3, text: "性能", lastUpdated: "10 分钟前", loading: false }
398
+ ];
399
+
400
+ let activeDataTab = dataTabs[0];
401
+
402
+ function handleTabReload(tab) {
403
+ console.log(`刷新标签页:${tab.text}`);
404
+
405
+ // 设置加载状态
406
+ tab.loading = true;
407
+ dataTabs = [...dataTabs];
408
+
409
+ // 模拟数据刷新
410
+ setTimeout(() => {
411
+ tab.loading = false;
412
+ tab.lastUpdated = "刚刚更新";
413
+ dataTabs = [...dataTabs];
414
+ }, 2000);
415
+ }
416
+ </script>
417
+
418
+ <div class="data-dashboard">
419
+ <Tabs
420
+ tabs={dataTabs}
421
+ bind:activeTab={activeDataTab}
422
+ reloadHandler={handleTabReload}
423
+ style="height: 400px;"
424
+ >
425
+ <div class="data-content">
426
+ <div class="data-header">
427
+ <h3>{activeDataTab.text}</h3>
428
+ <div class="last-updated">
429
+ {#if activeDataTab.loading}
430
+ <span class="loading">🔄 正在刷新...</span>
431
+ {:else}
432
+ <span>最后更新:{activeDataTab.lastUpdated}</span>
433
+ {/if}
434
+ </div>
435
+ </div>
436
+
437
+ <div class="data-body">
438
+ {#if activeDataTab.id === 1}
439
+ <div class="chart-placeholder">
440
+ <h4>销售概览</h4>
441
+ <div class="metrics">
442
+ <div>总销售额:¥45,678</div>
443
+ <div>增长率:+12.5%</div>
444
+ <div>交易数:234</div>
445
+ </div>
446
+ </div>
447
+ {:else if activeDataTab.id === 2}
448
+ <div class="chart-placeholder">
449
+ <h4>用户参与度</h4>
450
+ <div class="metrics">
451
+ <div>活跃用户:1,890</div>
452
+ <div>会话时长:4:32</div>
453
+ <div>跳出率:23%</div>
454
+ </div>
455
+ </div>
456
+ {:else if activeDataTab.id === 3}
457
+ <div class="chart-placeholder">
458
+ <h4>系统性能</h4>
459
+ <div class="metrics">
460
+ <div>响应时间:145ms</div>
461
+ <div>正常运行时间:99.9%</div>
462
+ <div>CPU 使用率:45%</div>
463
+ </div>
464
+ </div>
465
+ {/if}
466
+ </div>
467
+ </div>
468
+ </Tabs>
469
+ </div>
470
+
471
+ <style>
472
+ .data-dashboard {
473
+ max-width: 800px;
474
+ margin: 20px auto;
475
+ border: 1px solid #ddd;
476
+ border-radius: 8px;
477
+ }
478
+
479
+ .data-content {
480
+ padding: 20px;
481
+ height: 100%;
482
+ display: flex;
483
+ flex-direction: column;
484
+ }
485
+
486
+ .data-header {
487
+ display: flex;
488
+ justify-content: space-between;
489
+ align-items: center;
490
+ margin-bottom: 20px;
491
+ padding-bottom: 12px;
492
+ border-bottom: 1px solid #eee;
493
+ }
494
+
495
+ .data-header h3 {
496
+ margin: 0;
497
+ }
498
+
499
+ .last-updated {
500
+ font-size: 14px;
501
+ color: #666;
502
+ }
503
+
504
+ .loading {
505
+ color: #007bff;
506
+ animation: pulse 1.5s infinite;
507
+ }
508
+
509
+ @keyframes pulse {
510
+ 0%, 100% { opacity: 1; }
511
+ 50% { opacity: 0.5; }
512
+ }
513
+
514
+ .chart-placeholder {
515
+ flex: 1;
516
+ background: #f8f9fa;
517
+ border-radius: 8px;
518
+ padding: 20px;
519
+ text-align: center;
520
+ }
521
+
522
+ .chart-placeholder h4 {
523
+ margin: 0 0 20px 0;
524
+ color: #333;
525
+ }
526
+
527
+ .metrics {
528
+ display: grid;
529
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
530
+ gap: 16px;
531
+ }
532
+
533
+ .metrics div {
534
+ padding: 16px;
535
+ background: white;
536
+ border-radius: 4px;
537
+ font-weight: 500;
538
+ }
539
+ </style>
540
+ ```
541
+
542
+ ### 自定义标签页渲染
543
+
544
+ ```svelte
545
+ <script>
546
+ import Tabs from "@ticatec/uniface-element/Tabs";
547
+ import CustomTab from "./CustomTab.svelte";
548
+
549
+ let projectTabs = [
550
+ {
551
+ id: 1,
552
+ text: "前端",
553
+ status: "active",
554
+ notifications: 3,
555
+ color: "#007bff"
556
+ },
557
+ {
558
+ id: 2,
559
+ text: "后端",
560
+ status: "warning",
561
+ notifications: 1,
562
+ color: "#ffc107"
563
+ },
564
+ {
565
+ id: 3,
566
+ text: "数据库",
567
+ status: "error",
568
+ notifications: 5,
569
+ color: "#dc3545"
570
+ },
571
+ {
572
+ id: 4,
573
+ text: "运维",
574
+ status: "success",
575
+ notifications: 0,
576
+ color: "#28a745"
577
+ }
578
+ ];
579
+
580
+ let activeProject = projectTabs[0];
581
+
582
+ async function handleProjectClose(tab) {
583
+ const confirmed = confirm(`关闭项目 "${tab.text}"?`);
584
+ return confirmed;
585
+ }
586
+ </script>
587
+
588
+ <!-- CustomTab.svelte -->
589
+ <script>
590
+ export let tab;
591
+ export let closeTab = null;
592
+ export let reloadTab = null;
593
+ export let closable = false;
594
+
595
+ function getStatusIcon(status) {
596
+ switch (status) {
597
+ case 'active': return '🟢';
598
+ case 'warning': return '🟡';
599
+ case 'error': return '🔴';
600
+ case 'success': return '✅';
601
+ default: return '⚪';
602
+ }
603
+ }
604
+ </script>
605
+
606
+ <div class="custom-tab" style="border-left: 3px solid {tab.color};">
607
+ <div class="tab-content">
608
+ <span class="status-icon">{getStatusIcon(tab.status)}</span>
609
+ <span class="tab-text">{tab.text}</span>
610
+ {#if tab.notifications > 0}
611
+ <span class="notification-badge">{tab.notifications}</span>
612
+ {/if}
613
+ </div>
614
+
615
+ <div class="tab-actions">
616
+ {#if reloadTab}
617
+ <button class="action-btn" on:click={reloadTab}>🔄</button>
618
+ {/if}
619
+ {#if closable && closeTab}
620
+ <button class="action-btn close" on:click={closeTab}>×</button>
621
+ {/if}
622
+ </div>
623
+ </div>
624
+
625
+ <style>
626
+ .custom-tab {
627
+ display: flex;
628
+ align-items: center;
629
+ justify-content: space-between;
630
+ padding: 8px 12px;
631
+ background: white;
632
+ border-radius: 4px 4px 0 0;
633
+ min-width: 120px;
634
+ }
635
+
636
+ .tab-content {
637
+ display: flex;
638
+ align-items: center;
639
+ gap: 6px;
640
+ }
641
+
642
+ .status-icon {
643
+ font-size: 12px;
644
+ }
645
+
646
+ .tab-text {
647
+ font-weight: 500;
648
+ }
649
+
650
+ .notification-badge {
651
+ background: #dc3545;
652
+ color: white;
653
+ font-size: 10px;
654
+ padding: 2px 6px;
655
+ border-radius: 10px;
656
+ min-width: 16px;
657
+ text-align: center;
658
+ }
659
+
660
+ .tab-actions {
661
+ display: flex;
662
+ gap: 4px;
663
+ }
664
+
665
+ .action-btn {
666
+ background: none;
667
+ border: none;
668
+ padding: 2px 4px;
669
+ cursor: pointer;
670
+ border-radius: 2px;
671
+ font-size: 12px;
672
+ }
673
+
674
+ .action-btn:hover {
675
+ background: #f8f9fa;
676
+ }
677
+
678
+ .action-btn.close:hover {
679
+ background: #dc3545;
680
+ color: white;
681
+ }
682
+ </style>
683
+
684
+ <!-- 主组件 -->
685
+ <div class="project-dashboard">
686
+ <Tabs
687
+ tabs={projectTabs}
688
+ bind:activeTab={activeProject}
689
+ tabRender={CustomTab}
690
+ closable={true}
691
+ closeHandler={handleProjectClose}
692
+ style="height: 350px;"
693
+ >
694
+ <div class="project-content">
695
+ <h3>{activeProject.text} 项目</h3>
696
+ <div class="project-status">
697
+ <span>状态:</span>
698
+ <span class="status {activeProject.status}">{activeProject.status.toUpperCase()}</span>
699
+ </div>
700
+
701
+ {#if activeProject.notifications > 0}
702
+ <div class="notifications">
703
+ <h4>通知 ({activeProject.notifications})</h4>
704
+ <ul>
705
+ {#each Array(activeProject.notifications) as _, i}
706
+ <li>{activeProject.text} 的通知 #{i + 1}</li>
707
+ {/each}
708
+ </ul>
709
+ </div>
710
+ {:else}
711
+ <p>此项目没有通知。</p>
712
+ {/if}
713
+ </div>
714
+ </Tabs>
715
+ </div>
716
+
717
+ <style>
718
+ .project-dashboard {
719
+ max-width: 800px;
720
+ margin: 20px auto;
721
+ border: 1px solid #ddd;
722
+ border-radius: 8px;
723
+ }
724
+
725
+ .project-content {
726
+ padding: 20px;
727
+ }
728
+
729
+ .project-status {
730
+ margin: 16px 0;
731
+ }
732
+
733
+ .status {
734
+ padding: 4px 8px;
735
+ border-radius: 4px;
736
+ font-weight: bold;
737
+ text-transform: uppercase;
738
+ font-size: 12px;
739
+ }
740
+
741
+ .status.active {
742
+ background: #cce5ff;
743
+ color: #004085;
744
+ }
745
+
746
+ .status.warning {
747
+ background: #fff3cd;
748
+ color: #856404;
749
+ }
750
+
751
+ .status.error {
752
+ background: #f8d7da;
753
+ color: #721c24;
754
+ }
755
+
756
+ .status.success {
757
+ background: #d4edda;
758
+ color: #155724;
759
+ }
760
+
761
+ .notifications h4 {
762
+ margin: 20px 0 12px 0;
763
+ }
764
+
765
+ .notifications ul {
766
+ padding-left: 20px;
767
+ }
768
+
769
+ .notifications li {
770
+ margin: 8px 0;
771
+ }
772
+ </style>
773
+ ```
774
+
775
+ ### 水平滚动标签页
776
+
777
+ ```svelte
778
+ <script>
779
+ import Tabs from "@ticatec/uniface-element/Tabs";
780
+
781
+ // 创建多个标签页以展示滚动效果
782
+ let manyTabs = Array.from({length: 15}, (_, i) => ({
783
+ id: i + 1,
784
+ text: `标签页 ${i + 1}`,
785
+ content: `这是标签页 ${i + 1} 的内容。Lorem ipsum dolor sit amet, consectetur adipiscing elit。`
786
+ }));
787
+
788
+ let currentTab = manyTabs[0];
789
+ </script>
790
+
791
+ <div class="scrollable-demo">
792
+ <h3>水平滚动标签页演示</h3>
793
+ <p>此示例展示了当标签页数量过多时如何自动滚动。</p>
794
+
795
+ <Tabs
796
+ tabs={manyTabs}
797
+ bind:activeTab={currentTab}
798
+ scrollStep={150}
799
+ style="height: 300px; width: 600px;"
800
+ >
801
+ <div class="scroll-content">
802
+ <h4>{currentTab.text}</h4>
803
+ <p>{currentTab.content}</p>
804
+ <div class="tab-info">
805
+ <p><strong>标签页 ID:</strong> {currentTab.id}</p>
806
+ <p><strong>位置:</strong> {manyTabs.indexOf(currentTab) + 1} / {manyTabs.length}</p>
807
+ </div>
808
+ </div>
809
+ </Tabs>
810
+ </div>
811
+
812
+ <style>
813
+ .scrollable-demo {
814
+ max-width: 700px;
815
+ margin: 20px auto;
816
+ padding: 20px;
817
+ }
818
+
819
+ .scrollable-demo h3 {
820
+ margin-bottom: 8px;
821
+ }
822
+
823
+ .scrollable-demo p {
824
+ margin-bottom: 20px;
825
+ color: #666;
826
+ }
827
+
828
+ .scroll-content {
829
+ padding: 20px;
830
+ background: #f8f9fa;
831
+ height: 100%;
832
+ }
833
+
834
+ .tab-info {
835
+ margin-top: 20px;
836
+ padding: 12px;
837
+ background: white;
838
+ border-radius: 4px;
839
+ border-left: 3px solid #007bff;
840
+ }
841
+
842
+ .tab-info p {
843
+ margin: 4px 0;
844
+ font-size: 14px;
845
+ }
846
+ </style>
847
+ ```
848
+
849
+ ## 功能
850
+
851
+ - **水平滚动**:标签页溢出时自动显示滚动控件
852
+ - **可关闭标签页**:支持可选的标签页关闭功能,带有确认回调
853
+ - **刷新功能**:内置刷新按钮,支持自定义处理程序
854
+ - **自定义渲染**:使用自定义组件定义标签页外观
855
+ - **平滑动画**:CSS 过渡和运动补间
856
+ - **键盘可访问性**:支持完整的键盘导航
857
+ - **响应式设计**:适配容器宽度
858
+ - **简约模式**:简洁的样式选项
859
+
860
+ ## 样式
861
+
862
+ Tabs 组件支持广泛的 CSS 自定义:
863
+
864
+ ```css
865
+ /* 标签页面板容器 */
866
+ .uniface-tab-panel {
867
+ /* 自定义样式 */
868
+ }
869
+
870
+ /* 单个标签页样式 */
871
+ .uniface-tab {
872
+ /* 标签页外观 */
873
+ }
874
+
875
+ .uniface-tab.active {
876
+ /* 激活标签页样式 */
877
+ }
878
+
879
+ /* 简约模式样式 */
880
+ .uniface-tabs-wrap.simple {
881
+ /* 简约模式覆盖样式 */
882
+ }
883
+
884
+ /* 滚动按钮 */
885
+ .scroll-left, .scroll-right {
886
+ /* 滚动控件样式 */
887
+ }
888
+ ```
889
+
890
+ ## 可访问性
891
+
892
+ - 支持 Tab 和箭头键的键盘导航
893
+ - 为屏幕阅读器提供 ARIA 属性
894
+ - 焦点管理和视觉指示器
895
+ - 语义化 HTML 结构
896
+ - 高对比度支持
897
+
898
+ ## 最佳实践
899
+
900
+ 1. **标签页管理**:保持合理的标签页数量以提升用户体验
901
+ 2. **内容加载**:使用刷新功能加载动态内容
902
+ 3. **关闭确认**:在关闭已修改的标签页前始终进行确认
903
+ 4. **自定义渲染**:使用自定义标签页组件处理复杂布局
904
+ 5. **响应式设计**:在不同屏幕尺寸上测试标签页行为
905
+ 6. **性能**:考虑为标签页内容实现懒加载
906
+
907
+ ## 浏览器支持
908
+
909
+ - 支持 CSS Grid 和 Flexbox 的现代浏览器
910
+ - 兼容 Svelte 5+
911
+ - 支持平滑动画的浏览器
912
+ - 触控友好界面
913
+ - 完整的 TypeScript 支持
914
+
915
+ ## 相关组件
916
+
917
+ - `Accordion` - 可折叠内容面板
918
+ - `Stepper` - 逐步导航
919
+ - `Breadcrumb` - 层级导航
920
+ - `Sidebar` - 侧边导航组件