@bouko/react 2.7.0 → 2.7.2

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.
Files changed (38) hide show
  1. package/dist/assets/icons/check copy.svg +6 -0
  2. package/dist/assets/icons/check-circle copy.svg +6 -0
  3. package/dist/assets/icons/chevron copy.svg +6 -0
  4. package/dist/assets/icons/paperclip copy.svg +6 -0
  5. package/dist/assets/icons/spinner copy.svg +6 -0
  6. package/dist/assets/icons/x-circle copy.svg +6 -0
  7. package/dist/components/animate/index.d.ts +1 -0
  8. package/dist/components/badge.d.ts +5 -0
  9. package/dist/components/badge.js +4 -0
  10. package/dist/components/button/ghost.d.ts +7 -0
  11. package/dist/components/button/ghost.js +8 -0
  12. package/dist/components/button/load.d.ts +10 -0
  13. package/dist/components/button/load.js +35 -0
  14. package/dist/components/button.d.ts +10 -0
  15. package/dist/components/button.js +22 -0
  16. package/dist/components/flex.d.ts +16 -0
  17. package/dist/components/flex.js +8 -0
  18. package/dist/components/form/builder.d.ts +24 -0
  19. package/dist/components/form/builder.js +61 -0
  20. package/dist/components/form/fields.d.ts +16 -0
  21. package/dist/components/form/fields.js +21 -0
  22. package/dist/components/form/footer.d.ts +9 -0
  23. package/dist/components/form/footer.js +17 -0
  24. package/dist/components/form/index.d.ts +3 -0
  25. package/dist/components/form/index.js +3 -0
  26. package/dist/components/form/loaders.d.ts +3 -0
  27. package/dist/components/form/loaders.js +11 -0
  28. package/dist/components/form/test-next.d.ts +1 -0
  29. package/dist/components/form/test-next.js +6 -0
  30. package/dist/components/layout/heading.d.ts +31 -0
  31. package/dist/components/layout/heading.js +22 -0
  32. package/dist/components/search/index.d.ts +6 -0
  33. package/dist/components/search/index.js +12 -0
  34. package/dist/components/search-bar.d.ts +1 -1
  35. package/dist/components/search-bar.js +1 -1
  36. package/dist/hooks/color.d.ts +7 -0
  37. package/dist/hooks/color.js +8 -0
  38. package/package.json +1 -1
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="1em" height="1em">
2
+ <path
3
+ d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"
4
+ fill="currentColor"
5
+ />
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em">
2
+ <path
3
+ d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-111 111-47-47c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l64 64c9.4 9.4 24.6 9.4 33.9 0L369 209z"
4
+ fill="currentColor"
5
+ />
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em">
2
+ <path
3
+ d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"
4
+ fill="currentColor"
5
+ />
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="1em" height="1em">
2
+ <path
3
+ d="M364.2 83.8c-24.4-24.4-64-24.4-88.4 0l-184 184c-42.1 42.1-42.1 110.3 0 152.4s110.3 42.1 152.4 0l152-152c10.9-10.9 28.7-10.9 39.6 0s10.9 28.7 0 39.6l-152 152c-64 64-167.6 64-231.6 0s-64-167.6 0-231.6l184-184c46.3-46.3 121.3-46.3 167.6 0s46.3 121.3 0 167.6l-176 176c-28.6 28.6-75 28.6-103.6 0s-28.6-75 0-103.6l144-144c10.9-10.9 28.7-10.9 39.6 0s10.9 28.7 0 39.6l-144 144c-6.7 6.7-6.7 17.7 0 24.4s17.7 6.7 24.4 0l176-176c24.4-24.4 24.4-64 0-88.4z"
4
+ fill="currentColor"
5
+ />
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em">
2
+ <path
3
+ d="M304 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zm0 416a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM48 304a48 48 0 1 0 0-96 48 48 0 1 0 0 96zm464-48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM142.9 437A48 48 0 1 0 75 369.1 48 48 0 1 0 142.9 437zm0-294.2A48 48 0 1 0 75 75a48 48 0 1 0 67.9 67.9zM369.1 437A48 48 0 1 0 437 369.1 48 48 0 1 0 369.1 437z"
4
+ fill="currentColor"
5
+ />
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em">
2
+ <path
3
+ d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"
4
+ fill="currentColor"
5
+ />
6
+ </svg>
@@ -6,6 +6,7 @@ export type Props = {
6
6
  duration?: number;
7
7
  style?: string;
8
8
  layout?: boolean;
9
+ onClick?: () => void;
9
10
  children?: ReactNode;
10
11
  };
11
12
  export declare function Animation({ variants, style, direction, interval, duration, ...props }: Props): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import type { ReactNode } from "react";
2
+ export default function Badge({ style, children }: {
3
+ style?: string;
4
+ children: ReactNode;
5
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export default function Badge({ style, children }) {
3
+ return (_jsx("span", { className: "w-min px-3 py-1 bg-accent/20 border border-accent-dark rounded-full text-xs text-accent-dark font-semibold", children: children }));
4
+ }
@@ -0,0 +1,7 @@
1
+ import type { Component, Clickable } from "../../core/types";
2
+ export default function GhostButton({ style, action, children }: Component & Clickable): import("react/jsx-runtime").JSX.Element | null;
3
+ /**
4
+ * Problems:
5
+ *
6
+ * - Perfect `Button`
7
+ **/
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Button } from "./normal";
3
+ import { cn } from "@bouko/style";
4
+ export default function GhostButton({ style, action, children }) {
5
+ if (!children)
6
+ return null;
7
+ return (_jsx(Button, { variant: "ghost", style: cn("p-0 hover:brightness-110", style), onClick: action, children: children }));
8
+ }
@@ -0,0 +1,10 @@
1
+ import type { ReactNode } from "react";
2
+ export type ButtonProps = {
3
+ variant?: "primary" | "outline" | "ghost";
4
+ size?: "xs" | "sm" | "md" | "lg";
5
+ style?: string;
6
+ onClick?: () => void;
7
+ disabled?: boolean;
8
+ children: ReactNode;
9
+ };
10
+ export default function LoadButton({ size, variant, style, onClick, children, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,35 @@
1
+ "use state";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { cn, tv } from "@bouko/style";
5
+ import CheckCircle from "../../assets/icons/check-circle.svg";
6
+ import Spinner from "../../assets/icons/spinner.svg";
7
+ export default function LoadButton({ size, variant, style, onClick, children, ...props }) {
8
+ const [isLoading, setLoading] = useState(false);
9
+ const submit = async () => {
10
+ setLoading(true);
11
+ try {
12
+ await onClick?.();
13
+ }
14
+ catch { }
15
+ setLoading(false);
16
+ };
17
+ return (_jsxs("button", { className: cn(styles({ variant, size }), style), onClick: submit, ...props, children: [isLoading ? _jsx(Spinner, { className: "animate-spin" }) : _jsx(CheckCircle, {}), children] }));
18
+ }
19
+ const styles = tv({
20
+ 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",
21
+ defaultVariants: { size: "md" },
22
+ variants: {
23
+ variant: {
24
+ primary: "bg-primary hover:bg-primary-dark border-primary-dark",
25
+ outline: "!bg-transparent border-accent hover:border-accent-dark text-primary",
26
+ ghost: "!bg-transparent border-transparent text-accent hover:text-accent-dark"
27
+ },
28
+ size: {
29
+ xs: "px-3 py-1 text-xs",
30
+ sm: "px-4 py-2 text-xs sm:text-sm",
31
+ md: "px-4 py-2",
32
+ lg: "px-5 py-3 text-lg"
33
+ }
34
+ }
35
+ });
@@ -0,0 +1,10 @@
1
+ import type { ReactNode } from "react";
2
+ export type ButtonProps = {
3
+ variant?: "primary" | "outline" | "ghost";
4
+ size?: "xs" | "sm" | "md" | "lg";
5
+ style?: string;
6
+ onClick?: () => void;
7
+ disabled?: boolean;
8
+ children: ReactNode;
9
+ };
10
+ export declare function Button({ size, variant, style, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn, tv } from "@bouko/style";
3
+ export function Button({ size, variant, style, ...props }) {
4
+ return (_jsx("button", { className: cn(styles({ variant, size }), style), ...props }));
5
+ }
6
+ const styles = tv({
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
+ defaultVariants: { size: "md" },
9
+ variants: {
10
+ variant: {
11
+ primary: "bg-primary hover:bg-primary-dark border-primary-dark",
12
+ outline: "!bg-transparent border-accent hover:border-accent-dark text-primary",
13
+ ghost: "!bg-transparent border-transparent text-accent hover:text-accent-dark"
14
+ },
15
+ size: {
16
+ xs: "px-3 py-1 text-xs",
17
+ sm: "px-4 py-2 text-xs sm:text-sm",
18
+ md: "px-4 py-2",
19
+ lg: "px-5 py-3 text-lg"
20
+ }
21
+ }
22
+ });
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from "react";
2
+ type Props = Position & {
3
+ style?: string;
4
+ children: ReactNode;
5
+ };
6
+ type Position = {
7
+ center?: boolean;
8
+ centerX?: boolean;
9
+ centerY?: boolean;
10
+ };
11
+ export declare function ColumnBox({ style, center, centerX, centerY, children }: Props): import("react/jsx-runtime").JSX.Element;
12
+ export declare function RowBox({ style, children }: {
13
+ style?: string;
14
+ children: ReactNode;
15
+ }): import("react/jsx-runtime").JSX.Element;
16
+ export {};
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "@bouko/style";
3
+ export function ColumnBox({ style, center, centerX, centerY, children }) {
4
+ return (_jsx("div", { className: cn("flex flex-col", center && "items-center justify-center", centerX && "items-center", centerY && "justify-center", style), children: children }));
5
+ }
6
+ export function RowBox({ style, children }) {
7
+ return (_jsx("div", { className: cn("flex", style), children: children }));
8
+ }
@@ -0,0 +1,24 @@
1
+ import { FormBuilderField } from "./types";
2
+ type Props<T> = {
3
+ styles?: {
4
+ container?: string;
5
+ submit?: string;
6
+ cancel?: string;
7
+ };
8
+ id?: string;
9
+ button?: string;
10
+ fields: FormBuilderField<T>;
11
+ validator?: (x: Partial<T>) => ({
12
+ success: boolean;
13
+ });
14
+ sound?: string;
15
+ cancel?: boolean;
16
+ submit: (data: T, clear?: () => void) => Promise<void | never>;
17
+ };
18
+ type Item = {
19
+ id: string;
20
+ initial?: string;
21
+ };
22
+ export declare function mapIdToInitial<T>(arrays: Item[][]): Partial<T>;
23
+ export default function FormBuilder<T>({ fields, button, styles, submit, cancel }: Props<T>): import("react/jsx-runtime").JSX.Element;
24
+ export {};
@@ -0,0 +1,61 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { useForm } from "./functions";
5
+ import { cn } from "@bouko/style";
6
+ import { RowBox } from "../layout/flex";
7
+ import Input from "../input";
8
+ import TextArea from "../textarea";
9
+ import Select from "../select";
10
+ import MultipleChoice from "../multiple-choice";
11
+ import Attachment from "../attachment";
12
+ import { Button } from "../button";
13
+ import CheckCircle from "../../assets/icons/check-circle.svg";
14
+ import XCircle from "../../assets/icons/x-circle.svg";
15
+ import Spinner from "../../assets/icons/spinner.svg";
16
+ export function mapIdToInitial(arrays) {
17
+ const result = {};
18
+ for (const inner of arrays) {
19
+ for (const obj of inner) {
20
+ if ("initial" in obj && obj["initial"]) {
21
+ result[obj.id] = obj.initial;
22
+ }
23
+ }
24
+ }
25
+ return result;
26
+ }
27
+ export default function FormBuilder({ fields, button, styles, submit, cancel = false }) {
28
+ const initialShi = mapIdToInitial(fields);
29
+ const { data, setField, clear } = useForm(initialShi);
30
+ const [isLoading, setLoading] = useState(false);
31
+ const requiredFields = fields.flatMap(arr => arr.filter(item => item.required !== false));
32
+ const isValid = requiredFields.filter(x => {
33
+ const val = data[x.id];
34
+ return !val || val === "";
35
+ }).length === 0; // validator(data).success;
36
+ // const play = useSound(sound);
37
+ const handleSubmit = async () => {
38
+ setLoading(true);
39
+ try {
40
+ await submit(data, clear);
41
+ }
42
+ catch (err) {
43
+ let msg = err.message;
44
+ if (msg !== "NEXT_REDIRECT")
45
+ alert(msg);
46
+ }
47
+ setLoading(false);
48
+ };
49
+ return (_jsxs("div", { className: cn("flex flex-col w-full gap-4", styles?.container), children: [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 }) => {
50
+ if (element === "input")
51
+ 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));
52
+ else if (element === "select")
53
+ return (_jsx(Select, { id: id, label: label, placeholder: placeholder, options: options || [], value: data[id], update: x => setField(id, x), note: note, required: required }, id));
54
+ else if (element === "textarea")
55
+ return (_jsx(TextArea, { id: id, label: label, placeholder: placeholder, rows: rows, value: data[id], update: x => setField(id, x), note: note, required: required }, id));
56
+ else if (element === "multiple-choice")
57
+ return (_jsx(MultipleChoice, { id: id, label: label, options: options || [], value: data[id], update: x => setField(id, x), note: note, required: required }, id));
58
+ else if (element === "attachment")
59
+ return (_jsx(Attachment, { id: id, label: label, value: data[id], update: x => setField(id, x), note: note, required: required }, id));
60
+ }) }, i))), _jsxs(RowBox, { style: "items-center gap-2 mt-2 w-full", children: [_jsxs(Button, { style: cn("flex-1 text-sm", styles?.submit), onClick: handleSubmit, disabled: !isValid || isLoading, children: [_jsx("div", { className: cn(isLoading ? "hidden" : ""), children: _jsx(CheckCircle, {}) }), _jsx("div", { className: cn(isLoading ? "animate-spin" : "hidden"), children: _jsx(Spinner, {}) }), 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"] }))] })] }));
61
+ }
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+ import type { ZodTypeAny } from "zod";
2
+ type Props<T> = {
3
+ data: T;
4
+ validator: ZodTypeAny;
5
+ submit: (data: T) => void;
6
+ clear: () => void;
7
+ };
8
+ export default function FormFooter<T>({ data, validator, submit, clear }: Props<T>): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { Button } from "../button";
5
+ import { RowBox } from "../layout/flex";
6
+ import CheckCircle from "../../assets/icons/check-circle.svg";
7
+ import Spinner from "../../assets/icons/spinner.svg";
8
+ export default function FormFooter({ data, validator, submit, clear }) {
9
+ const isValid = validator.safeParse(data).success;
10
+ const [isLoading, setLoading] = useState(false);
11
+ const handleSubmit = async () => {
12
+ setLoading(true);
13
+ await submit(data);
14
+ setLoading(false);
15
+ };
16
+ return (_jsxs(RowBox, { style: "items-center gap-2 mt-2 w-full", children: [_jsxs(Button, { onClick: handleSubmit, disabled: !isValid || isLoading, children: [_jsx(Spinner, { className: isLoading ? "animate-spin" : "hidden" }), _jsx(CheckCircle, { className: isLoading ? "hidden" : "" }), "Create"] }), _jsx(Button, { variant: "ghost", onClick: clear, disabled: isLoading, children: "Cancel" })] }));
17
+ }
@@ -0,0 +1,3 @@
1
+ export { default as FormBuilder } from "./builder";
2
+ export * from "./functions";
3
+ export * from "./types";
@@ -0,0 +1,3 @@
1
+ export { default as FormBuilder } from "./builder";
2
+ export * from "./functions";
3
+ export * from "./types";
@@ -0,0 +1,3 @@
1
+ import { FormBuilderField } from "./fields";
2
+ export declare function loadJson<T>(name: string): Promise<T>;
3
+ export declare function loadForm<T>(name?: string): Promise<FormBuilderField<T>>;
@@ -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 found");
10
+ return loadJson(`forms/${name}`);
11
+ }
@@ -0,0 +1 @@
1
+ export declare function loadJson<T>(name: string): Promise<T>;
@@ -0,0 +1,6 @@
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
+ }
@@ -0,0 +1,31 @@
1
+ import { ReactNode } from "react";
2
+ type Props = {
3
+ badge?: string;
4
+ title: ReactNode;
5
+ subtitle?: ReactNode;
6
+ style?: Styles;
7
+ };
8
+ type Styles = {
9
+ container?: string;
10
+ badge?: string;
11
+ title?: string;
12
+ subtitle?: string;
13
+ };
14
+ /**
15
+ * Text heading with badge, title, subtitle.
16
+ *
17
+ * @param {string} badge - Little note above the title (optional).
18
+ * @param {ReactNode} title - Main title content.
19
+ * @param {ReactNode} subtitle - Subtitle content (optional).
20
+ * @param {Styles} style - Additional styles (optional).
21
+ **/
22
+ export default function Heading({ badge, title, subtitle, style }: Props): import("react/jsx-runtime").JSX.Element;
23
+ export {};
24
+ /**
25
+ * Problems
26
+ *
27
+ * - Perfect `mergeStyles`
28
+ * - Perfect `RowBox`
29
+ * - Perfect `ColumnBox`
30
+ * - Perfect `Badge`
31
+ **/
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { mergeStyles } from "@bouko/style";
3
+ import { RowBox, ColumnBox } from "./flex";
4
+ import { default as Badge } from "../text/badge";
5
+ /**
6
+ * Text heading with badge, title, subtitle.
7
+ *
8
+ * @param {string} badge - Little note above the title (optional).
9
+ * @param {ReactNode} title - Main title content.
10
+ * @param {ReactNode} subtitle - Subtitle content (optional).
11
+ * @param {Styles} style - Additional styles (optional).
12
+ **/
13
+ export default function Heading({ badge, title, subtitle, style = {} }) {
14
+ const styles = mergeStyles(base, style);
15
+ return (_jsxs(ColumnBox, { style: styles.container, children: [_jsx(Badge, { style: styles.badge, children: badge }), _jsx(RowBox, { style: styles.title, children: title }), _jsx(RowBox, { style: styles.subtitle, children: subtitle })] }));
16
+ }
17
+ const base = {
18
+ container: "items-center",
19
+ badge: "mb-2",
20
+ title: "items-center gap-2 text-xl sm:text-2xl 2xl:text-3xl font-bold text-primary",
21
+ subtitle: "items-center gap-2 max-sm:text-sm 2xl:text-lg text-primary-light dark:text-primary-dark"
22
+ };
@@ -0,0 +1,6 @@
1
+ type Props = {
2
+ placeholder?: string;
3
+ action: (query: string) => void;
4
+ };
5
+ export default function SearchBar({ placeholder, action }: Props): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { RowBox } from "../flex";
5
+ import { Button } from "../button";
6
+ export default function SearchBar({ placeholder, action }) {
7
+ const [query, search] = useState("");
8
+ return (_jsxs(RowBox, { style: styles.container, children: [_jsxs("div", { className: "relative grow", children: [_jsx("input", { className: "w-full outline-none lowercase text-lg placeholder-slate-500 tracking-wide", placeholder: placeholder, value: query, onChange: (e) => search(e.target.value), onKeyUp: (e) => e.key === "Enter" ? action(query) : null }), _jsx("div", { className: "absolute top-0 right-0 w-12 h-full bg-gradient-to-l from-slate-950" })] }), _jsx(Button, { size: "sm", style: "gap-[0.4rem] font-extrabold py-1 px-3 font-mono", onClick: () => action(query), children: "GO" })] }));
9
+ }
10
+ const styles = {
11
+ container: "items-center gap-6 w-xl pl-5 pr-4 py-3 bg-slate-950 border border-border rounded-md"
12
+ };
@@ -2,7 +2,7 @@ type Props<T> = {
2
2
  style?: Styles;
3
3
  placeholder?: string;
4
4
  trigger?: React.ReactNode;
5
- submit: (query: string) => Promise<T>;
5
+ submit: (query: string) => void;
6
6
  oops?: (x: string) => void;
7
7
  };
8
8
  type Styles = {
@@ -19,7 +19,7 @@ export function SearchBar({ style = {}, placeholder, trigger, submit, oops = con
19
19
  oops(err.message);
20
20
  }
21
21
  };
22
- return (_jsxs(RowBox, { style: styles.container, children: [_jsx(FadeBox, { style: "grow", gradient: "from-slate-950", children: _jsx(Input, { variant: "ghost", style: styles.input, placeholder: placeholder, value: query, update: setQuery, onEnter: search }) }), trigger && (_jsx(Button, { variant: "ghost", style: style?.trigger, action: search, children: trigger }))] }));
22
+ return (_jsxs(RowBox, { style: styles.container, children: [_jsx(FadeBox, { style: "grow", gradient: "from-slate-950", children: _jsx(Input, { variant: "ghost", style: styles.input, placeholder: placeholder, value: query, update: setQuery, onEnter: search }) }), trigger && (_jsx(Button, { variant: "ghost", style: style?.trigger, action: search, disabled: query === "", children: trigger }))] }));
23
23
  }
24
24
  const base = {
25
25
  container: "items-center gap-3 sm:gap-5 w-xl max-w-full pl-4 sm:pl-5 pr-2 sm:pr-4 py-2 sm:py-3 bg-slate-950 border border-border rounded-md",
@@ -0,0 +1,7 @@
1
+ type Props = {
2
+ variable: string;
3
+ color: string;
4
+ original: string;
5
+ };
6
+ export default function useColor({ variable, color, original }: Props): void;
7
+ export {};
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ export default function useColor({ variable, color, original }) {
4
+ useEffect(() => {
5
+ document.documentElement.style.setProperty(`--${variable}`, color);
6
+ return () => document.documentElement.style.setProperty(`--${variable}`, original);
7
+ }, []);
8
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
 
3
3
  "name": "@bouko/react",
4
- "version": "2.7.0",
4
+ "version": "2.7.2",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "license": "MIT",