@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,767 @@
|
|
|
1
|
+
# Dialog System
|
|
2
|
+
|
|
3
|
+
The Uniface Element Dialog System provides a comprehensive modal dialog solution for Svelte applications. It includes global dialog management, built-in dialog components, and flexible customization options.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Architecture Overview](#architecture-overview)
|
|
8
|
+
- [DialogBoard - Global Dialog Manager](#dialogboard---global-dialog-manager)
|
|
9
|
+
- [Built-in Dialog Components](#built-in-dialog-components)
|
|
10
|
+
- [Creating Custom Dialogs](#creating-custom-dialogs)
|
|
11
|
+
- [API Reference](#api-reference)
|
|
12
|
+
- [Advanced Usage](#advanced-usage)
|
|
13
|
+
- [Best Practices](#best-practices)
|
|
14
|
+
|
|
15
|
+
## Architecture Overview
|
|
16
|
+
|
|
17
|
+
The dialog system consists of several interconnected components:
|
|
18
|
+
|
|
19
|
+
- **DialogBoard**: Global dialog manager that handles dialog lifecycle
|
|
20
|
+
- **Dialog**: Base dialog component with standard UI elements
|
|
21
|
+
- **CommonDialog**: Pre-configured dialog for common use cases
|
|
22
|
+
- **IDialog**: TypeScript interface for global dialog access
|
|
23
|
+
- **Dialogs Store**: Svelte store managing dialog state
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
graph TD
|
|
27
|
+
A[DialogBoard] --> B[Dialogs Store]
|
|
28
|
+
A --> C[Dialog Components]
|
|
29
|
+
C --> D[Dialog.svelte]
|
|
30
|
+
C --> E[CommonDialog.svelte]
|
|
31
|
+
F[Custom Components] --> A
|
|
32
|
+
G[window.Dialog.showModal] --> A
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## DialogBoard - Global Dialog Manager
|
|
36
|
+
|
|
37
|
+
The `DialogBoard` component manages all modal dialogs in your application and provides global access through the `window.Dialog` API.
|
|
38
|
+
|
|
39
|
+
### Setup
|
|
40
|
+
|
|
41
|
+
Include `DialogBoard` in your root layout:
|
|
42
|
+
|
|
43
|
+
```svelte
|
|
44
|
+
<!-- +layout.svelte or app.html -->
|
|
45
|
+
<script lang="ts">
|
|
46
|
+
import { DialogBoard } from "@ticatec/uniface-element/DialogBoard";
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<!-- Your application content -->
|
|
50
|
+
<main>
|
|
51
|
+
<slot />
|
|
52
|
+
</main>
|
|
53
|
+
|
|
54
|
+
<!-- Global dialog manager -->
|
|
55
|
+
<DialogBoard />
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Global API
|
|
59
|
+
|
|
60
|
+
Once `DialogBoard` is mounted, you can access the dialog system globally:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Open any Svelte component as a modal dialog
|
|
64
|
+
window.Dialog.showModal(MyComponent, {
|
|
65
|
+
// Props to pass to the component
|
|
66
|
+
title: "My Dialog",
|
|
67
|
+
data: someData,
|
|
68
|
+
onSave: (result) => {
|
|
69
|
+
console.log("Saved:", result);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### TypeScript Support
|
|
75
|
+
|
|
76
|
+
Add global type declarations:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// src/app.d.ts
|
|
80
|
+
import type { IDialog } from '@ticatec/uniface-element';
|
|
81
|
+
|
|
82
|
+
declare global {
|
|
83
|
+
interface Window {
|
|
84
|
+
Dialog: IDialog;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Built-in Dialog Components
|
|
90
|
+
|
|
91
|
+
### Dialog Component
|
|
92
|
+
|
|
93
|
+
The base `Dialog` component provides standard dialog functionality:
|
|
94
|
+
|
|
95
|
+
```svelte
|
|
96
|
+
<script lang="ts">
|
|
97
|
+
import Dialog from '@ticatec/uniface-element/Dialog';
|
|
98
|
+
import type { ButtonActions } from '@ticatec/uniface-element';
|
|
99
|
+
|
|
100
|
+
let modalResult = null;
|
|
101
|
+
|
|
102
|
+
const actions: ButtonActions = [
|
|
103
|
+
{
|
|
104
|
+
label: "Save",
|
|
105
|
+
type: "primary",
|
|
106
|
+
handler: async () => {
|
|
107
|
+
// Perform save operation
|
|
108
|
+
await saveData();
|
|
109
|
+
return true; // Return true to auto-close dialog
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const onClose = (result) => {
|
|
115
|
+
console.log("Dialog closed with result:", result);
|
|
116
|
+
};
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<Dialog
|
|
120
|
+
title="My Dialog"
|
|
121
|
+
width="500px"
|
|
122
|
+
height="400px"
|
|
123
|
+
bind:modalResult
|
|
124
|
+
{actions}
|
|
125
|
+
{onClose}
|
|
126
|
+
>
|
|
127
|
+
<!-- Dialog content -->
|
|
128
|
+
<p>This is the dialog content.</p>
|
|
129
|
+
</Dialog>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Dialog Properties
|
|
133
|
+
|
|
134
|
+
| Property | Type | Description |
|
|
135
|
+
|----------|------|-------------|
|
|
136
|
+
| `title` | `string` | Dialog title |
|
|
137
|
+
| `width` | `string` | Dialog width (CSS value) |
|
|
138
|
+
| `height` | `string` | Dialog height (CSS value) |
|
|
139
|
+
| `actions` | `ButtonActions` | Array of action buttons |
|
|
140
|
+
| `closeConfirm` | `DialogCloseConfirm` | Confirmation function for close |
|
|
141
|
+
| `content$style` | `string` | Custom styles for content area |
|
|
142
|
+
| `modalResult` | `ModalResult` | Result binding for programmatic close |
|
|
143
|
+
| `onClose` | `OnClose` | Callback when dialog closes |
|
|
144
|
+
|
|
145
|
+
### CommonDialog Component
|
|
146
|
+
|
|
147
|
+
The `CommonDialog` is a pre-configured dialog for typical use cases:
|
|
148
|
+
|
|
149
|
+
```svelte
|
|
150
|
+
<script lang="ts">
|
|
151
|
+
import CommonDialog, ModalResult from '@ticatec/uniface-element/CommonDialog, ModalResult';
|
|
152
|
+
|
|
153
|
+
export let user: any;
|
|
154
|
+
export let onSave: (user: any) => void;
|
|
155
|
+
|
|
156
|
+
let modalResult = null;
|
|
157
|
+
let enableConfirm = true;
|
|
158
|
+
|
|
159
|
+
const confirmHandler = async () => {
|
|
160
|
+
try {
|
|
161
|
+
await onSave(user);
|
|
162
|
+
return true; // Return true to auto-close
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error("Save failed:", error);
|
|
165
|
+
return false; // Keep dialog open on error
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const onClose = (result) => {
|
|
170
|
+
if (result === ModalResult.Ok) {
|
|
171
|
+
console.log("User saved successfully");
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
</script>
|
|
175
|
+
|
|
176
|
+
<CommonDialog
|
|
177
|
+
title="Edit User"
|
|
178
|
+
width="600px"
|
|
179
|
+
height="500px"
|
|
180
|
+
bind:modalResult
|
|
181
|
+
bind:enableConfirm
|
|
182
|
+
{confirmHandler}
|
|
183
|
+
confirmText="Save Changes"
|
|
184
|
+
{onClose}
|
|
185
|
+
>
|
|
186
|
+
<div class="form-content">
|
|
187
|
+
<label>
|
|
188
|
+
Name:
|
|
189
|
+
<input bind:value={user.name} />
|
|
190
|
+
</label>
|
|
191
|
+
<label>
|
|
192
|
+
Email:
|
|
193
|
+
<input bind:value={user.email} type="email" />
|
|
194
|
+
</label>
|
|
195
|
+
</div>
|
|
196
|
+
</CommonDialog>
|
|
197
|
+
|
|
198
|
+
<style>
|
|
199
|
+
.form-content {
|
|
200
|
+
display: flex;
|
|
201
|
+
flex-direction: column;
|
|
202
|
+
gap: 16px;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
label {
|
|
206
|
+
display: flex;
|
|
207
|
+
flex-direction: column;
|
|
208
|
+
gap: 4px;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
input {
|
|
212
|
+
padding: 8px;
|
|
213
|
+
border: 1px solid #ccc;
|
|
214
|
+
border-radius: 4px;
|
|
215
|
+
}
|
|
216
|
+
</style>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### CommonDialog Properties
|
|
220
|
+
|
|
221
|
+
| Property | Type | Description |
|
|
222
|
+
|----------|------|-------------|
|
|
223
|
+
| `title` | `string` | Dialog title |
|
|
224
|
+
| `width` | `string` | Dialog width |
|
|
225
|
+
| `height` | `string` | Dialog height |
|
|
226
|
+
| `closeConfirm` | `DialogCloseConfirm` | Close confirmation function |
|
|
227
|
+
| `content$style` | `string` | Content area custom styles |
|
|
228
|
+
| `modalResult` | `ModalResult` | Result binding |
|
|
229
|
+
| `enableConfirm` | `boolean` | Enable/disable confirm button |
|
|
230
|
+
| `confirmHandler` | `() => Promise<boolean>` | Confirm button handler |
|
|
231
|
+
| `confirmText` | `string` | Custom confirm button text |
|
|
232
|
+
| `onClose` | `OnClose` | Close callback |
|
|
233
|
+
|
|
234
|
+
## Creating Custom Dialogs
|
|
235
|
+
|
|
236
|
+
### Method 1: Using Global Dialog API
|
|
237
|
+
|
|
238
|
+
```svelte
|
|
239
|
+
<!-- UserEditDialog.svelte -->
|
|
240
|
+
<script lang="ts">
|
|
241
|
+
import { getContext } from 'svelte';
|
|
242
|
+
import CommonDialog, ModalResult from '@ticatec/uniface-element/CommonDialog, ModalResult';
|
|
243
|
+
|
|
244
|
+
export let user: any;
|
|
245
|
+
export let onSave: (user: any) => Promise<void>;
|
|
246
|
+
|
|
247
|
+
// Get close function from context
|
|
248
|
+
const closeDialog = getContext('closeDialog');
|
|
249
|
+
|
|
250
|
+
let saving = false;
|
|
251
|
+
let formData = { ...user };
|
|
252
|
+
let enableConfirm = true;
|
|
253
|
+
|
|
254
|
+
const handleSave = async () => {
|
|
255
|
+
if (saving) return false;
|
|
256
|
+
|
|
257
|
+
saving = true;
|
|
258
|
+
try {
|
|
259
|
+
await onSave(formData);
|
|
260
|
+
return true; // Auto-close on success
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error('Save failed:', error);
|
|
263
|
+
return false; // Keep open on error
|
|
264
|
+
} finally {
|
|
265
|
+
saving = false;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
</script>
|
|
269
|
+
|
|
270
|
+
<CommonDialog
|
|
271
|
+
title="Edit User"
|
|
272
|
+
width="600px"
|
|
273
|
+
height="400px"
|
|
274
|
+
bind:enableConfirm
|
|
275
|
+
confirmHandler={handleSave}
|
|
276
|
+
confirmText={saving ? "Saving..." : "Save Changes"}
|
|
277
|
+
>
|
|
278
|
+
<form class="user-form">
|
|
279
|
+
<div class="field">
|
|
280
|
+
<label for="name">Name:</label>
|
|
281
|
+
<input id="name" bind:value={formData.name} required />
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<div class="field">
|
|
285
|
+
<label for="email">Email:</label>
|
|
286
|
+
<input id="email" type="email" bind:value={formData.email} required />
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div class="field">
|
|
290
|
+
<label for="role">Role:</label>
|
|
291
|
+
<select id="role" bind:value={formData.role}>
|
|
292
|
+
<option value="user">User</option>
|
|
293
|
+
<option value="admin">Admin</option>
|
|
294
|
+
<option value="moderator">Moderator</option>
|
|
295
|
+
</select>
|
|
296
|
+
</div>
|
|
297
|
+
</form>
|
|
298
|
+
</CommonDialog>
|
|
299
|
+
|
|
300
|
+
<style>
|
|
301
|
+
.user-form {
|
|
302
|
+
display: flex;
|
|
303
|
+
flex-direction: column;
|
|
304
|
+
gap: 16px;
|
|
305
|
+
padding: 20px;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.field {
|
|
309
|
+
display: flex;
|
|
310
|
+
flex-direction: column;
|
|
311
|
+
gap: 4px;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
label {
|
|
315
|
+
font-weight: 500;
|
|
316
|
+
color: #374151;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
input, select {
|
|
320
|
+
padding: 8px 12px;
|
|
321
|
+
border: 1px solid #d1d5db;
|
|
322
|
+
border-radius: 6px;
|
|
323
|
+
font-size: 14px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
input:focus, select:focus {
|
|
327
|
+
outline: none;
|
|
328
|
+
border-color: #3b82f6;
|
|
329
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
330
|
+
}
|
|
331
|
+
</style>
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Method 2: Custom Modal Component
|
|
335
|
+
|
|
336
|
+
```svelte
|
|
337
|
+
<!-- ConfirmationDialog.svelte -->
|
|
338
|
+
<script lang="ts">
|
|
339
|
+
import { createEventDispatcher } from 'svelte';
|
|
340
|
+
import Button from '@ticatec/uniface-element/Button';
|
|
341
|
+
|
|
342
|
+
export let title = "Confirm Action";
|
|
343
|
+
export let message = "Are you sure you want to continue?";
|
|
344
|
+
export let confirmText = "Confirm";
|
|
345
|
+
export let cancelText = "Cancel";
|
|
346
|
+
export let danger = false;
|
|
347
|
+
|
|
348
|
+
const dispatch = createEventDispatcher();
|
|
349
|
+
|
|
350
|
+
const handleConfirm = () => {
|
|
351
|
+
dispatch('confirm');
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const handleCancel = () => {
|
|
355
|
+
dispatch('cancel');
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// Handle backdrop click
|
|
359
|
+
const handleBackdrop = (e) => {
|
|
360
|
+
if (e.target === e.currentTarget) {
|
|
361
|
+
handleCancel();
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
</script>
|
|
365
|
+
|
|
366
|
+
<div class="modal-backdrop" on:click={handleBackdrop}>
|
|
367
|
+
<div class="confirmation-dialog" role="dialog" aria-labelledby="dialog-title">
|
|
368
|
+
<div class="dialog-header">
|
|
369
|
+
<h2 id="dialog-title">{title}</h2>
|
|
370
|
+
</div>
|
|
371
|
+
|
|
372
|
+
<div class="dialog-body">
|
|
373
|
+
<p>{message}</p>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
<div class="dialog-footer">
|
|
377
|
+
<Button
|
|
378
|
+
label={cancelText}
|
|
379
|
+
type="secondary"
|
|
380
|
+
onClick={handleCancel}
|
|
381
|
+
/>
|
|
382
|
+
<Button
|
|
383
|
+
label={confirmText}
|
|
384
|
+
type={danger ? "third" : "primary"}
|
|
385
|
+
onClick={handleConfirm}
|
|
386
|
+
/>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
|
|
391
|
+
<style>
|
|
392
|
+
.modal-backdrop {
|
|
393
|
+
position: fixed;
|
|
394
|
+
top: 0;
|
|
395
|
+
left: 0;
|
|
396
|
+
width: 100%;
|
|
397
|
+
height: 100%;
|
|
398
|
+
background: rgba(0, 0, 0, 0.5);
|
|
399
|
+
display: flex;
|
|
400
|
+
align-items: center;
|
|
401
|
+
justify-content: center;
|
|
402
|
+
z-index: 1000;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.confirmation-dialog {
|
|
406
|
+
background: white;
|
|
407
|
+
border-radius: 8px;
|
|
408
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
|
409
|
+
max-width: 400px;
|
|
410
|
+
width: 90%;
|
|
411
|
+
max-height: 90vh;
|
|
412
|
+
overflow: hidden;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.dialog-header {
|
|
416
|
+
padding: 20px 20px 0;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.dialog-header h2 {
|
|
420
|
+
margin: 0;
|
|
421
|
+
font-size: 1.25rem;
|
|
422
|
+
color: #374151;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.dialog-body {
|
|
426
|
+
padding: 16px 20px;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.dialog-body p {
|
|
430
|
+
margin: 0;
|
|
431
|
+
color: #6b7280;
|
|
432
|
+
line-height: 1.5;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.dialog-footer {
|
|
436
|
+
padding: 16px 20px 20px;
|
|
437
|
+
display: flex;
|
|
438
|
+
justify-content: flex-end;
|
|
439
|
+
gap: 12px;
|
|
440
|
+
}
|
|
441
|
+
</style>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Advanced Usage
|
|
445
|
+
|
|
446
|
+
### Dialog with Form Validation
|
|
447
|
+
|
|
448
|
+
```svelte
|
|
449
|
+
<script lang="ts">
|
|
450
|
+
import CommonDialog from '@ticatec/uniface-element/CommonDialog';
|
|
451
|
+
|
|
452
|
+
export let product: any;
|
|
453
|
+
export let onSave: (product: any) => Promise<void>;
|
|
454
|
+
|
|
455
|
+
let formData = { ...product };
|
|
456
|
+
let errors = {};
|
|
457
|
+
let saving = false;
|
|
458
|
+
|
|
459
|
+
$: enableConfirm = isFormValid(formData) && !saving;
|
|
460
|
+
|
|
461
|
+
const isFormValid = (data) => {
|
|
462
|
+
const newErrors = {};
|
|
463
|
+
|
|
464
|
+
if (!data.name?.trim()) {
|
|
465
|
+
newErrors.name = "Product name is required";
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (!data.price || data.price <= 0) {
|
|
469
|
+
newErrors.price = "Price must be greater than 0";
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (!data.category) {
|
|
473
|
+
newErrors.category = "Category is required";
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
errors = newErrors;
|
|
477
|
+
return Object.keys(newErrors).length === 0;
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
const handleSave = async () => {
|
|
481
|
+
if (!isFormValid(formData) || saving) {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
saving = true;
|
|
486
|
+
try {
|
|
487
|
+
await onSave(formData);
|
|
488
|
+
return true;
|
|
489
|
+
} catch (error) {
|
|
490
|
+
console.error('Save failed:', error);
|
|
491
|
+
return false;
|
|
492
|
+
} finally {
|
|
493
|
+
saving = false;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
</script>
|
|
497
|
+
|
|
498
|
+
<CommonDialog
|
|
499
|
+
title="Edit Product"
|
|
500
|
+
width="700px"
|
|
501
|
+
height="600px"
|
|
502
|
+
bind:enableConfirm
|
|
503
|
+
confirmHandler={handleSave}
|
|
504
|
+
confirmText={saving ? "Saving..." : "Save Product"}
|
|
505
|
+
>
|
|
506
|
+
<form class="product-form">
|
|
507
|
+
<div class="field">
|
|
508
|
+
<label for="name">Product Name *</label>
|
|
509
|
+
<input
|
|
510
|
+
id="name"
|
|
511
|
+
bind:value={formData.name}
|
|
512
|
+
class:error={errors.name}
|
|
513
|
+
placeholder="Enter product name"
|
|
514
|
+
/>
|
|
515
|
+
{#if errors.name}
|
|
516
|
+
<span class="error-text">{errors.name}</span>
|
|
517
|
+
{/if}
|
|
518
|
+
</div>
|
|
519
|
+
|
|
520
|
+
<div class="field">
|
|
521
|
+
<label for="price">Price *</label>
|
|
522
|
+
<input
|
|
523
|
+
id="price"
|
|
524
|
+
type="number"
|
|
525
|
+
min="0"
|
|
526
|
+
step="0.01"
|
|
527
|
+
bind:value={formData.price}
|
|
528
|
+
class:error={errors.price}
|
|
529
|
+
placeholder="0.00"
|
|
530
|
+
/>
|
|
531
|
+
{#if errors.price}
|
|
532
|
+
<span class="error-text">{errors.price}</span>
|
|
533
|
+
{/if}
|
|
534
|
+
</div>
|
|
535
|
+
|
|
536
|
+
<div class="field">
|
|
537
|
+
<label for="category">Category *</label>
|
|
538
|
+
<select
|
|
539
|
+
id="category"
|
|
540
|
+
bind:value={formData.category}
|
|
541
|
+
class:error={errors.category}
|
|
542
|
+
>
|
|
543
|
+
<option value="">Select category</option>
|
|
544
|
+
<option value="electronics">Electronics</option>
|
|
545
|
+
<option value="clothing">Clothing</option>
|
|
546
|
+
<option value="books">Books</option>
|
|
547
|
+
<option value="home">Home & Garden</option>
|
|
548
|
+
</select>
|
|
549
|
+
{#if errors.category}
|
|
550
|
+
<span class="error-text">{errors.category}</span>
|
|
551
|
+
{/if}
|
|
552
|
+
</div>
|
|
553
|
+
|
|
554
|
+
<div class="field">
|
|
555
|
+
<label for="description">Description</label>
|
|
556
|
+
<textarea
|
|
557
|
+
id="description"
|
|
558
|
+
bind:value={formData.description}
|
|
559
|
+
placeholder="Product description (optional)"
|
|
560
|
+
rows="4"
|
|
561
|
+
></textarea>
|
|
562
|
+
</div>
|
|
563
|
+
</form>
|
|
564
|
+
</CommonDialog>
|
|
565
|
+
|
|
566
|
+
<style>
|
|
567
|
+
.product-form {
|
|
568
|
+
padding: 20px;
|
|
569
|
+
display: flex;
|
|
570
|
+
flex-direction: column;
|
|
571
|
+
gap: 16px;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.field {
|
|
575
|
+
display: flex;
|
|
576
|
+
flex-direction: column;
|
|
577
|
+
gap: 4px;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
label {
|
|
581
|
+
font-weight: 500;
|
|
582
|
+
color: #374151;
|
|
583
|
+
font-size: 14px;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
input, select, textarea {
|
|
587
|
+
padding: 8px 12px;
|
|
588
|
+
border: 1px solid #d1d5db;
|
|
589
|
+
border-radius: 6px;
|
|
590
|
+
font-size: 14px;
|
|
591
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
input:focus, select:focus, textarea:focus {
|
|
595
|
+
outline: none;
|
|
596
|
+
border-color: #3b82f6;
|
|
597
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
input.error, select.error, textarea.error {
|
|
601
|
+
border-color: #ef4444;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.error-text {
|
|
605
|
+
color: #ef4444;
|
|
606
|
+
font-size: 12px;
|
|
607
|
+
margin-top: 2px;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
textarea {
|
|
611
|
+
resize: vertical;
|
|
612
|
+
min-height: 80px;
|
|
613
|
+
}
|
|
614
|
+
</style>
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
## API Reference
|
|
618
|
+
|
|
619
|
+
### Global Dialog Interface
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
interface IDialog {
|
|
623
|
+
showModal<T>(component: any, props?: T): void;
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### ModalResult Enum
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
enum ModalResult {
|
|
631
|
+
None = 0,
|
|
632
|
+
Ok = 1,
|
|
633
|
+
Cancel = 2,
|
|
634
|
+
Abort = 3,
|
|
635
|
+
Retry = 4,
|
|
636
|
+
Ignore = 5,
|
|
637
|
+
Yes = 6,
|
|
638
|
+
No = 7
|
|
639
|
+
}
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Event Handlers
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
type OnClose = (result: ModalResult) => void;
|
|
646
|
+
type DialogCloseConfirm = () => Promise<boolean>;
|
|
647
|
+
type ConfirmHandler = () => Promise<boolean>;
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
## Best Practices
|
|
651
|
+
|
|
652
|
+
### 1. Use Appropriate Dialog Sizes
|
|
653
|
+
|
|
654
|
+
```svelte
|
|
655
|
+
<!-- Small confirmation dialogs -->
|
|
656
|
+
<CommonDialog width="400px" height="200px">
|
|
657
|
+
|
|
658
|
+
<!-- Form dialogs -->
|
|
659
|
+
<CommonDialog width="600px" height="500px">
|
|
660
|
+
|
|
661
|
+
<!-- Large content dialogs -->
|
|
662
|
+
<CommonDialog width="800px" height="700px">
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### 2. Handle Loading States
|
|
666
|
+
|
|
667
|
+
```svelte
|
|
668
|
+
<script>
|
|
669
|
+
let saving = false;
|
|
670
|
+
let enableConfirm = true;
|
|
671
|
+
|
|
672
|
+
const handleSave = async () => {
|
|
673
|
+
saving = true;
|
|
674
|
+
enableConfirm = false;
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
await saveData();
|
|
678
|
+
return true; // Close dialog
|
|
679
|
+
} catch (error) {
|
|
680
|
+
// Handle error, keep dialog open
|
|
681
|
+
return false;
|
|
682
|
+
} finally {
|
|
683
|
+
saving = false;
|
|
684
|
+
enableConfirm = true;
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
</script>
|
|
688
|
+
|
|
689
|
+
<CommonDialog
|
|
690
|
+
bind:enableConfirm
|
|
691
|
+
confirmHandler={handleSave}
|
|
692
|
+
confirmText={saving ? "Saving..." : "Save"}
|
|
693
|
+
>
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
### 3. Implement Proper Validation
|
|
697
|
+
|
|
698
|
+
```svelte
|
|
699
|
+
<script>
|
|
700
|
+
let formData = { name: '', email: '' };
|
|
701
|
+
let errors = {};
|
|
702
|
+
|
|
703
|
+
$: enableConfirm = isValid(formData);
|
|
704
|
+
|
|
705
|
+
const isValid = (data) => {
|
|
706
|
+
return data.name.trim() &&
|
|
707
|
+
data.email.trim() &&
|
|
708
|
+
data.email.includes('@');
|
|
709
|
+
};
|
|
710
|
+
</script>
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
### 4. Use Context for Complex Dialogs
|
|
714
|
+
|
|
715
|
+
```svelte
|
|
716
|
+
<script>
|
|
717
|
+
import { setContext } from 'svelte';
|
|
718
|
+
|
|
719
|
+
// Provide helper functions to child components
|
|
720
|
+
setContext('showNotification', (message) => {
|
|
721
|
+
// Show notification
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
setContext('closeDialog', () => {
|
|
725
|
+
modalResult = ModalResult.Cancel;
|
|
726
|
+
});
|
|
727
|
+
</script>
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### 5. Keyboard Navigation Support
|
|
731
|
+
|
|
732
|
+
```svelte
|
|
733
|
+
<script>
|
|
734
|
+
import { onMount } from 'svelte';
|
|
735
|
+
|
|
736
|
+
onMount(() => {
|
|
737
|
+
const handleKeydown = (e) => {
|
|
738
|
+
if (e.key === 'Escape') {
|
|
739
|
+
handleCancel();
|
|
740
|
+
} else if (e.key === 'Enter' && e.ctrlKey) {
|
|
741
|
+
handleConfirm();
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
document.addEventListener('keydown', handleKeydown);
|
|
746
|
+
|
|
747
|
+
return () => {
|
|
748
|
+
document.removeEventListener('keydown', handleKeydown);
|
|
749
|
+
};
|
|
750
|
+
});
|
|
751
|
+
</script>
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
## Accessibility Considerations
|
|
755
|
+
|
|
756
|
+
- Always provide proper `aria-labelledby` and `role="dialog"` attributes
|
|
757
|
+
- Ensure keyboard navigation works (Tab, Enter, Escape)
|
|
758
|
+
- Focus management - focus should be trapped within the dialog
|
|
759
|
+
- Provide clear visual indicators for required fields
|
|
760
|
+
- Use semantic HTML elements within dialog content
|
|
761
|
+
- Ensure sufficient color contrast for all text and interactive elements
|
|
762
|
+
|
|
763
|
+
## Browser Support
|
|
764
|
+
|
|
765
|
+
- Modern browsers with ES2020+ support
|
|
766
|
+
- CSS Grid and Flexbox support required for layout
|
|
767
|
+
- JavaScript Proxy support needed for reactive stores
|