Skip to content

Commit bfcc68b

Browse files
authored
Update dependencies (#22)
1 parent 588b447 commit bfcc68b

File tree

11 files changed

+1800
-1777
lines changed

11 files changed

+1800
-1777
lines changed

__tests__/focusHandling.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ test("the first errored field is focused after submission", async () => {
9999
await screen.findByText("firstName valid");
100100
await screen.findByText("lastName error");
101101

102-
expect(lastNameInput).toHaveFocus();
102+
expect(document.activeElement).toBe(lastNameInput);
103103
});
104104

105105
test("the user can disable autofocus on first error", async () => {
@@ -169,7 +169,7 @@ test("the user can disable autofocus on first error", async () => {
169169

170170
await screen.findByText("error");
171171

172-
expect(input).not.toHaveFocus();
172+
expect(document.activeElement).not.toBe(input);
173173
});
174174

175175
test("focusField and focusNextField behave like expected", async () => {
@@ -249,8 +249,8 @@ test("focusField and focusNextField behave like expected", async () => {
249249
const focusFirstNameButton = await screen.findByText("Focus firstName");
250250

251251
fireEvent.click(focusFirstNameButton);
252-
expect(firstNameInput).toHaveFocus();
252+
expect(document.activeElement).toBe(firstNameInput);
253253

254254
fireEvent.input(firstNameInput, { target: { value: "Nicolas" } });
255-
expect(lastNameInput).toHaveFocus();
255+
expect(document.activeElement).toBe(lastNameInput);
256256
});

package.json

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,25 +58,21 @@
5858
"dependencies": {
5959
"use-sync-external-store": "^1.2.0"
6060
},
61-
"resolutions": {
62-
"@types/testing-library__jest-dom": "github:zoontek/types-testing-library-vitest-dom"
63-
},
6461
"devDependencies": {
65-
"@testing-library/jest-dom": "^5.16.5",
6662
"@testing-library/react": "^12.1.5",
67-
"@types/react": "^17.0.58",
63+
"@types/react": "^17.0.62",
6864
"@types/use-sync-external-store": "^0.0.3",
69-
"@typescript-eslint/eslint-plugin": "^5.59.2",
70-
"@typescript-eslint/parser": "^5.59.2",
71-
"eslint": "^8.39.0",
65+
"@typescript-eslint/eslint-plugin": "^5.60.0",
66+
"@typescript-eslint/parser": "^5.60.0",
67+
"eslint": "^8.43.0",
7268
"eslint-plugin-react-hooks": "^4.6.0",
73-
"jsdom": "^22.0.0",
69+
"jsdom": "^22.1.0",
7470
"microbundle": "^0.15.1",
7571
"prettier": "2.8.8",
7672
"prettier-plugin-organize-imports": "^3.2.2",
7773
"react": "^17.0.2",
7874
"react-dom": "^17.0.2",
79-
"typescript": "^5.0.4",
80-
"vitest": "^0.30.1"
75+
"typescript": "^5.1.3",
76+
"vitest": "^0.32.2"
8177
}
8278
}

src/index.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { useSyncExternalStore } from "use-sync-external-store/shim";
44
// For server-side rendering / react-native
55
const useIsoLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
66

7+
type AnyRecord = Record<string, unknown>;
8+
79
export type ValidatorResult<ErrorMessage = string> =
810
| ErrorMessage
911
| void
@@ -25,7 +27,7 @@ export type FieldState<Value, ErrorMessage = string> = {
2527
error: ErrorMessage | undefined;
2628
};
2729

28-
export type FormConfig<Values extends Record<string, unknown>, ErrorMessage = string> = {
30+
export type FormConfig<Values extends AnyRecord, ErrorMessage = string> = {
2931
[N in keyof Values]: {
3032
initialValue: Values[N] | (() => Values[N]);
3133
strategy?: Strategy;
@@ -45,7 +47,7 @@ export type FormConfig<Values extends Record<string, unknown>, ErrorMessage = st
4547
};
4648
};
4749

48-
export type Form<Values extends Record<string, unknown>, ErrorMessage = string> = {
50+
export type Form<Values extends AnyRecord, ErrorMessage = string> = {
4951
formStatus: FormStatus;
5052

5153
Field: (<N extends keyof Values>(props: {
@@ -141,14 +143,14 @@ export const combineValidators =
141143
}
142144
};
143145

144-
export const hasDefinedKeys = <T extends Record<string, unknown>, K extends keyof T = keyof T>(
146+
export const hasDefinedKeys = <T extends AnyRecord, K extends keyof T = keyof T>(
145147
object: T,
146148
keys: K[],
147149
): object is T & {
148150
[K1 in K]-?: Exclude<T[K1], undefined>;
149151
} => keys.every((key) => typeof object[key] !== "undefined");
150152

151-
export const useForm = <Values extends Record<string, unknown>, ErrorMessage = string>(
153+
export const useForm = <Values extends AnyRecord, ErrorMessage = string>(
152154
fields: FormConfig<Values, ErrorMessage>,
153155
): Form<Values, ErrorMessage> => {
154156
type Contract = Form<Values, ErrorMessage>;

vitest-setup.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
1-
// jest-dom adds custom jest matchers for asserting on DOM nodes
2-
// learn more: https://github.com/testing-library/jest-dom
3-
import matchers from "@testing-library/jest-dom/matchers";
41
import { cleanup } from "@testing-library/react";
5-
import { afterEach, expect } from "vitest";
2+
import { afterEach } from "vitest";
63

74
// https://testing-library.com/docs/react-testing-library/api/#cleanup
85
afterEach(cleanup);
96

107
// https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#configuring-your-testing-environment
118
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
12-
13-
expect.extend(matchers);

website/package.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,26 @@
88
},
99
"dependencies": {
1010
"@chakra-ui/icons": "^2.0.19",
11-
"@chakra-ui/react": "^2.6.0",
12-
"@chakra-ui/system": "^2.5.6",
13-
"@emotion/react": "^11.10.8",
14-
"@emotion/styled": "^11.10.8",
11+
"@chakra-ui/react": "^2.7.1",
12+
"@chakra-ui/system": "^2.5.8",
13+
"@emotion/react": "^11.11.1",
14+
"@emotion/styled": "^11.11.0",
15+
"@swan-io/chicane": "^1.4.0",
1516
"card-validator": "^8.1.1",
16-
"framer-motion": "^10.12.7",
17+
"framer-motion": "^10.12.16",
1718
"react": "^18.2.0",
1819
"react-dom": "^18.2.0",
1920
"react-ux-form": "file:../",
2021
"rifm": "^0.12.1",
21-
"validator": "^13.9.0",
22-
"wouter": "^2.10.1"
22+
"ts-pattern": "^5.0.1",
23+
"validator": "^13.9.0"
2324
},
2425
"devDependencies": {
25-
"@types/react": "^18.2.0",
26-
"@types/react-dom": "^18.2.1",
27-
"@types/validator": "^13.7.15",
28-
"@vitejs/plugin-react-swc": "^3.3.0",
29-
"typescript": "^5.0.4",
30-
"vite": "^4.3.4"
26+
"@types/react": "^18.2.13",
27+
"@types/react-dom": "^18.2.6",
28+
"@types/validator": "^13.7.17",
29+
"@vitejs/plugin-react-swc": "^3.3.2",
30+
"typescript": "^5.1.3",
31+
"vite": "^4.3.9"
3132
}
3233
}

website/src/App.tsx

Lines changed: 69 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { HamburgerIcon } from "@chakra-ui/icons";
44
import { Flex, Text, VStack } from "@chakra-ui/layout";
55
import { useBreakpointValue } from "@chakra-ui/media-query";
66
import * as React from "react";
7-
import { Route, Router, useLocation } from "wouter";
7+
import { P, match } from "ts-pattern";
88
import { Link } from "./components/Link";
9+
import { Page } from "./components/Page";
910
import { AsyncSubmissionForm } from "./forms/AsyncSubmissionForm";
1011
import { AsyncValidationForm } from "./forms/AsyncValidationForm";
1112
import { BasicForm } from "./forms/BasicForm";
@@ -15,81 +16,84 @@ import { FieldsListenerForm } from "./forms/FieldsListenerForm";
1516
import { IBANForm } from "./forms/IBANForm";
1617
import { InputMaskingForm } from "./forms/InputMaskingForm";
1718
import { StrategiesForm } from "./forms/StrategiesForm";
19+
import { Router, routes } from "./utils/router";
1820

1921
export const App = () => {
20-
const [path] = useLocation();
22+
const route = Router.useRoute(routes);
2123
const isDesktop = !useBreakpointValue({ base: true, md: false });
2224
const { isOpen, onToggle, onClose } = useDisclosure();
2325

24-
React.useEffect(onClose, [path]);
26+
const pathKey = route?.key.split("-")[0];
27+
React.useEffect(onClose, [pathKey]);
2528

2629
return (
27-
<Router base="/react-ux-form">
28-
<Flex flex={1} flexDirection={{ base: "column-reverse", md: "row" }}>
29-
<Button
30-
borderRadius={0}
31-
display={{ base: "flex", md: "none" }}
30+
<Flex flex={1} flexDirection={{ base: "column-reverse", md: "row" }}>
31+
<Button
32+
borderRadius={0}
33+
display={{ base: "flex", md: "none" }}
34+
flexShrink={0}
35+
fontSize={14}
36+
height="48px"
37+
onClick={onToggle}
38+
>
39+
<HamburgerIcon height={5} width={5} marginRight={2} />
40+
MENU
41+
</Button>
42+
43+
{(isDesktop || isOpen) && (
44+
<Flex
45+
backgroundColor="gray.50"
46+
flexDirection="column"
47+
overflowY="scroll"
48+
paddingTop={6}
49+
paddingBottom={6}
50+
paddingLeft={4}
51+
paddingRight={4}
52+
borderColor="gray.100"
53+
borderStyle="solid"
54+
borderTopWidth={{ base: 1, md: 0 }}
55+
borderRightWidth={{ base: 0, md: 1 }}
3256
flexShrink={0}
33-
fontSize={14}
34-
height="48px"
35-
onClick={onToggle}
57+
height={{ base: "40%", md: "auto" }}
58+
width={{ base: "auto", md: 320 }}
3659
>
37-
<HamburgerIcon height={5} width={5} marginRight={2} />
38-
MENU
39-
</Button>
40-
41-
{(isDesktop || isOpen) && (
42-
<Flex
43-
backgroundColor="gray.50"
44-
flexDirection="column"
45-
overflowY="scroll"
46-
paddingTop={6}
47-
paddingBottom={6}
48-
paddingLeft={4}
49-
paddingRight={4}
50-
borderColor="gray.100"
51-
borderStyle="solid"
52-
borderTopWidth={{ base: 1, md: 0 }}
53-
borderRightWidth={{ base: 0, md: 1 }}
54-
flexShrink={0}
55-
height={{ base: "40%", md: "auto" }}
56-
width={{ base: "auto", md: 320 }}
60+
<Text
61+
color="gray.500"
62+
fontSize={12}
63+
fontWeight={600}
64+
marginLeft={3}
65+
marginBottom={3}
66+
textTransform="uppercase"
5767
>
58-
<Text
59-
color="gray.500"
60-
fontSize={12}
61-
fontWeight={600}
62-
marginLeft={3}
63-
marginBottom={3}
64-
textTransform="uppercase"
65-
>
66-
Examples
67-
</Text>
68+
Examples
69+
</Text>
6870

69-
<VStack align="initial" spacing={1}>
70-
<Link href="/">Basic</Link>
71-
<Link href="/strategies">Validation strategies</Link>
72-
<Link href="/fields-listener">Fields listener</Link>
73-
<Link href="/async-validation">Async validation</Link>
74-
<Link href="/async-submission">Async submission</Link>
75-
<Link href="/checkboxes">Checkboxes</Link>
76-
<Link href="/iban">IBAN</Link>
77-
<Link href="/credit-card">Credit card</Link>
78-
<Link href="/input-masking">Input masking</Link>
79-
</VStack>
80-
</Flex>
81-
)}
71+
<VStack align="initial" spacing={1}>
72+
<Link to={Router.Home()}>Basic</Link>
73+
<Link to={Router.Strategies()}>Validation strategies</Link>
74+
<Link to={Router.FieldsListener()}>Fields listener</Link>
75+
<Link to={Router.AsyncValidation()}>Async validation</Link>
76+
<Link to={Router.AsyncSubmission()}>Async submission</Link>
77+
<Link to={Router.Checkboxes()}>Checkboxes</Link>
78+
<Link to={Router.IBAN()}>IBAN</Link>
79+
<Link to={Router.CreditCard()}>Credit card</Link>
80+
<Link to={Router.InputMasking()}>Input masking</Link>
81+
</VStack>
82+
</Flex>
83+
)}
8284

83-
<Route path="/" component={BasicForm} />
84-
<Route path="/strategies" component={StrategiesForm} />
85-
<Route path="/fields-listener" component={FieldsListenerForm} />
86-
<Route path="/async-validation" component={AsyncValidationForm} />
87-
<Route path="/async-submission" component={AsyncSubmissionForm} />
88-
<Route path="/checkboxes" component={CheckboxesForm} />
89-
<Route path="/iban" component={IBANForm} />
90-
<Route path="/credit-card" component={CreditCardForm} />
91-
<Route path="/input-masking" component={InputMaskingForm} />
92-
</Flex>
93-
</Router>
85+
{match(route)
86+
.with({ name: "Home" }, () => <BasicForm />)
87+
.with({ name: "Strategies" }, () => <StrategiesForm />)
88+
.with({ name: "FieldsListener" }, () => <FieldsListenerForm />)
89+
.with({ name: "AsyncValidation" }, () => <AsyncValidationForm />)
90+
.with({ name: "AsyncSubmission" }, () => <AsyncSubmissionForm />)
91+
.with({ name: "Checkboxes" }, () => <CheckboxesForm />)
92+
.with({ name: "IBAN" }, () => <IBANForm />)
93+
.with({ name: "CreditCard" }, () => <CreditCardForm />)
94+
.with({ name: "InputMasking" }, () => <InputMaskingForm />)
95+
.with(P.nullish, () => <Page title="Not found" />)
96+
.exhaustive()}
97+
</Flex>
9498
);
9599
};

website/src/components/Link.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { useTheme } from "@chakra-ui/system";
2+
import { useLinkProps } from "@swan-io/chicane";
23
import * as React from "react";
3-
import { Link as WouterLink, LinkProps, useRoute } from "wouter";
44

5-
export const Link = (props: LinkProps & { href: string }) => {
5+
export const Link = ({ to, children }: { to: string; children: string }) => {
66
const { colors } = useTheme();
7-
const [active] = useRoute(props.href);
7+
const { active, onClick } = useLinkProps({ href: to });
88

99
return (
10-
<WouterLink
11-
{...props}
10+
<a
11+
href={to}
12+
onClick={onClick}
1213
style={{
1314
borderRadius: 4,
1415
color: colors.gray[600],
@@ -24,6 +25,8 @@ export const Link = (props: LinkProps & { href: string }) => {
2425
color: colors.green[700],
2526
}),
2627
}}
27-
/>
28+
>
29+
{children}
30+
</a>
2831
);
2932
};

website/src/components/Page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const Page = ({
66
title,
77
description,
88
}: {
9-
children: React.ReactNode;
9+
children?: React.ReactNode;
1010
title: string;
1111
description?: React.ReactNode;
1212
}) => (

website/src/utils/router.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { createRouter } from "@swan-io/chicane";
2+
3+
const routesObject = {
4+
Home: "/",
5+
Strategies: "/strategies",
6+
FieldsListener: "/fields-listener",
7+
AsyncValidation: "/async-validation",
8+
AsyncSubmission: "/async-submission",
9+
Checkboxes: "/checkboxes",
10+
IBAN: "/iban",
11+
CreditCard: "/credit-card",
12+
InputMasking: "/input-masking",
13+
} as const;
14+
15+
export const routes = Object.keys(routesObject) as (keyof typeof routesObject)[];
16+
17+
export const Router = createRouter(routesObject, {
18+
basePath: "/react-ux-form",
19+
});

0 commit comments

Comments
 (0)