@reformer/ui 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/FormArray-K2YVvq1u.js +101 -0
- package/dist/FormNavigation-3rg4tJyl.js +227 -0
- package/dist/form-array/FormArray.d.ts +170 -0
- package/dist/form-array/FormArrayAddButton.d.ts +19 -0
- package/dist/form-array/FormArrayContext.d.ts +46 -0
- package/dist/form-array/FormArrayCount.d.ts +17 -0
- package/dist/form-array/FormArrayEmpty.d.ts +22 -0
- package/dist/form-array/FormArrayItemIndex.d.ts +24 -0
- package/dist/form-array/FormArrayList.d.ts +26 -0
- package/dist/form-array/FormArrayRemoveButton.d.ts +19 -0
- package/dist/form-array/index.d.ts +13 -0
- package/dist/form-array/types.d.ts +72 -0
- package/dist/form-array/useFormArray.d.ts +66 -0
- package/dist/form-array.d.ts +2 -0
- package/dist/form-array.js +15 -0
- package/dist/form-navigation/FormNavigation.d.ts +16 -0
- package/dist/form-navigation/FormNavigationActions.d.ts +113 -0
- package/dist/form-navigation/FormNavigationContext.d.ts +42 -0
- package/dist/form-navigation/FormNavigationIndicator.d.ts +113 -0
- package/dist/form-navigation/FormNavigationProgress.d.ts +83 -0
- package/dist/form-navigation/FormNavigationStep.d.ts +37 -0
- package/dist/form-navigation/index.d.ts +12 -0
- package/dist/form-navigation/types.d.ts +52 -0
- package/dist/form-navigation.d.ts +2 -0
- package/dist/form-navigation.js +10 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +23 -0
- package/llms.txt +343 -0
- package/package.json +85 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { FormArrayEmptyProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* FormArray.Empty - Renders children only when array is empty
|
|
4
|
+
*
|
|
5
|
+
* @example Basic usage
|
|
6
|
+
* ```tsx
|
|
7
|
+
* <FormArray.Empty>
|
|
8
|
+
* <p className="text-gray-500">No items added yet</p>
|
|
9
|
+
* </FormArray.Empty>
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @example With call to action
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <FormArray.Empty>
|
|
15
|
+
* <div className="text-center p-8">
|
|
16
|
+
* <p>No properties</p>
|
|
17
|
+
* <FormArray.AddButton>Add your first property</FormArray.AddButton>
|
|
18
|
+
* </div>
|
|
19
|
+
* </FormArray.Empty>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function FormArrayEmpty({ children }: FormArrayEmptyProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { FormArrayItemIndexProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* FormArray.ItemIndex - Displays the index of current item (must be inside FormArray.List)
|
|
4
|
+
*
|
|
5
|
+
* @example Basic usage (1-based display)
|
|
6
|
+
* ```tsx
|
|
7
|
+
* <FormArray.List>
|
|
8
|
+
* {() => (
|
|
9
|
+
* <h4>Item #<FormArray.ItemIndex render={(i) => i + 1} /></h4>
|
|
10
|
+
* )}
|
|
11
|
+
* </FormArray.List>
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @example Zero-based index
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <FormArray.ItemIndex /> // Renders 0, 1, 2, ...
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @example Custom render
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <FormArray.ItemIndex render={(index) => `Position: ${index + 1}`} />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function FormArrayItemIndex({ render }: FormArrayItemIndexProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FormFields } from '@reformer/core';
|
|
2
|
+
import type { FormArrayListProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* FormArray.List - Iterates over array items and provides item context
|
|
5
|
+
*
|
|
6
|
+
* @example Basic usage
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <FormArray.List>
|
|
9
|
+
* {({ control, index, remove }) => (
|
|
10
|
+
* <div>
|
|
11
|
+
* <span>Item #{index + 1}</span>
|
|
12
|
+
* <button onClick={remove}>Remove</button>
|
|
13
|
+
* <ItemForm control={control} />
|
|
14
|
+
* </div>
|
|
15
|
+
* )}
|
|
16
|
+
* </FormArray.List>
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @example With custom container
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <FormArray.List className="space-y-4" as="ul">
|
|
22
|
+
* {(item) => <li><ItemForm control={item.control} /></li>}
|
|
23
|
+
* </FormArray.List>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function FormArrayList<T extends FormFields>({ children, className, as, }: FormArrayListProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FormArrayRemoveButtonProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* FormArray.RemoveButton - Button to remove current item (must be inside FormArray.List)
|
|
4
|
+
*
|
|
5
|
+
* @example Basic usage
|
|
6
|
+
* ```tsx
|
|
7
|
+
* <FormArray.List>
|
|
8
|
+
* {({ control }) => (
|
|
9
|
+
* <div>
|
|
10
|
+
* <ItemForm control={control} />
|
|
11
|
+
* <FormArray.RemoveButton className="text-red-500">
|
|
12
|
+
* Remove
|
|
13
|
+
* </FormArray.RemoveButton>
|
|
14
|
+
* </div>
|
|
15
|
+
* )}
|
|
16
|
+
* </FormArray.List>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function FormArrayRemoveButton({ children, ...props }: FormArrayRemoveButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { FormArray } from './FormArray';
|
|
2
|
+
export type { FormArrayHandle } from './FormArray';
|
|
3
|
+
export { FormArrayList } from './FormArrayList';
|
|
4
|
+
export { FormArrayAddButton } from './FormArrayAddButton';
|
|
5
|
+
export { FormArrayRemoveButton } from './FormArrayRemoveButton';
|
|
6
|
+
export { FormArrayEmpty } from './FormArrayEmpty';
|
|
7
|
+
export { FormArrayCount } from './FormArrayCount';
|
|
8
|
+
export { FormArrayItemIndex } from './FormArrayItemIndex';
|
|
9
|
+
export { useFormArray } from './useFormArray';
|
|
10
|
+
export type { FormArrayItem, UseFormArrayReturn } from './useFormArray';
|
|
11
|
+
export { FormArrayContext, FormArrayItemContext, useFormArrayContext, useFormArrayItemContext, } from './FormArrayContext';
|
|
12
|
+
export type { FormArrayRootProps, FormArrayListProps, FormArrayItemRenderProps, FormArrayAddButtonProps, FormArrayRemoveButtonProps, FormArrayEmptyProps, FormArrayCountProps, FormArrayItemIndexProps, } from './types';
|
|
13
|
+
export type { FormArrayContextValue, FormArrayItemContextValue } from './FormArrayContext';
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ReactNode, ElementType } from 'react';
|
|
2
|
+
import type { ArrayNode, FormFields, GroupNodeWithControls } from '@reformer/core';
|
|
3
|
+
/**
|
|
4
|
+
* Props for FormArray.Root component
|
|
5
|
+
*/
|
|
6
|
+
export interface FormArrayRootProps<T extends FormFields> {
|
|
7
|
+
/** The ArrayNode control from the form */
|
|
8
|
+
control: ArrayNode<T>;
|
|
9
|
+
/** Child components */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Props for FormArray.List component
|
|
14
|
+
*/
|
|
15
|
+
export interface FormArrayListProps<T extends FormFields> {
|
|
16
|
+
/** Render function for each item */
|
|
17
|
+
children: (item: FormArrayItemRenderProps<T>) => ReactNode;
|
|
18
|
+
/** Optional className for the list container */
|
|
19
|
+
className?: string;
|
|
20
|
+
/** Optional element type for the container (default: 'div') */
|
|
21
|
+
as?: ElementType;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Props passed to the render function in FormArray.List
|
|
25
|
+
*/
|
|
26
|
+
export interface FormArrayItemRenderProps<T extends FormFields> {
|
|
27
|
+
/** The form control for this item */
|
|
28
|
+
control: GroupNodeWithControls<T>;
|
|
29
|
+
/** Zero-based index of the item */
|
|
30
|
+
index: number;
|
|
31
|
+
/** Unique identifier for React key */
|
|
32
|
+
id: string | number;
|
|
33
|
+
/** Remove this item from the array */
|
|
34
|
+
remove: () => void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Props for FormArray.AddButton component
|
|
38
|
+
*/
|
|
39
|
+
export interface FormArrayAddButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> {
|
|
40
|
+
/** Initial value for the new item */
|
|
41
|
+
initialValue?: Partial<FormFields>;
|
|
42
|
+
/** Custom render function for the button */
|
|
43
|
+
asChild?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Props for FormArray.RemoveButton component
|
|
47
|
+
*/
|
|
48
|
+
export interface FormArrayRemoveButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> {
|
|
49
|
+
/** Custom render function for the button */
|
|
50
|
+
asChild?: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Props for FormArray.Empty component
|
|
54
|
+
*/
|
|
55
|
+
export interface FormArrayEmptyProps {
|
|
56
|
+
/** Content to show when array is empty */
|
|
57
|
+
children: ReactNode;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Props for FormArray.Count component
|
|
61
|
+
*/
|
|
62
|
+
export interface FormArrayCountProps {
|
|
63
|
+
/** Custom render function for the count */
|
|
64
|
+
render?: (count: number) => ReactNode;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Props for FormArray.ItemIndex component
|
|
68
|
+
*/
|
|
69
|
+
export interface FormArrayItemIndexProps {
|
|
70
|
+
/** Custom render function for the index (receives 0-based index) */
|
|
71
|
+
render?: (index: number) => ReactNode;
|
|
72
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type ArrayNode, type FormFields, type GroupNodeWithControls } from '@reformer/core';
|
|
2
|
+
/**
|
|
3
|
+
* Represents a single item in a form array with its control, index, and actions
|
|
4
|
+
*/
|
|
5
|
+
export interface FormArrayItem<T extends FormFields> {
|
|
6
|
+
/** The form control for this item */
|
|
7
|
+
control: GroupNodeWithControls<T>;
|
|
8
|
+
/** Zero-based index of the item in the array */
|
|
9
|
+
index: number;
|
|
10
|
+
/** Unique identifier for React key (uses internal id or falls back to index) */
|
|
11
|
+
id: string | number;
|
|
12
|
+
/** Remove this item from the array */
|
|
13
|
+
remove: () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Return type for useFormArray hook
|
|
17
|
+
*/
|
|
18
|
+
export interface UseFormArrayReturn<T extends FormFields> {
|
|
19
|
+
/** Array of items with their controls and actions */
|
|
20
|
+
items: FormArrayItem<T>[];
|
|
21
|
+
/** Current number of items in the array */
|
|
22
|
+
length: number;
|
|
23
|
+
/** Whether the array is empty */
|
|
24
|
+
isEmpty: boolean;
|
|
25
|
+
/** Add a new item to the end of the array */
|
|
26
|
+
add: (value?: Partial<T>) => void;
|
|
27
|
+
/** Remove all items from the array */
|
|
28
|
+
clear: () => void;
|
|
29
|
+
/** Insert a new item at a specific index */
|
|
30
|
+
insert: (index: number, value?: Partial<T>) => void;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Headless hook for managing form arrays
|
|
34
|
+
*
|
|
35
|
+
* Provides reactive state and actions for form array manipulation
|
|
36
|
+
* without any UI - perfect for building custom array interfaces.
|
|
37
|
+
*
|
|
38
|
+
* @example Basic usage
|
|
39
|
+
* ```tsx
|
|
40
|
+
* function PropertyList() {
|
|
41
|
+
* const { items, add, isEmpty } = useFormArray(form.properties);
|
|
42
|
+
*
|
|
43
|
+
* return (
|
|
44
|
+
* <div>
|
|
45
|
+
* {items.map(({ control, index, remove, id }) => (
|
|
46
|
+
* <div key={id}>
|
|
47
|
+
* <span>Property #{index + 1}</span>
|
|
48
|
+
* <button onClick={remove}>Remove</button>
|
|
49
|
+
* <PropertyForm control={control} />
|
|
50
|
+
* </div>
|
|
51
|
+
* ))}
|
|
52
|
+
* {isEmpty && <p>No properties added</p>}
|
|
53
|
+
* <button onClick={() => add()}>Add Property</button>
|
|
54
|
+
* </div>
|
|
55
|
+
* );
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example With initial values
|
|
60
|
+
* ```tsx
|
|
61
|
+
* const { add } = useFormArray(form.items);
|
|
62
|
+
* // Add item with pre-filled values
|
|
63
|
+
* add({ name: 'New Item', quantity: 1 });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function useFormArray<T extends FormFields>(control: ArrayNode<T>): UseFormArrayReturn<T>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { F as o, b as t, g as m, e as s, d as e, h as y, f as A, a as F, c as n, u, i as x, j as C } from "./FormArray-K2YVvq1u.js";
|
|
2
|
+
export {
|
|
3
|
+
o as FormArray,
|
|
4
|
+
t as FormArrayAddButton,
|
|
5
|
+
m as FormArrayContext,
|
|
6
|
+
s as FormArrayCount,
|
|
7
|
+
e as FormArrayEmpty,
|
|
8
|
+
y as FormArrayItemContext,
|
|
9
|
+
A as FormArrayItemIndex,
|
|
10
|
+
F as FormArrayList,
|
|
11
|
+
n as FormArrayRemoveButton,
|
|
12
|
+
u as useFormArray,
|
|
13
|
+
x as useFormArrayContext,
|
|
14
|
+
C as useFormArrayItemContext
|
|
15
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FormNavigationStep } from './FormNavigationStep';
|
|
2
|
+
import { FormNavigationIndicator } from './FormNavigationIndicator';
|
|
3
|
+
import { FormNavigationActions } from './FormNavigationActions';
|
|
4
|
+
import { FormNavigationProgress } from './FormNavigationProgress';
|
|
5
|
+
import type { FormNavigationHandle, FormNavigationProps } from './types';
|
|
6
|
+
declare const FormNavigationBase: <T extends Record<string, any>>(props: FormNavigationProps<T> & {
|
|
7
|
+
ref?: React.ForwardedRef<FormNavigationHandle<T>>;
|
|
8
|
+
}) => React.ReactElement;
|
|
9
|
+
type FormNavigationComponent = typeof FormNavigationBase & {
|
|
10
|
+
Step: typeof FormNavigationStep;
|
|
11
|
+
Indicator: typeof FormNavigationIndicator;
|
|
12
|
+
Actions: typeof FormNavigationActions;
|
|
13
|
+
Progress: typeof FormNavigationProgress;
|
|
14
|
+
};
|
|
15
|
+
export declare const FormNavigation: FormNavigationComponent;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Props for a navigation button (prev/next)
|
|
4
|
+
*/
|
|
5
|
+
export interface FormNavigationButtonProps {
|
|
6
|
+
/** Click handler */
|
|
7
|
+
onClick: () => void;
|
|
8
|
+
/** Whether the button is disabled */
|
|
9
|
+
disabled: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Props for the submit button
|
|
13
|
+
*/
|
|
14
|
+
export interface FormNavigationSubmitProps extends FormNavigationButtonProps {
|
|
15
|
+
/** Whether form is currently submitting */
|
|
16
|
+
isSubmitting: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Render props passed to children function
|
|
20
|
+
*/
|
|
21
|
+
export interface FormNavigationActionsRenderProps {
|
|
22
|
+
/** Props for the "Previous" button */
|
|
23
|
+
prev: FormNavigationButtonProps;
|
|
24
|
+
/** Props for the "Next" button */
|
|
25
|
+
next: FormNavigationButtonProps;
|
|
26
|
+
/** Props for the "Submit" button */
|
|
27
|
+
submit: FormNavigationSubmitProps;
|
|
28
|
+
/** Whether current step is the first step */
|
|
29
|
+
isFirstStep: boolean;
|
|
30
|
+
/** Whether current step is the last step */
|
|
31
|
+
isLastStep: boolean;
|
|
32
|
+
/** Whether validation is in progress */
|
|
33
|
+
isValidating: boolean;
|
|
34
|
+
/** Whether form is submitting */
|
|
35
|
+
isSubmitting: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Props for FormNavigation.Actions component
|
|
39
|
+
*/
|
|
40
|
+
export interface FormNavigationActionsProps {
|
|
41
|
+
/** Submit handler (called on last step) */
|
|
42
|
+
onSubmit?: () => void | Promise<void>;
|
|
43
|
+
/** Render function for custom UI */
|
|
44
|
+
children: (props: FormNavigationActionsRenderProps) => ReactNode;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* FormNavigation.Actions - Headless component for navigation buttons
|
|
48
|
+
*
|
|
49
|
+
* Provides all necessary props and state for building custom navigation UI.
|
|
50
|
+
* No default UI - you build exactly what you need.
|
|
51
|
+
*
|
|
52
|
+
* ## Render Props
|
|
53
|
+
* - `prev` - props for Previous button (`onClick`, `disabled`)
|
|
54
|
+
* - `next` - props for Next button (`onClick`, `disabled`)
|
|
55
|
+
* - `submit` - props for Submit button (`onClick`, `disabled`, `isSubmitting`)
|
|
56
|
+
* - `isFirstStep` - hide prev button on first step
|
|
57
|
+
* - `isLastStep` - show submit instead of next on last step
|
|
58
|
+
* - `isValidating` - show loading state during validation
|
|
59
|
+
* - `isSubmitting` - show loading state during submission
|
|
60
|
+
*
|
|
61
|
+
* @example Basic usage
|
|
62
|
+
* ```tsx
|
|
63
|
+
* <FormNavigation.Actions onSubmit={handleSubmit}>
|
|
64
|
+
* {({ prev, next, submit, isFirstStep, isLastStep }) => (
|
|
65
|
+
* <div className="flex justify-between">
|
|
66
|
+
* {!isFirstStep && (
|
|
67
|
+
* <Button onClick={prev.onClick} disabled={prev.disabled}>
|
|
68
|
+
* Back
|
|
69
|
+
* </Button>
|
|
70
|
+
* )}
|
|
71
|
+
* <div className="flex-1" />
|
|
72
|
+
* {!isLastStep ? (
|
|
73
|
+
* <Button onClick={next.onClick} disabled={next.disabled}>
|
|
74
|
+
* Next
|
|
75
|
+
* </Button>
|
|
76
|
+
* ) : (
|
|
77
|
+
* <Button onClick={submit.onClick} disabled={submit.disabled}>
|
|
78
|
+
* {submit.isSubmitting ? 'Submitting...' : 'Submit'}
|
|
79
|
+
* </Button>
|
|
80
|
+
* )}
|
|
81
|
+
* </div>
|
|
82
|
+
* )}
|
|
83
|
+
* </FormNavigation.Actions>
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example With custom button component
|
|
87
|
+
* ```tsx
|
|
88
|
+
* <FormNavigation.Actions onSubmit={handleSubmit}>
|
|
89
|
+
* {({ prev, next, submit, isFirstStep, isLastStep, isValidating }) => (
|
|
90
|
+
* <ActionBar>
|
|
91
|
+
* <ActionBar.Left>
|
|
92
|
+
* {!isFirstStep && <IconButton icon="arrow-left" {...prev} />}
|
|
93
|
+
* </ActionBar.Left>
|
|
94
|
+
* <ActionBar.Right>
|
|
95
|
+
* {isLastStep ? (
|
|
96
|
+
* <PrimaryButton {...submit} loading={submit.isSubmitting}>
|
|
97
|
+
* Submit Application
|
|
98
|
+
* </PrimaryButton>
|
|
99
|
+
* ) : (
|
|
100
|
+
* <PrimaryButton {...next} loading={isValidating}>
|
|
101
|
+
* Continue
|
|
102
|
+
* </PrimaryButton>
|
|
103
|
+
* )}
|
|
104
|
+
* </ActionBar.Right>
|
|
105
|
+
* </ActionBar>
|
|
106
|
+
* )}
|
|
107
|
+
* </FormNavigation.Actions>
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function FormNavigationActions({ onSubmit, children }: FormNavigationActionsProps): import("react/jsx-runtime").JSX.Element;
|
|
111
|
+
export declare namespace FormNavigationActions {
|
|
112
|
+
var displayName: string;
|
|
113
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { GroupNodeWithControls } from '@reformer/core';
|
|
2
|
+
/**
|
|
3
|
+
* Context value for FormNavigation
|
|
4
|
+
* Shares navigation state and methods with child components
|
|
5
|
+
*/
|
|
6
|
+
export interface FormNavigationContextValue<T extends Record<string, any>> {
|
|
7
|
+
/** Current step (1-based) */
|
|
8
|
+
currentStep: number;
|
|
9
|
+
/** Total number of steps */
|
|
10
|
+
totalSteps: number;
|
|
11
|
+
/** Completed steps */
|
|
12
|
+
completedSteps: number[];
|
|
13
|
+
/** Is this the first step */
|
|
14
|
+
isFirstStep: boolean;
|
|
15
|
+
/** Is this the last step */
|
|
16
|
+
isLastStep: boolean;
|
|
17
|
+
/** Is validation in progress */
|
|
18
|
+
isValidating: boolean;
|
|
19
|
+
/** Is form submitting */
|
|
20
|
+
isSubmitting: boolean;
|
|
21
|
+
/** Form instance */
|
|
22
|
+
form: GroupNodeWithControls<T>;
|
|
23
|
+
/** Go to next step (with validation) */
|
|
24
|
+
goToNextStep: () => Promise<boolean>;
|
|
25
|
+
/** Go to previous step */
|
|
26
|
+
goToPreviousStep: () => void;
|
|
27
|
+
/** Go to specific step */
|
|
28
|
+
goToStep: (step: number) => boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare const FormNavigationContext: import("react").Context<FormNavigationContextValue<any> | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Hook to access FormNavigation context
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* function MyStepComponent() {
|
|
37
|
+
* const { currentStep, isLastStep } = useFormNavigation();
|
|
38
|
+
* // ...
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function useFormNavigation<T extends Record<string, any>>(): FormNavigationContextValue<T>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Step definition for the indicator
|
|
4
|
+
*/
|
|
5
|
+
export interface FormNavigationIndicatorStep {
|
|
6
|
+
/** Step number (1-based) */
|
|
7
|
+
number: number;
|
|
8
|
+
/** Step title/label */
|
|
9
|
+
title: string;
|
|
10
|
+
/** Optional icon */
|
|
11
|
+
icon?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Enriched step with state information
|
|
15
|
+
*/
|
|
16
|
+
export interface FormNavigationIndicatorStepWithState extends FormNavigationIndicatorStep {
|
|
17
|
+
/** Whether this is the current step */
|
|
18
|
+
isCurrent: boolean;
|
|
19
|
+
/** Whether this step is completed */
|
|
20
|
+
isCompleted: boolean;
|
|
21
|
+
/** Whether user can navigate to this step */
|
|
22
|
+
canNavigate: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Render props passed to children function
|
|
26
|
+
*/
|
|
27
|
+
export interface FormNavigationIndicatorRenderProps {
|
|
28
|
+
/** Steps with their current state */
|
|
29
|
+
steps: FormNavigationIndicatorStepWithState[];
|
|
30
|
+
/** Navigate to a specific step */
|
|
31
|
+
goToStep: (step: number) => boolean;
|
|
32
|
+
/** Current step number */
|
|
33
|
+
currentStep: number;
|
|
34
|
+
/** Total number of steps */
|
|
35
|
+
totalSteps: number;
|
|
36
|
+
/** Completed step numbers */
|
|
37
|
+
completedSteps: number[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Props for FormNavigation.Indicator component
|
|
41
|
+
*/
|
|
42
|
+
export interface FormNavigationIndicatorProps {
|
|
43
|
+
/** Step definitions */
|
|
44
|
+
steps: FormNavigationIndicatorStep[];
|
|
45
|
+
/** Render function for custom UI */
|
|
46
|
+
children: (props: FormNavigationIndicatorRenderProps) => ReactNode;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* FormNavigation.Indicator - Headless component for step indicator
|
|
50
|
+
*
|
|
51
|
+
* Provides step data with state for building custom step indicators.
|
|
52
|
+
* No default UI - you build exactly what you need.
|
|
53
|
+
*
|
|
54
|
+
* ## Render Props
|
|
55
|
+
* - `steps` - array of steps with state (`isCurrent`, `isCompleted`, `canNavigate`)
|
|
56
|
+
* - `goToStep` - function to navigate to a step
|
|
57
|
+
* - `currentStep` - current step number
|
|
58
|
+
* - `totalSteps` - total number of steps
|
|
59
|
+
* - `completedSteps` - array of completed step numbers
|
|
60
|
+
*
|
|
61
|
+
* @example Basic stepper
|
|
62
|
+
* ```tsx
|
|
63
|
+
* <FormNavigation.Indicator steps={STEPS}>
|
|
64
|
+
* {({ steps, goToStep }) => (
|
|
65
|
+
* <nav className="flex gap-2">
|
|
66
|
+
* {steps.map((step) => (
|
|
67
|
+
* <button
|
|
68
|
+
* key={step.number}
|
|
69
|
+
* onClick={() => goToStep(step.number)}
|
|
70
|
+
* disabled={!step.canNavigate}
|
|
71
|
+
* className={cn(
|
|
72
|
+
* 'px-4 py-2 rounded',
|
|
73
|
+
* step.isCurrent && 'bg-blue-500 text-white',
|
|
74
|
+
* step.isCompleted && 'bg-green-100',
|
|
75
|
+
* !step.canNavigate && 'opacity-50 cursor-not-allowed'
|
|
76
|
+
* )}
|
|
77
|
+
* >
|
|
78
|
+
* {step.icon} {step.title}
|
|
79
|
+
* </button>
|
|
80
|
+
* ))}
|
|
81
|
+
* </nav>
|
|
82
|
+
* )}
|
|
83
|
+
* </FormNavigation.Indicator>
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example With progress line
|
|
87
|
+
* ```tsx
|
|
88
|
+
* <FormNavigation.Indicator steps={STEPS}>
|
|
89
|
+
* {({ steps, goToStep }) => (
|
|
90
|
+
* <div className="flex items-center">
|
|
91
|
+
* {steps.map((step, index) => (
|
|
92
|
+
* <Fragment key={step.number}>
|
|
93
|
+
* <StepCircle
|
|
94
|
+
* active={step.isCurrent}
|
|
95
|
+
* completed={step.isCompleted}
|
|
96
|
+
* onClick={() => step.canNavigate && goToStep(step.number)}
|
|
97
|
+
* >
|
|
98
|
+
* {step.isCompleted ? '✓' : step.number}
|
|
99
|
+
* </StepCircle>
|
|
100
|
+
* {index < steps.length - 1 && (
|
|
101
|
+
* <StepLine completed={step.isCompleted} />
|
|
102
|
+
* )}
|
|
103
|
+
* </Fragment>
|
|
104
|
+
* ))}
|
|
105
|
+
* </div>
|
|
106
|
+
* )}
|
|
107
|
+
* </FormNavigation.Indicator>
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export declare function FormNavigationIndicator({ steps, children }: FormNavigationIndicatorProps): import("react/jsx-runtime").JSX.Element;
|
|
111
|
+
export declare namespace FormNavigationIndicator {
|
|
112
|
+
var displayName: string;
|
|
113
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Render props passed to children function
|
|
4
|
+
*/
|
|
5
|
+
export interface FormNavigationProgressRenderProps {
|
|
6
|
+
/** Current step number (1-based) */
|
|
7
|
+
current: number;
|
|
8
|
+
/** Total number of steps */
|
|
9
|
+
total: number;
|
|
10
|
+
/** Completion percentage (0-100) */
|
|
11
|
+
percent: number;
|
|
12
|
+
/** Number of completed steps */
|
|
13
|
+
completedCount: number;
|
|
14
|
+
/** Whether on first step */
|
|
15
|
+
isFirstStep: boolean;
|
|
16
|
+
/** Whether on last step */
|
|
17
|
+
isLastStep: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Props for FormNavigation.Progress component
|
|
21
|
+
*/
|
|
22
|
+
export interface FormNavigationProgressProps {
|
|
23
|
+
/** Render function for custom UI */
|
|
24
|
+
children: (props: FormNavigationProgressRenderProps) => ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* FormNavigation.Progress - Headless component for progress display
|
|
28
|
+
*
|
|
29
|
+
* Provides progress data for building custom progress indicators.
|
|
30
|
+
* No default UI - you build exactly what you need.
|
|
31
|
+
*
|
|
32
|
+
* ## Render Props
|
|
33
|
+
* - `current` - current step number
|
|
34
|
+
* - `total` - total number of steps
|
|
35
|
+
* - `percent` - completion percentage (0-100)
|
|
36
|
+
* - `completedCount` - number of completed steps
|
|
37
|
+
* - `isFirstStep` - whether on first step
|
|
38
|
+
* - `isLastStep` - whether on last step
|
|
39
|
+
*
|
|
40
|
+
* @example Simple text progress
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <FormNavigation.Progress>
|
|
43
|
+
* {({ current, total, percent }) => (
|
|
44
|
+
* <div className="text-sm text-gray-600">
|
|
45
|
+
* Step {current} of {total} ({percent}% complete)
|
|
46
|
+
* </div>
|
|
47
|
+
* )}
|
|
48
|
+
* </FormNavigation.Progress>
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example Progress bar
|
|
52
|
+
* ```tsx
|
|
53
|
+
* <FormNavigation.Progress>
|
|
54
|
+
* {({ percent, current, total }) => (
|
|
55
|
+
* <div className="space-y-2">
|
|
56
|
+
* <div className="flex justify-between text-sm">
|
|
57
|
+
* <span>Step {current}/{total}</span>
|
|
58
|
+
* <span>{percent}%</span>
|
|
59
|
+
* </div>
|
|
60
|
+
* <div className="h-2 bg-gray-200 rounded-full overflow-hidden">
|
|
61
|
+
* <div
|
|
62
|
+
* className="h-full bg-blue-500 transition-all"
|
|
63
|
+
* style={{ width: `${percent}%` }}
|
|
64
|
+
* />
|
|
65
|
+
* </div>
|
|
66
|
+
* </div>
|
|
67
|
+
* )}
|
|
68
|
+
* </FormNavigation.Progress>
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example Circular progress
|
|
72
|
+
* ```tsx
|
|
73
|
+
* <FormNavigation.Progress>
|
|
74
|
+
* {({ percent }) => (
|
|
75
|
+
* <CircularProgress value={percent} />
|
|
76
|
+
* )}
|
|
77
|
+
* </FormNavigation.Progress>
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function FormNavigationProgress({ children }: FormNavigationProgressProps): import("react/jsx-runtime").JSX.Element;
|
|
81
|
+
export declare namespace FormNavigationProgress {
|
|
82
|
+
var displayName: string;
|
|
83
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
import type { GroupNodeWithControls } from '@reformer/core';
|
|
3
|
+
/**
|
|
4
|
+
* Props for FormNavigation.Step component
|
|
5
|
+
*/
|
|
6
|
+
export interface FormNavigationStepProps<T extends Record<string, any>> {
|
|
7
|
+
/** Component to render for this step */
|
|
8
|
+
component: ComponentType<{
|
|
9
|
+
control: GroupNodeWithControls<T>;
|
|
10
|
+
} & Record<string, unknown>>;
|
|
11
|
+
/** Form control to pass to the component */
|
|
12
|
+
control: GroupNodeWithControls<T>;
|
|
13
|
+
/** Any additional props to pass to the component */
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Internal props that include the step index (set by parent FormNavigation)
|
|
18
|
+
*/
|
|
19
|
+
export interface FormNavigationStepInternalProps<T extends Record<string, any>> extends FormNavigationStepProps<T> {
|
|
20
|
+
/** Step index (1-based), set internally by FormNavigation */
|
|
21
|
+
_stepIndex?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* FormNavigation.Step - renders a step component when it's the current step
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* <FormNavigation ref={navRef} form={form} config={config}>
|
|
29
|
+
* <FormNavigation.Step component={Step1} control={form} />
|
|
30
|
+
* <FormNavigation.Step component={Step2} control={form} extraProp="value" />
|
|
31
|
+
* </FormNavigation>
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function FormNavigationStep<T extends Record<string, any>>({ component: Component, control, _stepIndex, ...restProps }: FormNavigationStepInternalProps<T>): import("react/jsx-runtime").JSX.Element | null;
|
|
35
|
+
export declare namespace FormNavigationStep {
|
|
36
|
+
var displayName: string;
|
|
37
|
+
}
|