@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.
- package/README.md +320 -1
- package/README_CN.md +392 -0
- package/dist/accordion/Accordion.svelte +1 -1
- package/dist/action-bar/ActionBar.svelte +7 -1
- package/dist/attachment-files/FileRender.svelte +1 -1
- package/dist/attachment-files/FileUploadBar.svelte +7 -6
- package/dist/attachment-files/FileUploadPanel.svelte +2 -2
- package/dist/base-calendar/DateContext.js +5 -4
- package/dist/base-calendar/YearPickupPanel.svelte +4 -4
- package/dist/card/Card.svelte +1 -1
- package/dist/card/Card.svelte.d.ts +1 -1
- package/dist/cascade-options-select/CascadeOptionSelect.svelte +2 -3
- package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +46 -1
- package/dist/cascade-options-select/CascadePanel.svelte +1 -1
- package/dist/checkbox/CheckBox.svelte +1 -1
- package/dist/color-picker/ColorPicker.svelte +9 -9
- package/dist/color-picker/ColorPicker.svelte.d.ts +0 -2
- package/dist/color-picker/ColorPickerPanel.svelte +11 -15
- package/dist/color-picker/ColorPickerPanel.svelte.d.ts +1 -1
- package/dist/common/CommonPicker.svelte +2 -2
- package/dist/common/CommonPicker.svelte.d.ts +1 -1
- package/dist/common/MouseClickHandler.d.ts +1 -1
- package/dist/common/Popover.svelte +28 -6
- package/dist/common/Popover.svelte.d.ts +9 -3
- package/dist/common/uniface-utils.js +6 -4
- package/dist/common-editor/CommonEditor.svelte +1 -1
- package/dist/common-editor/CommonEditor.svelte.d.ts +1 -1
- package/dist/common-editor/NumberInput.svelte +1 -1
- package/dist/common-editor/NumberInput.svelte.d.ts +1 -1
- package/dist/concise-data-table/ConciseListTable.svelte +7 -2
- package/dist/concise-data-table/ConciseListTable.svelte.d.ts +1 -0
- package/dist/concise-data-table/DataRow.svelte +1 -1
- package/dist/concise-data-table/TableOptions.d.ts +1 -1
- package/dist/data-table/DataTable.svelte +1 -1
- package/dist/data-table/parts/ActionsPanel.svelte +4 -3
- package/dist/data-table/parts/ActionsRow.svelte +3 -3
- package/dist/data-table/parts/ContentPanel.svelte +3 -2
- package/dist/data-table/parts/FixedColumnsPanel.svelte +0 -1
- package/dist/data-table/parts/FixedColumnsPanel.svelte.d.ts +1 -2
- package/dist/data-table/parts/FixedHeaderPanel.svelte +2 -2
- package/dist/data-table/parts/FixedRow.svelte +2 -1
- package/dist/data-table/parts/FixedRow.svelte.d.ts +1 -1
- package/dist/data-table/parts/HrefCell.svelte +23 -2
- package/dist/data-table/parts/PopupMenu.svelte +25 -2
- package/dist/data-table/parts/PopupMenu.svelte.d.ts +8 -1
- package/dist/date-picker/DatePicker.svelte +0 -1
- package/dist/date-picker/DateTimePicker.svelte +3 -3
- package/dist/date-picker/ScrollBar.svelte +4 -7
- package/dist/date-range/DateRangeEditor.svelte +1 -1
- package/dist/dialog/CommonDialog.svelte +8 -5
- package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
- package/dist/dialog/Dialog.svelte +37 -12
- package/dist/dialog/Dialog.svelte.d.ts +4 -3
- package/dist/dialog/DialogBoard.svelte +11 -8
- package/dist/dialog/DialogWrapper.svelte +10 -0
- package/dist/{common-editor/DateInput.svelte.d.ts → dialog/DialogWrapper.svelte.d.ts} +6 -13
- package/dist/dialog/Dialogs.js +1 -1
- package/dist/dialog/ModalResult.d.ts +5 -0
- package/dist/dialog/ModalResult.js +5 -0
- package/dist/drawer/Drawer.svelte +1 -1
- package/dist/form-field/FormField.svelte +2 -1
- package/dist/form-field/FormField.svelte.d.ts +1 -0
- package/dist/form-panel/flex-row-form/FormContainer.svelte +1 -1
- package/dist/form-panel/grid-form/EmptyCell.svelte +8 -7
- package/dist/form-panel/grid-form/EmptyCell.svelte.d.ts +2 -2
- package/dist/form-panel/grid-form/GridField.svelte +1 -1
- package/dist/i18nRes/i18nRes.d.ts +2 -0
- package/dist/i18nRes/i18nRes.js +44 -0
- package/dist/i18nRes/index.d.ts +2 -0
- package/dist/i18nRes/index.js +2 -0
- package/dist/image-files/ImageFilesField.svelte +1 -1
- package/dist/indicator/IndicatorBoard.svelte +1 -1
- package/dist/inline-cell-editor/InvalidEditor.svelte +1 -0
- package/dist/input-options-select/InputOptionsSelect.svelte +6 -6
- package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +1 -1
- package/dist/layout/flex/FlexBlock.svelte +1 -1
- package/dist/lookup-editor/LookupEditor.svelte +1 -1
- package/dist/memo-editor/MemoEditor.svelte +2 -2
- package/dist/message-box/IMessageBox.d.ts +2 -4
- package/dist/message-box/IMessageBox.js +4 -6
- package/dist/message-box/MessageBoxBoard.svelte +1 -3
- package/dist/options-multi-select/OptionsMultiSelect.svelte +1 -1
- package/dist/prompts-text-editor/PromptsTextEditor.svelte +2 -2
- package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +1 -1
- package/dist/property-editor/PropertyEditor.svelte +3 -3
- package/dist/text-editor/PasswordEditor.svelte +1 -1
- package/dist/transfer/Transfer.svelte +17 -12
- package/dist/transfer/Transfer.svelte.d.ts +0 -1
- package/dist/unit-number-editor/UnitNumberEditor.svelte +2 -2
- package/docs/buttons/cn/ActionBar.md +459 -0
- package/docs/buttons/cn/Button.md +228 -0
- package/docs/buttons/cn/IconButton.md +294 -0
- package/docs/buttons/cn/README.md +600 -0
- package/docs/buttons/cn/TextButton.md +163 -0
- package/docs/buttons/en/ActionBar.md +459 -0
- package/docs/buttons/en/Button.md +228 -0
- package/docs/buttons/en/IconButton.md +294 -0
- package/docs/buttons/en/README.md +600 -0
- package/docs/buttons/en/TextButton.md +163 -0
- package/docs/containers/cn/accordion.md +622 -0
- package/docs/containers/cn/box.md +445 -0
- package/docs/containers/cn/card.md +404 -0
- package/docs/containers/cn/page.md +576 -0
- package/docs/containers/cn/tabs.md +686 -0
- package/docs/containers/en/accordion.md +622 -0
- package/docs/containers/en/box.md +445 -0
- package/docs/containers/en/card.md +404 -0
- package/docs/containers/en/page.md +576 -0
- package/docs/containers/en/tabs.md +686 -0
- package/docs/data-display/cn/concise-data-table.md +731 -0
- package/docs/data-display/cn/listbox.md +786 -0
- package/docs/data-display/cn/treeview.md +863 -0
- package/docs/data-display/en/concise-data-table.md +732 -0
- package/docs/data-display/en/listbox.md +786 -0
- package/docs/data-display/en/treeview.md +863 -0
- package/docs/data-table/cn/README.md +596 -0
- package/docs/data-table/en/README.md +596 -0
- package/docs/dialog/cn/README.md +767 -0
- package/docs/dialog/en/README.md +767 -0
- package/docs/form/cn/README.md +847 -0
- package/docs/form/en/README.md +847 -0
- package/docs/form-components/cn/README.md +495 -0
- package/docs/form-components/cn/attachmentfilesfield.md +757 -0
- package/docs/form-components/cn/cascade-options-select.md +374 -0
- package/docs/form-components/cn/checkbox.md +58 -0
- package/docs/form-components/cn/date-picker.md +138 -0
- package/docs/form-components/cn/datetime-picker.md +228 -0
- package/docs/form-components/cn/group-checkbox.md +405 -0
- package/docs/form-components/cn/group-radiobox.md +525 -0
- package/docs/form-components/cn/imagefilesfield.md +651 -0
- package/docs/form-components/cn/input-options-select.md +250 -0
- package/docs/form-components/cn/lookup-editor.md +406 -0
- package/docs/form-components/cn/memoeditor.md +409 -0
- package/docs/form-components/cn/number-editor.md +261 -0
- package/docs/form-components/cn/options-multi-select.md +177 -0
- package/docs/form-components/cn/options-select.md +83 -0
- package/docs/form-components/cn/passwordeditor.md +538 -0
- package/docs/form-components/cn/prompts-text-editor.md +241 -0
- package/docs/form-components/cn/radiobutton.md +84 -0
- package/docs/form-components/cn/switch.md +178 -0
- package/docs/form-components/cn/text-editor.md +142 -0
- package/docs/form-components/cn/time-editor.md +159 -0
- package/docs/form-components/cn/unit-number-editor.md +164 -0
- package/docs/form-components/en/README.md +463 -0
- package/docs/form-components/en/attachmentfilesfield.md +757 -0
- package/docs/form-components/en/cascade-options-select.md +358 -0
- package/docs/form-components/en/checkbox.md +59 -0
- package/docs/form-components/en/date-picker.md +138 -0
- package/docs/form-components/en/datetime-picker.md +228 -0
- package/docs/form-components/en/group-checkbox.md +395 -0
- package/docs/form-components/en/group-radiobox.md +498 -0
- package/docs/form-components/en/imagefilesfield.md +651 -0
- package/docs/form-components/en/input-options-select.md +239 -0
- package/docs/form-components/en/lookup-editor.md +389 -0
- package/docs/form-components/en/memoeditor.md +409 -0
- package/docs/form-components/en/number-editor.md +249 -0
- package/docs/form-components/en/options-multi-select.md +177 -0
- package/docs/form-components/en/options-select.md +83 -0
- package/docs/form-components/en/passwordeditor.md +538 -0
- package/docs/form-components/en/prompts-text-editor.md +241 -0
- package/docs/form-components/en/radiobutton.md +84 -0
- package/docs/form-components/en/switch.md +180 -0
- package/docs/form-components/en/text-editor.md +142 -0
- package/docs/form-components/en/time-editor.md +159 -0
- package/docs/form-components/en/unit-number-editor.md +164 -0
- package/docs/form-layout/cn/criteria-field.md +652 -0
- package/docs/form-layout/cn/flex-form.md +454 -0
- package/docs/form-layout/cn/flex-row-form.md +542 -0
- package/docs/form-layout/cn/form-field.md +923 -0
- package/docs/form-layout/cn/grid-form.md +676 -0
- package/docs/form-layout/en/criteria-field.md +652 -0
- package/docs/form-layout/en/flex-form.md +454 -0
- package/docs/form-layout/en/flex-row-form.md +542 -0
- package/docs/form-layout/en/form-field.md +923 -0
- package/docs/form-layout/en/grid-form.md +676 -0
- package/docs/global/cn/README.md +534 -0
- package/docs/global/en/README.md +534 -0
- package/docs/layout/cn/classiclayout.md +460 -0
- package/docs/layout/cn/headerlayout.md +524 -0
- package/docs/layout/cn/sidebarlayout.md +263 -0
- package/docs/layout/en/classiclayout.md +951 -0
- package/docs/layout/en/headerlayout.md +524 -0
- package/docs/layout/en/sidebarlayout.md +262 -0
- package/docs/misc/cn/README.md +1217 -0
- package/docs/misc/en/README.md +1217 -0
- package/docs/navigation/cn/breadcrumb.md +291 -0
- package/docs/navigation/cn/navigator.md +322 -0
- package/docs/navigation/cn/navigatormenu.md +512 -0
- package/docs/navigation/cn/progressbar.md +199 -0
- package/docs/navigation/cn/progressstepbar.md +299 -0
- package/docs/navigation/en/breadcrumb.md +291 -0
- package/docs/navigation/en/navigator.md +322 -0
- package/docs/navigation/en/navigatormenu.md +512 -0
- package/docs/navigation/en/progressbar.md +199 -0
- package/docs/navigation/en/progressstepbar.md +299 -0
- package/docs/search-filters/cn/daterange.md +1156 -0
- package/docs/search-filters/cn/numberrange.md +688 -0
- package/docs/search-filters/cn/searchbox.md +1582 -0
- package/docs/search-filters/en/daterange.md +1156 -0
- package/docs/search-filters/en/numberrange.md +688 -0
- package/docs/search-filters/en/searchbox.md +1582 -0
- package/package.json +53 -13
- package/dist/common-editor/DateInput.svelte +0 -27
- package/dist/i18n_resources/index.d.ts +0 -3
- package/dist/i18n_resources/index.js +0 -3
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.d.ts +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.js +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.d.ts +0 -0
- /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
|
+
```
|