@skalfa/skalfa-component 1.0.7 → 1.0.9

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 (107) hide show
  1. package/dist/accordion/Accordion.component.js +2 -3
  2. package/dist/breadcrumb/Breadcrumb.component.js +2 -3
  3. package/dist/button/Button.component.d.ts +2 -1
  4. package/dist/button/Button.component.js +2 -2
  5. package/dist/carousel/Carousel.component.js +2 -3
  6. package/dist/chip/Chip.component.js +2 -3
  7. package/dist/contexts-mock.d.ts +2 -0
  8. package/dist/contexts-mock.js +10 -0
  9. package/dist/input/Checkbox.component.js +2 -3
  10. package/dist/input/Input.component.d.ts +3 -2
  11. package/dist/input/Input.component.js +3 -3
  12. package/dist/input/InputCheckbox.component.js +1 -1
  13. package/dist/input/InputCurrency.component.d.ts +3 -2
  14. package/dist/input/InputCurrency.component.js +3 -3
  15. package/dist/input/InputDate.component.js +4 -5
  16. package/dist/input/InputDatetime.component.d.ts +3 -2
  17. package/dist/input/InputDatetime.component.js +3 -3
  18. package/dist/input/InputDocument.component.js +7 -8
  19. package/dist/input/InputImage.component.js +3 -4
  20. package/dist/input/InputNumber.component.js +3 -4
  21. package/dist/input/InputPassword.component.js +3 -3
  22. package/dist/input/InputRadio.component.js +1 -1
  23. package/dist/input/InputTime.component.js +3 -3
  24. package/dist/input/InputValues.component.js +3 -4
  25. package/dist/input/Select.component.js +6 -7
  26. package/dist/modal/FloatingPage.component.d.ts +3 -1
  27. package/dist/modal/FloatingPage.component.js +7 -3
  28. package/dist/modal/Modal.component.js +1 -2
  29. package/dist/modal/ModalConfirm.component.d.ts +2 -2
  30. package/dist/modal/ModalConfirm.component.js +14 -12
  31. package/dist/modal/Toast.component.js +1 -2
  32. package/dist/nav/Bottombar.component.d.ts +2 -2
  33. package/dist/nav/Bottombar.component.js +7 -8
  34. package/dist/nav/Footer.component.d.ts +2 -2
  35. package/dist/nav/Footer.component.js +6 -7
  36. package/dist/nav/Headbar.component.js +2 -3
  37. package/dist/nav/Navbar.component.d.ts +2 -2
  38. package/dist/nav/Navbar.component.js +3 -4
  39. package/dist/nav/Sidebar.component.d.ts +3 -7
  40. package/dist/nav/Sidebar.component.js +14 -17
  41. package/dist/supervision/FormSupervision.component.d.ts +4 -29
  42. package/dist/supervision/FormSupervision.component.js +84 -136
  43. package/dist/supervision/TableSupervision.component.d.ts +17 -26
  44. package/dist/supervision/TableSupervision.component.js +207 -193
  45. package/dist/table/ControlBar.component.js +15 -16
  46. package/dist/table/FilterComponent.js +4 -6
  47. package/dist/table/Pagination.component.js +2 -3
  48. package/dist/table/Table.component.js +3 -4
  49. package/dist/wrap/Swipe.component.js +2 -2
  50. package/package.json +18 -10
  51. package/src/accordion/Accordion.component.tsx +87 -0
  52. package/src/breadcrumb/Breadcrumb.component.tsx +79 -0
  53. package/src/button/Button.component.tsx +89 -0
  54. package/src/card/AlertCard.component.tsx +69 -0
  55. package/src/card/Card.component.tsx +25 -0
  56. package/src/card/DashboardCard.component.tsx +44 -0
  57. package/src/card/GalleryCard.component.tsx +50 -0
  58. package/src/card/ProductCard.component.tsx +65 -0
  59. package/src/card/ProfileCard.component.tsx +71 -0
  60. package/src/carousel/Carousel.component.tsx +111 -0
  61. package/src/chip/Chip.component.tsx +38 -0
  62. package/src/contexts-mock.ts +6 -0
  63. package/src/index.ts +70 -0
  64. package/src/input/Checkbox.component.tsx +102 -0
  65. package/src/input/Input.component.tsx +334 -0
  66. package/src/input/InputCheckbox.component.tsx +174 -0
  67. package/src/input/InputCurrency.component.tsx +165 -0
  68. package/src/input/InputDate.component.tsx +355 -0
  69. package/src/input/InputDatetime.component.tsx +267 -0
  70. package/src/input/InputDocument.component.tsx +360 -0
  71. package/src/input/InputImage.component.tsx +534 -0
  72. package/src/input/InputNumber.component.tsx +193 -0
  73. package/src/input/InputOtp.component.tsx +169 -0
  74. package/src/input/InputPassword.component.tsx +245 -0
  75. package/src/input/InputRadio.component.tsx +174 -0
  76. package/src/input/InputTime.component.tsx +280 -0
  77. package/src/input/InputValues.component.tsx +70 -0
  78. package/src/input/Radio.component.tsx +98 -0
  79. package/src/input/Select.component.tsx +557 -0
  80. package/src/modal/BottomSheet.component.tsx +246 -0
  81. package/src/modal/FloatingPage.component.tsx +133 -0
  82. package/src/modal/Modal.component.tsx +94 -0
  83. package/src/modal/ModalConfirm.component.tsx +204 -0
  84. package/src/modal/Toast.component.tsx +124 -0
  85. package/src/nav/Bottombar.component.tsx +71 -0
  86. package/src/nav/Footer.component.tsx +176 -0
  87. package/src/nav/Headbar.component.tsx +33 -0
  88. package/src/nav/Navbar.component.tsx +137 -0
  89. package/src/nav/Sidebar.component.tsx +307 -0
  90. package/src/nav/Tabbar.component.tsx +61 -0
  91. package/src/nav/Wizard.component.tsx +80 -0
  92. package/src/supervision/FormSupervision.component.tsx +404 -0
  93. package/src/supervision/TableSupervision.component.tsx +653 -0
  94. package/src/table/ControlBar.component.tsx +501 -0
  95. package/src/table/FilterComponent.tsx +517 -0
  96. package/src/table/Pagination.component.tsx +152 -0
  97. package/src/table/Table.component.tsx +436 -0
  98. package/src/typography/TypographyArticle.component.tsx +26 -0
  99. package/src/typography/TypographyColumn.component.tsx +20 -0
  100. package/src/typography/TypographyContent.component.tsx +20 -0
  101. package/src/typography/TypographyTips.component.tsx +20 -0
  102. package/src/wrap/Draggable.component.tsx +303 -0
  103. package/src/wrap/Image.component.tsx +10 -0
  104. package/src/wrap/OutsideClick.component.tsx +48 -0
  105. package/src/wrap/ScrollContainer.component.tsx +107 -0
  106. package/src/wrap/ShortcutProvider.tsx +57 -0
  107. package/src/wrap/Swipe.component.tsx +121 -0
@@ -0,0 +1,69 @@
1
+ "use client"
2
+
3
+ import { ReactNode } from "react";
4
+ import { cn, pcn } from "@utils";
5
+
6
+
7
+
8
+ type CT = "badge" | "title" | "base";
9
+
10
+ export interface AlertCardProps {
11
+ title ?: string | ReactNode;
12
+ leftContent ?: string | ReactNode;
13
+ badge ?: string | ReactNode;
14
+ content ?: string | ReactNode;
15
+ footer ?: string | ReactNode;
16
+
17
+ /** Use custom class with: "badge::", "title::". */
18
+ className ?: string;
19
+ }
20
+
21
+
22
+
23
+ export function AlertCardComponent({
24
+ title,
25
+ leftContent,
26
+ badge,
27
+ content,
28
+ footer,
29
+ className = "",
30
+ }: AlertCardProps) {
31
+ return (
32
+ <>
33
+ <section
34
+ className={cn(
35
+ "alert-card",
36
+ pcn<CT>(className, "base"),
37
+ )}
38
+ >
39
+ <div className="flex items-start sm:gap-8">
40
+ {leftContent}
41
+
42
+ <div>
43
+ <strong
44
+ className={cn(
45
+ "alert-card-badge",
46
+ pcn<CT>(className, "badge"),
47
+ )}
48
+ >
49
+ {badge}
50
+ </strong>
51
+
52
+ <h3
53
+ className={cn(
54
+ "alert-card-title",
55
+ pcn<CT>(className, "title"),
56
+ )}
57
+ >
58
+ {title}
59
+ </h3>
60
+
61
+ {content}
62
+
63
+ {footer && <div className="pt-4">{footer}</div>}
64
+ </div>
65
+ </div>
66
+ </section>
67
+ </>
68
+ );
69
+ }
@@ -0,0 +1,25 @@
1
+ "use client"
2
+
3
+ import { cn } from "@utils";
4
+
5
+
6
+
7
+ export interface CardProps {
8
+ children : React.ReactNode;
9
+ className ?: string;
10
+ }
11
+
12
+
13
+
14
+ export function CardComponent({
15
+ children,
16
+ className,
17
+ }: CardProps) {
18
+ return (
19
+ <>
20
+ <div className={cn("card", className)}>
21
+ {children}
22
+ </div>
23
+ </>
24
+ );
25
+ }
@@ -0,0 +1,44 @@
1
+ "use client"
2
+
3
+ import Link from "next/link";
4
+ import { ReactNode } from "react";
5
+ import { cn } from "@utils";
6
+
7
+
8
+
9
+ export interface DashboardCardProps {
10
+ content ?: string | ReactNode;
11
+ title ?: string | ReactNode;
12
+ rightContent ?: string | ReactNode;
13
+ path ?: string;
14
+ className ?: string;
15
+ }
16
+
17
+
18
+
19
+ export function DashboardCardComponent({
20
+ content,
21
+ title,
22
+ rightContent,
23
+ path,
24
+ className,
25
+ } : DashboardCardProps) {
26
+ return (
27
+ <>
28
+ <Link href={path || ""}>
29
+ <div
30
+ className={cn(
31
+ "dashboard-card",
32
+ className,
33
+ )}
34
+ >
35
+ <div>
36
+ <div className="flex gap-4 items-center">{content}</div>
37
+ {title}
38
+ </div>
39
+ <div>{rightContent}</div>
40
+ </div>
41
+ </Link>
42
+ </>
43
+ );
44
+ }
@@ -0,0 +1,50 @@
1
+ "use client"
2
+
3
+ import Image from "next/image";
4
+ import { cn, pcn } from "@utils";
5
+
6
+
7
+
8
+ type CT = "label" | "image" | "base";
9
+
10
+ export interface GalleryCardProps {
11
+ src : string;
12
+ alt ?: string;
13
+
14
+ /** Use custom class with: "label::", "image::". */
15
+ className?: string;
16
+ }
17
+
18
+
19
+
20
+ export function GalleryCardComponent({
21
+ src,
22
+ alt = "",
23
+ className = "",
24
+ } : GalleryCardProps) {
25
+ return (
26
+ <>
27
+ <div className={pcn<CT>(className, "base")}>
28
+ <Image
29
+ src={src}
30
+ alt={src}
31
+ width={400}
32
+ height={300}
33
+ className={cn(
34
+ "gallery-card-image",
35
+ pcn<CT>(className, "image"),
36
+ )}
37
+ />
38
+
39
+ <div
40
+ className={cn(
41
+ "gallery-card-label",
42
+ pcn<CT>(className, "label"),
43
+ )}
44
+ >
45
+ {alt}
46
+ </div>
47
+ </div>
48
+ </>
49
+ );
50
+ }
@@ -0,0 +1,65 @@
1
+ "use client"
2
+
3
+ import Image from "next/image";
4
+ import { cn, pcn } from "@utils";
5
+
6
+
7
+
8
+ type CT = "image" | "base" | "content";
9
+
10
+ export interface ProductCardProps {
11
+ name : string;
12
+ price ?: string;
13
+ image ?: string;
14
+ description ?: string | React.ReactNode;
15
+
16
+ /** Use custom class with: "image::", "content::". */
17
+ className ?: string;
18
+ }
19
+
20
+
21
+
22
+ export function ProductCardComponent({
23
+ image = "",
24
+ name,
25
+ price,
26
+ description,
27
+ className = "",
28
+ } : ProductCardProps) {
29
+ return (
30
+ <>
31
+ <div
32
+ className={cn(
33
+ "product-card",
34
+ pcn<CT>(className, "base"),
35
+ )}
36
+ >
37
+ <Image
38
+ src={image}
39
+ alt={image}
40
+ width={400}
41
+ height={300}
42
+ className={cn(
43
+ "product-card-image",
44
+ pcn<CT>(className, "image"),
45
+ )}
46
+ />
47
+
48
+ <div className={cn("p-2", pcn<CT>(className, "content"))}>
49
+ <dl>
50
+ <div>
51
+ <dt className="sr-only">Name</dt>
52
+ <dd className="text-sm">{name}</dd>
53
+ </div>
54
+ <div>
55
+ <dt className="sr-only">Price</dt>
56
+ <dd className="font-semibold">{price}</dd>
57
+ </div>
58
+ </dl>
59
+
60
+ {description && <div>{description}</div>}
61
+ </div>
62
+ </div>
63
+ </>
64
+ );
65
+ }
@@ -0,0 +1,71 @@
1
+ "use client"
2
+
3
+ import Image from "next/image";
4
+ import { cn, pcn } from "@utils";
5
+
6
+
7
+
8
+ type CT = "image" | "base" | "content";
9
+
10
+ export interface ProfileCardProps {
11
+ name : string;
12
+ short ?: string;
13
+ image ?: string;
14
+ description ?: string | React.ReactNode;
15
+ footer ?: string | React.ReactNode;
16
+
17
+ /** Use custom class with: "image::", "content::". */
18
+ className ?: string;
19
+ }
20
+
21
+
22
+
23
+ export function ProfileCardComponent({
24
+ image = "",
25
+ name,
26
+ short,
27
+ description,
28
+ footer,
29
+ className = "",
30
+ } : ProfileCardProps) {
31
+ return (
32
+ <>
33
+ <div
34
+ className={cn(
35
+ "profile-card",
36
+ pcn<CT>(className, "base"),
37
+ )}
38
+ >
39
+ <span className="absolute inset-x-0 bottom-0 h-1 bg-primary"></span>
40
+
41
+ <div className="sm:flex sm:gap-4 sm:items-center">
42
+ {image && (
43
+ <div className="hidden sm:block sm:shrink-0">
44
+ <Image
45
+ src={image}
46
+ alt={image}
47
+ width={400}
48
+ height={400}
49
+ className={cn(
50
+ "profile-card-image",
51
+ pcn<CT>(className, "image"),
52
+ )}
53
+ />
54
+ </div>
55
+ )}
56
+ <div className={pcn<CT>(className, "content")}>
57
+ <h3 className="text-lg font-bold sm:text-xl">{name}</h3>
58
+
59
+ <p className="mt-1 text-xs font-medium text-light-foreground">
60
+ {short}
61
+ </p>
62
+ </div>
63
+ </div>
64
+
65
+ {description}
66
+
67
+ {footer && <dl className="mt-4">{footer}</dl>}
68
+ </div>
69
+ </>
70
+ );
71
+ }
@@ -0,0 +1,111 @@
1
+ "use client"
2
+ import { Icon, type IconName } from "@skalfa/skalfa-icon";
3
+
4
+
5
+ import { useState, useRef, useEffect } from "react";
6
+ import { cn, pcn } from "@utils";
7
+
8
+
9
+
10
+ type CT = "item" | "prev-button" | "next-button" | "navigation" | "base";
11
+
12
+ interface CarouselItem {
13
+ background : string;
14
+ content ?: string;
15
+ }
16
+
17
+ interface CarouselProps {
18
+ items : CarouselItem[];
19
+ noButton ?: boolean;
20
+ noNavigation ?: boolean;
21
+
22
+ /** Use custom class with: "item::", "prev-button::", "next-button::", "navigation::". */
23
+ className ?: string;
24
+ }
25
+
26
+
27
+
28
+ export function CarouselComponent({
29
+ items,
30
+ className = "",
31
+ noButton,
32
+ noNavigation,
33
+ }: CarouselProps) {
34
+ const [currentIndex, setCurrentIndex] = useState<number>(0);
35
+ const touchStartX = useRef<number | null>(null);
36
+ const touchEndX = useRef<number | null>(null);
37
+ const intervalRef = useRef<NodeJS.Timeout | null>(null);
38
+
39
+ const handlePrev = (): void => setCurrentIndex((prevIndex) => (prevIndex - 1 + items.length) % items.length);
40
+
41
+ const handleNext = (): void => setCurrentIndex((prevIndex) => (prevIndex + 1) % items.length);
42
+
43
+ const handleTouchStart = (e: React.TouchEvent<HTMLDivElement>): void => {
44
+ touchStartX.current = e.touches[0].clientX;
45
+ };
46
+
47
+ const handleTouchEnd = (e: React.TouchEvent<HTMLDivElement>): void => {
48
+ touchEndX.current = e.changedTouches[0].clientX;
49
+ if (touchStartX.current !== null && touchEndX.current !== null) {
50
+ if (touchStartX.current - touchEndX.current > 50) handleNext();
51
+ if (touchEndX.current - touchStartX.current > 50) handlePrev();
52
+ }
53
+ };
54
+
55
+ useEffect(() => {
56
+ intervalRef.current = setInterval(handleNext, 10000);
57
+ return () => {
58
+ if (intervalRef.current) clearInterval(intervalRef.current);
59
+ };
60
+ }, []);
61
+
62
+ return (
63
+ <div className={cn("carousel", pcn<CT>(className, "base"))}>
64
+ <div
65
+ className="carousel-inner"
66
+ style={{ transform: `translateX(-${currentIndex * 100}%)` }}
67
+ onTouchStart={handleTouchStart}
68
+ onTouchEnd={handleTouchEnd}
69
+ >
70
+ {items.map((item, index) => (
71
+ <div
72
+ key={index}
73
+ className={cn("carousel-item", pcn<CT>(className, "item"))}
74
+ style={{ backgroundImage: `url(${item.background})` }}
75
+ >
76
+ {item.content}
77
+ </div>
78
+ ))}
79
+ </div>
80
+
81
+ {!noNavigation && (
82
+ <div className={cn("carousel-navigation", pcn<CT>(className, "navigation"))}>
83
+ {items.map((_, index) => (
84
+ <button
85
+ key={index}
86
+ className={`carousel-indicator ${currentIndex === index ? "carousel-indicator-active" : ""}`}
87
+ onClick={() => setCurrentIndex(index)}
88
+ ></button>
89
+ ))}
90
+ </div>
91
+ )}
92
+
93
+ {!noButton && (
94
+ <>
95
+ <button
96
+ className={cn("carousel-btn carousel-prev-btn", pcn<CT>(className, "prev-button"))}
97
+ onClick={handlePrev}
98
+ >
99
+ <Icon icon="solid/chevron-left" />
100
+ </button>
101
+ <button
102
+ className={cn("carousel-btn carousel-next-btn", pcn<CT>(className, "next-button"))}
103
+ onClick={handleNext}
104
+ >
105
+ <Icon icon="solid/chevron-right" />
106
+ </button>
107
+ </>
108
+ )}
109
+ </div>
110
+ );
111
+ }
@@ -0,0 +1,38 @@
1
+ import { Icon, type IconName } from "@skalfa/skalfa-icon";
2
+ import { cn } from "@utils";
3
+
4
+ export function ChipComponent({
5
+ items,
6
+ onClick,
7
+ onDelete,
8
+ className,
9
+ } : {
10
+ items : Record<string, any>,
11
+ onClick ?: (item: any, index: number) => void,
12
+ onDelete ?: (item: any, index: number) => void,
13
+ className ?: string,
14
+ }) {
15
+ return (
16
+ <div className={cn("chip-group", className)}>
17
+ {items?.map((item: any, key: number) => {
18
+ return (
19
+ <div
20
+ key={key}
21
+ className="chip"
22
+ onClick={() => onClick?.(item, key)}
23
+ >
24
+ <span>{item}</span>
25
+
26
+ {onDelete && (
27
+ <Icon
28
+ icon="solid/times"
29
+ className="chip-delete"
30
+ onClick={() => onDelete?.(item, key)}
31
+ />
32
+ )}
33
+ </div>
34
+ );
35
+ })}
36
+ </div>
37
+ )
38
+ }
@@ -0,0 +1,6 @@
1
+ export function useToggleContext(): any {
2
+ return { toggle: {}, setToggle: () => {} };
3
+ }
4
+ export function useAuthContext(): any {
5
+ return { setUser: () => {}, setAccessToken: () => {} };
6
+ }
package/src/index.ts ADDED
@@ -0,0 +1,70 @@
1
+ export * from "./accordion/Accordion.component";
2
+ export * from "./breadcrumb/Breadcrumb.component";
3
+ export * from "./button/Button.component";
4
+ export * from "./card/AlertCard.component";
5
+ export * from "./card/Card.component";
6
+ export * from "./card/DashboardCard.component";
7
+ export * from "./card/GalleryCard.component";
8
+ export * from "./card/ProductCard.component";
9
+ export * from "./card/ProfileCard.component";
10
+ export * from "./carousel/Carousel.component";
11
+ export * from "./chip/Chip.component";
12
+ export * from "./input/Checkbox.component";
13
+ export * from "./input/Input.component";
14
+ export * from "./input/InputCheckbox.component";
15
+ export * from "./input/InputCurrency.component";
16
+ export * from "./input/InputDate.component";
17
+ export * from "./input/InputDatetime.component";
18
+ export * from "./input/InputDocument.component";
19
+ export * from "./input/InputImage.component";
20
+ export * from "./input/InputNumber.component";
21
+ export * from "./input/InputOtp.component";
22
+ export * from "./input/InputPassword.component";
23
+ export * from "./input/InputRadio.component";
24
+ export * from "./input/InputTime.component";
25
+ export * from "./input/InputValues.component";
26
+ export * from "./input/Radio.component";
27
+ export * from "./input/Select.component";
28
+ export * from "./modal/BottomSheet.component";
29
+ export * from "./modal/FloatingPage.component";
30
+ export * from "./modal/Modal.component";
31
+ export * from "./modal/ModalConfirm.component";
32
+ export * from "./modal/Toast.component";
33
+ export * from "./nav/Bottombar.component";
34
+ export * from "./nav/Footer.component";
35
+ export * from "./nav/Headbar.component";
36
+ export * from "./nav/Navbar.component";
37
+ export * from "./nav/Sidebar.component";
38
+ export * from "./nav/Tabbar.component";
39
+ export * from "./nav/Wizard.component";
40
+ export * from "./supervision/FormSupervision.component";
41
+ export * from "./supervision/TableSupervision.component";
42
+ export * from "./table/ControlBar.component";
43
+ export * from "./table/FilterComponent";
44
+ export * from "./table/Pagination.component";
45
+ export * from "./table/Table.component";
46
+ export * from "./typography/TypographyArticle.component";
47
+ export * from "./typography/TypographyColumn.component";
48
+ export * from "./typography/TypographyContent.component";
49
+ export * from "./typography/TypographyTips.component";
50
+ export * from "./wrap/Draggable.component";
51
+ export * from "./wrap/Image.component";
52
+ export * from "./wrap/OutsideClick.component";
53
+ export * from "./wrap/ScrollContainer.component";
54
+ export * from "./wrap/ShortcutProvider";
55
+ export * from "./wrap/Swipe.component";
56
+
57
+ import { registry } from "@utils";
58
+ import { TableComponent } from "./table/Table.component";
59
+ import { ButtonComponent } from "./button/Button.component";
60
+ import { SelectComponent } from "./input/Select.component";
61
+ import { ModalComponent } from "./modal/Modal.component";
62
+ import { FilterComponent } from "./table/FilterComponent";
63
+ import { useToggleContext } from "@contexts";
64
+
65
+ registry.register("TableComponent", TableComponent);
66
+ registry.register("ButtonComponent", ButtonComponent);
67
+ registry.register("SelectComponent", SelectComponent);
68
+ registry.register("ModalComponent", ModalComponent);
69
+ registry.register("FilterComponent", FilterComponent);
70
+ registry.register("useToggleContext", useToggleContext);
@@ -0,0 +1,102 @@
1
+ "use client"
2
+ import { Icon, type IconName } from "@skalfa/skalfa-icon";
3
+
4
+
5
+ import { ReactNode, useEffect, useState } from "react";
6
+ import { cn, pcn, useInputRandomId } from "@utils";
7
+
8
+ type CT = "label" | "checked" | "error" | "base";
9
+
10
+ export type CheckboxProps = {
11
+ name : string;
12
+ label ?: string | ReactNode;
13
+
14
+ value ?: string;
15
+ disabled ?: boolean;
16
+ checked ?: boolean;
17
+ invalid ?: string;
18
+
19
+ onChange ?: () => void;
20
+
21
+ /** Use custom class with: "label::", "checked::", "error::". */
22
+ className ?: string;
23
+ };
24
+
25
+ export function CheckboxComponent({
26
+ name,
27
+ label,
28
+
29
+ value,
30
+ disabled = false,
31
+ checked = false,
32
+ invalid,
33
+
34
+ onChange,
35
+
36
+ className = "",
37
+ }: CheckboxProps) {
38
+
39
+ // =========================>
40
+ // ## Initial
41
+ // =========================>
42
+ const randomId = useInputRandomId()
43
+ const [invalidMessage, setInvalidMessage] = useState("");
44
+
45
+ // =========================>
46
+ // ## Invalid handler
47
+ // =========================>
48
+ useEffect(() => {
49
+ setInvalidMessage(invalid || "");
50
+ }, [invalid]);
51
+
52
+ return (
53
+ <div className="checkbox-container">
54
+ <input
55
+ type="checkbox"
56
+ className="hidden"
57
+ id={randomId}
58
+ name={name}
59
+ onChange={onChange}
60
+ defaultChecked={checked}
61
+ value={value}
62
+ disabled={disabled}
63
+ />
64
+
65
+ <label
66
+ htmlFor={randomId}
67
+ className={cn(
68
+ "checkbox-wrapper",
69
+ disabled && "checkbox-wrapper-disabled"
70
+ )}
71
+ >
72
+ <div>
73
+ <div
74
+ className={cn(
75
+ "checkbox-input",
76
+ checked && "checkbox-input-checked",
77
+ checked && pcn<CT>(className, "checked"),
78
+ pcn<CT>(className, "base"),
79
+ )}
80
+ >
81
+ {checked && <Icon icon="solid/check" className="text-sm" />}
82
+ </div>
83
+ </div>
84
+ <span
85
+ className={cn(
86
+ "checkbox-label",
87
+ checked && "checkbox-label-checked",
88
+ pcn<CT>(className, "label"),
89
+ checked && pcn<CT>(className, "label", "checked"),
90
+ disabled && pcn<CT>(className, "label", "disabled"),
91
+ )}
92
+ >
93
+ {label}
94
+ </span>
95
+ </label>
96
+
97
+ {invalidMessage && (
98
+ <small className={cn("input-error-message", pcn<CT>(className, "error"))}>{invalidMessage}</small>
99
+ )}
100
+ </div>
101
+ );
102
+ }