@skalfa/skalfa-app 1.0.2 → 1.0.5

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 (99) hide show
  1. package/.env.example +8 -16
  2. package/app/auth/edit/page.tsx +1 -1
  3. package/app/auth/login/page.tsx +1 -1
  4. package/app/auth/me/page.tsx +1 -1
  5. package/app/auth/register/page.tsx +1 -1
  6. package/app/auth/verify/page.tsx +1 -1
  7. package/app/dashboard/layout.tsx +2 -2
  8. package/app/dashboard/page.tsx +1 -1
  9. package/app/index.ts +1 -0
  10. package/app/layout.tsx +2 -4
  11. package/app/page.tsx +2 -2
  12. package/bun.lock +39 -24
  13. package/components/index.ts +1 -3
  14. package/package.json +8 -7
  15. package/styles/components.css +1392 -0
  16. package/styles/globals.css +40 -175
  17. package/styles/utilities.css +37 -0
  18. package/tsconfig.json +4 -2
  19. package/utils/commands/skalfa.ts +3 -0
  20. package/blueprints/starter.blueprint.json +0 -103
  21. package/components/base.components/accordion/Accordion.component.tsx +0 -82
  22. package/components/base.components/breadcrumb/Breadcrumb.component.tsx +0 -80
  23. package/components/base.components/button/Button.component.tsx +0 -91
  24. package/components/base.components/button/IconButton.component.tsx +0 -88
  25. package/components/base.components/button/button.decorate.ts +0 -82
  26. package/components/base.components/card/AlertCard.component.tsx +0 -69
  27. package/components/base.components/card/Card.component.tsx +0 -25
  28. package/components/base.components/card/DashboardCard.component.tsx +0 -44
  29. package/components/base.components/card/GalleryCard.component.tsx +0 -50
  30. package/components/base.components/card/ProductCard.component.tsx +0 -65
  31. package/components/base.components/card/ProfileCard.component.tsx +0 -71
  32. package/components/base.components/carousel/Carousel.component.tsx +0 -113
  33. package/components/base.components/chip/Chip.component.tsx +0 -39
  34. package/components/base.components/document/DocumentViewer.component.tsx +0 -164
  35. package/components/base.components/document/ExportExcel.component.tsx +0 -340
  36. package/components/base.components/document/ImportExcel.component.tsx +0 -315
  37. package/components/base.components/document/PrintTable.component.tsx +0 -204
  38. package/components/base.components/document/RenderPDF.component.tsx +0 -416
  39. package/components/base.components/index.ts +0 -85
  40. package/components/base.components/input/Checkbox.component.tsx +0 -109
  41. package/components/base.components/input/Input.component.tsx +0 -332
  42. package/components/base.components/input/InputCheckbox.component.tsx +0 -174
  43. package/components/base.components/input/InputCurrency.component.tsx +0 -163
  44. package/components/base.components/input/InputDate.component.tsx +0 -352
  45. package/components/base.components/input/InputDatetime.component.tsx +0 -260
  46. package/components/base.components/input/InputDocument.component.tsx +0 -352
  47. package/components/base.components/input/InputImage.component.tsx +0 -533
  48. package/components/base.components/input/InputMap.component.tsx +0 -318
  49. package/components/base.components/input/InputNumber.component.tsx +0 -192
  50. package/components/base.components/input/InputOtp.component.tsx +0 -169
  51. package/components/base.components/input/InputPassword.component.tsx +0 -236
  52. package/components/base.components/input/InputRadio.component.tsx +0 -175
  53. package/components/base.components/input/InputTime.component.tsx +0 -276
  54. package/components/base.components/input/InputValues.component.tsx +0 -68
  55. package/components/base.components/input/Radio.component.tsx +0 -102
  56. package/components/base.components/input/Select.component.tsx +0 -541
  57. package/components/base.components/modal/BottomSheet.component.tsx +0 -246
  58. package/components/base.components/modal/FloatingPage.component.tsx +0 -104
  59. package/components/base.components/modal/Modal.component.tsx +0 -96
  60. package/components/base.components/modal/ModalConfirm.component.tsx +0 -218
  61. package/components/base.components/modal/Toast.component.tsx +0 -126
  62. package/components/base.components/nav/Bottombar.component.tsx +0 -116
  63. package/components/base.components/nav/Footer.component.tsx +0 -144
  64. package/components/base.components/nav/Headbar.component.tsx +0 -104
  65. package/components/base.components/nav/Navbar.component.tsx +0 -100
  66. package/components/base.components/nav/Sidebar.component.tsx +0 -301
  67. package/components/base.components/nav/Tabbar.component.tsx +0 -60
  68. package/components/base.components/nav/Wizard.component.tsx +0 -73
  69. package/components/base.components/supervision/FormSupervision.component.tsx +0 -434
  70. package/components/base.components/supervision/TableSupervision.component.tsx +0 -697
  71. package/components/base.components/table/ControlBar.component.tsx +0 -497
  72. package/components/base.components/table/FilterComponent.tsx +0 -518
  73. package/components/base.components/table/Pagination.component.tsx +0 -159
  74. package/components/base.components/table/Table.component.tsx +0 -469
  75. package/components/base.components/typography/TypographyArticle.component.tsx +0 -26
  76. package/components/base.components/typography/TypographyColumn.component.tsx +0 -20
  77. package/components/base.components/typography/TypographyContent.component.tsx +0 -20
  78. package/components/base.components/typography/TypographyTips.component.tsx +0 -20
  79. package/components/base.components/wrap/Draggable.component.tsx +0 -303
  80. package/components/base.components/wrap/IDBProvider.tsx +0 -12
  81. package/components/base.components/wrap/Image.component.tsx +0 -10
  82. package/components/base.components/wrap/OutsideClick.component.tsx +0 -48
  83. package/components/base.components/wrap/ScrollContainer.component.tsx +0 -104
  84. package/components/base.components/wrap/ShortcutProvider.tsx +0 -57
  85. package/components/base.components/wrap/Swipe.component.tsx +0 -93
  86. package/components/construct.components/example.tsx +0 -1
  87. package/components/construct.components/index.ts +0 -5
  88. package/components/structure.components/example.tsx +0 -1
  89. package/components/structure.components/index.ts +0 -5
  90. package/langs/index.ts +0 -1
  91. package/langs/validation.langs.ts +0 -17
  92. package/schema/idb/app.schema.ts +0 -9
  93. package/schema/index.ts +0 -5
  94. package/utils/commands/barrels.ts +0 -28
  95. package/utils/commands/blueprint.ts +0 -421
  96. package/utils/commands/light.ts +0 -21
  97. package/utils/commands/logger.ts +0 -42
  98. package/utils/commands/stubs/table-blueprint.stub +0 -13
  99. package/utils/commands/use-pdf.ts +0 -29
@@ -1,416 +0,0 @@
1
- "use client"
2
-
3
- import { PDFDocument, StandardFonts, PDFPage, rgb } from 'pdf-lib'
4
- import { useEffect, useRef } from 'react'
5
-
6
- export const PaperSize = {
7
- LETTER: { width: 612, height: 792 },
8
- A4: { width: 595, height: 842 },
9
- }
10
-
11
- export type RenderPDFProps = {
12
- content: PageSchema[]
13
- }
14
-
15
- export type PageSchema = {
16
- page: {
17
- size?: keyof typeof PaperSize | { width: number; height: number }
18
- margin?: number
19
- content: NodeSchema[]
20
- }
21
- }
22
-
23
- export type Style = {
24
- width?: number
25
- height?: number
26
-
27
- padding?: number
28
- paddingTop?: number
29
- paddingRight?: number
30
- paddingBottom?: number
31
- paddingLeft?: number
32
- paddingX?: number
33
- paddingY?: number
34
-
35
- marginTop?: number
36
- marginBottom?: number
37
-
38
- fontSize?: number
39
- fontWeight?: "normal" | "bold"
40
- lineHeight?: number
41
- letterSpacing?: number
42
- color?: string
43
- opacity?: number
44
- align?: "left" | "center" | "right"
45
- textTransform?: "uppercase" | "lowercase" | "capitalize"
46
-
47
- backgroundColor?: string
48
- borderColor?: string
49
- borderWidth?: number
50
-
51
- underline?: boolean
52
-
53
- textAlign?: "left" | "center" | "right"
54
- }
55
-
56
- export type NodeSchema =
57
- | { type: "view"; style?: Style; content: NodeSchema[] }
58
- | { type: "text"; content: string; style?: Style }
59
- | { type: "image"; src: string | Uint8Array | ArrayBuffer; style?: Style }
60
- | { type: "table"; content: NodeSchema[] }
61
- | { type: "tr"; content: NodeSchema[], style?: Style }
62
- | { type: 'td' | 'th'; content: NodeSchema[] | string; style?: Style }
63
-
64
- // ==================================================
65
- // Layout Context
66
- // ==================================================
67
-
68
- class LayoutContext {
69
- x: number
70
- y: number
71
- constructor(
72
- public width: number,
73
- public height: number,
74
- public margin: number
75
- ) {
76
- this.x = margin
77
- this.y = height - margin
78
- }
79
-
80
- needBreak(h: number) {
81
- return this.y - h < this.margin
82
- }
83
-
84
- reset() {
85
- this.x = this.margin
86
- this.y = this.height - this.margin
87
- }
88
- }
89
-
90
- // ==================================================
91
- // Helpers
92
- // ==================================================
93
-
94
- function resolvePadding(style?: Style) {
95
- const p = style?.padding ?? 0
96
- const px = style?.paddingX ?? p
97
- const py = style?.paddingY ?? p
98
-
99
- return {
100
- top: style?.paddingTop ?? py,
101
- bottom: style?.paddingBottom ?? py,
102
- left: style?.paddingLeft ?? px,
103
- right: style?.paddingRight ?? px,
104
- }
105
- }
106
-
107
- function resolveText(text: string, style?: Style) {
108
- if (!style?.textTransform) return text
109
- if (style.textTransform === "uppercase") return text.toUpperCase()
110
- if (style.textTransform === "lowercase") return text.toLowerCase()
111
- if (style.textTransform === "capitalize")
112
- return text.replace(/\b\w/g, c => c.toUpperCase())
113
- return text
114
- }
115
-
116
- function hexToRgb(hex?: string) {
117
- if (!hex) return undefined
118
- const h = hex.replace("#", "")
119
- return rgb(
120
- parseInt(h.slice(0, 2), 16) / 255,
121
- parseInt(h.slice(2, 4), 16) / 255,
122
- parseInt(h.slice(4, 6), 16) / 255
123
- )
124
- }
125
-
126
- async function embedImage(pdf: PDFDocument, bytes: Uint8Array | ArrayBuffer) {
127
- const data = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes)
128
- try {
129
- return await pdf.embedPng(data)
130
- } catch {
131
- return await pdf.embedJpg(data)
132
- }
133
- }
134
-
135
- async function resolveImageSource(
136
- src: string | Uint8Array | ArrayBuffer
137
- ): Promise<Uint8Array> {
138
- if (src instanceof Uint8Array) return src
139
- if (src instanceof ArrayBuffer) return new Uint8Array(src)
140
-
141
- const res = await fetch(src)
142
- if (!res.ok) {
143
- throw new Error(`Failed to load image: ${src}`)
144
- }
145
-
146
- const buffer = await res.arrayBuffer()
147
- return new Uint8Array(buffer)
148
- }
149
-
150
-
151
- function normalizeContent(
152
- content: string | NodeSchema[]
153
- ): NodeSchema[] {
154
- if (typeof content === "string") {
155
- return [
156
- {
157
- type: "text",
158
- content
159
- }
160
- ]
161
- }
162
- return content
163
- }
164
-
165
-
166
- // ==================================================
167
- // Render Engine
168
- // ==================================================
169
-
170
- export async function RenderPDF(
171
- { content }: RenderPDFProps
172
- ): Promise<Uint8Array> {
173
-
174
- const pdf = await PDFDocument.create()
175
-
176
- const fontRegular = await pdf.embedFont(StandardFonts.Courier)
177
- const fontBold = await pdf.embedFont(StandardFonts.CourierBold)
178
-
179
- for (const p of content) {
180
- const size =
181
- typeof p.page.size === "string"
182
- ? PaperSize[p.page.size]
183
- : p.page.size ?? PaperSize.A4
184
-
185
- const margin = p.page.margin ?? 40
186
-
187
- let page: PDFPage = pdf.addPage([size.width, size.height])
188
- const ctx = new LayoutContext(size.width, size.height, margin)
189
-
190
- const draw = async (node: NodeSchema) => {
191
-
192
- // ===================== VIEW =====================
193
- if (node.type === "view") {
194
- const pad = resolvePadding(node.style)
195
- const startY = ctx.y
196
-
197
- ctx.y -= pad.top
198
- ctx.x += pad.left
199
-
200
- for (const c of node.content) await draw(c)
201
-
202
- const endY = ctx.y
203
- const boxHeight = startY - endY
204
-
205
- if (node.style?.backgroundColor) {
206
- page.drawRectangle({
207
- x: ctx.margin,
208
- y: endY,
209
- width: size.width - ctx.margin * 2,
210
- height: boxHeight,
211
- color: hexToRgb(node.style.backgroundColor),
212
- })
213
- }
214
-
215
- if (node.style?.borderWidth && node.style?.borderColor) {
216
- page.drawRectangle({
217
- x: ctx.margin,
218
- y: endY,
219
- width: size.width - ctx.margin * 2,
220
- height: boxHeight,
221
- borderColor: hexToRgb(node.style.borderColor),
222
- borderWidth: node.style.borderWidth,
223
- })
224
- }
225
-
226
- ctx.x -= pad.left
227
- ctx.y -= pad.bottom
228
- return
229
- }
230
-
231
- // ===================== TEXT =====================
232
- if (node.type === "text") {
233
- const style = node.style
234
- const fs = style?.fontSize ?? 12
235
- const lh = style?.lineHeight ?? fs + 4
236
-
237
- if (ctx.needBreak(lh)) {
238
- page = pdf.addPage([size.width, size.height])
239
- ctx.reset()
240
- }
241
-
242
- const font =
243
- style?.fontWeight === "bold"
244
- ? fontBold
245
- : fontRegular
246
-
247
- const text = resolveText(node.content, style)
248
- const color = hexToRgb(style?.color)
249
-
250
- let x = ctx.x
251
- if (style?.align === "center") {
252
- const w = font.widthOfTextAtSize(text, fs)
253
- x = (size.width - w) / 2
254
- }
255
- if (style?.align === "right") {
256
- const w = font.widthOfTextAtSize(text, fs)
257
- x = size.width - ctx.margin - w
258
- }
259
-
260
- page.drawText(text, {
261
- x,
262
- y: ctx.y - fs,
263
- size: fs,
264
- font,
265
- color,
266
- opacity: style?.opacity,
267
- })
268
-
269
- if (style?.underline) {
270
- const w = font.widthOfTextAtSize(text, fs)
271
- page.drawLine({
272
- start: { x, y: ctx.y - fs - 2 },
273
- end: { x: x + w, y: ctx.y - fs - 2 },
274
- thickness: 1,
275
- })
276
- }
277
-
278
- ctx.y -= lh + (style?.marginBottom ?? 0)
279
- return
280
- }
281
-
282
- // ===================== IMAGE =====================
283
- if (node.type === "image") {
284
- const bytes = await resolveImageSource(node.src)
285
- const img = await embedImage(pdf, bytes)
286
- const base = img.scale(1)
287
-
288
- let w = node.style?.width ?? base.width
289
- let h = node.style?.height ?? base.height
290
-
291
- if (node.style?.width && !node.style?.height)
292
- h = (base.height / base.width) * w
293
-
294
- if (node.style?.height && !node.style?.width)
295
- w = (base.width / base.height) * h
296
-
297
- if (ctx.needBreak(h)) {
298
- page = pdf.addPage([size.width, size.height])
299
- ctx.reset()
300
- }
301
-
302
- page.drawImage(img, {
303
- x: ctx.x,
304
- y: ctx.y - h,
305
- width: w,
306
- height: h,
307
- })
308
-
309
- ctx.y -= h + (node.style?.marginBottom ?? 0)
310
- return
311
- }
312
-
313
-
314
- // ===================== TABLE =====================
315
- if (node.type === "table") {
316
- for (const r of node.content) await draw(r)
317
- ctx.y -= 8
318
- return
319
- }
320
-
321
- if (node.type === "tr") {
322
- const rowH = node.style?.height || 20;
323
-
324
- if (ctx.needBreak(rowH)) {
325
- page = pdf.addPage([size.width, size.height])
326
- ctx.reset()
327
- }
328
-
329
- const tableWidth = size.width - ctx.margin * 2
330
- const colCount = node.content.length
331
- const colWidth = tableWidth / colCount
332
-
333
- const originalX = ctx.x
334
- let x = ctx.margin
335
-
336
- for (const cell of node.content) {
337
- if (cell.type !== "td" && cell.type !== "th") continue
338
-
339
- const children = normalizeContent(cell.content)
340
- const pad = resolvePadding(cell.style)
341
- const startY = ctx.y
342
-
343
- ctx.x = x + pad.left
344
- ctx.y -= pad.top
345
-
346
- for (const child of children) {
347
- await draw(child)
348
- }
349
-
350
- ctx.y = startY
351
- x += colWidth
352
- }
353
-
354
- ctx.x = originalX
355
- ctx.y -= rowH
356
- return
357
- }
358
-
359
-
360
-
361
-
362
- }
363
-
364
- for (const n of p.page.content) await draw(n)
365
- }
366
-
367
- return await pdf.save()
368
- }
369
-
370
- export function RenderPDFPreview({ schema, className }: { schema: PageSchema[], className?: string }) {
371
- const canvasRef = useRef<HTMLCanvasElement>(null);
372
-
373
- useEffect(() => {
374
- let cancelled = false;
375
-
376
- (async () => {
377
- const bytes = await RenderPDF({ content: schema });
378
- const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
379
- pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.mjs";
380
-
381
- const pdf = await pdfjs.getDocument({ data: bytes }).promise;
382
- if (cancelled) return;
383
-
384
- const page = await pdf.getPage(1);
385
- const dpr = 1;
386
- const viewport = page.getViewport({ scale: 1 });
387
-
388
- const canvas = canvasRef.current!;
389
- const ctx = canvas.getContext("2d")!;
390
- canvas.style.width = `${viewport.width}px`;
391
- canvas.style.height = `${viewport.height}px`
392
- canvas.width = viewport.width;
393
- canvas.height = viewport.height;
394
-
395
- const scaledViewport = page.getViewport({ scale: dpr });
396
-
397
- const renderTask = page.render({
398
- canvas,
399
- canvasContext: ctx,
400
- viewport: scaledViewport,
401
- });
402
-
403
- await renderTask.promise;
404
- })();
405
-
406
- return () => {
407
- cancelled = true;
408
- };
409
- }, [schema]);
410
-
411
- return <>
412
- <div className={className}>
413
- <canvas ref={canvasRef} className="w-full border" />
414
- </div>
415
- </>
416
- }
@@ -1,85 +0,0 @@
1
- /**
2
- * @file Automatically generated by barrelsby.
3
- */
4
-
5
- export * from "./accordion/Accordion.component";
6
- export * from "./breadcrumb/Breadcrumb.component";
7
- export * from "./button/Button.component";
8
- export * from "./button/button.decorate";
9
- export * from "./button/IconButton.component";
10
- export * from "./card/AlertCard.component";
11
- export * from "./card/Card.component";
12
- export * from "./card/DashboardCard.component";
13
- export * from "./card/GalleryCard.component";
14
- export * from "./card/ProductCard.component";
15
- export * from "./card/ProfileCard.component";
16
- export * from "./carousel/Carousel.component";
17
- export * from "./chip/Chip.component";
18
- export * from "./document/DocumentViewer.component";
19
- export * from "./document/ExportExcel.component";
20
- export * from "./document/ImportExcel.component";
21
- export * from "./document/PrintTable.component";
22
- export * from "./document/RenderPDF.component";
23
- export * from "./input/Checkbox.component";
24
- export * from "./input/Input.component";
25
- export * from "./input/InputCheckbox.component";
26
- export * from "./input/InputCurrency.component";
27
- export * from "./input/InputDate.component";
28
- export * from "./input/InputDatetime.component";
29
- export * from "./input/InputDocument.component";
30
- export * from "./input/InputImage.component";
31
- export * from "./input/InputMap.component";
32
- export * from "./input/InputNumber.component";
33
- export * from "./input/InputOtp.component";
34
- export * from "./input/InputPassword.component";
35
- export * from "./input/InputRadio.component";
36
- export * from "./input/InputTime.component";
37
- export * from "./input/InputValues.component";
38
- export * from "./input/Radio.component";
39
- export * from "./input/Select.component";
40
- export * from "./modal/BottomSheet.component";
41
- export * from "./modal/FloatingPage.component";
42
- export * from "./modal/Modal.component";
43
- export * from "./modal/ModalConfirm.component";
44
- export * from "./modal/Toast.component";
45
- export * from "./nav/Bottombar.component";
46
- export * from "./nav/Footer.component";
47
- export * from "./nav/Headbar.component";
48
- export * from "./nav/Navbar.component";
49
- export * from "./nav/Sidebar.component";
50
- export * from "./nav/Tabbar.component";
51
- export * from "./nav/Wizard.component";
52
- export * from "./supervision/FormSupervision.component";
53
- export * from "./supervision/TableSupervision.component";
54
- export * from "./table/ControlBar.component";
55
- export * from "./table/FilterComponent";
56
- export * from "./table/Pagination.component";
57
- export * from "./table/Table.component";
58
- export * from "./typography/TypographyArticle.component";
59
- export * from "./typography/TypographyColumn.component";
60
- export * from "./typography/TypographyContent.component";
61
- export * from "./typography/TypographyTips.component";
62
- export * from "./wrap/Draggable.component";
63
- export * from "./wrap/IDBProvider";
64
- export * from "./wrap/Image.component";
65
- export * from "./wrap/OutsideClick.component";
66
- export * from "./wrap/ScrollContainer.component";
67
- export * from "./wrap/ShortcutProvider";
68
- export * from "./wrap/Swipe.component";
69
-
70
- import { registry } from "@utils";
71
- import { TableComponent } from "./table/Table.component.js";
72
- import { ButtonComponent } from "./button/Button.component.js";
73
- import { IconButtonComponent } from "./button/IconButton.component.js";
74
- import { SelectComponent } from "./input/Select.component.js";
75
- import { ModalComponent } from "./modal/Modal.component.js";
76
- import { FilterComponent } from "./table/FilterComponent.js";
77
- import { useToggleContext } from "../../contexts/index.js";
78
-
79
- registry.register("TableComponent", TableComponent);
80
- registry.register("ButtonComponent", ButtonComponent);
81
- registry.register("IconButtonComponent", IconButtonComponent);
82
- registry.register("SelectComponent", SelectComponent);
83
- registry.register("ModalComponent", ModalComponent);
84
- registry.register("FilterComponent", FilterComponent);
85
- registry.register("useToggleContext", useToggleContext);
@@ -1,109 +0,0 @@
1
- "use client"
2
-
3
- import { ReactNode, useEffect, useState } from "react";
4
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5
- import { faCheck } from "@fortawesome/free-solid-svg-icons";
6
- import { cn, pcn, useInputRandomId } from "@utils";
7
-
8
-
9
-
10
- type CT = "label" | "checked" | "error" | "base";
11
-
12
- export type CheckboxProps = {
13
- name : string;
14
- label ?: string | ReactNode;
15
-
16
- value ?: string;
17
- disabled ?: boolean;
18
- checked ?: boolean;
19
- invalid ?: string;
20
-
21
- onChange ?: () => void;
22
-
23
- /** Use custom class with: "label::", "checked::", "error::". */
24
- className ?: string;
25
- };
26
-
27
-
28
-
29
- export function CheckboxComponent({
30
- name,
31
- label,
32
-
33
- value,
34
- disabled = false,
35
- checked = false,
36
- invalid,
37
-
38
- onChange,
39
-
40
- className = "",
41
- }: CheckboxProps) {
42
-
43
-
44
- // =========================>
45
- // ## Initial
46
- // =========================>
47
- const randomId = useInputRandomId()
48
- const [invalidMessage, setInvalidMessage] = useState("");
49
-
50
-
51
- // =========================>
52
- // ## Invalid handler
53
- // =========================>
54
- useEffect(() => {
55
- setInvalidMessage(invalid || "");
56
- }, [invalid]);
57
-
58
-
59
- return (
60
- <div className={`flex flex-col gap-1`}>
61
- <input
62
- type="checkbox"
63
- className="hidden"
64
- id={randomId}
65
- name={name}
66
- onChange={onChange}
67
- defaultChecked={checked}
68
- value={value}
69
- disabled={disabled}
70
- />
71
-
72
- <label
73
- htmlFor={randomId}
74
- className={cn(
75
- "flex gap-2 items-center cursor-pointer active:scale-x-[102%]",
76
- disabled && "pointer-events-none opacity-60"
77
- )}
78
- >
79
- <div>
80
- <div
81
- className={cn(
82
- `flex justify-center items-center rounded-md border w-6 h-6 transition-colors border-light-foreground text-light-foreground`,
83
- checked && "border-light-primary bg-primary !text-background",
84
- checked && pcn<CT>(className, "checked"),
85
- pcn<CT>(className, "base"),
86
- )}
87
- >
88
- {checked && <FontAwesomeIcon icon={faCheck} className="text-sm" />}
89
- </div>
90
- </div>
91
- <span
92
- className={cn(
93
- "whitespace-nowrap",
94
- checked && "font-semibold",
95
- pcn<CT>(className, "label"),
96
- checked && pcn<CT>(className, "label", "checked"),
97
- disabled && pcn<CT>(className, "label", "disabled"),
98
- )}
99
- >
100
- {label}
101
- </span>
102
- </label>
103
-
104
- {invalidMessage && (
105
- <small className={cn("input-error-message", pcn<CT>(className, "error"))}>{invalidMessage}</small>
106
- )}
107
- </div>
108
- );
109
- }