@bouko/react 2.1.9 → 2.2.0
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/dist/components/button.js +1 -1
- package/dist/components/form/fields.d.ts +16 -0
- package/dist/components/form/fields.js +21 -0
- package/dist/components/form/functions.d.ts +4 -4
- package/dist/components/form/functions.js +1 -0
- package/dist/components/form/index.d.ts +14 -12
- package/dist/components/form/index.js +21 -23
- package/dist/components/form/loaders.d.ts +3 -0
- package/dist/components/form/loaders.js +11 -0
- package/dist/components/input.d.ts +2 -2
- package/dist/components/input.js +2 -3
- package/package.json +2 -2
|
@@ -4,7 +4,7 @@ export function Button({ size, variant, style, ...props }) {
|
|
|
4
4
|
return (_jsx("button", { className: cn(styles({ variant, size }), style), ...props }));
|
|
5
5
|
}
|
|
6
6
|
const styles = tv({
|
|
7
|
-
base: "flex items-center gap-2 bg-accent hover:bg-accent-dark border border-accent-dark rounded font-semibold text-background-light duration-200 cursor-pointer disabled:cursor-not-allowed",
|
|
7
|
+
base: "flex justify-center items-center gap-2 bg-accent hover:bg-accent-dark border border-accent-dark rounded font-semibold text-background-light duration-200 cursor-pointer disabled:cursor-not-allowed",
|
|
8
8
|
defaultVariants: { size: "md" },
|
|
9
9
|
variants: {
|
|
10
10
|
variant: {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Field, Option } from "./types";
|
|
2
|
+
export type FormBuilderField<T = unknown> = (Omit<Field<T>, "value" | "update"> & {
|
|
3
|
+
id: string;
|
|
4
|
+
element: string;
|
|
5
|
+
rows?: number;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
options?: Option[];
|
|
8
|
+
})[][];
|
|
9
|
+
type Props<T> = {
|
|
10
|
+
id?: string;
|
|
11
|
+
fields: FormBuilderField<T>;
|
|
12
|
+
data: T;
|
|
13
|
+
setField: (x: string, y: unknown) => void;
|
|
14
|
+
};
|
|
15
|
+
export default function Fields<T>({ fields, data, setField }: Props<T>): Promise<import("react/jsx-runtime").JSX.Element[]>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { RowBox } from "../layout/flex";
|
|
3
|
+
import Input from "../input";
|
|
4
|
+
import Select from "../select";
|
|
5
|
+
import TextArea from "../textarea";
|
|
6
|
+
import MultipleChoice from "../multiple-choice";
|
|
7
|
+
import Attachment from "../attachment";
|
|
8
|
+
export default async function Fields({ fields, data, setField }) {
|
|
9
|
+
return fields.map((row, i) => (_jsx(RowBox, { style: "w-full gap-5 overflow-hidden", children: row.map(({ element, id, rows, label, placeholder, disabled, options, required, note }) => {
|
|
10
|
+
if (element === "input")
|
|
11
|
+
return (_jsx(Input, { id: id, styles: { container: "flex-1" }, label: label, placeholder: placeholder, value: data[id], update: x => setField(id, x), disabled: disabled, note: note, required: required }, id));
|
|
12
|
+
else if (element === "select")
|
|
13
|
+
return (_jsx(Select, { id: id, label: label, placeholder: placeholder, options: options || [], value: data[id], update: x => setField(id, x), note: note, required: required }, id));
|
|
14
|
+
else if (element === "textarea")
|
|
15
|
+
return (_jsx(TextArea, { id: id, label: label, placeholder: placeholder, rows: rows, value: data[id], update: x => setField(id, x), note: note, required: required }, id));
|
|
16
|
+
else if (element === "multiple-choice")
|
|
17
|
+
return (_jsx(MultipleChoice, { id: id, label: label, options: options || [], value: data[id], update: x => setField(id, x), note: note, required: required }, id));
|
|
18
|
+
else if (element === "attachment")
|
|
19
|
+
return (_jsx(Attachment, { id: id, label: label, value: data[id], update: x => setField(id, x), note: note, required: required }, id));
|
|
20
|
+
}) }, i)));
|
|
21
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { SetState } from "./types";
|
|
2
|
-
export declare const useForm: <T>(init: T) => {
|
|
3
|
-
data: T
|
|
4
|
-
update: import("react").Dispatch<import("react").SetStateAction<T
|
|
2
|
+
export declare const useForm: <T>(init: Partial<T>) => {
|
|
3
|
+
data: Partial<T>;
|
|
4
|
+
update: import("react").Dispatch<import("react").SetStateAction<Partial<T>>>;
|
|
5
5
|
clear: () => void;
|
|
6
|
-
setField:
|
|
6
|
+
setField: (name: string, value: unknown) => void;
|
|
7
7
|
};
|
|
8
8
|
export declare const setField: <T>(update: SetState<T>, id: string, value: unknown) => void;
|
|
9
9
|
export declare const parseData: <T extends Record<string, unknown>>(data: T) => T;
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { Field, Option, FormSection } from "./types";
|
|
1
|
+
import { FormBuilderField } from "./fields";
|
|
3
2
|
export * from "./functions";
|
|
4
3
|
export * from "./types";
|
|
5
|
-
type
|
|
6
|
-
element: string;
|
|
7
|
-
rows?: number;
|
|
8
|
-
placeholder?: string;
|
|
9
|
-
options?: Option[];
|
|
10
|
-
})[][];
|
|
11
|
-
type Props<T> = FormSection<T> & {
|
|
4
|
+
type Props<T> = {
|
|
12
5
|
styles?: {
|
|
13
6
|
container?: string;
|
|
14
7
|
submit?: string;
|
|
15
8
|
cancel?: string;
|
|
16
9
|
};
|
|
17
10
|
id?: string;
|
|
11
|
+
button?: string;
|
|
18
12
|
fields: FormBuilderField<T>;
|
|
19
|
-
validator:
|
|
13
|
+
validator: (x: Partial<T>) => ({
|
|
14
|
+
success: boolean;
|
|
15
|
+
});
|
|
20
16
|
sound?: string;
|
|
21
17
|
cancel?: boolean;
|
|
22
|
-
|
|
18
|
+
submit: (data: Partial<T>) => Promise<void | never>;
|
|
23
19
|
};
|
|
24
20
|
export declare function useSound(filename?: string): import("use-sound/dist/types").PlayFunction | undefined;
|
|
25
|
-
export
|
|
21
|
+
export * from "./loaders";
|
|
22
|
+
type Item = {
|
|
23
|
+
id: string;
|
|
24
|
+
initial?: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function mapIdToInitial<T>(arrays: Item[][]): Partial<T>;
|
|
27
|
+
export declare function FormBuilder<T>({ fields, validator, button, styles, submit, cancel }: Props<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,41 +1,39 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useForm } from "./functions";
|
|
3
4
|
import { cn } from "@bouko/style";
|
|
5
|
+
import Fields from "./fields";
|
|
4
6
|
import CheckCircle from "../../assets/icons/check-circle.svg";
|
|
5
7
|
import XCircle from "../../assets/icons/x-circle.svg";
|
|
6
8
|
import { default as base } from "use-sound";
|
|
7
9
|
export * from "./functions";
|
|
8
10
|
export * from "./types";
|
|
9
11
|
import { RowBox } from "../layout/flex";
|
|
10
|
-
import Input from "../input";
|
|
11
|
-
import Select from "../select";
|
|
12
|
-
import TextArea from "../textarea";
|
|
13
|
-
import MultipleChoice from "../multiple-choice";
|
|
14
12
|
import { Button } from "../button";
|
|
15
|
-
import Attachment from "../attachment";
|
|
16
|
-
import { loadJson } from "./test-next";
|
|
17
13
|
export function useSound(filename) {
|
|
18
14
|
if (!filename)
|
|
19
15
|
return;
|
|
20
16
|
return base(filename)[0];
|
|
21
17
|
}
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
const
|
|
18
|
+
export * from "./loaders";
|
|
19
|
+
export function mapIdToInitial(arrays) {
|
|
20
|
+
const result = {};
|
|
21
|
+
for (const inner of arrays) {
|
|
22
|
+
for (const obj of inner) {
|
|
23
|
+
if ("initial" in obj && obj["initial"]) {
|
|
24
|
+
result[obj.id] = obj.initial;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
export function FormBuilder({ fields, validator, button, styles, submit, cancel = false }) {
|
|
31
|
+
const initialShi = mapIdToInitial(fields);
|
|
32
|
+
const { data, setField, clear } = useForm(initialShi);
|
|
33
|
+
const isValid = true; // validator(data).success;
|
|
34
|
+
// const play = useSound(sound);
|
|
26
35
|
const handleSubmit = async () => {
|
|
27
|
-
await
|
|
36
|
+
await submit(data);
|
|
28
37
|
};
|
|
29
|
-
return (_jsxs("div", { className: cn("flex flex-col w-full gap-4", styles?.container), children: [(
|
|
30
|
-
if (element === "input")
|
|
31
|
-
return (_jsx(Input, { id: id, styles: { container: "flex-1" }, label: label, placeholder: placeholder, value: data[id], update: x => setField(id, x), disabled: disabled, note: note, required: required }, id));
|
|
32
|
-
else if (element === "select")
|
|
33
|
-
return (_jsx(Select, { id: id, label: label, placeholder: placeholder, options: options || [], value: data[id], update: update, note: note, required: required }, id));
|
|
34
|
-
else if (element === "textarea")
|
|
35
|
-
return (_jsx(TextArea, { id: id, label: label, placeholder: placeholder, rows: rows, value: data[id], update: update, note: note, required: required }, id));
|
|
36
|
-
else if (element === "multiple-choice")
|
|
37
|
-
return (_jsx(MultipleChoice, { id: id, label: label, options: options || [], value: data[id], update: update, note: note, required: required }, id));
|
|
38
|
-
else if (element === "attachment")
|
|
39
|
-
return (_jsx(Attachment, { id: id, label: label, value: data[id], update: update, note: note, required: required }, id));
|
|
40
|
-
}) }, i))), _jsxs(RowBox, { style: "items-center gap-2 mt-2 w-full", children: [_jsxs(Button, { style: cn("text-sm", styles?.submit), onClick: handleSubmit, disabled: !isValid, children: [_jsx("div", { children: _jsx(CheckCircle, {}) }), "Submit"] }), cancel !== false && (_jsxs(Button, { style: cn("text-sm text-error hover:text-error-light", styles?.cancel), variant: "ghost", onClick: clear, children: [_jsx(XCircle, {}), "Cancel"] }))] })] }));
|
|
38
|
+
return (_jsxs("div", { className: cn("flex flex-col w-full gap-4", styles?.container), children: [_jsx(Fields, { fields: fields, data: data, setField: setField }), _jsxs(RowBox, { style: "items-center gap-2 mt-2 w-full", children: [_jsxs(Button, { style: cn("text-sm", styles?.submit), onClick: handleSubmit, disabled: !isValid, children: [_jsx("div", { children: _jsx(CheckCircle, {}) }), button || "Submit"] }), cancel !== false && (_jsxs(Button, { style: cn("text-sm text-error hover:text-error-light", styles?.cancel), variant: "ghost", onClick: clear, children: [_jsx(XCircle, {}), "Cancel"] }))] })] }));
|
|
41
39
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
export async function loadJson(name) {
|
|
4
|
+
const file = await fs.readFile(process.cwd() + "/assets/" + name + ".json", "utf-8");
|
|
5
|
+
return JSON.parse(file);
|
|
6
|
+
}
|
|
7
|
+
export async function loadForm(name) {
|
|
8
|
+
if (!name)
|
|
9
|
+
throw new Error("Form not foud");
|
|
10
|
+
return loadJson(`forms/${name}`);
|
|
11
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Field as FieldProps } from "./form/types";
|
|
2
2
|
type Props<T> = FieldProps<T> & {
|
|
3
3
|
placeholder?: string;
|
|
4
4
|
styles?: {
|
|
@@ -7,5 +7,5 @@ type Props<T> = FieldProps<T> & {
|
|
|
7
7
|
};
|
|
8
8
|
disabled?: boolean;
|
|
9
9
|
};
|
|
10
|
-
export default function Input
|
|
10
|
+
export default function Input({ id, styles, label, required, note, style, update, ...props }: Props<string>): import("react/jsx-runtime").JSX.Element;
|
|
11
11
|
export {};
|
package/dist/components/input.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import Field from "./field";
|
|
3
3
|
import { cn } from "@bouko/style";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return (_jsx(Field, { style: styles?.container, label: label, required: required, note: note, children: _jsx("input", { className: cn("px-3 py-2 bg-input border border-outline duration-200 focus:border-outline-light outline-none rounded text-sm disabled:brightness-90 disabled:cursor-not-allowed", styles?.input), onChange: ({ target: { value } }) => setField(update, id, value), ...props }) }));
|
|
4
|
+
export default function Input({ id, styles, label, required = true, note, style, update, ...props }) {
|
|
5
|
+
return (_jsx(Field, { style: styles?.container, label: label, required: required, note: note, children: _jsx("input", { className: cn("px-3 py-2 bg-input border border-outline duration-200 focus:border-outline-light outline-none rounded text-sm disabled:brightness-90 disabled:cursor-not-allowed", styles?.input), onChange: ({ target: { value } }) => update(value), ...props }) }));
|
|
7
6
|
}
|
package/package.json
CHANGED