warqadui 0.0.4 → 0.0.6

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 (179) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/apps/dev-app/.env +1 -0
  3. package/apps/dev-app/errors.log +0 -0
  4. package/apps/dev-app/index.html +12 -0
  5. package/apps/dev-app/node_modules/.vite/deps/@tanstack_react-table.js +3254 -0
  6. package/apps/dev-app/node_modules/.vite/deps/@tanstack_react-table.js.map +7 -0
  7. package/apps/dev-app/node_modules/.vite/deps/_metadata.json +178 -0
  8. package/apps/dev-app/node_modules/.vite/deps/antd.js +108982 -0
  9. package/apps/dev-app/node_modules/.vite/deps/antd.js.map +7 -0
  10. package/apps/dev-app/node_modules/.vite/deps/axios.js +2751 -0
  11. package/apps/dev-app/node_modules/.vite/deps/axios.js.map +7 -0
  12. package/apps/dev-app/node_modules/.vite/deps/chunk-5OG7DCD7.js +41 -0
  13. package/apps/dev-app/node_modules/.vite/deps/chunk-5OG7DCD7.js.map +7 -0
  14. package/apps/dev-app/node_modules/.vite/deps/chunk-7YRZYZRE.js +7807 -0
  15. package/apps/dev-app/node_modules/.vite/deps/chunk-7YRZYZRE.js.map +7 -0
  16. package/apps/dev-app/node_modules/.vite/deps/chunk-DC5AMYBS.js +39 -0
  17. package/apps/dev-app/node_modules/.vite/deps/chunk-DC5AMYBS.js.map +7 -0
  18. package/apps/dev-app/node_modules/.vite/deps/chunk-DKXRQMOD.js +135 -0
  19. package/apps/dev-app/node_modules/.vite/deps/chunk-DKXRQMOD.js.map +7 -0
  20. package/apps/dev-app/node_modules/.vite/deps/chunk-EL47BWQR.js +37 -0
  21. package/apps/dev-app/node_modules/.vite/deps/chunk-EL47BWQR.js.map +7 -0
  22. package/apps/dev-app/node_modules/.vite/deps/chunk-HHL3MHGV.js +288 -0
  23. package/apps/dev-app/node_modules/.vite/deps/chunk-HHL3MHGV.js.map +7 -0
  24. package/apps/dev-app/node_modules/.vite/deps/chunk-IGGUWUPT.js +60 -0
  25. package/apps/dev-app/node_modules/.vite/deps/chunk-IGGUWUPT.js.map +7 -0
  26. package/apps/dev-app/node_modules/.vite/deps/chunk-IGXZPJXT.js +928 -0
  27. package/apps/dev-app/node_modules/.vite/deps/chunk-IGXZPJXT.js.map +7 -0
  28. package/apps/dev-app/node_modules/.vite/deps/chunk-L2GCM37S.js +21628 -0
  29. package/apps/dev-app/node_modules/.vite/deps/chunk-L2GCM37S.js.map +7 -0
  30. package/apps/dev-app/node_modules/.vite/deps/chunk-LDRT62EN.js +14806 -0
  31. package/apps/dev-app/node_modules/.vite/deps/chunk-LDRT62EN.js.map +7 -0
  32. package/apps/dev-app/node_modules/.vite/deps/chunk-M7DZDBHW.js +14 -0
  33. package/apps/dev-app/node_modules/.vite/deps/chunk-M7DZDBHW.js.map +7 -0
  34. package/apps/dev-app/node_modules/.vite/deps/chunk-S54SBVCU.js +1906 -0
  35. package/apps/dev-app/node_modules/.vite/deps/chunk-S54SBVCU.js.map +7 -0
  36. package/apps/dev-app/node_modules/.vite/deps/chunk-WFNHCR67.js +21 -0
  37. package/apps/dev-app/node_modules/.vite/deps/chunk-WFNHCR67.js.map +7 -0
  38. package/apps/dev-app/node_modules/.vite/deps/clsx.js +10 -0
  39. package/apps/dev-app/node_modules/.vite/deps/clsx.js.map +7 -0
  40. package/apps/dev-app/node_modules/.vite/deps/dayjs.js +6 -0
  41. package/apps/dev-app/node_modules/.vite/deps/dayjs.js.map +7 -0
  42. package/apps/dev-app/node_modules/.vite/deps/dayjs_plugin_customParseFormat.js +6 -0
  43. package/apps/dev-app/node_modules/.vite/deps/dayjs_plugin_customParseFormat.js.map +7 -0
  44. package/apps/dev-app/node_modules/.vite/deps/framer-motion.js +12388 -0
  45. package/apps/dev-app/node_modules/.vite/deps/framer-motion.js.map +7 -0
  46. package/apps/dev-app/node_modules/.vite/deps/html2canvas-pro.js +9713 -0
  47. package/apps/dev-app/node_modules/.vite/deps/html2canvas-pro.js.map +7 -0
  48. package/apps/dev-app/node_modules/.vite/deps/html2canvas.esm-VL7GM4AH.js +8 -0
  49. package/apps/dev-app/node_modules/.vite/deps/html2canvas.esm-VL7GM4AH.js.map +7 -0
  50. package/apps/dev-app/node_modules/.vite/deps/index.es-3WTXOFZ2.js +10392 -0
  51. package/apps/dev-app/node_modules/.vite/deps/index.es-3WTXOFZ2.js.map +7 -0
  52. package/apps/dev-app/node_modules/.vite/deps/jspdf.js +41 -0
  53. package/apps/dev-app/node_modules/.vite/deps/jspdf.js.map +7 -0
  54. package/apps/dev-app/node_modules/.vite/deps/lucide-react.js +31586 -0
  55. package/apps/dev-app/node_modules/.vite/deps/lucide-react.js.map +7 -0
  56. package/apps/dev-app/node_modules/.vite/deps/package.json +3 -0
  57. package/apps/dev-app/node_modules/.vite/deps/purify.es-JNLDEIMX.js +1029 -0
  58. package/apps/dev-app/node_modules/.vite/deps/purify.es-JNLDEIMX.js.map +7 -0
  59. package/apps/dev-app/node_modules/.vite/deps/react-dom.js +7 -0
  60. package/apps/dev-app/node_modules/.vite/deps/react-dom.js.map +7 -0
  61. package/apps/dev-app/node_modules/.vite/deps/react-dom_client.js +8 -0
  62. package/apps/dev-app/node_modules/.vite/deps/react-dom_client.js.map +7 -0
  63. package/apps/dev-app/node_modules/.vite/deps/react-hook-form.js +2233 -0
  64. package/apps/dev-app/node_modules/.vite/deps/react-hook-form.js.map +7 -0
  65. package/apps/dev-app/node_modules/.vite/deps/react-phone-number-input.js +9307 -0
  66. package/apps/dev-app/node_modules/.vite/deps/react-phone-number-input.js.map +7 -0
  67. package/apps/dev-app/node_modules/.vite/deps/react-router-dom.js +14234 -0
  68. package/apps/dev-app/node_modules/.vite/deps/react-router-dom.js.map +7 -0
  69. package/apps/dev-app/node_modules/.vite/deps/react-to-pdf.js +268 -0
  70. package/apps/dev-app/node_modules/.vite/deps/react-to-pdf.js.map +7 -0
  71. package/apps/dev-app/node_modules/.vite/deps/react.js +6 -0
  72. package/apps/dev-app/node_modules/.vite/deps/react.js.map +7 -0
  73. package/apps/dev-app/node_modules/.vite/deps/react_jsx-dev-runtime.js +913 -0
  74. package/apps/dev-app/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
  75. package/apps/dev-app/node_modules/.vite/deps/react_jsx-runtime.js +7 -0
  76. package/apps/dev-app/node_modules/.vite/deps/react_jsx-runtime.js.map +7 -0
  77. package/apps/dev-app/node_modules/.vite/deps/tailwind-merge.js +2534 -0
  78. package/apps/dev-app/node_modules/.vite/deps/tailwind-merge.js.map +7 -0
  79. package/apps/dev-app/node_modules/tailwindcss/LICENSE +21 -0
  80. package/apps/dev-app/node_modules/tailwindcss/README.md +36 -0
  81. package/apps/dev-app/node_modules/tailwindcss/dist/chunk-L5IEUH3R.mjs +38 -0
  82. package/apps/dev-app/node_modules/tailwindcss/dist/chunk-UWKE2Z6N.mjs +1 -0
  83. package/apps/dev-app/node_modules/tailwindcss/dist/chunk-X4GG3EDV.mjs +1 -0
  84. package/apps/dev-app/node_modules/tailwindcss/dist/colors-C__qRT83.d.ts +347 -0
  85. package/apps/dev-app/node_modules/tailwindcss/dist/colors.d.mts +347 -0
  86. package/apps/dev-app/node_modules/tailwindcss/dist/colors.d.ts +5 -0
  87. package/apps/dev-app/node_modules/tailwindcss/dist/colors.js +1 -0
  88. package/apps/dev-app/node_modules/tailwindcss/dist/colors.mjs +1 -0
  89. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.d.mts +1199 -0
  90. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.d.ts +1199 -0
  91. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.js +1 -0
  92. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.mjs +1 -0
  93. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.d.mts +6 -0
  94. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.d.ts +6 -0
  95. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.js +3 -0
  96. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.mjs +1 -0
  97. package/apps/dev-app/node_modules/tailwindcss/dist/lib.d.mts +378 -0
  98. package/apps/dev-app/node_modules/tailwindcss/dist/lib.d.ts +3 -0
  99. package/apps/dev-app/node_modules/tailwindcss/dist/lib.js +38 -0
  100. package/apps/dev-app/node_modules/tailwindcss/dist/lib.mjs +1 -0
  101. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.d.mts +11 -0
  102. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.d.ts +134 -0
  103. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.js +1 -0
  104. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.mjs +1 -0
  105. package/apps/dev-app/node_modules/tailwindcss/dist/resolve-config-B4yBzhca.d.ts +29 -0
  106. package/apps/dev-app/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.mts +190 -0
  107. package/apps/dev-app/node_modules/tailwindcss/dist/types-CJYAW1ql.d.mts +128 -0
  108. package/apps/dev-app/node_modules/tailwindcss/index.css +944 -0
  109. package/apps/dev-app/node_modules/tailwindcss/package.json +89 -0
  110. package/apps/dev-app/node_modules/tailwindcss/preflight.css +393 -0
  111. package/apps/dev-app/node_modules/tailwindcss/theme.css +510 -0
  112. package/apps/dev-app/node_modules/tailwindcss/utilities.css +1 -0
  113. package/apps/dev-app/package.json +35 -0
  114. package/apps/dev-app/src/App.tsx +74 -0
  115. package/apps/dev-app/src/index.css +18 -0
  116. package/apps/dev-app/src/main.tsx +18 -0
  117. package/apps/dev-app/src/pages/Buttons.tsx +122 -0
  118. package/apps/dev-app/src/pages/DataTable.tsx +208 -0
  119. package/apps/dev-app/src/pages/Fields.tsx +342 -0
  120. package/apps/dev-app/src/pages/Modals.tsx +151 -0
  121. package/apps/dev-app/src/pages/Spins.tsx +161 -0
  122. package/apps/dev-app/ts_errors.txt +0 -0
  123. package/apps/dev-app/tsconfig.json +25 -0
  124. package/apps/dev-app/tsconfig.node.json +10 -0
  125. package/apps/dev-app/vite.config.ts +11 -0
  126. package/package.json +10 -49
  127. package/packages/ui/dist/index.d.mts +356 -0
  128. package/packages/ui/dist/index.d.ts +356 -0
  129. package/packages/ui/dist/index.js +2296 -0
  130. package/packages/ui/dist/index.mjs +2249 -0
  131. package/packages/ui/dist/styles.js +26 -0
  132. package/packages/ui/dist/styles.mjs +24 -0
  133. package/packages/ui/log.txt +0 -0
  134. package/packages/ui/package.json +68 -0
  135. package/packages/ui/postcss.config.js +6 -0
  136. package/packages/ui/src/components/Button.tsx +85 -0
  137. package/packages/ui/src/components/Card.tsx +97 -0
  138. package/packages/ui/src/components/CodeBlock.tsx +53 -0
  139. package/packages/ui/src/components/DashboardLayout.tsx +442 -0
  140. package/packages/ui/src/components/Fields/Input.tsx +191 -0
  141. package/packages/ui/src/components/Fields/PhoneInput.tsx +134 -0
  142. package/packages/ui/src/components/Fields/date.tsx +165 -0
  143. package/packages/ui/src/components/Fields/index.tsx +17 -0
  144. package/packages/ui/src/components/Fields/searchApi.tsx +479 -0
  145. package/packages/ui/src/components/Fields/select.tsx +131 -0
  146. package/packages/ui/src/components/Fields/textArea.tsx +121 -0
  147. package/packages/ui/src/components/LoadingBox.tsx +11 -0
  148. package/packages/ui/src/components/PageHeader.tsx +34 -0
  149. package/packages/ui/src/components/ThemeToggle.tsx +35 -0
  150. package/packages/ui/src/components/modal/Modal.tsx +81 -0
  151. package/packages/ui/src/components/spins/ClassicSpin.tsx +18 -0
  152. package/packages/ui/src/components/spins/LoadingSpin.tsx +45 -0
  153. package/packages/ui/src/components/spins/OverlaySpin.tsx +10 -0
  154. package/packages/ui/src/components/spins/index.tsx +13 -0
  155. package/packages/ui/src/components/tables/DataTable.tsx +261 -0
  156. package/packages/ui/src/components/tables/index.ts +1 -0
  157. package/packages/ui/src/hooks/Fetches/useApis.tsx +197 -0
  158. package/packages/ui/src/hooks/ThemeContext.tsx +56 -0
  159. package/packages/ui/src/hooks/useModal.tsx +38 -0
  160. package/packages/ui/src/hooks/useTheme.ts +34 -0
  161. package/packages/ui/src/index.ts +24 -0
  162. package/packages/ui/src/providers/WarqadProvider.tsx +69 -0
  163. package/packages/ui/src/styles.css +26 -0
  164. package/packages/ui/src/utils/cn.ts +6 -0
  165. package/packages/ui/src/utils/pdf.ts +171 -0
  166. package/packages/ui/tailwind.config.js +13 -0
  167. package/packages/ui/tsconfig.json +17 -0
  168. package/packages/ui/warqad-ui-0.0.1.tgz +0 -0
  169. package/packages/ui/warqadui-0.0.3.tgz +0 -0
  170. package/warqad-ui-0.0.1.tgz +0 -0
  171. package/dist/index.d.mts +0 -35
  172. package/dist/index.d.ts +0 -35
  173. package/dist/index.js +0 -470
  174. package/dist/index.mjs +0 -440
  175. package/dist/styles.js +0 -26
  176. package/dist/styles.mjs +0 -24
  177. /package/{dist → packages/ui/dist}/index.css +0 -0
  178. /package/{dist → packages/ui/dist}/styles.d.mts +0 -0
  179. /package/{dist → packages/ui/dist}/styles.d.ts +0 -0
@@ -0,0 +1,2249 @@
1
+ // src/utils/cn.ts
2
+ import { clsx } from "clsx";
3
+ import { twMerge } from "tailwind-merge";
4
+ function cn(...inputs) {
5
+ return twMerge(clsx(inputs));
6
+ }
7
+
8
+ // src/components/Button.tsx
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var Button = ({
11
+ children,
12
+ className,
13
+ variant = "primary",
14
+ size = "md",
15
+ isLoading,
16
+ icon,
17
+ ...props
18
+ }) => {
19
+ const variants = {
20
+ primary: "bg-[#007AFF] text-white hover:bg-[#0071e3] active:scale-[0.98] active:opacity-90 shadow-[0_1px_2px_rgba(0,0,0,0.1)] focus:ring-[#007AFF]",
21
+ secondary: "bg-[#F5F5F7] text-[#1D1D1F] hover:bg-[#E8E8ED] dark:bg-[#FFFFFF]/10 dark:text-[#F5F5F7] dark:hover:bg-[#FFFFFF]/15 active:scale-[0.98] focus:ring-gray-400",
22
+ outline: "border border-gray-200 dark:border-gray-800 bg-white/50 dark:bg-black/50 backdrop-blur-md text-[#1D1D1F] dark:text-white hover:bg-gray-50 dark:hover:bg-gray-900 active:scale-[0.98] focus:ring-gray-400",
23
+ ghost: "bg-transparent text-[#007AFF] hover:bg-[#007AFF]/10 active:scale-[0.98] focus:ring-[#007AFF]",
24
+ danger: "bg-[#FF3B30] text-white hover:bg-[#E03126] active:scale-[0.98] active:opacity-90 shadow-[0_1px_2px_rgba(0,0,0,0.1)] focus:ring-[#FF3B30]",
25
+ warning: "bg-[#FF9500] text-white hover:bg-[#E68600] active:scale-[0.98] active:opacity-90 shadow-[0_1px_2px_rgba(0,0,0,0.1)] focus:ring-[#FF9500]"
26
+ };
27
+ const sizes = {
28
+ sm: "px-3 py-1.5 text-sm rounded-[10px] gap-1.5 font-medium",
29
+ md: "px-5 py-2.5 rounded-[12px] gap-2 font-medium tracking-tight",
30
+ lg: "px-7 py-3.5 text-lg rounded-[16px] font-semibold tracking-tight gap-2.5"
31
+ };
32
+ return /* @__PURE__ */ jsxs(
33
+ "button",
34
+ {
35
+ className: cn(
36
+ "inline-flex items-center justify-center transition-all duration-200 ease-out focus:outline-none focus:ring-2 focus:ring-offset-1 disabled:opacity-50 select-none cursor-pointer disabled:cursor-not-allowed",
37
+ variants[variant],
38
+ sizes[size],
39
+ className
40
+ ),
41
+ disabled: isLoading || props.disabled,
42
+ ...props,
43
+ children: [
44
+ isLoading ? /* @__PURE__ */ jsxs(
45
+ "svg",
46
+ {
47
+ className: "animate-spin -ml-1 mr-2 h-4 w-4",
48
+ fill: "none",
49
+ viewBox: "0 0 24 24",
50
+ xmlns: "http://www.w3.org/2000/svg",
51
+ children: [
52
+ /* @__PURE__ */ jsx(
53
+ "circle",
54
+ {
55
+ className: "opacity-25",
56
+ cx: "12",
57
+ cy: "12",
58
+ r: "10",
59
+ stroke: "currentColor",
60
+ strokeWidth: "4"
61
+ }
62
+ ),
63
+ /* @__PURE__ */ jsx(
64
+ "path",
65
+ {
66
+ className: "opacity-75",
67
+ fill: "currentColor",
68
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
69
+ }
70
+ )
71
+ ]
72
+ }
73
+ ) : icon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: icon }),
74
+ children
75
+ ]
76
+ }
77
+ );
78
+ };
79
+
80
+ // src/components/DashboardLayout.tsx
81
+ import { useState, useEffect, useRef } from "react";
82
+ import { useLocation, useNavigate } from "react-router-dom";
83
+ import { Menu, ChevronDown, ChevronRight } from "lucide-react";
84
+ import { motion, AnimatePresence } from "framer-motion";
85
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
86
+ var useMediaQuery = (query) => {
87
+ const [matches, setMatches] = useState(() => {
88
+ if (typeof window !== "undefined") {
89
+ return window.matchMedia(query).matches;
90
+ }
91
+ return false;
92
+ });
93
+ useEffect(() => {
94
+ const media = window.matchMedia(query);
95
+ if (media.matches !== matches) {
96
+ setMatches(media.matches);
97
+ }
98
+ const listener = () => setMatches(media.matches);
99
+ media.addEventListener("change", listener);
100
+ return () => media.removeEventListener("change", listener);
101
+ }, [matches, query]);
102
+ return matches;
103
+ };
104
+ var isPathActive = (navPath, currentPath) => {
105
+ if (!navPath || !currentPath) return false;
106
+ return currentPath === navPath || navPath !== "/" && currentPath.startsWith(`${navPath}/`);
107
+ };
108
+ var SidebarItem = ({
109
+ item,
110
+ isActive,
111
+ isChildActive,
112
+ onClick,
113
+ isExpanded,
114
+ onToggleExpand,
115
+ isSidebarCollapsed
116
+ }) => {
117
+ const hasSubItems = item.subItems && item.subItems.length > 0;
118
+ const shouldHighlight = isActive || hasSubItems && isExpanded || isChildActive;
119
+ return /* @__PURE__ */ jsxs2("div", { className: "mb-1 group relative ", children: [
120
+ /* @__PURE__ */ jsxs2(
121
+ "button",
122
+ {
123
+ type: "button",
124
+ onClick: item.disabled ? void 0 : hasSubItems ? onToggleExpand : onClick,
125
+ disabled: item.disabled,
126
+ title: isSidebarCollapsed ? item.label : void 0,
127
+ className: cn(
128
+ "w-full flex items-center py-2.5 rounded-xl text-sm font-medium transition-all duration-200",
129
+ isSidebarCollapsed ? "justify-center px-2" : "justify-between px-3",
130
+ shouldHighlight && !item.disabled ? "bg-blue-50 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400" : "text-gray-600 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200",
131
+ item.disabled && "opacity-50 cursor-not-allowed grayscale-[0.5]"
132
+ ),
133
+ children: [
134
+ /* @__PURE__ */ jsxs2(
135
+ "div",
136
+ {
137
+ className: cn(
138
+ "flex items-center gap-3 overflow-hidden",
139
+ isSidebarCollapsed ? "justify-center w-full" : ""
140
+ ),
141
+ children: [
142
+ item.icon && /* @__PURE__ */ jsx2(
143
+ "span",
144
+ {
145
+ className: cn(
146
+ "flex-shrink-0 transition-colors [&_svg]:w-4 [&_svg]:h-4",
147
+ shouldHighlight && !item.disabled ? "text-blue-600 dark:text-blue-400" : "text-gray-400 group-hover:text-blue-500 dark:text-gray-500 dark:group-hover:text-blue-400",
148
+ item.disabled && "group-hover:text-gray-400"
149
+ ),
150
+ children: item.icon
151
+ }
152
+ ),
153
+ /* @__PURE__ */ jsx2(AnimatePresence, { children: !isSidebarCollapsed && /* @__PURE__ */ jsx2(
154
+ motion.span,
155
+ {
156
+ initial: { opacity: 0, width: 0 },
157
+ animate: { opacity: 1, width: "auto" },
158
+ exit: { opacity: 0, width: 0 },
159
+ transition: { duration: 0.2 },
160
+ className: "truncate",
161
+ children: item.label
162
+ }
163
+ ) })
164
+ ]
165
+ }
166
+ ),
167
+ !isSidebarCollapsed && hasSubItems && /* @__PURE__ */ jsx2(
168
+ "span",
169
+ {
170
+ className: cn(
171
+ "flex-shrink-0 ml-2 transition-transform duration-200",
172
+ shouldHighlight ? "text-blue-500" : "text-gray-400"
173
+ ),
174
+ children: isExpanded ? /* @__PURE__ */ jsx2(ChevronDown, { size: 16 }) : /* @__PURE__ */ jsx2(ChevronRight, { size: 16 })
175
+ }
176
+ )
177
+ ]
178
+ }
179
+ ),
180
+ /* @__PURE__ */ jsx2(AnimatePresence, { initial: false, children: !isSidebarCollapsed && hasSubItems && isExpanded && !item.disabled && /* @__PURE__ */ jsx2(
181
+ motion.div,
182
+ {
183
+ initial: { height: 0, opacity: 0 },
184
+ animate: { height: "auto", opacity: 1 },
185
+ exit: { height: 0, opacity: 0 },
186
+ transition: { duration: 0.2 },
187
+ className: "overflow-hidden",
188
+ children: /* @__PURE__ */ jsxs2("div", { className: "relative ml-6 mt-1 space-y-1", children: [
189
+ /* @__PURE__ */ jsx2("div", { className: "absolute left-0 top-0 bottom-0 w-px bg-gray-200 dark:bg-gray-800" }),
190
+ item.subItems.filter((sub) => !!sub && !sub.hidden).map((subItem, index) => /* @__PURE__ */ jsx2(
191
+ SubItem,
192
+ {
193
+ item: subItem,
194
+ parentDisabled: item.disabled
195
+ },
196
+ index
197
+ ))
198
+ ] })
199
+ }
200
+ ) })
201
+ ] });
202
+ };
203
+ var SubItem = ({
204
+ item,
205
+ parentDisabled
206
+ }) => {
207
+ const location = useLocation();
208
+ const navigate = useNavigate();
209
+ const isActive = isPathActive(item.path, location.pathname);
210
+ const isDisabled = item.disabled || parentDisabled;
211
+ return /* @__PURE__ */ jsxs2(
212
+ "button",
213
+ {
214
+ onClick: () => !isDisabled && item.path && navigate(item.path),
215
+ disabled: isDisabled,
216
+ className: cn(
217
+ "relative w-full flex items-center px-3 py-2 pl-6 rounded-lg text-sm transition-colors duration-200",
218
+ isActive && !isDisabled ? "bg-blue-100/50 text-blue-700 font-medium dark:bg-blue-900/30 dark:text-blue-400" : "text-gray-500 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200",
219
+ isDisabled && "opacity-50 cursor-not-allowed grayscale-[0.5]"
220
+ ),
221
+ children: [
222
+ /* @__PURE__ */ jsx2("span", { className: "truncate", children: item.label }),
223
+ isActive && !isDisabled && /* @__PURE__ */ jsx2("div", { className: "absolute left-0 top-1/2 -translate-y-1/2 w-1 h-4 bg-blue-500 rounded-r-full" })
224
+ ]
225
+ }
226
+ );
227
+ };
228
+ var DashboardLayout = ({
229
+ children,
230
+ navItems,
231
+ title = "Dashboard",
232
+ logo,
233
+ userProfile,
234
+ fontFamily = 'system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"'
235
+ // Humanist System Stack
236
+ }) => {
237
+ const isDesktop = useMediaQuery("(min-width: 1024px)");
238
+ const location = useLocation();
239
+ const navigate = useNavigate();
240
+ const [isSidebarOpen, setIsSidebarOpen] = useState(true);
241
+ const [expandedMenus, setExpandedMenus] = useState(
242
+ () => {
243
+ const initialState = {};
244
+ navItems.forEach((item) => {
245
+ if (item && !item.hidden && !item.disabled && item.subItems?.some(
246
+ (sub) => sub && !sub.hidden && isPathActive(sub.path, location.pathname)
247
+ )) {
248
+ initialState[item.label] = true;
249
+ }
250
+ });
251
+ return initialState;
252
+ }
253
+ );
254
+ const prevPathRef = useRef(location.pathname);
255
+ useEffect(() => {
256
+ if (prevPathRef.current !== location.pathname) {
257
+ const activeItem = navItems.find(
258
+ (item) => !!item && !item.hidden && !item.disabled && item.subItems?.some(
259
+ (sub) => sub && !sub.hidden && isPathActive(sub.path, location.pathname)
260
+ ) === true
261
+ );
262
+ if (activeItem) {
263
+ setExpandedMenus((prev) => ({ ...prev, [activeItem.label]: true }));
264
+ }
265
+ prevPathRef.current = location.pathname;
266
+ }
267
+ }, [location.pathname, navItems]);
268
+ const isCollapsed = isDesktop && !isSidebarOpen;
269
+ useEffect(() => {
270
+ if (!isDesktop) {
271
+ setIsSidebarOpen(false);
272
+ } else {
273
+ setIsSidebarOpen(true);
274
+ }
275
+ }, [isDesktop]);
276
+ const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen);
277
+ const toggleMenu = (label) => {
278
+ if (isCollapsed) {
279
+ setIsSidebarOpen(true);
280
+ setTimeout(() => {
281
+ setExpandedMenus((prev) => {
282
+ const isCurrentlyOpen = !!prev[label];
283
+ return isCurrentlyOpen ? {} : { [label]: true };
284
+ });
285
+ }, 50);
286
+ return;
287
+ }
288
+ setExpandedMenus((prev) => {
289
+ const isCurrentlyOpen = !!prev[label];
290
+ return isCurrentlyOpen ? {} : { [label]: true };
291
+ });
292
+ };
293
+ const sidebarVariants = {
294
+ desktopOpen: {
295
+ width: "16rem",
296
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
297
+ },
298
+ desktopClosed: {
299
+ width: "5rem",
300
+ // Mini Sidebar Width
301
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
302
+ },
303
+ mobileOpen: {
304
+ x: 0,
305
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
306
+ },
307
+ mobileClosed: {
308
+ x: "-100%",
309
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
310
+ }
311
+ };
312
+ return /* @__PURE__ */ jsxs2(
313
+ "div",
314
+ {
315
+ className: "min-h-screen bg-gray-50 dark:bg-[#0B0F1A] text-slate-900 dark:text-slate-100 flex transition-colors duration-500 font-sans overflow-hidden",
316
+ style: { fontFamily },
317
+ children: [
318
+ /* @__PURE__ */ jsx2(AnimatePresence, { children: !isDesktop && isSidebarOpen && /* @__PURE__ */ jsx2(
319
+ motion.div,
320
+ {
321
+ initial: { opacity: 0 },
322
+ animate: { opacity: 0.5 },
323
+ exit: { opacity: 0 },
324
+ onClick: () => setIsSidebarOpen(false),
325
+ className: "fixed inset-0 bg-black/50 z-40 lg:hidden backdrop-blur-sm"
326
+ }
327
+ ) }),
328
+ /* @__PURE__ */ jsxs2(
329
+ motion.aside,
330
+ {
331
+ className: "fixed lg:relative inset-y-0 left-0 z-50 bg-white dark:bg-gray-900 border-r border-gray-200 dark:border-gray-800 flex flex-col h-screen",
332
+ initial: isDesktop ? "desktopOpen" : "mobileClosed",
333
+ animate: isDesktop ? isSidebarOpen ? "desktopOpen" : "desktopClosed" : isSidebarOpen ? "mobileOpen" : "mobileClosed",
334
+ variants: sidebarVariants,
335
+ children: [
336
+ /* @__PURE__ */ jsx2(
337
+ "div",
338
+ {
339
+ className: cn(
340
+ "h-16 flex items-center border-b border-gray-100 dark:border-gray-800 flex-shrink-0 overflow-hidden transition-all duration-300",
341
+ isCollapsed ? "justify-center px-0" : "px-6"
342
+ ),
343
+ children: /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-2 text-blue-600 dark:text-blue-400", children: isCollapsed ? logo : /* @__PURE__ */ jsxs2(Fragment, { children: [
344
+ logo,
345
+ /* @__PURE__ */ jsx2("span", { className: "font-bold text-lg tracking-tight text-gray-900 dark:text-white", children: title })
346
+ ] }) })
347
+ }
348
+ ),
349
+ /* @__PURE__ */ jsx2("div", { className: "flex-1 p-4 overflow-y-auto overflow-x-hidden scrollbar-hide", children: /* @__PURE__ */ jsx2("nav", { className: "space-y-1", children: navItems.filter((item) => !!item && !item.hidden).map((item) => {
350
+ const isActive = isPathActive(item.path, location.pathname);
351
+ const isChildActive = item.subItems?.some(
352
+ (sub) => sub && !sub.hidden && isPathActive(sub.path, location.pathname)
353
+ );
354
+ const isExpanded = expandedMenus[item.label];
355
+ return /* @__PURE__ */ jsx2(
356
+ SidebarItem,
357
+ {
358
+ item,
359
+ isActive,
360
+ isChildActive: !!isChildActive,
361
+ isExpanded: !!isExpanded,
362
+ isSidebarCollapsed: !!isCollapsed,
363
+ onClick: () => {
364
+ if (item.path) navigate(item.path);
365
+ if (isCollapsed && !item.path) {
366
+ setIsSidebarOpen(true);
367
+ }
368
+ },
369
+ onToggleExpand: () => toggleMenu(item.label)
370
+ },
371
+ item.label
372
+ );
373
+ }) }) })
374
+ ]
375
+ }
376
+ ),
377
+ /* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col min-w-0 h-screen overflow-hidden", children: [
378
+ /* @__PURE__ */ jsxs2("header", { className: "sticky top-0 z-30 h-16 bg-white/80 dark:bg-gray-900/80 backdrop-blur-md border-b border-gray-200 dark:border-gray-800 px-4 sm:px-6 flex items-center justify-between flex-shrink-0", children: [
379
+ /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsx2(
380
+ "button",
381
+ {
382
+ onClick: toggleSidebar,
383
+ className: "p-2 -ml-2 rounded-lg text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800 transition-colors",
384
+ children: /* @__PURE__ */ jsx2(Menu, { size: 20 })
385
+ }
386
+ ) }),
387
+ /* @__PURE__ */ jsx2("div", { className: "flex items-center gap-2", children: userProfile && /* @__PURE__ */ jsxs2(Fragment, { children: [
388
+ /* @__PURE__ */ jsx2("div", { className: "w-px h-6 mx-2 bg-gray-200 dark:bg-gray-800" }),
389
+ userProfile
390
+ ] }) })
391
+ ] }),
392
+ /* @__PURE__ */ jsx2("main", { className: "flex-1 p-2 md:p-4 overflow-y-auto", children: /* @__PURE__ */ jsx2("div", { className: "max-w-7xl mx-auto", children }) })
393
+ ] })
394
+ ]
395
+ }
396
+ );
397
+ };
398
+
399
+ // src/components/ThemeToggle.tsx
400
+ import { Sun, Moon } from "lucide-react";
401
+
402
+ // src/hooks/ThemeContext.tsx
403
+ import {
404
+ createContext,
405
+ useContext,
406
+ useState as useState2,
407
+ useEffect as useEffect2
408
+ } from "react";
409
+ import { jsx as jsx3 } from "react/jsx-runtime";
410
+ var ThemeContext = createContext(void 0);
411
+ var ThemeProvider = ({ children }) => {
412
+ const [isDarkMode, setIsDarkMode] = useState2(() => {
413
+ if (typeof window !== "undefined") {
414
+ const savedTheme = localStorage.getItem("theme");
415
+ if (savedTheme) {
416
+ return savedTheme === "dark";
417
+ }
418
+ return window.matchMedia("(prefers-color-scheme: dark)").matches;
419
+ }
420
+ return false;
421
+ });
422
+ useEffect2(() => {
423
+ const root = window.document.documentElement;
424
+ if (isDarkMode) {
425
+ root.classList.add("dark");
426
+ localStorage.setItem("theme", "dark");
427
+ } else {
428
+ root.classList.remove("dark");
429
+ localStorage.setItem("theme", "light");
430
+ }
431
+ }, [isDarkMode]);
432
+ const toggleTheme = () => setIsDarkMode((prev) => !prev);
433
+ const setTheme = (theme) => setIsDarkMode(theme === "dark");
434
+ return /* @__PURE__ */ jsx3(ThemeContext.Provider, { value: { isDarkMode, toggleTheme, setTheme }, children });
435
+ };
436
+ var useTheme = () => {
437
+ const context = useContext(ThemeContext);
438
+ if (context === void 0) {
439
+ throw new Error("useTheme must be used within a ThemeProvider");
440
+ }
441
+ return context;
442
+ };
443
+
444
+ // src/components/ThemeToggle.tsx
445
+ import { jsx as jsx4 } from "react/jsx-runtime";
446
+ var ThemeToggle = ({
447
+ className
448
+ }) => {
449
+ const { isDarkMode, toggleTheme } = useTheme();
450
+ return /* @__PURE__ */ jsx4(
451
+ "button",
452
+ {
453
+ onClick: toggleTheme,
454
+ className: cn(
455
+ "p-2 rounded-lg transition-all duration-200",
456
+ "text-slate-500 hover:text-blue-600 hover:bg-slate-100",
457
+ "dark:text-yellow-400 dark:hover:text-yellow-300 dark:hover:bg-slate-800",
458
+ className
459
+ ),
460
+ "aria-label": "Toggle dark mode",
461
+ children: isDarkMode ? /* @__PURE__ */ jsx4(
462
+ Sun,
463
+ {
464
+ size: 20,
465
+ className: "stroke-2 transition-transform duration-300 rotate-0 scale-100"
466
+ }
467
+ ) : /* @__PURE__ */ jsx4(
468
+ Moon,
469
+ {
470
+ size: 20,
471
+ className: "stroke-2 transition-transform duration-300 rotate-0 scale-100"
472
+ }
473
+ )
474
+ }
475
+ );
476
+ };
477
+
478
+ // src/hooks/useTheme.ts
479
+ import { useState as useState3, useEffect as useEffect3 } from "react";
480
+
481
+ // src/components/LoadingBox.tsx
482
+ import { jsx as jsx5 } from "react/jsx-runtime";
483
+ var LoadingBox = () => {
484
+ return /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx5("div", { className: "animate-spin rounded-full h-32 w-32 border-b-2 border-primary", children: "aaa" }) }) });
485
+ };
486
+
487
+ // src/components/spins/ClassicSpin.tsx
488
+ import { Loader2 } from "lucide-react";
489
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
490
+ var ClassicSpin = ({ msg = "Please wait..." }) => {
491
+ return /* @__PURE__ */ jsx6("div", { className: "absolute inset-0 z-50 flex flex-col items-center justify-center bg-white/30 dark:bg-zinc-900/30 backdrop-blur-[0.5px] transition-all duration-200", children: /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center p-6 bg-white dark:bg-zinc-800 rounded-2xl shadow-2xl border border-gray-100 dark:border-zinc-700 animate-in zoom-in-95 duration-200", children: [
492
+ /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
493
+ /* @__PURE__ */ jsx6("div", { className: "absolute inset-0 bg-indigo-500 blur-lg opacity-20 animate-pulse" }),
494
+ /* @__PURE__ */ jsx6(Loader2, { className: "h-8 w-8 animate-spin text-indigo-600 dark:text-indigo-400 relative z-10" })
495
+ ] }),
496
+ /* @__PURE__ */ jsx6("p", { className: "mt-3 text-sm font-medium text-gray-900 dark:text-white", children: msg })
497
+ ] }) });
498
+ };
499
+
500
+ // src/components/spins/OverlaySpin.tsx
501
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
502
+ var OverlaySpin = ({ msg = "Processing..." }) => /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 bg-white/50 dark:bg-black/50 backdrop-blur-[1px] z-50 flex items-center justify-center rounded-xl transition-all duration-300", children: /* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center gap-2 bg-white dark:bg-zinc-800 p-4 rounded-xl shadow-xl border border-gray-100 dark:border-zinc-700", children: [
503
+ /* @__PURE__ */ jsx7("div", { className: "w-6 h-6 border-2 border-blue-600 border-t-transparent rounded-full animate-spin" }),
504
+ /* @__PURE__ */ jsx7("span", { className: "text-xs font-medium text-gray-500 animate-pulse", children: msg })
505
+ ] }) });
506
+
507
+ // src/components/spins/LoadingSpin.tsx
508
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
509
+ var LoadingSpin = ({
510
+ className,
511
+ size = "md",
512
+ color = "text-current"
513
+ }) => {
514
+ const sizeClasses = {
515
+ sm: "h-4 w-4",
516
+ md: "h-6 w-6",
517
+ lg: "h-10 w-10"
518
+ };
519
+ return /* @__PURE__ */ jsxs5(
520
+ "svg",
521
+ {
522
+ className: cn("animate-spin", sizeClasses[size], color, className),
523
+ fill: "none",
524
+ viewBox: "0 0 24 24",
525
+ xmlns: "http://www.w3.org/2000/svg",
526
+ children: [
527
+ /* @__PURE__ */ jsx8(
528
+ "circle",
529
+ {
530
+ className: "opacity-25",
531
+ cx: "12",
532
+ cy: "12",
533
+ r: "10",
534
+ stroke: "currentColor",
535
+ strokeWidth: "4"
536
+ }
537
+ ),
538
+ /* @__PURE__ */ jsx8(
539
+ "path",
540
+ {
541
+ className: "opacity-75",
542
+ fill: "currentColor",
543
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
544
+ }
545
+ )
546
+ ]
547
+ }
548
+ );
549
+ };
550
+
551
+ // src/components/CodeBlock.tsx
552
+ import { useState as useState4 } from "react";
553
+ import { Check, Copy } from "lucide-react";
554
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
555
+ var CodeBlock = ({
556
+ code,
557
+ language = "tsx",
558
+ className
559
+ }) => {
560
+ const [copied, setCopied] = useState4(false);
561
+ const handleCopy = () => {
562
+ navigator.clipboard.writeText(code);
563
+ setCopied(true);
564
+ setTimeout(() => setCopied(false), 2e3);
565
+ };
566
+ return /* @__PURE__ */ jsxs6(
567
+ "div",
568
+ {
569
+ className: cn(
570
+ "relative group rounded-2xl overflow-hidden border border-gray-200 dark:border-gray-800 bg-gray-50/50 dark:bg-black/50 backdrop-blur-sm",
571
+ className
572
+ ),
573
+ children: [
574
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-4 py-2 bg-gray-100 dark:bg-zinc-900/50 border-b border-gray-200 dark:border-gray-800", children: [
575
+ /* @__PURE__ */ jsx9("span", { className: "text-[10px] font-bold uppercase tracking-widest text-gray-400", children: language }),
576
+ /* @__PURE__ */ jsx9(
577
+ "button",
578
+ {
579
+ onClick: handleCopy,
580
+ className: "p-1.5 rounded-lg text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-white dark:hover:bg-zinc-800 transition-all duration-200",
581
+ children: copied ? /* @__PURE__ */ jsx9(Check, { size: 14, className: "text-green-500" }) : /* @__PURE__ */ jsx9(Copy, { size: 14 })
582
+ }
583
+ )
584
+ ] }),
585
+ /* @__PURE__ */ jsx9("div", { className: "p-4 overflow-x-auto", children: /* @__PURE__ */ jsx9("pre", { className: "text-sm font-mono leading-relaxed text-gray-800 dark:text-gray-300", children: code }) })
586
+ ]
587
+ }
588
+ );
589
+ };
590
+
591
+ // src/components/Card.tsx
592
+ import { jsx as jsx10 } from "react/jsx-runtime";
593
+ var Card = ({
594
+ children,
595
+ className,
596
+ variant = "default",
597
+ ...props
598
+ }) => {
599
+ const variants = {
600
+ default: "bg-white dark:bg-zinc-900 border-gray-200 dark:border-zinc-800 shadow-sm",
601
+ flat: "bg-gray-50/50 dark:bg-zinc-950/50 border-gray-100 dark:border-zinc-900",
602
+ glass: "bg-white/70 dark:bg-black/40 backdrop-blur-md border-white/20 dark:border-white/5 shadow-xl"
603
+ };
604
+ return /* @__PURE__ */ jsx10(
605
+ "div",
606
+ {
607
+ className: cn(
608
+ "rounded-[2rem] border p-6 transition-all duration-300",
609
+ variants[variant],
610
+ className
611
+ ),
612
+ ...props,
613
+ children
614
+ }
615
+ );
616
+ };
617
+ var CardHeader = ({
618
+ children,
619
+ className
620
+ }) => /* @__PURE__ */ jsx10("div", { className: cn("mb-4 space-y-1.5", className), children });
621
+ var CardTitle = ({
622
+ children,
623
+ className
624
+ }) => /* @__PURE__ */ jsx10(
625
+ "h3",
626
+ {
627
+ className: cn(
628
+ "text-lg font-semibold leading-none tracking-tight text-gray-900 dark:text-gray-100",
629
+ className
630
+ ),
631
+ children
632
+ }
633
+ );
634
+ var CardDescription = ({
635
+ children,
636
+ className
637
+ }) => /* @__PURE__ */ jsx10("p", { className: cn("text-sm text-gray-500 dark:text-gray-400", className), children });
638
+ var CardContent = ({
639
+ children,
640
+ className
641
+ }) => /* @__PURE__ */ jsx10("div", { className: cn("", className), children });
642
+ var CardFooter = ({
643
+ children,
644
+ className
645
+ }) => /* @__PURE__ */ jsx10("div", { className: cn("mt-6 flex items-center pt-0", className), children });
646
+ Card.Header = CardHeader;
647
+ Card.Title = CardTitle;
648
+ Card.Description = CardDescription;
649
+ Card.Content = CardContent;
650
+ Card.Footer = CardFooter;
651
+
652
+ // src/components/modal/Modal.tsx
653
+ import { X } from "lucide-react";
654
+ import { motion as motion2, AnimatePresence as AnimatePresence2 } from "framer-motion";
655
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
656
+ var Modal = ({
657
+ isOpen,
658
+ onClose,
659
+ title,
660
+ children,
661
+ isLoading = false,
662
+ width = 500
663
+ }) => {
664
+ return /* @__PURE__ */ jsx11(AnimatePresence2, { children: isOpen && /* @__PURE__ */ jsxs7("div", { className: "fixed inset-0 z-[1000] flex items-center justify-center p-4 sm:p-6", children: [
665
+ /* @__PURE__ */ jsx11(
666
+ motion2.div,
667
+ {
668
+ initial: { opacity: 0 },
669
+ animate: { opacity: 1 },
670
+ exit: { opacity: 0 },
671
+ onClick: isLoading ? void 0 : onClose,
672
+ className: "fixed inset-0 bg-black/40 backdrop-blur-sm transition-all"
673
+ }
674
+ ),
675
+ /* @__PURE__ */ jsxs7(
676
+ motion2.div,
677
+ {
678
+ initial: { opacity: 0, scale: 0.95, y: 10 },
679
+ animate: { opacity: 1, scale: 1, y: 0 },
680
+ exit: { opacity: 0, scale: 0.95, y: 10 },
681
+ transition: { type: "spring", duration: 0.3 },
682
+ style: { maxWidth: width },
683
+ className: "w-full bg-white dark:bg-zinc-900 rounded-[2rem] shadow-2xl border border-gray-200 dark:border-white/5 overflow-hidden relative z-10 flex flex-col max-h-[90vh]",
684
+ children: [
685
+ /* @__PURE__ */ jsxs7("div", { className: "px-8 py-5 border-b border-gray-100 dark:border-white/5 flex items-center justify-between bg-white/50 dark:bg-zinc-900/50 backdrop-blur-xl sticky top-0 z-20", children: [
686
+ /* @__PURE__ */ jsx11("h3", { className: "text-xl font-bold text-gray-900 dark:text-white tracking-tight", children: title }),
687
+ /* @__PURE__ */ jsx11(
688
+ "button",
689
+ {
690
+ onClick: onClose,
691
+ disabled: isLoading,
692
+ className: "p-2 -mr-2 rounded-full text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-white/5 transition-all disabled:opacity-50",
693
+ children: /* @__PURE__ */ jsx11(X, { size: 20 })
694
+ }
695
+ )
696
+ ] }),
697
+ /* @__PURE__ */ jsx11("div", { className: "absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-blue-500 via-indigo-600 to-purple-500 opacity-60" }),
698
+ /* @__PURE__ */ jsxs7("div", { className: "p-8 overflow-y-auto relative flex-1", children: [
699
+ isLoading && /* @__PURE__ */ jsx11(ClassicSpin, {}),
700
+ /* @__PURE__ */ jsx11(
701
+ "div",
702
+ {
703
+ className: isLoading ? "opacity-20 blur-sm transition-all" : "transition-all",
704
+ children
705
+ }
706
+ )
707
+ ] })
708
+ ]
709
+ }
710
+ )
711
+ ] }) });
712
+ };
713
+
714
+ // src/components/PageHeader.tsx
715
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
716
+ var PageHeader = ({
717
+ title,
718
+ description,
719
+ children,
720
+ className
721
+ }) => {
722
+ return /* @__PURE__ */ jsxs8("div", { className: cn("space-y-2 mb-8", className), children: [
723
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between", children: [
724
+ /* @__PURE__ */ jsx12("h1", { className: "text-3xl font-bold text-gray-900 dark:text-white tracking-tight", children: title }),
725
+ children
726
+ ] }),
727
+ description && /* @__PURE__ */ jsx12("p", { className: "text-gray-500 dark:text-gray-400 max-w-2xl leading-relaxed", children: description })
728
+ ] });
729
+ };
730
+
731
+ // src/hooks/useModal.tsx
732
+ import { useState as useState5, useCallback } from "react";
733
+ var useModal = (initialState = false) => {
734
+ const [isOpen, setIsOpen] = useState5(initialState);
735
+ const [state, setState] = useState5(null);
736
+ const open = useCallback(() => setIsOpen(true), []);
737
+ const close = useCallback(() => {
738
+ setIsOpen(false);
739
+ setState(null);
740
+ }, []);
741
+ const toggle = useCallback(() => setIsOpen((prev) => !prev), []);
742
+ const openState = useCallback((data) => {
743
+ setState(data);
744
+ open();
745
+ }, []);
746
+ return {
747
+ isOpen,
748
+ open,
749
+ close,
750
+ toggle,
751
+ openState,
752
+ state,
753
+ Modal
754
+ };
755
+ };
756
+
757
+ // src/components/Fields/Input.tsx
758
+ import { forwardRef, useEffect as useEffect4, useState as useState6 } from "react";
759
+ import { Eye, EyeOff } from "lucide-react";
760
+
761
+ // src/providers/WarqadProvider.tsx
762
+ import { createContext as createContext2, useContext as useContext2 } from "react";
763
+ import { jsx as jsx13 } from "react/jsx-runtime";
764
+ var WarqadConfigContext = createContext2(
765
+ void 0
766
+ );
767
+ var useWarqadConfig = () => {
768
+ const context = useContext2(WarqadConfigContext);
769
+ if (context === void 0) {
770
+ throw new Error("useWarqadConfig must be used within a WarqadProvider");
771
+ }
772
+ return context.config;
773
+ };
774
+ var WarqadProvider = ({
775
+ children,
776
+ config = { apiUrl: "/api" }
777
+ }) => {
778
+ const mergedConfig = {
779
+ apiUrl: "/api",
780
+ ...config,
781
+ theme: {
782
+ primaryColor: "#3b82f6",
783
+ // Default blue-500
784
+ ...config?.theme
785
+ }
786
+ };
787
+ return /* @__PURE__ */ jsx13(WarqadConfigContext.Provider, { value: { config: mergedConfig }, children: /* @__PURE__ */ jsx13(ThemeProvider, { children: /* @__PURE__ */ jsx13(
788
+ "div",
789
+ {
790
+ style: {
791
+ "--primary-color": mergedConfig.theme?.primaryColor
792
+ },
793
+ children
794
+ }
795
+ ) }) });
796
+ };
797
+
798
+ // src/components/Fields/Input.tsx
799
+ import {
800
+ Controller
801
+ } from "react-hook-form";
802
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
803
+ var Input = forwardRef(
804
+ ({
805
+ label,
806
+ icon,
807
+ error,
808
+ containerClassName = "",
809
+ name,
810
+ form,
811
+ onFocus,
812
+ onBlur,
813
+ className = "",
814
+ type,
815
+ ...props
816
+ }, ref) => {
817
+ const [isFocused, setIsFocused] = useState6(false);
818
+ const [showPassword, setShowPassword] = useState6(false);
819
+ const { theme } = useWarqadConfig();
820
+ const primaryColor = theme?.primaryColor;
821
+ let message = error;
822
+ if (form && name) {
823
+ const {
824
+ formState: { errors }
825
+ } = form;
826
+ const errorObj = name.split(".").reduce((acc, current) => acc?.[current], errors);
827
+ message = errorObj?.message;
828
+ }
829
+ useEffect4(() => {
830
+ if (form && name) {
831
+ form.clearErrors("root");
832
+ }
833
+ }, [form?.watch(name)]);
834
+ const renderInput = (inputProps, localType = type || "text") => /* @__PURE__ */ jsxs9("div", { className: `space-y-2 group ${containerClassName}`, children: [
835
+ /* @__PURE__ */ jsxs9(
836
+ "label",
837
+ {
838
+ htmlFor: props.id,
839
+ className: `block capitalize text-xs font-medium transition-colors duration-200`,
840
+ style: { color: isFocused ? primaryColor : void 0 },
841
+ children: [
842
+ label,
843
+ props.required && /* @__PURE__ */ jsx14("span", { className: "text-red-500 ml-1", children: "*" })
844
+ ]
845
+ }
846
+ ),
847
+ /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
848
+ icon && /* @__PURE__ */ jsx14("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx14(
849
+ "div",
850
+ {
851
+ className: `transition-colors duration-200`,
852
+ style: { color: isFocused ? primaryColor : "#9ca3af" },
853
+ children: icon
854
+ }
855
+ ) }),
856
+ /* @__PURE__ */ jsx14(
857
+ "input",
858
+ {
859
+ ref,
860
+ onFocus: (e) => {
861
+ setIsFocused(true);
862
+ onFocus?.(e);
863
+ },
864
+ onBlur: (e) => {
865
+ setIsFocused(false);
866
+ onBlur?.(e);
867
+ },
868
+ className: `block w-full ${icon ? "pl-10" : "pl-3"} pr-3 h-8 py-0 rounded-lg border-gray-200 dark:border-zinc-800 bg-gray-50 dark:bg-zinc-900/50 text-gray-900 dark:text-white placeholder-gray-400 focus:bg-white dark:focus:bg-zinc-900 outline-none transition-all duration-200 border text-sm ${className}`,
869
+ style: {
870
+ borderColor: isFocused ? primaryColor : void 0,
871
+ boxShadow: isFocused ? `${primaryColor}33 0px 0px 0px 2px` : void 0
872
+ },
873
+ ...props,
874
+ ...inputProps,
875
+ type: localType === "password" ? showPassword ? "text" : "password" : localType
876
+ }
877
+ ),
878
+ type === "password" && /* @__PURE__ */ jsx14(
879
+ "button",
880
+ {
881
+ type: "button",
882
+ onClick: () => setShowPassword(!showPassword),
883
+ className: "absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors focus:outline-none cursor-pointer",
884
+ tabIndex: -1,
885
+ children: showPassword ? /* @__PURE__ */ jsx14(EyeOff, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx14(Eye, { className: "h-5 w-5" })
886
+ }
887
+ )
888
+ ] }),
889
+ message && /* @__PURE__ */ jsx14("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
890
+ ] });
891
+ if (form && name && type === "number") {
892
+ return /* @__PURE__ */ jsx14(
893
+ Controller,
894
+ {
895
+ control: form.control,
896
+ name,
897
+ render: ({ field: { onChange, value, ref: fieldRef, onBlur: onBlur2 } }) => renderInput(
898
+ {
899
+ ref: fieldRef,
900
+ onBlur: () => {
901
+ onBlur2();
902
+ },
903
+ value: value ? String(value).split(".").map(
904
+ (part, index) => index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
905
+ ).join(".") : "",
906
+ onChange: (e) => {
907
+ const rawValue = e.target.value.replace(/,/g, "");
908
+ if (!/^\d*\.?\d*$/.test(rawValue)) return;
909
+ if (rawValue === "") {
910
+ onChange("");
911
+ } else {
912
+ const numValue = Number(rawValue);
913
+ if (!isNaN(numValue) && String(numValue) === rawValue) {
914
+ onChange(numValue);
915
+ } else {
916
+ onChange(rawValue);
917
+ }
918
+ }
919
+ props.onChange?.(e);
920
+ }
921
+ },
922
+ "text"
923
+ )
924
+ }
925
+ );
926
+ }
927
+ return renderInput(
928
+ form && name ? form.register(name, type === "number" ? { valueAsNumber: true } : {}) : {}
929
+ );
930
+ }
931
+ );
932
+
933
+ // src/components/Fields/PhoneInput.tsx
934
+ import { forwardRef as forwardRef2, useState as useState7 } from "react";
935
+ import PhoneInputOriginal, {
936
+ isValidPhoneNumber
937
+ } from "react-phone-number-input";
938
+ import "react-phone-number-input/style.css";
939
+ import { Controller as Controller2 } from "react-hook-form";
940
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
941
+ var PhoneInput = forwardRef2(
942
+ ({
943
+ label,
944
+ icon,
945
+ error,
946
+ containerClassName = "",
947
+ name,
948
+ form,
949
+ onChange,
950
+ value,
951
+ className = "",
952
+ ...props
953
+ }, ref) => {
954
+ const [isFocused, setIsFocused] = useState7(false);
955
+ const { theme } = useWarqadConfig();
956
+ const primaryColor = theme?.primaryColor;
957
+ let message = error;
958
+ if (form && name) {
959
+ const {
960
+ formState: { errors }
961
+ } = form;
962
+ const nameParts = name.split(".");
963
+ let currentError = errors;
964
+ for (const part of nameParts) {
965
+ currentError = currentError?.[part];
966
+ }
967
+ message = currentError?.message || message;
968
+ }
969
+ const renderInput = (onChangeHandler, currentValue) => /* @__PURE__ */ jsxs10("div", { className: `space-y-2 group ${containerClassName}`, children: [
970
+ /* @__PURE__ */ jsxs10(
971
+ "label",
972
+ {
973
+ className: `block text-xs font-medium transition-colors duration-200`,
974
+ style: {
975
+ color: isFocused || currentValue ? primaryColor : void 0
976
+ },
977
+ children: [
978
+ label,
979
+ props.required && /* @__PURE__ */ jsx15("span", { className: "text-red-500 ml-1", children: "*" })
980
+ ]
981
+ }
982
+ ),
983
+ /* @__PURE__ */ jsxs10("div", { className: "relative", children: [
984
+ icon && /* @__PURE__ */ jsx15("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none z-10", children: /* @__PURE__ */ jsx15(
985
+ "div",
986
+ {
987
+ className: `transition-colors duration-200`,
988
+ style: { color: isFocused ? primaryColor : "#9ca3af" },
989
+ children: icon
990
+ }
991
+ ) }),
992
+ /* @__PURE__ */ jsx15(
993
+ PhoneInputOriginal,
994
+ {
995
+ ref,
996
+ defaultCountry: "KE",
997
+ international: true,
998
+ withCountryCallingCode: true,
999
+ value: currentValue,
1000
+ onChange: (val) => onChangeHandler(val),
1001
+ onFocus: () => setIsFocused(true),
1002
+ onBlur: () => setIsFocused(false),
1003
+ className: `block w-full rounded-lg border-gray-200 dark:border-zinc-800 bg-gray-50 dark:bg-zinc-900/50 text-gray-900 dark:text-white placeholder-gray-400 focus-within:bg-white dark:focus-within:bg-zinc-900 outline-none transition-all duration-200 border [&_.PhoneInputInput]:bg-transparent [&_.PhoneInputInput]:outline-none [&_.PhoneInputInput]:text-sm [&_.PhoneInputCountry]:mr-2 ${icon ? "pl-10" : "pl-3"} pr-3 h-8 py-0 ${className}`,
1004
+ style: {
1005
+ borderColor: isFocused ? primaryColor : void 0,
1006
+ boxShadow: isFocused ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1007
+ },
1008
+ ...props
1009
+ }
1010
+ )
1011
+ ] }),
1012
+ message && /* @__PURE__ */ jsx15("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1013
+ ] });
1014
+ if (form && name) {
1015
+ return /* @__PURE__ */ jsx15(
1016
+ Controller2,
1017
+ {
1018
+ name,
1019
+ control: form.control,
1020
+ rules: {
1021
+ validate: (value2) => value2 && isValidPhoneNumber(value2) ? true : "Invalid phone number"
1022
+ },
1023
+ render: ({ field: { onChange: onChange2, value: value2 } }) => renderInput(onChange2, value2)
1024
+ }
1025
+ );
1026
+ }
1027
+ return renderInput(onChange || (() => {
1028
+ }), value || "");
1029
+ }
1030
+ );
1031
+ PhoneInput.displayName = "PhoneInput";
1032
+
1033
+ // src/components/Fields/select.tsx
1034
+ import { forwardRef as forwardRef3, useState as useState8 } from "react";
1035
+ import { ChevronDown as ChevronDown2 } from "lucide-react";
1036
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
1037
+ var Select = forwardRef3(
1038
+ ({
1039
+ label,
1040
+ options,
1041
+ icon,
1042
+ error,
1043
+ containerClassName = "",
1044
+ name,
1045
+ form,
1046
+ onChange,
1047
+ onFocus,
1048
+ onBlur,
1049
+ className = "",
1050
+ ...props
1051
+ }, ref) => {
1052
+ const [isFocused, setIsFocused] = useState8(false);
1053
+ const { theme } = useWarqadConfig();
1054
+ const primaryColor = theme?.primaryColor;
1055
+ let message = error;
1056
+ if (form) {
1057
+ const {
1058
+ formState: { errors }
1059
+ } = form;
1060
+ const nameI = name.split(".");
1061
+ const names = nameI.length > 1 ? nameI[1] : nameI[0];
1062
+ message = errors?.[names ? names : name]?.message;
1063
+ }
1064
+ return /* @__PURE__ */ jsxs11("div", { className: `space-y-2 group ${containerClassName}`, children: [
1065
+ /* @__PURE__ */ jsxs11(
1066
+ "label",
1067
+ {
1068
+ htmlFor: props.id,
1069
+ className: `block text-xs font-medium transition-colors duration-200`,
1070
+ style: { color: isFocused ? primaryColor : void 0 },
1071
+ children: [
1072
+ label,
1073
+ props.required && /* @__PURE__ */ jsx16("span", { className: "text-red-500 ml-1", children: "*" })
1074
+ ]
1075
+ }
1076
+ ),
1077
+ /* @__PURE__ */ jsxs11("div", { className: "relative", children: [
1078
+ icon && /* @__PURE__ */ jsx16("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx16(
1079
+ "div",
1080
+ {
1081
+ className: `transition-colors duration-200`,
1082
+ style: { color: isFocused ? primaryColor : "#9ca3af" },
1083
+ children: icon
1084
+ }
1085
+ ) }),
1086
+ /* @__PURE__ */ jsxs11(
1087
+ "select",
1088
+ {
1089
+ ref,
1090
+ onFocus: (e) => {
1091
+ setIsFocused(true);
1092
+ onFocus?.(e);
1093
+ },
1094
+ ...form ? form.register(name) : {},
1095
+ onBlur: (e) => {
1096
+ setIsFocused(false);
1097
+ onBlur?.(e);
1098
+ },
1099
+ onChange: (e) => {
1100
+ onChange?.(e.target.value);
1101
+ if (form) {
1102
+ form.setValue(name, e.target.value);
1103
+ }
1104
+ },
1105
+ className: `block w-full ${icon ? "pl-10" : "pl-3"} pr-10 h-8 py-0 rounded-lg border-gray-200 dark:border-zinc-800 bg-gray-50 dark:bg-zinc-900/50 text-gray-900 dark:text-white placeholder-gray-400 focus:bg-white dark:focus:bg-zinc-900 outline-none transition-all duration-200 border appearance-none text-sm ${className}`,
1106
+ style: {
1107
+ borderColor: isFocused ? primaryColor : void 0,
1108
+ boxShadow: isFocused ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1109
+ },
1110
+ ...props,
1111
+ children: [
1112
+ /* @__PURE__ */ jsxs11("option", { value: "", disabled: true, children: [
1113
+ "Select ",
1114
+ label
1115
+ ] }),
1116
+ options.map((option) => /* @__PURE__ */ jsx16(
1117
+ "option",
1118
+ {
1119
+ value: String(option.value),
1120
+ disabled: option.disabled,
1121
+ children: option.label
1122
+ },
1123
+ String(option.value)
1124
+ ))
1125
+ ]
1126
+ }
1127
+ ),
1128
+ /* @__PURE__ */ jsx16("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx16(ChevronDown2, { className: "h-4 w-4 text-gray-400" }) })
1129
+ ] }),
1130
+ message && /* @__PURE__ */ jsx16("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1131
+ ] });
1132
+ }
1133
+ );
1134
+ Select.displayName = "Select";
1135
+
1136
+ // src/components/Fields/textArea.tsx
1137
+ import { forwardRef as forwardRef4, useState as useState9 } from "react";
1138
+ import {
1139
+ Controller as Controller3
1140
+ } from "react-hook-form";
1141
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
1142
+ var Textarea = forwardRef4(
1143
+ ({
1144
+ label,
1145
+ error,
1146
+ containerClassName = "",
1147
+ name,
1148
+ form,
1149
+ onFocus,
1150
+ onBlur,
1151
+ className = "",
1152
+ ...props
1153
+ }, ref) => {
1154
+ const [isFocused, setIsFocused] = useState9(false);
1155
+ const { theme } = useWarqadConfig();
1156
+ const primaryColor = theme?.primaryColor;
1157
+ let message = error;
1158
+ if (form && name) {
1159
+ const {
1160
+ formState: { errors }
1161
+ } = form;
1162
+ const errorObj = name.split(".").reduce((acc, current) => acc?.[current], errors);
1163
+ message = errorObj?.message;
1164
+ }
1165
+ const renderInput = (inputProps, ref2) => /* @__PURE__ */ jsxs12("div", { className: `space-y-2 group ${containerClassName}`, children: [
1166
+ /* @__PURE__ */ jsxs12(
1167
+ "label",
1168
+ {
1169
+ htmlFor: props.id,
1170
+ className: `block capitalize text-xs font-medium transition-colors duration-200`,
1171
+ style: { color: isFocused ? primaryColor : void 0 },
1172
+ children: [
1173
+ label,
1174
+ props.required && /* @__PURE__ */ jsx17("span", { className: "text-red-500 ml-1", children: "*" })
1175
+ ]
1176
+ }
1177
+ ),
1178
+ /* @__PURE__ */ jsx17("div", { className: "relative", children: /* @__PURE__ */ jsx17(
1179
+ "textarea",
1180
+ {
1181
+ ref: ref2,
1182
+ onFocus: (e) => {
1183
+ setIsFocused(true);
1184
+ onFocus?.(e);
1185
+ },
1186
+ onBlur: (e) => {
1187
+ setIsFocused(false);
1188
+ onBlur?.(e);
1189
+ },
1190
+ className: `block w-full px-3 py-3 rounded-lg border-gray-200 dark:border-zinc-800 bg-gray-50 dark:bg-zinc-900/50 text-gray-900 dark:text-white placeholder-gray-400 focus:bg-white dark:focus:bg-zinc-900 outline-none transition-all duration-200 border min-h-[100px] resize-none text-sm ${className}`,
1191
+ style: {
1192
+ borderColor: isFocused ? primaryColor : void 0,
1193
+ boxShadow: isFocused ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1194
+ },
1195
+ ...props,
1196
+ ...inputProps
1197
+ }
1198
+ ) }),
1199
+ message && /* @__PURE__ */ jsx17("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1200
+ ] });
1201
+ if (form && name) {
1202
+ return /* @__PURE__ */ jsx17(
1203
+ Controller3,
1204
+ {
1205
+ control: form.control,
1206
+ name,
1207
+ render: ({ field: { onChange, value, ref: fieldRef, onBlur: onBlur2 } }) => renderInput(
1208
+ {
1209
+ value: value || "",
1210
+ // Ensure controlled input doesn't warn about uncontrolled
1211
+ onChange: (e) => {
1212
+ onChange(e);
1213
+ props.onChange?.(e);
1214
+ },
1215
+ onBlur: () => {
1216
+ onBlur2();
1217
+ }
1218
+ },
1219
+ fieldRef
1220
+ )
1221
+ }
1222
+ );
1223
+ }
1224
+ return renderInput({}, ref);
1225
+ }
1226
+ );
1227
+
1228
+ // src/components/Fields/searchApi.tsx
1229
+ import { useState as useState11, useEffect as useEffect5, useRef as useRef2, forwardRef as forwardRef5 } from "react";
1230
+ import { Search, Loader2 as Loader22, ChevronDown as ChevronDown3, Check as Check2, X as X2 } from "lucide-react";
1231
+
1232
+ // src/hooks/Fetches/useApis.tsx
1233
+ import { useState as useState10, useMemo } from "react";
1234
+ import axios from "axios";
1235
+ var useApi = () => {
1236
+ const { apiUrl } = useWarqadConfig();
1237
+ const api = useMemo(
1238
+ () => axios.create({
1239
+ baseURL: apiUrl || "/api",
1240
+ withCredentials: true
1241
+ }),
1242
+ [apiUrl]
1243
+ );
1244
+ const [data, setData] = useState10();
1245
+ const [isLoading, setIsLoading] = useState10(false);
1246
+ const [pdfLoading, setPdfLoading] = useState10(false);
1247
+ const [error, setError] = useState10(null);
1248
+ const get = async ({ url, v = 1, params, delay }) => {
1249
+ setIsLoading(true);
1250
+ try {
1251
+ if (delay) await new Promise((r) => setTimeout(r, delay));
1252
+ const response = await api.get(`/v${v}${url}`, { params });
1253
+ setData(response.data);
1254
+ setError(null);
1255
+ return response.data;
1256
+ } catch (err) {
1257
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1258
+ setError(msg);
1259
+ setData(null);
1260
+ throw new Error(msg);
1261
+ } finally {
1262
+ setIsLoading(false);
1263
+ }
1264
+ };
1265
+ const post = async ({
1266
+ url,
1267
+ v = 1,
1268
+ body,
1269
+ form,
1270
+ multipart = false
1271
+ }) => {
1272
+ setIsLoading(true);
1273
+ try {
1274
+ let response;
1275
+ if (multipart) {
1276
+ const formData = new FormData();
1277
+ if (body) {
1278
+ Object.keys(body).forEach((key) => {
1279
+ if (key === "files") {
1280
+ const files = body[key];
1281
+ if (Array.isArray(files)) {
1282
+ files.forEach((file) => formData.append(key, file));
1283
+ } else {
1284
+ formData.append(key, files);
1285
+ }
1286
+ } else if (Array.isArray(body[key]) || typeof body[key] === "object") {
1287
+ formData.append(key, JSON.stringify(body[key]));
1288
+ } else {
1289
+ formData.append(key, body[key]);
1290
+ }
1291
+ });
1292
+ }
1293
+ response = await api.post(`/v${v}${url}`, formData, {
1294
+ headers: { "Content-Type": "multipart/form-data" }
1295
+ });
1296
+ } else {
1297
+ response = await api.post(`/v${v}${url}`, body);
1298
+ }
1299
+ setData(response.data);
1300
+ return response.data;
1301
+ } catch (err) {
1302
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1303
+ setError(msg);
1304
+ if (form) {
1305
+ if (msg !== "zodError") {
1306
+ form.setError("root", { message: msg });
1307
+ } else {
1308
+ const errors = err?.response?.data?.errors || [];
1309
+ errors.forEach((e) => {
1310
+ form.setError(e.field, { message: e.message });
1311
+ });
1312
+ }
1313
+ }
1314
+ throw new Error(msg);
1315
+ } finally {
1316
+ setIsLoading(false);
1317
+ }
1318
+ };
1319
+ const put = async ({ url, v = 1, body }) => {
1320
+ setIsLoading(true);
1321
+ try {
1322
+ const response = await api.put(`/v${v}${url}`, body);
1323
+ setData(response.data);
1324
+ return response.data;
1325
+ } catch (err) {
1326
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1327
+ setError(msg);
1328
+ throw new Error(msg);
1329
+ } finally {
1330
+ setIsLoading(false);
1331
+ }
1332
+ };
1333
+ const remove = async ({ url, v = 1, params }) => {
1334
+ setIsLoading(true);
1335
+ try {
1336
+ const response = await api.delete(`/v${v}${url}`, { params });
1337
+ setData(response.data);
1338
+ setError(null);
1339
+ return response.data;
1340
+ } catch (err) {
1341
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1342
+ setError(msg);
1343
+ setData(null);
1344
+ throw new Error(msg);
1345
+ } finally {
1346
+ setIsLoading(false);
1347
+ }
1348
+ };
1349
+ const fetchPdf = async ({
1350
+ url,
1351
+ v = 1,
1352
+ method,
1353
+ body
1354
+ }) => {
1355
+ setPdfLoading(true);
1356
+ try {
1357
+ const response = await api.request({
1358
+ url: `/v${v}${url}`,
1359
+ method,
1360
+ data: body,
1361
+ responseType: "blob"
1362
+ });
1363
+ if (!response.data || response.data.size === 0) {
1364
+ return { ok: false, message: "Received empty PDF file", errors: [] };
1365
+ }
1366
+ setError(null);
1367
+ const pdfObjectUrl = URL.createObjectURL(response.data);
1368
+ return { ok: true, data: pdfObjectUrl };
1369
+ } catch (err) {
1370
+ return {
1371
+ ok: false,
1372
+ message: err.response?.data?.message || err.message || "Server error, something went wrong"
1373
+ };
1374
+ } finally {
1375
+ setPdfLoading(false);
1376
+ }
1377
+ };
1378
+ return {
1379
+ data,
1380
+ error,
1381
+ isLoading,
1382
+ pdfLoading,
1383
+ get,
1384
+ post,
1385
+ put,
1386
+ remove,
1387
+ fetchPdf
1388
+ };
1389
+ };
1390
+ var useApis_default = useApi;
1391
+
1392
+ // src/components/Fields/searchApi.tsx
1393
+ import { Controller as Controller4 } from "react-hook-form";
1394
+ import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
1395
+ var SearchApiContent = ({
1396
+ label,
1397
+ apiUrl,
1398
+ placeholder = "Search...",
1399
+ currentValue,
1400
+ onChangeHandler,
1401
+ queryKey = "search",
1402
+ labelKey = "name",
1403
+ valueKey = "_id",
1404
+ error,
1405
+ containerClassName = "",
1406
+ className = "",
1407
+ disabled,
1408
+ name,
1409
+ obj,
1410
+ form,
1411
+ filter = [],
1412
+ required,
1413
+ v = 2,
1414
+ fieldInternalProps,
1415
+ ...props
1416
+ }) => {
1417
+ const [searchTerm, setSearchTerm] = useState11("");
1418
+ const { theme } = useWarqadConfig();
1419
+ const primaryColor = theme?.primaryColor;
1420
+ const [options, setOptions] = useState11([]);
1421
+ const [isOpen, setIsOpen] = useState11(false);
1422
+ const [isFocused, setIsFocused] = useState11(false);
1423
+ const [activeIndex, setActiveIndex] = useState11(-1);
1424
+ const [selectedObject, setSelectedObject] = useState11(void 0);
1425
+ const [hasAttemptedHydration, setHasAttemptedHydration] = useState11(false);
1426
+ const containerRef = useRef2(null);
1427
+ const inputRef = useRef2(null);
1428
+ const prevApiUrlRef = useRef2(apiUrl);
1429
+ const setInputRef = (element) => {
1430
+ inputRef.current = element;
1431
+ if (fieldInternalProps?.ref) {
1432
+ if (typeof fieldInternalProps.ref === "function") {
1433
+ fieldInternalProps.ref(element);
1434
+ } else {
1435
+ fieldInternalProps.ref.current = element;
1436
+ }
1437
+ }
1438
+ };
1439
+ const { get, isLoading, error: errorMessage } = useApis_default();
1440
+ const fetchOptions = async (query) => {
1441
+ try {
1442
+ const params = {};
1443
+ if (query) params[queryKey] = query;
1444
+ const response = await get({
1445
+ url: apiUrl,
1446
+ params,
1447
+ v
1448
+ });
1449
+ if (Array.isArray(response)) {
1450
+ setOptions(response);
1451
+ } else if (response?.data && Array.isArray(response.data)) {
1452
+ setOptions(response.data);
1453
+ } else if (response?.items && Array.isArray(response.items)) {
1454
+ setOptions(response.items);
1455
+ } else {
1456
+ setOptions([]);
1457
+ }
1458
+ } catch (err) {
1459
+ console.error("Failed to fetch options:", err);
1460
+ if (form && name) {
1461
+ form.setError(name, {
1462
+ type: "manual",
1463
+ message: err.message || "Failed to fetch options"
1464
+ });
1465
+ }
1466
+ setOptions([]);
1467
+ }
1468
+ };
1469
+ useEffect5(() => {
1470
+ const timer = setTimeout(() => {
1471
+ if (isOpen) {
1472
+ fetchOptions(searchTerm);
1473
+ }
1474
+ }, 300);
1475
+ return () => clearTimeout(timer);
1476
+ }, [searchTerm, apiUrl, isOpen]);
1477
+ useEffect5(() => {
1478
+ if (isOpen && options.length === 0) {
1479
+ fetchOptions("");
1480
+ }
1481
+ }, [isOpen]);
1482
+ useEffect5(() => {
1483
+ if (currentValue && !selectedObject) {
1484
+ setHasAttemptedHydration(false);
1485
+ fetchOptions(currentValue).finally(() => {
1486
+ setHasAttemptedHydration(true);
1487
+ });
1488
+ } else if (!currentValue) {
1489
+ setHasAttemptedHydration(true);
1490
+ if (selectedObject) setSelectedObject(void 0);
1491
+ }
1492
+ }, [currentValue, selectedObject]);
1493
+ const getOptionValue = (option) => {
1494
+ if (valueKey === "_id" && option._id === void 0 && option.id !== void 0) {
1495
+ return option.id;
1496
+ }
1497
+ return option[valueKey];
1498
+ };
1499
+ useEffect5(() => {
1500
+ if (currentValue && !selectedObject && options.length > 0) {
1501
+ const found = options.find((o) => getOptionValue(o) === currentValue);
1502
+ if (found) {
1503
+ setSelectedObject(found);
1504
+ if (form && obj) {
1505
+ form.setValue(obj, found);
1506
+ }
1507
+ }
1508
+ }
1509
+ }, [currentValue, options, selectedObject, form, obj]);
1510
+ useEffect5(() => {
1511
+ if (prevApiUrlRef.current !== apiUrl) {
1512
+ prevApiUrlRef.current = apiUrl;
1513
+ setSearchTerm("");
1514
+ setOptions([]);
1515
+ setSelectedObject(void 0);
1516
+ if (form) {
1517
+ if (name) {
1518
+ form.setValue(name, void 0, {
1519
+ shouldValidate: true,
1520
+ shouldDirty: true
1521
+ });
1522
+ }
1523
+ if (obj) {
1524
+ form.setValue(obj, void 0, {
1525
+ shouldValidate: true,
1526
+ shouldDirty: true
1527
+ });
1528
+ }
1529
+ } else {
1530
+ onChangeHandler(void 0);
1531
+ }
1532
+ fetchOptions("");
1533
+ }
1534
+ }, [apiUrl, form, name, obj, onChangeHandler]);
1535
+ useEffect5(() => {
1536
+ const handleClickOutside = (event) => {
1537
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
1538
+ setIsOpen(false);
1539
+ setIsFocused(false);
1540
+ setSearchTerm("");
1541
+ fieldInternalProps?.onBlur?.();
1542
+ }
1543
+ };
1544
+ document.addEventListener("mousedown", handleClickOutside);
1545
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1546
+ }, [fieldInternalProps]);
1547
+ const getDisplayValue = () => {
1548
+ if (selectedObject) return selectedObject[labelKey];
1549
+ if (options.length > 0 && currentValue) {
1550
+ const found = options.find((o) => getOptionValue(o) === currentValue);
1551
+ if (found) return found[labelKey];
1552
+ }
1553
+ if (isLoading || currentValue && !hasAttemptedHydration)
1554
+ return "Loading...";
1555
+ return currentValue || "";
1556
+ };
1557
+ const handleSelect = (option) => {
1558
+ const value = getOptionValue(option);
1559
+ setSelectedObject(option);
1560
+ onChangeHandler(value);
1561
+ if (form) {
1562
+ if (obj) form.setValue(obj, option);
1563
+ if (name) form.clearErrors(name);
1564
+ }
1565
+ setIsOpen(false);
1566
+ setSearchTerm("");
1567
+ setActiveIndex(-1);
1568
+ fieldInternalProps?.onBlur?.();
1569
+ };
1570
+ const handleKeyDown = (e) => {
1571
+ if (!isOpen) {
1572
+ if (e.key === "ArrowDown" || e.key === "Enter") setIsOpen(true);
1573
+ return;
1574
+ }
1575
+ switch (e.key) {
1576
+ case "ArrowDown":
1577
+ e.preventDefault();
1578
+ setActiveIndex((prev) => prev < options.length - 1 ? prev + 1 : prev);
1579
+ break;
1580
+ case "ArrowUp":
1581
+ e.preventDefault();
1582
+ setActiveIndex((prev) => prev > 0 ? prev - 1 : prev);
1583
+ break;
1584
+ case "Enter":
1585
+ e.preventDefault();
1586
+ if (activeIndex >= 0 && activeIndex < options.length)
1587
+ handleSelect(options[activeIndex]);
1588
+ break;
1589
+ case "Escape":
1590
+ setIsOpen(false);
1591
+ break;
1592
+ }
1593
+ };
1594
+ const clearSelection = (e) => {
1595
+ e.stopPropagation();
1596
+ if (form) {
1597
+ if (name)
1598
+ form.setValue(name, void 0, {
1599
+ shouldValidate: true,
1600
+ shouldDirty: true
1601
+ });
1602
+ if (obj)
1603
+ form.setValue(obj, void 0, {
1604
+ shouldValidate: true,
1605
+ shouldDirty: true
1606
+ });
1607
+ } else {
1608
+ onChangeHandler(void 0);
1609
+ }
1610
+ setSearchTerm("");
1611
+ };
1612
+ const filteredOptions = options.filter(
1613
+ (option) => !filter.includes(getOptionValue(option))
1614
+ );
1615
+ useEffect5(() => {
1616
+ if (form && name && !form.watch(name)) {
1617
+ form.setValue(name, void 0);
1618
+ if (obj) form.setValue(obj, void 0);
1619
+ }
1620
+ }, [form, name, obj]);
1621
+ let message = error;
1622
+ if (form && name) {
1623
+ const {
1624
+ formState: { errors }
1625
+ } = form;
1626
+ const nameParts = name.split(".");
1627
+ let currentError = errors;
1628
+ for (const part of nameParts) {
1629
+ currentError = currentError?.[part];
1630
+ }
1631
+ message = currentError?.message || message;
1632
+ }
1633
+ return /* @__PURE__ */ jsxs13("div", { ref: containerRef, className: `space-y-2 group ${containerClassName}`, children: [
1634
+ label && /* @__PURE__ */ jsxs13(
1635
+ "label",
1636
+ {
1637
+ className: `block text-xs font-medium transition-colors duration-200`,
1638
+ style: { color: isFocused || isOpen ? primaryColor : void 0 },
1639
+ children: [
1640
+ label,
1641
+ required && /* @__PURE__ */ jsx18("span", { className: "text-red-500 ml-1", children: "*" })
1642
+ ]
1643
+ }
1644
+ ),
1645
+ /* @__PURE__ */ jsxs13("div", { className: "relative", children: [
1646
+ /* @__PURE__ */ jsxs13(
1647
+ "div",
1648
+ {
1649
+ className: `flex items-center w-full h-8 rounded-lg border bg-gray-50 dark:bg-zinc-900/50 text-gray-900 dark:text-white transition-all duration-200 cursor-text ${isFocused || isOpen ? "ring-2 bg-white dark:bg-zinc-900" : "border-gray-200 dark:border-zinc-800"} ${className}`,
1650
+ style: {
1651
+ borderColor: isFocused || isOpen ? primaryColor : void 0,
1652
+ boxShadow: isFocused || isOpen ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1653
+ },
1654
+ onClick: () => {
1655
+ if (disabled) return;
1656
+ inputRef.current?.focus();
1657
+ setIsOpen(true);
1658
+ },
1659
+ children: [
1660
+ /* @__PURE__ */ jsx18("div", { className: "pl-3 text-gray-400", children: /* @__PURE__ */ jsx18(Search, { className: "h-4 w-4" }) }),
1661
+ /* @__PURE__ */ jsxs13("div", { className: "flex-1 relative", children: [
1662
+ !isOpen && currentValue && /* @__PURE__ */ jsx18("div", { className: "absolute inset-0 flex items-center px-3 truncate select-none", children: getDisplayValue() }),
1663
+ /* @__PURE__ */ jsx18(
1664
+ "input",
1665
+ {
1666
+ ref: setInputRef,
1667
+ type: "text",
1668
+ className: `block w-full bg-transparent border-none focus:ring-0 h-8 py-0 pr-8 placeholder-gray-400 focus:outline-none text-sm ${!isOpen && currentValue ? "opacity-0" : "opacity-100"}`,
1669
+ placeholder: !currentValue ? placeholder : "",
1670
+ value: searchTerm,
1671
+ onChange: (e) => setSearchTerm(e.target.value),
1672
+ onFocus: () => {
1673
+ setIsFocused(true);
1674
+ setIsOpen(true);
1675
+ },
1676
+ onKeyDown: handleKeyDown,
1677
+ disabled,
1678
+ ...props
1679
+ }
1680
+ )
1681
+ ] }),
1682
+ /* @__PURE__ */ jsx18("div", { className: "pr-3 flex items-center gap-1", children: isLoading ? /* @__PURE__ */ jsx18(Loader22, { className: "h-4 w-4 animate-spin text-blue-500" }) : /* @__PURE__ */ jsxs13(Fragment2, { children: [
1683
+ currentValue && !disabled && /* @__PURE__ */ jsx18(
1684
+ "button",
1685
+ {
1686
+ onClick: clearSelection,
1687
+ type: "button",
1688
+ className: "p-0.5 hover:bg-gray-200 dark:hover:bg-zinc-700 rounded-full text-gray-400 hover:text-gray-600 dark:hover:text-gray-300",
1689
+ children: /* @__PURE__ */ jsx18(X2, { className: "h-3 w-3" })
1690
+ }
1691
+ ),
1692
+ /* @__PURE__ */ jsx18(
1693
+ ChevronDown3,
1694
+ {
1695
+ className: `h-4 w-4 text-gray-400 transition-transform ${isOpen ? "rotate-180" : ""}`
1696
+ }
1697
+ )
1698
+ ] }) })
1699
+ ]
1700
+ }
1701
+ ),
1702
+ isOpen && /* @__PURE__ */ jsx18("div", { className: "absolute z-50 w-full mt-1 bg-white dark:bg-zinc-900 rounded-xl border border-gray-200 dark:border-zinc-800 shadow-lg max-h-60 overflow-y-auto overflow-x-hidden", children: isLoading && options.length === 0 ? /* @__PURE__ */ jsxs13("div", { className: "p-4 text-center text-sm text-gray-500", children: [
1703
+ /* @__PURE__ */ jsx18(Loader22, { className: "h-5 w-5 animate-spin mx-auto mb-2" }),
1704
+ "Loading options..."
1705
+ ] }) : filteredOptions.length > 0 ? /* @__PURE__ */ jsx18("div", { className: "py-1", children: filteredOptions.map((option, index) => {
1706
+ const optValue = getOptionValue(option);
1707
+ const isSelected = currentValue === optValue;
1708
+ const isHighlighted = index === activeIndex;
1709
+ return /* @__PURE__ */ jsxs13(
1710
+ "button",
1711
+ {
1712
+ type: "button",
1713
+ className: `w-full text-left px-3 py-2 text-sm flex items-center justify-between transition-colors ${isSelected ? "font-medium" : isHighlighted ? "bg-gray-100 dark:bg-zinc-800 text-gray-900 dark:text-gray-100" : "text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-zinc-800"}`,
1714
+ style: {
1715
+ backgroundColor: isSelected ? `${primaryColor}1A` : void 0,
1716
+ color: isSelected ? primaryColor : void 0
1717
+ },
1718
+ onClick: () => handleSelect(option),
1719
+ onMouseEnter: () => setActiveIndex(index),
1720
+ children: [
1721
+ /* @__PURE__ */ jsx18("span", { className: "truncate", children: option[labelKey] }),
1722
+ isSelected && /* @__PURE__ */ jsx18(
1723
+ Check2,
1724
+ {
1725
+ className: "h-4 w-4",
1726
+ style: { color: primaryColor }
1727
+ }
1728
+ )
1729
+ ]
1730
+ },
1731
+ optValue || index
1732
+ );
1733
+ }) }) : /* @__PURE__ */ jsx18("div", { className: "p-4 text-center text-sm text-gray-500", children: errorMessage || (searchTerm ? `No results for "${searchTerm}"` : "No options available") }) })
1734
+ ] }),
1735
+ message && /* @__PURE__ */ jsx18("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1736
+ ] });
1737
+ };
1738
+ var SearchApi = forwardRef5(
1739
+ (props, _) => {
1740
+ const { form, name, onChange, value } = props;
1741
+ if (form && name) {
1742
+ return /* @__PURE__ */ jsx18(
1743
+ Controller4,
1744
+ {
1745
+ name,
1746
+ control: form.control,
1747
+ render: ({
1748
+ field: { onChange: formOnChange, value: formValue, ref, onBlur }
1749
+ }) => /* @__PURE__ */ jsx18(
1750
+ SearchApiContent,
1751
+ {
1752
+ ...props,
1753
+ currentValue: formValue,
1754
+ onChangeHandler: formOnChange,
1755
+ fieldInternalProps: { ref, onBlur }
1756
+ }
1757
+ )
1758
+ }
1759
+ );
1760
+ }
1761
+ return /* @__PURE__ */ jsx18(
1762
+ SearchApiContent,
1763
+ {
1764
+ ...props,
1765
+ currentValue: value,
1766
+ onChangeHandler: onChange || (() => {
1767
+ })
1768
+ }
1769
+ );
1770
+ }
1771
+ );
1772
+ SearchApi.displayName = "SearchApi";
1773
+
1774
+ // src/components/Fields/date.tsx
1775
+ import { forwardRef as forwardRef6, useState as useState12 } from "react";
1776
+ import { DatePicker } from "antd";
1777
+ import {
1778
+ Controller as Controller5
1779
+ } from "react-hook-form";
1780
+ import dayjs from "dayjs";
1781
+ import customParseFormat from "dayjs/plugin/customParseFormat";
1782
+ import { Calendar } from "lucide-react";
1783
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
1784
+ dayjs.extend(customParseFormat);
1785
+ var DateInput = forwardRef6(
1786
+ ({
1787
+ label,
1788
+ error,
1789
+ containerClassName = "",
1790
+ name,
1791
+ form,
1792
+ className = "",
1793
+ value,
1794
+ onBlur = () => {
1795
+ },
1796
+ onChange = () => {
1797
+ },
1798
+ ...props
1799
+ }, ref) => {
1800
+ const { theme } = useWarqadConfig();
1801
+ const primaryColor = theme?.primaryColor;
1802
+ const [isFocused, setIsFocused] = useState12(false);
1803
+ let message = error;
1804
+ if (form && name) {
1805
+ const {
1806
+ formState: { errors }
1807
+ } = form;
1808
+ const errorObj = name.split(".").reduce((acc, current) => acc?.[current], errors);
1809
+ message = errorObj?.message;
1810
+ }
1811
+ const inputStyles = `w-full px-3 py-0 rounded-lg! border! shadow-none transition-all! duration-200! outline-none!
1812
+ bg-gray-50! dark:bg-zinc-900!
1813
+ text-gray-900! dark:text-zinc-100!
1814
+ hover:bg-gray-50! dark:hover:bg-zinc-900!
1815
+ ${message ? "border-red-500 hover:border-red-500 [&.ant-picker-focused]:border-red-500 [&.ant-picker-focused]:ring-red-500/20" : "border-gray-200 dark:border-zinc-700 hover:border-gray-200 dark:hover:border-zinc-700 [&.ant-picker-focused]:ring-2"}
1816
+ [&.ant-picker-focused]:bg-white dark:[&.ant-picker-focused]:bg-zinc-900
1817
+ ${className}`;
1818
+ const renderDatePicker = (val, changeHandler, blurHandler, refProps) => {
1819
+ const dateValue = val && typeof val === "string" ? dayjs(val, "DD/MM/YYYY", true) : dayjs.isDayjs(val) ? val : null;
1820
+ return /* @__PURE__ */ jsx19(
1821
+ DatePicker,
1822
+ {
1823
+ ref: refProps,
1824
+ format: "DD/MM/YYYY",
1825
+ value: dateValue && dateValue.isValid() ? dateValue : null,
1826
+ onChange: (date) => {
1827
+ if (date && dayjs.isDayjs(date)) {
1828
+ changeHandler?.(date.format("DD/MM/YYYY"));
1829
+ } else {
1830
+ changeHandler?.("");
1831
+ }
1832
+ },
1833
+ onFocus: () => setIsFocused(true),
1834
+ onBlur: () => {
1835
+ setIsFocused(false);
1836
+ blurHandler?.();
1837
+ },
1838
+ className: `${inputStyles} [&>input]:text-gray-900! [&>input]:dark:text-zinc-100! [&>input]:text-base rounded-md`,
1839
+ placeholder: "DD/MM/YYYY",
1840
+ needConfirm: false,
1841
+ style: {
1842
+ height: "32px",
1843
+ borderColor: isFocused && !message ? primaryColor : void 0,
1844
+ boxShadow: isFocused && !message ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1845
+ },
1846
+ popupClassName: "z-50",
1847
+ suffixIcon: /* @__PURE__ */ jsx19(
1848
+ Calendar,
1849
+ {
1850
+ className: "h-5 w-5 text-gray-400",
1851
+ style: { color: isFocused ? primaryColor : void 0 }
1852
+ }
1853
+ ),
1854
+ allowClear: true,
1855
+ ...props
1856
+ }
1857
+ );
1858
+ };
1859
+ return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 group ${containerClassName}`, children: [
1860
+ /* @__PURE__ */ jsx19(
1861
+ "label",
1862
+ {
1863
+ className: "block text-xs font-medium transition-colors duration-200",
1864
+ style: {
1865
+ color: message ? "#ef4444" : isFocused ? primaryColor : void 0
1866
+ },
1867
+ children: label
1868
+ }
1869
+ ),
1870
+ form && name ? /* @__PURE__ */ jsx19(
1871
+ Controller5,
1872
+ {
1873
+ control: form.control,
1874
+ name,
1875
+ render: ({ field }) => renderDatePicker(
1876
+ field.value,
1877
+ field.onChange,
1878
+ field.onBlur,
1879
+ field.ref
1880
+ )
1881
+ }
1882
+ ) : renderDatePicker(value, onChange, onBlur, ref),
1883
+ message && /* @__PURE__ */ jsx19("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1884
+ ] });
1885
+ }
1886
+ );
1887
+
1888
+ // src/components/Fields/index.tsx
1889
+ var Fields = {
1890
+ Input,
1891
+ PhoneInput,
1892
+ Select,
1893
+ Textarea,
1894
+ SearchApi,
1895
+ DateInput
1896
+ };
1897
+ var Fields_default = Fields;
1898
+
1899
+ // src/components/tables/DataTable.tsx
1900
+ import { useState as useState13, useEffect as useEffect6 } from "react";
1901
+ import {
1902
+ useReactTable,
1903
+ getCoreRowModel,
1904
+ getPaginationRowModel,
1905
+ getSortedRowModel,
1906
+ getFilteredRowModel,
1907
+ flexRender
1908
+ } from "@tanstack/react-table";
1909
+ import { ChevronDown as ChevronDown4, Search as Search2 } from "lucide-react";
1910
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1911
+ function DataTable({
1912
+ columns,
1913
+ data,
1914
+ isLoading = false,
1915
+ pageRows,
1916
+ searchPlaceholder = "Search all columns...",
1917
+ className = "",
1918
+ onChange
1919
+ }) {
1920
+ const { theme } = useWarqadConfig();
1921
+ const primaryColor = theme?.primaryColor;
1922
+ const [sorting, setSorting] = useState13([]);
1923
+ const [columnFilters, setColumnFilters] = useState13([]);
1924
+ const [columnVisibility, setColumnVisibility] = useState13({});
1925
+ const [rowSelection, setRowSelection] = useState13({});
1926
+ const [globalFilter, setGlobalFilter] = useState13("");
1927
+ const table = useReactTable({
1928
+ data,
1929
+ columns,
1930
+ onSortingChange: setSorting,
1931
+ onColumnFiltersChange: setColumnFilters,
1932
+ getCoreRowModel: getCoreRowModel(),
1933
+ getPaginationRowModel: pageRows ? getPaginationRowModel() : void 0,
1934
+ getSortedRowModel: getSortedRowModel(),
1935
+ getFilteredRowModel: getFilteredRowModel(),
1936
+ onColumnVisibilityChange: setColumnVisibility,
1937
+ onRowSelectionChange: setRowSelection,
1938
+ onGlobalFilterChange: setGlobalFilter,
1939
+ globalFilterFn: "includesString",
1940
+ state: {
1941
+ sorting,
1942
+ columnFilters,
1943
+ columnVisibility,
1944
+ rowSelection,
1945
+ globalFilter,
1946
+ ...pageRows ? { pagination: { pageSize: pageRows, pageIndex: 0 } } : {}
1947
+ },
1948
+ manualPagination: false
1949
+ });
1950
+ useEffect6(() => {
1951
+ if (onChange) {
1952
+ onChange({
1953
+ pagination: {
1954
+ pageIndex: table.getState().pagination.pageIndex,
1955
+ pageSize: table.getState().pagination.pageSize,
1956
+ pageCount: table.getPageCount()
1957
+ },
1958
+ sorting,
1959
+ columnFilters,
1960
+ globalFilter,
1961
+ selectedRows: table.getSelectedRowModel().rows.map((row) => row.original),
1962
+ filteredData: table.getFilteredRowModel().rows.map((row) => row.original)
1963
+ });
1964
+ }
1965
+ }, [
1966
+ sorting,
1967
+ columnFilters,
1968
+ globalFilter,
1969
+ rowSelection,
1970
+ table,
1971
+ onChange,
1972
+ table.getState().pagination.pageIndex,
1973
+ table.getState().pagination.pageSize
1974
+ ]);
1975
+ return /* @__PURE__ */ jsxs15("div", { className: `space-y-4 w-full ${className}`, children: [
1976
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between gap-4", children: [
1977
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 max-w-sm", children: /* @__PURE__ */ jsx20(
1978
+ Fields_default.Input,
1979
+ {
1980
+ label: "Search",
1981
+ placeholder: searchPlaceholder,
1982
+ value: globalFilter,
1983
+ onChange: (e) => setGlobalFilter(e.target.value),
1984
+ icon: /* @__PURE__ */ jsx20(Search2, { size: 16 }),
1985
+ className: "!h-9"
1986
+ }
1987
+ ) }),
1988
+ /* @__PURE__ */ jsx20("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs15("div", { className: "relative group", children: [
1989
+ /* @__PURE__ */ jsxs15("button", { className: "flex items-center gap-2 px-3 h-9 rounded-lg border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 text-sm font-medium text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-zinc-800 transition-colors", children: [
1990
+ "Columns",
1991
+ /* @__PURE__ */ jsx20(ChevronDown4, { size: 14, className: "text-gray-400" })
1992
+ ] }),
1993
+ /* @__PURE__ */ jsx20("div", { className: "absolute right-0 top-full mt-2 w-48 py-1 bg-white dark:bg-zinc-900 border border-gray-200 dark:border-zinc-800 rounded-lg shadow-xl opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all z-50", children: table.getAllColumns().filter((column) => column.getCanHide()).map((column) => /* @__PURE__ */ jsxs15(
1994
+ "label",
1995
+ {
1996
+ className: "flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-zinc-800 cursor-pointer capitalize",
1997
+ children: [
1998
+ /* @__PURE__ */ jsx20(
1999
+ "input",
2000
+ {
2001
+ type: "checkbox",
2002
+ checked: column.getIsVisible(),
2003
+ onChange: (e) => column.toggleVisibility(!!e.target.checked),
2004
+ className: "rounded border-gray-300 text-blue-600 focus:ring-blue-500",
2005
+ style: { accentColor: primaryColor }
2006
+ }
2007
+ ),
2008
+ column.id
2009
+ ]
2010
+ },
2011
+ column.id
2012
+ )) })
2013
+ ] }) })
2014
+ ] }),
2015
+ /* @__PURE__ */ jsx20("div", { className: "rounded-lg border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 overflow-hidden relative", children: /* @__PURE__ */ jsx20("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs15("table", { className: "w-full text-left border-collapse", children: [
2016
+ /* @__PURE__ */ jsx20("thead", { className: "bg-gray-50/50 dark:bg-zinc-900/50 border-b border-gray-200 dark:border-zinc-800", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx20("tr", { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx20(
2017
+ "th",
2018
+ {
2019
+ className: "px-4 py-3 text-[13px] font-semibold text-gray-900 dark:text-zinc-100 text-left",
2020
+ children: header.isPlaceholder ? null : flexRender(
2021
+ header.column.columnDef.header,
2022
+ header.getContext()
2023
+ )
2024
+ },
2025
+ header.id
2026
+ )) }, headerGroup.id)) }),
2027
+ /* @__PURE__ */ jsx20("tbody", { className: "divide-y divide-gray-200 dark:divide-zinc-800", children: isLoading ? Array.from({ length: pageRows || 5 }).map((_, i) => /* @__PURE__ */ jsx20(
2028
+ "tr",
2029
+ {
2030
+ className: "border-b border-gray-100 dark:border-zinc-800/50",
2031
+ children: columns.map((_2, j) => /* @__PURE__ */ jsx20("td", { className: "px-4 py-4", children: /* @__PURE__ */ jsx20("div", { className: "h-4 bg-gray-100 dark:bg-zinc-800 rounded animate-pulse w-full" }) }, `skeleton-cell-${j}`))
2032
+ },
2033
+ `skeleton-${i}`
2034
+ )) : table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx20(
2035
+ "tr",
2036
+ {
2037
+ className: "hover:bg-gray-50/50 dark:hover:bg-zinc-900/50 transition-colors",
2038
+ "data-state": row.getIsSelected() && "selected",
2039
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx20(
2040
+ "td",
2041
+ {
2042
+ className: "px-4 py-3 text-sm text-gray-700 dark:text-gray-200",
2043
+ children: flexRender(
2044
+ cell.column.columnDef.cell,
2045
+ cell.getContext()
2046
+ )
2047
+ },
2048
+ cell.id
2049
+ ))
2050
+ },
2051
+ row.id
2052
+ )) : /* @__PURE__ */ jsx20("tr", { children: /* @__PURE__ */ jsx20(
2053
+ "td",
2054
+ {
2055
+ colSpan: columns.length,
2056
+ className: "h-32 text-center text-sm text-gray-500",
2057
+ children: "No results found."
2058
+ }
2059
+ ) }) })
2060
+ ] }) }) }),
2061
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between px-2", children: [
2062
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1 text-xs text-gray-500", children: [
2063
+ table.getFilteredSelectedRowModel().rows.length,
2064
+ " of",
2065
+ " ",
2066
+ table.getFilteredRowModel().rows.length,
2067
+ " row(s) selected."
2068
+ ] }),
2069
+ pageRows && table.getPageCount() > 1 && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
2070
+ /* @__PURE__ */ jsx20(
2071
+ "button",
2072
+ {
2073
+ onClick: () => table.previousPage(),
2074
+ disabled: !table.getCanPreviousPage(),
2075
+ className: "p-1 px-3 rounded-md border border-gray-200 dark:border-zinc-800 text-sm disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-50 dark:hover:bg-zinc-800 transition-colors",
2076
+ children: "Previous"
2077
+ }
2078
+ ),
2079
+ /* @__PURE__ */ jsx20(
2080
+ "button",
2081
+ {
2082
+ onClick: () => table.nextPage(),
2083
+ disabled: !table.getCanNextPage(),
2084
+ className: "p-1 px-3 rounded-md border border-gray-200 dark:border-zinc-800 text-sm disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-50 dark:hover:bg-zinc-800 transition-colors",
2085
+ children: "Next"
2086
+ }
2087
+ )
2088
+ ] })
2089
+ ] })
2090
+ ] });
2091
+ }
2092
+
2093
+ // src/utils/pdf.ts
2094
+ import html2canvas from "html2canvas-pro";
2095
+ import { jsPDF } from "jspdf";
2096
+ var generatePdf = async (elementId, options = {}) => {
2097
+ const {
2098
+ orientation = "landscape",
2099
+ unit = "mm",
2100
+ format = "a4",
2101
+ filename = "export.pdf",
2102
+ margin = 10,
2103
+ windowWidth = 1200,
2104
+ scale = 1,
2105
+ showPageNumbers = true
2106
+ } = options;
2107
+ const element = document.getElementById(elementId);
2108
+ if (!element) {
2109
+ console.error(
2110
+ `PDF generation failed: Element with ID "${elementId}" not found.`
2111
+ );
2112
+ return;
2113
+ }
2114
+ try {
2115
+ const pdf = new jsPDF({
2116
+ orientation,
2117
+ unit,
2118
+ format,
2119
+ compress: true
2120
+ });
2121
+ const pageWidth = pdf.internal.pageSize.getWidth();
2122
+ const pageHeight = pdf.internal.pageSize.getHeight();
2123
+ window.html2canvas = html2canvas;
2124
+ await pdf.html(element, {
2125
+ callback: function(doc) {
2126
+ if (showPageNumbers) {
2127
+ const pageCount = doc.internal.getNumberOfPages();
2128
+ for (let i = 1; i <= pageCount; i++) {
2129
+ doc.setPage(i);
2130
+ doc.setFontSize(8);
2131
+ doc.setTextColor(150);
2132
+ const text = `Page ${i} of ${pageCount}`;
2133
+ const textWidth = doc.getStringUnitWidth(text) * 8 / doc.internal.scaleFactor;
2134
+ doc.text(text, (pageWidth - textWidth) / 2, pageHeight - 5);
2135
+ }
2136
+ }
2137
+ doc.save(filename);
2138
+ const pdfBlob = doc.output("blob");
2139
+ const url = URL.createObjectURL(pdfBlob);
2140
+ window.open(url, "_blank");
2141
+ },
2142
+ x: margin,
2143
+ y: margin,
2144
+ width: pageWidth - margin * 2,
2145
+ windowWidth,
2146
+ html2canvas: {
2147
+ useCORS: true,
2148
+ scale: Math.max(scale, 2),
2149
+ // Ensure scale is at least 2 for text clarity
2150
+ logging: false,
2151
+ onclone: (clonedDoc) => {
2152
+ const elements = clonedDoc.getElementsByTagName("*");
2153
+ const tempCanvas = clonedDoc.createElement("canvas");
2154
+ tempCanvas.width = 1;
2155
+ tempCanvas.height = 1;
2156
+ const ctx = tempCanvas.getContext("2d");
2157
+ const target = clonedDoc.getElementById(elementId);
2158
+ if (target) {
2159
+ target.style.width = `${windowWidth}px`;
2160
+ target.style.maxWidth = "none";
2161
+ }
2162
+ const toRgb = (color) => {
2163
+ if (!color || !color.includes("oklch") && !color.includes("oklab"))
2164
+ return color;
2165
+ if (!ctx) return "rgb(0,0,0)";
2166
+ try {
2167
+ ctx.fillStyle = color;
2168
+ const result = ctx.fillStyle;
2169
+ return result.includes("ok") ? "rgb(0,0,0)" : result;
2170
+ } catch (e) {
2171
+ return "rgb(0,0,0)";
2172
+ }
2173
+ };
2174
+ for (let i = 0; i < elements.length; i++) {
2175
+ const el = elements[i];
2176
+ const style = window.getComputedStyle(elements[i]);
2177
+ const colorProps = [
2178
+ "color",
2179
+ "backgroundColor",
2180
+ "borderColor",
2181
+ "borderTopColor",
2182
+ "borderBottomColor",
2183
+ "borderLeftColor",
2184
+ "borderRightColor",
2185
+ "fill",
2186
+ "stroke",
2187
+ "outlineColor",
2188
+ "stopColor",
2189
+ "floodColor",
2190
+ "lightingColor"
2191
+ ];
2192
+ colorProps.forEach((prop) => {
2193
+ const val = style[prop];
2194
+ if (val && (val.includes("oklch") || val.includes("oklab"))) {
2195
+ el.style[prop] = toRgb(val);
2196
+ }
2197
+ });
2198
+ }
2199
+ const styleTags = clonedDoc.getElementsByTagName("style");
2200
+ for (let i = 0; i < styleTags.length; i++) {
2201
+ let cssText = styleTags[i].innerHTML;
2202
+ if (cssText.includes("oklch") || cssText.includes("oklab")) {
2203
+ cssText = cssText.replace(/oklch\([^)]+\)/g, "rgb(0,0,0)");
2204
+ cssText = cssText.replace(/oklab\([^)]+\)/g, "rgb(0,0,0)");
2205
+ styleTags[i].innerHTML = cssText;
2206
+ }
2207
+ }
2208
+ }
2209
+ },
2210
+ autoPaging: "text"
2211
+ });
2212
+ } catch (error) {
2213
+ console.error("PDF generation failed:", error);
2214
+ throw error;
2215
+ }
2216
+ };
2217
+ export {
2218
+ Button,
2219
+ Card,
2220
+ CardContent,
2221
+ CardDescription,
2222
+ CardFooter,
2223
+ CardHeader,
2224
+ CardTitle,
2225
+ ClassicSpin,
2226
+ CodeBlock,
2227
+ DashboardLayout,
2228
+ DataTable,
2229
+ DateInput,
2230
+ Fields_default as Fields,
2231
+ Input,
2232
+ LoadingBox,
2233
+ LoadingSpin,
2234
+ Modal,
2235
+ OverlaySpin,
2236
+ PageHeader,
2237
+ PhoneInput,
2238
+ SearchApi,
2239
+ Select,
2240
+ Textarea,
2241
+ ThemeProvider,
2242
+ ThemeToggle,
2243
+ WarqadProvider,
2244
+ generatePdf,
2245
+ useApis_default as useApi,
2246
+ useModal,
2247
+ useTheme,
2248
+ useWarqadConfig
2249
+ };