Skip to content

Commit 2db29ab

Browse files
committed
feat: add form renderer component
1 parent 30dbffa commit 2db29ab

23 files changed

+724
-1
lines changed

docs/ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ This roadmap is our plan for building a complete front-end framework. Each item
3636

3737
[ ] **Choice / Toggle:** Things for making selections or turning stuff on/off.
3838

39-
[ ] **Form Renderer:** Tool to make forms show up the way we want.
39+
[x] **Form Renderer:** Tool to make forms show up the way we want.
4040

4141
[x] **Form Field:** Boxes where people type stuff or pick options.
4242

package-lock.json

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
extends: "@react-ck/babel-config",
3+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module "*.module.scss" {
2+
const content: Record<string, string>;
3+
export default content;
4+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { type FormValues, type FormFieldMap, type FormValidators } from "../src";
2+
import { REGEX, regexValidation } from "./utils";
3+
4+
export const fields = {
5+
email: {
6+
type: "input",
7+
props: {
8+
label: "Email Address",
9+
placeholder: "john-doe@aaa.com",
10+
description: "Your work email address",
11+
},
12+
},
13+
password: {
14+
type: "input",
15+
props: {
16+
type: "password",
17+
label: "Password",
18+
placeholder: "Strong password",
19+
description: REGEX.password.description,
20+
},
21+
},
22+
passwordRepeat: {
23+
type: "input",
24+
props: {
25+
type: "password",
26+
label: "Repeat Password",
27+
placeholder: "Repeat password",
28+
},
29+
},
30+
} satisfies FormFieldMap;
31+
32+
export type Values = FormValues<typeof fields>;
33+
34+
export const validators = {
35+
email: (values) => {
36+
if (!values.email?.toString().trim().length) return "Required field";
37+
return regexValidation(String(values.email), "email");
38+
},
39+
password: (values) => {
40+
if (!values.password?.toString().trim().length) return "Required field";
41+
return regexValidation(String(values.password), "password");
42+
},
43+
passwordRepeat: (values) => {
44+
if (!values.passwordRepeat?.toString().trim().length) return "Required field";
45+
if (values.password !== values.passwordRepeat) return "Passwords must be equal";
46+
return regexValidation(String(values.passwordRepeat), "password");
47+
},
48+
} satisfies FormValidators<typeof fields>;
49+
50+
export const values = {
51+
email: "",
52+
password: "",
53+
passwordRepeat: "",
54+
} satisfies FormValues<typeof fields>;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export const REGEX = {
2+
email: {
3+
exp: /[\d%+._a-z-]+@[\d.a-z-]+.[a-z]{2,}$/,
4+
description: "Insert a valid email",
5+
},
6+
password: {
7+
exp: /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/,
8+
description:
9+
"Must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters",
10+
},
11+
} satisfies Record<
12+
string,
13+
{
14+
exp: RegExp;
15+
description: string;
16+
}
17+
>;
18+
19+
export const regexValidation = (value: string, key: keyof typeof REGEX): string | undefined => {
20+
if (REGEX[key].exp.exec(value) === null) return REGEX[key].description;
21+
return undefined;
22+
};

packages/components/form/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Hack for module resolution of non built packages
2+
export * from "./src/index";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { config as default } from "@react-ck/jest-config";
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "@react-ck/form",
3+
"private": false,
4+
"version": "1.0.0",
5+
"main": "dist/index.js",
6+
"types": "dist/index.d.ts",
7+
"files": [
8+
"/dist"
9+
],
10+
"homepage": "https://github.com/abelflopes/react-ck/tree/master/packages/components/form#readme",
11+
"repository": {
12+
"type": "git",
13+
"url": "git+https://github.com/abelflopes/react-ck.git"
14+
},
15+
"scripts": {
16+
"build": "NODE_ENV=production webpack",
17+
"lint:typescript": "tsc --noEmit",
18+
"test": "npx -y npm-run-all -s test:*",
19+
"test:unit": "jest --testPathPattern=\".unit.*\"",
20+
"test:snapshot": "jest --testPathPattern=\".snapshot.*\"",
21+
"test:snapshot:update": "jest --testPathPattern=\".snapshot.*\" -u"
22+
},
23+
"devDependencies": {
24+
"@react-ck/babel-config": "^1.0.0",
25+
"@react-ck/jest-config": "^1.0.0",
26+
"@react-ck/typescript-config": "^1.0.0",
27+
"@react-ck/webpack-config": "^1.0.0",
28+
"@types/react": "^18.2.33"
29+
},
30+
"peerDependencies": {
31+
"react": "^18.2.0"
32+
},
33+
"dependencies": {
34+
"@react-ck/input": "^1.0.0",
35+
"@react-ck/scss-utils": "^1.1.2",
36+
"@react-ck/select": "^1.0.0",
37+
"@react-ck/textarea": "^1.0.0",
38+
"@react-ck/theme": "^1.5.0",
39+
"classnames": "^2.3.2"
40+
}
41+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Snapshot Form renders correctly 1`] = `
4+
<div
5+
className="root"
6+
>
7+
<div
8+
className="root default"
9+
>
10+
<div
11+
className="content"
12+
>
13+
<input
14+
className="root"
15+
onChange={[Function]}
16+
placeholder="Email Address"
17+
value=""
18+
/>
19+
</div>
20+
</div>
21+
<div
22+
className="root default"
23+
>
24+
<div
25+
className="content"
26+
>
27+
<input
28+
className="root"
29+
onChange={[Function]}
30+
placeholder="Password"
31+
type="password"
32+
value=""
33+
/>
34+
</div>
35+
</div>
36+
</div>
37+
`;

0 commit comments

Comments
 (0)