@enerjisaformlibrary/formbuilder-react 1.0.9 → 1.0.22

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 CHANGED
@@ -1,27 +1,22 @@
1
1
  # @enerjisaformlibrary/formbuilder-react
2
2
 
3
- A comprehensive, standalone drag-and-drop form builder React component. All UI components, styles, and dependencies are bundled - only React is required as a peer dependency.
4
-
5
- ## Table of Contents
6
-
7
- - [Installation](#installation)
8
- - [Quick Start](#quick-start)
9
- - [FormBuilder Props](#formbuilder-props)
10
- - [Exported Components](#exported-components)
11
- - [Form Schema Structure](#form-schema-structure)
12
- - [Field Types](#field-types)
13
- - [Validation Rules](#validation-rules)
14
- - [Conditional Logic](#conditional-logic)
15
- - [Multi-Step Forms](#multi-step-forms)
16
- - [Container Fields](#container-fields)
17
- - [Custom Styling](#custom-styling)
18
- - [Events & Actions](#events--actions)
19
- - [Zustand Store API](#zustand-store-api)
20
- - [TypeScript Types](#typescript-types)
21
- - [Complete JSON Example](#complete-json-example)
22
- - [Extracting Form Values](#extracting-form-values)
23
-
24
- ---
3
+ Professional drag-and-drop form builder React component with 20+ field types, multi-step wizard support, conditional logic, undo/redo history, and JSON export/import.
4
+
5
+ ## Features
6
+
7
+ - **20+ Field Types**: Text, textarea, number, email, phone, URL, password, date, time, date range, dropdown, checkbox, radio, toggle, multi-select, file upload, signature pad, star rating, slider, color picker, rich text editor, autocomplete, QR code, pattern format, and more
8
+ - **Drag & Drop**: Intuitive drag-and-drop interface for building forms
9
+ - **Multi-Step Wizard**: Create multi-step forms with progress indicator
10
+ - **Conditional Logic**: Show/hide/enable/disable fields based on conditions
11
+ - **Undo/Redo**: Full undo/redo support with 50-state history
12
+ - **Grid Layout**: 12-column responsive grid system
13
+ - **Containers**: Nested row/column layouts within containers
14
+ - **JSON Export/Import**: Export forms as JSON and import them back
15
+ - **Custom Styling**: Per-field CSS class customization
16
+ - **Form Versioning**: Save and restore form versions
17
+ - **Tooltips**: Help text support for fields
18
+ - **Actions System**: onClick, onChange, onFocus, onBlur event handlers
19
+ - **Tab Index**: Keyboard navigation order for form fields
25
20
 
26
21
  ## Installation
27
22
 
@@ -29,700 +24,290 @@ A comprehensive, standalone drag-and-drop form builder React component. All UI c
29
24
  npm install @enerjisaformlibrary/formbuilder-react
30
25
  ```
31
26
 
32
- **Peer Dependencies:**
33
- - `react`: ^18.0.0
34
- - `react-dom`: ^18.0.0
35
-
36
- ---
37
-
38
27
  ## Quick Start
39
28
 
40
29
  ```tsx
41
- import { FormBuilder, useFormStore } from '@enerjisaformlibrary/formbuilder-react';
30
+ import { FormBuilder } from '@enerjisaformlibrary/formbuilder-react';
42
31
  import '@enerjisaformlibrary/formbuilder-react/styles.css';
43
32
 
44
33
  function App() {
45
- const handleChange = (form) => {
46
- // Called on every form schema change
47
- console.log('Form schema updated:', form);
34
+ const handleSave = (formSchema) => {
35
+ console.log('Form saved:', formSchema);
36
+ // Save to your database
48
37
  };
49
38
 
50
- const handleSave = (form) => {
51
- // Save form JSON to your database
52
- const jsonString = JSON.stringify(form, null, 2);
53
- saveToDatabase(jsonString);
39
+ const handleChange = (formSchema) => {
40
+ console.log('Form changed:', formSchema);
54
41
  };
55
42
 
56
43
  return (
57
- <div style={{ height: '100vh', width: '100%' }}>
58
- <FormBuilder
59
- onChange={handleChange}
60
- onSave={handleSave}
61
- theme="light"
62
- showToolbar={true}
63
- showComponentLibrary={true}
64
- showPropertiesPanel={true}
65
- />
66
- </div>
67
- );
68
- }
69
- ```
70
-
71
- ### Loading Existing Form
72
-
73
- ```tsx
74
- import { FormBuilder } from '@enerjisaformlibrary/formbuilder-react';
75
- import '@enerjisaformlibrary/formbuilder-react/styles.css';
76
-
77
- function EditForm({ existingFormJson }) {
78
- // Parse JSON string if needed
79
- const initialForm = typeof existingFormJson === 'string'
80
- ? JSON.parse(existingFormJson)
81
- : existingFormJson;
82
-
83
- return (
84
- <FormBuilder
85
- initialForm={initialForm}
86
- onSave={(form) => updateInDatabase(form)}
44
+ <FormBuilder
45
+ onSave={handleSave}
46
+ onChange={handleChange}
87
47
  />
88
48
  );
89
49
  }
90
50
  ```
91
51
 
92
- ---
93
-
94
- ## FormBuilder Props
95
-
96
- | Prop | Type | Default | Description |
97
- |------|------|---------|-------------|
98
- | `initialForm` | `FormSchema` | `undefined` | Pre-existing form schema to load |
99
- | `onSave` | `(form: FormSchema) => void` | `undefined` | Callback when save button clicked |
100
- | `onChange` | `(form: FormSchema) => void` | `undefined` | Callback on every form change |
101
- | `className` | `string` | `''` | Additional CSS class for container |
102
- | `theme` | `'light' \| 'dark'` | `'light'` | Color theme |
103
- | `showToolbar` | `boolean` | `true` | Show/hide top toolbar |
104
- | `showComponentLibrary` | `boolean` | `true` | Show/hide left component panel |
105
- | `showPropertiesPanel` | `boolean` | `true` | Show/hide right properties panel |
106
-
107
- ---
108
-
109
- ## Exported Components
110
-
111
- ```tsx
112
- // Main wrapper component (recommended)
113
- import { FormBuilder } from '@enerjisaformlibrary/formbuilder-react';
114
-
115
- // Individual components for custom layouts
116
- import {
117
- FormCanvas, // Central form editing canvas
118
- PropertiesPanel, // Right-side property editor
119
- ComponentLibrary, // Left-side component palette
120
- Toolbar, // Top toolbar with actions
121
- CanvasField, // Individual field renderer
122
- DragOverlayContent, // Drag preview overlay
123
- JsonViewerModal, // JSON preview modal
124
- } from '@enerjisaformlibrary/formbuilder-react';
125
-
126
- // Zustand store for state management
127
- import { useFormStore } from '@enerjisaformlibrary/formbuilder-react';
128
-
129
- // All TypeScript types and schemas
130
- import type {
131
- FormSchema,
132
- FormField,
133
- FormRow,
134
- FormColumn,
135
- Step,
136
- FieldProps,
137
- Validation,
138
- ConditionalLogic,
139
- CustomStyle,
140
- SubmissionConfig,
141
- } from '@enerjisaformlibrary/formbuilder-react';
142
- ```
52
+ ## Props
143
53
 
144
- ---
54
+ | Prop | Type | Required | Description |
55
+ |------|------|----------|-------------|
56
+ | `initialSchema` | `FormSchema` | No | Initial form schema to load |
57
+ | `onSave` | `(schema: FormSchema) => void` | No | Called when user clicks Save button |
58
+ | `onChange` | `(schema: FormSchema) => void` | No | Called on every form change |
145
59
 
146
60
  ## Form Schema Structure
147
61
 
148
- The form is represented as a hierarchical JSON structure:
149
-
150
62
  ```typescript
151
63
  interface FormSchema {
152
- id: string; // Unique form identifier
153
- name: string; // Form display name
154
- description?: string; // Optional description
155
- rows: FormRow[]; // Array of rows (single-page mode)
156
- steps?: Step[]; // Array of steps (multi-step mode)
157
- isMultiStep?: boolean; // Enable multi-step wizard
158
- submissionConfig?: SubmissionConfig; // Webhook/submission settings
159
- settings?: FormSettings; // Global form settings
160
- versions?: FormVersion[]; // Version history
161
- currentVersion?: number; // Current version number
162
- createdAt?: string; // ISO date string
163
- updatedAt?: string; // ISO date string
64
+ id: string;
65
+ name: string;
66
+ description?: string;
67
+ isMultiStep: boolean;
68
+ currentVersion: number;
69
+ rows: FormRow[]; // For single-page forms
70
+ steps?: FormStep[]; // For multi-step forms
71
+ settings?: FormSettings;
72
+ submissionConfig?: SubmissionConfig;
73
+ versions?: FormVersion[];
164
74
  }
165
75
 
166
76
  interface FormRow {
167
77
  id: string;
168
- columns: FormColumn[]; // 12-column grid system
169
- conditionalLogic?: ConditionalLogic; // Row-level conditions
170
- fieldSize?: 'compact' | 'normal' | 'comfortable';
171
- spacing?: number; // 0-16
172
- padding?: number; // 0-16
78
+ columns: FormColumn[];
79
+ conditionalLogic?: ConditionalLogic;
173
80
  }
174
81
 
175
82
  interface FormColumn {
176
83
  id: string;
177
- width: number; // 1-12 (grid columns)
178
- responsiveWidth?: ResponsiveWidth; // Mobile/tablet overrides
179
- fields: FormField[]; // Fields in this column
84
+ width: number; // 1-12 (grid columns)
85
+ fields: FormField[];
86
+ responsiveWidth?: ResponsiveWidth;
180
87
  }
181
88
 
182
89
  interface FormField {
183
- id: string; // Unique field identifier
184
- type: string; // Field type (see Field Types)
185
- props: FieldProps; // Field properties
186
- validation?: Validation; // Validation rules
187
- conditionalLogic?: ConditionalLogic; // Field conditions
188
- customStyle?: CustomStyle; // CSS customization
189
- localization?: Localization; // Multi-language support
190
- computed?: ComputedField; // Calculated fields
191
- responsiveWidth?: ResponsiveWidth; // Responsive breakpoints
192
- events?: FieldEvents; // Event handlers
90
+ id: string;
91
+ type: FieldType;
92
+ props: FieldProps;
93
+ validation?: FieldValidation;
94
+ conditionalLogic?: ConditionalLogic;
95
+ customStyle?: CustomStyle;
193
96
  }
194
97
  ```
195
98
 
196
- ---
197
-
198
99
  ## Field Types
199
100
 
200
- ### Basic Input Fields
101
+ ### Basic Fields
102
+ - `input` - Single line text input
103
+ - `textarea` - Multi-line text area
104
+ - `number` - Numeric input
105
+ - `email` - Email input with validation
106
+ - `password` - Password input
107
+ - `phone` - Phone number input
108
+ - `url` - URL input
201
109
 
202
- | Type | Description | Key Props |
203
- |------|-------------|-----------|
204
- | `input` | Single-line text input | `placeholder`, `maxLength` |
205
- | `textarea` | Multi-line text area | `placeholder`, `rows` |
206
- | `number` | Numeric input | `min`, `max`, `step` |
207
- | `email` | Email input with validation | `placeholder` |
208
- | `password` | Password input (masked) | `placeholder` |
209
- | `phone` | Phone number input | `placeholder` |
210
- | `url` | URL input with validation | `placeholder` |
110
+ ### Date & Time
111
+ - `date` - Date picker
112
+ - `time` - Time picker
113
+ - `daterange` - Date range picker
211
114
 
212
115
  ### Selection Fields
213
-
214
- | Type | Description | Key Props |
215
- |------|-------------|-----------|
216
- | `dropdown` | Single select dropdown | `options`, `optionsString` |
217
- | `checkbox` | Single checkbox | `defaultValue` |
218
- | `radio` | Radio button group | `options`, `optionsString` |
219
- | `toggle` | On/off toggle switch | `defaultValue` |
220
- | `multiselect` | Multi-select with tags | `options`, `multiSelectConfig` |
221
-
222
- ### Date & Time Fields
223
-
224
- | Type | Description | Key Props |
225
- |------|-------------|-----------|
226
- | `date` | Date picker | `defaultValue` |
227
- | `time` | Time picker | `timeConfig.format` |
228
- | `daterange` | Date range picker | `dateRangeConfig` |
116
+ - `dropdown` - Single select dropdown
117
+ - `checkbox` - Checkbox field
118
+ - `radio` - Radio button group
119
+ - `toggle` - Toggle switch
120
+ - `multiselect` - Multi-select with tags
229
121
 
230
122
  ### Advanced Fields
231
-
232
- | Type | Description | Key Props |
233
- |------|-------------|-----------|
234
- | `file` | File upload with drag-drop | `fileConfig` |
235
- | `signature` | Signature pad (canvas) | `signatureConfig` |
236
- | `rating` | Star rating | `ratingConfig.maxRating` |
237
- | `richtext` | Rich text editor | `richTextConfig` |
238
- | `autocomplete` | Autocomplete input | `autocompleteConfig`, `options` |
239
- | `slider` | Range slider | `min`, `max`, `step` |
240
- | `pattern` | Input masking | `patternConfig.format` |
241
- | `qrcode` | QR code display | `qrCodeConfig.value`, `qrCodeConfig.size` |
242
- | `table` | Data table input | `tableConfig` |
243
- | `color` | Color picker | `defaultValue` |
244
-
245
- ### Static/Display Elements
246
-
247
- | Type | Description | Key Props |
248
- |------|-------------|-----------|
249
- | `header` | H1 heading | `label` |
250
- | `subheader` | H2/H3 heading | `label` |
251
- | `label` | Text label | `label` |
252
- | `paragraph` | Paragraph text | `label` |
253
- | `divider` | Horizontal divider | `dividerMargin` |
254
- | `spacer` | Vertical spacer | `spacerHeight` |
255
- | `image` | Image display | `imageUrl`, `imageWidth`, `imageHeight` |
256
- | `button` | Action button | `buttonConfig` |
257
-
258
- ### Structure Elements
259
-
260
- | Type | Description | Key Props |
261
- |------|-------------|-----------|
262
- | `container` | Grouping container | `containerConfig` |
263
- | `row` | Grid row | - |
264
-
265
- ---
266
-
267
- ## Field Props (FieldProps)
123
+ - `file` - File upload with drag-drop
124
+ - `signature` - Signature pad with canvas drawing
125
+ - `rating` - Star rating (configurable max stars)
126
+ - `slider` - Range slider with min/max
127
+ - `color` - Color picker with hex input
128
+ - `richtext` - Rich text editor
129
+ - `autocomplete` - Autocomplete input
130
+ - `pattern` - Pattern format input (phone, credit card, etc.)
131
+ - `qrcode` - Static QR code display
132
+
133
+ ### Static Elements
134
+ - `header` - Section header
135
+ - `label` - Static label text
136
+ - `paragraph` - Paragraph text
137
+ - `divider` - Horizontal divider
138
+ - `spacer` - Vertical spacer
139
+ - `alert` - Alert/notification box
140
+ - `image` - Image placeholder
141
+ - `button` - Submit/reset/custom action buttons
142
+
143
+ ### Structure
144
+ - `container` - Grouping element with nested rows/columns
145
+
146
+ ## Field Props
268
147
 
269
148
  ```typescript
270
149
  interface FieldProps {
271
- key: string; // Unique field key (for form values)
272
- label: string; // Display label
273
- placeholder?: string; // Input placeholder
274
- value?: any; // Current value
275
- defaultValue?: any; // Default value
276
- helpText?: string; // Help text below field
277
- tooltip?: string; // Tooltip on hover
150
+ key: string; // Unique field key for form data
151
+ label?: string; // Field label
152
+ placeholder?: string; // Placeholder text
153
+ tooltip?: string; // Help tooltip text
154
+ optionsString?: string; // Options for dropdown/radio/checkbox (one per line)
278
155
  size?: 'small' | 'medium' | 'large';
279
- containerWidth?: 'auto' | '25' | '33' | '50' | '66' | '75' | '100';
280
- disabled?: boolean; // Disable field
281
- readOnly?: boolean; // Read-only mode
282
- hidden?: boolean; // Hide field
283
- autoFocus?: boolean; // Auto-focus on mount
284
- tabIndex?: number; // Tab order
285
- htmlAttributes?: Record<string, string>; // Custom HTML attributes
156
+ autoFocus?: boolean;
157
+ tabIndex?: number; // Keyboard navigation order (positive = order, -1 = skip, 0 = natural order)
158
+ htmlAttributes?: Record<string, string>;
286
159
 
287
- // Options for selection fields
288
- options?: Array<{ label: string; value: string }>;
289
- optionsString?: string[]; // Simple string array for options
160
+ // Button specific
161
+ buttonConfig?: {
162
+ buttonType: 'submit' | 'reset' | 'button';
163
+ variant: 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive';
164
+ actionType?: 'submit' | 'reset' | 'navigate' | 'custom';
165
+ navigateUrl?: string;
166
+ customAction?: string;
167
+ };
290
168
 
291
- // Field-specific configs
292
- fileConfig?: FileUploadConfig;
293
- ratingConfig?: RatingConfig;
294
- autocompleteConfig?: AutocompleteConfig;
295
- richTextConfig?: RichTextConfig;
296
- dateRangeConfig?: DateRangeConfig;
297
- timeConfig?: TimeConfig;
298
- signatureConfig?: SignatureConfig;
299
- multiSelectConfig?: MultiSelectConfig;
300
- patternConfig?: PatternConfig;
301
- buttonConfig?: ButtonConfig;
302
- qrCodeConfig?: QRCodeConfig;
303
- containerConfig?: ContainerConfig;
304
- tableConfig?: TableConfig;
169
+ // Pattern format specific
170
+ patternConfig?: {
171
+ format: 'phone' | 'creditCard' | 'date' | 'ssn' | 'custom';
172
+ mask?: string;
173
+ customPattern?: string;
174
+ };
305
175
 
306
- // Layout
307
- spacerHeight?: number; // For spacer type
308
- dividerMargin?: number; // For divider type
309
- imageUrl?: string; // For image type
310
- imageWidth?: string;
311
- imageHeight?: string;
312
- }
313
- ```
314
-
315
- ---
316
-
317
- ## Validation Rules
318
-
319
- ```typescript
320
- interface Validation {
321
- required?: boolean; // Field is required
322
- minLength?: number; // Minimum text length
323
- maxLength?: number; // Maximum text length
324
- min?: number; // Minimum numeric value
325
- max?: number; // Maximum numeric value
326
- pattern?: string; // Regex pattern
327
- errorMessage?: string; // Custom error message
328
- customValidation?: string; // Custom validation code
329
- validationType?: 'email' | 'url' | 'phone' | 'creditCard' | 'custom';
330
- autoValidate?: boolean; // Validate automatically
331
- validateOnBlur?: boolean; // Validate on blur
332
- validateOnChange?: boolean; // Validate on change
333
- }
334
- ```
335
-
336
- **Example:**
337
- ```json
338
- {
339
- "validation": {
340
- "required": true,
341
- "minLength": 3,
342
- "maxLength": 100,
343
- "pattern": "^[a-zA-Z]+$",
344
- "errorMessage": "Only letters allowed, 3-100 characters"
345
- }
176
+ // QR Code specific
177
+ qrCodeConfig?: {
178
+ value: string;
179
+ size: number;
180
+ };
181
+
182
+ // Container specific
183
+ containerConfig?: {
184
+ rows: ContainerRow[];
185
+ gap?: number;
186
+ padding?: number;
187
+ borderStyle?: 'none' | 'solid' | 'dashed';
188
+ };
189
+
190
+ // Rating specific
191
+ maxRating?: number;
192
+
193
+ // Slider specific
194
+ min?: number;
195
+ max?: number;
196
+ step?: number;
346
197
  }
347
198
  ```
348
199
 
349
- ---
350
-
351
- ## Conditional Logic
352
-
353
- Show, hide, enable, disable, or require fields based on other field values:
354
-
355
- ```typescript
356
- interface ConditionalLogic {
357
- enabled: boolean; // Enable/disable conditional logic
358
- action: 'show' | 'hide' | 'enable' | 'disable' | 'require';
359
- logicType: 'all' | 'any'; // Match all or any condition
360
- conditions: Condition[];
361
- }
200
+ ## Tab Index Usage
362
201
 
363
- interface Condition {
364
- fieldKey: string; // Key of field to check
365
- operator: ConditionOperator; // Comparison operator
366
- value?: any; // Value to compare against
367
- }
202
+ The `tabIndex` property controls keyboard navigation order when users press Tab to move between form fields:
368
203
 
369
- type ConditionOperator =
370
- | 'equals'
371
- | 'notEquals'
372
- | 'contains'
373
- | 'notContains'
374
- | 'greaterThan'
375
- | 'lessThan'
376
- | 'greaterThanOrEqual'
377
- | 'lessThanOrEqual'
378
- | 'isEmpty'
379
- | 'isNotEmpty'
380
- | 'startsWith'
381
- | 'endsWith';
382
- ```
204
+ | Value | Behavior |
205
+ |-------|----------|
206
+ | Positive (1, 2, 3...) | Field is focused in order from lowest to highest tabIndex |
207
+ | 0 | Field follows natural DOM order |
208
+ | -1 | Field is skipped during Tab navigation |
383
209
 
384
- **Example: Show field when another field equals "yes":**
385
- ```json
386
- {
387
- "conditionalLogic": {
388
- "enabled": true,
389
- "action": "show",
390
- "logicType": "all",
391
- "conditions": [
392
- {
393
- "fieldKey": "has_experience",
394
- "operator": "equals",
395
- "value": "yes"
396
- }
397
- ]
398
- }
399
- }
400
- ```
210
+ **Example:** To create a custom tab order:
211
+ - First Name: tabIndex = 1
212
+ - Email: tabIndex = 2
213
+ - Last Name: tabIndex = 3
214
+ - Phone: tabIndex = 4
401
215
 
402
- ---
216
+ When user presses Tab, they'll move: First Name → Email → Last Name → Phone
403
217
 
404
- ## Multi-Step Forms
218
+ **Important:** tabIndex only works in **Preview Mode**. In editor mode, fields don't receive focus in the same way.
405
219
 
406
- Enable wizard-style forms with multiple steps:
220
+ ## Validation
407
221
 
408
222
  ```typescript
409
- interface Step {
410
- id: string;
411
- title: string; // Step title
412
- description?: string; // Step description
413
- icon?: string; // Lucide icon name
414
- rows: FormRow[]; // Rows in this step
415
- validation?: {
416
- validateOnNext?: boolean; // Validate before next step
417
- allowSkip?: boolean; // Allow skipping this step
418
- };
223
+ interface FieldValidation {
224
+ required?: boolean;
225
+ minLength?: number;
226
+ maxLength?: number;
227
+ min?: number;
228
+ max?: number;
229
+ pattern?: string;
230
+ customMessage?: string;
419
231
  }
420
232
  ```
421
233
 
422
- **Example Multi-Step Form:**
423
- ```json
424
- {
425
- "id": "registration-form",
426
- "name": "User Registration",
427
- "isMultiStep": true,
428
- "steps": [
429
- {
430
- "id": "step-1",
431
- "title": "Personal Info",
432
- "description": "Enter your personal details",
433
- "rows": [...]
434
- },
435
- {
436
- "id": "step-2",
437
- "title": "Contact",
438
- "description": "How can we reach you?",
439
- "rows": [...]
440
- },
441
- {
442
- "id": "step-3",
443
- "title": "Preferences",
444
- "validation": { "allowSkip": true },
445
- "rows": [...]
446
- }
447
- ],
448
- "rows": []
449
- }
450
- ```
451
-
452
- ---
453
-
454
- ## Container Fields
455
-
456
- Containers allow nested layouts with their own grid system:
234
+ ## Conditional Logic
457
235
 
458
236
  ```typescript
459
- interface ContainerConfig {
460
- direction?: 'row' | 'column';
461
- gap?: number; // Gap between items
462
- padding?: number; // Internal padding
463
- background?: string; // Background color
464
- border?: boolean; // Show border
465
- flexWrap?: 'wrap' | 'nowrap';
466
- justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
467
- alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
468
- fieldSize?: 'compact' | 'normal' | 'comfortable';
469
- rows?: ContainerRow[]; // Nested rows structure
470
- }
471
-
472
- interface ContainerRow {
473
- id: string;
474
- width: number; // 1-12 grid width
475
- height?: number; // 40-500 pixels or auto
476
- columns: ContainerColumn[];
237
+ interface ConditionalLogic {
238
+ enabled: boolean;
239
+ action: 'show' | 'hide' | 'enable' | 'disable' | 'require';
240
+ conditions: Condition[];
241
+ logicOperator: 'and' | 'or';
477
242
  }
478
243
 
479
- interface ContainerColumn {
480
- id: string;
481
- width: number; // 1-12 grid width
482
- fieldId?: string; // ID of field in this column
483
- fields?: FormField[]; // Fields in this column
244
+ interface Condition {
245
+ fieldKey: string;
246
+ operator: 'equals' | 'notEquals' | 'contains' | 'notContains' |
247
+ 'greaterThan' | 'lessThan' | 'isEmpty' | 'isNotEmpty';
248
+ value: string;
484
249
  }
485
250
  ```
486
251
 
487
- ---
488
-
489
252
  ## Custom Styling
490
253
 
491
- Per-field CSS customization:
492
-
493
254
  ```typescript
494
255
  interface CustomStyle {
495
- className?: string; // Additional CSS class
256
+ containerClassName?: string; // CSS class for field container
496
257
  labelClassName?: string; // CSS class for label
497
- inputClassName?: string; // CSS class for input
498
- containerClassName?: string; // CSS class for container
499
- css?: string; // Custom inline CSS
500
- wrapperCss?: string; // Wrapper element CSS
501
- deviceTarget?: 'any' | 'mobile' | 'tablet' | 'desktop';
502
- width?: { value?: number; unit?: string };
503
- height?: string;
504
- marginTop?: string;
505
- marginRight?: string;
506
- marginBottom?: string;
507
- marginLeft?: string;
508
- color?: string;
509
- backgroundColor?: string;
510
- }
511
- ```
512
-
513
- **Example:**
514
- ```json
515
- {
516
- "customStyle": {
517
- "containerClassName": "my-field-wrapper",
518
- "labelClassName": "text-lg font-bold",
519
- "inputClassName": "border-2 border-blue-500",
520
- "backgroundColor": "#f0f0f0"
521
- }
258
+ inputClassName?: string; // CSS class for input element
259
+ css?: string; // Custom CSS (applied inline)
522
260
  }
523
261
  ```
524
262
 
525
- ---
263
+ ## Actions System
526
264
 
527
- ## Events & Actions
528
-
529
- Define event handlers for field interactions:
265
+ Each field can have event handlers:
530
266
 
531
267
  ```typescript
532
- interface FieldEvents {
533
- onClick?: EventAction[];
534
- onChange?: EventAction[];
535
- onFocus?: EventAction[];
536
- onBlur?: EventAction[];
537
- onMount?: EventAction[];
538
- onUnmount?: EventAction[];
268
+ interface FieldActions {
269
+ onClick?: FieldAction;
270
+ onChange?: FieldAction;
271
+ onFocus?: FieldAction;
272
+ onBlur?: FieldAction;
539
273
  }
540
274
 
541
- interface EventAction {
542
- type: 'common' | 'code' | 'custom';
543
- name: string; // Action name
544
- code?: string; // JavaScript code (for code type)
545
- args?: Record<string, any>; // Action arguments
275
+ interface FieldAction {
276
+ type: 'showMessage' | 'hideField' | 'showField' | 'clearField' |
277
+ 'setFieldValue' | 'focusField' | 'submitForm' | 'custom' | 'code';
278
+ args?: {
279
+ message?: string;
280
+ targetFieldKey?: string;
281
+ value?: string;
282
+ code?: string;
283
+ };
546
284
  }
547
285
  ```
548
286
 
549
- ---
550
-
551
- ## Submission Config
552
-
553
- Configure form submission behavior:
287
+ ## Multi-Step Forms
554
288
 
555
289
  ```typescript
556
- interface SubmissionConfig {
557
- enabled: boolean;
558
- webhookUrl?: string; // Webhook endpoint
559
- webhookMethod?: 'POST' | 'PUT' | 'PATCH';
560
- webhookHeaders?: Record<string, string>;
561
- emailNotification?: {
562
- enabled?: boolean;
563
- to?: string[];
564
- subject?: string;
565
- template?: string;
566
- };
567
- apiEndpoint?: {
568
- url?: string;
569
- method?: 'POST' | 'PUT' | 'PATCH';
570
- headers?: Record<string, string>;
290
+ interface FormStep {
291
+ id: string;
292
+ title: string;
293
+ description?: string;
294
+ order: number;
295
+ rows: FormRow[];
296
+ validation?: {
297
+ validateOnNext?: boolean;
298
+ allowSkip?: boolean;
571
299
  };
572
- redirectUrl?: string; // Redirect after submit
573
- successMessage?: string; // Success message
574
- errorMessage?: string; // Error message
575
- }
576
- ```
577
-
578
- ---
579
-
580
- ## Zustand Store API
581
-
582
- Access and manipulate form state programmatically:
583
-
584
- ```tsx
585
- import { useFormStore } from '@enerjisaformlibrary/formbuilder-react';
586
-
587
- function MyComponent() {
588
- const {
589
- // State
590
- form, // Current FormSchema
591
- selection, // Selected element
592
- previewMode, // Preview mode state
593
- formValues, // Form values (in preview)
594
-
595
- // Form Actions
596
- loadForm, // Load form schema
597
- setFormName, // Set form name
598
- resetForm, // Reset to empty form
599
-
600
- // Row Actions
601
- addRow, // Add empty row
602
- addRowWithField, // Add row with a field
603
- updateRow, // Update row properties
604
- deleteRow, // Delete row
605
- moveRow, // Move/reorder row
606
-
607
- // Column Actions
608
- addColumn, // Add column to row
609
- updateColumn, // Update column properties
610
- deleteColumn, // Delete column
611
-
612
- // Field Actions
613
- addField, // Add field to column
614
- updateField, // Update field properties
615
- deleteField, // Delete field
616
- moveField, // Move field between columns
617
-
618
- // Container Actions
619
- addFieldToContainer, // Add field to container column
620
- addFieldToContainerDirect, // Add field to container
621
-
622
- // Selection
623
- setSelection, // Set selected element
624
- clearSelection, // Clear selection
625
-
626
- // Preview
627
- setPreviewMode, // Toggle preview mode
628
- setFormValue, // Set field value in preview
629
-
630
- // Multi-step
631
- addStep, // Add wizard step
632
- updateStep, // Update step
633
- deleteStep, // Delete step
634
- moveStep, // Reorder step
635
- setCurrentStep, // Navigate to step
636
-
637
- // Version Control
638
- saveVersion, // Save form version
639
- restoreVersion, // Restore previous version
640
-
641
- // Undo/Redo
642
- undo, // Undo last action
643
- redo, // Redo undone action
644
- canUndo, // Check if undo available
645
- canRedo, // Check if redo available
646
-
647
- } = useFormStore();
648
-
649
- // Example: Get current form JSON
650
- const formJson = JSON.stringify(form, null, 2);
651
-
652
- // Example: Load existing form
653
- useEffect(() => {
654
- loadForm(existingFormData);
655
- }, []);
656
300
  }
657
301
  ```
658
302
 
659
- ---
660
-
661
- ## TypeScript Types
662
-
663
- All types are exported for TypeScript usage:
664
-
665
- ```typescript
666
- import type {
667
- // Core Types
668
- FormSchema,
669
- FormField,
670
- FormRow,
671
- FormColumn,
672
- Step,
673
-
674
- // Field Configuration
675
- FieldProps,
676
- Validation,
677
- ConditionalLogic,
678
- Condition,
679
- ConditionOperator,
680
- CustomStyle,
681
- ResponsiveWidth,
682
- FieldEvents,
683
- EventAction,
684
-
685
- // Field-Specific Configs
686
- FileUploadConfig,
687
- RatingConfig,
688
- AutocompleteConfig,
689
- SignatureConfig,
690
- PatternConfig,
691
- ButtonConfig,
692
- QRCodeConfig,
693
- ContainerConfig,
694
- TableConfig,
695
-
696
- // Form Settings
697
- FormSettings,
698
- SubmissionConfig,
699
- FormVersion,
700
- Localization,
701
- ComputedField,
702
-
703
- // Selection
704
- Selection,
705
- SelectionType,
706
-
707
- // Field Type Constants
708
- FieldType,
709
- StructureType,
710
- StaticType,
711
- } from '@enerjisaformlibrary/formbuilder-react';
712
- ```
713
-
714
- ---
715
-
716
- ## Complete JSON Example
717
-
718
- Here's a complete form with various field types:
303
+ ## Example: Complete Form Schema
719
304
 
720
305
  ```json
721
306
  {
722
- "id": "contact-form-001",
307
+ "id": "contact-form",
723
308
  "name": "Contact Form",
724
- "description": "A sample contact form",
725
309
  "isMultiStep": false,
310
+ "currentVersion": 1,
726
311
  "rows": [
727
312
  {
728
313
  "id": "row-1",
@@ -735,9 +320,10 @@ Here's a complete form with various field types:
735
320
  "id": "field-1",
736
321
  "type": "input",
737
322
  "props": {
738
- "key": "first_name",
323
+ "key": "firstName",
739
324
  "label": "First Name",
740
- "placeholder": "Enter your first name"
325
+ "placeholder": "Enter your first name",
326
+ "tabIndex": 1
741
327
  },
742
328
  "validation": {
743
329
  "required": true,
@@ -754,9 +340,10 @@ Here's a complete form with various field types:
754
340
  "id": "field-2",
755
341
  "type": "input",
756
342
  "props": {
757
- "key": "last_name",
343
+ "key": "lastName",
758
344
  "label": "Last Name",
759
- "placeholder": "Enter your last name"
345
+ "placeholder": "Enter your last name",
346
+ "tabIndex": 2
760
347
  },
761
348
  "validation": {
762
349
  "required": true
@@ -779,11 +366,12 @@ Here's a complete form with various field types:
779
366
  "props": {
780
367
  "key": "email",
781
368
  "label": "Email Address",
782
- "placeholder": "you@example.com"
369
+ "placeholder": "you@example.com",
370
+ "tooltip": "We'll never share your email",
371
+ "tabIndex": 3
783
372
  },
784
373
  "validation": {
785
- "required": true,
786
- "validationType": "email"
374
+ "required": true
787
375
  }
788
376
  }
789
377
  ]
@@ -801,17 +389,10 @@ Here's a complete form with various field types:
801
389
  "id": "field-4",
802
390
  "type": "dropdown",
803
391
  "props": {
804
- "key": "inquiry_type",
805
- "label": "Inquiry Type",
806
- "options": [
807
- { "label": "General Question", "value": "general" },
808
- { "label": "Technical Support", "value": "support" },
809
- { "label": "Sales", "value": "sales" },
810
- { "label": "Other", "value": "other" }
811
- ]
812
- },
813
- "validation": {
814
- "required": true
392
+ "key": "country",
393
+ "label": "Country",
394
+ "optionsString": "USA\nCanada\nUK\nGermany\nFrance\nOther",
395
+ "tabIndex": 4
815
396
  }
816
397
  }
817
398
  ]
@@ -831,23 +412,13 @@ Here's a complete form with various field types:
831
412
  "props": {
832
413
  "key": "message",
833
414
  "label": "Message",
834
- "placeholder": "Type your message here..."
415
+ "placeholder": "How can we help you?",
416
+ "tabIndex": 5
835
417
  },
836
418
  "validation": {
837
419
  "required": true,
838
420
  "minLength": 10,
839
- "maxLength": 1000
840
- },
841
- "conditionalLogic": {
842
- "enabled": true,
843
- "action": "show",
844
- "logicType": "all",
845
- "conditions": [
846
- {
847
- "fieldKey": "inquiry_type",
848
- "operator": "isNotEmpty"
849
- }
850
- ]
421
+ "maxLength": 500
851
422
  }
852
423
  }
853
424
  ]
@@ -863,36 +434,14 @@ Here's a complete form with various field types:
863
434
  "fields": [
864
435
  {
865
436
  "id": "field-6",
866
- "type": "checkbox",
867
- "props": {
868
- "key": "agree_terms",
869
- "label": "I agree to the terms and conditions"
870
- },
871
- "validation": {
872
- "required": true,
873
- "errorMessage": "You must agree to continue"
874
- }
875
- }
876
- ]
877
- }
878
- ]
879
- },
880
- {
881
- "id": "row-6",
882
- "columns": [
883
- {
884
- "id": "col-7",
885
- "width": 12,
886
- "fields": [
887
- {
888
- "id": "field-7",
889
437
  "type": "button",
890
438
  "props": {
891
- "key": "submit_btn",
439
+ "key": "submit",
892
440
  "label": "Submit",
893
441
  "buttonConfig": {
894
- "action": "submit",
895
- "variant": "default"
442
+ "buttonType": "submit",
443
+ "variant": "primary",
444
+ "actionType": "submit"
896
445
  }
897
446
  }
898
447
  }
@@ -900,192 +449,65 @@ Here's a complete form with various field types:
900
449
  }
901
450
  ]
902
451
  }
903
- ],
904
- "submissionConfig": {
905
- "enabled": true,
906
- "webhookUrl": "https://api.example.com/forms/submit",
907
- "webhookMethod": "POST",
908
- "successMessage": "Thank you! Your message has been sent.",
909
- "redirectUrl": "/thank-you"
910
- },
911
- "settings": {
912
- "defaultLanguage": "en",
913
- "layout": {
914
- "labelPosition": "top",
915
- "spacing": "normal"
916
- }
917
- }
452
+ ]
918
453
  }
919
454
  ```
920
455
 
921
- ---
922
-
923
- ## Extracting Form Values
456
+ ## Integration with JetDesk
924
457
 
925
- When rendering this form to end users, you'll need to:
926
-
927
- 1. **Parse the JSON** to get field structure
928
- 2. **Render fields** based on their `type`
929
- 3. **Collect values** using field `props.key` as the key
930
- 4. **Apply validation** from `validation` object
931
- 5. **Handle conditional logic** to show/hide fields
458
+ ```tsx
459
+ import { FormBuilder } from '@enerjisaformlibrary/formbuilder-react';
460
+ import '@enerjisaformlibrary/formbuilder-react/styles.css';
932
461
 
933
- **Expected form values output:**
934
- ```json
935
- {
936
- "first_name": "John",
937
- "last_name": "Doe",
938
- "email": "john@example.com",
939
- "inquiry_type": "support",
940
- "message": "I need help with...",
941
- "agree_terms": true
942
- }
943
- ```
462
+ function FormEditor({ formId }) {
463
+ const [initialSchema, setInitialSchema] = useState(null);
944
464
 
945
- **Iterating through fields:**
946
- ```typescript
947
- function extractFieldsFromForm(form: FormSchema): FormField[] {
948
- const fields: FormField[] = [];
949
-
950
- const processRows = (rows: FormRow[]) => {
951
- for (const row of rows) {
952
- for (const column of row.columns) {
953
- for (const field of column.fields) {
954
- fields.push(field);
955
-
956
- // Handle container fields (nested)
957
- if (field.type === 'container' && field.props.containerConfig?.rows) {
958
- for (const containerRow of field.props.containerConfig.rows) {
959
- for (const containerCol of containerRow.columns) {
960
- if (containerCol.fields) {
961
- fields.push(...containerCol.fields);
962
- }
963
- }
964
- }
965
- }
966
- }
967
- }
968
- }
465
+ useEffect(() => {
466
+ // Load existing form from database
467
+ fetch(`/api/forms/${formId}`)
468
+ .then(res => res.json())
469
+ .then(data => setInitialSchema(data.schema));
470
+ }, [formId]);
471
+
472
+ const handleSave = async (schema) => {
473
+ await fetch(`/api/forms/${formId}`, {
474
+ method: 'PUT',
475
+ headers: { 'Content-Type': 'application/json' },
476
+ body: JSON.stringify({ schema })
477
+ });
969
478
  };
970
-
971
- if (form.isMultiStep && form.steps) {
972
- for (const step of form.steps) {
973
- processRows(step.rows);
974
- }
975
- } else {
976
- processRows(form.rows);
977
- }
978
-
979
- return fields;
980
- }
981
-
982
- // Get field keys for form values
983
- const fields = extractFieldsFromForm(formSchema);
984
- const fieldKeys = fields
985
- .filter(f => !['header', 'subheader', 'label', 'paragraph', 'divider', 'spacer', 'image', 'button'].includes(f.type))
986
- .map(f => f.props.key);
987
- ```
988
-
989
- ---
990
479
 
991
- ## Responsive Width
480
+ if (!initialSchema) return <div>Loading...</div>;
992
481
 
993
- Fields support responsive grid widths:
994
-
995
- ```typescript
996
- interface ResponsiveWidth {
997
- mobile?: number; // 1-12 columns on mobile
998
- tablet?: number; // 1-12 columns on tablet
999
- desktop?: number; // 1-12 columns on desktop
1000
- }
1001
- ```
1002
-
1003
- **Example:**
1004
- ```json
1005
- {
1006
- "responsiveWidth": {
1007
- "mobile": 12,
1008
- "tablet": 6,
1009
- "desktop": 4
1010
- }
1011
- }
1012
- ```
1013
-
1014
- ---
1015
-
1016
- ## Version History
1017
-
1018
- The form supports versioning:
1019
-
1020
- ```typescript
1021
- interface FormVersion {
1022
- id: string;
1023
- version: number;
1024
- createdAt: string; // ISO date
1025
- createdBy?: string; // User identifier
1026
- changelog?: string; // Description of changes
1027
- snapshot: FormSchema; // Complete form state
482
+ return (
483
+ <FormBuilder
484
+ initialSchema={initialSchema}
485
+ onSave={handleSave}
486
+ />
487
+ );
1028
488
  }
1029
489
  ```
1030
490
 
1031
- ---
491
+ ## Keyboard Shortcuts
1032
492
 
1033
- ## Localization
493
+ - **Ctrl/Cmd + Z**: Undo
494
+ - **Ctrl/Cmd + Shift + Z**: Redo
1034
495
 
1035
- Multi-language support per field:
496
+ ## Browser Support
1036
497
 
1037
- ```typescript
1038
- interface Localization {
1039
- translations?: Record<string, {
1040
- label?: string;
1041
- placeholder?: string;
1042
- helpText?: string;
1043
- errorMessages?: Record<string, string>;
1044
- }>;
1045
- }
1046
- ```
498
+ - Chrome (latest)
499
+ - Firefox (latest)
500
+ - Safari (latest)
501
+ - Edge (latest)
1047
502
 
1048
- **Example:**
1049
- ```json
1050
- {
1051
- "localization": {
1052
- "translations": {
1053
- "tr": {
1054
- "label": "Ad",
1055
- "placeholder": "Adınızı girin"
1056
- },
1057
- "de": {
1058
- "label": "Vorname",
1059
- "placeholder": "Geben Sie Ihren Vornamen ein"
1060
- }
1061
- }
1062
- }
1063
- }
1064
- ```
1065
-
1066
- ---
503
+ ## Changelog
1067
504
 
1068
- ## Supported Languages
1069
-
1070
- ```typescript
1071
- const SUPPORTED_LANGUAGES = [
1072
- { code: 'en', name: 'English' },
1073
- { code: 'tr', name: 'Turkish' },
1074
- { code: 'de', name: 'German' },
1075
- { code: 'fr', name: 'French' },
1076
- { code: 'es', name: 'Spanish' },
1077
- { code: 'pt', name: 'Portuguese' },
1078
- { code: 'it', name: 'Italian' },
1079
- { code: 'nl', name: 'Dutch' },
1080
- { code: 'ru', name: 'Russian' },
1081
- { code: 'zh', name: 'Chinese' },
1082
- { code: 'ja', name: 'Japanese' },
1083
- { code: 'ko', name: 'Korean' },
1084
- { code: 'ar', name: 'Arabic' },
1085
- ];
1086
- ```
505
+ ### 1.0.22
506
+ - Fixed: tabIndex now properly applied to all interactive field types (dropdown, checkbox, radio, toggle, slider, autocomplete, daterange)
1087
507
 
1088
- ---
508
+ ### 1.0.21
509
+ - Added: Comprehensive undo/redo functionality with 50-state history
510
+ - Each form modification creates a separate history entry
1089
511
 
1090
512
  ## License
1091
513