@adobe-commerce/aio-experience-kit 1.0.2 → 1.0.4

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/README.md +590 -2
  3. package/dist/cjs/components/DataForm/ButtonContainer/index.js +158 -0
  4. package/dist/cjs/components/DataForm/ButtonContainer/index.js.map +1 -0
  5. package/dist/cjs/components/DataForm/FieldBuilder/index.js +3 -2
  6. package/dist/cjs/components/DataForm/FieldBuilder/index.js.map +1 -1
  7. package/dist/cjs/components/DataForm/FormBuilder/index.js +178 -65
  8. package/dist/cjs/components/DataForm/FormBuilder/index.js.map +1 -1
  9. package/dist/cjs/components/DataForm/FormBuilder/types.js.map +1 -1
  10. package/dist/cjs/components/DataForm/index.js +6 -3
  11. package/dist/cjs/components/DataForm/index.js.map +1 -1
  12. package/dist/cjs/components/DataTable/GridBuilder/index.js +72 -58
  13. package/dist/cjs/components/DataTable/GridBuilder/index.js.map +1 -1
  14. package/dist/cjs/components/DataTable/SearchBar/index.js +184 -0
  15. package/dist/cjs/components/DataTable/SearchBar/index.js.map +1 -0
  16. package/dist/cjs/components/DataTable/index.js +53 -33
  17. package/dist/cjs/components/DataTable/index.js.map +1 -1
  18. package/dist/cjs/components/DataTable/types.js.map +1 -1
  19. package/dist/cjs/components/FileUpload/index.js +12 -2
  20. package/dist/cjs/components/FileUpload/index.js.map +1 -1
  21. package/dist/esm/components/DataForm/ButtonContainer/index.js +154 -0
  22. package/dist/esm/components/DataForm/ButtonContainer/index.js.map +1 -0
  23. package/dist/esm/components/DataForm/FieldBuilder/index.js +3 -2
  24. package/dist/esm/components/DataForm/FieldBuilder/index.js.map +1 -1
  25. package/dist/esm/components/DataForm/FormBuilder/index.js +180 -67
  26. package/dist/esm/components/DataForm/FormBuilder/index.js.map +1 -1
  27. package/dist/esm/components/DataForm/FormBuilder/types.js.map +1 -1
  28. package/dist/esm/components/DataForm/index.js +7 -4
  29. package/dist/esm/components/DataForm/index.js.map +1 -1
  30. package/dist/esm/components/DataTable/GridBuilder/index.js +74 -60
  31. package/dist/esm/components/DataTable/GridBuilder/index.js.map +1 -1
  32. package/dist/esm/components/DataTable/SearchBar/index.js +180 -0
  33. package/dist/esm/components/DataTable/SearchBar/index.js.map +1 -0
  34. package/dist/esm/components/DataTable/index.js +53 -33
  35. package/dist/esm/components/DataTable/index.js.map +1 -1
  36. package/dist/esm/components/DataTable/types.js.map +1 -1
  37. package/dist/esm/components/FileUpload/index.js +13 -3
  38. package/dist/esm/components/FileUpload/index.js.map +1 -1
  39. package/dist/esm/types/components/DataForm/ButtonContainer/index.d.ts +12 -0
  40. package/dist/esm/types/components/DataForm/ButtonContainer/index.d.ts.map +1 -0
  41. package/dist/esm/types/components/DataForm/ButtonContainer/types.d.ts +82 -0
  42. package/dist/esm/types/components/DataForm/ButtonContainer/types.d.ts.map +1 -0
  43. package/dist/esm/types/components/DataForm/FieldBuilder/index.d.ts.map +1 -1
  44. package/dist/esm/types/components/DataForm/FormBuilder/index.d.ts.map +1 -1
  45. package/dist/esm/types/components/DataForm/FormBuilder/types.d.ts +40 -0
  46. package/dist/esm/types/components/DataForm/FormBuilder/types.d.ts.map +1 -1
  47. package/dist/esm/types/components/DataForm/index.d.ts.map +1 -1
  48. package/dist/esm/types/components/DataForm/types.d.ts +2 -0
  49. package/dist/esm/types/components/DataForm/types.d.ts.map +1 -1
  50. package/dist/esm/types/components/DataTable/GridBuilder/index.d.ts +1 -1
  51. package/dist/esm/types/components/DataTable/GridBuilder/index.d.ts.map +1 -1
  52. package/dist/esm/types/components/DataTable/GridBuilder/types.d.ts +1 -0
  53. package/dist/esm/types/components/DataTable/GridBuilder/types.d.ts.map +1 -1
  54. package/dist/esm/types/components/DataTable/SearchBar/index.d.ts +11 -0
  55. package/dist/esm/types/components/DataTable/SearchBar/index.d.ts.map +1 -0
  56. package/dist/esm/types/components/DataTable/index.d.ts +1 -1
  57. package/dist/esm/types/components/DataTable/index.d.ts.map +1 -1
  58. package/dist/esm/types/components/DataTable/types.d.ts +38 -0
  59. package/dist/esm/types/components/DataTable/types.d.ts.map +1 -1
  60. package/dist/esm/types/components/FileUpload/index.d.ts +2 -3
  61. package/dist/esm/types/components/FileUpload/index.d.ts.map +1 -1
  62. package/dist/esm/types/components/FileUpload/types.d.ts +14 -0
  63. package/dist/esm/types/components/FileUpload/types.d.ts.map +1 -1
  64. package/dist/esm/types/components/index.d.ts +2 -1
  65. package/dist/esm/types/components/index.d.ts.map +1 -1
  66. package/package.json +6 -6
package/README.md CHANGED
@@ -181,13 +181,167 @@ class EntityModel {
181
181
  }
182
182
  ```
183
183
 
184
+ **Vertical Scrolling for Large Datasets (v1.0.3+):**
185
+
186
+ Control table height with automatic scrolling:
187
+
188
+ ```javascript
189
+ <DataTable
190
+ columns={columns}
191
+ data={largeDataset}
192
+ maxHeight="size-6000" // Spectrum token (480px)
193
+ // or maxHeight="500px" // CSS value
194
+ // or maxHeight="60vh" // Viewport height
195
+ onGridLoad={async () => {
196
+ // Load large dataset
197
+ }}
198
+ />
199
+ ```
200
+
201
+ **Search and Filtering Capabilities:**
202
+
203
+ Add built-in search functionality to enable users to quickly find and filter records within your DataTable. The search bar is configurable and supports both button-triggered and search-as-you-type modes.
204
+
205
+ *Example 1: Basic Search (Button Click Mode)*
206
+
207
+ ```javascript
208
+ <DataTable
209
+ columns={columns}
210
+ data={data}
211
+ searchConfig={{
212
+ enabled: true,
213
+ placeholder: "Search products...",
214
+ searchOnType: false, // Only search when button clicked or Enter pressed
215
+ }}
216
+ onSearch={async (searchText) => {
217
+ // Triggered only on button click or Enter key
218
+ await fetchFilteredData(searchText);
219
+ }}
220
+ />
221
+ ```
222
+
223
+ *Example 2: Search-as-you-type with Debounce (Recommended for Client-Side Filtering)*
224
+
225
+ ```javascript
226
+ const [allData, setAllData] = useState(products);
227
+ const [filteredData, setFilteredData] = useState(products);
228
+
229
+ <DataTable
230
+ columns={columns}
231
+ data={filteredData} // Show filtered results
232
+ searchConfig={{
233
+ enabled: true,
234
+ searchOnType: true, // Search while typing
235
+ debounceMs: 300, // Wait 300ms after user stops typing
236
+ showClearButton: true,
237
+ minCharacters: 2, // Only search if 2+ characters entered
238
+ }}
239
+ onSearch={async (searchText) => {
240
+ if (!searchText) {
241
+ setFilteredData(allData); // Show all if search is empty
242
+ return;
243
+ }
244
+
245
+ // Client-side filtering
246
+ const filtered = allData.filter(item =>
247
+ Object.values(item).some(val =>
248
+ String(val).toLowerCase().includes(searchText.toLowerCase())
249
+ )
250
+ );
251
+ setFilteredData(filtered);
252
+ }}
253
+ />
254
+ ```
255
+
256
+ *Example 3: Server-Side Search with Loading State*
257
+
258
+ ```javascript
259
+ const [isSearching, setSearching] = useState(false);
260
+
261
+ <DataTable
262
+ columns={columns}
263
+ data={data}
264
+ searchConfig={{
265
+ enabled: true,
266
+ isSearching: isSearching, // Shows spinner in search button
267
+ placeholder: "Search across 10,000+ records...",
268
+ searchOnType: true,
269
+ debounceMs: 800, // Longer debounce for server calls
270
+ }}
271
+ onSearch={async (searchText) => {
272
+ setSearching(true);
273
+ try {
274
+ const results = await apiSearchCall(searchText);
275
+ setData(results);
276
+ } finally {
277
+ setSearching(false);
278
+ }
279
+ }}
280
+ />
281
+ ```
282
+
283
+ *Example 4: Column-Specific Search*
284
+
285
+ ```javascript
286
+ <DataTable
287
+ columns={columns}
288
+ data={data}
289
+ searchConfig={{
290
+ enabled: true,
291
+ searchableColumns: ['name', 'sku', 'email'], // Only search these columns
292
+ caseSensitive: false,
293
+ }}
294
+ onSearch={async (searchText, searchColumns) => {
295
+ // searchColumns will be ['name', 'sku', 'email']
296
+ await searchInColumns(searchText, searchColumns);
297
+ }}
298
+ />
299
+ ```
300
+
301
+ **Search Configuration Options:**
302
+
303
+ | Property | Type | Default | Description |
304
+ |----------|------|---------|-------------|
305
+ | `enabled` | boolean | `false` | Enable/disable search bar |
306
+ | `placeholder` | string | `"Search..."` | Placeholder text for search input |
307
+ | `searchButtonLabel` | string | `"Search"` | Label text displayed on search button (shown with icon) |
308
+ | `clearButtonLabel` | string | `"Clear search"` | Accessible label for clear button |
309
+ | `showClearButton` | boolean | `true` | Show clear button when text exists |
310
+ | `searchOnType` | boolean | `false` | Search while typing vs. button click only |
311
+ | `debounceMs` | number | `300` | Debounce time for search-as-you-type (ms) |
312
+ | `caseSensitive` | boolean | `false` | Case-sensitive search |
313
+ | `searchableColumns` | string[] | `[]` | Specific columns to search (empty = all columns) |
314
+ | `minCharacters` | number | `1` | Minimum characters before search triggers |
315
+ | `maxLength` | number | `100` | Maximum length of search input |
316
+ | `showResultsCount` | boolean | `false` | Show count of filtered results |
317
+ | `isSearching` | boolean | `false` | Show loading state in search button |
318
+ | `ariaLabel` | string | `"Search table"` | ARIA label for search input |
319
+
320
+ **Search Behavior Modes:**
321
+
322
+ - **Button Mode** (`searchOnType: false`): Search only triggers when the search button is clicked or Enter key is pressed. Ideal for server-side searches with expensive operations.
323
+
324
+ - **Type Mode** (`searchOnType: true`): Search triggers as the user types (with debouncing). Perfect for client-side filtering or real-time search experiences.
325
+
326
+ **Keyboard Shortcuts:**
327
+ - **Enter**: Triggers search in both modes (bypasses debounce in type mode)
328
+ - **Escape**: Clears search when `showClearButton` is enabled
329
+
330
+ **Accessibility Features:**
331
+ - Full keyboard navigation support
332
+ - Customizable ARIA labels for screen readers
333
+ - Loading state announcements
334
+ - High contrast mode support
335
+
184
336
  **Features:**
185
337
  - **Advanced Data Management**: Sortable columns with intelligent data type handling and custom sort functions
186
338
  - **Flexible Selection**: Support for single-row selection or multi-row selection with visual feedback
187
339
  - **Bulk Operations**: Mass action system for performing operations on multiple selected items
188
340
  - **Contextual Actions**: Per-row actions with customizable button layouts, links, or dropdown menus
189
341
  - **State Management**: Built-in loading states, empty state handling, and error boundary support
190
- - **Performance Optimized**: Virtual scrolling for large datasets and efficient re-rendering
342
+ - **Performance Optimized**: Virtual scrolling for large datasets with efficient re-rendering
343
+ - **Scrollable Tables**: Optional maxHeight prop for vertical scrolling with large datasets (v1.0.3+)
344
+ - **Search & Filter**: Built-in search bar with button and type modes, column-specific filtering
191
345
  - **User Experience**: Intuitive interactions with hover states, keyboard navigation, and clear visual hierarchy
192
346
 
193
347
  #### `DataForm`
@@ -398,9 +552,202 @@ The DataForm component supports various field types for different input scenario
398
552
  }
399
553
  ```
400
554
 
555
+ ##### Dependent Field Visibility
556
+
557
+ The DataForm component supports conditional field visibility based on the values of other fields. This allows you to create dynamic forms that show or hide fields based on user selections.
558
+
559
+ **Basic Example:**
560
+
561
+ ```javascript
562
+ {
563
+ groups: [
564
+ {
565
+ code: 'settings',
566
+ label: 'Settings',
567
+ fields: [
568
+ {
569
+ label: 'Enable Feature',
570
+ code: 'feature_enabled',
571
+ db_field: 'feature_enabled',
572
+ type: FieldType.TOGGLE,
573
+ required: false
574
+ },
575
+ {
576
+ label: 'Feature Configuration',
577
+ code: 'feature_config',
578
+ db_field: 'feature_config',
579
+ type: FieldType.TEXT,
580
+ required: false,
581
+ // This field only shows when feature_enabled is truthy
582
+ dependsOn: {
583
+ field: 'feature_enabled',
584
+ condition: { type: 'truthy' }
585
+ }
586
+ }
587
+ ]
588
+ }
589
+ ]
590
+ }
591
+ ```
592
+
593
+ **Dependency Condition Types:**
594
+
595
+ ```javascript
596
+ // Equals - Show field when value matches exactly
597
+ dependsOn: {
598
+ field: 'status',
599
+ condition: { type: 'equals', value: 'active' }
600
+ }
601
+
602
+ // Not Equals - Show field when value doesn't match
603
+ dependsOn: {
604
+ field: 'status',
605
+ condition: { type: 'notEquals', value: 'disabled' }
606
+ }
607
+
608
+ // In - Show field when value is in array
609
+ dependsOn: {
610
+ field: 'status',
611
+ condition: { type: 'in', values: ['pending', 'processing'] }
612
+ }
613
+
614
+ // Not In - Show field when value is not in array
615
+ dependsOn: {
616
+ field: 'status',
617
+ condition: { type: 'notIn', values: ['cancelled', 'completed'] }
618
+ }
619
+
620
+ // Greater Than - Show field when numeric value is greater
621
+ dependsOn: {
622
+ field: 'quantity',
623
+ condition: { type: 'greaterThan', value: 10 }
624
+ }
625
+
626
+ // Less Than - Show field when numeric value is less
627
+ dependsOn: {
628
+ field: 'stock_level',
629
+ condition: { type: 'lessThan', value: 5 }
630
+ }
631
+
632
+ // Truthy - Show field when value is truthy (handles '0' and 'false' as falsy)
633
+ dependsOn: {
634
+ field: 'enable_feature',
635
+ condition: { type: 'truthy' }
636
+ }
637
+
638
+ // Falsy - Show field when value is falsy
639
+ dependsOn: {
640
+ field: 'enable_feature',
641
+ condition: { type: 'falsy' }
642
+ }
643
+
644
+ // Custom - Show field based on custom validation function
645
+ dependsOn: {
646
+ field: 'username',
647
+ condition: {
648
+ type: 'custom',
649
+ validator: (value, allFormValues) => {
650
+ return value && value.length > 3;
651
+ }
652
+ }
653
+ }
654
+ ```
655
+
656
+ **Advanced Example - Multi-Step Configuration:**
657
+
658
+ ```javascript
659
+ {
660
+ groups: [
661
+ {
662
+ code: 'shipping',
663
+ label: 'Shipping Configuration',
664
+ fields: [
665
+ {
666
+ label: 'Shipping Method',
667
+ code: 'shipping_method',
668
+ db_field: 'shipping_method',
669
+ type: FieldType.SELECT,
670
+ required: true,
671
+ options: [
672
+ { value: 'standard', label: 'Standard Shipping' },
673
+ { value: 'express', label: 'Express Shipping' },
674
+ { value: 'pickup', label: 'Store Pickup' }
675
+ ]
676
+ },
677
+ {
678
+ label: 'Carrier',
679
+ code: 'carrier',
680
+ db_field: 'carrier',
681
+ type: FieldType.SELECT,
682
+ required: true,
683
+ options: [
684
+ { value: 'ups', label: 'UPS' },
685
+ { value: 'fedex', label: 'FedEx' },
686
+ { value: 'usps', label: 'USPS' }
687
+ ],
688
+ // Only show carrier selection for standard and express shipping
689
+ dependsOn: {
690
+ field: 'shipping_method',
691
+ condition: { type: 'in', values: ['standard', 'express'] }
692
+ }
693
+ },
694
+ {
695
+ label: 'Tracking Number',
696
+ code: 'tracking_number',
697
+ db_field: 'tracking_number',
698
+ type: FieldType.TEXT,
699
+ required: false,
700
+ // Only show tracking for shipped methods
701
+ dependsOn: {
702
+ field: 'shipping_method',
703
+ condition: { type: 'notEquals', value: 'pickup' }
704
+ }
705
+ },
706
+ {
707
+ label: 'Store Location',
708
+ code: 'store_location',
709
+ db_field: 'store_location',
710
+ type: FieldType.SELECT,
711
+ required: true,
712
+ options: [
713
+ { value: 'store1', label: 'Main Street Store' },
714
+ { value: 'store2', label: 'Downtown Store' }
715
+ ],
716
+ // Only show store location for pickup
717
+ dependsOn: {
718
+ field: 'shipping_method',
719
+ condition: { type: 'equals', value: 'pickup' }
720
+ }
721
+ }
722
+ ]
723
+ }
724
+ ]
725
+ }
726
+ ```
727
+
728
+ **Dependency Configuration:**
729
+
730
+ ```typescript
731
+ interface FieldDependency {
732
+ field: string; // The code of the field this depends on
733
+ condition: DependencyCondition; // The condition to evaluate
734
+ clearValueOnHide?: boolean; // Whether to clear field value when hidden (default: false)
735
+ }
736
+ ```
737
+
738
+ **Key Features:**
739
+ - **Dynamic Visibility**: Fields automatically show/hide based on dependency conditions
740
+ - **Multiple Conditions**: Support for equals, notEquals, in, notIn, greaterThan, lessThan, truthy, falsy, and custom validators
741
+ - **Validation Integration**: Hidden fields are excluded from form validation
742
+ - **Value Management**: Optional automatic clearing of hidden field values
743
+ - **Performance Optimized**: Uses React memoization to prevent unnecessary re-renders
744
+ - **Chain Dependencies**: Fields can depend on other dependent fields
745
+ - **Form Submission**: Hidden field values are automatically excluded from submission
746
+
401
747
  **Features:**
402
748
  - **Dynamic Form Generation**: Create complex forms from simple configuration objects without manual field creation
403
749
  - **Rich Field Types**: Support for text, email, password, number, select, multiselect, toggle, and specialized input types
750
+ - **Conditional Field Visibility**: Show/hide fields dynamically based on other field values with multiple condition types
404
751
  - **Multi-Selection Support**: MULTISELECT field type with React Spectrum CheckboxGroup for selecting multiple options with scrollable overflow and accessibility support
405
752
  - **Toggle Controls**: TOGGLE field type using React Spectrum Switch component with '1'/'0' value handling and automatic default value initialization
406
753
  - **Environment Variable Support**: Built-in support for environment variable checkboxes on compatible field types (TEXT, SELECT, MULTISELECT, TOGGLE)
@@ -408,6 +755,211 @@ The DataForm component supports various field types for different input scenario
408
755
  - **Workflow Integration**: Loading states, processing indicators, and navigation controls for multi-step workflows
409
756
  - **Organized Layout**: Logical field grouping with collapsible sections and intuitive information hierarchy
410
757
  - **Developer Friendly**: Event-driven architecture with lifecycle hooks for custom business logic integration
758
+ - **Configurable Buttons**: Full control over form action buttons with custom labels, icons, visibility, positioning, and alignment
759
+
760
+ ##### Button Configuration
761
+
762
+ The DataForm component provides extensive button customization through the `buttonConfig` prop:
763
+
764
+ **Basic Usage:**
765
+
766
+ ```javascript
767
+ <DataForm
768
+ components={formFields}
769
+ editItem={editItem}
770
+ onFormLoad={onFormLoad}
771
+ onFormSubmit={onFormSubmit}
772
+ onBackPress={onBackPress}
773
+ buttonConfig={{
774
+ submitButton: { label: 'Create Product' },
775
+ backButton: { label: 'Cancel' },
776
+ }}
777
+ />
778
+ ```
779
+
780
+ **Button Configuration Options:**
781
+
782
+ ```typescript
783
+ interface FormButtonConfig {
784
+ submitButton?: {
785
+ label?: string; // Button text (default: "Save")
786
+ icon?: ReactElement; // Custom icon (default: SaveFloppy)
787
+ isHidden?: boolean; // Hide button (default: false)
788
+ ariaLabel?: string; // Custom ARIA label
789
+ };
790
+
791
+ backButton?: {
792
+ label?: string; // Button text (default: "Back")
793
+ icon?: ReactElement; // Custom icon (default: Back)
794
+ isHidden?: boolean; // Hide button (default: false)
795
+ ariaLabel?: string; // Custom ARIA label
796
+ };
797
+
798
+ secondaryButtons?: Array<{
799
+ key: string; // Unique identifier
800
+ label: string; // Button text
801
+ icon?: ReactElement; // Optional icon
802
+ onPress: () => Promise<void>; // Click handler
803
+ variant?: 'primary' | 'secondary' | 'negative'; // Style variant
804
+ isDisabled?: boolean; // Disable state
805
+ type?: 'button' | 'submit'; // Button type (default: 'button')
806
+ ariaLabel?: string; // Custom ARIA label
807
+ }>;
808
+
809
+ position?: 'before' | 'after'; // Button position relative to form (default: 'after')
810
+ alignment?: 'start' | 'center' | 'end'; // Horizontal alignment (default: 'start')
811
+ gap?: 'small' | 'medium' | 'large'; // Spacing between buttons (default: 'small')
812
+ }
813
+ ```
814
+
815
+ **Common Use Cases:**
816
+
817
+ ```javascript
818
+ // Example 1: Create vs Edit Forms
819
+ <DataForm
820
+ buttonConfig={{
821
+ submitButton: {
822
+ label: isEditMode ? 'Update Product' : 'Create Product'
823
+ },
824
+ }}
825
+ />
826
+
827
+ // Example 2: Modal Forms (hide back button)
828
+ <DataForm
829
+ buttonConfig={{
830
+ submitButton: { label: 'Save Changes' },
831
+ backButton: { isHidden: true },
832
+ }}
833
+ />
834
+
835
+ // Example 3: Wizard Forms with Navigation
836
+ <DataForm
837
+ buttonConfig={{
838
+ submitButton: { label: 'Next Step' },
839
+ backButton: { label: 'Previous Step' },
840
+ }}
841
+ />
842
+
843
+ // Example 4: Draft Workflow with Secondary Action
844
+ <DataForm
845
+ buttonConfig={{
846
+ submitButton: { label: 'Save Draft' },
847
+ secondaryButtons: [
848
+ {
849
+ key: 'publish',
850
+ label: 'Publish',
851
+ variant: 'primary',
852
+ onPress: async () => {
853
+ await handlePublish();
854
+ },
855
+ },
856
+ ],
857
+ }}
858
+ />
859
+
860
+ // Example 5: Edit Form with Delete Action
861
+ <DataForm
862
+ buttonConfig={{
863
+ submitButton: { label: 'Update' },
864
+ secondaryButtons: [
865
+ {
866
+ key: 'delete',
867
+ label: 'Delete',
868
+ variant: 'negative',
869
+ onPress: async () => {
870
+ const confirmed = await showConfirmDialog();
871
+ if (confirmed) {
872
+ await handleDelete();
873
+ navigate('/products');
874
+ }
875
+ },
876
+ },
877
+ ],
878
+ }}
879
+ />
880
+
881
+ // Example 6: Top-Aligned Buttons for Long Forms
882
+ <DataForm
883
+ buttonConfig={{
884
+ submitButton: { label: 'Save' },
885
+ position: 'before',
886
+ alignment: 'end',
887
+ }}
888
+ />
889
+
890
+ // Example 7: Right-Aligned Buttons (Dialog Pattern)
891
+ <DataForm
892
+ buttonConfig={{
893
+ submitButton: { label: 'Confirm' },
894
+ backButton: { label: 'Cancel' },
895
+ alignment: 'end',
896
+ }}
897
+ />
898
+
899
+ // Example 8: Multi-Action Workflow
900
+ <DataForm
901
+ buttonConfig={{
902
+ submitButton: { label: 'Save' },
903
+ secondaryButtons: [
904
+ {
905
+ key: 'save-continue',
906
+ label: 'Save & Continue',
907
+ onPress: async () => {
908
+ await handleSave();
909
+ navigateToNext();
910
+ },
911
+ },
912
+ {
913
+ key: 'save-new',
914
+ label: 'Save & Add New',
915
+ onPress: async () => {
916
+ await handleSave();
917
+ resetForm();
918
+ },
919
+ },
920
+ ],
921
+ }}
922
+ />
923
+
924
+ // Example 9: Custom Icons and ARIA Labels
925
+ import SaveFloppy from '@spectrum-icons/workflow/SaveFloppy';
926
+ import CheckmarkCircle from '@spectrum-icons/workflow/CheckmarkCircle';
927
+
928
+ <DataForm
929
+ buttonConfig={{
930
+ submitButton: {
931
+ label: 'Approve',
932
+ icon: <CheckmarkCircle />,
933
+ ariaLabel: 'Approve and save changes',
934
+ },
935
+ }}
936
+ />
937
+
938
+ // Example 10: Centered Buttons with Custom Gap
939
+ <DataForm
940
+ buttonConfig={{
941
+ submitButton: { label: 'Submit' },
942
+ backButton: { label: 'Cancel' },
943
+ alignment: 'center',
944
+ gap: 'large',
945
+ }}
946
+ />
947
+ ```
948
+
949
+ **Button Order and States:**
950
+
951
+ - **Button Order**: ProgressCircle → Submit → Back → Secondary buttons (in order)
952
+ - **Disabled States**: All buttons are automatically disabled during form submission or when `isProcessing` is true
953
+ - **Loading States**: ProgressCircle shows automatically during submission, secondary buttons can show individual loading states
954
+ - **Accessibility**: All buttons have proper ARIA labels and keyboard navigation support
955
+
956
+ **Migration Notes:**
957
+
958
+ For existing implementations without `buttonConfig`, the default behavior is preserved:
959
+ - Submit button labeled "Save" with SaveFloppy icon
960
+ - Back button labeled "Back" with Back icon
961
+ - Buttons positioned after the form with start (left) alignment
962
+ - No breaking changes to existing code
411
963
 
412
964
  #### `ConfirmationDialog`
413
965
 
@@ -528,12 +1080,47 @@ const DocumentUploader = () => {
528
1080
  };
529
1081
  ```
530
1082
 
1083
+ **Programmatic Control with Refs (v1.0.3+):**
1084
+
1085
+ Reset the component programmatically from parent components:
1086
+
1087
+ ```javascript
1088
+ import React, { useRef } from 'react';
1089
+ import { FileUpload, FileUploadHandle } from '@adobe-commerce/aio-experience-kit';
1090
+
1091
+ const MyForm = () => {
1092
+ const fileUploadRef = useRef<FileUploadHandle>(null);
1093
+
1094
+ const handleReset = () => {
1095
+ fileUploadRef.current?.reset(); // Clear all files
1096
+ };
1097
+
1098
+ const handleGetFiles = () => {
1099
+ const files = fileUploadRef.current?.getFiles(); // Get current files
1100
+ console.log('Current files:', files);
1101
+ };
1102
+
1103
+ return (
1104
+ <>
1105
+ <FileUpload
1106
+ ref={fileUploadRef}
1107
+ label="Upload Files"
1108
+ onSelect={(files) => console.log('Selected:', files)}
1109
+ />
1110
+ <Button onPress={handleReset}>Reset</Button>
1111
+ <Button onPress={handleGetFiles}>Get Files</Button>
1112
+ </>
1113
+ );
1114
+ };
1115
+ ```
1116
+
531
1117
  **Features:**
532
1118
  - **File Selection**: Click to browse files with support for single or multiple file selection
533
1119
  - **Automatic Content Reading**: Automatically reads file content as text or base64 based on file type
534
1120
  - **File Type Validation**: Built-in validation for accepted MIME types and file extensions
535
1121
  - **Built-in Display**: Automatically displays selected files with name, size, and type information
536
- - **Clear Functionality**: Built-in "Clear Files" link to remove selected files
1122
+ - **Clear Functionality**: Built-in "Clear Files" link to remove selected files and programmatic reset via ref
1123
+ - **Imperative Handle**: Access reset() and getFiles() methods via React refs for parent control
537
1124
  - **Loading States**: Shows processing indicator while reading file contents
538
1125
  - **Error Handling**: Comprehensive error messaging for file reading failures
539
1126
  - **Accessibility**: Full keyboard navigation, screen reader support, and ARIA labels
@@ -631,6 +1218,7 @@ import type {
631
1218
  DataFormProps,
632
1219
  ConfirmationDialogProps,
633
1220
  FileUploadProps,
1221
+ FileUploadHandle,
634
1222
  FieldType,
635
1223
  AdminUiSdkInterface,
636
1224
  AdminUiSdkCredentials