@ticatec/uniface-element 0.2.3 → 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 (178) 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/DialogBoard.svelte +1 -1
  70. package/dist/dialog/README.md +596 -0
  71. package/dist/dialog/README_CN.md +596 -0
  72. package/dist/drawer/README.md +679 -1
  73. package/dist/drawer/README_CN.md +679 -0
  74. package/dist/group-box/group-check-box/GroupCheckBox.svelte +62 -5
  75. package/dist/group-box/group-check-box/GroupCheckBox.svelte.d.ts +7 -2
  76. package/dist/group-box/group-check-box/README.md +749 -0
  77. package/dist/group-box/group-check-box/README_CN.md +750 -0
  78. package/dist/group-box/group-radio-box/GroupRadioBox.svelte +69 -4
  79. package/dist/group-box/group-radio-box/GroupRadioBox.svelte.d.ts +8 -2
  80. package/dist/group-box/group-radio-box/README.md +920 -0
  81. package/dist/group-box/group-radio-box/README_CN.md +920 -0
  82. package/dist/image-files/README.md +1346 -0
  83. package/dist/image-files/README_CN.md +1346 -0
  84. package/dist/input-options-select/InputOptionsSelect.svelte +161 -65
  85. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +4 -1
  86. package/dist/lib/forwardAllEvents.d.ts +3 -0
  87. package/dist/lib/forwardAllEvents.js +24 -0
  88. package/dist/list-box/README.md +579 -0
  89. package/dist/list-box/README_CN.md +682 -0
  90. package/dist/lookup-editor/LookupEditor.svelte +15 -3
  91. package/dist/lookup-editor/LookupEditor.svelte.d.ts +3 -4
  92. package/dist/lookup-editor/README.md +684 -0
  93. package/dist/lookup-editor/README_CN.md +684 -0
  94. package/dist/memo-editor/MemoEditor.svelte +77 -27
  95. package/dist/memo-editor/MemoEditor.svelte.d.ts +6 -3
  96. package/dist/memo-editor/README.md +819 -0
  97. package/dist/memo-editor/README_CN.md +819 -0
  98. package/dist/message-box/README.md +398 -0
  99. package/dist/message-box/README_CN.md +398 -0
  100. package/dist/number-editor/NumberEditor.svelte +2 -2
  101. package/dist/number-editor/NumberEditor.svelte.d.ts +1 -1
  102. package/dist/number-editor/README.md +353 -22
  103. package/dist/number-editor/README_CN.md +357 -0
  104. package/dist/number-range/README.md +443 -0
  105. package/dist/number-range/README_CN.md +443 -0
  106. package/dist/options-multi-select/OptionsMultiSelect.svelte +87 -12
  107. package/dist/options-multi-select/OptionsMultiSelect.svelte.d.ts +3 -1
  108. package/dist/options-multi-select/README.md +480 -0
  109. package/dist/options-multi-select/README_CN.md +480 -0
  110. package/dist/options-select/OptionsSelect.svelte +36 -5
  111. package/dist/options-select/OptionsSelect.svelte.d.ts +3 -4
  112. package/dist/options-select/README.md +632 -0
  113. package/dist/options-select/README_CN.md +632 -0
  114. package/dist/page/README.md +605 -0
  115. package/dist/page/README_CN.md +605 -0
  116. package/dist/pagination/README.md +946 -0
  117. package/dist/pagination/README_CN.md +946 -0
  118. package/dist/pagination-panel/README.md +1075 -0
  119. package/dist/pagination-panel/README_CN.md +1075 -0
  120. package/dist/popup-hint/README.md +841 -0
  121. package/dist/popup-hint/README_CN.md +840 -0
  122. package/dist/progress-bar/README.md +242 -0
  123. package/dist/progress-bar/README_CN.md +242 -0
  124. package/dist/progress-step-bar/README.md +316 -0
  125. package/dist/progress-step-bar/README_CN.md +316 -0
  126. package/dist/prompts-text-editor/PromptsTextEditor.svelte +6 -3
  127. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +3 -1
  128. package/dist/prompts-text-editor/README.md +329 -0
  129. package/dist/prompts-text-editor/README_CN.md +329 -0
  130. package/dist/property-editor/README.md +969 -0
  131. package/dist/property-editor/README_CN.md +969 -0
  132. package/dist/radio-button/README.md +372 -0
  133. package/dist/radio-button/README_CN.md +372 -0
  134. package/dist/radio-button/RadioButton.svelte +32 -3
  135. package/dist/radio-button/RadioButton.svelte.d.ts +12 -1
  136. package/dist/search-box/README.md +425 -0
  137. package/dist/search-box/README_CN.md +424 -0
  138. package/dist/search-box/SearchBox.svelte +22 -6
  139. package/dist/search-box/SearchBox.svelte.d.ts +4 -1
  140. package/dist/tabs/README.md +919 -0
  141. package/dist/tabs/README_CN.md +920 -0
  142. package/dist/tag/README.md +922 -0
  143. package/dist/tag/README_CN.md +922 -0
  144. package/dist/text-editor/PasswordEditor.svelte +17 -2
  145. package/dist/text-editor/PasswordEditor.svelte.d.ts +3 -3
  146. package/dist/text-editor/PasswordEditor_README.md +551 -0
  147. package/dist/text-editor/PasswordEditor_README_CN.md +551 -0
  148. package/dist/text-editor/README.md +466 -0
  149. package/dist/text-editor/README_CN.md +466 -0
  150. package/dist/text-editor/TextEditor.svelte +51 -19
  151. package/dist/text-editor/TextEditor.svelte.d.ts +0 -1
  152. package/dist/ticatec-uniface-web.css +1 -0
  153. package/dist/time-editor/README.md +498 -24
  154. package/dist/time-editor/README_CN.md +498 -0
  155. package/dist/time-editor/TimeEditor.svelte +7 -3
  156. package/dist/time-editor/TimeEditor.svelte.d.ts +3 -1
  157. package/dist/toast/README.md +667 -0
  158. package/dist/toast/README_CN.md +667 -0
  159. package/dist/transfer/README.md +795 -0
  160. package/dist/transfer/Transfer.svelte +6 -4
  161. package/dist/transfer/Transfer.svelte.d.ts +3 -1
  162. package/dist/tree-view/README.md +761 -0
  163. package/dist/tree-view/README_CN.md +761 -0
  164. package/dist/tree-view/TreeView.svelte +5 -3
  165. package/dist/tree-view/TreeView.svelte.d.ts +3 -1
  166. package/dist/unit-number-editor/README.md +546 -20
  167. package/dist/unit-number-editor/README_CN.md +525 -0
  168. package/dist/unit-number-editor/UnitNumberEditor.svelte +62 -8
  169. package/dist/unit-number-editor/UnitNumberEditor.svelte.d.ts +5 -1
  170. package/docs/form-field/cn/README_CN.md +364 -0
  171. package/docs/form-field/en/README.md +364 -0
  172. package/docs/form-panel/flex-form/cn/README_CN.md +586 -0
  173. package/docs/form-panel/flex-form/en/README.md +586 -0
  174. package/docs/form-panel/flex-row-form/cn/README_CN.md +787 -0
  175. package/docs/form-panel/flex-row-form/en/README.md +787 -0
  176. package/docs/form-panel/grid-form/en/README.md +744 -0
  177. package/package.json +1 -1
  178. package/dist/drawer/README-CN.md +0 -1
@@ -0,0 +1,920 @@
1
+ # GroupRadioBox 组单选框组件
2
+
3
+ 一个灵活的组单选框组件,允许用户从预定义的选项列表中选择单个选项。具备全面的状态管理、自定义样式变体以及焦点/失焦事件处理,可无缝集成到表单中。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @ticatec/uniface-element
9
+ ```
10
+
11
+ ## 导入
12
+
13
+ ```typescript
14
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
15
+ import { DisplayMode } from "@ticatec/uniface-element";
16
+ import type { OnChangeHandler } from "@ticatec/uniface-element";
17
+ ```
18
+
19
+ ## 基本用法
20
+
21
+ ```svelte
22
+ <script>
23
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
24
+
25
+ const options = [
26
+ { code: "sm", text: "小号" },
27
+ { code: "md", text: "中号" },
28
+ { code: "lg", text: "大号" },
29
+ { code: "xl", text: "特大号" }
30
+ ];
31
+
32
+ let selectedSize = "md";
33
+
34
+ function handleChange(value) {
35
+ console.log('选择的尺码:', value);
36
+ }
37
+ </script>
38
+
39
+ <GroupRadioBox
40
+ {options}
41
+ bind:value={selectedSize}
42
+ onchange={handleChange}
43
+ />
44
+ ```
45
+
46
+ ## 属性
47
+
48
+ | 属性 | 类型 | 默认值 | 描述 |
49
+ |------|------|---------|-------------|
50
+ | `value` | `any` | 必需 | 选中的值 |
51
+ | `options` | `Array<any>` | 必需 | 选项对象数组 |
52
+ | `keyField` | `string` | `"code"` | 选项键/值的字段名称 |
53
+ | `textField` | `string` | `"text"` | 选项显示文本的字段名称 |
54
+ | `disabled` | `boolean` | `false` | 组件是否禁用 |
55
+ | `readonly` | `boolean` | `false` | 组件是否只读 |
56
+ | `displayMode` | `DisplayMode` | `DisplayMode.Edit` | 显示模式(编辑或查看) |
57
+ | `variant` | `"" \| "plain" \| "outlined" \| "filled"` | `""` | 视觉变体 |
58
+ | `compact` | `boolean` | `false` | 是否使用紧凑间距 |
59
+ | `disabledOptions` | `Array<string>` | `[]` | 要禁用的选项键数组 |
60
+ | `style` | `string` | `""` | 附加 CSS 样式 |
61
+ | `item$style` | `string` | `""` | 单个单选框项目的 CSS 样式 |
62
+ | `onchange` | `OnChangeHandler<any>` | `null` | 更改事件处理程序 |
63
+ | `onfocus` | `(() => void) \| null` | `null` | 焦点事件处理程序 |
64
+ | `onblur` | `(() => void) \| null` | `null` | 失焦事件处理程序 |
65
+
66
+ ## 方法
67
+
68
+ | 方法 | 描述 |
69
+ |--------|-------------|
70
+ | `setFocus()` | 以编程方式聚焦第一个启用的单选框 |
71
+
72
+ ## 示例
73
+
74
+ ### 基本选择
75
+
76
+ ```svelte
77
+ <script>
78
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
79
+ import FormField from "@ticatec/uniface-element/FormField";
80
+
81
+ const priorities = [
82
+ { code: "low", text: "低优先级" },
83
+ { code: "medium", text: "中优先级" },
84
+ { code: "high", text: "高优先级" },
85
+ { code: "urgent", text: "紧急" }
86
+ ];
87
+
88
+ let taskPriority = "medium";
89
+
90
+ function handlePriorityChange(value) {
91
+ console.log('优先级更改为:', value);
92
+
93
+ // 处理优先级特定逻辑
94
+ if (value === 'urgent') {
95
+ console.log('紧急任务 - 通知团队负责人');
96
+ }
97
+ }
98
+ </script>
99
+
100
+ <div class="demo-section">
101
+ <FormField label="任务优先级">
102
+ <GroupRadioBox
103
+ options={priorities}
104
+ bind:value={taskPriority}
105
+ onchange={handlePriorityChange}
106
+ onfocus={() => console.log('优先级字段获得焦点')}
107
+ onblur={() => console.log('优先级字段失去焦点')}
108
+ />
109
+ </FormField>
110
+
111
+ <div class="result">
112
+ <p><strong>选中的优先级:</strong> {taskPriority}</p>
113
+ <p><strong>显示文本:</strong> {priorities.find(p => p.code === taskPriority)?.text ?? '无'}</p>
114
+ </div>
115
+ </div>
116
+
117
+ <style>
118
+ .demo-section {
119
+ margin: 20px;
120
+ padding: 20px;
121
+ border: 1px solid #e2e8f0;
122
+ border-radius: 8px;
123
+ }
124
+
125
+ .result {
126
+ margin-top: 16px;
127
+ padding: 12px;
128
+ background: #f8fafc;
129
+ border-radius: 6px;
130
+ }
131
+ </style>
132
+ ```
133
+
134
+ ### 不同视觉变体
135
+
136
+ ```svelte
137
+ <script>
138
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
139
+ import FormField from "@ticatec/uniface-element/FormField";
140
+
141
+ const themes = [
142
+ { code: "light", text: "浅色主题" },
143
+ { code: "dark", text: "深色主题" },
144
+ { code: "auto", text: "自动(系统)" }
145
+ ];
146
+
147
+ let selectedTheme = "auto";
148
+ </script>
149
+
150
+ <div class="variants-demo">
151
+ <div class="variant-section">
152
+ <h3>默认变体</h3>
153
+ <FormField label="主题偏好">
154
+ <GroupRadioBox options={themes} bind:value={selectedTheme} />
155
+ </FormField>
156
+ </div>
157
+
158
+ <div class="variant-section">
159
+ <h3>轮廓变体</h3>
160
+ <FormField label="主题偏好">
161
+ <GroupRadioBox
162
+ options={themes}
163
+ variant="outlined"
164
+ bind:value={selectedTheme}
165
+ />
166
+ </FormField>
167
+ </div>
168
+
169
+ <div class="variant-section">
170
+ <h3>填充变体</h3>
171
+ <FormField label="主题偏好">
172
+ <GroupRadioBox
173
+ options={themes}
174
+ variant="filled"
175
+ bind:value={selectedTheme}
176
+ />
177
+ </FormField>
178
+ </div>
179
+
180
+ <div class="variant-section">
181
+ <h3>紧凑变体</h3>
182
+ <FormField label="主题偏好">
183
+ <GroupRadioBox
184
+ options={themes}
185
+ compact={true}
186
+ bind:value={selectedTheme}
187
+ />
188
+ </FormField>
189
+ </div>
190
+ </div>
191
+
192
+ <style>
193
+ .variants-demo {
194
+ display: grid;
195
+ grid-template-columns: 1fr 1fr;
196
+ gap: 20px;
197
+ margin: 20px;
198
+ }
199
+
200
+ .variant-section {
201
+ padding: 16px;
202
+ border: 1px solid #e2e8f0;
203
+ border-radius: 8px;
204
+ }
205
+ </style>
206
+ ```
207
+
208
+ ### 条件选项和动态行为
209
+
210
+ ```svelte
211
+ <script>
212
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
213
+ import FormField from "@ticatec/uniface-element/FormField";
214
+
215
+ const paymentMethods = [
216
+ { code: "card", text: "信用卡" },
217
+ { code: "alipay", text: "支付宝" },
218
+ { code: "weixin", text: "微信支付" },
219
+ { code: "crypto", text: "加密货币" },
220
+ { code: "cash", text: "货到付款" }
221
+ ];
222
+
223
+ let selectedPayment = "card";
224
+ let disabledOptions = [];
225
+ let orderTotal = 1500.00;
226
+ let region = "domestic";
227
+
228
+ // 根据订单条件更新可用支付方式
229
+ $: {
230
+ disabledOptions = [];
231
+
232
+ // 小额订单禁用加密货币
233
+ if (orderTotal < 1000) {
234
+ disabledOptions.push("crypto");
235
+ }
236
+
237
+ // 国际订单禁用货到付款
238
+ if (region === "international") {
239
+ disabledOptions.push("cash");
240
+ }
241
+
242
+ // 如果当前选择被禁用,自动选择可用选项
243
+ if (disabledOptions.includes(selectedPayment)) {
244
+ const availableOptions = paymentMethods.filter(method =>
245
+ !disabledOptions.includes(method.code)
246
+ );
247
+ if (availableOptions.length > 0) {
248
+ selectedPayment = availableOptions[0].code;
249
+ }
250
+ }
251
+ }
252
+
253
+ function handlePaymentChange(value) {
254
+ console.log('支付方式更改为:', value);
255
+
256
+ // 处理支付特定逻辑
257
+ if (value === 'crypto') {
258
+ console.log('选择了加密货币支付 - 显示钱包选项');
259
+ } else if (value === 'weixin') {
260
+ console.log('选择了微信支付 - 显示二维码');
261
+ }
262
+ }
263
+ </script>
264
+
265
+ <div class="conditional-demo">
266
+ <div class="controls">
267
+ <FormField label="订单总计">
268
+ <input
269
+ type="number"
270
+ bind:value={orderTotal}
271
+ min="100"
272
+ step="100"
273
+ class="number-input"
274
+ />
275
+ </FormField>
276
+
277
+ <FormField label="地区">
278
+ <select bind:value={region} class="select-input">
279
+ <option value="domestic">国内</option>
280
+ <option value="international">国际</option>
281
+ </select>
282
+ </FormField>
283
+ </div>
284
+
285
+ <FormField label="支付方式">
286
+ <GroupRadioBox
287
+ options={paymentMethods}
288
+ bind:value={selectedPayment}
289
+ {disabledOptions}
290
+ onchange={handlePaymentChange}
291
+ variant="outlined"
292
+ />
293
+ </FormField>
294
+
295
+ <div class="info-panel">
296
+ <p><strong>已选择:</strong> {selectedPayment}</p>
297
+ <p><strong>订单总计:</strong> ¥{orderTotal}</p>
298
+ <p><strong>地区:</strong> {region === 'domestic' ? '国内' : '国际'}</p>
299
+ <p><strong>禁用的支付方式:</strong> {disabledOptions.join(', ') || '无'}</p>
300
+
301
+ {#if disabledOptions.includes('crypto')}
302
+ <p class="info-note">💡 加密货币支付要求最低订单金额 ¥1000</p>
303
+ {/if}
304
+
305
+ {#if disabledOptions.includes('cash')}
306
+ <p class="info-note">💡 国际订单不可使用货到付款</p>
307
+ {/if}
308
+ </div>
309
+ </div>
310
+
311
+ <style>
312
+ .conditional-demo {
313
+ margin: 20px;
314
+ padding: 20px;
315
+ border: 1px solid #e2e8f0;
316
+ border-radius: 8px;
317
+ }
318
+
319
+ .controls {
320
+ display: grid;
321
+ grid-template-columns: 1fr 1fr;
322
+ gap: 16px;
323
+ margin-bottom: 20px;
324
+ }
325
+
326
+ .number-input, .select-input {
327
+ width: 100%;
328
+ padding: 8px 12px;
329
+ border: 1px solid #d1d5db;
330
+ border-radius: 6px;
331
+ }
332
+
333
+ .info-panel {
334
+ margin-top: 16px;
335
+ padding: 12px;
336
+ background: #f8fafc;
337
+ border-radius: 6px;
338
+ }
339
+
340
+ .info-note {
341
+ color: #6b7280;
342
+ font-style: italic;
343
+ margin-top: 8px;
344
+ }
345
+ </style>
346
+ ```
347
+
348
+ ### 自定义字段配置
349
+
350
+ ```svelte
351
+ <script>
352
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
353
+ import FormField from "@ticatec/uniface-element/FormField";
354
+
355
+ // 使用自定义字段名称
356
+ const departments = [
357
+ { id: "eng", name: "工程部", active: true },
358
+ { id: "sales", name: "销售与市场部", active: true },
359
+ { id: "hr", name: "人力资源部", active: false },
360
+ { id: "finance", name: "财务与会计部", active: true }
361
+ ];
362
+
363
+ let selectedDepartment = "eng";
364
+
365
+ function handleDepartmentChange(value) {
366
+ const selected = departments.find(dept => dept.id === value);
367
+ console.log('部门更改为:', selected);
368
+ }
369
+ </script>
370
+
371
+ <div class="custom-demo">
372
+ <FormField label="选择部门">
373
+ <GroupRadioBox
374
+ options={departments}
375
+ keyField="id"
376
+ textField="name"
377
+ bind:value={selectedDepartment}
378
+ onchange={handleDepartmentChange}
379
+ variant="filled"
380
+ style="padding: 16px; background: linear-gradient(145deg, #f8fafc, #e2e8f0);"
381
+ item$style="margin: 8px 0; padding: 6px 12px; border-radius: 8px; background: white;"
382
+ />
383
+ </FormField>
384
+
385
+ <div class="department-info">
386
+ {#each departments as dept}
387
+ {#if dept.id === selectedDepartment}
388
+ <div class="selected-dept">
389
+ <h4>{dept.name}</h4>
390
+ <p>状态: {dept.active ? '✅ 活跃' : '❌ 非活跃'}</p>
391
+ <p>部门ID: {dept.id}</p>
392
+ </div>
393
+ {/if}
394
+ {/each}
395
+ </div>
396
+ </div>
397
+
398
+ <style>
399
+ .custom-demo {
400
+ margin: 20px;
401
+ padding: 20px;
402
+ border: 1px solid #e2e8f0;
403
+ border-radius: 8px;
404
+ }
405
+
406
+ .department-info {
407
+ margin-top: 16px;
408
+ }
409
+
410
+ .selected-dept {
411
+ padding: 16px;
412
+ background: #dbeafe;
413
+ border-radius: 8px;
414
+ border-left: 4px solid #3b82f6;
415
+ }
416
+ </style>
417
+ ```
418
+
419
+ ### 只读和显示模式
420
+
421
+ ```svelte
422
+ <script>
423
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
424
+ import FormField from "@ticatec/uniface-element/FormField";
425
+ import { DisplayMode } from "@ticatec/uniface-element";
426
+
427
+ const subscriptionPlans = [
428
+ { code: "basic", text: "基础计划" },
429
+ { code: "premium", text: "高级计划" },
430
+ { code: "enterprise", text: "企业计划" }
431
+ ];
432
+
433
+ let currentPlan = "premium"; // 预选计划
434
+ </script>
435
+
436
+ <div class="readonly-demo">
437
+ <div class="mode-section">
438
+ <h3>可编辑模式</h3>
439
+ <FormField label="更改订阅计划">
440
+ <GroupRadioBox
441
+ options={subscriptionPlans}
442
+ bind:value={currentPlan}
443
+ />
444
+ </FormField>
445
+ </div>
446
+
447
+ <div class="mode-section">
448
+ <h3>只读模式</h3>
449
+ <FormField label="当前计划(只读)">
450
+ <GroupRadioBox
451
+ options={subscriptionPlans}
452
+ value={currentPlan}
453
+ readonly={true}
454
+ />
455
+ </FormField>
456
+ </div>
457
+
458
+ <div class="mode-section">
459
+ <h3>禁用模式</h3>
460
+ <FormField label="计划选择(禁用)">
461
+ <GroupRadioBox
462
+ options={subscriptionPlans}
463
+ value={currentPlan}
464
+ disabled={true}
465
+ />
466
+ </FormField>
467
+ </div>
468
+
469
+ <div class="mode-section">
470
+ <h3>仅显示模式</h3>
471
+ <FormField label="活跃计划">
472
+ <GroupRadioBox
473
+ options={subscriptionPlans}
474
+ value={currentPlan}
475
+ displayMode={DisplayMode.View}
476
+ />
477
+ </FormField>
478
+ </div>
479
+ </div>
480
+
481
+ <style>
482
+ .readonly-demo {
483
+ display: grid;
484
+ grid-template-columns: 1fr 1fr;
485
+ gap: 20px;
486
+ margin: 20px;
487
+ }
488
+
489
+ .mode-section {
490
+ padding: 16px;
491
+ border: 1px solid #e2e8f0;
492
+ border-radius: 8px;
493
+ }
494
+ </style>
495
+ ```
496
+
497
+ ### 表单集成与验证
498
+
499
+ ```svelte
500
+ <script>
501
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
502
+ import FormField from "@ticatec/uniface-element/FormField";
503
+
504
+ const shippingOptions = [
505
+ { code: "standard", text: "标准配送(5-7天)" },
506
+ { code: "express", text: "快递(2-3天)" },
507
+ { code: "overnight", text: "次日达" }
508
+ ];
509
+
510
+ const countries = [
511
+ { code: "cn", text: "中国" },
512
+ { code: "us", text: "美国" },
513
+ { code: "uk", text: "英国" },
514
+ { code: "au", text: "澳大利亚" }
515
+ ];
516
+
517
+ let formData = {
518
+ name: '',
519
+ country: '',
520
+ shipping: ''
521
+ };
522
+
523
+ let errors = {};
524
+ let groupRadioBoxRef;
525
+
526
+ function validateForm() {
527
+ errors = {};
528
+
529
+ if (!formData.name.trim()) {
530
+ errors.name = '姓名是必填项';
531
+ }
532
+
533
+ if (!formData.country) {
534
+ errors.country = '请选择一个国家';
535
+ }
536
+
537
+ if (!formData.shipping) {
538
+ errors.shipping = '请选择配送方式';
539
+ }
540
+
541
+ return Object.keys(errors).length === 0;
542
+ }
543
+
544
+ function handleSubmit() {
545
+ if (validateForm()) {
546
+ console.log('表单提交:', formData);
547
+ alert('订单提交成功!');
548
+ } else {
549
+ console.log('验证错误:', errors);
550
+ // 聚焦第一个错误字段
551
+ if (errors.shipping) {
552
+ groupRadioBoxRef.setFocus();
553
+ }
554
+ }
555
+ }
556
+
557
+ function handleShippingChange(value) {
558
+ formData.shipping = value;
559
+ // 用户选择时清除错误
560
+ if (errors.shipping && value) {
561
+ delete errors.shipping;
562
+ errors = { ...errors };
563
+ }
564
+ }
565
+
566
+ function handleCountryChange(value) {
567
+ formData.country = value;
568
+ // 更改国家时清除配送选择(可能有不同的选项)
569
+ if (formData.shipping) {
570
+ formData.shipping = '';
571
+ }
572
+ // 清除错误
573
+ if (errors.country && value) {
574
+ delete errors.country;
575
+ errors = { ...errors };
576
+ }
577
+ }
578
+ </script>
579
+
580
+ <div class="form-demo">
581
+ <form on:submit|preventDefault={handleSubmit}>
582
+ <FormField label="全名" error={errors.name}>
583
+ <input
584
+ type="text"
585
+ bind:value={formData.name}
586
+ class="form-input"
587
+ class:error={errors.name}
588
+ placeholder="输入您的全名"
589
+ />
590
+ </FormField>
591
+
592
+ <FormField label="国家" error={errors.country}>
593
+ <GroupRadioBox
594
+ options={countries}
595
+ bind:value={formData.country}
596
+ onchange={handleCountryChange}
597
+ variant="outlined"
598
+ />
599
+ </FormField>
600
+
601
+ <FormField label="配送方式" error={errors.shipping}>
602
+ <GroupRadioBox
603
+ bind:this={groupRadioBoxRef}
604
+ options={shippingOptions}
605
+ bind:value={formData.shipping}
606
+ onchange={handleShippingChange}
607
+ variant="outlined"
608
+ />
609
+ <p class="field-hint">配送费用将根据您的选择计算</p>
610
+ </FormField>
611
+
612
+ <div class="form-actions">
613
+ <button type="submit" class="submit-btn">提交订单</button>
614
+ <button type="button" on:click={() => console.log(formData)} class="preview-btn">
615
+ 预览订单
616
+ </button>
617
+ </div>
618
+
619
+ {#if formData.country && formData.shipping}
620
+ <div class="order-summary">
621
+ <h4>订单摘要</h4>
622
+ <p>配送至: {countries.find(c => c.code === formData.country)?.text}</p>
623
+ <p>配送方式: {shippingOptions.find(s => s.code === formData.shipping)?.text}</p>
624
+ </div>
625
+ {/if}
626
+ </form>
627
+ </div>
628
+
629
+ <style>
630
+ .form-demo {
631
+ max-width: 500px;
632
+ margin: 20px;
633
+ padding: 24px;
634
+ border: 1px solid #e2e8f0;
635
+ border-radius: 8px;
636
+ }
637
+
638
+ .form-input {
639
+ width: 100%;
640
+ padding: 8px 12px;
641
+ border: 1px solid #d1d5db;
642
+ border-radius: 6px;
643
+ }
644
+
645
+ .form-input.error {
646
+ border-color: #dc2626;
647
+ }
648
+
649
+ .field-hint {
650
+ margin-top: 4px;
651
+ font-size: 0.875rem;
652
+ color: #6b7280;
653
+ }
654
+
655
+ .form-actions {
656
+ display: flex;
657
+ gap: 12px;
658
+ margin-top: 20px;
659
+ }
660
+
661
+ .submit-btn, .preview-btn {
662
+ padding: 10px 20px;
663
+ border-radius: 6px;
664
+ border: none;
665
+ cursor: pointer;
666
+ }
667
+
668
+ .submit-btn {
669
+ background: #3b82f6;
670
+ color: white;
671
+ }
672
+
673
+ .preview-btn {
674
+ background: #f3f4f6;
675
+ color: #374151;
676
+ border: 1px solid #d1d5db;
677
+ }
678
+
679
+ .order-summary {
680
+ margin-top: 20px;
681
+ padding: 16px;
682
+ background: #f0f9ff;
683
+ border-radius: 8px;
684
+ border-left: 4px solid #3b82f6;
685
+ }
686
+ </style>
687
+ ```
688
+
689
+ ### 调查和评分实现
690
+
691
+ ```svelte
692
+ <script>
693
+ import GroupRadioBox from "@ticatec/uniface-element/GroupRadioBox";
694
+ import FormField from "@ticatec/uniface-element/FormField";
695
+
696
+ const satisfactionLevels = [
697
+ { code: "1", text: "非常不满意" },
698
+ { code: "2", text: "不满意" },
699
+ { code: "3", text: "中立" },
700
+ { code: "4", text: "满意" },
701
+ { code: "5", text: "非常满意" }
702
+ ];
703
+
704
+ const frequencies = [
705
+ { code: "daily", text: "每天" },
706
+ { code: "weekly", text: "每周" },
707
+ { code: "monthly", text: "每月" },
708
+ { code: "rarely", text: "很少" },
709
+ { code: "never", text: "从不" }
710
+ ];
711
+
712
+ let surveyData = {
713
+ satisfaction: '',
714
+ frequency: '',
715
+ recommendation: ''
716
+ };
717
+
718
+ let isCompleted = false;
719
+
720
+ $: isCompleted = surveyData.satisfaction && surveyData.frequency && surveyData.recommendation;
721
+
722
+ function handleSurveySubmit() {
723
+ if (isCompleted) {
724
+ console.log('调查提交:', surveyData);
725
+ alert('感谢您的反馈!');
726
+ }
727
+ }
728
+
729
+ function getSatisfactionColor(level) {
730
+ const colors = {
731
+ '1': '#dc2626', '2': '#ea580c', '3': '#d97706',
732
+ '4': '#65a30d', '5': '#16a34a'
733
+ };
734
+ return colors[level] || '#6b7280';
735
+ }
736
+ </script>
737
+
738
+ <div class="survey-demo">
739
+ <h2>客户满意度调查</h2>
740
+
741
+ <div class="survey-section">
742
+ <FormField label="您对我们的服务满意度如何?">
743
+ <GroupRadioBox
744
+ options={satisfactionLevels}
745
+ bind:value={surveyData.satisfaction}
746
+ variant="outlined"
747
+ item$style="padding: 12px; margin: 4px 0; border-radius: 8px;"
748
+ />
749
+ </FormField>
750
+
751
+ {#if surveyData.satisfaction}
752
+ <div class="satisfaction-feedback" style="color: {getSatisfactionColor(surveyData.satisfaction)}">
753
+ <strong>您选择了: {satisfactionLevels.find(s => s.code === surveyData.satisfaction)?.text}</strong>
754
+ </div>
755
+ {/if}
756
+ </div>
757
+
758
+ <div class="survey-section">
759
+ <FormField label="您使用我们服务的频率?">
760
+ <GroupRadioBox
761
+ options={frequencies}
762
+ bind:value={surveyData.frequency}
763
+ variant="filled"
764
+ compact={true}
765
+ />
766
+ </FormField>
767
+ </div>
768
+
769
+ <div class="survey-section">
770
+ <FormField label="您会向他人推荐我们吗?">
771
+ <GroupRadioBox
772
+ options={[
773
+ { code: "yes", text: "是的,绝对会" },
774
+ { code: "maybe", text: "可能会" },
775
+ { code: "no", text: "不会" }
776
+ ]}
777
+ bind:value={surveyData.recommendation}
778
+ variant="outlined"
779
+ />
780
+ </FormField>
781
+ </div>
782
+
783
+ <div class="survey-progress">
784
+ <div class="progress-bar">
785
+ <div
786
+ class="progress-fill"
787
+ style="width: {(Object.values(surveyData).filter(v => v).length / 3) * 100}%"
788
+ ></div>
789
+ </div>
790
+ <p>进度: {Object.values(surveyData).filter(v => v).length}/3 问题已完成</p>
791
+ </div>
792
+
793
+ <button
794
+ on:click={handleSurveySubmit}
795
+ disabled={!isCompleted}
796
+ class="submit-survey-btn"
797
+ class:disabled={!isCompleted}
798
+ >
799
+ 提交调查
800
+ </button>
801
+ </div>
802
+
803
+ <style>
804
+ .survey-demo {
805
+ max-width: 600px;
806
+ margin: 20px;
807
+ padding: 24px;
808
+ border: 1px solid #e2e8f0;
809
+ border-radius: 8px;
810
+ }
811
+
812
+ .survey-section {
813
+ margin-bottom: 24px;
814
+ }
815
+
816
+ .satisfaction-feedback {
817
+ margin-top: 8px;
818
+ padding: 8px 12px;
819
+ background: #f0f9ff;
820
+ border-radius: 6px;
821
+ font-weight: 500;
822
+ }
823
+
824
+ .survey-progress {
825
+ margin: 24px 0;
826
+ }
827
+
828
+ .progress-bar {
829
+ height: 8px;
830
+ background: #e5e7eb;
831
+ border-radius: 4px;
832
+ overflow: hidden;
833
+ margin-bottom: 8px;
834
+ }
835
+
836
+ .progress-fill {
837
+ height: 100%;
838
+ background: #3b82f6;
839
+ transition: width 0.3s ease;
840
+ }
841
+
842
+ .submit-survey-btn {
843
+ width: 100%;
844
+ padding: 12px 24px;
845
+ background: #3b82f6;
846
+ color: white;
847
+ border: none;
848
+ border-radius: 8px;
849
+ font-size: 16px;
850
+ cursor: pointer;
851
+ transition: all 0.2s;
852
+ }
853
+
854
+ .submit-survey-btn:hover:not(.disabled) {
855
+ background: #2563eb;
856
+ }
857
+
858
+ .submit-survey-btn.disabled {
859
+ background: #d1d5db;
860
+ color: #9ca3af;
861
+ cursor: not-allowed;
862
+ }
863
+ </style>
864
+ ```
865
+
866
+ ## 样式
867
+
868
+ GroupRadioBox 组件可通过 CSS 自定义属性进行样式化:
869
+
870
+ ```css
871
+ .uniface-group-box {
872
+ --radio-spacing: 8px;
873
+ --radio-padding: 4px 8px;
874
+ --border-color: #e2e8f0;
875
+ --background-color: #ffffff;
876
+ --hover-background: #f9fafb;
877
+ --selected-color: #3b82f6;
878
+ }
879
+
880
+ /* 变体特定样式 */
881
+ .uniface-group-box.outlined {
882
+ border: 1px solid var(--border-color);
883
+ border-radius: 6px;
884
+ padding: 12px;
885
+ }
886
+
887
+ .uniface-group-box.filled {
888
+ background-color: #f8fafc;
889
+ border-radius: 6px;
890
+ padding: 12px;
891
+ }
892
+
893
+ .uniface-group-box.compact {
894
+ --radio-spacing: 4px;
895
+ --radio-padding: 2px 4px;
896
+ }
897
+ ```
898
+
899
+ ## 可访问性
900
+
901
+ GroupRadioBox 组件包括以下可访问性功能:
902
+
903
+ - 单选框之间的键盘导航
904
+ - 使用 `setFocus()` 方法进行焦点管理
905
+ - ARIA 标签和单选框组语义
906
+ - 选择变化的屏幕阅读器提示
907
+ - 适当的 Tab 键顺序管理
908
+
909
+ ## 最佳实践
910
+
911
+ 1. **选项管理**:保持选项数组的稳定性以避免不必要的重新渲染
912
+ 2. **默认选择**:始终提供合理的默认值以提升用户体验
913
+ 3. **验证**:为必选项目实现适当的验证
914
+ 4. **用户反馈**:为选择变化提供清晰的视觉反馈
915
+ 5. **可访问性**:始终提供有意义的标签和组描述
916
+ 6. **状态管理**:适当地处理焦点/失焦事件以进行表单验证
917
+
918
+ ## 许可证
919
+
920
+ MIT