@sikka/hawa
Version:
Modern UI Kit made with Tailwind
1 lines • 128 kB
Source Map (JSON)
{"version":3,"sources":["../../elements/dataTable/DataTable.tsx","../../util/index.ts","../../elements/button/Button.tsx","../../elements/helperText/HelperText.tsx","../../elements/label/Label.tsx","../../elements/tooltip/Tooltip.tsx","../../elements/loading/Loading.tsx","../../elements/checkbox/Checkbox.tsx","../../elements/dropdownMenu/DropdownMenu.tsx","../../elements/input/Input.tsx","../../elements/skeleton/Skeleton.tsx","../../elements/table/Table.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport {\n ColumnDef,\n ColumnFiltersState,\n SortingState,\n VisibilityState,\n flexRender,\n getCoreRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getExpandedRowModel,\n getSortedRowModel,\n useReactTable,\n RowData,\n ExpandedState,\n} from \"@tanstack/react-table\";\nimport { cn } from \"@util/index\";\n\nimport { DirectionType } from \"@_types/commonTypes\";\n\nimport { Button } from \"../button\";\nimport { Checkbox } from \"../checkbox\";\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuRoot,\n DropdownMenuTrigger,\n} from \"../dropdownMenu\";\nimport { Input } from \"../input\";\nimport { Skeleton } from \"../skeleton\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"../table\";\n\nexport type { ColumnDef } from \"@tanstack/react-table\";\n\ntype DataTableProps<DataProps = {}> = {\n direction?: DirectionType;\n columns: ColumnDef<DataProps>[];\n enableSearch?: boolean;\n enableHideColumns?: boolean;\n enableGoTo?: boolean;\n enableSelection?: boolean;\n enableFiltering?: boolean;\n resetSelection?: boolean;\n filters?: { accessorKey: string; value: string; label: string }[];\n hideHeader?: boolean;\n data: DataProps[];\n itemsPerPage?: any[];\n showCount?: boolean;\n showSelectionCount?: boolean;\n paginationPosition?: \"top\" | \"bottom\";\n condensed?: boolean;\n isLoading?: boolean;\n defaultSort?: string;\n translateFn?: any;\n bulkActions?: any[];\n texts?: {\n columns?: string;\n searchPlaceholder?: string;\n item?: string;\n noData?: any;\n page?: string;\n filter?: string;\n of?: string;\n total?: string;\n goTo?: string;\n selectedRows?: string;\n bulkAction?: string;\n };\n};\n\ndeclare module \"@tanstack/table-core\" {\n interface ColumnMeta<TData extends RowData, TValue> {\n padding?: \"condensed\" | \"default\" | \"noPadding\";\n sortable?: boolean;\n hidden?: boolean;\n i18nKey?: string;\n }\n}\n\nconst LOCAL_STORAGE_KEY = \"@sikka/hawa/data-table-columns\";\n\nexport const DataTable = <DataProps extends {}>({\n columns,\n data,\n paginationPosition = \"bottom\",\n translateFn,\n resetSelection,\n enableHideColumns,\n enableSelection,\n enableFiltering,\n enableSearch,\n enableGoTo,\n ...props\n}: DataTableProps<DataProps>) => {\n const [sorting, setSorting] = React.useState<SortingState>(\n props.defaultSort ? [{ id: props.defaultSort, desc: false }] : [],\n );\n const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(\n [],\n );\n const [globalFilter, setGlobalFilter] = React.useState(\"\");\n const [expanded, setExpanded] = React.useState<ExpandedState>({});\n\n const [columnVisibility, setColumnVisibility] =\n React.useState<VisibilityState>(() => {\n const savedVisibility = localStorage.getItem(LOCAL_STORAGE_KEY);\n return savedVisibility ? JSON.parse(savedVisibility) : {};\n });\n\n const [rowSelection, setRowSelection] = React.useState({});\n const [selectedFilters, setSelectedFilters] = React.useState<string[]>([]);\n\n let mainColumns: ColumnDef<DataProps>[] = enableSelection\n ? [\n {\n id: \"select\",\n maxSize: 16,\n minSize: 16,\n size: 16,\n\n header: ({ table }) => (\n <Checkbox\n dir={props.direction}\n id=\"select_all\"\n aria-label=\"Select all\"\n className={props.direction === \"rtl\" ? \"hawa-ms-4\" : \"hawa-me-0\"}\n checked={\n table.getIsAllPageRowsSelected() ||\n (table.getIsSomePageRowsSelected() && \"indeterminate\")\n }\n onCheckedChange={(value) =>\n table.toggleAllPageRowsSelected(!!value)\n }\n />\n ),\n cell: ({ row }) => (\n <Checkbox\n dir={props.direction}\n id=\"select_row\"\n className={props.direction === \"rtl\" ? \"hawa-ms-4\" : \"hawa-me-4\"}\n checked={row.getIsSelected()}\n onCheckedChange={(value) => row.toggleSelected(!!value)}\n aria-label=\"Select row\"\n />\n ),\n enableSorting: false,\n enableHiding: false,\n },\n ...columns,\n ]\n : columns;\n const table = useReactTable({\n data,\n columns: mainColumns,\n onExpandedChange: setExpanded,\n getExpandedRowModel: getExpandedRowModel(),\n onGlobalFilterChange: setGlobalFilter,\n onSortingChange: setSorting,\n onColumnFiltersChange: setColumnFilters,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: getPaginationRowModel(),\n getSortedRowModel: getSortedRowModel(),\n getFilteredRowModel: getFilteredRowModel(),\n onColumnVisibilityChange: setColumnVisibility,\n onRowSelectionChange: setRowSelection,\n state: {\n sorting,\n columnFilters,\n columnVisibility,\n globalFilter,\n rowSelection,\n expanded,\n },\n });\n const pageText = props.texts?.page || \"page\";\n const itemsPerPageOptions = props.itemsPerPage?.map((item) => ({\n label: `${item} / ${pageText}`,\n value: item,\n }));\n\n React.useEffect(() => {\n localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(columnVisibility));\n }, [columnVisibility]);\n\n React.useEffect(() => {\n setRowSelection({});\n }, [resetSelection]);\n\n React.useEffect(() => {\n setColumnVisibility((prev) => {\n let newColumnVisibility: VisibilityState = {};\n columns.forEach((column: any) => {\n const savedVisibility = prev[column.accessorKey];\n if (savedVisibility !== undefined) {\n newColumnVisibility[column.accessorKey] = savedVisibility;\n } else {\n newColumnVisibility[column.accessorKey] = !column.meta?.hidden;\n }\n });\n return newColumnVisibility;\n });\n }, [columns]);\n\n React.useEffect(() => {\n props.filters?.forEach((filter) => {\n const activeFilter = selectedFilters.find(\n (selectedFilter) =>\n filter.accessorKey ===\n props.filters?.find((f) => f.value === selectedFilter)?.accessorKey,\n );\n table.getColumn(filter.accessorKey)?.setFilterValue(activeFilter || \"\");\n });\n }, [selectedFilters, props.filters]);\n\n return (\n <div className=\"hawa-flex hawa-w-full hawa-flex-col hawa-gap-4\">\n {(enableSearch || enableHideColumns) && (\n <div className=\"hawa-flex hawa-flex-row hawa-items-center hawa-gap-4\">\n {enableSearch && (\n <Input\n inputProps={{ title: \"\" }}\n forceHideHelperText\n placeholder={props.texts?.searchPlaceholder}\n value={globalFilter ?? \"\"}\n onChange={(event: any) => setGlobalFilter(event.target.value)}\n margin=\"none\"\n className=\"hawa-w-full md:hawa-max-w-sm\"\n endIconProps={{ className: \"!hawa-end-2\" }}\n endIcon={\n globalFilter ? (\n <Button\n onClick={() => setGlobalFilter(\"\")}\n variant={\"ghost\"}\n size={\"smallIcon\"}\n aria-label=\"Clear Search\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"hawa-icon hawa-text-muted-foreground\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </Button>\n ) : null\n }\n />\n )}\n {enableHideColumns && (\n <DropdownMenuRoot>\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"outline\"\n className=\"hawa-flex hawa-flex-row hawa-gap-2\"\n >\n {props.texts?.columns || \"Columns\"}\n <svg\n width=\"15\"\n height=\"15\"\n viewBox=\"0 0 15 15\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M5.5 3C4.67157 3 4 3.67157 4 4.5C4 5.32843 4.67157 6 5.5 6C6.32843 6 7 5.32843 7 4.5C7 3.67157 6.32843 3 5.5 3ZM3 5C3.01671 5 3.03323 4.99918 3.04952 4.99758C3.28022 6.1399 4.28967 7 5.5 7C6.71033 7 7.71978 6.1399 7.95048 4.99758C7.96677 4.99918 7.98329 5 8 5H13.5C13.7761 5 14 4.77614 14 4.5C14 4.22386 13.7761 4 13.5 4H8C7.98329 4 7.96677 4.00082 7.95048 4.00242C7.71978 2.86009 6.71033 2 5.5 2C4.28967 2 3.28022 2.86009 3.04952 4.00242C3.03323 4.00082 3.01671 4 3 4H1.5C1.22386 4 1 4.22386 1 4.5C1 4.77614 1.22386 5 1.5 5H3ZM11.9505 10.9976C11.7198 12.1399 10.7103 13 9.5 13C8.28967 13 7.28022 12.1399 7.04952 10.9976C7.03323 10.9992 7.01671 11 7 11H1.5C1.22386 11 1 10.7761 1 10.5C1 10.2239 1.22386 10 1.5 10H7C7.01671 10 7.03323 10.0008 7.04952 10.0024C7.28022 8.8601 8.28967 8 9.5 8C10.7103 8 11.7198 8.8601 11.9505 10.0024C11.9668 10.0008 11.9833 10 12 10H13.5C13.7761 10 14 10.2239 14 10.5C14 10.7761 13.7761 11 13.5 11H12C11.9833 11 11.9668 10.9992 11.9505 10.9976ZM8 10.5C8 9.67157 8.67157 9 9.5 9C10.3284 9 11 9.67157 11 10.5C11 11.3284 10.3284 12 9.5 12C8.67157 12 8 11.3284 8 10.5Z\"\n fill=\"currentColor\"\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n ></path>\n </svg>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align={props.direction === \"rtl\" ? \"start\" : \"end\"}\n >\n {table\n .getAllColumns()\n .filter((column) => column.getCanHide())\n .map((column) => {\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n checked={column.getIsVisible()}\n onCheckedChange={(value) =>\n column.toggleVisibility(!!value)\n }\n >\n {translateFn\n ? translateFn(\n column.columnDef.meta?.i18nKey\n ? column.columnDef.meta?.i18nKey\n : column.id,\n )\n : column.id}\n </DropdownMenuCheckboxItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenuRoot>\n )}\n </div>\n )}\n\n {enableFiltering && props.filters?.length && (\n <div className=\"hawa-flex-row hawa-gap-2 hawa-flex\">\n {props.filters?.map((filter) => {\n return (\n <Button\n variant=\"outline\"\n className={\n selectedFilters.includes(filter.value)\n ? \"!hawa-bg-primary !hawa-text-primary-foreground\"\n : \"\"\n }\n size=\"xs\"\n onClick={() => {\n let newSelectedFilters = selectedFilters.filter(\n (item) =>\n props.filters?.find((f) => f.value === item)\n ?.accessorKey !== filter.accessorKey,\n );\n\n if (!selectedFilters.includes(filter.value)) {\n newSelectedFilters.push(filter.value);\n table\n .getColumn(filter.accessorKey)\n ?.setFilterValue(filter.value);\n } else {\n table.getColumn(filter.accessorKey)?.setFilterValue(\"\");\n }\n setSelectedFilters(newSelectedFilters);\n }}\n >\n {filter.label}\n </Button>\n );\n })}\n </div>\n )}\n {props.isLoading ? (\n <Skeleton className=\"hawa-h-[130px] hawa-w-full\" />\n ) : (\n <div\n className={cn(\n \"hawa-flex hawa-w-full hawa-gap-4\",\n paginationPosition === \"top\"\n ? \"hawa-flex-col-reverse\"\n : \"hawa-flex-col\",\n )}\n >\n <div className=\"hawa-rounded-md\">\n <Table>\n {!props.hideHeader && table.getAllColumns().length > 0 && (\n <TableHeader>\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => {\n let isSortable = header.column.columnDef.meta?.sortable;\n return (\n <TableHead\n key={header.id}\n dir={props.direction}\n condensed={props.condensed}\n clickable={Boolean(isSortable)}\n style={{\n maxWidth: `${header.column.columnDef.maxSize}px !important`,\n minWidth: `${header.column.columnDef.minSize}px !important`,\n width: `${header.column.columnDef.size}px !important`,\n }}\n >\n {header.isPlaceholder\n ? null\n : flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n </TableHead>\n );\n })}\n </TableRow>\n ))}\n </TableHeader>\n )}\n <TableBody>\n {table.getRowModel().rows?.length ? (\n table.getRowModel().rows.map((row) => (\n <TableRow\n key={row.id}\n data-state={row.getIsSelected() && \"selected\"}\n >\n {row.getVisibleCells().map((cell) => (\n <TableCell\n key={cell.id}\n dir={props.direction}\n style={{\n maxWidth: `${cell.column.columnDef.maxSize}px !important`,\n minWidth: `${cell.column.columnDef.minSize}px !important`,\n width: `${cell.column.columnDef.size}px !important`,\n }}\n padding={\n props.condensed\n ? \"condensed\"\n : cell.column.columnDef.meta?.padding\n }\n >\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : (\n <TableRow>\n <TableCell\n colSpan={columns.length}\n className=\"hawa-h-24 hawa-text-center\"\n >\n {props.texts?.noData}\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n <div\n className={cn(\n \"hawa-flex hawa-justify-between hawa-gap-4 tablet:hawa-gap-0\",\n props.showSelectionCount\n ? \"hawa-flex-col tablet:hawa-flex-row\"\n : \"hawa-flex-col mobile:hawa-flex-row\",\n )}\n >\n {!props.showCount && (\n <div className=\"hawa-flex hawa-w-fit hawa-flex-row hawa-items-center hawa-gap-2 hawa-text-sm hawa-text-muted-foreground\"></div>\n )}\n\n {props.showCount ||\n (table.getFilteredSelectedRowModel().rows.length > 0 &&\n props.showSelectionCount) ? (\n <div className=\"hawa-flex hawa-flex-row hawa-h-auto hawa-gap-4\">\n <div className=\"hawa-flex hawa-flex-row hawa-h-auto hawa-items-center hawa-justify-between\">\n {/* CAPTION FOR CURRENT SELECTED ROWS */}\n {props.showCount && (\n <div\n className=\"hawa-text-muted-foreground hawa-text-sm\"\n dir={props.direction}\n >\n <span>{props.texts?.total}</span>{\" \"}\n <span>\n {table\n .getFilteredRowModel()\n .rows.length.toLocaleString()}\n </span>\n </div>\n )}\n {props.showCount &&\n table.getFilteredSelectedRowModel().rows.length > 0 &&\n props.showSelectionCount && (\n <div className=\"hawa-w-[0.5px] hawa-mx-2 hawa-bg-red-500 hawa-h-full\" />\n )}\n {table.getFilteredSelectedRowModel().rows.length > 0 &&\n props.showSelectionCount && (\n <div\n className=\"hawa-text-muted-foreground hawa-text-sm\"\n dir={props.direction}\n >\n {table.getFilteredSelectedRowModel().rows.length}{\" \"}\n {props.texts?.of}{\" \"}\n {table.getFilteredRowModel().rows.length}{\" \"}\n {props.texts?.selectedRows}\n </div>\n )}\n </div>\n {table.getFilteredSelectedRowModel().rows.length > 0 && (\n <div className=\"\">\n <DropdownMenu\n size=\"sm\"\n width=\"sm\"\n direction={props.direction}\n items={(props.bulkActions || []).map((action) => ({\n ...action,\n action: () =>\n action.action(\n table.getFilteredSelectedRowModel().rows,\n ),\n }))}\n trigger={\n <Button size=\"xs\">\n {props.texts?.bulkAction || \"Bulk Action\"}\n </Button>\n }\n />\n </div>\n )}\n </div>\n ) : null}\n {/* NEXT & PREV BUTTONS */}\n\n <div className=\"hawa-flex hawa-w-full hawa-flex-row hawa-items-center hawa-gap-2 hawa-bg--500 tablet:hawa-w-fit hawa-justify-between\">\n {enableGoTo && (\n <div className=\"hawa-flex hawa-flex-row hawa-items-center hawa-justify-center hawa-gap-2\">\n <span className=\"hawa-text-sm\">{props.texts?.goTo}</span>\n <input\n max={table.getPageCount()}\n min={0}\n type=\"number\"\n defaultValue={table.getState().pagination.pageIndex + 1}\n onChange={(e) => {\n let page = Number(e.target.value) - 1;\n const max = table.getPageCount();\n if (!isNaN(page) && Number(page) > max) {\n page = max - 1;\n }\n table.setPageIndex(page);\n }}\n className=\"hawa-w-16 hawa-rounded hawa-border hawa-p-1 hawa-px-2 hawa-text-sm placeholder:hawa-text-muted-foreground\"\n />\n </div>\n )}\n <DropdownMenu\n size=\"sm\"\n width=\"sm\"\n direction={props.direction}\n items={\n itemsPerPageOptions || [\n { label: `10 / ${pageText}`, value: 10 },\n { label: `20 / ${pageText}`, value: 20 },\n { label: `30 / ${pageText}`, value: 30 },\n { label: `40 / ${pageText}`, value: 40 },\n { label: `50 / ${pageText}`, value: 50 },\n ]\n }\n trigger={\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"hawa-h-fit hawa-w-fit hawa-p-0 hawa-px-2 hawa-py-1 hawa-whitespace-nowrap\"\n >\n {`${table.getState().pagination.pageSize} / ${\n props.texts?.page\n }`}\n </Button>\n }\n onItemSelect={(e: any) => table.setPageSize(Number(e))}\n />\n {table.getPageCount() > 1 && (\n <div className=\"hawa-bg--500 hawa-flex hawa-flex-row hawa-gap-2\">\n <div className=\"hawa-flex hawa-bg--500 hawa-w-fit hawa-flex-row hawa-items-center hawa-gap-2 hawa-text-sm\">\n <span className=\"hawa-flex hawa-items-center hawa-gap-1\">\n <div>{props.texts?.page}</div>\n <div className=\"hawa-flex hawa-flex-row hawa-gap-1\">\n <span className=\"hawa-font-bold\">\n {table.getState().pagination.pageIndex + 1}\n </span>\n <span>{props.texts?.of}</span>\n <span className=\"hawa-font-bold\">\n {table.getPageCount()}\n </span>\n </div>\n </span>\n </div>\n\n <div className=\"hawa-flex hawa-flex-row hawa-gap-2 hawa-items-center hawa-bg--500\">\n <Button\n aria-label=\"Next Table Page\"\n variant=\"outline\"\n size=\"smallIcon\"\n onClick={() => table.setPageIndex(0)}\n disabled={!table.getCanPreviousPage()}\n className={cn(\n props.direction === \"rtl\" && \"hawa-rotate-180\",\n )}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m11 17-5-5 5-5\" />\n <path d=\"m18 17-5-5 5-5\" />\n </svg>\n </Button>\n\n <Button\n aria-label=\"Previous Table Page\"\n variant=\"outline\"\n size=\"smallIcon\"\n onClick={() => table.previousPage()}\n disabled={!table.getCanPreviousPage()}\n className={cn(\n props.direction === \"rtl\" && \"hawa-rotate-180\",\n )}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n aria-label=\"Single Chevron Icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </Button>\n\n <Button\n aria-label=\"Next Table Page\"\n variant=\"outline\"\n size=\"smallIcon\"\n onClick={() => table.nextPage()}\n disabled={!table.getCanNextPage()}\n className={cn(\n props.direction === \"ltr\" && \"hawa-rotate-180\",\n )}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n aria-label=\"Single Chevron Icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </Button>\n <Button\n aria-label=\"Next Table Page\"\n variant=\"outline\"\n size=\"smallIcon\"\n onClick={() =>\n table.setPageIndex(table.getPageCount() - 1)\n }\n disabled={!table.getCanNextPage()}\n className={cn(\n props.direction === \"ltr\" && \"hawa-rotate-180\",\n )}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"m11 17-5-5 5-5\" />\n <path d=\"m18 17-5-5 5-5\" />\n </svg>\n </Button>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\ntype Palette = {\n name: string;\n colors: {\n [key: number]: string;\n };\n};\ntype Rgb = {\n r: number;\n g: number;\n b: number;\n};\nfunction hexToRgb(hex: string): Rgb | null {\n const sanitizedHex = hex.replaceAll(\"##\", \"#\");\n const colorParts = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(\n sanitizedHex\n );\n\n if (!colorParts) {\n return null;\n }\n\n const [, r, g, b] = colorParts;\n\n return {\n r: parseInt(r, 16),\n g: parseInt(g, 16),\n b: parseInt(b, 16)\n } as Rgb;\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n const toHex = (c: number) => `0${c.toString(16)}`.slice(-2);\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n}\n\nexport function getTextColor(color: string): \"#FFF\" | \"#333\" {\n const rgbColor = hexToRgb(color);\n\n if (!rgbColor) {\n return \"#333\";\n }\n\n const { r, g, b } = rgbColor;\n const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;\n\n return luma < 120 ? \"#FFF\" : \"#333\";\n}\n\nfunction lighten(hex: string, intensity: number): string {\n const color = hexToRgb(`#${hex}`);\n\n if (!color) {\n return \"\";\n }\n\n const r = Math.round(color.r + (255 - color.r) * intensity);\n const g = Math.round(color.g + (255 - color.g) * intensity);\n const b = Math.round(color.b + (255 - color.b) * intensity);\n\n return rgbToHex(r, g, b);\n}\n\nfunction darken(hex: string, intensity: number): string {\n const color = hexToRgb(hex);\n\n if (!color) {\n return \"\";\n }\n\n const r = Math.round(color.r * intensity);\n const g = Math.round(color.g * intensity);\n const b = Math.round(color.b * intensity);\n\n return rgbToHex(r, g, b);\n}\nconst parseColor = (color: any) => {\n if (color.startsWith(\"#\")) {\n // Convert hex to RGB\n let r = parseInt(color.slice(1, 3), 16);\n let g = parseInt(color.slice(3, 5), 16);\n let b = parseInt(color.slice(5, 7), 16);\n return [r, g, b];\n } else if (color.startsWith(\"rgb\")) {\n // Extract RGB values from rgb() format\n return color.match(/\\d+/g).map(Number);\n }\n // Default to white if format is unrecognized\n return [255, 255, 255];\n};\nexport const calculateLuminance = (color: any) => {\n const [r, g, b] = parseColor(color)?.map((c: any) => {\n c /= 255;\n return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n });\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n};\n\nfunction getPallette(baseColor: string): Palette {\n const name = baseColor;\n\n const response: Palette = {\n name,\n colors: {\n 500: `#${baseColor}`.replace(\"##\", \"#\")\n }\n };\n\n const intensityMap: {\n [key: number]: number;\n } = {\n 50: 0.95,\n 100: 0.9,\n 200: 0.75,\n 300: 0.6,\n 400: 0.3,\n 600: 0.9,\n 700: 0.75,\n 800: 0.6,\n 900: 0.49\n };\n\n [50, 100, 200, 300, 400].forEach((level) => {\n response.colors[level] = lighten(baseColor, intensityMap[level]);\n });\n [600, 700, 800, 900].forEach((level) => {\n response.colors[level] = darken(baseColor, intensityMap[level]);\n });\n\n return response as Palette;\n}\n\nexport { getPallette };\n\n// const hexToRgb = (hex) => {\n// let d = hex?.split(\"#\")[1];\n// var aRgbHex = d?.match(/.{1,2}/g);\n// var aRgb = [\n// parseInt(aRgbHex[0], 16),\n// parseInt(aRgbHex[1], 16),\n// parseInt(aRgbHex[2], 16)\n// ];\n// return aRgb;\n// };\n// const getTextColor = (backColor) => {\n// let rgbArray = hexToRgb(backColor);\n// if (rgbArray[0] * 0.299 + rgbArray[1] * 0.587 + rgbArray[2] * 0.114 > 186) {\n// return \"#000000\";\n// } else {\n// return \"#ffffff\";\n// }\n// };\n// const replaceAt = function (string, index, replacement) {\n// // if (replacement == \"\" || replacement == \" \") {\n// // return (\n// // string.substring(0, index) +\n// // string.substring(index + replacement.length )\n// // );\n// // }\n// const replaced = string.substring(0, index) + replacement + string.substring(index + 1)\n// return replaced\n// };\n\n// export { hexToRgb, getTextColor, replaceAt };\n","import * as React from \"react\";\n\nimport { cn } from \"@util/index\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { HelperText } from \"../helperText\";\nimport { Label, LabelProps } from \"../label\";\nimport { Loading } from \"../loading/Loading\";\n\nconst buttonVariants = cva(\n \"hawa-inline-flex hawa-items-center hawa-select-none hawa-rounded-md hawa-text-sm hawa-font-medium hawa-ring-offset-background hawa-transition-colors focus-visible:hawa-outline-none focus-visible:hawa-ring-2 focus-visible:hawa-ring-ring focus-visible:hawa-ring-offset-2 disabled:hawa-pointer-events-none disabled:hawa-opacity-50\",\n {\n variants: {\n variant: {\n default:\n \"hawa-bg-primary hawa-text-primary-foreground hover:hawa-bg-primary/90\",\n light: \"hawa-bg-primary/20 hawa-text-primary hover:hawa-bg-primary/40\",\n destructive:\n \"hawa-bg-destructive hawa-text-destructive-foreground hover:hawa-bg-destructive/90\",\n outline:\n \"hawa-border hawa-border-input hawa-bg-transparent hover:hawa-bg-accent hover:hawa-text-accent-foreground\",\n secondary:\n \"hawa-bg-secondary hawa-text-secondary-foreground hover:hawa-bg-secondary/80\",\n ghost: \"hover:hawa-bg-accent hover:hawa-text-accent-foreground\",\n link: \"hawa-text-primary hawa-underline-offset-4 hover:hawa-underline\",\n combobox: \"hawa-bg-background hawa-border\",\n neoBrutalism: \"neo-brutalism\",\n // \"hawa-cursor-pointer hawa-transition-all hawa-uppercase hawa-font-mono dark:hawa-bg-black hawa-font-bold hawa-py-2 hawa-px-4 hawa-rounded hawa-border-2 hawa-border-primary hawa-shadow-color-primary hawa-transition-[hawa-transform_50ms, hawa-box-shadow_50ms] active:hawa-translate-x-0.5 active:hawa-translate-y-0.5 active:hawa-shadow-color-primary-active shadow-color-primary active:shadow-color-primary-active\",\n },\n size: {\n default: \"hawa-h-10 hawa-px-4 hawa-py-2\",\n heightless: \"hawa-px-4 hawa-py-4\",\n xs: \"hawa-h-fit hawa-min-h-[25px] hawa-py-1 hawa-text-[10px] hawa-px-2 \",\n sm: \"hawa-h-9 hawa-text-[11px] hawa-rounded-md hawa-px-3\",\n lg: \"hawa-h-11 hawa-rounded-md hawa-px-8\",\n xl: \"hawa-h-14 hawa-rounded-md hawa-px-10\",\n icon: \"hawa-h-10 hawa-w-10\",\n smallIcon: \"hawa-h-7 hawa-w-7\",\n },\n },\n defaultVariants: { variant: \"default\", size: \"default\" },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n centered?: boolean;\n isLoading?: boolean;\n label?: string;\n labelProps?: LabelProps;\n /** The small red text under the input field to show validation. */\n helperText?: any;\n showHelperText?: boolean;\n /**\n * If true, the button will include a label and helper text. This is useful for forms where the button is part of the form.\n */\n asInput?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n label,\n variant,\n size,\n asChild = false,\n centered = true,\n isLoading,\n children,\n labelProps,\n showHelperText = false,\n asInput = false,\n ...props\n },\n ref,\n ) => {\n const Comp = \"button\";\n\n // Determine the color for the Loading component based on the variant\n const loadingColor =\n variant === \"outline\" || variant === \"ghost\" || variant === \"neoBrutalism\"\n ? \"hawa-bg-primary\"\n : \"hawa-bg-primary-foreground\";\n\n if (asInput) {\n return (\n <div className=\"hawa-flex hawa-flex-col hawa-gap-2\">\n {label && <Label {...labelProps}>{label}</Label>}\n <Comp\n className={cn(\n buttonVariants({ variant, size, className }),\n centered && \"hawa-justify-center\",\n )}\n ref={ref}\n {...props}\n >\n {isLoading ? (\n <Loading\n design={\n size === \"icon\" || size === \"smallIcon\"\n ? \"spinner\"\n : \"dots-pulse\"\n }\n themeMode={variant === \"outline\" ? \"light\" : \"dark\"}\n color={loadingColor}\n size={size === \"sm\" || size === \"xs\" ? \"xs\" : \"button\"}\n />\n ) : (\n children\n )}\n </Comp>\n {showHelperText && <HelperText helperText={props.helperText} />}\n </div>\n );\n } else {\n return (\n <Comp\n className={cn(\n buttonVariants({ variant, size, className }),\n centered && \"hawa-justify-center\",\n )}\n ref={ref}\n {...props}\n >\n {isLoading ? (\n <Loading\n design={\n size === \"icon\" || size === \"smallIcon\"\n ? \"spinner\"\n : \"dots-pulse\"\n }\n themeMode={variant === \"outline\" ? \"light\" : \"dark\"}\n color={loadingColor}\n size={size === \"sm\" || size === \"xs\" ? \"xs\" : \"button\"}\n />\n ) : (\n children\n )}\n </Comp>\n );\n }\n },\n);\n\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n","import React from \"react\";\n\nimport { cn } from \"@util/index\";\n\nexport const HelperText = ({ helperText }: { helperText?: any }) => (\n <p\n className={cn(\n \"hawa-my-0 hawa-text-start hawa-text-xs hawa-text-helper-color hawa-transition-all\",\n helperText ? \"hawa-h-4 hawa-opacity-100\" : \"hawa-h-0 hawa-opacity-0\",\n )}\n >\n {helperText}\n </p>\n);\n","import * as React from \"react\";\n\nimport { cn } from \"@util/index\";\n\nimport { PositionType } from \"@_types/commonTypes\";\n\nimport { Tooltip } from \"../tooltip\";\n\nexport type LabelProps = {\n hint?: React.ReactNode;\n hintSide?: PositionType;\n htmlFor?: string;\n required?: boolean;\n};\n\nconst Label = React.forwardRef<\n HTMLLabelElement,\n React.LabelHTMLAttributes<HTMLLabelElement> & LabelProps\n>(({ className, hint, hintSide, required, children, ...props }, ref) => (\n <div className=\"hawa-flex hawa-flex-row hawa-items-center hawa-gap-1 hawa-transition-all\">\n <label\n ref={ref}\n className={cn(\n \"hawa-text-sm hawa-font-medium hawa-leading-none peer-disabled:hawa-cursor-not-allowed peer-disabled:hawa-opacity-70\",\n className,\n )}\n {...props}\n >\n {children}\n {required && <span className=\"hawa-mx-0.5 hawa-text-red-500\">*</span>}\n </label>\n {hint && (\n <Tooltip\n content={hint}\n side={hintSide}\n triggerProps={{\n tabIndex: -1,\n onClick: (event) => event.preventDefault(),\n }}\n >\n <div>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"hawa-h-[14px] hawa-w-[14px] hawa-cursor-help\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\" />\n <path d=\"M12 17h.01\" />\n </svg>\n </div>\n </Tooltip>\n )}\n </div>\n));\n\nLabel.displayName = \"Label\";\n\nexport { Label };\n","import React from \"react\";\n\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { cn } from \"@util/index\";\n\nimport { PositionType } from \"@_types/commonTypes\";\n\nconst TooltipContent = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {\n size?: \"default\" | \"small\" | \"large\";\n }\n>(({ className, sideOffset = 4, size = \"default\", ...props }, ref) => (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"hawa-z-50 hawa-overflow-hidden hawa-rounded-md hawa-border hawa-bg-popover hawa-px-3 hawa-py-1.5 hawa-text-sm hawa-text-popover-foreground hawa-shadow-md hawa-animate-in hawa-fade-in-0 hawa-zoom-in-95 data-[state=closed]:hawa-animate-out data-[state=closed]:hawa-fade-out-0 data-[state=closed]:hawa-zoom-out-95 data-[side=bottom]:hawa-slide-in-from-top-2 data-[side=left]:hawa-slide-in-from-right-2 data-[side=right]:hawa-slide-in-from-left-2 data-[side=top]:hawa-slide-in-from-bottom-2\",\n {\n \"hawa-text-xs\": size === \"small\",\n \"hawa-text-xl\": size === \"large\",\n },\n className,\n )}\n {...props}\n />\n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\n\nconst TooltipArrow = React.forwardRef<\n React.ElementRef<typeof TooltipPrimitive.Arrow>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>\n>(({ className, ...props }, ref) => (\n <TooltipPrimitive.Arrow ref={ref} className={cn(className)} {...props} />\n));\nTooltipArrow.displayName = TooltipPrimitive.Arrow.displayName;\n\ntype TooltipTypes = {\n /** Controls the open state of the tooltip. */\n open?: any;\n /** Specifies the side where the tooltip will appear. */\n side?: PositionType;\n /** Content to be displayed within the tooltip. */\n content?: any;\n /** Elements to which the tooltip is anchored. */\n children?: any;\n /** Sets the default open state of the tooltip. */\n defaultOpen?: any;\n /** Event handler for open state changes. */\n onOpenChange?: any;\n /** Duration of the delay before the tooltip appears. */\n delayDuration?: any;\n /** Size of the tooltip. */\n size?: \"default\" | \"small\" | \"large\";\n /** Disables the tooltip. */\n disabled?: boolean;\n triggerProps?: TooltipPrimitive.TooltipTriggerProps;\n contentProps?: TooltipPrimitive.TooltipContentProps;\n providerProps?: TooltipPrimitive.TooltipProps;\n};\n\nconst Tooltip: React.FunctionComponent<TooltipTypes> = ({\n side,\n size,\n open,\n content,\n children,\n disabled,\n defaultOpen,\n onOpenChange,\n triggerProps,\n contentProps,\n providerProps,\n delayDuration = 300,\n ...props\n}) => {\n return (\n <TooltipPrimitive.TooltipProvider\n delayDuration={delayDuration}\n {...providerProps}\n >\n <TooltipPrimitive.Root\n open={!disabled && open}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n {...props}\n >\n <TooltipPrimitive.Trigger {...triggerProps}>\n {children}\n </TooltipPrimitive.Trigger>\n <TooltipContent\n size={size}\n side={side}\n align=\"center\"\n {...contentProps}\n style={{\n ...contentProps?.style,\n maxWidth: \"var(--radix-tooltip-content-available-width)\",\n maxHeight: \"var(--radix-tooltip-content-available-height)\",\n }}\n >\n {content}\n </TooltipContent>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.TooltipProvider>\n );\n};\n\nexport { Tooltip };\n","import React, { FC } from \"react\";\n\nimport { cn } from \"@util/index\";\n\ntype LoadingTypes = {\n /** Specifies the size of the loading component.*/\n size?: \"button\" | \"xs\" | \"sm\" | \"normal\" | \"lg\" | \"xl\";\n /** Determines the design of the loading animation.*/\n design?:\n | \"spinner\"\n | \"dots-bounce\"\n | \"dots-pulse\"\n | \"pulse\"\n | \"spinner-dots\"\n | \"squircle\"\n | \"square\"\n | \"progress\"\n | \"orbit\";\n /** Specifies the color of the loading component. By default it will inherit the value of --primary global CSS variable*/\n color?: string;\n classNames?: {\n container?: string;\n track?: string;\n car?: string;\n };\n themeMode?: \"dark\" | \"light\";\n};\n\nexport const Loading: FC<LoadingTypes> = ({\n design = \"spinner\",\n size = \"normal\",\n themeMode = \"light\",\n classNames,\n color,\n ...props\n}) => {\n let sizeStyles = {\n button: \"hawa-h-4 hawa-w-4\",\n xs: \"hawa-h-1 hawa-w-1\",\n sm: \"hawa-h-6 hawa-w-6\",\n normal: \"hawa-h-8 hawa-w-8\",\n lg: \"hawa-h-14 hawa-w-14\",\n xl: \"hawa-h-24 hawa-w-24\",\n };\n let progressSizes = {\n button: \"hawa-h-1\",\n xs: \"hawa-h-1 hawa-w-1\",\n sm: \"hawa-h-6 hawa-w-6\",\n normal: \"\",\n lg: \"hawa-h-6\",\n xl: \"hawa-h-10 hawa-w-64\",\n };\n\n let animationStyles: any = {\n pulse: \"hawa-animate-in hawa-fade-in hawa-duration-1000\",\n bounce: \"hawa-animate-bounce\",\n };\n switch (design.split(\"-\")[0]) {\n case \"dots\":\n return (\n <div\n className={cn(\n \"hawa-flex hawa-flex-row hawa-gap-2\",\n classNames?.container,\n )}\n >\n <div\n className={cn(\n \"hawa-animate-bounce hawa-rounded-full hawa-delay-100 hawa-repeat-infinite\",\n size === \"button\" ? \"hawa-h-2 hawa-w-2\" : sizeStyles[size],\n animationStyles[design.split(\"-\")[1]],\n color ? color : \"hawa-bg-primary\",\n )}\n ></div>\n <div\n className={cn(\n \"hawa-animate-bounce hawa-rounded-full hawa-delay-200 hawa-repeat-infinite\",\n size === \"button\" ? \"hawa-h-2 hawa-w-2\" : sizeStyles[size],\n animationStyles[design.split(\"-\")[1]],\n color ? color : \"hawa-bg-primary\",\n )}\n ></div>\n <div\n className={cn(\n \"hawa-animate-bounce hawa-rounded-full hawa-delay-300 hawa-repeat-infinite\",\n size === \"button\" ? \"hawa-h-2 hawa-w-2\" : sizeStyles[size],\n animationStyles[design.split(\"-\")[1]],\n color ? color : \"hawa-bg-primary\",\n )}\n ></div>\n </div>\n );\n case \"square\":\n return (\n <svg\n className={cn(\n \"squircle-container\",\n sizeStyles[size],\n classNames?.container,\n )}\n viewBox=\"0 0 35 35\"\n height=\"35\"\n width=\"35\"\n >\n <rect\n className=\"squircle-track\"\n x=\"2.5\"\n y=\"2.5\"\n fill=\"none\"\n strokeWidth=\"5px\"\n width=\"32.5\"\n height=\"32.5\"\n />\n <rect\n className=\"square-car\"\n x=\"2.5\"\n y=\"2.5\"\n fill=\"none\"\n strokeWidth=\"5px\"\n width=\"32.5\"\n height=\"32.5\"\n pathLength=\"100\"\n />\n </svg>\n );\n case \"squircle\":\n return (\n <svg\n x=\"0px\"\n y=\"0px\"\n viewBox=\"0 0 37 37\"\n height=\"37\"\n width=\"37\"\n preserveAspectRatio=\"xMidYMid meet\"\n className={cn(\n \"squircle-container\",\n sizeStyles[size],\n classNames?.container,\n )}\n >\n <path\n className={cn(\"squircle-track\", classNames?.track)}\n fill=\"none\"\n strokeWidth=\"5\"\n pathLength=\"100\"\n d=\"M0.37 18.5 C0.37 5.772 5.772 0.37 18.5 0.37 S36.63 5.772 36.63 18.5 S31.228 36.63 18.5 36.63 S0.37 31.228 0.37 18.5\"\n ></path>\n <path\n className={cn(\"squircle-car\", classNames?.car)}\n fill=\"none\"\n strokeWidth=\"5\"\n pathLength=\"100\"\n d=\"M0.37 18.5 C0.37 5.772 5.772 0.37 18.5 0.37 S36.63 5.772 36.63 18.5 S31.228 36.63 18.5 36.63 S0.37 31.228 0.37 18.5\"\n ></path>\n </svg>\n );\n case \"progress\":\n return (\n <div\n className={cn(\n \"progress-loading after:hawa-rounded hawa-rounded\",\n progressSizes[size],\n classNames?.container,\n )}\n ></div>\n );\n case \"orbit\":\n return (\n <div className={cn(\"orbit-container\", classNames?.container)}></div>\n );\n\n default:\n return (\n <svg\n viewBox=\"0 0 40 40\"\n height=\"40\"\n width=\"40\"\n className={cn(\n \"circle-container\",\n sizeStyles[size],\n classNames?.container,\n )}\n >\n <circle\n className={cn(\n \"circle-track\",\n {\n \"hawa-stroke-primary-foreground\": themeMode === \"dark\",\n \"hawa-stroke-primary\": themeMode === \"light\",\n },\n classNames?.track,\n )}\n cx=\"20\"\n cy=\"20\"\n r=\"17.5\"\n fill=\"none\"\n strokeWidth=\"5px\"\n pathLength=\"100\"\n />\n <circle\n className={cn(\n \"circle-car\",\n {\n \"hawa-stroke-primary-foreground\": themeMode === \"dark\",\n \"hawa-stroke-primary\": themeMode === \"light\",\n },\n class