@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,538 @@
1
+ # PasswordEditor 密码编辑器组件
2
+
3
+ PasswordEditor 组件提供安全的密码输入字段,内置可见性切换功能,允许用户显示/隐藏密码内容,在保持安全性的同时提供更好的可用性。
4
+
5
+ ## 功能特性
6
+
7
+ - **安全密码输入**:带有掩码输入的标准密码字段
8
+ - **可见性切换**:眼睛图标用于显示/隐藏密码文本
9
+ - **CommonEditor 集成**:基于统一的 CommonEditor 组件构建
10
+ - **变体支持**:多种样式变体(plain、outlined、filled)
11
+ - **状态管理**:适当处理只读和禁用状态
12
+ - **事件转发**:转发标准输入事件(blur、focus)
13
+ - **紧凑模式**:可选的紧凑显示模式
14
+
15
+ ## 导入
16
+
17
+ ```typescript
18
+ import PasswordEditor from '@ticatec/uniface-element/PasswordEditor';
19
+ ```
20
+
21
+ ## 基本用法
22
+
23
+ ### 简单密码字段
24
+
25
+ ```svelte
26
+ <script>
27
+ import PasswordEditor from '@ticatec/uniface-element/PasswordEditor';
28
+
29
+ let password = '';
30
+ </script>
31
+
32
+ <PasswordEditor
33
+ bind:value={password}
34
+ placeholder="请输入密码"
35
+ />
36
+ ```
37
+
38
+ ### 样式化密码字段
39
+
40
+ ```svelte
41
+ <script>
42
+ import PasswordEditor from '@ticatec/uniface-element/PasswordEditor';
43
+
44
+ let userPassword = '';
45
+ </script>
46
+
47
+ <PasswordEditor
48
+ bind:value={userPassword}
49
+ variant="outlined"
50
+ placeholder="密码"
51
+ style="width: 300px;"
52
+ />
53
+ ```
54
+
55
+ ### 紧凑密码字段
56
+
57
+ ```svelte
58
+ <script>
59
+ import PasswordEditor from '@ticatec/uniface-element/PasswordEditor';
60
+
61
+ let pin = '';
62
+ </script>
63
+
64
+ <PasswordEditor
65
+ bind:value={pin}
66
+ compact={true}
67
+ variant="filled"
68
+ placeholder="PIN码"
69
+ />
70
+ ```
71
+
72
+ ## API 参考
73
+
74
+ ### 属性
75
+
76
+ | 属性 | 类型 | 默认值 | 描述 |
77
+ |------|------|--------|------|
78
+ | `value` | `string` | `''` | 密码值 |
79
+ | `disabled` | `boolean` | `false` | 输入框是否禁用 |
80
+ | `readonly` | `boolean` | `false` | 输入框是否只读 |
81
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | 视觉变体 |
82
+ | `compact` | `boolean` | `false` | 紧凑显示模式 |
83
+ | `style` | `string` | `''` | 附加CSS样式 |
84
+
85
+ ### 事件
86
+
87
+ - `on:blur` - 输入框失去焦点时触发
88
+ - `on:focus` - 输入框获得焦点时触发
89
+
90
+ ## 高级示例
91
+
92
+ ### 登录表单
93
+
94
+ ```svelte
95
+ <script>
96
+ import PasswordEditor from '@ticatec/uniface-element/PasswordEditor';
97
+
98
+ let credentials = {
99
+ username: '',
100
+ password: ''
101
+ };
102
+
103
+ let loginError = '';
104
+ let isLoading = false;
105
+
106
+ const handleLogin = async () => {
107
+ if (!credentials.username || !credentials.password) {
108
+ loginError = '请输入用户名和密码';
109
+ return;
110
+ }
111
+
112
+ isLoading = true;
113
+ loginError = '';
114
+
115
+ try {
116
+ // 模拟登录 API 调用
117
+ await new Promise(resolve => setTimeout(resolve, 1000));
118
+
119
+ // 模拟成功登录
120
+ if (credentials.username === 'admin' && credentials.password === 'password123') {
121
+ alert('登录成功!');
122
+ credentials = { username: '', password: '' };
123
+ } else {
124
+ loginError = '用户名或密码错误';
125
+ }
126
+ } catch (error) {
127
+ loginError = '登录失败,请重试';
128
+ } finally {
129
+ isLoading = false;
130
+ }
131
+ };
132
+
133
+ const handleKeyDown = (event) => {
134
+ if (event.key === 'Enter' && !isLoading) {
135
+ handleLogin();
136
+ }
137
+ };
138
+ </script>
139
+
140
+ <div class="login-form" style="max-width: 400px; margin: 50px auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px;">
141
+ <h2 style="text-align: center; margin-bottom: 30px;">登录</h2>
142
+
143
+ <div class="form-field" style="margin-bottom: 20px;">
144
+ <label for="username" style="display: block; margin-bottom: 5px; font-weight: bold;">用户名</label>
145
+ <input
146
+ id="username"
147
+ type="text"
148
+ bind:value={credentials.username}
149
+ placeholder="请输入用户名"
150
+ disabled={isLoading}
151
+ on:keydown={handleKeyDown}
152
+ style="width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 4px;"
153
+ />
154
+ </div>
155
+
156
+ <div class="form-field" style="margin-bottom: 20px;">
157
+ <label for="password" style="display: block; margin-bottom: 5px; font-weight: bold;">密码</label>
158
+ <PasswordEditor
159
+ bind:value={credentials.password}
160
+ variant="outlined"
161
+ disabled={isLoading}
162
+ placeholder="请输入密码"
163
+ style="width: 100%;"
164
+ on:keydown={handleKeyDown}
165
+ />
166
+ </div>
167
+
168
+ {#if loginError}
169
+ <div class="error-message" style="color: #d32f2f; margin-bottom: 15px; font-size: 0.875em;">
170
+ {loginError}
171
+ </div>
172
+ {/if}
173
+
174
+ <button
175
+ on:click={handleLogin}
176
+ disabled={isLoading}
177
+ style="width: 100%; padding: 12px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: {isLoading ? 'not-allowed' : 'pointer'};"
178
+ >
179
+ {isLoading ? '登录中...' : '登录'}
180
+ </button>
181
+ </div>
182
+ ```
183
+
184
+ ### 密码修改表单
185
+
186
+ ```svelte
187
+ <script>
188
+ import PasswordEditor from '@ticatec/uniface-element/PasswordEditor';
189
+
190
+ let passwordForm = {
191
+ currentPassword: '',
192
+ newPassword: '',
193
+ confirmPassword: ''
194
+ };
195
+
196
+ let errors = {};
197
+ let showSuccess = false;
198
+
199
+ const validatePassword = (password) => {
200
+ if (password.length < 8) return '密码长度至少需要8个字符';
201
+ if (!/(?=.*[a-z])/.test(password)) return '密码必须包含至少一个小写字母';
202
+ if (!/(?=.*[A-Z])/.test(password)) return '密码必须包含至少一个大写字母';
203
+ if (!/(?=.*\d)/.test(password)) return '密码必须包含至少一个数字';
204
+ if (!/(?=.*[@$!%*?&])/.test(password)) return '密码必须包含至少一个特殊字符';
205
+ return '';
206
+ };
207
+
208
+ const validateForm = () => {
209
+ errors = {};
210
+
211
+ if (!passwordForm.currentPassword) {
212
+ errors.currentPassword = '当前密码是必填项';
213
+ }
214
+
215
+ if (!passwordForm.newPassword) {
216
+ errors.newPassword = '新密码是必填项';
217
+ } else {
218
+ const passwordError = validatePassword(passwordForm.newPassword);
219
+ if (passwordError) errors.newPassword = passwordError;
220
+ }
221
+
222
+ if (!passwordForm.confirmPassword) {
223
+ errors.confirmPassword = '密码确认是必填项';
224
+ } else if (passwordForm.newPassword !== passwordForm.confirmPassword) {
225
+ errors.confirmPassword = '密码不匹配';
226
+ }
227
+
228
+ return Object.keys(errors).length === 0;
229
+ };
230
+
231
+ const handleSubmit = () => {
232
+ if (validateForm()) {
233
+ // 模拟 API 调用
234
+ setTimeout(() => {
235
+ showSuccess = true;
236
+ passwordForm = { currentPassword: '', newPassword: '', confirmPassword: '' };
237
+ setTimeout(() => showSuccess = false, 3000);
238
+ }, 500);
239
+ }
240
+ };
241
+
242
+ const handleFieldBlur = (field) => () => {
243
+ if (field === 'newPassword' && passwordForm.newPassword) {
244
+ const error = validatePassword(passwordForm.newPassword);
245
+ if (error) errors.newPassword = error;
246
+ else delete errors.newPassword;
247
+ errors = {...errors};
248
+ }
249
+
250
+ if (field === 'confirmPassword' && passwordForm.confirmPassword && passwordForm.newPassword) {
251
+ if (passwordForm.newPassword !== passwordForm.confirmPassword) {
252
+ errors.confirmPassword = '密码不匹配';
253
+ } else {
254
+ delete errors.confirmPassword;
255
+ }
256
+ errors = {...errors};
257
+ }
258
+ };
259
+ </script>
260
+
261
+ <div class="password-change-form" style="max-width: 500px; margin: 50px auto; padding: 30px; border: 1px solid #e0e0e0; border-radius: 8px; background: #fafafa;">
262
+ <h2 style="text-align: center; margin-bottom: 30px; color: #333;">修改密码</h2>
263
+
264
+ {#if showSuccess}
265
+ <div class="success-message" style="background: #d4edda; color: #155724; padding: 10px; border-radius: 4px; margin-bottom: 20px; text-align: center;">
266
+ 密码修改成功!
267
+ </div>
268
+ {/if}
269
+
270
+ <div class="form-field" style="margin-bottom: 25px;">
271
+ <label style="display: block; margin-bottom: 8px; font-weight: 600; color: #555;">当前密码</label>
272
+ <PasswordEditor
273
+ bind:value={passwordForm.currentPassword}
274
+ variant="outlined"
275
+ placeholder="请输入当前密码"
276
+ style="width: 100%;"
277
+ />
278
+ {#if errors.currentPassword}
279
+ <div class="field-error" style="color: #d32f2f; font-size: 0.875em; margin-top: 5px;">
280
+ {errors.currentPassword}
281
+ </div>
282
+ {/if}
283
+ </div>
284
+
285
+ <div class="form-field" style="margin-bottom: 25px;">
286
+ <label style="display: block; margin-bottom: 8px; font-weight: 600; color: #555;">新密码</label>
287
+ <PasswordEditor
288
+ bind:value={passwordForm.newPassword}
289
+ variant="outlined"
290
+ placeholder="请输入新密码"
291
+ style="width: 100%;"
292
+ on:blur={handleFieldBlur('newPassword')}
293
+ />
294
+ {#if errors.newPassword}
295
+ <div class="field-error" style="color: #d32f2f; font-size: 0.875em; margin-top: 5px;">
296
+ {errors.newPassword}
297
+ </div>
298
+ {:else if passwordForm.newPassword}
299
+ <div class="password-requirements" style="font-size: 0.75em; color: #666; margin-top: 5px;">
300
+ 密码要求:8个以上字符,包含大写字母、小写字母、数字、特殊字符
301
+ </div>
302
+ {/if}
303
+ </div>
304
+
305
+ <div class="form-field" style="margin-bottom: 30px;">
306
+ <label style="display: block; margin-bottom: 8px; font-weight: 600; color: #555;">确认新密码</label>
307
+ <PasswordEditor
308
+ bind:value={passwordForm.confirmPassword}
309
+ variant="outlined"
310
+ placeholder="请确认新密码"
311
+ style="width: 100%;"
312
+ on:blur={handleFieldBlur('confirmPassword')}
313
+ />
314
+ {#if errors.confirmPassword}
315
+ <div class="field-error" style="color: #d32f2f; font-size: 0.875em; margin-top: 5px;">
316
+ {errors.confirmPassword}
317
+ </div>
318
+ {/if}
319
+ </div>
320
+
321
+ <div class="form-actions" style="display: flex; gap: 10px;">
322
+ <button
323
+ type="button"
324
+ on:click={() => passwordForm = { currentPassword: '', newPassword: '', confirmPassword: '' }}
325
+ style="flex: 1; padding: 12px; background: #f5f5f5; color: #333; border: 1px solid #ddd; border-radius: 4px; cursor: pointer;"
326
+ >
327
+ 取消
328
+ </button>
329
+ <button
330
+ type="button"
331
+ on:click={handleSubmit}
332
+ style="flex: 2; padding: 12px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer;"
333
+ >
334
+ 修改密码
335
+ </button>
336
+ </div>
337
+ </div>
338
+ ```
339
+
340
+ ### 注册表单密码确认
341
+
342
+ ```svelte
343
+ <script>
344
+ import PasswordEditor from '@ticatec/uniface-element/PasswordEditor';
345
+
346
+ let registrationForm = {
347
+ email: '',
348
+ password: '',
349
+ confirmPassword: '',
350
+ acceptTerms: false
351
+ };
352
+
353
+ let fieldErrors = {};
354
+ let passwordStrength = '';
355
+
356
+ $: {
357
+ // 实时密码强度计算
358
+ if (registrationForm.password) {
359
+ let strength = 0;
360
+ if (registrationForm.password.length >= 8) strength++;
361
+ if (/[A-Z]/.test(registrationForm.password)) strength++;
362
+ if (/[a-z]/.test(registrationForm.password)) strength++;
363
+ if (/\d/.test(registrationForm.password)) strength++;
364
+ if (/[@$!%*?&]/.test(registrationForm.password)) strength++;
365
+
366
+ switch (strength) {
367
+ case 0:
368
+ case 1: passwordStrength = '非常弱'; break;
369
+ case 2: passwordStrength = '弱'; break;
370
+ case 3: passwordStrength = '一般'; break;
371
+ case 4: passwordStrength = '良好'; break;
372
+ case 5: passwordStrength = '强'; break;
373
+ }
374
+ } else {
375
+ passwordStrength = '';
376
+ }
377
+ }
378
+
379
+ const getStrengthColor = (strength) => {
380
+ switch (strength) {
381
+ case '非常弱': return '#d32f2f';
382
+ case '弱': return '#f57c00';
383
+ case '一般': return '#fbc02d';
384
+ case '良好': return '#388e3c';
385
+ case '强': return '#1976d2';
386
+ default: return '#666';
387
+ }
388
+ };
389
+
390
+ const validateEmail = (email) => {
391
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
392
+ return emailRegex.test(email);
393
+ };
394
+
395
+ const handleSubmit = () => {
396
+ fieldErrors = {};
397
+
398
+ if (!registrationForm.email) {
399
+ fieldErrors.email = '邮箱是必填项';
400
+ } else if (!validateEmail(registrationForm.email)) {
401
+ fieldErrors.email = '请输入有效的邮箱地址';
402
+ }
403
+
404
+ if (!registrationForm.password) {
405
+ fieldErrors.password = '密码是必填项';
406
+ } else if (passwordStrength === '非常弱' || passwordStrength === '弱') {
407
+ fieldErrors.password = '密码强度太弱';
408
+ }
409
+
410
+ if (!registrationForm.confirmPassword) {
411
+ fieldErrors.confirmPassword = '密码确认是必填项';
412
+ } else if (registrationForm.password !== registrationForm.confirmPassword) {
413
+ fieldErrors.confirmPassword = '密码不匹配';
414
+ }
415
+
416
+ if (!registrationForm.acceptTerms) {
417
+ fieldErrors.terms = '您必须同意条款和条件';
418
+ }
419
+
420
+ if (Object.keys(fieldErrors).length === 0) {
421
+ alert('注册成功!');
422
+ registrationForm = { email: '', password: '', confirmPassword: '', acceptTerms: false };
423
+ }
424
+
425
+ fieldErrors = {...fieldErrors};
426
+ };
427
+ </script>
428
+
429
+ <div class="registration-form" style="max-width: 450px; margin: 50px auto; padding: 30px; border: 1px solid #e0e0e0; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
430
+ <h2 style="text-align: center; margin-bottom: 30px; color: #1976d2;">创建账户</h2>
431
+
432
+ <div class="form-field" style="margin-bottom: 20px;">
433
+ <label style="display: block; margin-bottom: 8px; font-weight: 600;">邮箱地址</label>
434
+ <input
435
+ type="email"
436
+ bind:value={registrationForm.email}
437
+ placeholder="your.email@example.com"
438
+ style="width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px;"
439
+ class:error={fieldErrors.email}
440
+ />
441
+ {#if fieldErrors.email}
442
+ <div class="error" style="color: #d32f2f; font-size: 0.875em; margin-top: 4px;">
443
+ {fieldErrors.email}
444
+ </div>
445
+ {/if}
446
+ </div>
447
+
448
+ <div class="form-field" style="margin-bottom: 20px;">
449
+ <label style="display: block; margin-bottom: 8px; font-weight: 600;">密码</label>
450
+ <PasswordEditor
451
+ bind:value={registrationForm.password}
452
+ variant="outlined"
453
+ placeholder="创建强密码"
454
+ style="width: 100%;"
455
+ />
456
+ {#if passwordStrength}
457
+ <div class="password-strength" style="margin-top: 5px; font-size: 0.875em;">
458
+ 强度: <span style="color: {getStrengthColor(passwordStrength)}; font-weight: bold;">{passwordStrength}</span>
459
+ </div>
460
+ {/if}
461
+ {#if fieldErrors.password}
462
+ <div class="error" style="color: #d32f2f; font-size: 0.875em; margin-top: 4px;">
463
+ {fieldErrors.password}
464
+ </div>
465
+ {/if}
466
+ </div>
467
+
468
+ <div class="form-field" style="margin-bottom: 25px;">
469
+ <label style="display: block; margin-bottom: 8px; font-weight: 600;">确认密码</label>
470
+ <PasswordEditor
471
+ bind:value={registrationForm.confirmPassword}
472
+ variant="outlined"
473
+ placeholder="确认您的密码"
474
+ style="width: 100%;"
475
+ />
476
+ {#if fieldErrors.confirmPassword}
477
+ <div class="error" style="color: #d32f2f; font-size: 0.875em; margin-top: 4px;">
478
+ {fieldErrors.confirmPassword}
479
+ </div>
480
+ {/if}
481
+ </div>
482
+
483
+ <div class="form-field" style="margin-bottom: 25px;">
484
+ <label style="display: flex; align-items: center; font-size: 0.9em; color: #555;">
485
+ <input
486
+ type="checkbox"
487
+ bind:checked={registrationForm.acceptTerms}
488
+ style="margin-right: 8px;"
489
+ />
490
+ 我同意 <a href="#" style="color: #1976d2; text-decoration: none;">条款和条件</a>
491
+ </label>
492
+ {#if fieldErrors.terms}
493
+ <div class="error" style="color: #d32f2f; font-size: 0.875em; margin-top: 4px;">
494
+ {fieldErrors.terms}
495
+ </div>
496
+ {/if}
497
+ </div>
498
+
499
+ <button
500
+ type="button"
501
+ on:click={handleSubmit}
502
+ style="width: 100%; padding: 14px; background: #1976d2; color: white; border: none; border-radius: 6px; font-size: 16px; font-weight: 600; cursor: pointer;"
503
+ >
504
+ 创建账户
505
+ </button>
506
+ </div>
507
+ ```
508
+
509
+ ## 最佳实践
510
+
511
+ 1. **安全第一**:永远不要以明文形式存储或传输密码
512
+ 2. **可见性切换**:眼睛图标帮助用户验证密码输入
513
+ 3. **验证**:实施适当的密码强度验证
514
+ 4. **无障碍访问**:提供清晰的标签和适当的ARIA属性
515
+ 5. **确认字段**:在注册表单中始终包含密码确认
516
+ 6. **只读状态**:适当处理只读状态,防止在不可编辑时切换
517
+ 7. **表单集成**:与适当的表单验证和提交处理一起使用
518
+
519
+ ## 样式说明
520
+
521
+ - 组件继承 CommonEditor 的样式
522
+ - 眼睛图标根据当前可见性状态变化(眼睛/眼睛关闭)
523
+ - 支持所有 CommonEditor 变体和样式选项
524
+ - 自定义样式可以通过`style`属性应用
525
+
526
+ ## 安全注意事项
527
+
528
+ - 密码掩码自动处理
529
+ - 只读模式下禁用可见性切换
530
+ - 组件不存储密码历史或实现自动完成
531
+ - 生产环境中使用HTTPS进行安全传输
532
+
533
+ ## 无障碍访问功能
534
+
535
+ - 在"password"和"text"输入类型之间适当切换
536
+ - 可见性切换期间保持焦点管理
537
+ - 与标准输入行为兼容的屏幕阅读器
538
+ - 交互元素的清晰视觉指示器