@algodomain/smart-forms 0.1.8 → 0.1.9

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
@@ -19,8 +19,11 @@ Built with TypeScript, Tailwind CSS, Zod validation, and shadcn/ui components.
19
19
  - [Opinionated Fields](#-opinionated-fields)
20
20
  - [Configuration Reference](#-configuration-reference)
21
21
  - [Advanced Features](#-advanced-features)
22
+ - [UI Components](#-ui-components)
23
+ - [Button Components](#-button-components)
22
24
  - [Theming](#-theming--customization)
23
25
  - [Hooks & Context](#-hooks--context)
26
+ - [Context Providers](#-context-providers)
24
27
  - [Examples](#-examples)
25
28
  - [Troubleshooting](#-troubleshooting)
26
29
  - [Contributing](#-contributing)
@@ -199,16 +202,34 @@ Multi-step form with tabs and progress tracking.
199
202
  api="/api/submit"
200
203
  showProgressBar={true}
201
204
  showTabNumbers={true}
205
+ animateTabs={false}
206
+ tabType="default"
202
207
  >
203
- <Tab title="Step 1">
208
+ <Tab title="Step 1" onNext={async () => { /* custom logic */ }}>
204
209
  {/* Fields */}
205
210
  </Tab>
206
- <Tab title="Step 2">
211
+ <Tab title="Step 2" processingOverlay={<LoadingSpinner />}>
207
212
  {/* Fields */}
208
213
  </Tab>
209
214
  </MultiTabSmartForm>
210
215
  ```
211
216
 
217
+ **Additional Props:**
218
+
219
+ | Prop | Type | Default | Description |
220
+ |------|------|---------|-------------|
221
+ | `animateTabs` | `boolean` | `false` | Enable tab transition animations |
222
+ | `tabType` | `'underline' \| 'default'` | `'default'` | Tab styling variant |
223
+
224
+ **Tab Component Props:**
225
+
226
+ | Prop | Type | Description |
227
+ |------|------|-------------|
228
+ | `title` | `string` | **Required.** Tab title |
229
+ | `children` | `ReactNode` | Tab content |
230
+ | `onNext` | `() => Promise<void> \| void` | Callback executed before moving to next tab. Can be async. If it throws, navigation is prevented. |
231
+ | `processingOverlay` | `ReactNode` | Overlay shown while `onNext` is processing |
232
+
212
233
  ### BaseSmartForm
213
234
 
214
235
  Low-level form component for custom layouts.
@@ -224,6 +245,63 @@ Low-level form component for custom layouts.
224
245
  </BaseSmartForm>
225
246
  ```
226
247
 
248
+ ### FormFieldGroup
249
+
250
+ A layout component for grouping form fields horizontally with responsive spacing. Fields automatically wrap to multiple rows on smaller screens.
251
+
252
+ **Usage:**
253
+
254
+ ```tsx
255
+ import { FormFieldGroup } from '@algodomain/smart-forms'
256
+ import { SmartInput, SmartSelect } from '@algodomain/smart-forms/fields'
257
+
258
+ <SmartForm api="/api/submit">
259
+ <FormFieldGroup>
260
+ <SmartInput field="firstName" label="First Name" />
261
+ <SmartInput field="lastName" label="Last Name" />
262
+ </FormFieldGroup>
263
+
264
+ <FormFieldGroup>
265
+ <SmartInput field="city" label="City" />
266
+ <SmartSelect field="state" label="State" options={stateOptions} />
267
+ <SmartInput field="zipCode" label="Zip Code" />
268
+ </FormFieldGroup>
269
+ </SmartForm>
270
+ ```
271
+
272
+ **Props:**
273
+
274
+ | Prop | Type | Default | Description |
275
+ |------|------|---------|-------------|
276
+ | `children` | `ReactNode` | - | **Required.** Form field components to group |
277
+ | `className` | `string` | `''` | Additional CSS classes to apply |
278
+
279
+ **Features:**
280
+ - Responsive flex layout with automatic wrapping
281
+ - Spacing: `gap-2` on mobile, `gap-4` on medium screens and above
282
+ - Bottom margin: `mb-4` for consistent spacing between groups
283
+
284
+ **Example: Address Form with Grouped Fields**
285
+
286
+ ```tsx
287
+ <SmartForm api="/api/submit">
288
+ <FormFieldGroup>
289
+ <SmartInput field="streetAddress" label="Street Address" required />
290
+ </FormFieldGroup>
291
+
292
+ <FormFieldGroup>
293
+ <SmartInput field="city" label="City" required />
294
+ <SmartSelect field="state" label="State" options={states} required />
295
+ <SmartInput field="zipCode" label="Zip Code" required />
296
+ </FormFieldGroup>
297
+
298
+ <FormFieldGroup className="gap-6">
299
+ <SmartInput field="country" label="Country" required />
300
+ <SmartSelect field="phoneCode" label="Phone Code" options={phoneCodes} />
301
+ </FormFieldGroup>
302
+ </SmartForm>
303
+ ```
304
+
227
305
  ---
228
306
 
229
307
  ## 🎯 Field Components
@@ -477,6 +555,8 @@ All form components (`SmartForm`, `MultiTabSmartForm`, `BaseSmartForm`) support
477
555
  | `showReset` | `boolean` | `false` | Show reset button |
478
556
  | `showProgressBar` | `boolean` | `true` | Display progress bar (MultiTab only) |
479
557
  | `showTabNumbers` | `boolean` | `true` | Show tab numbers (MultiTab only) |
558
+ | `animateTabs` | `boolean` | `false` | Enable tab animations (MultiTab only) |
559
+ | `tabType` | `'underline' \| 'default'` | `'default'` | Tab styling variant (MultiTab only) |
480
560
  | `authentication` | `AuthenticationConfig` | - | Authentication configuration |
481
561
  | `includeQueryParams` | `boolean` | `false` | Include URL query parameters |
482
562
  | `queryParamsToInclude` | `string[]` | - | Filter specific query params |
@@ -598,6 +678,173 @@ All field components support these props:
598
678
 
599
679
  ## 🚀 Advanced Features
600
680
 
681
+ ### Tab Callbacks and Processing Overlays
682
+
683
+ In MultiTabSmartForm, you can add custom logic before moving to the next tab using the `onNext` callback. This is useful for async operations like API calls or data processing.
684
+
685
+ **Basic Usage:**
686
+
687
+ ```tsx
688
+ <MultiTabSmartForm api="/api/submit">
689
+ <Tab
690
+ title="Step 1"
691
+ onNext={async () => {
692
+ // Custom validation or API call
693
+ const response = await fetch('/api/validate-step1')
694
+ if (!response.ok) {
695
+ throw new Error('Validation failed')
696
+ }
697
+ }}
698
+ >
699
+ <SmartInput field="name" label="Name" required />
700
+ </Tab>
701
+
702
+ <Tab title="Step 2">
703
+ <SmartInput field="email" label="Email" required />
704
+ </Tab>
705
+ </MultiTabSmartForm>
706
+ ```
707
+
708
+ **With Processing Overlay:**
709
+
710
+ ```tsx
711
+ import { LoadingSpinner } from '@algodomain/smart-forms'
712
+
713
+ <MultiTabSmartForm api="/api/submit">
714
+ <Tab
715
+ title="Processing Step"
716
+ onNext={async () => {
717
+ // Long-running operation
718
+ await processData()
719
+ }}
720
+ processingOverlay={
721
+ <div className="flex flex-col items-center gap-2">
722
+ <LoadingSpinner className="h-8 w-8" />
723
+ <p>Processing your data...</p>
724
+ </div>
725
+ }
726
+ >
727
+ <SmartInput field="data" label="Data" required />
728
+ </Tab>
729
+ </MultiTabSmartForm>
730
+ ```
731
+
732
+ **Error Handling:**
733
+
734
+ If `onNext` throws an error, navigation to the next tab is prevented and the error message is displayed:
735
+
736
+ ```tsx
737
+ <Tab
738
+ title="Step 1"
739
+ onNext={async () => {
740
+ const result = await validateData()
741
+ if (!result.valid) {
742
+ throw new Error(result.message) // Navigation prevented, error shown
743
+ }
744
+ }}
745
+ >
746
+ {/* Fields */}
747
+ </Tab>
748
+ ```
749
+
750
+ ### External Forms Integration
751
+
752
+ You can integrate external forms (forms outside the MultiTabSmartForm component) with the tab system for validation and navigation.
753
+
754
+ **Method 1: Manual Registration (Recommended for known fields)**
755
+
756
+ ```tsx
757
+ import { useExternalFormFields } from '@algodomain/smart-forms'
758
+
759
+ function ExternalForm() {
760
+ // Register fields for tab index 0
761
+ useExternalFormFields(['name', 'email', 'phone'], 0)
762
+
763
+ return (
764
+ <div>
765
+ <input name="name" />
766
+ <input name="email" />
767
+ <input name="phone" />
768
+ </div>
769
+ )
770
+ }
771
+
772
+ // In your MultiTabSmartForm
773
+ <MultiTabSmartForm api="/api/submit">
774
+ <Tab title="Step 1">
775
+ <ExternalForm />
776
+ </Tab>
777
+ </MultiTabSmartForm>
778
+ ```
779
+
780
+ **Method 2: Auto-Detection (Recommended for dynamic fields)**
781
+
782
+ ```tsx
783
+ import { useExternalTab, ExternalFieldProvider } from '@algodomain/smart-forms'
784
+ import { SmartInput } from '@algodomain/smart-forms/fields'
785
+
786
+ function ExternalForm() {
787
+ const { registerField, ExternalFieldProvider } = useExternalTab()
788
+
789
+ return (
790
+ <ExternalFieldProvider registerField={registerField}>
791
+ <SmartInput field="name" label="Name" />
792
+ <SmartInput field="email" label="Email" />
793
+ </ExternalFieldProvider>
794
+ )
795
+ }
796
+ ```
797
+
798
+ **Method 3: Using TabIndexProvider**
799
+
800
+ ```tsx
801
+ import { TabIndexProvider, useExternalFormFields } from '@algodomain/smart-forms'
802
+
803
+ function ExternalForm() {
804
+ const tabIndexContext = useTabIndex()
805
+ const tabIndex = tabIndexContext?.tabIndex ?? 0
806
+
807
+ useExternalFormFields(['field1', 'field2'], tabIndex)
808
+
809
+ return <div>{/* Your form */}</div>
810
+ }
811
+
812
+ // Wrap with TabIndexProvider
813
+ <TabIndexProvider tabIndex={0}>
814
+ <ExternalForm />
815
+ </TabIndexProvider>
816
+ ```
817
+
818
+ ### Submit Hooks
819
+
820
+ Register custom hooks to execute before form submission. Useful for file uploads or other async operations.
821
+
822
+ ```tsx
823
+ import { useSmartForm } from '@algodomain/smart-forms'
824
+
825
+ function FileUploadField() {
826
+ const { registerSubmitHook, unregisterSubmitHook } = useSmartForm()
827
+ const field = 'resume'
828
+
829
+ useEffect(() => {
830
+ const key = `upload-${field}`
831
+
832
+ const uploadHook = async () => {
833
+ // Upload file before form submission
834
+ await uploadFile(file)
835
+ }
836
+
837
+ registerSubmitHook(key, uploadHook)
838
+
839
+ return () => {
840
+ unregisterSubmitHook(key)
841
+ }
842
+ }, [field, file])
843
+
844
+ return <input type="file" />
845
+ }
846
+ ```
847
+
601
848
  ### Conditional Field Disabling
602
849
 
603
850
  Disable fields or submit buttons based on form data values. Supports both static boolean values and dynamic functions.
@@ -946,6 +1193,146 @@ The library will:
946
1193
 
947
1194
  ---
948
1195
 
1196
+ ## 🧩 UI Components
1197
+
1198
+ ### FormHeader
1199
+
1200
+ Display form title, subtitle, and logo.
1201
+
1202
+ ```tsx
1203
+ import { FormHeader } from '@algodomain/smart-forms'
1204
+
1205
+ <FormHeader
1206
+ title="Registration Form"
1207
+ subTitle="Please fill in your details"
1208
+ logo={<img src="/logo.png" alt="Logo" />}
1209
+ />
1210
+ ```
1211
+
1212
+ ### Section
1213
+
1214
+ Section divider with optional text.
1215
+
1216
+ ```tsx
1217
+ import { Section } from '@algodomain/smart-forms'
1218
+
1219
+ <Section text="Personal Information" />
1220
+ ```
1221
+
1222
+ ### Footer
1223
+
1224
+ Footer component for form content.
1225
+
1226
+ ```tsx
1227
+ import { Footer } from '@algodomain/smart-forms'
1228
+
1229
+ <Footer>
1230
+ <p className="text-sm text-gray-500">
1231
+ By submitting, you agree to our terms and conditions.
1232
+ </p>
1233
+ </Footer>
1234
+ ```
1235
+
1236
+ ### ToastContainerWrapper
1237
+
1238
+ Toast notification container (automatically included in forms).
1239
+
1240
+ ```tsx
1241
+ import { ToastContainerWrapper } from '@algodomain/smart-forms'
1242
+
1243
+ <ToastContainerWrapper />
1244
+ ```
1245
+
1246
+ ## 🔘 Button Components
1247
+
1248
+ ### LoadingSpinner
1249
+
1250
+ Loading spinner component.
1251
+
1252
+ ```tsx
1253
+ import { LoadingSpinner } from '@algodomain/smart-forms'
1254
+
1255
+ <LoadingSpinner className="h-6 w-6" />
1256
+ ```
1257
+
1258
+ ### SubmitButton
1259
+
1260
+ Submit button with loading state.
1261
+
1262
+ ```tsx
1263
+ import { SubmitButton } from '@algodomain/smart-forms'
1264
+
1265
+ <SubmitButton
1266
+ onClick={handleSubmit}
1267
+ disabled={isLoading}
1268
+ isLoading={isLoading}
1269
+ >
1270
+ Submit Form
1271
+ </SubmitButton>
1272
+ ```
1273
+
1274
+ ### DraftSaveButton
1275
+
1276
+ Draft save button.
1277
+
1278
+ ```tsx
1279
+ import { DraftSaveButton } from '@algodomain/smart-forms'
1280
+
1281
+ <DraftSaveButton
1282
+ onClick={handleSaveDraft}
1283
+ disabled={isDraftSaving}
1284
+ />
1285
+ ```
1286
+
1287
+ ### ResetButton
1288
+
1289
+ Reset form button.
1290
+
1291
+ ```tsx
1292
+ import { ResetButton } from '@algodomain/smart-forms'
1293
+
1294
+ <ResetButton onClick={handleReset} />
1295
+ ```
1296
+
1297
+ ### NavigationButtons
1298
+
1299
+ Navigation buttons for multi-tab forms.
1300
+
1301
+ ```tsx
1302
+ import { NavigationButtons } from '@algodomain/smart-forms'
1303
+
1304
+ <NavigationButtons
1305
+ onPrevious={handlePrevious}
1306
+ onNext={handleNext}
1307
+ onSubmit={handleSubmit}
1308
+ onSaveDraft={handleSaveDraft}
1309
+ onReset={handleReset}
1310
+ isLoading={isLoading}
1311
+ isDraftSaving={isDraftSaving}
1312
+ config={config}
1313
+ isFirstTab={false}
1314
+ isLastTab={false}
1315
+ disabled={false}
1316
+ />
1317
+ ```
1318
+
1319
+ ### SimpleFormButtons
1320
+
1321
+ Simple button group for single-page forms.
1322
+
1323
+ ```tsx
1324
+ import { SimpleFormButtons } from '@algodomain/smart-forms'
1325
+
1326
+ <SimpleFormButtons
1327
+ onSubmit={handleSubmit}
1328
+ onSaveDraft={handleSaveDraft}
1329
+ onReset={handleReset}
1330
+ isLoading={isLoading}
1331
+ isDraftSaving={isDraftSaving}
1332
+ config={config}
1333
+ />
1334
+ ```
1335
+
949
1336
  ## 🎨 Theming & Customization
950
1337
 
951
1338
  ### CSS Variables
@@ -1025,21 +1412,36 @@ import { useSmartForm } from '@algodomain/smart-forms'
1025
1412
 
1026
1413
  function MyComponent() {
1027
1414
  const {
1028
- formData, // Current form values
1029
- errors, // Validation errors
1030
- isLoading, // Submission loading state
1031
- isDraftSaving, // Draft saving state
1032
- submitForm, // Submit function
1033
- saveDraft, // Save draft function
1034
- resetForm, // Reset to initial values
1035
- updateField, // Update specific field
1036
- config // Form configuration
1415
+ formData, // Current form values
1416
+ errors, // Validation errors
1417
+ isLoading, // Submission loading state
1418
+ isDraftSaving, // Draft saving state
1419
+ submitForm, // Submit function
1420
+ saveDraft, // Save draft function
1421
+ resetForm, // Reset to initial values
1422
+ updateField, // Update specific field
1423
+ validateField, // Validate a single field
1424
+ validateFields, // Validate multiple fields
1425
+ validateFormAndGetResult, // Validate entire form and return boolean
1426
+ registerSubmitHook, // Register a hook to run before submission
1427
+ unregisterSubmitHook, // Unregister a submit hook
1428
+ setErrors, // Manually set validation errors
1429
+ config // Form configuration
1037
1430
  } = useSmartForm()
1038
1431
 
1039
1432
  return <button onClick={submitForm}>Submit</button>
1040
1433
  }
1041
1434
  ```
1042
1435
 
1436
+ **Methods:**
1437
+
1438
+ - `validateField(field: string, value: any): boolean` - Validate a single field
1439
+ - `validateFields(fields: string[]): boolean` - Validate multiple fields
1440
+ - `validateFormAndGetResult(): boolean` - Validate entire form and return result
1441
+ - `registerSubmitHook(key: string, hook: () => Promise<void>): void` - Register a hook to execute before form submission
1442
+ - `unregisterSubmitHook(key: string): void` - Unregister a submit hook
1443
+ - `setErrors(errors: Record<string, string>): void` - Manually set validation errors
1444
+
1043
1445
  ### useFormField
1044
1446
 
1045
1447
  Access individual field state (used internally by field components).
@@ -1059,6 +1461,170 @@ function CustomField({ field }) {
1059
1461
  }
1060
1462
  ```
1061
1463
 
1464
+ ### useFormWrapper
1465
+
1466
+ Alias for `useSmartForm` (for convenience).
1467
+
1468
+ ```tsx
1469
+ import { useFormWrapper } from '@algodomain/smart-forms'
1470
+
1471
+ function MyComponent() {
1472
+ const { formData, submitForm } = useFormWrapper()
1473
+ // Same as useSmartForm
1474
+ }
1475
+ ```
1476
+
1477
+ ### useTabIndex
1478
+
1479
+ Get the current tab index in a MultiTabSmartForm.
1480
+
1481
+ ```tsx
1482
+ import { useTabIndex } from '@algodomain/smart-forms'
1483
+
1484
+ function MyComponent() {
1485
+ const tabIndexContext = useTabIndex()
1486
+ const tabIndex = tabIndexContext?.tabIndex ?? 0
1487
+
1488
+ return <div>Current tab: {tabIndex + 1}</div>
1489
+ }
1490
+ ```
1491
+
1492
+ ### useExternalFormRegistration
1493
+
1494
+ Register external forms with MultiTabSmartForm for validation and tab navigation.
1495
+
1496
+ ```tsx
1497
+ import { useExternalFormRegistration } from '@algodomain/smart-forms'
1498
+
1499
+ function ExternalForm() {
1500
+ const { registerTabFields, currentTabIndex } = useExternalFormRegistration()
1501
+
1502
+ useEffect(() => {
1503
+ registerTabFields(currentTabIndex, ['field1', 'field2'])
1504
+ }, [])
1505
+
1506
+ return <div>{/* Your form fields */}</div>
1507
+ }
1508
+ ```
1509
+
1510
+ ### useExternalFormFields
1511
+
1512
+ Register fields from external forms with a specific tab index.
1513
+
1514
+ ```tsx
1515
+ import { useExternalFormFields } from '@algodomain/smart-forms'
1516
+
1517
+ function ExternalForm() {
1518
+ useExternalFormFields(['field1', 'field2'], 0) // Register fields for tab 0
1519
+
1520
+ return <div>{/* Your form fields */}</div>
1521
+ }
1522
+ ```
1523
+
1524
+ ### useAutoDetectFields
1525
+
1526
+ Automatically detect and register fields in external forms.
1527
+
1528
+ ```tsx
1529
+ import { useAutoDetectFields, ExternalFieldProvider } from '@algodomain/smart-forms'
1530
+
1531
+ function ExternalForm() {
1532
+ const { registerField, ExternalFieldProvider } = useAutoDetectFields(0)
1533
+
1534
+ return (
1535
+ <ExternalFieldProvider registerField={registerField}>
1536
+ <SmartInput field="name" label="Name" />
1537
+ <SmartInput field="email" label="Email" />
1538
+ </ExternalFieldProvider>
1539
+ )
1540
+ }
1541
+ ```
1542
+
1543
+ ### useExternalTab
1544
+
1545
+ Automatically detect both tab index and fields in external forms (recommended).
1546
+
1547
+ ```tsx
1548
+ import { useExternalTab, ExternalFieldProvider } from '@algodomain/smart-forms'
1549
+
1550
+ function ExternalForm() {
1551
+ const { registerField, ExternalFieldProvider } = useExternalTab()
1552
+
1553
+ return (
1554
+ <ExternalFieldProvider registerField={registerField}>
1555
+ <SmartInput field="name" label="Name" />
1556
+ <SmartInput field="email" label="Email" />
1557
+ </ExternalFieldProvider>
1558
+ )
1559
+ }
1560
+ ```
1561
+
1562
+ ### useFieldDetection
1563
+
1564
+ Access field detection context (used internally by field components).
1565
+
1566
+ ```tsx
1567
+ import { useFieldDetection } from '@algodomain/smart-forms'
1568
+
1569
+ function CustomField({ field }) {
1570
+ const context = useFieldDetection()
1571
+
1572
+ useEffect(() => {
1573
+ if (context) {
1574
+ context.registerField(field)
1575
+ }
1576
+ }, [field, context])
1577
+
1578
+ return <input />
1579
+ }
1580
+ ```
1581
+
1582
+ ## 🔌 Context Providers
1583
+
1584
+ ### TabIndexProvider
1585
+
1586
+ Provide tab index context to child components.
1587
+
1588
+ ```tsx
1589
+ import { TabIndexProvider, useTabIndex } from '@algodomain/smart-forms'
1590
+
1591
+ function MyComponent() {
1592
+ return (
1593
+ <TabIndexProvider tabIndex={0}>
1594
+ <ChildComponent />
1595
+ </TabIndexProvider>
1596
+ )
1597
+ }
1598
+
1599
+ function ChildComponent() {
1600
+ const context = useTabIndex()
1601
+ const tabIndex = context?.tabIndex ?? 0
1602
+ return <div>Tab: {tabIndex}</div>
1603
+ }
1604
+ ```
1605
+
1606
+ ### ExternalFieldProvider
1607
+
1608
+ Provider for automatic field detection in external forms.
1609
+
1610
+ ```tsx
1611
+ import { ExternalFieldProvider } from '@algodomain/smart-forms'
1612
+
1613
+ function ExternalForm() {
1614
+ const registerField = (fieldName: string) => {
1615
+ // Register field with parent form
1616
+ console.log('Registering field:', fieldName)
1617
+ }
1618
+
1619
+ return (
1620
+ <ExternalFieldProvider registerField={registerField}>
1621
+ <SmartInput field="name" label="Name" />
1622
+ <SmartInput field="email" label="Email" />
1623
+ </ExternalFieldProvider>
1624
+ )
1625
+ }
1626
+ ```
1627
+
1062
1628
  ---
1063
1629
 
1064
1630
  ## 💡 Examples
@@ -1066,7 +1632,7 @@ function CustomField({ field }) {
1066
1632
  ### Complete Registration Form
1067
1633
 
1068
1634
  ```tsx
1069
- import { SmartForm } from '@algodomain/smart-forms'
1635
+ import { SmartForm, FormHeader, Section, Footer } from '@algodomain/smart-forms'
1070
1636
  import { SmartInput, SmartSelect, SmartCheckbox, SmartDatePicker } from '@algodomain/smart-forms/fields'
1071
1637
  import { FieldEmail, FieldPassword } from '@algodomain/smart-forms/opinionated'
1072
1638
  import { z } from 'zod'
@@ -1086,6 +1652,13 @@ export function RegistrationForm() {
1086
1652
  toast.error('Registration failed.')
1087
1653
  }}
1088
1654
  >
1655
+ <FormHeader
1656
+ title="Create Your Account"
1657
+ subTitle="Join us today and get started"
1658
+ />
1659
+
1660
+ <Section text="Personal Information" />
1661
+
1089
1662
  <SmartInput
1090
1663
  field="fullName"
1091
1664
  label="Full Name"
@@ -1096,6 +1669,8 @@ export function RegistrationForm() {
1096
1669
  <FieldEmail field="email" required />
1097
1670
  <FieldPassword field="password" required />
1098
1671
 
1672
+ <Section text="Location" />
1673
+
1099
1674
  <SmartSelect
1100
1675
  field="country"
1101
1676
  label="Country"
@@ -1121,12 +1696,20 @@ export function RegistrationForm() {
1121
1696
  required
1122
1697
  />
1123
1698
 
1699
+ <Section text="Agreements" />
1700
+
1124
1701
  <SmartCheckbox
1125
1702
  field="terms"
1126
1703
  label="I agree to the Terms and Conditions"
1127
1704
  validation={z.boolean().refine(val => val === true)}
1128
1705
  required
1129
1706
  />
1707
+
1708
+ <Footer>
1709
+ <p className="text-sm text-gray-500 text-center">
1710
+ By submitting, you agree to our terms and conditions.
1711
+ </p>
1712
+ </Footer>
1130
1713
  </SmartForm>
1131
1714
  )
1132
1715
  }
@@ -1135,7 +1718,7 @@ export function RegistrationForm() {
1135
1718
  ### Multi-Tab Job Application
1136
1719
 
1137
1720
  ```tsx
1138
- import { MultiTabSmartForm, Tab } from '@algodomain/smart-forms'
1721
+ import { MultiTabSmartForm, Tab, LoadingSpinner } from '@algodomain/smart-forms'
1139
1722
  import { SmartInput, SmartTags, SmartDualRangeSlider } from '@algodomain/smart-forms/fields'
1140
1723
  import { FieldEmail, FieldPhone } from '@algodomain/smart-forms/opinionated'
1141
1724
  import { z } from 'zod'
@@ -1147,11 +1730,22 @@ export function JobApplicationForm() {
1147
1730
  method="POST"
1148
1731
  showProgressBar={true}
1149
1732
  showTabNumbers={true}
1733
+ animateTabs={true}
1734
+ tabType="underline"
1150
1735
  allowSaveDraft={true}
1151
1736
  enableLocalStorage={true}
1152
1737
  storageKey="job-application"
1153
1738
  >
1154
- <Tab title="Personal Info">
1739
+ <Tab
1740
+ title="Personal Info"
1741
+ onNext={async () => {
1742
+ // Validate with external API before proceeding
1743
+ const response = await fetch('/api/validate-personal-info')
1744
+ if (!response.ok) {
1745
+ throw new Error('Personal information validation failed')
1746
+ }
1747
+ }}
1748
+ >
1155
1749
  <SmartInput
1156
1750
  field="fullName"
1157
1751
  label="Full Name"
@@ -1162,7 +1756,15 @@ export function JobApplicationForm() {
1162
1756
  <FieldPhone field="phone" required />
1163
1757
  </Tab>
1164
1758
 
1165
- <Tab title="Experience">
1759
+ <Tab
1760
+ title="Experience"
1761
+ processingOverlay={
1762
+ <div className="flex flex-col items-center gap-2">
1763
+ <LoadingSpinner className="h-8 w-8" />
1764
+ <p>Processing experience data...</p>
1765
+ </div>
1766
+ }
1767
+ >
1166
1768
  <SmartDualRangeSlider
1167
1769
  minField="minExperience"
1168
1770
  maxField="maxExperience"
@@ -1183,6 +1785,41 @@ export function JobApplicationForm() {
1183
1785
  }
1184
1786
  ```
1185
1787
 
1788
+ ### Form with External Components
1789
+
1790
+ ```tsx
1791
+ import { MultiTabSmartForm, Tab, useExternalTab, ExternalFieldProvider } from '@algodomain/smart-forms'
1792
+ import { SmartInput } from '@algodomain/smart-forms/fields'
1793
+
1794
+ // External form component
1795
+ function ExternalAddressForm() {
1796
+ const { registerField, ExternalFieldProvider } = useExternalTab()
1797
+
1798
+ return (
1799
+ <ExternalFieldProvider registerField={registerField}>
1800
+ <SmartInput field="street" label="Street" required />
1801
+ <SmartInput field="city" label="City" required />
1802
+ <SmartInput field="zipCode" label="Zip Code" required />
1803
+ </ExternalFieldProvider>
1804
+ )
1805
+ }
1806
+
1807
+ // Main form
1808
+ export function FormWithExternalComponents() {
1809
+ return (
1810
+ <MultiTabSmartForm api="/api/submit">
1811
+ <Tab title="Basic Info">
1812
+ <SmartInput field="name" label="Name" required />
1813
+ </Tab>
1814
+
1815
+ <Tab title="Address">
1816
+ <ExternalAddressForm />
1817
+ </Tab>
1818
+ </MultiTabSmartForm>
1819
+ )
1820
+ }
1821
+ ```
1822
+
1186
1823
  ### Form with Query Parameters
1187
1824
 
1188
1825
  ```tsx