Skip to content

Commit 38ffc11

Browse files
committed
DeepPartial, docs updates
1 parent 9e55087 commit 38ffc11

19 files changed

+111
-70
lines changed

README.md

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
# react-multi-page-form
1+
![React Multi Page Form](https://stutrek.github.io/react-multi-page-form/Logo.svg "")
22

33
This is a tool for managing the sequence and flow of multi-page workflows. Given a long series of screens, it can put them in the proper order makes it easy to show and hide screens based on previous input.
44

55
Workflows can be composed, allowing you to reuse parts of a flow.
66

77
This should be used in combination with a component library and validation schema to improve your form management.
88

9-
All of the examples use react-hook-form, but any library could be used.
9+
An integration with React Hook Form is provided, but the base could be used with any library.
10+
11+
[View the docs](https://stutrek.github.io/react-multi-page-form/)
1012

1113
## Basic Usage
1214

@@ -61,6 +63,9 @@ const MyMultiPageForm = () => {
6163
</>);
6264
};
6365
```
66+
[View the docs](https://stutrek.github.io/react-multi-page-form/)
67+
68+
6469
### Pages and Sequences
6570

6671
A **page** represents a single screen that will be shown to the user as part of this multi-step form. It can have as many fields or as few as you'd like. It can even have logic to show and hide fields built in.
@@ -71,18 +76,20 @@ A **sequence** is an array of pages and sequences that represent a specific flow
7176
type FormPage<DataT, ComponentProps, ErrorList> = {
7277
id: string;
7378
// determines whether or not this page is needed
74-
isRequired?: (data: Partial<DataT>) => boolean | undefined
79+
isRequired?: (data: DeepPartial<DataT>) => boolean | undefined
7580
// determines if the page is already complete
76-
isComplete: (data: Partial<DataT>) => boolean;
81+
isComplete: (data: DeepPartial<DataT>) => boolean;
7782
// determines if this should be a final step in the flow
78-
isFinal?: (data: Partial<DataT>) => boolean;
83+
isFinal?: (data: DeepPartial<DataT>) => boolean;
84+
// if you need to break the flow of the sequence, this makes that possible
85+
alternateNextPage?: (data: DeepPartial<DataT>) => Boolean
7986
// Mounted inputs are automatically validated.
8087
// If you need specific validation logic, put it here.
81-
validate?: (data: Partial<DataT>) => ErrorList | undefined;
88+
validate?: (data: DeepPartial<DataT>) => ErrorList | undefined;
8289
// callback on arrival
83-
onArrive?: (data: Partial<DataT>) => void;
90+
onArrive?: (data: DeepPartial<DataT>) => void;
8491
// callback on departure
85-
onExit?: (data: Partial<DataT>) => Promise<void> | void;
92+
onExit?: (data: DeepPartial<DataT>) => Promise<void> | void;
8693
// the component that will be rendered
8794
Component: (props: ComponentProps) => JSX.Element;
8895
};
@@ -96,6 +103,9 @@ export type FormSequence<DataT, ComponentProps, ErrorList> = {
96103
};
97104
```
98105

106+
[View the docs](https://stutrek.github.io/react-multi-page-form/)
107+
108+
99109
## A More Complete Example
100110

101111
```typescript
@@ -163,5 +173,6 @@ export function MyMultiPageForm() {
163173
);
164174
}
165175
```
176+
[View the docs](https://stutrek.github.io/react-multi-page-form/)
166177

167178

docs/src/app/Intro.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,18 @@ This example features a short form that displays additional pages only if the us
1010

1111
## Integration within the Ecosystem
1212

13-
<img src="/how%20it%20fits%20in.png" alt="" className="mx-auto w-[32rem]" />
13+
<img src="/react-multi-page-form/how%20it%20fits%20in.png" alt="" className="mx-auto w-[32rem]" />
1414

1515
React Multi Page Form seamlessly integrates into the React ecosystem by focusing exclusively on sequence and flow management. It doesn’t handle UI rendering or data persistence, allowing developers to pair it with their preferred component libraries and state management tools. While it includes integration with React Hook Form, it can also work with Formik, Final Form, or any other React form library.
1616

1717
## Why Use React Multi Page Form?
1818

1919
- **Streamline Long Forms:** Skip unnecessary pages dynamically based on user inputs.
20+
- **Easy Testing:** Quickly see the list of pages used for any set of data, and render all pages at once.
2021
- **Simplified Navigation:** Implement next and previous buttons effortlessly.
2122
- **Dynamic Form Testing:** Quickly test and determine which forms are displayed to users depending on their selections.
2223
- **Resume Functionality:** Enable users to pick up where they left off, improving completion rates.
2324
- **Composable Workflows:** Combine multiple workflows into a single cohesive process, promoting reusability and modularity in form management.
2425
- **Great for AI:** Clear separation of concerns makes it easy for AI to generate the first draft of your sequences and forms.
2526

26-
Ready to simplify your multi-page forms? See the [getting started page](/docs) or check out the [GitHub repository](https://github.com/stutrek/react-multi-page-form).
27+
Ready to simplify your multi-page forms? See the [getting started page](/react-multi-page-form/docs) or check out the [GitHub repository](https://github.com/stutrek/react-multi-page-form).

docs/src/app/docs/api/page.mdx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ type HookFormPage<DataT, ComponentProps = { hookForm: UseFormReturn }> = {
2020
// these three are required
2121
id: string; // Unique identifier for the form page.
2222
Component: (props: ComponentProps) => JSX.Element; // React component to render the form page.
23-
isComplete: (data: Partial<DataT>) => boolean; // Checks if the user has already filled out this page.
23+
isComplete: (data: DeepPartial<DataT>) => boolean; // Checks if the user has already filled out this page.
2424

2525
// these manage the sequence
26-
isFinal?: (data: Partial<DataT>) => boolean; // return true if this should be the final page of the form.
27-
isRequired?: (data: Partial<DataT>) => boolean | undefined; // Determines if this page is needed based on form data. Default: () => true
28-
validate?: (data: Partial<DataT>) => Promise<FieldErrors | undefined>; // Determines whether or not to continue.
29-
alternateNextPage: (data: Partial<DataT>) => pageId; // Useful if you need to override the default order of pages
26+
isFinal?: (data: DeepPartial<DataT>) => boolean; // return true if this should be the final page of the form.
27+
isRequired?: (data: DeepPartial<DataT>) => boolean | undefined; // Determines if this page is needed based on form data. Default: () => true
28+
validate?: (data: DeepPartial<DataT>) => Promise<FieldErrors | undefined>; // Determines whether or not to continue.
29+
alternateNextPage?: (data: DeepPartial<DataT>) => pageId; // Useful if you need to override the default order of pages
3030

3131
// event handlers
32-
onArrive?: (data: Partial<DataT>) => void; // Function to execute upon arriving at this page.
33-
onExit?: (data: Partial<DataT>) => Promise<void> | void; // Function to execute when exiting the page.
32+
onArrive?: (data: DeepPartial<DataT>) => void; // Function to execute upon arriving at this page.
33+
onExit?: (data: DeepPartial<DataT>) => Promise<void> | void; // Function to execute when exiting the page.
3434
};
3535
```
3636

@@ -63,7 +63,7 @@ A sequence contains pages or more sequences that represent a single workflow. Th
6363
export type FormSequence<DataT, ComponentProps, ErrorList> = {
6464
id: string; // Unique identifier for the form sequence.
6565
pages: HookFormSequenceChild[]; // A SequenceChild is either a FormPage or a FormSequence.
66-
isRequired?: (data: Partial<DataT>) => boolean | undefined; // Determines if the sequence is needed based on form data.
66+
isRequired?: (data: DeepPartial<DataT>) => boolean | undefined; // Determines if the sequence is needed based on form data.
6767
};
6868
```
6969

docs/src/app/docs/page.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ To allow consistent typing throughout the library, you need a single type for yo
2929

3030
### Schema
3131

32-
This is the shape the data takes for the entirety of the form. Not all of it will be on the screen at the same time, and you'll have a chance to save data when changing pages. This data will be Partial'd, since it won't all be available until the user is done providing it.
32+
This is the shape the data takes for the entirety of the form. Not all of it will be on the screen at the same time, and you'll have a chance to save data when changing pages. This data will be DeepPartial'd, since it won't all be available until the user is done providing it.
3333

3434
```typescript
3535
type MySchema = {

docs/src/app/header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function Header({ showLogo = true }: HeaderProps) {
1616
<li>
1717
<Link href="/">
1818
<img
19-
src="./Logo.svg"
19+
src="/react-multi-page-form/Logo.svg"
2020
alt="React Multi Page Form"
2121
className="h-7"
2222
/>

docs/src/app/layout.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ export default function RootLayout({
99
}>) {
1010
return (
1111
<html lang="en">
12-
<head>
13-
<base href="/react-multi-page-form/" />
14-
</head>
1512
<body className="antialiased">{children}</body>
13+
<div className="container max-w-3xl mx-auto p-4 text-sm text-gray-400">
14+
<hr className="mb-3" />
15+
&copy; 2024 Stu Kabakoff
16+
</div>
1617
</html>
1718
);
1819
}

docs/src/app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default function () {
55
<div className="container max-w-3xl mx-auto prose p-4">
66
<div className="text-center">
77
<img
8-
src="./Logo.svg"
8+
src="/react-multi-page-form/Logo.svg"
99
alt="React Multi Page Form"
1010
className="h-13"
1111
/>

docs/src/mdx-components.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import type { MDXComponents } from 'mdx/types';
22

33
export function useMDXComponents(components: MDXComponents): MDXComponents {
44
return {
5+
a: (props) => {
6+
let href = props.href as string;
7+
if (href?.startsWith('/')) {
8+
href = `/react-multi-page-form${href}`;
9+
}
10+
return <a href={href} {...props} />;
11+
},
512
...components,
613
};
714
}

package.json

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
"version": "0.1.0",
44
"description": "Tools to handle multi-page forms",
55
"main": "dist/index.js",
6-
"files": [
7-
"dist"
8-
],
6+
"files": ["dist"],
97
"scripts": {
108
"build": "tsc",
119
"build:watch": "tsc -w",
@@ -16,10 +14,7 @@
1614
"test": "jest",
1715
"test:watch": "jest --watch"
1816
},
19-
"keywords": [
20-
"forms",
21-
"multi-page"
22-
],
17+
"keywords": ["forms", "multi-page"],
2318
"author": "Stu Kabakoff",
2419
"license": "MIT",
2520
"devDependencies": {

src/__tests__/initialization.spec.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { renderHook } from '@testing-library/react';
33
import { useMultiPageFormBase } from '../base';
4-
import { StartingPage } from '../types';
4+
import { type DeepPartial, StartingPage } from '../types';
55

66
describe('useMultiPageFormBase - Initialization Tests', () => {
77
const pages = [
@@ -285,7 +285,7 @@ describe('useMultiPageFormBase - Initialization Tests', () => {
285285
{
286286
id: 'page2',
287287
isComplete: () => false,
288-
isRequired: (data: Partial<{ skipPage2: boolean }>) =>
288+
isRequired: (data: DeepPartial<{ skipPage2: boolean }>) =>
289289
!data.skipPage2,
290290
Component: () => <div />,
291291
},

0 commit comments

Comments
 (0)