@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,409 @@
1
+ # MemoEditor 备忘录编辑器组件
2
+
3
+ MemoEditor 组件提供多行文本输入,具有字符计数、调整大小选项和显示模式支持等高级功能,适用于较长的文本内容。
4
+
5
+ ## 功能特性
6
+
7
+ - **多行文本输入**:基于textarea的长文本内容输入
8
+ - **字符计数**:可选的字符限制和计数器显示
9
+ - **可调整大小输入**:可配置的调整大小行为(无、水平、垂直、双向)
10
+ - **显示模式**:编辑和查看模式,支持HTML渲染
11
+ - **文本换行**:可配置的文本换行行为
12
+ - **清除功能**:内置带图标的清除按钮
13
+ - **变体支持**:多种样式变体(plain、outlined、filled)
14
+ - **HTML转义**:查看模式下的安全HTML渲染
15
+
16
+ ## 导入
17
+
18
+ ```typescript
19
+ import MemoEditor from '@ticatec/uniface-element/MemoEditor';
20
+ ```
21
+
22
+ ## 基本用法
23
+
24
+ ### 简单备忘录编辑器
25
+
26
+ ```svelte
27
+ <script>
28
+ import MemoEditor from '@ticatec/uniface-element/MemoEditor';
29
+
30
+ let content = '';
31
+ </script>
32
+
33
+ <MemoEditor
34
+ bind:value={content}
35
+ input$rows={4}
36
+ placeholder="输入您的备忘录..."
37
+ />
38
+ ```
39
+
40
+ ### 带字符限制和计数器
41
+
42
+ ```svelte
43
+ <script>
44
+ import MemoEditor from '@ticatec/uniface-element/MemoEditor';
45
+
46
+ let message = '';
47
+ </script>
48
+
49
+ <MemoEditor
50
+ bind:value={message}
51
+ maxLength={500}
52
+ showIndicator={true}
53
+ input$rows={5}
54
+ placeholder="写下您的消息(最多500个字符)..."
55
+ />
56
+ ```
57
+
58
+ ### 可调整大小的编辑器
59
+
60
+ ```svelte
61
+ <script>
62
+ import MemoEditor from '@ticatec/uniface-element/MemoEditor';
63
+
64
+ let notes = '';
65
+ </script>
66
+
67
+ <MemoEditor
68
+ bind:value={notes}
69
+ resize="both"
70
+ input$rows={6}
71
+ variant="outlined"
72
+ placeholder="可调整大小的笔记编辑器..."
73
+ />
74
+ ```
75
+
76
+ ## API 参考
77
+
78
+ ### 属性
79
+
80
+ | 属性 | 类型 | 默认值 | 描述 |
81
+ |------|------|--------|------|
82
+ | `value` | `string` | 必需 | 文本内容 |
83
+ | `disabled` | `boolean` | `false` | 编辑器是否禁用 |
84
+ | `readonly` | `boolean` | `false` | 编辑器是否只读 |
85
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | 视觉变体 |
86
+ | `style` | `string` | `''` | 附加CSS样式 |
87
+ | `wrap` | `'hard' \| 'soft'` | `'hard'` | 文本换行行为 |
88
+ | `resize` | `'none' \| 'horizontal' \| 'vertical' \| 'both'` | `'none'` | 调整大小功能 |
89
+ | `displayMode` | `DisplayMode` | `DisplayMode.Edit` | 显示模式(编辑/查看) |
90
+ | `input$rows` | `number` | `3` | 可见文本行数 |
91
+ | `showIndicator` | `boolean` | `false` | 显示字符计数器 |
92
+ | `maxLength` | `number` | `null` | 最大字符限制 |
93
+
94
+ ### DisplayMode 枚举
95
+
96
+ ```typescript
97
+ enum DisplayMode {
98
+ Edit = 'edit', // 编辑模式
99
+ View = 'view' // 查看模式
100
+ }
101
+ ```
102
+
103
+ ## 高级示例
104
+
105
+ ### 评论系统
106
+
107
+ ```svelte
108
+ <script>
109
+ import MemoEditor, { DisplayMode } from '@ticatec/uniface-element/MemoEditor';
110
+
111
+ let comment = '';
112
+ let isEditing = true;
113
+ let savedComments = [];
114
+
115
+ const saveComment = () => {
116
+ if (comment.trim()) {
117
+ savedComments = [...savedComments, {
118
+ id: Date.now(),
119
+ content: comment,
120
+ timestamp: new Date().toLocaleString()
121
+ }];
122
+ comment = '';
123
+ }
124
+ };
125
+
126
+ const editComment = (commentObj) => {
127
+ comment = commentObj.content;
128
+ isEditing = true;
129
+ };
130
+ </script>
131
+
132
+ <div class="comment-system">
133
+ <div class="comment-input">
134
+ <MemoEditor
135
+ bind:value={comment}
136
+ maxLength={1000}
137
+ showIndicator={true}
138
+ input$rows={4}
139
+ variant="outlined"
140
+ resize="vertical"
141
+ placeholder="写下您的评论..."
142
+ style="margin-bottom: 10px;"
143
+ />
144
+ <button on:click={saveComment} disabled={!comment.trim()}>
145
+ 发表评论
146
+ </button>
147
+ </div>
148
+
149
+ <div class="comment-list">
150
+ {#each savedComments as commentObj (commentObj.id)}
151
+ <div class="comment-item" style="border: 1px solid #ddd; padding: 10px; margin: 5px 0;">
152
+ <MemoEditor
153
+ value={commentObj.content}
154
+ displayMode={DisplayMode.View}
155
+ style="border: none; background: transparent;"
156
+ />
157
+ <div class="comment-meta" style="font-size: 0.8em; color: #666; margin-top: 5px;">
158
+ {commentObj.timestamp}
159
+ <button on:click={() => editComment(commentObj)}>编辑</button>
160
+ </div>
161
+ </div>
162
+ {/each}
163
+ </div>
164
+ </div>
165
+ ```
166
+
167
+ ### 富文本笔记系统
168
+
169
+ ```svelte
170
+ <script>
171
+ import MemoEditor, { DisplayMode } from '@ticatec/uniface-element/MemoEditor';
172
+
173
+ let notes = {};
174
+ let currentNoteId = null;
175
+ let currentContent = '';
176
+ let isPreviewMode = false;
177
+
178
+ const createNote = () => {
179
+ const id = Date.now();
180
+ notes[id] = {
181
+ title: `笔记 ${Object.keys(notes).length + 1}`,
182
+ content: '',
183
+ lastModified: new Date()
184
+ };
185
+ currentNoteId = id;
186
+ currentContent = '';
187
+ isPreviewMode = false;
188
+ };
189
+
190
+ const selectNote = (id) => {
191
+ if (currentNoteId && notes[currentNoteId]) {
192
+ notes[currentNoteId].content = currentContent;
193
+ notes[currentNoteId].lastModified = new Date();
194
+ }
195
+ currentNoteId = id;
196
+ currentContent = notes[id].content;
197
+ isPreviewMode = false;
198
+ };
199
+
200
+ const saveCurrentNote = () => {
201
+ if (currentNoteId && notes[currentNoteId]) {
202
+ notes[currentNoteId].content = currentContent;
203
+ notes[currentNoteId].lastModified = new Date();
204
+ }
205
+ };
206
+
207
+ const togglePreview = () => {
208
+ saveCurrentNote();
209
+ isPreviewMode = !isPreviewMode;
210
+ };
211
+ </script>
212
+
213
+ <div class="note-app" style="display: flex; height: 400px;">
214
+ <div class="note-list" style="width: 200px; border-right: 1px solid #ddd; padding: 10px;">
215
+ <button on:click={createNote} style="width: 100%; margin-bottom: 10px;">
216
+ 新建笔记
217
+ </button>
218
+ {#each Object.entries(notes) as [id, note] (id)}
219
+ <div
220
+ class="note-item"
221
+ class:active={currentNoteId == id}
222
+ style="padding: 8px; margin: 2px 0; cursor: pointer; background: {currentNoteId == id ? '#e3f2fd' : 'transparent'};"
223
+ on:click={() => selectNote(id)}
224
+ >
225
+ <div style="font-weight: bold; font-size: 0.9em;">{note.title}</div>
226
+ <div style="font-size: 0.7em; color: #666;">{note.lastModified.toLocaleDateString()}</div>
227
+ </div>
228
+ {/each}
229
+ </div>
230
+
231
+ <div class="note-editor" style="flex: 1; display: flex; flex-direction: column;">
232
+ {#if currentNoteId}
233
+ <div class="editor-toolbar" style="padding: 10px; border-bottom: 1px solid #ddd;">
234
+ <button on:click={togglePreview}>
235
+ {isPreviewMode ? '编辑' : '预览'}
236
+ </button>
237
+ <button on:click={saveCurrentNote}>保存</button>
238
+ </div>
239
+
240
+ <div class="editor-content" style="flex: 1; padding: 10px;">
241
+ <MemoEditor
242
+ bind:value={currentContent}
243
+ displayMode={isPreviewMode ? DisplayMode.View : DisplayMode.Edit}
244
+ resize="none"
245
+ input$rows={15}
246
+ maxLength={10000}
247
+ showIndicator={!isPreviewMode}
248
+ style="height: 100%; border: none;"
249
+ placeholder="开始写您的笔记..."
250
+ />
251
+ </div>
252
+ {:else}
253
+ <div class="no-note" style="flex: 1; display: flex; align-items: center; justify-content: center; color: #666;">
254
+ 选择一个笔记或创建新笔记
255
+ </div>
256
+ {/if}
257
+ </div>
258
+ </div>
259
+ ```
260
+
261
+ ### 带验证的表单
262
+
263
+ ```svelte
264
+ <script>
265
+ import MemoEditor from '@ticatec/uniface-element/MemoEditor';
266
+
267
+ let formData = {
268
+ description: '',
269
+ feedback: '',
270
+ requirements: ''
271
+ };
272
+
273
+ let errors = {};
274
+
275
+ const validateField = (field, value) => {
276
+ switch (field) {
277
+ case 'description':
278
+ return value.trim().length >= 10 ? '' : '描述至少需要10个字符';
279
+ case 'feedback':
280
+ return value.trim().length >= 5 ? '' : '反馈至少需要5个字符';
281
+ case 'requirements':
282
+ return value.trim().length > 0 ? '' : '需求是必填项';
283
+ default:
284
+ return '';
285
+ }
286
+ };
287
+
288
+ const handleFieldChange = (field) => (event) => {
289
+ const value = event.target.value;
290
+ formData[field] = value;
291
+ errors[field] = validateField(field, value);
292
+ };
293
+
294
+ const submitForm = () => {
295
+ // 验证所有字段
296
+ Object.keys(formData).forEach(field => {
297
+ errors[field] = validateField(field, formData[field]);
298
+ });
299
+
300
+ const hasErrors = Object.values(errors).some(error => error !== '');
301
+
302
+ if (!hasErrors) {
303
+ console.log('表单提交:', formData);
304
+ alert('表单提交成功!');
305
+ }
306
+ };
307
+ </script>
308
+
309
+ <form class="validated-form" style="max-width: 600px; margin: 0 auto;">
310
+ <div class="field-group" style="margin-bottom: 20px;">
311
+ <label for="description" style="display: block; margin-bottom: 5px; font-weight: bold;">
312
+ 项目描述 *
313
+ </label>
314
+ <MemoEditor
315
+ bind:value={formData.description}
316
+ input$rows={4}
317
+ maxLength={500}
318
+ showIndicator={true}
319
+ variant="outlined"
320
+ resize="vertical"
321
+ placeholder="描述您的项目..."
322
+ on:input={handleFieldChange('description')}
323
+ />
324
+ {#if errors.description}
325
+ <div class="error" style="color: #d32f2f; font-size: 0.875em; margin-top: 4px;">
326
+ {errors.description}
327
+ </div>
328
+ {/if}
329
+ </div>
330
+
331
+ <div class="field-group" style="margin-bottom: 20px;">
332
+ <label for="feedback" style="display: block; margin-bottom: 5px; font-weight: bold;">
333
+ 附加反馈
334
+ </label>
335
+ <MemoEditor
336
+ bind:value={formData.feedback}
337
+ input$rows={3}
338
+ maxLength={300}
339
+ showIndicator={true}
340
+ variant="filled"
341
+ placeholder="任何额外的反馈..."
342
+ on:input={handleFieldChange('feedback')}
343
+ />
344
+ {#if errors.feedback}
345
+ <div class="error" style="color: #d32f2f; font-size: 0.875em; margin-top: 4px;">
346
+ {errors.feedback}
347
+ </div>
348
+ {/if}
349
+ </div>
350
+
351
+ <div class="field-group" style="margin-bottom: 20px;">
352
+ <label for="requirements" style="display: block; margin-bottom: 5px; font-weight: bold;">
353
+ 需求 *
354
+ </label>
355
+ <MemoEditor
356
+ bind:value={formData.requirements}
357
+ input$rows={5}
358
+ variant="outlined"
359
+ resize="both"
360
+ placeholder="列出您的需求..."
361
+ on:input={handleFieldChange('requirements')}
362
+ />
363
+ {#if errors.requirements}
364
+ <div class="error" style="color: #d32f2f; font-size: 0.875em; margin-top: 4px;">
365
+ {errors.requirements}
366
+ </div>
367
+ {/if}
368
+ </div>
369
+
370
+ <button type="button" on:click={submitForm} style="padding: 10px 20px; background: #1976d2; color: white; border: none; border-radius: 4px;">
371
+ 提交表单
372
+ </button>
373
+ </form>
374
+ ```
375
+
376
+ ## 最佳实践
377
+
378
+ 1. **字符限制**:为用户指导和数据约束设置适当的`maxLength`
379
+ 2. **视觉反馈**:在字符限制时使用`showIndicator`以获得更好的用户体验
380
+ 3. **无障碍访问**:提供清晰的标签和占位符文本
381
+ 4. **调整大小行为**:根据布局约束选择适当的调整大小选项
382
+ 5. **验证**:实现带有清晰错误消息的客户端验证
383
+ 6. **性能**:考虑对实时验证或自动保存功能进行防抖处理
384
+ 7. **内容安全**:组件在查看模式下自动转义HTML
385
+
386
+ ## 样式说明
387
+
388
+ - 组件支持标准变体样式(plain、outlined、filled)
389
+ - 自定义样式可以通过`style`属性应用
390
+ - 启用时字符计数器出现在右下角
391
+ - 当有内容且未禁用时出现清除按钮
392
+
393
+ ## 事件
394
+
395
+ 组件转发标准的textarea事件:
396
+ - `on:blur`
397
+ - `on:focus`
398
+ - `on:keydown`
399
+ - `on:keyup`
400
+ - `on:keypress`
401
+ - `on:change`
402
+ - `on:input`
403
+
404
+ ## 无障碍访问注意事项
405
+
406
+ - textarea元素的适当焦点管理
407
+ - 字符限制信息以可视方式呈现
408
+ - 清除按钮提供替代内容清除方法
409
+ - 查看模式下HTML内容安全转义
@@ -0,0 +1,261 @@
1
+ # NumberEditor 组件
2
+
3
+ 专用于数字输入的组件,支持整数和浮点数。
4
+
5
+ ## 属性
6
+
7
+ | 属性 | 类型 | 默认值 | 描述 |
8
+ |------|------|--------|------|
9
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | 外观变体 |
10
+ | `disabled` | `boolean` | `false` | 是否禁用 |
11
+ | `readonly` | `boolean` | `false` | 是否只读 |
12
+ | `compact` | `boolean` | `false` | 是否紧凑模式 |
13
+ | `value` | `number \| null` | `null` | 数值 |
14
+ | `placeholder` | `string` | `''` | 占位符文本 |
15
+ | `precision` | `number \| null` | `null` | 小数位数 |
16
+ | `suffix` | `string` | `''` | 文本后缀 |
17
+ | `prefix` | `string` | `''` | 文本前缀 |
18
+ | `allowNegative` | `boolean` | `false` | 允许负数 |
19
+ | `displayMode` | `DisplayMode` | `DisplayMode.Edit` | 显示模式 |
20
+ | `max` | `number \| null` | `null` | 最大值 |
21
+ | `min` | `number \| null` | `null` | 最小值 |
22
+ | `removable` | `boolean` | `true` | 显示清除按钮 |
23
+ | `style` | `string` | `''` | 自定义样式 |
24
+ | `onChange` | `OnChangeHandler<number \| null>` | - | 值变化回调 |
25
+
26
+ ## 使用示例
27
+
28
+ ```svelte
29
+ <script lang="ts">
30
+ import NumberEditor from '@ticatec/uniface-element/NumberEditor';
31
+
32
+ let price: number | null = null;
33
+ let quantity: number | null = 1;
34
+ let rating: number | null = null;
35
+
36
+ const handlePriceChange = (value: number | null) => {
37
+ price = value;
38
+ console.log('价格:', value);
39
+ };
40
+
41
+ const handleQuantityChange = (value: number | null) => {
42
+ quantity = value;
43
+ console.log('数量:', value);
44
+ };
45
+
46
+ const handleRatingChange = (value: number | null) => {
47
+ rating = value;
48
+ console.log('评分:', value);
49
+ };
50
+ </script>
51
+
52
+ <!-- 带前缀的价格输入 -->
53
+ <NumberEditor
54
+ placeholder="请输入价格"
55
+ min={0}
56
+ precision={2}
57
+ prefix="¥"
58
+ onChange={handlePriceChange}
59
+ bind:value={price}
60
+ />
61
+
62
+ <!-- 带限制的数量输入 -->
63
+ <NumberEditor
64
+ placeholder="请输入数量"
65
+ min={1}
66
+ max={999}
67
+ precision={0}
68
+ onChange={handleQuantityChange}
69
+ bind:value={quantity}
70
+ />
71
+
72
+ <!-- 带后缀的评分输入 -->
73
+ <NumberEditor
74
+ placeholder="请输入评分"
75
+ min={0}
76
+ max={5}
77
+ precision={1}
78
+ suffix="/5"
79
+ onChange={handleRatingChange}
80
+ bind:value={rating}
81
+ />
82
+ ```
83
+
84
+ ## 高级用法
85
+
86
+ ### 货币输入
87
+ ```svelte
88
+ <script lang="ts">
89
+ let amount = null;
90
+ let formattedAmount = '';
91
+
92
+ const formatCurrency = (value) => {
93
+ if (value === null || value === undefined) return '';
94
+ return new Intl.NumberFormat('zh-CN', {
95
+ style: 'currency',
96
+ currency: 'CNY'
97
+ }).format(value);
98
+ };
99
+
100
+ const handleAmountChange = (value) => {
101
+ amount = value;
102
+ formattedAmount = formatCurrency(value);
103
+ };
104
+ </script>
105
+
106
+ <div class="currency-input">
107
+ <NumberEditor
108
+ placeholder="请输入金额"
109
+ min={0}
110
+ precision={2}
111
+ prefix="¥"
112
+ bind:value={amount}
113
+ onChange={handleAmountChange}
114
+ />
115
+ {#if formattedAmount}
116
+ <div class="currency-display">{formattedAmount}</div>
117
+ {/if}
118
+ </div>
119
+ ```
120
+
121
+ ### 百分比输入
122
+ ```svelte
123
+ <script lang="ts">
124
+ let percentage = null;
125
+
126
+ const handlePercentageChange = (value) => {
127
+ // 限制在0-100之间
128
+ if (value !== null) {
129
+ percentage = Math.min(Math.max(value, 0), 100);
130
+ } else {
131
+ percentage = value;
132
+ }
133
+ };
134
+ </script>
135
+
136
+ <div class="percentage-input">
137
+ <NumberEditor
138
+ placeholder="请输入百分比"
139
+ min={0}
140
+ max={100}
141
+ precision={1}
142
+ suffix="%"
143
+ bind:value={percentage}
144
+ onChange={handlePercentageChange}
145
+ />
146
+ </div>
147
+ ```
148
+
149
+ ### 表单验证
150
+ ```svelte
151
+ <script lang="ts">
152
+ let age = null;
153
+ let ageError = '';
154
+
155
+ const validateAge = (value) => {
156
+ if (value === null) {
157
+ ageError = '年龄不能为空';
158
+ } else if (value < 18) {
159
+ ageError = '年龄必须满18岁';
160
+ } else if (value > 120) {
161
+ ageError = '请输入有效的年龄';
162
+ } else {
163
+ ageError = '';
164
+ }
165
+ };
166
+
167
+ const handleAgeChange = (value) => {
168
+ age = value;
169
+ validateAge(value);
170
+ };
171
+ </script>
172
+
173
+ <div class="form-field">
174
+ <NumberEditor
175
+ placeholder="请输入年龄"
176
+ min={1}
177
+ max={120}
178
+ bind:value={age}
179
+ onChange={handleAgeChange}
180
+ />
181
+ {#if ageError}
182
+ <div class="error-message">{ageError}</div>
183
+ {/if}
184
+ </div>
185
+ ```
186
+
187
+ ## 样式定制
188
+
189
+ ```css
190
+ .currency-input {
191
+ position: relative;
192
+ display: flex;
193
+ flex-direction: column;
194
+ gap: 4px;
195
+ }
196
+
197
+ .currency-display {
198
+ font-size: 12px;
199
+ color: #6c757d;
200
+ font-weight: 500;
201
+ }
202
+
203
+ .percentage-input {
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 8px;
207
+ }
208
+
209
+ .suffix {
210
+ font-weight: 500;
211
+ color: #495057;
212
+ }
213
+
214
+ .form-field {
215
+ margin-bottom: 16px;
216
+ }
217
+
218
+ .error-message {
219
+ color: #dc3545;
220
+ font-size: 12px;
221
+ margin-top: 4px;
222
+ }
223
+ ```
224
+
225
+ ## 最佳实践
226
+
227
+ ### 1. 设置合适的精度
228
+ ```svelte
229
+ <!-- 货币:2位小数 -->
230
+ <NumberEditor precision={2} prefix="¥" />
231
+
232
+ <!-- 百分比:1位小数 -->
233
+ <NumberEditor precision={1} suffix="%" max={100} />
234
+
235
+ <!-- 整数:不设置precision -->
236
+ <NumberEditor precision={0} />
237
+ ```
238
+
239
+ ### 2. 合理的范围限制
240
+ ```svelte
241
+ <!-- 年龄 -->
242
+ <NumberEditor min={0} max={150} precision={0} />
243
+
244
+ <!-- 评分 -->
245
+ <NumberEditor min={0} max={5} precision={1} suffix="/5" />
246
+
247
+ <!-- 价格 -->
248
+ <NumberEditor min={0} precision={2} prefix="¥" />
249
+ ```
250
+
251
+ ### 3. 合适的前后缀使用
252
+ ```svelte
253
+ <!-- 货币前缀 -->
254
+ <NumberEditor prefix="¥" precision={2} />
255
+
256
+ <!-- 百分比后缀 -->
257
+ <NumberEditor suffix="%" precision={1} max={100} />
258
+
259
+ <!-- 单位后缀 -->
260
+ <NumberEditor suffix="kg" precision={1} min={0} />
261
+ ```