@ask-ell/react 0.0.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/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # react
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build react` to build the library.
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@ask-ell/react",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ "./package.json": "./package.json",
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "react": "^19.2.0",
19
+ "tslib": "^2.3.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/react": "^19.2.2"
23
+ }
24
+ }
package/src/forms.ts ADDED
@@ -0,0 +1,92 @@
1
+ import { Dispatch, FormEvent, SetStateAction, useState } from "react";
2
+
3
+ export enum SubmitMode {
4
+ ON_TRIGGER,
5
+ AUTOMATIC
6
+ }
7
+
8
+ export type ErrorSetter<FormData> = (key: keyof FormData) => (errorMessage: string) => void;
9
+
10
+ export type OnSubmitCallbackParams<FormData> = {
11
+ formData: FormData;
12
+ appendError: ErrorSetter<FormData>;
13
+ };
14
+
15
+ export type OnSubmitCallback<FormData> = (params: OnSubmitCallbackParams<FormData>) => void;
16
+
17
+ export type UseFormParams<FormData> = {
18
+ defaultValue: FormData;
19
+ onSubmit: OnSubmitCallback<FormData>;
20
+ submitMode?: SubmitMode
21
+ };
22
+
23
+ type FormDataFieldUpdater<FormData> = <Key extends keyof FormData>(key: Key) => (value: FormData[Key]) => void;
24
+
25
+ type SubmitTrigger = () => void;
26
+
27
+ export interface ErrorsMap<FormData> extends Map<keyof FormData, string[]> { }
28
+
29
+ export type FormController<FormData> = {
30
+ formData: FormData;
31
+ errors: ErrorsMap<FormData>;
32
+ setFormData: Dispatch<SetStateAction<FormData>>;
33
+ updateFormData: FormDataFieldUpdater<FormData>;
34
+ submit: SubmitTrigger;
35
+ reset: () => void;
36
+ };
37
+
38
+ export function useFormController<FormData>({ defaultValue, onSubmit, submitMode }: UseFormParams<FormData>): FormController<FormData> {
39
+ const [formData, setFormData] = useState<FormData>(defaultValue);
40
+ const [errors, setErrors] = useState<ErrorsMap<FormData>>(new Map());
41
+
42
+ const appendError: ErrorSetter<FormData> = (key: keyof FormData) => (message: string): void => {
43
+ const existingErrors: string[] = errors.get(key) ?? [];
44
+ existingErrors.push(message);
45
+ errors.set(key, existingErrors);
46
+ setErrors(new Map(errors));
47
+ }
48
+
49
+ const prepareOnSubmit = (callback: () => void) => {
50
+ errors.clear()
51
+ setErrors(new Map(errors));
52
+ callback();
53
+ }
54
+
55
+ const updateFormData: FormDataFieldUpdater<FormData> = <Key extends keyof FormData>(key: Key) => (value: FormData[Key]) => {
56
+ setTimeout((): void => {
57
+ const newFormData: FormData = {
58
+ ...formData,
59
+ [key]: value
60
+ }
61
+ setFormData(() => newFormData);
62
+ if (submitMode === SubmitMode.AUTOMATIC) {
63
+ prepareOnSubmit(
64
+ (): void => onSubmit({ formData: newFormData, appendError })
65
+ );
66
+ }
67
+ });
68
+ };
69
+
70
+ const submit: SubmitTrigger = (): void => prepareOnSubmit(
71
+ (): void => onSubmit({ formData, appendError })
72
+ );
73
+
74
+ const reset = (): void => {
75
+ setFormData(defaultValue)
76
+ errors.clear();
77
+ }
78
+
79
+ return {
80
+ formData,
81
+ errors,
82
+ setFormData,
83
+ updateFormData,
84
+ submit,
85
+ reset
86
+ }
87
+ }
88
+
89
+ export const preventDefault = (callback: () => void) => (event: FormEvent): void => {
90
+ event.preventDefault();
91
+ callback();
92
+ };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './forms.js'
2
+ export * from './keyboard-events.js'
3
+ export * from './select-events.js'
@@ -0,0 +1,19 @@
1
+ import { ChangeEvent, KeyboardEvent } from 'react';
2
+
3
+
4
+ export const handleEnterKeyDown =
5
+ (callback: () => void) => (event: KeyboardEvent<HTMLInputElement>) => {
6
+ if (event.key === 'Enter') {
7
+ callback();
8
+ }
9
+ };
10
+
11
+ export const handleKeyboardEvent =
12
+ (callback: (fieldValue: string) => void) => <TargetType>(event: KeyboardEvent<TargetType>) => {
13
+ callback((event.target as any).value as string);
14
+ };
15
+
16
+ export const handleChangeEvent =
17
+ (callback: (fieldValue: string) => void) => <TargetType>(event: ChangeEvent<TargetType>) => {
18
+ callback((event.target as any).value as string);
19
+ };
@@ -0,0 +1,5 @@
1
+ export const handleSelectChange =
2
+ (callback: (data: string) => void) =>
3
+ <T>(event: T): void => {
4
+ callback((event as any).target.value);
5
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "files": [],
4
+ "include": [],
5
+ "references": [
6
+ {
7
+ "path": "./tsconfig.lib.json"
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "rootDir": "src",
6
+ "outDir": "dist",
7
+ "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
8
+ "emitDeclarationOnly": false,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "types": ["node"]
11
+ },
12
+ "include": ["src/**/*.ts"],
13
+ "references": []
14
+ }