ngx-lite-form 1.2.3 → 1.3.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/LICENSE +21 -0
- package/README.md +711 -147
- package/fesm2022/ngx-lite-form.mjs +132 -26
- package/fesm2022/ngx-lite-form.mjs.map +1 -1
- package/index.d.ts +56 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,23 +1,65 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Lite Form - Angular Form Components Library
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Overview
|
|
4
|
+
Lite Form is a comprehensive Angular library that provides lightweight, customizable form components with built-in validation, styling, and animations. It includes input, password, textarea, select, multi-select, radio, checkbox, file upload, advanced date picker, datetime-picker, and panel components designed for Angular 20+ with standalone component support.
|
|
4
5
|
|
|
5
6
|
## Features
|
|
7
|
+
- ✅ **Modern Angular 20+** - Built with standalone components, signals, and latest CLI tooling
|
|
8
|
+
- ✅ **TypeScript Support** - Fully typed with generic support and DTO helpers
|
|
9
|
+
- ✅ **Reactive Forms** - Integrated with Angular Reactive Forms
|
|
10
|
+
- ✅ **Built-in Validation** - Form validation with error messages and utilities
|
|
11
|
+
- ✅ **Password Security** - Advanced password validation and strength analysis
|
|
12
|
+
- ✅ **Date Handling** - Single date and date range selection with custom formatting
|
|
13
|
+
- ✅ **File Upload** - Drag & drop file upload with camera capture and file management
|
|
14
|
+
- ✅ **Panels & Dialogs** - Template-driven modal panels with configurable action buttons
|
|
15
|
+
- ✅ **Data Tables** - Flexible table component with custom columns, sorting, and pagination
|
|
16
|
+
- ✅ **Pagination** - Standalone pagination component with customizable navigation
|
|
17
|
+
- ✅ **Customizable Styling** - Space-saving SCSS style guide for consistent overrides
|
|
18
|
+
- ✅ **Accessibility** - ARIA-compliant form controls
|
|
19
|
+
- ✅ **Animations** - Smooth transitions and interactions
|
|
6
20
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
+
## Components
|
|
22
|
+
|
|
23
|
+
### 🎯 LiteInput
|
|
24
|
+
Basic text input component with floating labels and validation.
|
|
25
|
+
|
|
26
|
+
### 🔐 LitePassword
|
|
27
|
+
Password input component with toggle visibility, strength indicator, and advanced validation features.
|
|
28
|
+
|
|
29
|
+
### 📝 LiteTextarea
|
|
30
|
+
Multi-line text input with auto-resize capabilities.
|
|
31
|
+
|
|
32
|
+
### 📋 LiteSelect
|
|
33
|
+
Single-selection dropdown with search and filtering.
|
|
34
|
+
|
|
35
|
+
### ☑️ LiteMultiSelect
|
|
36
|
+
Multi-selection dropdown with inline selected items display and dynamic height adjustment.
|
|
37
|
+
|
|
38
|
+
### 🔘 LiteRadio
|
|
39
|
+
Radio button group component for single selection from multiple options.
|
|
40
|
+
|
|
41
|
+
### ✅ LiteCheckbox
|
|
42
|
+
Checkbox component for boolean input with validation support.
|
|
43
|
+
|
|
44
|
+
### 📅 LiteDate
|
|
45
|
+
Advanced date picker component with single date and date range selection, custom formatting, and intelligent calendar positioning.
|
|
46
|
+
|
|
47
|
+
### 📎 LiteFile
|
|
48
|
+
File upload component with drag & drop, badge, file management panel, and camera capture support.
|
|
49
|
+
|
|
50
|
+
### 📅 LiteDateTime
|
|
51
|
+
Date and time picker with timezone-safe handling and consistent formatting utilities.
|
|
52
|
+
|
|
53
|
+
### 📊 LiteTable
|
|
54
|
+
Flexible data table component with custom columns, cell templates, nested property access, and integrated pagination.
|
|
55
|
+
|
|
56
|
+
### 📄 LitePaginator
|
|
57
|
+
Standalone pagination component with customizable page navigation, items per page selection, and total item display.
|
|
58
|
+
|
|
59
|
+
### 🪟 LitePanel
|
|
60
|
+
Modal-style panel component that renders custom templates, configurable header text, and action buttons via `LitePanelAction` definitions. Supports custom `width`, `height`, `maxWidth`, and `maxHeight` inputs with automatic `px` suffix for numeric values.
|
|
61
|
+
|
|
62
|
+
---
|
|
21
63
|
|
|
22
64
|
## Installation
|
|
23
65
|
|
|
@@ -25,266 +67,788 @@ A modern, lightweight Angular form components library with TypeScript support, b
|
|
|
25
67
|
npm install ngx-lite-form
|
|
26
68
|
```
|
|
27
69
|
|
|
28
|
-
## Quick
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
### 1. Import Components
|
|
29
73
|
|
|
30
74
|
```typescript
|
|
31
|
-
import {
|
|
75
|
+
import {
|
|
76
|
+
LiteInput,
|
|
77
|
+
LitePassword,
|
|
78
|
+
LiteTextarea,
|
|
79
|
+
LiteSelect,
|
|
80
|
+
LiteMultiSelect,
|
|
81
|
+
LiteRadio,
|
|
82
|
+
LiteCheckbox,
|
|
83
|
+
LiteDate,
|
|
84
|
+
LiteDateTime,
|
|
85
|
+
LiteFile,
|
|
86
|
+
LiteTable,
|
|
87
|
+
LitePaginator,
|
|
88
|
+
LitePanel
|
|
89
|
+
} from 'ngx-lite-form';
|
|
32
90
|
import { FormControl, Validators } from '@angular/forms';
|
|
33
91
|
|
|
34
|
-
import {
|
|
92
|
+
import {
|
|
93
|
+
FieldDto,
|
|
94
|
+
SelectFieldDto,
|
|
95
|
+
MultiSelectFieldDto,
|
|
96
|
+
RadioFieldDto,
|
|
97
|
+
DateRangeFieldDto,
|
|
98
|
+
FileFieldDto,
|
|
99
|
+
TableFieldDto,
|
|
100
|
+
PaginatorFieldDto,
|
|
101
|
+
LitePanelAction
|
|
102
|
+
} from 'ngx-lite-form';
|
|
35
103
|
|
|
36
104
|
@Component({
|
|
37
105
|
standalone: true,
|
|
38
|
-
imports: [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
106
|
+
imports: [
|
|
107
|
+
LiteInput,
|
|
108
|
+
LitePassword,
|
|
109
|
+
LiteTextarea,
|
|
110
|
+
LiteSelect,
|
|
111
|
+
LiteMultiSelect,
|
|
112
|
+
LiteRadio,
|
|
113
|
+
LiteCheckbox,
|
|
114
|
+
LiteDate,
|
|
115
|
+
LiteDateTime,
|
|
116
|
+
LiteFile,
|
|
117
|
+
LiteTable,
|
|
118
|
+
LitePaginator
|
|
119
|
+
],
|
|
120
|
+
templateUrl: './app.component.html',
|
|
121
|
+
styleUrl: './app.component.scss'
|
|
44
122
|
})
|
|
45
|
-
export class
|
|
46
|
-
|
|
123
|
+
export class AppComponent {
|
|
124
|
+
// Basic input
|
|
125
|
+
nameField = new FieldDto('Full Name', new FormControl(''));
|
|
126
|
+
|
|
127
|
+
// Number input
|
|
128
|
+
ageField = new FieldDto('Age', new FormControl(0), 2, 'number');
|
|
129
|
+
|
|
130
|
+
// Password with validation
|
|
131
|
+
passwordField = new FieldDto('Password', new FormControl('', [
|
|
132
|
+
Validators.required,
|
|
133
|
+
Validators.minLength(8),
|
|
134
|
+
Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/)
|
|
135
|
+
]));
|
|
136
|
+
|
|
137
|
+
// Textarea
|
|
138
|
+
descriptionField = new FieldDto('Description', new FormControl(''), 4);
|
|
139
|
+
|
|
140
|
+
// Checkbox (using basic FieldDto for boolean)
|
|
47
141
|
agreeField = new FieldDto('I agree to terms', new FormControl<boolean>(false, { nonNullable: true }));
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
142
|
+
|
|
143
|
+
// Select dropdown
|
|
144
|
+
countryField = new SelectFieldDto(
|
|
145
|
+
'Country',
|
|
51
146
|
new FormControl(''),
|
|
52
|
-
['
|
|
147
|
+
['USA', 'Canada', 'Mexico'],
|
|
53
148
|
(option) => option
|
|
54
149
|
);
|
|
150
|
+
|
|
151
|
+
// Multi-select
|
|
152
|
+
skillsField = new MultiSelectFieldDto(
|
|
153
|
+
'Skills',
|
|
154
|
+
new FormControl<string[]>([]),
|
|
155
|
+
['JavaScript', 'TypeScript', 'Angular', 'React'],
|
|
156
|
+
(option) => option
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// Radio group
|
|
160
|
+
planField = new RadioFieldDto(
|
|
161
|
+
'Choose Plan',
|
|
162
|
+
new FormControl(''),
|
|
163
|
+
['Basic', 'Premium', 'Enterprise'],
|
|
164
|
+
(option) => option
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// Single date
|
|
168
|
+
birthdateField: FieldDto = {
|
|
169
|
+
label: 'Birth Date',
|
|
170
|
+
formControl: new FormControl<string>('', { nonNullable: true })
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Date range
|
|
174
|
+
eventDateField: DateRangeFieldDto = {
|
|
175
|
+
label: 'Event Date Range',
|
|
176
|
+
formControl: new FormControl<string[]>(['', ''], { nonNullable: true })
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// File upload
|
|
180
|
+
fileField = new FileFieldDto('Attachments', new FormControl([]), {
|
|
181
|
+
multiple: true,
|
|
182
|
+
accept: 'image/*,application/pdf',
|
|
183
|
+
maxFileSize: 5 * 1024 * 1024,
|
|
184
|
+
maxFiles: 5,
|
|
185
|
+
showPreview: true
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Table with custom columns
|
|
189
|
+
employeeTable = new TableFieldDto(
|
|
190
|
+
[
|
|
191
|
+
{ key: 'name', label: 'Name', flex: '1' },
|
|
192
|
+
{ key: 'department', label: 'Department', flex: '0 0 150px' },
|
|
193
|
+
{ key: 'salary', label: 'Salary', flex: '0 0 120px', cellTemplate: (value) => `$${value?.toLocaleString() || '0'}` }
|
|
194
|
+
],
|
|
195
|
+
[
|
|
196
|
+
{ name: 'John Smith', department: 'Engineering', salary: 75000 },
|
|
197
|
+
{ name: 'Sarah Johnson', department: 'Marketing', salary: 65000 }
|
|
198
|
+
]
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// Paginated table
|
|
202
|
+
userTable = new TableFieldDto(
|
|
203
|
+
[
|
|
204
|
+
{ key: 'name', label: 'Name', flex: '1' },
|
|
205
|
+
{ key: 'email', label: 'Email', flex: '1' },
|
|
206
|
+
{ key: 'location.country', label: 'Country', flex: '0 0 120px' }
|
|
207
|
+
],
|
|
208
|
+
[], // Will be populated by API
|
|
209
|
+
true, // Enable pagination
|
|
210
|
+
new PaginatorFieldDto(1, 100, 10) // Page 1, 100 total items, 10 per page
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
// Standalone paginator
|
|
214
|
+
paginator = new PaginatorFieldDto(1, 500, 25);
|
|
215
|
+
|
|
216
|
+
// Panel demo state
|
|
217
|
+
basicPanelOpen = signal(false);
|
|
218
|
+
panelResult = signal<unknown | null>(null);
|
|
219
|
+
confirmationActions: LitePanelAction[] = [
|
|
220
|
+
{ label: 'Confirm', value: 'confirm', variant: 'danger' },
|
|
221
|
+
{ label: 'Cancel', value: null, variant: 'secondary' }
|
|
222
|
+
];
|
|
223
|
+
|
|
224
|
+
openPanel() {
|
|
225
|
+
this.panelResult.set(null);
|
|
226
|
+
this.basicPanelOpen.set(true);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
onPanelClosed(result: unknown | null) {
|
|
230
|
+
this.panelResult.set(result);
|
|
231
|
+
this.basicPanelOpen.set(false);
|
|
232
|
+
}
|
|
55
233
|
}
|
|
56
234
|
```
|
|
57
235
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
### LiteInput
|
|
61
|
-
Basic text input with floating label animation and validation display.
|
|
236
|
+
### 3. Use in Templates
|
|
62
237
|
|
|
63
|
-
```
|
|
64
|
-
|
|
238
|
+
```html
|
|
239
|
+
<form>
|
|
240
|
+
<lite-input [control]="nameField"></lite-input>
|
|
241
|
+
<lite-password [control]="passwordField" [showStrengthIndicator]="true"></lite-password>
|
|
242
|
+
<lite-textarea [control]="descriptionField"></lite-textarea>
|
|
243
|
+
<lite-checkbox [control]="agreeField"></lite-checkbox>
|
|
244
|
+
<lite-select [control]="countryField"></lite-select>
|
|
245
|
+
<lite-multi-select [control]="skillsField"></lite-multi-select>
|
|
246
|
+
<lite-radio [control]="planField"></lite-radio>
|
|
247
|
+
<lite-date [control]="birthdateField"></lite-date>
|
|
248
|
+
<lite-date [control]="eventDateField" [range]="true" [format]="'dd/MM/yyyy'"></lite-date>
|
|
249
|
+
<lite-file [control]="fileField"></lite-file>
|
|
250
|
+
</form>
|
|
251
|
+
|
|
252
|
+
<!-- Data Table -->
|
|
253
|
+
<lite-table [table]="employeeTable"></lite-table>
|
|
254
|
+
|
|
255
|
+
<!-- Paginated Table -->
|
|
256
|
+
<lite-table
|
|
257
|
+
[table]="userTable"
|
|
258
|
+
(pageChange)="onPageChange($event)"
|
|
259
|
+
(itemsPerPageChange)="onItemsPerPageChange($event)">
|
|
260
|
+
</lite-table>
|
|
261
|
+
|
|
262
|
+
<!-- Standalone Paginator -->
|
|
263
|
+
<lite-paginator
|
|
264
|
+
[paginator]="paginator"
|
|
265
|
+
(pageChange)="onPaginatorPageChange($event)"
|
|
266
|
+
(itemsPerPageChange)="onPaginatorItemsChange($event)">
|
|
267
|
+
</lite-paginator>
|
|
268
|
+
|
|
269
|
+
<!-- Lite Panel -->
|
|
270
|
+
<button type="button" (click)="openPanel()">Open Panel</button>
|
|
271
|
+
|
|
272
|
+
@if (basicPanelOpen()) {
|
|
273
|
+
<lite-panel
|
|
274
|
+
[title]="'Review details'"
|
|
275
|
+
[content]="panelTemplate"
|
|
276
|
+
[actions]="confirmationActions"
|
|
277
|
+
(closed)="onPanelClosed($event)">
|
|
278
|
+
</lite-panel>
|
|
279
|
+
}
|
|
65
280
|
|
|
66
|
-
|
|
281
|
+
<ng-template #panelTemplate let-close="close">
|
|
282
|
+
<p>Panel content can render any Angular template.</p>
|
|
283
|
+
<button type="button" (click)="close('acknowledged')">Acknowledge</button>
|
|
284
|
+
</ng-template>
|
|
67
285
|
```
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Component Documentation
|
|
289
|
+
|
|
290
|
+
### LiteInput Component
|
|
68
291
|
|
|
69
|
-
|
|
70
|
-
Multi-line text input that supports configurable rows.
|
|
292
|
+
**Selector:** `lite-input`
|
|
71
293
|
|
|
294
|
+
**Inputs:**
|
|
295
|
+
- `control: FieldDto` - Field configuration and form control
|
|
296
|
+
- `inEdit: boolean` - Whether the field is in edit mode (default: true)
|
|
297
|
+
|
|
298
|
+
**Example:**
|
|
72
299
|
```typescript
|
|
73
|
-
|
|
300
|
+
// Component
|
|
301
|
+
nameField = new FieldDto('Full Name', new FormControl('', [Validators.required]));
|
|
74
302
|
|
|
75
|
-
|
|
303
|
+
// Template
|
|
304
|
+
<lite-input [control]="nameField"></lite-input>
|
|
76
305
|
```
|
|
77
306
|
|
|
78
|
-
### LitePassword
|
|
79
|
-
Password input with strength indicator, toggle visibility, and advanced validation.
|
|
307
|
+
### LitePassword Component
|
|
80
308
|
|
|
81
|
-
|
|
82
|
-
|
|
309
|
+
**Selector:** `lite-password`
|
|
310
|
+
|
|
311
|
+
**Inputs:**
|
|
312
|
+
- `control: FieldDto` - Field configuration and form control
|
|
313
|
+
- `inEdit: boolean` - Whether the field is in edit mode (default: true)
|
|
314
|
+
- `showToggle: boolean` - Whether to show the password visibility toggle (default: true)
|
|
315
|
+
- `showStrengthIndicator: boolean` - Whether to show password strength indicator (default: false)
|
|
316
|
+
|
|
317
|
+
**Features:**
|
|
318
|
+
- Password visibility toggle with eye/eye-off icons
|
|
319
|
+
- Real-time password strength analysis
|
|
320
|
+
- Advanced password validation error messages
|
|
321
|
+
- Support for complex password patterns
|
|
322
|
+
- Accessibility features (ARIA labels)
|
|
83
323
|
|
|
324
|
+
**Example:**
|
|
325
|
+
```typescript
|
|
326
|
+
// Basic password
|
|
84
327
|
passwordField = new FieldDto('Password', new FormControl('', [
|
|
85
328
|
Validators.required,
|
|
86
329
|
Validators.minLength(8)
|
|
87
330
|
]));
|
|
331
|
+
|
|
332
|
+
// Advanced password with pattern validation
|
|
333
|
+
strongPasswordField = new FieldDto('Strong Password', new FormControl('', [
|
|
334
|
+
Validators.required,
|
|
335
|
+
Validators.minLength(8),
|
|
336
|
+
Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/)
|
|
337
|
+
]));
|
|
338
|
+
|
|
339
|
+
// Template
|
|
340
|
+
<lite-password [control]="passwordField"></lite-password>
|
|
341
|
+
<lite-password [control]="strongPasswordField" [showStrengthIndicator]="true"></lite-password>
|
|
342
|
+
<lite-password [control]="confirmPasswordField" [showToggle]="false"></lite-password>
|
|
88
343
|
```
|
|
89
344
|
|
|
90
|
-
|
|
91
|
-
|
|
345
|
+
**Password Strength Analysis:**
|
|
346
|
+
```typescript
|
|
347
|
+
import { FormUtils } from 'ngx-lite-form';
|
|
348
|
+
|
|
349
|
+
// Analyze password strength programmatically
|
|
350
|
+
const analysis = FormUtils.analyzePasswordStrength('MyStr0ng@Pass');
|
|
351
|
+
// Returns: { score: 6, level: 'Good', feedback: ['Consider using 12+ characters'] }
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### LiteTextarea Component
|
|
355
|
+
|
|
356
|
+
**Selector:** `lite-textarea`
|
|
357
|
+
|
|
358
|
+
**Inputs:**
|
|
359
|
+
- `control: FieldDto` - Field configuration and form control (supports `rows` property)
|
|
360
|
+
- `inEdit: boolean` - Whether the field is in edit mode (default: true)
|
|
92
361
|
|
|
362
|
+
**Example:**
|
|
93
363
|
```typescript
|
|
94
|
-
|
|
364
|
+
// Component
|
|
365
|
+
// With validation
|
|
366
|
+
descriptionField = new FieldDto('Description', new FormControl(''), 4);
|
|
367
|
+
|
|
368
|
+
// Template
|
|
369
|
+
<lite-textarea [control]="descriptionField"></lite-textarea>
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### LiteSelect Component
|
|
373
|
+
|
|
374
|
+
**Selector:** `lite-select`
|
|
95
375
|
|
|
376
|
+
**Inputs:**
|
|
377
|
+
- `control: SelectFieldDto<T>` - Select field configuration with options
|
|
378
|
+
- `inEdit: boolean` - Whether the field is in edit mode (default: true)
|
|
379
|
+
|
|
380
|
+
**Example:**
|
|
381
|
+
```typescript
|
|
382
|
+
// Component
|
|
96
383
|
statusField = new SelectFieldDto(
|
|
97
384
|
'Status',
|
|
98
385
|
new FormControl(''),
|
|
99
|
-
[
|
|
100
|
-
|
|
386
|
+
[
|
|
387
|
+
{ id: 1, name: 'Active' },
|
|
388
|
+
{ id: 2, name: 'Inactive' }
|
|
389
|
+
],
|
|
390
|
+
(option) => option.name
|
|
101
391
|
);
|
|
392
|
+
|
|
393
|
+
// Template
|
|
394
|
+
<lite-select [control]="statusField"></lite-select>
|
|
102
395
|
```
|
|
103
396
|
|
|
104
|
-
### LiteMultiSelect
|
|
105
|
-
Multi-selection dropdown with inline selected items display and dynamic height adjustment.
|
|
397
|
+
### LiteMultiSelect Component
|
|
106
398
|
|
|
107
|
-
|
|
108
|
-
import { LiteMultiSelect, MultiSelectFieldDto } from 'ngx-lite-form';
|
|
399
|
+
**Selector:** `lite-multi-select`
|
|
109
400
|
|
|
110
|
-
|
|
111
|
-
|
|
401
|
+
**Inputs:**
|
|
402
|
+
- `control: MultiSelectFieldDto<T>` - Multi-select field configuration
|
|
403
|
+
- `inEdit: boolean` - Whether the field is in edit mode (default: true)
|
|
404
|
+
|
|
405
|
+
**Features:**
|
|
406
|
+
- Inline selected items display
|
|
407
|
+
- Dynamic height adjustment
|
|
408
|
+
- Filtering/search functionality
|
|
409
|
+
- Individual item removal
|
|
410
|
+
|
|
411
|
+
**Example:**
|
|
412
|
+
```typescript
|
|
413
|
+
// Component
|
|
414
|
+
tagsField = new MultiSelectFieldDto(
|
|
415
|
+
'Tags',
|
|
112
416
|
new FormControl<string[]>([]),
|
|
113
|
-
['
|
|
417
|
+
['Frontend', 'Backend', 'DevOps', 'Testing'],
|
|
114
418
|
(option) => option
|
|
115
419
|
);
|
|
420
|
+
|
|
421
|
+
// Template
|
|
422
|
+
<lite-multi-select [control]="tagsField"></lite-multi-select>
|
|
116
423
|
```
|
|
117
424
|
|
|
118
|
-
###
|
|
119
|
-
Radio button group component for single selection from multiple options.
|
|
425
|
+
### LiteDate Component
|
|
120
426
|
|
|
427
|
+
**Selector:** `lite-date`
|
|
428
|
+
|
|
429
|
+
**Inputs:**
|
|
430
|
+
- `control: FieldDto | DateRangeFieldDto` - Date field configuration
|
|
431
|
+
- `inEdit: boolean` - Whether the field is in edit mode (default: true)
|
|
432
|
+
- `format: string` - Date display format (default: 'dd/MM/yyyy')
|
|
433
|
+
- `range: boolean` - Enable date range selection (default: false)
|
|
434
|
+
|
|
435
|
+
**Features:**
|
|
436
|
+
- Single date and date range selection
|
|
437
|
+
- Custom date formatting (dd/MM/yyyy, MM/dd/yyyy, yyyy-MM-dd)
|
|
438
|
+
- Intelligent calendar positioning (auto-adjusts based on screen space)
|
|
439
|
+
- Dual calendar display for range selection
|
|
440
|
+
- Visual range highlighting with different styles for start, end, and in-between dates
|
|
441
|
+
- Manual input parsing with format validation
|
|
442
|
+
- Timezone-safe date handling
|
|
443
|
+
- Today's date highlighting with distinctive styling
|
|
444
|
+
- Auto-close calendar after range selection
|
|
445
|
+
|
|
446
|
+
**Single Date Example:**
|
|
121
447
|
```typescript
|
|
122
|
-
|
|
448
|
+
// Component
|
|
449
|
+
birthdateField: FieldDto = {
|
|
450
|
+
label: 'Birth Date',
|
|
451
|
+
formControl: new FormControl<string>('', {
|
|
452
|
+
nonNullable: true,
|
|
453
|
+
validators: [Validators.required]
|
|
454
|
+
})
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
// Template
|
|
458
|
+
<lite-date [control]="birthdateField" [format]="'dd/MM/yyyy'"></lite-date>
|
|
459
|
+
```
|
|
123
460
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
461
|
+
**Date Range Example:**
|
|
462
|
+
```typescript
|
|
463
|
+
// Component
|
|
464
|
+
import { DateRangeFieldDto } from 'ngx-lite-form';
|
|
465
|
+
|
|
466
|
+
eventDateField: DateRangeFieldDto = {
|
|
467
|
+
label: 'Event Date Range',
|
|
468
|
+
formControl: new FormControl<string[]>(['', ''], { nonNullable: true })
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// Template
|
|
472
|
+
<lite-date [control]="eventDateField" [range]="true" [format]="'dd/MM/yyyy'"></lite-date>
|
|
130
473
|
```
|
|
131
474
|
|
|
132
|
-
|
|
133
|
-
|
|
475
|
+
**Range Selection Behavior:**
|
|
476
|
+
- First click: Sets start date, clears any existing range
|
|
477
|
+
- Second click: Sets end date, completes range selection
|
|
478
|
+
- Clicking same date twice: Resets to single start date
|
|
479
|
+
- Auto-orders dates (earlier date becomes start, later becomes end)
|
|
480
|
+
- Calendar auto-closes 1 second after completing range selection
|
|
134
481
|
|
|
482
|
+
### LiteFile Component
|
|
483
|
+
|
|
484
|
+
**Selector:** `lite-file`
|
|
485
|
+
|
|
486
|
+
**Inputs:**
|
|
487
|
+
- `control: FileFieldDto` - File field configuration including label, FormControl, and file options
|
|
488
|
+
- `inEdit: boolean` - Whether the field is in edit mode (default: true)
|
|
489
|
+
|
|
490
|
+
**Features:**
|
|
491
|
+
- File upload via button, drag & drop, or camera capture (on supported devices)
|
|
492
|
+
- Always-visible badge shows file count
|
|
493
|
+
- Management panel lists files, upload area, and action buttons
|
|
494
|
+
- Camera capture on devices with a camera using `<input type="file" accept="image/*" capture="environment">`
|
|
495
|
+
- Validation: max files, max file size, file type restrictions
|
|
496
|
+
- Image preview with thumbnails for image files
|
|
497
|
+
- Progress tracking for file uploads
|
|
498
|
+
- Accessibility: keyboard and screen reader friendly
|
|
499
|
+
|
|
500
|
+
**Example:**
|
|
135
501
|
```typescript
|
|
136
|
-
|
|
502
|
+
// Component
|
|
503
|
+
import { FileFieldDto } from 'ngx-lite-form';
|
|
504
|
+
|
|
505
|
+
// Basic file upload
|
|
506
|
+
fileField = new FileFieldDto('Upload Files', new FormControl([]));
|
|
137
507
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
508
|
+
// Image upload with restrictions
|
|
509
|
+
imageField = new FileFieldDto(
|
|
510
|
+
'Profile Picture',
|
|
511
|
+
new FormControl([]),
|
|
512
|
+
false, // single file only
|
|
513
|
+
'image/*', // images only
|
|
514
|
+
2 * 1024 * 1024, // 2MB limit
|
|
515
|
+
1, // max 1 file
|
|
516
|
+
true // show preview
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
// Template
|
|
520
|
+
<lite-file [control]="fileField"></lite-file>
|
|
521
|
+
<lite-file [control]="imageField"></lite-file>
|
|
142
522
|
```
|
|
143
523
|
|
|
144
|
-
|
|
145
|
-
|
|
524
|
+
**Camera Capture:**
|
|
525
|
+
- The "Take Picture" button opens the device camera using a hidden file input with `accept="image/*" capture="environment"`
|
|
526
|
+
- Works on mobile devices and laptops with a camera
|
|
527
|
+
- On desktops without a camera, the button will do nothing or fall back to file selection
|
|
528
|
+
- No special permissions required, but the browser may prompt for camera access
|
|
529
|
+
|
|
530
|
+
**File Management Panel:**
|
|
531
|
+
- Click the file icon button to open the management panel
|
|
532
|
+
- Drag & drop files or click the upload area to select files
|
|
533
|
+
- Use action buttons to upload files, take a picture, or close the panel
|
|
534
|
+
- Remove files individually or clear all files
|
|
535
|
+
|
|
536
|
+
### LiteTable Component
|
|
537
|
+
|
|
538
|
+
**Selector:** `lite-table`
|
|
539
|
+
|
|
540
|
+
**Inputs:**
|
|
541
|
+
- `table: TableFieldDto<T>` - Table configuration including columns and data
|
|
542
|
+
|
|
543
|
+
**Outputs:**
|
|
544
|
+
- `pageChange: number` - Emitted when user changes page (for paginated tables)
|
|
545
|
+
- `itemsPerPageChange: number` - Emitted when user changes items per page
|
|
546
|
+
- `menuAction: { action: string; row: T }` - Emitted when a row action is selected from a menu-type column
|
|
547
|
+
|
|
548
|
+
**Features:**
|
|
549
|
+
- Flexbox-based responsive layout for modern table design
|
|
550
|
+
- Custom column definitions with labels, flex sizing, and cell templates
|
|
551
|
+
- Support for nested object property access (dot notation)
|
|
552
|
+
- Integrated pagination with lite-paginator component
|
|
553
|
+
- Custom cell templates for advanced formatting (images, status indicators, dates)
|
|
554
|
+
- Automatic handling of special data formats (name objects, nested properties)
|
|
555
|
+
- Empty state display when no data is available
|
|
556
|
+
- Sorting indicators (visual styling support)
|
|
557
|
+
- Per-row actions menu via a dedicated `menu`-type column (kebab/tri-dot)
|
|
558
|
+
|
|
559
|
+
**Example:**
|
|
560
|
+
```typescript
|
|
561
|
+
// Component
|
|
562
|
+
import { TableFieldDto, TableColumn } from 'ngx-lite-form';
|
|
563
|
+
|
|
564
|
+
interface Product {
|
|
565
|
+
id: number;
|
|
566
|
+
name: string;
|
|
567
|
+
price: number;
|
|
568
|
+
category: string;
|
|
569
|
+
inStock: boolean;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const columns: TableColumn[] = [
|
|
573
|
+
{ key: 'id', label: 'ID', flex: '0 0 80px' },
|
|
574
|
+
{ key: 'name', label: 'Product Name', flex: '2' },
|
|
575
|
+
{ key: 'price', label: 'Price', flex: '0 0 100px', cellTemplate: (value) => `$${value?.toFixed(2)}` },
|
|
576
|
+
{ key: 'category', label: 'Category', flex: '1' },
|
|
577
|
+
{ key: 'inStock', label: 'Status', flex: '0 0 100px', cellTemplate: (value) => value ? '✓ In Stock' : '✗ Out of Stock' }
|
|
578
|
+
];
|
|
579
|
+
|
|
580
|
+
productTable = new TableFieldDto(columns, productData, false);
|
|
581
|
+
|
|
582
|
+
// Template
|
|
583
|
+
<lite-table [table]="productTable"></lite-table>
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
#### Row Actions Menu
|
|
587
|
+
|
|
588
|
+
Add a dedicated menu column to show a kebab (tri-dot) button per row. Configure menu items on the column and handle the `(menuAction)` output.
|
|
146
589
|
|
|
147
590
|
```typescript
|
|
148
|
-
import {
|
|
591
|
+
import { TableFieldDto, TableColumn } from 'ngx-lite-form';
|
|
592
|
+
|
|
593
|
+
const columns: TableColumn[] = [
|
|
594
|
+
{ key: 'name', label: 'Name', flex: '1' },
|
|
595
|
+
{ key: 'email', label: 'Email', flex: '1' },
|
|
596
|
+
// Menu column (last column)
|
|
597
|
+
{
|
|
598
|
+
key: 'actions',
|
|
599
|
+
label: '',
|
|
600
|
+
flex: '0 0 44px',
|
|
601
|
+
type: 'menu',
|
|
602
|
+
menuItems: [
|
|
603
|
+
{ label: 'Edit', value: 'edit' },
|
|
604
|
+
{ label: 'Delete', value: 'delete', variant: 'danger' }
|
|
605
|
+
]
|
|
606
|
+
}
|
|
607
|
+
];
|
|
608
|
+
|
|
609
|
+
table = new TableFieldDto(columns, userData, false);
|
|
610
|
+
|
|
611
|
+
// In your component class
|
|
612
|
+
onRowMenuAction(event: { action: string; row: any }) {
|
|
613
|
+
if (event.action === 'edit') {
|
|
614
|
+
// handle edit
|
|
615
|
+
} else if (event.action === 'delete') {
|
|
616
|
+
// handle delete
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
```
|
|
149
620
|
|
|
150
|
-
|
|
621
|
+
```html
|
|
622
|
+
<lite-table [table]="table" (menuAction)="onRowMenuAction($event)"></lite-table>
|
|
151
623
|
```
|
|
152
624
|
|
|
153
|
-
###
|
|
154
|
-
|
|
625
|
+
### LitePaginator Component
|
|
626
|
+
|
|
627
|
+
**Selector:** `lite-paginator`
|
|
628
|
+
|
|
629
|
+
**Inputs:**
|
|
630
|
+
- `paginator: PaginatorFieldDto` - Pagination configuration including current page, total items, and items per page
|
|
631
|
+
|
|
632
|
+
**Outputs:**
|
|
633
|
+
- `pageChange: number` - Emitted when user changes page
|
|
634
|
+
- `itemsPerPageChange: number` - Emitted when user changes items per page
|
|
155
635
|
|
|
636
|
+
**Features:**
|
|
637
|
+
- Previous/Next navigation buttons with disabled states
|
|
638
|
+
- Numbered page buttons with active state highlighting
|
|
639
|
+
- Items per page dropdown selection
|
|
640
|
+
- Total items display with customizable formatting
|
|
641
|
+
- Keyboard navigation support (arrow keys)
|
|
642
|
+
- Responsive design that adapts to different screen sizes
|
|
643
|
+
- Accessibility features with ARIA labels and screen reader support
|
|
644
|
+
- Configurable page range display and navigation controls
|
|
645
|
+
|
|
646
|
+
**Example:**
|
|
156
647
|
```typescript
|
|
157
|
-
|
|
648
|
+
// Component
|
|
649
|
+
import { PaginatorFieldDto } from 'ngx-lite-form';
|
|
650
|
+
|
|
651
|
+
paginator = new PaginatorFieldDto(1, 500, 25); // Page 1, 500 total items, 25 per page
|
|
158
652
|
|
|
159
|
-
|
|
653
|
+
// Template
|
|
654
|
+
<lite-paginator
|
|
655
|
+
[paginator]="paginator"
|
|
656
|
+
(pageChange)="onPageChange($event)"
|
|
657
|
+
(itemsPerPageChange)="onItemsPerPageChange($event)">
|
|
658
|
+
</lite-paginator>
|
|
160
659
|
```
|
|
161
660
|
|
|
162
|
-
|
|
163
|
-
|
|
661
|
+
## Snackbar Service
|
|
662
|
+
|
|
663
|
+
The library provides a simple snackbar notification service for showing messages at the top of the page. No component or template is needed.
|
|
664
|
+
|
|
665
|
+
### Usage
|
|
666
|
+
|
|
667
|
+
Inject the service and call `show()` with your message and type:
|
|
164
668
|
|
|
165
669
|
```typescript
|
|
166
|
-
import {
|
|
670
|
+
import { LiteSnackbarService } from 'ngx-lite-form';
|
|
167
671
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
)
|
|
672
|
+
constructor(private snackbar: LiteSnackbarService) {}
|
|
673
|
+
|
|
674
|
+
// Show a success message
|
|
675
|
+
this.snackbar.show('Operation completed!', 'done');
|
|
676
|
+
|
|
677
|
+
// Show a warning
|
|
678
|
+
this.snackbar.show('Please check your input.', 'warn');
|
|
679
|
+
|
|
680
|
+
// Show an error (with custom duration)
|
|
681
|
+
this.snackbar.show('Something went wrong.', 'error', 5000);
|
|
177
682
|
```
|
|
178
683
|
|
|
179
|
-
|
|
684
|
+
- Types: `'done' | 'warn' | 'error'`
|
|
685
|
+
- Duration: Optional, in milliseconds (default: 3000)
|
|
686
|
+
|
|
687
|
+
The snackbar will appear at the top of the page and auto-dismiss.
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## Data Transfer Objects (DTOs)
|
|
180
692
|
|
|
181
693
|
### FieldDto
|
|
694
|
+
Basic field configuration for input and textarea components.
|
|
695
|
+
|
|
182
696
|
```typescript
|
|
183
697
|
class FieldDto {
|
|
184
698
|
label: string;
|
|
185
699
|
formControl: FormControl;
|
|
186
|
-
rows?: number; // For textarea
|
|
700
|
+
rows?: number; // For textarea only
|
|
187
701
|
}
|
|
188
702
|
```
|
|
189
703
|
|
|
190
|
-
###
|
|
704
|
+
### BaseSelectFieldDto<T>
|
|
705
|
+
Abstract base class for select components.
|
|
706
|
+
|
|
191
707
|
```typescript
|
|
192
|
-
class
|
|
708
|
+
abstract class BaseSelectFieldDto<T> {
|
|
193
709
|
label: string;
|
|
194
|
-
formControl: FormControl<T>;
|
|
195
710
|
options: T[];
|
|
196
711
|
displayWith: (option: T) => string;
|
|
197
712
|
}
|
|
198
713
|
```
|
|
199
714
|
|
|
715
|
+
### SelectFieldDto<T>
|
|
716
|
+
Single-selection dropdown configuration.
|
|
717
|
+
|
|
718
|
+
```typescript
|
|
719
|
+
class SelectFieldDto<T> extends BaseSelectFieldDto<T> {
|
|
720
|
+
formControl: FormControl<T>;
|
|
721
|
+
}
|
|
722
|
+
```
|
|
723
|
+
|
|
200
724
|
### MultiSelectFieldDto<T>
|
|
725
|
+
Multi-selection dropdown configuration.
|
|
726
|
+
|
|
201
727
|
```typescript
|
|
202
|
-
class MultiSelectFieldDto<T> {
|
|
203
|
-
label: string;
|
|
728
|
+
class MultiSelectFieldDto<T> extends BaseSelectFieldDto<T> {
|
|
204
729
|
formControl: FormControl<T[]>;
|
|
205
|
-
options: T[];
|
|
206
|
-
displayWith: (option: T) => string;
|
|
207
730
|
}
|
|
208
731
|
```
|
|
209
732
|
|
|
210
|
-
###
|
|
733
|
+
### DateRangeFieldDto
|
|
734
|
+
Date range selection configuration.
|
|
735
|
+
|
|
211
736
|
```typescript
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
formControl: FormControl<T>;
|
|
215
|
-
options: T[];
|
|
216
|
-
displayWith: (option: T) => string;
|
|
737
|
+
interface DateRangeFieldDto extends Omit<FieldDto, 'formControl'> {
|
|
738
|
+
formControl: FormControl<string[]>;
|
|
217
739
|
}
|
|
218
740
|
```
|
|
219
741
|
|
|
220
742
|
### FileFieldDto
|
|
743
|
+
File field configuration for the LiteFile component.
|
|
744
|
+
|
|
221
745
|
```typescript
|
|
222
746
|
class FileFieldDto {
|
|
223
747
|
label: string;
|
|
224
748
|
formControl: FormControl;
|
|
225
|
-
multiple?: boolean;
|
|
226
|
-
accept?: string;
|
|
227
|
-
maxFileSize?: number;
|
|
228
|
-
maxFiles?: number;
|
|
229
|
-
showPreview?: boolean;
|
|
749
|
+
multiple?: boolean; // Allow multiple file selection (default: true)
|
|
750
|
+
accept?: string; // Accepted file types (default: '*/*')
|
|
751
|
+
maxFileSize?: number; // Maximum file size in bytes (default: 10MB)
|
|
752
|
+
maxFiles?: number; // Maximum number of files allowed (default: 10)
|
|
753
|
+
showPreview?: boolean; // Show image previews (default: true)
|
|
230
754
|
}
|
|
231
755
|
```
|
|
232
756
|
|
|
757
|
+
### TableFieldDto<T>
|
|
758
|
+
Table configuration for the LiteTable component.
|
|
759
|
+
|
|
760
|
+
```typescript
|
|
761
|
+
class TableFieldDto<T = any> {
|
|
762
|
+
columns: TableColumn[];
|
|
763
|
+
data: T[];
|
|
764
|
+
showPaginator?: boolean;
|
|
765
|
+
paginatorConfig: PaginatorFieldDto;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
interface TableColumn {
|
|
769
|
+
key: string; // Data property key (supports dot notation)
|
|
770
|
+
label: string; // Column header text
|
|
771
|
+
flex?: string; // CSS flex property (e.g., '0 0 100px', '1')
|
|
772
|
+
sortable?: boolean; // Show sorting indicator
|
|
773
|
+
cellTemplate?: (value: any, row: any) => string; // Custom HTML template
|
|
774
|
+
type?: 'text' | 'menu'; // Optional column type (default: 'text')
|
|
775
|
+
menuItems?: Array<{ label: string; value: string; variant?: 'danger' | 'default' }>; // For 'menu' type columns
|
|
776
|
+
}
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
### PaginatorFieldDto
|
|
780
|
+
Pagination configuration for table and standalone pagination components.
|
|
781
|
+
|
|
782
|
+
```typescript
|
|
783
|
+
class PaginatorFieldDto {
|
|
784
|
+
currentPage: number;
|
|
785
|
+
totalItems: number;
|
|
786
|
+
itemsPerPage: number;
|
|
787
|
+
}
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
---
|
|
791
|
+
|
|
233
792
|
## Validation
|
|
234
793
|
|
|
235
|
-
All components support Angular Reactive Forms
|
|
794
|
+
All components support Angular Reactive Forms validation:
|
|
236
795
|
|
|
237
796
|
```typescript
|
|
238
797
|
import { Validators } from '@angular/forms';
|
|
239
798
|
|
|
240
|
-
|
|
799
|
+
// Required field
|
|
800
|
+
emailField = new FieldDto(
|
|
241
801
|
'Email',
|
|
242
802
|
new FormControl('', [Validators.required, Validators.email])
|
|
243
803
|
);
|
|
804
|
+
|
|
805
|
+
// Custom validation
|
|
806
|
+
passwordField = new FieldDto(
|
|
807
|
+
'Password',
|
|
808
|
+
new FormControl('', [
|
|
809
|
+
Validators.required,
|
|
810
|
+
Validators.minLength(8),
|
|
811
|
+
this.customPasswordValidator
|
|
812
|
+
])
|
|
813
|
+
);
|
|
244
814
|
```
|
|
245
815
|
|
|
246
816
|
Error messages are automatically displayed below invalid fields.
|
|
247
817
|
|
|
248
|
-
|
|
818
|
+
---
|
|
249
819
|
|
|
250
|
-
|
|
820
|
+
## Styling and Customization
|
|
251
821
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
```
|
|
822
|
+
### Default Styling
|
|
823
|
+
The library includes pre-built SCSS styles that provide:
|
|
824
|
+
- Floating label animations
|
|
825
|
+
- Focus states and transitions
|
|
826
|
+
- Error styling
|
|
827
|
+
- Responsive design
|
|
259
828
|
|
|
260
|
-
|
|
829
|
+
### Custom Styling
|
|
830
|
+
- Follow the compact SCSS conventions described in [docs/STYLEGUIDE.md](https://github.com/liangk/lite-form/blob/main/docs/STYLEGUIDE.md).
|
|
831
|
+
- Components expose BEM-style class names for targeted overrides.
|
|
832
|
+
- Import `lite-styles.scss` to leverage shared design tokens and mixins.
|
|
261
833
|
|
|
262
|
-
|
|
263
|
-
```bash
|
|
264
|
-
ng build lite-form
|
|
265
|
-
```
|
|
834
|
+
---
|
|
266
835
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
cd dist/lite-form
|
|
270
|
-
npm publish
|
|
271
|
-
```
|
|
836
|
+
## Development
|
|
837
|
+
Project layout at a glance:
|
|
272
838
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
839
|
+
```
|
|
840
|
+
lite-form/
|
|
841
|
+
├── projects/lite-form/ # Library source and public API
|
|
842
|
+
├── projects/ui-sandbox/ # Demo application showcasing components
|
|
843
|
+
├── docs/ # Documentation, guides, and changelog
|
|
844
|
+
└── scripts/ # Build and publishing utilities
|
|
276
845
|
```
|
|
277
846
|
|
|
278
|
-
|
|
279
|
-
- Angular 17+
|
|
280
|
-
- Chrome 90+
|
|
281
|
-
- Firefox 88+
|
|
282
|
-
- Safari 14+
|
|
283
|
-
- Edge 90+
|
|
284
|
-
|
|
847
|
+
For the full contributor guide and extended structure diagram, see [docs/CONTRIBUTING.md](https://github.com/liangk/lite-form/blob/main/docs/CONTRIBUTING.md).
|
|
285
848
|
## License
|
|
286
|
-
MIT License
|
|
849
|
+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/liangk/lite-form/blob/main/LICENSE) file for details.
|
|
287
850
|
|
|
288
851
|
---
|
|
289
852
|
|
|
290
|
-
|
|
853
|
+
## Changelog
|
|
854
|
+
- See [docs/CHANGELOG.md](https://github.com/liangk/lite-form/blob/main/docs/CHANGELOG.md) for the full historical record, including the latest `v1.3.1` release with `LiteTable` row menu actions and README updates.
|