@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,686 @@
1
+ # Tabs Component
2
+
3
+ A flexible and feature-rich tabbed interface component that allows organizing content into multiple switchable panels with support for scrolling, closing, and custom tab rendering.
4
+
5
+ ## Overview
6
+
7
+ The Tabs component provides an intuitive way to organize related content into separate, navigable panels. It includes advanced features like horizontal scrolling for many tabs, closable tabs, reload functionality, and custom tab rendering. Perfect for dashboards, settings panels, multi-step forms, and content organization.
8
+
9
+ ## Installation
10
+
11
+ ```typescript
12
+ import Tabs from '@ticatec/uniface-element/Tabs';
13
+ import type { TabActionHandler, TabCloseHandler, TabRender } from '@ticatec/uniface-element/Tabs';
14
+ ```
15
+
16
+ ## Basic Usage
17
+
18
+ ```svelte
19
+ <script lang="ts">
20
+ import Tabs from '@ticatec/uniface-element/Tabs';
21
+
22
+ let tabData = [
23
+ { id: 1, text: 'Dashboard', content: 'dashboard' },
24
+ { id: 2, text: 'Users', content: 'users' },
25
+ { id: 3, text: 'Settings', content: 'settings' }
26
+ ];
27
+
28
+ let activeTab = tabData[0];
29
+ </script>
30
+
31
+ <Tabs tabs={tabData} bind:activeTab>
32
+ <div class="tab-content">
33
+ {#if activeTab.content === 'dashboard'}
34
+ <div class="dashboard-panel">
35
+ <h3>Dashboard Content</h3>
36
+ <p>Welcome to your dashboard...</p>
37
+ </div>
38
+ {:else if activeTab.content === 'users'}
39
+ <div class="users-panel">
40
+ <h3>User Management</h3>
41
+ <p>Manage your users here...</p>
42
+ </div>
43
+ {:else if activeTab.content === 'settings'}
44
+ <div class="settings-panel">
45
+ <h3>Application Settings</h3>
46
+ <p>Configure your application...</p>
47
+ </div>
48
+ {/if}
49
+ </div>
50
+ </Tabs>
51
+ ```
52
+
53
+ ## Properties
54
+
55
+ | Property | Type | Default | Description |
56
+ |----------|------|---------|-------------|
57
+ | `class` | `string` | `""` | Additional CSS class names |
58
+ | `simple` | `boolean` | `false` | Use simplified tab styling |
59
+ | `textField` | `string` | `'text'` | Property name to use for tab text |
60
+ | `style` | `string` | `''` | Custom CSS styles for tabs container |
61
+ | `tabs` | `Array<any>` | `[]` | Array of tab objects |
62
+ | `scrollStep` | `number` | `100` | Pixels to scroll when using scroll buttons |
63
+ | `closable` | `boolean \| TabActionHandler` | `false` | Enable tab closing or custom close logic |
64
+ | `activeTab` | `any` | `null` | Currently active tab object |
65
+ | `tabRender` | `TabRender` | `null` | Custom tab rendering component |
66
+ | `reloadHandler` | `TabActionHandler` | `null` | Handler for tab reload action |
67
+ | `closeHandler` | `TabCloseHandler` | `null` | Handler for tab close action |
68
+
69
+ ## Type Definitions
70
+
71
+ ```typescript
72
+ export type TabActionHandler = (tab: any) => void;
73
+ export type TabCloseHandler = (tab: any) => Promise<boolean>;
74
+ export type TabRender = (tab: any) => any;
75
+ ```
76
+
77
+ ## Usage Examples
78
+
79
+ ### Basic Tabs
80
+
81
+ ```svelte
82
+ <script lang="ts">
83
+ import Tabs from '@ticatec/uniface-element/Tabs';
84
+
85
+ let navigationTabs = [
86
+ { id: 'overview', text: 'Overview' },
87
+ { id: 'analytics', text: 'Analytics' },
88
+ { id: 'reports', text: 'Reports' },
89
+ { id: 'settings', text: 'Settings' }
90
+ ];
91
+
92
+ let currentTab = navigationTabs[0];
93
+ </script>
94
+
95
+ <Tabs tabs={navigationTabs} bind:activeTab={currentTab}>
96
+ <div class="content-area">
97
+ {#if currentTab.id === 'overview'}
98
+ <h2>System Overview</h2>
99
+ <p>General system information and status.</p>
100
+ {:else if currentTab.id === 'analytics'}
101
+ <h2>Analytics Dashboard</h2>
102
+ <p>View detailed analytics and metrics.</p>
103
+ {:else if currentTab.id === 'reports'}
104
+ <h2>Reports</h2>
105
+ <p>Generate and view system reports.</p>
106
+ {:else if currentTab.id === 'settings'}
107
+ <h2>Configuration</h2>
108
+ <p>Manage system settings and preferences.</p>
109
+ {/if}
110
+ </div>
111
+ </Tabs>
112
+ ```
113
+
114
+ ### Closable Tabs
115
+
116
+ ```svelte
117
+ <script lang="ts">
118
+ import Tabs from '@ticatec/uniface-element/Tabs';
119
+ import type { TabCloseHandler } from '@ticatec/uniface-element/Tabs';
120
+
121
+ let documentTabs = [
122
+ { id: 1, text: 'Document 1', modified: false },
123
+ { id: 2, text: 'Document 2', modified: true },
124
+ { id: 3, text: 'Document 3', modified: false }
125
+ ];
126
+
127
+ let activeDocument = documentTabs[0];
128
+
129
+ const handleTabClose: TabCloseHandler = async (tab) => {
130
+ if (tab.modified) {
131
+ const shouldClose = confirm(`"${tab.text}" has unsaved changes. Close anyway?`);
132
+ return shouldClose;
133
+ }
134
+ return true;
135
+ };
136
+ </script>
137
+
138
+ <Tabs
139
+ tabs={documentTabs}
140
+ bind:activeTab={activeDocument}
141
+ closable={true}
142
+ closeHandler={handleTabClose}
143
+ >
144
+ <div class="document-editor">
145
+ <h3>Editing: {activeDocument.text}</h3>
146
+ <textarea placeholder="Document content..." rows="10" cols="50"></textarea>
147
+ {#if activeDocument.modified}
148
+ <p class="unsaved-indicator">• Unsaved changes</p>
149
+ {/if}
150
+ </div>
151
+ </Tabs>
152
+ ```
153
+
154
+ ### Tabs with Reload Functionality
155
+
156
+ ```svelte
157
+ <script lang="ts">
158
+ import Tabs from '@ticatec/uniface-element/Tabs';
159
+ import type { TabActionHandler } from '@ticatec/uniface-element/Tabs';
160
+
161
+ let dataTabs = [
162
+ { id: 'users', text: 'Users', lastRefresh: new Date() },
163
+ { id: 'orders', text: 'Orders', lastRefresh: new Date() },
164
+ { id: 'products', text: 'Products', lastRefresh: new Date() }
165
+ ];
166
+
167
+ let activeDataTab = dataTabs[0];
168
+
169
+ const handleTabReload: TabActionHandler = (tab) => {
170
+ console.log(`Reloading ${tab.text} data...`);
171
+ tab.lastRefresh = new Date();
172
+ // Trigger data refresh logic here
173
+ refreshTabData(tab.id);
174
+ };
175
+
176
+ function refreshTabData(tabId: string) {
177
+ // Simulate data refresh
178
+ console.log(`Refreshing data for tab: ${tabId}`);
179
+ }
180
+ </script>
181
+
182
+ <Tabs
183
+ tabs={dataTabs}
184
+ bind:activeTab={activeDataTab}
185
+ reloadHandler={handleTabReload}
186
+ >
187
+ <div class="data-panel">
188
+ <div class="panel-header">
189
+ <h3>{activeDataTab.text} Data</h3>
190
+ <small>Last refreshed: {activeDataTab.lastRefresh.toLocaleTimeString()}</small>
191
+ </div>
192
+
193
+ <div class="data-content">
194
+ {#if activeDataTab.id === 'users'}
195
+ <p>User management interface...</p>
196
+ {:else if activeDataTab.id === 'orders'}
197
+ <p>Order tracking and management...</p>
198
+ {:else if activeDataTab.id === 'products'}
199
+ <p>Product catalog management...</p>
200
+ {/if}
201
+ </div>
202
+ </div>
203
+ </Tabs>
204
+ ```
205
+
206
+ ### Custom Tab Field
207
+
208
+ ```svelte
209
+ <script lang="ts">
210
+ import Tabs from '@ticatec/uniface-element/Tabs';
211
+
212
+ // Using custom field name for tab labels
213
+ let projectTabs = [
214
+ { projectId: 'proj-1', name: 'Website Redesign', status: 'active' },
215
+ { projectId: 'proj-2', name: 'Mobile App', status: 'completed' },
216
+ { projectId: 'proj-3', name: 'API Integration', status: 'pending' }
217
+ ];
218
+
219
+ let selectedProject = projectTabs[0];
220
+ </script>
221
+
222
+ <Tabs
223
+ tabs={projectTabs}
224
+ bind:activeTab={selectedProject}
225
+ textField="name"
226
+ >
227
+ <div class="project-details">
228
+ <h2>{selectedProject.name}</h2>
229
+ <p>Project ID: {selectedProject.projectId}</p>
230
+ <p>Status: <span class="status-{selectedProject.status}">{selectedProject.status}</span></p>
231
+ </div>
232
+ </Tabs>
233
+
234
+ <style>
235
+ .status-active { color: #28a745; }
236
+ .status-completed { color: #6c757d; }
237
+ .status-pending { color: #ffc107; }
238
+ </style>
239
+ ```
240
+
241
+ ### Scrollable Tabs with Many Items
242
+
243
+ ```svelte
244
+ <script lang="ts">
245
+ import Tabs from '@ticatec/uniface-element/Tabs';
246
+
247
+ // Generate many tabs to demonstrate scrolling
248
+ let manyTabs = Array.from({ length: 20 }, (_, i) => ({
249
+ id: i + 1,
250
+ text: `Tab ${i + 1}`,
251
+ content: `Content for tab ${i + 1}`
252
+ }));
253
+
254
+ let activeManyTab = manyTabs[0];
255
+ </script>
256
+
257
+ <div style="max-width: 600px; margin: 20px 0;">
258
+ <Tabs
259
+ tabs={manyTabs}
260
+ bind:activeTab={activeManyTab}
261
+ scrollStep={150}
262
+ style="border: 1px solid #dee2e6; border-radius: 8px;"
263
+ >
264
+ <div class="scrollable-content">
265
+ <h3>{activeManyTab.text}</h3>
266
+ <p>{activeManyTab.content}</p>
267
+ <p>This demonstrates horizontal scrolling when there are many tabs.</p>
268
+ </div>
269
+ </Tabs>
270
+ </div>
271
+
272
+ <style>
273
+ .scrollable-content {
274
+ padding: 20px;
275
+ min-height: 200px;
276
+ }
277
+ </style>
278
+ ```
279
+
280
+ ### Custom Tab Rendering
281
+
282
+ ```svelte
283
+ <script lang="ts">
284
+ import Tabs from '@ticatec/uniface-element/Tabs';
285
+ import type { TabRender } from '@ticatec/uniface-element/Tabs';
286
+ import CustomTabRenderer from './CustomTabRenderer.svelte';
287
+
288
+ let notificationTabs = [
289
+ { id: 'inbox', text: 'Inbox', count: 5, icon: 'inbox' },
290
+ { id: 'sent', text: 'Sent', count: 0, icon: 'send' },
291
+ { id: 'drafts', text: 'Drafts', count: 2, icon: 'draft' },
292
+ { id: 'trash', text: 'Trash', count: 1, icon: 'delete' }
293
+ ];
294
+
295
+ let activeNotificationTab = notificationTabs[0];
296
+
297
+ // Custom tab renderer component
298
+ const customTabRenderer: TabRender = CustomTabRenderer;
299
+ </script>
300
+
301
+ <Tabs
302
+ tabs={notificationTabs}
303
+ bind:activeTab={activeNotificationTab}
304
+ tabRender={customTabRenderer}
305
+ >
306
+ <div class="notification-panel">
307
+ <h3>{activeNotificationTab.text}</h3>
308
+ <p>Items: {activeNotificationTab.count}</p>
309
+
310
+ {#if activeNotificationTab.id === 'inbox'}
311
+ <div class="inbox-content">
312
+ <p>You have {activeNotificationTab.count} new messages.</p>
313
+ </div>
314
+ {:else if activeNotificationTab.id === 'drafts'}
315
+ <div class="drafts-content">
316
+ <p>You have {activeNotificationTab.count} draft messages.</p>
317
+ </div>
318
+ {:else}
319
+ <div class="empty-content">
320
+ <p>No items in {activeNotificationTab.text.toLowerCase()}.</p>
321
+ </div>
322
+ {/if}
323
+ </div>
324
+ </Tabs>
325
+ ```
326
+
327
+ CustomTabRenderer.svelte:
328
+ ```svelte
329
+ <script lang="ts">
330
+ export let tab: any;
331
+ export let closable: boolean = false;
332
+ export let closeTab: (() => void) | null = null;
333
+ export let reloadTab: (() => void) | null = null;
334
+ </script>
335
+
336
+ <div class="custom-tab">
337
+ <i class="icon-{tab.icon}"></i>
338
+ <span class="tab-text">{tab.text}</span>
339
+ {#if tab.count > 0}
340
+ <span class="badge">{tab.count}</span>
341
+ {/if}
342
+
343
+ {#if reloadTab}
344
+ <button class="tab-action reload" on:click={reloadTab} aria-label="Reload">
345
+ <i class="icon-refresh"></i>
346
+ </button>
347
+ {/if}
348
+
349
+ {#if closable && closeTab}
350
+ <button class="tab-action close" on:click={closeTab} aria-label="Close">
351
+ <i class="icon-close"></i>
352
+ </button>
353
+ {/if}
354
+ </div>
355
+
356
+ <style>
357
+ .custom-tab {
358
+ display: flex;
359
+ align-items: center;
360
+ gap: 6px;
361
+ padding: 8px 12px;
362
+ }
363
+
364
+ .badge {
365
+ background: #dc3545;
366
+ color: white;
367
+ font-size: 0.75rem;
368
+ padding: 2px 6px;
369
+ border-radius: 10px;
370
+ min-width: 18px;
371
+ text-align: center;
372
+ }
373
+
374
+ .tab-action {
375
+ background: none;
376
+ border: none;
377
+ cursor: pointer;
378
+ padding: 2px;
379
+ opacity: 0.6;
380
+ transition: opacity 0.2s;
381
+ }
382
+
383
+ .tab-action:hover {
384
+ opacity: 1;
385
+ }
386
+ </style>
387
+ ```
388
+
389
+ ### Advanced Tabs with Dynamic Content
390
+
391
+ ```svelte
392
+ <script lang="ts">
393
+ import Tabs from '@ticatec/uniface-element/Tabs';
394
+ import type { TabActionHandler, TabCloseHandler } from '@ticatec/uniface-element/Tabs';
395
+
396
+ let workspaceTabs = [
397
+ { id: 'workspace-1', text: 'Main Workspace', type: 'workspace', canClose: false },
398
+ { id: 'file-1', text: 'app.js', type: 'file', modified: false, canClose: true },
399
+ { id: 'file-2', text: 'styles.css', type: 'file', modified: true, canClose: true }
400
+ ];
401
+
402
+ let activeWorkspaceTab = workspaceTabs[0];
403
+
404
+ const isClosable: TabActionHandler = (tab) => {
405
+ return tab.canClose === true;
406
+ };
407
+
408
+ const handleClose: TabCloseHandler = async (tab) => {
409
+ if (tab.type === 'file' && tab.modified) {
410
+ const save = confirm(`Save changes to ${tab.text}?`);
411
+ if (save) {
412
+ // Simulate save operation
413
+ await new Promise(resolve => setTimeout(resolve, 500));
414
+ tab.modified = false;
415
+ }
416
+ }
417
+ return true;
418
+ };
419
+
420
+ const handleReload: TabActionHandler = (tab) => {
421
+ if (tab.type === 'file') {
422
+ console.log(`Reloading file: ${tab.text}`);
423
+ tab.modified = false;
424
+ }
425
+ };
426
+
427
+ function addNewFile() {
428
+ const fileId = `file-${Date.now()}`;
429
+ const newFile = {
430
+ id: fileId,
431
+ text: 'untitled.txt',
432
+ type: 'file',
433
+ modified: false,
434
+ canClose: true
435
+ };
436
+ workspaceTabs = [...workspaceTabs, newFile];
437
+ activeWorkspaceTab = newFile;
438
+ }
439
+ </script>
440
+
441
+ <div class="ide-interface">
442
+ <div class="toolbar">
443
+ <button on:click={addNewFile} class="btn-new-file">
444
+ + New File
445
+ </button>
446
+ </div>
447
+
448
+ <Tabs
449
+ tabs={workspaceTabs}
450
+ bind:activeTab={activeWorkspaceTab}
451
+ closable={isClosable}
452
+ closeHandler={handleClose}
453
+ reloadHandler={handleReload}
454
+ class="ide-tabs"
455
+ >
456
+ <div class="editor-area">
457
+ {#if activeWorkspaceTab.type === 'workspace'}
458
+ <div class="workspace-content">
459
+ <h3>Welcome to the Workspace</h3>
460
+ <p>Open files will appear as tabs above.</p>
461
+ </div>
462
+ {:else if activeWorkspaceTab.type === 'file'}
463
+ <div class="file-editor">
464
+ <div class="file-header">
465
+ <h4>{activeWorkspaceTab.text}</h4>
466
+ {#if activeWorkspaceTab.modified}
467
+ <span class="modified-indicator">●</span>
468
+ {/if}
469
+ </div>
470
+ <textarea
471
+ class="code-editor"
472
+ placeholder="Enter your code here..."
473
+ on:input={() => activeWorkspaceTab.modified = true}
474
+ ></textarea>
475
+ </div>
476
+ {/if}
477
+ </div>
478
+ </Tabs>
479
+ </div>
480
+
481
+ <style>
482
+ .ide-interface {
483
+ border: 1px solid #ccc;
484
+ border-radius: 8px;
485
+ overflow: hidden;
486
+ }
487
+
488
+ .toolbar {
489
+ background: #f8f9fa;
490
+ padding: 8px 16px;
491
+ border-bottom: 1px solid #dee2e6;
492
+ }
493
+
494
+ .btn-new-file {
495
+ padding: 6px 12px;
496
+ background: #007bff;
497
+ color: white;
498
+ border: none;
499
+ border-radius: 4px;
500
+ cursor: pointer;
501
+ }
502
+
503
+ .editor-area {
504
+ min-height: 300px;
505
+ padding: 16px;
506
+ }
507
+
508
+ .file-header {
509
+ display: flex;
510
+ align-items: center;
511
+ gap: 8px;
512
+ margin-bottom: 12px;
513
+ }
514
+
515
+ .file-header h4 {
516
+ margin: 0;
517
+ }
518
+
519
+ .modified-indicator {
520
+ color: #ffc107;
521
+ font-size: 1.5rem;
522
+ line-height: 1;
523
+ }
524
+
525
+ .code-editor {
526
+ width: 100%;
527
+ height: 200px;
528
+ font-family: 'Courier New', monospace;
529
+ padding: 12px;
530
+ border: 1px solid #ddd;
531
+ border-radius: 4px;
532
+ }
533
+
534
+ .workspace-content {
535
+ text-align: center;
536
+ padding: 40px;
537
+ color: #666;
538
+ }
539
+ </style>
540
+ ```
541
+
542
+ ## Styling
543
+
544
+ The Tabs component uses the following CSS classes:
545
+
546
+ ```css
547
+ .uniface-tab-panel {
548
+ /* Main tabs container */
549
+ }
550
+
551
+ .uniface-tabs-wrap {
552
+ /* Tab header container */
553
+ }
554
+
555
+ .uniface-tabs-wrap.simple {
556
+ /* Simple styling variant */
557
+ }
558
+
559
+ .scroll-left, .scroll-right {
560
+ /* Scroll control buttons */
561
+ }
562
+
563
+ .tabs-panel {
564
+ /* Tab buttons container */
565
+ }
566
+
567
+ .uniface-tab {
568
+ /* Individual tab button */
569
+ }
570
+
571
+ .uniface-tab.active {
572
+ /* Active tab styling */
573
+ }
574
+
575
+ .tab-content {
576
+ /* Tab content area */
577
+ }
578
+
579
+ .tab-refresh, .tab-action {
580
+ /* Tab action buttons (refresh, close) */
581
+ }
582
+ ```
583
+
584
+ ## API Reference
585
+
586
+ ### Tabs Component Props
587
+
588
+ ```typescript
589
+ interface TabsProps {
590
+ class?: string; // Additional CSS classes
591
+ simple?: boolean; // Simplified styling
592
+ textField?: string; // Field name for tab text
593
+ style?: string; // Custom styles
594
+ tabs: Array<any>; // Tab data array
595
+ scrollStep?: number; // Scroll amount in pixels
596
+ closable?: boolean | TabActionHandler; // Enable closing
597
+ activeTab?: any; // Current active tab
598
+ tabRender?: TabRender; // Custom tab renderer
599
+ reloadHandler?: TabActionHandler; // Reload callback
600
+ closeHandler?: TabCloseHandler; // Close callback
601
+ }
602
+ ```
603
+
604
+ ### Type Definitions
605
+
606
+ ```typescript
607
+ /**
608
+ * Tab action handler function
609
+ */
610
+ export type TabActionHandler = (tab: any) => void;
611
+
612
+ /**
613
+ * Tab close handler function - return false to prevent closing
614
+ */
615
+ export type TabCloseHandler = (tab: any) => Promise<boolean>;
616
+
617
+ /**
618
+ * Custom tab render component
619
+ */
620
+ export type TabRender = (tab: any) => any;
621
+ ```
622
+
623
+ ## Best Practices
624
+
625
+ 1. **Consistent Tab Data** - Use consistent object structure across all tab items
626
+ 2. **Performance** - Avoid heavy computations in tab rendering, especially with many tabs
627
+ 3. **Keyboard Navigation** - Ensure tabs are accessible via keyboard navigation
628
+ 4. **Loading States** - Show loading indicators when tab content is being fetched
629
+ 5. **Memory Management** - Clean up resources when tabs are closed
630
+ 6. **Visual Feedback** - Provide clear visual feedback for active, hover, and disabled states
631
+ 7. **Mobile Responsiveness** - Consider how tabs behave on smaller screens
632
+ 8. **Content Management** - Use proper lifecycle management for tab content components
633
+
634
+ ## Advanced Features
635
+
636
+ ### Programmatic Tab Control
637
+
638
+ ```svelte
639
+ <script lang="ts">
640
+ import Tabs from '@ticatec/uniface-element/Tabs';
641
+
642
+ let tabs = [...];
643
+ let activeTab = tabs[0];
644
+ let tabsRef: Tabs;
645
+
646
+ function switchToTab(tabId: string) {
647
+ const tab = tabs.find(t => t.id === tabId);
648
+ if (tab) {
649
+ activeTab = tab;
650
+ }
651
+ }
652
+
653
+ function addTab(tabData: any) {
654
+ tabs = [...tabs, tabData];
655
+ }
656
+
657
+ function removeTab(tabId: string) {
658
+ tabs = tabs.filter(t => t.id !== tabId);
659
+ // Update active tab if needed
660
+ if (activeTab.id === tabId && tabs.length > 0) {
661
+ activeTab = tabs[0];
662
+ }
663
+ }
664
+ </script>
665
+
666
+ <Tabs bind:this={tabsRef} bind:tabs bind:activeTab>
667
+ <!-- Tab content -->
668
+ </Tabs>
669
+ ```
670
+
671
+ ## Integration with Routing
672
+
673
+ The Tabs component can be integrated with client-side routing:
674
+
675
+ ```svelte
676
+ <script lang="ts">
677
+ import { page } from '$app/stores';
678
+ import { goto } from '$app/navigation';
679
+
680
+ $: currentRoute = $page.route.id;
681
+
682
+ function handleTabChange(tab: any) {
683
+ goto(`/dashboard/${tab.route}`);
684
+ }
685
+ </script>
686
+ ```