@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 Component
2
+
3
+ The MemoEditor component provides a multi-line text input with advanced features including character counting, resizing options, and display mode support for longer text content.
4
+
5
+ ## Features
6
+
7
+ - **Multi-line Text Input**: Textarea-based input for longer text content
8
+ - **Character Counting**: Optional character limit and counter display
9
+ - **Resizable Input**: Configurable resize behavior (none, horizontal, vertical, both)
10
+ - **Display Modes**: Edit and view modes with HTML rendering
11
+ - **Text Wrapping**: Configurable text wrapping behavior
12
+ - **Clear Function**: Built-in clear button with icon
13
+ - **Variant Support**: Multiple styling variants (plain, outlined, filled)
14
+ - **HTML Escaping**: Safe HTML rendering in view mode
15
+
16
+ ## Import
17
+
18
+ ```typescript
19
+ import MemoEditor from '@ticatec/uniface-element/MemoEditor';
20
+ ```
21
+
22
+ ## Basic Usage
23
+
24
+ ### Simple Memo Editor
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="Enter your memo..."
37
+ />
38
+ ```
39
+
40
+ ### With Character Limit and Counter
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="Write your message (max 500 characters)..."
55
+ />
56
+ ```
57
+
58
+ ### Resizable Editor
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="Resizable notes editor..."
73
+ />
74
+ ```
75
+
76
+ ## API Reference
77
+
78
+ ### Props
79
+
80
+ | Property | Type | Default | Description |
81
+ |----------|------|---------|-------------|
82
+ | `value` | `string` | required | The text content |
83
+ | `disabled` | `boolean` | `false` | Whether the editor is disabled |
84
+ | `readonly` | `boolean` | `false` | Whether the editor is read-only |
85
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Visual variant |
86
+ | `style` | `string` | `''` | Additional CSS styles |
87
+ | `wrap` | `'hard' \| 'soft'` | `'hard'` | Text wrapping behavior |
88
+ | `resize` | `'none' \| 'horizontal' \| 'vertical' \| 'both'` | `'none'` | Resize capability |
89
+ | `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode (Edit/View) |
90
+ | `input$rows` | `number` | `3` | Number of visible text lines |
91
+ | `showIndicator` | `boolean` | `false` | Show character counter |
92
+ | `maxLength` | `number` | `null` | Maximum character limit |
93
+
94
+ ### DisplayMode Enum
95
+
96
+ ```typescript
97
+ enum DisplayMode {
98
+ Edit = 'edit',
99
+ View = 'view'
100
+ }
101
+ ```
102
+
103
+ ## Advanced Examples
104
+
105
+ ### Comment System
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="Write your comment..."
142
+ style="margin-bottom: 10px;"
143
+ />
144
+ <button on:click={saveComment} disabled={!comment.trim()}>
145
+ Post Comment
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)}>Edit</button>
160
+ </div>
161
+ </div>
162
+ {/each}
163
+ </div>
164
+ </div>
165
+ ```
166
+
167
+ ### Rich Text Note-Taking
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: `Note ${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
+ New Note
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 ? 'Edit' : 'Preview'}
236
+ </button>
237
+ <button on:click={saveCurrentNote}>Save</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="Start writing your note..."
250
+ />
251
+ </div>
252
+ {:else}
253
+ <div class="no-note" style="flex: 1; display: flex; align-items: center; justify-content: center; color: #666;">
254
+ Select a note or create a new one
255
+ </div>
256
+ {/if}
257
+ </div>
258
+ </div>
259
+ ```
260
+
261
+ ### Form with Validation
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 ? '' : 'Description must be at least 10 characters';
279
+ case 'feedback':
280
+ return value.trim().length >= 5 ? '' : 'Feedback must be at least 5 characters';
281
+ case 'requirements':
282
+ return value.trim().length > 0 ? '' : 'Requirements are required';
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
+ // Validate all fields
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('Form submitted:', formData);
304
+ alert('Form submitted successfully!');
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
+ Project Description *
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="Describe your project..."
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
+ Additional Feedback
334
+ </label>
335
+ <MemoEditor
336
+ bind:value={formData.feedback}
337
+ input$rows={3}
338
+ maxLength={300}
339
+ showIndicator={true}
340
+ variant="filled"
341
+ placeholder="Any additional feedback..."
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
+ Requirements *
354
+ </label>
355
+ <MemoEditor
356
+ bind:value={formData.requirements}
357
+ input$rows={5}
358
+ variant="outlined"
359
+ resize="both"
360
+ placeholder="List your requirements..."
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
+ Submit Form
372
+ </button>
373
+ </form>
374
+ ```
375
+
376
+ ## Best Practices
377
+
378
+ 1. **Character Limits**: Set appropriate `maxLength` for user guidance and data constraints
379
+ 2. **Visual Feedback**: Use `showIndicator` with character limits for better UX
380
+ 3. **Accessibility**: Provide clear labels and placeholder text
381
+ 4. **Resize Behavior**: Choose appropriate resize options based on layout constraints
382
+ 5. **Validation**: Implement client-side validation with clear error messages
383
+ 6. **Performance**: Consider debouncing for real-time validation or auto-save features
384
+ 7. **Content Safety**: The component automatically escapes HTML in view mode
385
+
386
+ ## Styling Notes
387
+
388
+ - The component supports standard variant styling (plain, outlined, filled)
389
+ - Custom styles can be applied via the `style` prop
390
+ - Character counter appears at the bottom-right when enabled
391
+ - Clear button appears when content is present and not disabled
392
+
393
+ ## Events
394
+
395
+ The component forwards standard textarea events:
396
+ - `on:blur`
397
+ - `on:focus`
398
+ - `on:keydown`
399
+ - `on:keyup`
400
+ - `on:keypress`
401
+ - `on:change`
402
+ - `on:input`
403
+
404
+ ## Accessibility Considerations
405
+
406
+ - Proper focus management for textarea element
407
+ - Character limit information is visually presented
408
+ - Clear button provides alternative content clearing method
409
+ - HTML content is safely escaped in view mode
@@ -0,0 +1,249 @@
1
+ # NumberEditor Component
2
+
3
+ Specialized component for numeric input, supporting integers and floating-point numbers.
4
+
5
+ ## Properties
6
+
7
+ | Property | Type | Default | Description |
8
+ |----------|------|---------|-------------|
9
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Appearance variant |
10
+ | `disabled` | `boolean` | `false` | Whether disabled |
11
+ | `readonly` | `boolean` | `false` | Whether read-only |
12
+ | `compact` | `boolean` | `false` | Whether compact mode |
13
+ | `value` | `number \| null` | `null` | Numeric value |
14
+ | `placeholder` | `string` | `''` | Placeholder text |
15
+ | `precision` | `number \| null` | `null` | Number of decimal places |
16
+ | `suffix` | `string` | `''` | Text suffix |
17
+ | `prefix` | `string` | `''` | Text prefix |
18
+ | `allowNegative` | `boolean` | `false` | Allow negative numbers |
19
+ | `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode |
20
+ | `max` | `number \| null` | `null` | Maximum value |
21
+ | `min` | `number \| null` | `null` | Minimum value |
22
+ | `removable` | `boolean` | `true` | Show clear button |
23
+ | `style` | `string` | `''` | Custom styles |
24
+ | `onChange` | `OnChangeHandler<number \| null>` | - | Value change callback |
25
+
26
+ ## Usage Examples
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('Price:', value);
39
+ };
40
+
41
+ const handleQuantityChange = (value: number | null) => {
42
+ quantity = value;
43
+ console.log('Quantity:', value);
44
+ };
45
+
46
+ const handleRatingChange = (value: number | null) => {
47
+ rating = value;
48
+ console.log('Rating:', value);
49
+ };
50
+ </script>
51
+
52
+ <!-- Price input with prefix -->
53
+ <NumberEditor
54
+ placeholder="Enter price"
55
+ min={0}
56
+ precision={2}
57
+ prefix="$"
58
+ onChange={handlePriceChange}
59
+ bind:value={price}
60
+ />
61
+
62
+ <!-- Quantity input with limits -->
63
+ <NumberEditor
64
+ placeholder="Enter quantity"
65
+ min={1}
66
+ max={999}
67
+ precision={0}
68
+ onChange={handleQuantityChange}
69
+ bind:value={quantity}
70
+ />
71
+
72
+ <!-- Rating input with suffix -->
73
+ <NumberEditor
74
+ placeholder="Enter rating"
75
+ min={0}
76
+ max={5}
77
+ precision={1}
78
+ suffix="/5"
79
+ onChange={handleRatingChange}
80
+ bind:value={rating}
81
+ />
82
+ ```
83
+
84
+ ## Advanced Usage
85
+
86
+ ### Currency Input
87
+ ```svelte
88
+ <script lang="ts">
89
+ let amount: number | null = null;
90
+
91
+ const handleAmountChange = (value: number | null) => {
92
+ amount = value;
93
+ console.log('Amount:', value);
94
+ };
95
+ </script>
96
+
97
+ <div class="currency-input">
98
+ <NumberEditor
99
+ placeholder="Enter amount"
100
+ min={0}
101
+ precision={2}
102
+ prefix="$"
103
+ bind:value={amount}
104
+ onChange={handleAmountChange}
105
+ />
106
+ </div>
107
+ ```
108
+
109
+ ### Percentage Input
110
+ ```svelte
111
+ <script lang="ts">
112
+ let percentage: number | null = null;
113
+
114
+ const handlePercentageChange = (value: number | null) => {
115
+ // Limit to 0-100 range
116
+ if (value !== null) {
117
+ percentage = Math.min(Math.max(value, 0), 100);
118
+ } else {
119
+ percentage = value;
120
+ }
121
+ };
122
+ </script>
123
+
124
+ <div class="percentage-input">
125
+ <NumberEditor
126
+ placeholder="Enter percentage"
127
+ min={0}
128
+ max={100}
129
+ precision={1}
130
+ suffix="%"
131
+ bind:value={percentage}
132
+ onChange={handlePercentageChange}
133
+ />
134
+ </div>
135
+ ```
136
+
137
+ ### Form Validation
138
+ ```svelte
139
+ <script lang="ts">
140
+ let age: number | null = null;
141
+ let ageError = '';
142
+
143
+ const validateAge = (value: number | null) => {
144
+ if (value === null) {
145
+ ageError = 'Age cannot be empty';
146
+ } else if (value < 18) {
147
+ ageError = 'Age must be at least 18';
148
+ } else if (value > 120) {
149
+ ageError = 'Please enter a valid age';
150
+ } else {
151
+ ageError = '';
152
+ }
153
+ };
154
+
155
+ const handleAgeChange = (value: number) => {
156
+ age = value;
157
+ validateAge(value);
158
+ };
159
+ </script>
160
+
161
+ <div class="form-field">
162
+ <NumberEditor
163
+ placeholder="Enter age"
164
+ min={1}
165
+ max={120}
166
+ bind:value={age}
167
+ onChange={handleAgeChange}
168
+ />
169
+ {#if ageError}
170
+ <div class="error-message">{ageError}</div>
171
+ {/if}
172
+ </div>
173
+ ```
174
+
175
+ ## Style Customization
176
+
177
+ ```css
178
+ .currency-input {
179
+ position: relative;
180
+ display: flex;
181
+ flex-direction: column;
182
+ gap: 4px;
183
+ }
184
+
185
+ .currency-display {
186
+ font-size: 12px;
187
+ color: #6c757d;
188
+ font-weight: 500;
189
+ }
190
+
191
+ .percentage-input {
192
+ display: flex;
193
+ align-items: center;
194
+ gap: 8px;
195
+ }
196
+
197
+ .suffix {
198
+ font-weight: 500;
199
+ color: #495057;
200
+ }
201
+
202
+ .form-field {
203
+ margin-bottom: 16px;
204
+ }
205
+
206
+ .error-message {
207
+ color: #dc3545;
208
+ font-size: 12px;
209
+ margin-top: 4px;
210
+ }
211
+ ```
212
+
213
+ ## Best Practices
214
+
215
+ ### 1. Set Appropriate Precision
216
+ ```svelte
217
+ <!-- Currency: 2 decimal places -->
218
+ <NumberEditor precision={2} prefix="$" />
219
+
220
+ <!-- Percentage: 1 decimal place -->
221
+ <NumberEditor precision={1} suffix="%" max={100} />
222
+
223
+ <!-- Integer: no precision setting -->
224
+ <NumberEditor precision={0} />
225
+ ```
226
+
227
+ ### 2. Use Prefixes and Suffixes
228
+ ```svelte
229
+ <!-- Currency -->
230
+ <NumberEditor prefix="$" precision={2} />
231
+
232
+ <!-- Percentage -->
233
+ <NumberEditor suffix="%" precision={1} />
234
+
235
+ <!-- Units -->
236
+ <NumberEditor suffix="kg" precision={2} />
237
+ ```
238
+
239
+ ### 3. Set Reasonable Range Limits
240
+ ```svelte
241
+ <!-- Age -->
242
+ <NumberEditor min={0} max={150} precision={0} />
243
+
244
+ <!-- Rating -->
245
+ <NumberEditor min={0} max={5} precision={1} />
246
+
247
+ <!-- Price -->
248
+ <NumberEditor min={0} precision={2} allowNegative={false} />
249
+ ```