@ticatec/uniface-element 0.2.0 → 0.2.1
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 +273 -1
- package/README_CN.md +341 -0
- package/dist/common/MouseClickHandler.d.ts +1 -1
- package/dist/dialog/CommonDialog.svelte +6 -3
- package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
- package/dist/dialog/Dialog.svelte +36 -10
- 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/dialog/DialogWrapper.svelte.d.ts +22 -0
- package/dist/dialog/Dialogs.js +1 -1
- package/dist/dialog/ModalResult.d.ts +5 -0
- package/dist/dialog/ModalResult.js +5 -0
- 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 +38 -5
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
# GridForm Component
|
|
2
|
+
|
|
3
|
+
Grid-based form layout component providing CSS Grid-based form container with support for flexible grid layouts and field arrangements.
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
| Property | Type | Default | Description |
|
|
8
|
+
|----------|------|---------|-------------|
|
|
9
|
+
| `style` | `string` | `''` | Custom styles |
|
|
10
|
+
| `columns` | `number` | `6` | Number of grid columns |
|
|
11
|
+
| `fieldLayout` | `'vertical' \| 'horizontal'` | `'vertical'` | Field layout direction |
|
|
12
|
+
|
|
13
|
+
## Usage Examples
|
|
14
|
+
|
|
15
|
+
### Basic Grid Form
|
|
16
|
+
|
|
17
|
+
```svelte
|
|
18
|
+
<script lang="ts">
|
|
19
|
+
import GridForm, FormField, TextEditor, NumberEditor, OptionsSelect from '@ticatec/uniface-element/GridForm, FormField, TextEditor, NumberEditor, OptionsSelect';
|
|
20
|
+
|
|
21
|
+
interface UserProfile {
|
|
22
|
+
firstName: string;
|
|
23
|
+
lastName: string;
|
|
24
|
+
age: number | null;
|
|
25
|
+
gender: string;
|
|
26
|
+
email: string;
|
|
27
|
+
phone: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let userProfile: UserProfile = {
|
|
31
|
+
firstName: '',
|
|
32
|
+
lastName: '',
|
|
33
|
+
age: null,
|
|
34
|
+
gender: '',
|
|
35
|
+
email: '',
|
|
36
|
+
phone: ''
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const genderOptions = [
|
|
40
|
+
{ code: 'male', text: 'Male' },
|
|
41
|
+
{ code: 'female', text: 'Female' },
|
|
42
|
+
{ code: 'other', text: 'Other' }
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const handleSubmit = (): void => {
|
|
46
|
+
console.log('Submit user info:', userProfile);
|
|
47
|
+
};
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<!-- 6-column grid layout -->
|
|
51
|
+
<GridForm columns={6} fieldLayout="vertical">
|
|
52
|
+
<FormField label="First Name" style="grid-column: span 2;">
|
|
53
|
+
<TextEditor
|
|
54
|
+
placeholder="Enter first name"
|
|
55
|
+
bind:value={userProfile.firstName}
|
|
56
|
+
/>
|
|
57
|
+
</FormField>
|
|
58
|
+
|
|
59
|
+
<FormField label="Last Name" style="grid-column: span 2;">
|
|
60
|
+
<TextEditor
|
|
61
|
+
placeholder="Enter last name"
|
|
62
|
+
bind:value={userProfile.lastName}
|
|
63
|
+
/>
|
|
64
|
+
</FormField>
|
|
65
|
+
|
|
66
|
+
<FormField label="Age" style="grid-column: span 2;">
|
|
67
|
+
<NumberEditor
|
|
68
|
+
placeholder="Enter age"
|
|
69
|
+
min={1}
|
|
70
|
+
max={120}
|
|
71
|
+
bind:value={userProfile.age}
|
|
72
|
+
/>
|
|
73
|
+
</FormField>
|
|
74
|
+
|
|
75
|
+
<FormField label="Gender" style="grid-column: span 3;">
|
|
76
|
+
<OptionsSelect
|
|
77
|
+
options={genderOptions}
|
|
78
|
+
keyField="code"
|
|
79
|
+
textField="text"
|
|
80
|
+
bind:value={userProfile.gender}
|
|
81
|
+
/>
|
|
82
|
+
</FormField>
|
|
83
|
+
|
|
84
|
+
<FormField label="Phone" style="grid-column: span 3;">
|
|
85
|
+
<TextEditor
|
|
86
|
+
placeholder="Enter phone number"
|
|
87
|
+
bind:value={userProfile.phone}
|
|
88
|
+
/>
|
|
89
|
+
</FormField>
|
|
90
|
+
|
|
91
|
+
<FormField label="Email" style="grid-column: span 6;">
|
|
92
|
+
<TextEditor
|
|
93
|
+
placeholder="Enter email address"
|
|
94
|
+
bind:value={userProfile.email}
|
|
95
|
+
/>
|
|
96
|
+
</FormField>
|
|
97
|
+
|
|
98
|
+
<div style="grid-column: span 6;" class="form-actions">
|
|
99
|
+
<button type="button" on:click={handleSubmit}>
|
|
100
|
+
Submit
|
|
101
|
+
</button>
|
|
102
|
+
</div>
|
|
103
|
+
</GridForm>
|
|
104
|
+
|
|
105
|
+
<style>
|
|
106
|
+
.form-actions {
|
|
107
|
+
display: flex;
|
|
108
|
+
justify-content: center;
|
|
109
|
+
margin-top: 20px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.form-actions button {
|
|
113
|
+
padding: 10px 24px;
|
|
114
|
+
background: #007bff;
|
|
115
|
+
color: white;
|
|
116
|
+
border: none;
|
|
117
|
+
border-radius: 4px;
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.form-actions button:hover {
|
|
122
|
+
background: #0056b3;
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Complex Grid Form Layout
|
|
128
|
+
|
|
129
|
+
```svelte
|
|
130
|
+
<script lang="ts">
|
|
131
|
+
import GridForm, FormField, TextEditor, NumberEditor, DatePicker, OptionsSelect, CheckBox from '@ticatec/uniface-element/GridForm, FormField, TextEditor, NumberEditor, DatePicker, OptionsSelect, CheckBox';
|
|
132
|
+
|
|
133
|
+
interface ProductForm {
|
|
134
|
+
basicInfo: {
|
|
135
|
+
name: string;
|
|
136
|
+
category: string;
|
|
137
|
+
brand: string;
|
|
138
|
+
model: string;
|
|
139
|
+
};
|
|
140
|
+
pricing: {
|
|
141
|
+
cost: number | null;
|
|
142
|
+
price: number | null;
|
|
143
|
+
discount: number | null;
|
|
144
|
+
};
|
|
145
|
+
inventory: {
|
|
146
|
+
stock: number | null;
|
|
147
|
+
minStock: number | null;
|
|
148
|
+
maxStock: number | null;
|
|
149
|
+
};
|
|
150
|
+
details: {
|
|
151
|
+
description: string;
|
|
152
|
+
specifications: string;
|
|
153
|
+
launchDate: Date | null;
|
|
154
|
+
};
|
|
155
|
+
settings: {
|
|
156
|
+
isActive: boolean;
|
|
157
|
+
isFeatured: boolean;
|
|
158
|
+
allowBackorder: boolean;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let productData: ProductForm = {
|
|
163
|
+
basicInfo: {
|
|
164
|
+
name: '',
|
|
165
|
+
category: '',
|
|
166
|
+
brand: '',
|
|
167
|
+
model: ''
|
|
168
|
+
},
|
|
169
|
+
pricing: {
|
|
170
|
+
cost: null,
|
|
171
|
+
price: null,
|
|
172
|
+
discount: null
|
|
173
|
+
},
|
|
174
|
+
inventory: {
|
|
175
|
+
stock: null,
|
|
176
|
+
minStock: null,
|
|
177
|
+
maxStock: null
|
|
178
|
+
},
|
|
179
|
+
details: {
|
|
180
|
+
description: '',
|
|
181
|
+
specifications: '',
|
|
182
|
+
launchDate: null
|
|
183
|
+
},
|
|
184
|
+
settings: {
|
|
185
|
+
isActive: true,
|
|
186
|
+
isFeatured: false,
|
|
187
|
+
allowBackorder: false
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const categoryOptions = [
|
|
192
|
+
{ code: 'electronics', text: 'Electronics' },
|
|
193
|
+
{ code: 'clothing', text: 'Clothing' },
|
|
194
|
+
{ code: 'books', text: 'Books' },
|
|
195
|
+
{ code: 'home', text: 'Home & Garden' }
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
const validateForm = (): boolean => {
|
|
199
|
+
return productData.basicInfo.name.length > 0 &&
|
|
200
|
+
productData.basicInfo.category.length > 0 &&
|
|
201
|
+
productData.pricing.price !== null;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const handleSave = (): void => {
|
|
205
|
+
if (validateForm()) {
|
|
206
|
+
console.log('Save product info:', productData);
|
|
207
|
+
} else {
|
|
208
|
+
alert('Please fill in required fields');
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
</script>
|
|
212
|
+
|
|
213
|
+
<div class="product-form">
|
|
214
|
+
<h2>Product Information Form</h2>
|
|
215
|
+
|
|
216
|
+
<GridForm columns={12} fieldLayout="vertical">
|
|
217
|
+
<!-- Basic Information Section -->
|
|
218
|
+
<div style="grid-column: span 12;" class="section-header">
|
|
219
|
+
<h3>Basic Information</h3>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
<FormField label="Product Name" required style="grid-column: span 6;">
|
|
223
|
+
<TextEditor
|
|
224
|
+
placeholder="Enter product name"
|
|
225
|
+
bind:value={productData.basicInfo.name}
|
|
226
|
+
/>
|
|
227
|
+
</FormField>
|
|
228
|
+
|
|
229
|
+
<FormField label="Category" required style="grid-column: span 3;">
|
|
230
|
+
<OptionsSelect
|
|
231
|
+
options={categoryOptions}
|
|
232
|
+
keyField="code"
|
|
233
|
+
textField="text"
|
|
234
|
+
placeholder="Select category"
|
|
235
|
+
bind:value={productData.basicInfo.category}
|
|
236
|
+
/>
|
|
237
|
+
</FormField>
|
|
238
|
+
|
|
239
|
+
<FormField label="Brand" style="grid-column: span 3;">
|
|
240
|
+
<TextEditor
|
|
241
|
+
placeholder="Enter brand"
|
|
242
|
+
bind:value={productData.basicInfo.brand}
|
|
243
|
+
/>
|
|
244
|
+
</FormField>
|
|
245
|
+
|
|
246
|
+
<FormField label="Model" style="grid-column: span 6;">
|
|
247
|
+
<TextEditor
|
|
248
|
+
placeholder="Enter product model"
|
|
249
|
+
bind:value={productData.basicInfo.model}
|
|
250
|
+
/>
|
|
251
|
+
</FormField>
|
|
252
|
+
|
|
253
|
+
<FormField label="Launch Date" style="grid-column: span 6;">
|
|
254
|
+
<DatePicker bind:value={productData.details.launchDate} />
|
|
255
|
+
</FormField>
|
|
256
|
+
|
|
257
|
+
<!-- Pricing Information Section -->
|
|
258
|
+
<div style="grid-column: span 12;" class="section-header">
|
|
259
|
+
<h3>Pricing Information</h3>
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
<FormField label="Cost Price" style="grid-column: span 4;">
|
|
263
|
+
<NumberEditor
|
|
264
|
+
placeholder="Enter cost price"
|
|
265
|
+
min={0}
|
|
266
|
+
precision={2}
|
|
267
|
+
bind:value={productData.pricing.cost}
|
|
268
|
+
/>
|
|
269
|
+
</FormField>
|
|
270
|
+
|
|
271
|
+
<FormField label="Sale Price" required style="grid-column: span 4;">
|
|
272
|
+
<NumberEditor
|
|
273
|
+
placeholder="Enter sale price"
|
|
274
|
+
min={0}
|
|
275
|
+
precision={2}
|
|
276
|
+
bind:value={productData.pricing.price}
|
|
277
|
+
/>
|
|
278
|
+
</FormField>
|
|
279
|
+
|
|
280
|
+
<FormField label="Discount (%)" style="grid-column: span 4;">
|
|
281
|
+
<NumberEditor
|
|
282
|
+
placeholder="Enter discount"
|
|
283
|
+
min={0}
|
|
284
|
+
max={100}
|
|
285
|
+
precision={1}
|
|
286
|
+
bind:value={productData.pricing.discount}
|
|
287
|
+
/>
|
|
288
|
+
</FormField>
|
|
289
|
+
|
|
290
|
+
<!-- Inventory Information Section -->
|
|
291
|
+
<div style="grid-column: span 12;" class="section-header">
|
|
292
|
+
<h3>Inventory Information</h3>
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
<FormField label="Current Stock" style="grid-column: span 4;">
|
|
296
|
+
<NumberEditor
|
|
297
|
+
placeholder="Enter stock quantity"
|
|
298
|
+
min={0}
|
|
299
|
+
bind:value={productData.inventory.stock}
|
|
300
|
+
/>
|
|
301
|
+
</FormField>
|
|
302
|
+
|
|
303
|
+
<FormField label="Minimum Stock" style="grid-column: span 4;">
|
|
304
|
+
<NumberEditor
|
|
305
|
+
placeholder="Enter minimum stock"
|
|
306
|
+
min={0}
|
|
307
|
+
bind:value={productData.inventory.minStock}
|
|
308
|
+
/>
|
|
309
|
+
</FormField>
|
|
310
|
+
|
|
311
|
+
<FormField label="Maximum Stock" style="grid-column: span 4;">
|
|
312
|
+
<NumberEditor
|
|
313
|
+
placeholder="Enter maximum stock"
|
|
314
|
+
min={0}
|
|
315
|
+
bind:value={productData.inventory.maxStock}
|
|
316
|
+
/>
|
|
317
|
+
</FormField>
|
|
318
|
+
|
|
319
|
+
<!-- Details Section -->
|
|
320
|
+
<div style="grid-column: span 12;" class="section-header">
|
|
321
|
+
<h3>Product Details</h3>
|
|
322
|
+
</div>
|
|
323
|
+
|
|
324
|
+
<FormField label="Description" style="grid-column: span 6;">
|
|
325
|
+
<TextEditor
|
|
326
|
+
multiline
|
|
327
|
+
rows={4}
|
|
328
|
+
placeholder="Enter product description"
|
|
329
|
+
bind:value={productData.details.description}
|
|
330
|
+
/>
|
|
331
|
+
</FormField>
|
|
332
|
+
|
|
333
|
+
<FormField label="Specifications" style="grid-column: span 6;">
|
|
334
|
+
<TextEditor
|
|
335
|
+
multiline
|
|
336
|
+
rows={4}
|
|
337
|
+
placeholder="Enter technical specifications"
|
|
338
|
+
bind:value={productData.details.specifications}
|
|
339
|
+
/>
|
|
340
|
+
</FormField>
|
|
341
|
+
|
|
342
|
+
<!-- Settings Section -->
|
|
343
|
+
<div style="grid-column: span 12;" class="section-header">
|
|
344
|
+
<h3>Settings</h3>
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
<FormField label="" style="grid-column: span 4;">
|
|
348
|
+
<CheckBox
|
|
349
|
+
label="Active Product"
|
|
350
|
+
bind:value={productData.settings.isActive}
|
|
351
|
+
/>
|
|
352
|
+
</FormField>
|
|
353
|
+
|
|
354
|
+
<FormField label="" style="grid-column: span 4;">
|
|
355
|
+
<CheckBox
|
|
356
|
+
label="Featured Product"
|
|
357
|
+
bind:value={productData.settings.isFeatured}
|
|
358
|
+
/>
|
|
359
|
+
</FormField>
|
|
360
|
+
|
|
361
|
+
<FormField label="" style="grid-column: span 4;">
|
|
362
|
+
<CheckBox
|
|
363
|
+
label="Allow Backorder"
|
|
364
|
+
bind:value={productData.settings.allowBackorder}
|
|
365
|
+
/>
|
|
366
|
+
</FormField>
|
|
367
|
+
|
|
368
|
+
<!-- Action Buttons -->
|
|
369
|
+
<div style="grid-column: span 12;" class="form-actions">
|
|
370
|
+
<button type="button" class="btn-secondary">
|
|
371
|
+
Cancel
|
|
372
|
+
</button>
|
|
373
|
+
<button type="button" class="btn-primary" on:click={handleSave}>
|
|
374
|
+
Save Product
|
|
375
|
+
</button>
|
|
376
|
+
</div>
|
|
377
|
+
</GridForm>
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<style>
|
|
381
|
+
.product-form {
|
|
382
|
+
max-width: 1000px;
|
|
383
|
+
margin: 0 auto;
|
|
384
|
+
padding: 20px;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.product-form h2 {
|
|
388
|
+
margin-bottom: 30px;
|
|
389
|
+
color: #333;
|
|
390
|
+
text-align: center;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.section-header {
|
|
394
|
+
margin: 20px 0 10px 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.section-header h3 {
|
|
398
|
+
margin: 0;
|
|
399
|
+
padding: 10px 0;
|
|
400
|
+
color: #495057;
|
|
401
|
+
font-size: 16px;
|
|
402
|
+
border-bottom: 2px solid #007bff;
|
|
403
|
+
background: linear-gradient(90deg, #f8f9fa 0%, transparent 100%);
|
|
404
|
+
padding-left: 10px;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.form-actions {
|
|
408
|
+
display: flex;
|
|
409
|
+
gap: 15px;
|
|
410
|
+
justify-content: center;
|
|
411
|
+
margin-top: 30px;
|
|
412
|
+
padding-top: 20px;
|
|
413
|
+
border-top: 1px solid #dee2e6;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.btn-primary, .btn-secondary {
|
|
417
|
+
padding: 12px 24px;
|
|
418
|
+
border: none;
|
|
419
|
+
border-radius: 4px;
|
|
420
|
+
font-size: 14px;
|
|
421
|
+
font-weight: 500;
|
|
422
|
+
cursor: pointer;
|
|
423
|
+
transition: all 0.2s;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.btn-primary {
|
|
427
|
+
background: #007bff;
|
|
428
|
+
color: white;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.btn-secondary {
|
|
432
|
+
background: #6c757d;
|
|
433
|
+
color: white;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.btn-primary:hover {
|
|
437
|
+
background: #0056b3;
|
|
438
|
+
transform: translateY(-1px);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.btn-secondary:hover {
|
|
442
|
+
background: #545b62;
|
|
443
|
+
transform: translateY(-1px);
|
|
444
|
+
}
|
|
445
|
+
</style>
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Responsive Grid Form
|
|
449
|
+
|
|
450
|
+
```svelte
|
|
451
|
+
<script lang="ts">
|
|
452
|
+
import { onMount } from 'svelte';
|
|
453
|
+
|
|
454
|
+
let screenWidth: number = 0;
|
|
455
|
+
|
|
456
|
+
const updateScreenWidth = (): void => {
|
|
457
|
+
screenWidth = window.innerWidth;
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
onMount(() => {
|
|
461
|
+
updateScreenWidth();
|
|
462
|
+
window.addEventListener('resize', updateScreenWidth);
|
|
463
|
+
return () => window.removeEventListener('resize', updateScreenWidth);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// Responsive column calculation
|
|
467
|
+
$: columns = screenWidth < 768 ? 2 : (screenWidth < 1024 ? 4 : 6);
|
|
468
|
+
$: fieldLayout = screenWidth < 768 ? 'vertical' : 'horizontal';
|
|
469
|
+
|
|
470
|
+
interface ContactForm {
|
|
471
|
+
name: string;
|
|
472
|
+
email: string;
|
|
473
|
+
phone: string;
|
|
474
|
+
address: string;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
let contactData: ContactForm = {
|
|
478
|
+
name: '',
|
|
479
|
+
email: '',
|
|
480
|
+
phone: '',
|
|
481
|
+
address: ''
|
|
482
|
+
};
|
|
483
|
+
</script>
|
|
484
|
+
|
|
485
|
+
<div class="responsive-form">
|
|
486
|
+
<h3>Responsive Grid Form (Current columns: {columns})</h3>
|
|
487
|
+
|
|
488
|
+
<GridForm {columns} {fieldLayout}>
|
|
489
|
+
<FormField
|
|
490
|
+
label="Name"
|
|
491
|
+
style="grid-column: span {Math.min(columns, 3)};"
|
|
492
|
+
>
|
|
493
|
+
<TextEditor bind:value={contactData.name} />
|
|
494
|
+
</FormField>
|
|
495
|
+
|
|
496
|
+
<FormField
|
|
497
|
+
label="Email"
|
|
498
|
+
style="grid-column: span {Math.min(columns, 3)};"
|
|
499
|
+
>
|
|
500
|
+
<TextEditor bind:value={contactData.email} />
|
|
501
|
+
</FormField>
|
|
502
|
+
|
|
503
|
+
<FormField
|
|
504
|
+
label="Phone"
|
|
505
|
+
style="grid-column: span {Math.min(columns, 2)};"
|
|
506
|
+
>
|
|
507
|
+
<TextEditor bind:value={contactData.phone} />
|
|
508
|
+
</FormField>
|
|
509
|
+
|
|
510
|
+
<FormField
|
|
511
|
+
label="Address"
|
|
512
|
+
style="grid-column: span {columns};"
|
|
513
|
+
>
|
|
514
|
+
<TextEditor
|
|
515
|
+
multiline
|
|
516
|
+
rows={2}
|
|
517
|
+
bind:value={contactData.address}
|
|
518
|
+
/>
|
|
519
|
+
</FormField>
|
|
520
|
+
</GridForm>
|
|
521
|
+
</div>
|
|
522
|
+
|
|
523
|
+
<style>
|
|
524
|
+
.responsive-form {
|
|
525
|
+
max-width: 800px;
|
|
526
|
+
margin: 0 auto;
|
|
527
|
+
padding: 20px;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.responsive-form h3 {
|
|
531
|
+
margin-bottom: 20px;
|
|
532
|
+
color: #495057;
|
|
533
|
+
text-align: center;
|
|
534
|
+
}
|
|
535
|
+
</style>
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
## Grid Column Spanning Control
|
|
539
|
+
|
|
540
|
+
Use CSS Grid's `grid-column: span X` syntax to control the number of columns a field occupies:
|
|
541
|
+
|
|
542
|
+
```svelte
|
|
543
|
+
<GridForm columns={12}>
|
|
544
|
+
<!-- Span 2 columns -->
|
|
545
|
+
<FormField label="Name" style="grid-column: span 2;">
|
|
546
|
+
<TextEditor />
|
|
547
|
+
</FormField>
|
|
548
|
+
|
|
549
|
+
<!-- Span 4 columns -->
|
|
550
|
+
<FormField label="Email Address" style="grid-column: span 4;">
|
|
551
|
+
<TextEditor />
|
|
552
|
+
</FormField>
|
|
553
|
+
|
|
554
|
+
<!-- Span 6 columns -->
|
|
555
|
+
<FormField label="Detailed Address" style="grid-column: span 6;">
|
|
556
|
+
<TextEditor />
|
|
557
|
+
</FormField>
|
|
558
|
+
|
|
559
|
+
<!-- Span full row (12 columns) -->
|
|
560
|
+
<FormField label="Notes" style="grid-column: span 12;">
|
|
561
|
+
<TextEditor multiline rows={3} />
|
|
562
|
+
</FormField>
|
|
563
|
+
</GridForm>
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## Common Column Configurations
|
|
567
|
+
|
|
568
|
+
| Columns | Use Case | Typical Usage |
|
|
569
|
+
|---------|----------|---------------|
|
|
570
|
+
| 2 | Mobile or simple forms | Left-right two-column layout |
|
|
571
|
+
| 3 | Tablet or medium complexity forms | Three equal-width columns |
|
|
572
|
+
| 4 | Standard desktop forms | Four-column layout with flexible combinations |
|
|
573
|
+
| 6 | Complex forms | Supports 1/2, 1/3, 1/6 ratios |
|
|
574
|
+
| 12 | Highly flexible forms | Bootstrap-style 12-grid system |
|
|
575
|
+
|
|
576
|
+
## Best Practices
|
|
577
|
+
|
|
578
|
+
### 1. Plan Grid Columns Reasonably
|
|
579
|
+
```svelte
|
|
580
|
+
<!-- Mobile-first responsive design -->
|
|
581
|
+
<script lang="ts">
|
|
582
|
+
$: columns = window.innerWidth < 768 ? 2 :
|
|
583
|
+
window.innerWidth < 1024 ? 4 : 6;
|
|
584
|
+
</script>
|
|
585
|
+
|
|
586
|
+
<GridForm {columns}>
|
|
587
|
+
<!-- Field configuration -->
|
|
588
|
+
</GridForm>
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### 2. Logical Grouping and Alignment
|
|
592
|
+
```svelte
|
|
593
|
+
<GridForm columns={6}>
|
|
594
|
+
<!-- Keep related fields on the same row -->
|
|
595
|
+
<FormField label="First Name" style="grid-column: span 2;">
|
|
596
|
+
<TextEditor />
|
|
597
|
+
</FormField>
|
|
598
|
+
<FormField label="Last Name" style="grid-column: span 2;">
|
|
599
|
+
<TextEditor />
|
|
600
|
+
</FormField>
|
|
601
|
+
<FormField label="Age" style="grid-column: span 2;">
|
|
602
|
+
<NumberEditor />
|
|
603
|
+
</FormField>
|
|
604
|
+
|
|
605
|
+
<!-- Long fields occupy full row -->
|
|
606
|
+
<FormField label="Detailed Address" style="grid-column: span 6;">
|
|
607
|
+
<TextEditor />
|
|
608
|
+
</FormField>
|
|
609
|
+
</GridForm>
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### 3. Responsive Grid Gaps
|
|
613
|
+
```css
|
|
614
|
+
/* Responsive gap control */
|
|
615
|
+
:global(.grid-form > div) {
|
|
616
|
+
gap: 16px;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
@media (max-width: 768px) {
|
|
620
|
+
:global(.grid-form > div) {
|
|
621
|
+
gap: 12px;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
@media (max-width: 480px) {
|
|
626
|
+
:global(.grid-form > div) {
|
|
627
|
+
gap: 8px;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
## Style Customization
|
|
633
|
+
|
|
634
|
+
```css
|
|
635
|
+
/* Grid form container */
|
|
636
|
+
:global(.grid-form) {
|
|
637
|
+
display: block;
|
|
638
|
+
width: 100%;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/* Grid content area */
|
|
642
|
+
:global(.grid-form > div) {
|
|
643
|
+
display: grid;
|
|
644
|
+
gap: 16px;
|
|
645
|
+
align-items: start;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/* Horizontal layout styles */
|
|
649
|
+
:global(.grid-form.field-layout-horizontal > div) {
|
|
650
|
+
align-items: center;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/* Custom grid item styles */
|
|
654
|
+
.grid-item {
|
|
655
|
+
padding: 8px;
|
|
656
|
+
background: #f8f9fa;
|
|
657
|
+
border-radius: 4px;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/* Section styles */
|
|
661
|
+
.section-divider {
|
|
662
|
+
grid-column: 1 / -1;
|
|
663
|
+
height: 1px;
|
|
664
|
+
background: #dee2e6;
|
|
665
|
+
margin: 20px 0;
|
|
666
|
+
}
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
## Component Advantages
|
|
670
|
+
|
|
671
|
+
1. **Flexible Grid System** - Based on CSS Grid, supports any column configuration
|
|
672
|
+
2. **Precise Layout Control** - Can precisely control column span for each field
|
|
673
|
+
3. **Responsive Friendly** - Easy to implement responsive layout adjustments
|
|
674
|
+
4. **Consistent Alignment** - Automatically aligns form fields for visual consistency
|
|
675
|
+
5. **Highly Extensible** - Supports complex form layout requirements
|
|
676
|
+
6. **Performance Optimized** - Native CSS Grid support for excellent performance
|