warqadui 0.0.8 → 0.0.11

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 (170) hide show
  1. package/{packages/ui/dist → dist}/index.d.mts +100 -12
  2. package/{packages/ui/dist → dist}/index.d.ts +100 -12
  3. package/dist/index.js +3276 -0
  4. package/dist/index.mjs +3237 -0
  5. package/dist/styles.js +26 -0
  6. package/dist/styles.mjs +24 -0
  7. package/package.json +60 -10
  8. package/.vscode/settings.json +0 -3
  9. package/apps/dev-app/.env +0 -1
  10. package/apps/dev-app/errors.log +0 -0
  11. package/apps/dev-app/index.html +0 -12
  12. package/apps/dev-app/node_modules/.vite/deps/@tanstack_react-table.js +0 -3254
  13. package/apps/dev-app/node_modules/.vite/deps/@tanstack_react-table.js.map +0 -7
  14. package/apps/dev-app/node_modules/.vite/deps/_metadata.json +0 -166
  15. package/apps/dev-app/node_modules/.vite/deps/antd.js +0 -108982
  16. package/apps/dev-app/node_modules/.vite/deps/antd.js.map +0 -7
  17. package/apps/dev-app/node_modules/.vite/deps/axios.js +0 -2751
  18. package/apps/dev-app/node_modules/.vite/deps/axios.js.map +0 -7
  19. package/apps/dev-app/node_modules/.vite/deps/chunk-5OG7DCD7.js +0 -41
  20. package/apps/dev-app/node_modules/.vite/deps/chunk-5OG7DCD7.js.map +0 -7
  21. package/apps/dev-app/node_modules/.vite/deps/chunk-DC5AMYBS.js +0 -39
  22. package/apps/dev-app/node_modules/.vite/deps/chunk-DC5AMYBS.js.map +0 -7
  23. package/apps/dev-app/node_modules/.vite/deps/chunk-DKXRQMOD.js +0 -135
  24. package/apps/dev-app/node_modules/.vite/deps/chunk-DKXRQMOD.js.map +0 -7
  25. package/apps/dev-app/node_modules/.vite/deps/chunk-EL47BWQR.js +0 -37
  26. package/apps/dev-app/node_modules/.vite/deps/chunk-EL47BWQR.js.map +0 -7
  27. package/apps/dev-app/node_modules/.vite/deps/chunk-HHL3MHGV.js +0 -288
  28. package/apps/dev-app/node_modules/.vite/deps/chunk-HHL3MHGV.js.map +0 -7
  29. package/apps/dev-app/node_modules/.vite/deps/chunk-IGGUWUPT.js +0 -60
  30. package/apps/dev-app/node_modules/.vite/deps/chunk-IGGUWUPT.js.map +0 -7
  31. package/apps/dev-app/node_modules/.vite/deps/chunk-IGXZPJXT.js +0 -928
  32. package/apps/dev-app/node_modules/.vite/deps/chunk-IGXZPJXT.js.map +0 -7
  33. package/apps/dev-app/node_modules/.vite/deps/chunk-L2GCM37S.js +0 -21628
  34. package/apps/dev-app/node_modules/.vite/deps/chunk-L2GCM37S.js.map +0 -7
  35. package/apps/dev-app/node_modules/.vite/deps/chunk-M7DZDBHW.js +0 -14
  36. package/apps/dev-app/node_modules/.vite/deps/chunk-M7DZDBHW.js.map +0 -7
  37. package/apps/dev-app/node_modules/.vite/deps/chunk-S54SBVCU.js +0 -1906
  38. package/apps/dev-app/node_modules/.vite/deps/chunk-S54SBVCU.js.map +0 -7
  39. package/apps/dev-app/node_modules/.vite/deps/chunk-WFNHCR67.js +0 -21
  40. package/apps/dev-app/node_modules/.vite/deps/chunk-WFNHCR67.js.map +0 -7
  41. package/apps/dev-app/node_modules/.vite/deps/clsx.js +0 -10
  42. package/apps/dev-app/node_modules/.vite/deps/clsx.js.map +0 -7
  43. package/apps/dev-app/node_modules/.vite/deps/dayjs.js +0 -6
  44. package/apps/dev-app/node_modules/.vite/deps/dayjs.js.map +0 -7
  45. package/apps/dev-app/node_modules/.vite/deps/dayjs_plugin_customParseFormat.js +0 -6
  46. package/apps/dev-app/node_modules/.vite/deps/dayjs_plugin_customParseFormat.js.map +0 -7
  47. package/apps/dev-app/node_modules/.vite/deps/framer-motion.js +0 -12388
  48. package/apps/dev-app/node_modules/.vite/deps/framer-motion.js.map +0 -7
  49. package/apps/dev-app/node_modules/.vite/deps/html2canvas-pro.js +0 -9713
  50. package/apps/dev-app/node_modules/.vite/deps/html2canvas-pro.js.map +0 -7
  51. package/apps/dev-app/node_modules/.vite/deps/html2canvas.esm-IYRWPPEI.js +0 -7808
  52. package/apps/dev-app/node_modules/.vite/deps/html2canvas.esm-IYRWPPEI.js.map +0 -7
  53. package/apps/dev-app/node_modules/.vite/deps/index.es-3WTXOFZ2.js +0 -10392
  54. package/apps/dev-app/node_modules/.vite/deps/index.es-3WTXOFZ2.js.map +0 -7
  55. package/apps/dev-app/node_modules/.vite/deps/jspdf.js +0 -14806
  56. package/apps/dev-app/node_modules/.vite/deps/jspdf.js.map +0 -7
  57. package/apps/dev-app/node_modules/.vite/deps/lucide-react.js +0 -31586
  58. package/apps/dev-app/node_modules/.vite/deps/lucide-react.js.map +0 -7
  59. package/apps/dev-app/node_modules/.vite/deps/package.json +0 -3
  60. package/apps/dev-app/node_modules/.vite/deps/purify.es-JNLDEIMX.js +0 -1029
  61. package/apps/dev-app/node_modules/.vite/deps/purify.es-JNLDEIMX.js.map +0 -7
  62. package/apps/dev-app/node_modules/.vite/deps/react-dom.js +0 -7
  63. package/apps/dev-app/node_modules/.vite/deps/react-dom.js.map +0 -7
  64. package/apps/dev-app/node_modules/.vite/deps/react-dom_client.js +0 -8
  65. package/apps/dev-app/node_modules/.vite/deps/react-dom_client.js.map +0 -7
  66. package/apps/dev-app/node_modules/.vite/deps/react-hook-form.js +0 -2233
  67. package/apps/dev-app/node_modules/.vite/deps/react-hook-form.js.map +0 -7
  68. package/apps/dev-app/node_modules/.vite/deps/react-phone-number-input.js +0 -9307
  69. package/apps/dev-app/node_modules/.vite/deps/react-phone-number-input.js.map +0 -7
  70. package/apps/dev-app/node_modules/.vite/deps/react-router-dom.js +0 -14234
  71. package/apps/dev-app/node_modules/.vite/deps/react-router-dom.js.map +0 -7
  72. package/apps/dev-app/node_modules/.vite/deps/react.js +0 -6
  73. package/apps/dev-app/node_modules/.vite/deps/react.js.map +0 -7
  74. package/apps/dev-app/node_modules/.vite/deps/react_jsx-dev-runtime.js +0 -913
  75. package/apps/dev-app/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +0 -7
  76. package/apps/dev-app/node_modules/.vite/deps/react_jsx-runtime.js +0 -7
  77. package/apps/dev-app/node_modules/.vite/deps/react_jsx-runtime.js.map +0 -7
  78. package/apps/dev-app/node_modules/.vite/deps/tailwind-merge.js +0 -2534
  79. package/apps/dev-app/node_modules/.vite/deps/tailwind-merge.js.map +0 -7
  80. package/apps/dev-app/node_modules/tailwindcss/LICENSE +0 -21
  81. package/apps/dev-app/node_modules/tailwindcss/README.md +0 -36
  82. package/apps/dev-app/node_modules/tailwindcss/dist/chunk-L5IEUH3R.mjs +0 -38
  83. package/apps/dev-app/node_modules/tailwindcss/dist/chunk-UWKE2Z6N.mjs +0 -1
  84. package/apps/dev-app/node_modules/tailwindcss/dist/chunk-X4GG3EDV.mjs +0 -1
  85. package/apps/dev-app/node_modules/tailwindcss/dist/colors-C__qRT83.d.ts +0 -347
  86. package/apps/dev-app/node_modules/tailwindcss/dist/colors.d.mts +0 -347
  87. package/apps/dev-app/node_modules/tailwindcss/dist/colors.d.ts +0 -5
  88. package/apps/dev-app/node_modules/tailwindcss/dist/colors.js +0 -1
  89. package/apps/dev-app/node_modules/tailwindcss/dist/colors.mjs +0 -1
  90. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.d.mts +0 -1199
  91. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.d.ts +0 -1199
  92. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.js +0 -1
  93. package/apps/dev-app/node_modules/tailwindcss/dist/default-theme.mjs +0 -1
  94. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.d.mts +0 -6
  95. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.d.ts +0 -6
  96. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.js +0 -3
  97. package/apps/dev-app/node_modules/tailwindcss/dist/flatten-color-palette.mjs +0 -1
  98. package/apps/dev-app/node_modules/tailwindcss/dist/lib.d.mts +0 -378
  99. package/apps/dev-app/node_modules/tailwindcss/dist/lib.d.ts +0 -3
  100. package/apps/dev-app/node_modules/tailwindcss/dist/lib.js +0 -38
  101. package/apps/dev-app/node_modules/tailwindcss/dist/lib.mjs +0 -1
  102. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.d.mts +0 -11
  103. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.d.ts +0 -134
  104. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.js +0 -1
  105. package/apps/dev-app/node_modules/tailwindcss/dist/plugin.mjs +0 -1
  106. package/apps/dev-app/node_modules/tailwindcss/dist/resolve-config-B4yBzhca.d.ts +0 -29
  107. package/apps/dev-app/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.mts +0 -190
  108. package/apps/dev-app/node_modules/tailwindcss/dist/types-CJYAW1ql.d.mts +0 -128
  109. package/apps/dev-app/node_modules/tailwindcss/index.css +0 -944
  110. package/apps/dev-app/node_modules/tailwindcss/package.json +0 -89
  111. package/apps/dev-app/node_modules/tailwindcss/preflight.css +0 -393
  112. package/apps/dev-app/node_modules/tailwindcss/theme.css +0 -510
  113. package/apps/dev-app/node_modules/tailwindcss/utilities.css +0 -1
  114. package/apps/dev-app/package.json +0 -34
  115. package/apps/dev-app/src/App.tsx +0 -74
  116. package/apps/dev-app/src/index.css +0 -18
  117. package/apps/dev-app/src/main.tsx +0 -18
  118. package/apps/dev-app/src/pages/Buttons.tsx +0 -122
  119. package/apps/dev-app/src/pages/DataTable.tsx +0 -208
  120. package/apps/dev-app/src/pages/Fields.tsx +0 -342
  121. package/apps/dev-app/src/pages/Modals.tsx +0 -151
  122. package/apps/dev-app/src/pages/Spins.tsx +0 -161
  123. package/apps/dev-app/ts_errors.txt +0 -0
  124. package/apps/dev-app/tsconfig.json +0 -25
  125. package/apps/dev-app/tsconfig.node.json +0 -10
  126. package/apps/dev-app/vite.config.ts +0 -11
  127. package/packages/ui/dist/index.js +0 -2296
  128. package/packages/ui/dist/index.mjs +0 -2249
  129. package/packages/ui/dist/styles.js +0 -26
  130. package/packages/ui/dist/styles.mjs +0 -24
  131. package/packages/ui/log.txt +0 -0
  132. package/packages/ui/package.json +0 -70
  133. package/packages/ui/postcss.config.js +0 -6
  134. package/packages/ui/src/components/Button.tsx +0 -85
  135. package/packages/ui/src/components/Card.tsx +0 -97
  136. package/packages/ui/src/components/CodeBlock.tsx +0 -53
  137. package/packages/ui/src/components/DashboardLayout.tsx +0 -442
  138. package/packages/ui/src/components/Fields/Input.tsx +0 -191
  139. package/packages/ui/src/components/Fields/PhoneInput.tsx +0 -134
  140. package/packages/ui/src/components/Fields/date.tsx +0 -165
  141. package/packages/ui/src/components/Fields/index.tsx +0 -17
  142. package/packages/ui/src/components/Fields/searchApi.tsx +0 -479
  143. package/packages/ui/src/components/Fields/select.tsx +0 -131
  144. package/packages/ui/src/components/Fields/textArea.tsx +0 -121
  145. package/packages/ui/src/components/LoadingBox.tsx +0 -11
  146. package/packages/ui/src/components/PageHeader.tsx +0 -34
  147. package/packages/ui/src/components/ThemeToggle.tsx +0 -35
  148. package/packages/ui/src/components/modal/Modal.tsx +0 -81
  149. package/packages/ui/src/components/spins/ClassicSpin.tsx +0 -18
  150. package/packages/ui/src/components/spins/LoadingSpin.tsx +0 -45
  151. package/packages/ui/src/components/spins/OverlaySpin.tsx +0 -10
  152. package/packages/ui/src/components/spins/index.tsx +0 -13
  153. package/packages/ui/src/components/tables/DataTable.tsx +0 -261
  154. package/packages/ui/src/components/tables/index.ts +0 -1
  155. package/packages/ui/src/hooks/Fetches/useApis.tsx +0 -197
  156. package/packages/ui/src/hooks/ThemeContext.tsx +0 -56
  157. package/packages/ui/src/hooks/useModal.tsx +0 -38
  158. package/packages/ui/src/hooks/useTheme.ts +0 -34
  159. package/packages/ui/src/index.ts +0 -24
  160. package/packages/ui/src/providers/WarqadProvider.tsx +0 -69
  161. package/packages/ui/src/styles.css +0 -26
  162. package/packages/ui/src/utils/cn.ts +0 -6
  163. package/packages/ui/src/utils/pdf.ts +0 -171
  164. package/packages/ui/tailwind.config.js +0 -13
  165. package/packages/ui/tsconfig.json +0 -17
  166. package/packages/ui/warqad-ui-0.0.1.tgz +0 -0
  167. package/packages/ui/warqadui-0.0.3.tgz +0 -0
  168. package/warqad-ui-0.0.1.tgz +0 -0
  169. /package/{packages/ui/dist → dist}/styles.d.mts +0 -0
  170. /package/{packages/ui/dist → dist}/styles.d.ts +0 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,3237 @@
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 as useState2, useEffect as useEffect2, 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
+
86
+ // src/providers/WarqadProvider.tsx
87
+ import { createContext as createContext2, useContext as useContext2 } from "react";
88
+
89
+ // src/hooks/ThemeContext.tsx
90
+ import {
91
+ createContext,
92
+ useContext,
93
+ useState,
94
+ useEffect
95
+ } from "react";
96
+ import { jsx as jsx2 } from "react/jsx-runtime";
97
+ var ThemeContext = createContext(void 0);
98
+ var ThemeProvider = ({ children }) => {
99
+ const [isDarkMode, setIsDarkMode] = useState(() => {
100
+ if (typeof window !== "undefined") {
101
+ const savedTheme = localStorage.getItem("theme");
102
+ if (savedTheme) {
103
+ return savedTheme === "dark";
104
+ }
105
+ return window.matchMedia("(prefers-color-scheme: dark)").matches;
106
+ }
107
+ return false;
108
+ });
109
+ useEffect(() => {
110
+ const root = window.document.documentElement;
111
+ if (isDarkMode) {
112
+ root.classList.add("dark");
113
+ localStorage.setItem("theme", "dark");
114
+ } else {
115
+ root.classList.remove("dark");
116
+ localStorage.setItem("theme", "light");
117
+ }
118
+ }, [isDarkMode]);
119
+ const toggleTheme = () => setIsDarkMode((prev) => !prev);
120
+ const setTheme = (theme) => setIsDarkMode(theme === "dark");
121
+ return /* @__PURE__ */ jsx2(ThemeContext.Provider, { value: { isDarkMode, toggleTheme, setTheme }, children });
122
+ };
123
+ var useTheme = () => {
124
+ const context = useContext(ThemeContext);
125
+ if (context === void 0) {
126
+ throw new Error("useTheme must be used within a ThemeProvider");
127
+ }
128
+ return context;
129
+ };
130
+
131
+ // src/providers/WarqadProvider.tsx
132
+ import { jsx as jsx3 } from "react/jsx-runtime";
133
+ var WarqadConfigContext = createContext2(
134
+ void 0
135
+ );
136
+ var useWarqadConfig = () => {
137
+ const context = useContext2(WarqadConfigContext);
138
+ if (context === void 0) {
139
+ throw new Error("useWarqadConfig must be used within a WarqadProvider");
140
+ }
141
+ return context.config;
142
+ };
143
+ var WarqadProvider = ({
144
+ children,
145
+ config = { api: "/api" }
146
+ }) => {
147
+ const mergedConfig = {
148
+ api: "/api",
149
+ ...config,
150
+ theme: {
151
+ primaryColor: "#3b82f6",
152
+ // Default blue-500
153
+ ...config?.theme
154
+ }
155
+ };
156
+ return /* @__PURE__ */ jsx3(WarqadConfigContext.Provider, { value: { config: mergedConfig }, children: /* @__PURE__ */ jsx3(ThemeProvider, { children: /* @__PURE__ */ jsx3(
157
+ "div",
158
+ {
159
+ style: {
160
+ "--primary-color": mergedConfig.theme?.primaryColor
161
+ },
162
+ children
163
+ }
164
+ ) }) });
165
+ };
166
+
167
+ // src/components/DashboardLayout.tsx
168
+ import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
169
+ var useMediaQuery = (query) => {
170
+ const [matches, setMatches] = useState2(() => {
171
+ if (typeof window !== "undefined") {
172
+ return window.matchMedia(query).matches;
173
+ }
174
+ return false;
175
+ });
176
+ useEffect2(() => {
177
+ const media = window.matchMedia(query);
178
+ if (media.matches !== matches) {
179
+ setMatches(media.matches);
180
+ }
181
+ const listener = () => setMatches(media.matches);
182
+ media.addEventListener("change", listener);
183
+ return () => media.removeEventListener("change", listener);
184
+ }, [matches, query]);
185
+ return matches;
186
+ };
187
+ var isPathActive = (navPath, currentPath) => {
188
+ if (!navPath || !currentPath) return false;
189
+ return currentPath === navPath || navPath !== "/" && currentPath.startsWith(`${navPath}/`);
190
+ };
191
+ var SidebarItem = ({
192
+ item,
193
+ isActive,
194
+ isChildActive,
195
+ onClick,
196
+ isExpanded,
197
+ onToggleExpand,
198
+ isSidebarCollapsed
199
+ }) => {
200
+ const config = useWarqadConfig();
201
+ const primaryColor = config.theme?.primaryColor || "#3b82f6";
202
+ const { isDarkMode } = useTheme();
203
+ const hasSubItems = item.subItems && item.subItems.length > 0;
204
+ const shouldHighlight = isActive || hasSubItems && isExpanded || isChildActive;
205
+ return /* @__PURE__ */ jsxs2("div", { className: "mb-1 group relative ", children: [
206
+ /* @__PURE__ */ jsxs2(
207
+ "button",
208
+ {
209
+ type: "button",
210
+ onClick: item.disabled ? void 0 : hasSubItems ? onToggleExpand : onClick,
211
+ disabled: item.disabled,
212
+ title: isSidebarCollapsed ? item.label : void 0,
213
+ className: cn(
214
+ "w-full flex items-center py-2.5 rounded-xl text-sm font-medium transition-all duration-200",
215
+ isSidebarCollapsed ? "justify-center px-2" : "justify-between px-3",
216
+ !shouldHighlight || item.disabled ? "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" : "",
217
+ item.disabled && "opacity-50 cursor-not-allowed grayscale-[0.5]"
218
+ ),
219
+ style: shouldHighlight && !item.disabled ? {
220
+ backgroundColor: isDarkMode ? `${primaryColor}33` : `${primaryColor}1A`,
221
+ color: primaryColor
222
+ } : void 0,
223
+ children: [
224
+ /* @__PURE__ */ jsxs2(
225
+ "div",
226
+ {
227
+ className: cn(
228
+ "flex items-center gap-3 overflow-hidden",
229
+ isSidebarCollapsed ? "justify-center w-full" : ""
230
+ ),
231
+ children: [
232
+ item.icon && /* @__PURE__ */ jsx4(
233
+ "span",
234
+ {
235
+ className: cn(
236
+ "shrink-0 transition-colors [&_svg]:w-4 [&_svg]:h-4",
237
+ !shouldHighlight || item.disabled ? "text-gray-400 dark:text-gray-500" : "",
238
+ item.disabled && "group-hover:text-gray-400"
239
+ ),
240
+ style: shouldHighlight && !item.disabled ? { color: primaryColor } : { color: "var(--icon-color)" },
241
+ children: item.icon
242
+ }
243
+ ),
244
+ /* @__PURE__ */ jsx4(AnimatePresence, { children: !isSidebarCollapsed && /* @__PURE__ */ jsx4(
245
+ motion.span,
246
+ {
247
+ initial: { opacity: 0, width: 0 },
248
+ animate: { opacity: 1, width: "auto" },
249
+ exit: { opacity: 0, width: 0 },
250
+ transition: { duration: 0.2 },
251
+ className: "truncate",
252
+ children: item.label
253
+ }
254
+ ) })
255
+ ]
256
+ }
257
+ ),
258
+ !isSidebarCollapsed && hasSubItems && /* @__PURE__ */ jsx4(
259
+ "span",
260
+ {
261
+ className: cn(
262
+ "shrink-0 ml-2 transition-transform duration-200",
263
+ !shouldHighlight && "text-gray-400"
264
+ ),
265
+ style: shouldHighlight ? { color: primaryColor } : void 0,
266
+ children: isExpanded ? /* @__PURE__ */ jsx4(ChevronDown, { size: 16 }) : /* @__PURE__ */ jsx4(ChevronRight, { size: 16 })
267
+ }
268
+ )
269
+ ]
270
+ }
271
+ ),
272
+ /* @__PURE__ */ jsx4(AnimatePresence, { initial: false, children: !isSidebarCollapsed && hasSubItems && isExpanded && !item.disabled && /* @__PURE__ */ jsx4(
273
+ motion.div,
274
+ {
275
+ initial: { height: 0, opacity: 0 },
276
+ animate: { height: "auto", opacity: 1 },
277
+ exit: { height: 0, opacity: 0 },
278
+ transition: { duration: 0.2 },
279
+ className: "overflow-hidden",
280
+ children: /* @__PURE__ */ jsxs2("div", { className: "relative ml-6 mt-1 space-y-1", children: [
281
+ /* @__PURE__ */ jsx4("div", { className: "absolute left-0 top-0 bottom-0 w-px bg-gray-200 dark:bg-gray-800" }),
282
+ item.subItems.filter((sub) => !!sub && !sub.hidden).map((subItem, index) => /* @__PURE__ */ jsx4(
283
+ SubItem,
284
+ {
285
+ item: subItem,
286
+ parentDisabled: item.disabled
287
+ },
288
+ index
289
+ ))
290
+ ] })
291
+ }
292
+ ) })
293
+ ] });
294
+ };
295
+ var SubItem = ({
296
+ item,
297
+ parentDisabled
298
+ }) => {
299
+ const config = useWarqadConfig();
300
+ const primaryColor = config.theme?.primaryColor || "#3b82f6";
301
+ const { isDarkMode } = useTheme();
302
+ const location = useLocation();
303
+ const navigate = useNavigate();
304
+ const isActive = isPathActive(item.path, location.pathname);
305
+ const isDisabled = item.disabled || parentDisabled;
306
+ return /* @__PURE__ */ jsxs2(
307
+ "button",
308
+ {
309
+ onClick: () => !isDisabled && item.path && navigate(item.path),
310
+ disabled: isDisabled,
311
+ className: cn(
312
+ "relative w-full flex items-center px-3 py-2 pl-6 rounded-lg text-sm transition-colors duration-200",
313
+ isActive && !isDisabled ? "font-medium" : "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",
314
+ isDisabled && "opacity-50 cursor-not-allowed grayscale-[0.5]"
315
+ ),
316
+ style: isActive && !isDisabled ? {
317
+ backgroundColor: isDarkMode ? `${primaryColor}4D` : `${primaryColor}1A`,
318
+ // 10%
319
+ color: primaryColor
320
+ } : void 0,
321
+ children: [
322
+ /* @__PURE__ */ jsx4("span", { className: "truncate", children: item.label }),
323
+ isActive && !isDisabled && /* @__PURE__ */ jsx4(
324
+ "div",
325
+ {
326
+ className: "absolute left-0 top-1/2 -translate-y-1/2 w-1 h-4 rounded-r-full",
327
+ style: { backgroundColor: primaryColor }
328
+ }
329
+ )
330
+ ]
331
+ }
332
+ );
333
+ };
334
+ var DashboardLayout = ({
335
+ children,
336
+ navItems,
337
+ title = "Dashboard",
338
+ logo,
339
+ userProfile,
340
+ fontFamily = 'system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
341
+ // Humanist System Stack
342
+ sidebarFooter
343
+ }) => {
344
+ const config = useWarqadConfig();
345
+ const primaryColor = config.theme?.primaryColor || "#3b82f6";
346
+ const isDesktop = useMediaQuery("(min-width: 1024px)");
347
+ const location = useLocation();
348
+ const navigate = useNavigate();
349
+ const [isSidebarOpen, setIsSidebarOpen] = useState2(true);
350
+ const [expandedMenus, setExpandedMenus] = useState2(
351
+ () => {
352
+ const initialState = {};
353
+ navItems.forEach((item) => {
354
+ if (item && !item.hidden && !item.disabled && item.subItems?.some(
355
+ (sub) => sub && !sub.hidden && isPathActive(sub.path, location.pathname)
356
+ )) {
357
+ initialState[item.label] = true;
358
+ }
359
+ });
360
+ return initialState;
361
+ }
362
+ );
363
+ const prevPathRef = useRef(location.pathname);
364
+ useEffect2(() => {
365
+ if (prevPathRef.current !== location.pathname) {
366
+ const activeItem = navItems.find(
367
+ (item) => !!item && !item.hidden && !item.disabled && item.subItems?.some(
368
+ (sub) => sub && !sub.hidden && isPathActive(sub.path, location.pathname)
369
+ ) === true
370
+ );
371
+ if (activeItem) {
372
+ setExpandedMenus((prev) => ({ ...prev, [activeItem.label]: true }));
373
+ }
374
+ prevPathRef.current = location.pathname;
375
+ }
376
+ }, [location.pathname, navItems]);
377
+ const isCollapsed = isDesktop && !isSidebarOpen;
378
+ useEffect2(() => {
379
+ if (!isDesktop) {
380
+ setIsSidebarOpen(false);
381
+ } else {
382
+ setIsSidebarOpen(true);
383
+ }
384
+ }, [isDesktop]);
385
+ const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen);
386
+ const toggleMenu = (label) => {
387
+ if (isCollapsed) {
388
+ setIsSidebarOpen(true);
389
+ setTimeout(() => {
390
+ setExpandedMenus((prev) => {
391
+ const isCurrentlyOpen = !!prev[label];
392
+ return isCurrentlyOpen ? {} : { [label]: true };
393
+ });
394
+ }, 50);
395
+ return;
396
+ }
397
+ setExpandedMenus((prev) => {
398
+ const isCurrentlyOpen = !!prev[label];
399
+ return isCurrentlyOpen ? {} : { [label]: true };
400
+ });
401
+ };
402
+ const sidebarVariants = {
403
+ desktopOpen: {
404
+ width: "16rem",
405
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
406
+ },
407
+ desktopClosed: {
408
+ width: "5rem",
409
+ // Mini Sidebar Width
410
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
411
+ },
412
+ mobileOpen: {
413
+ x: 0,
414
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
415
+ },
416
+ mobileClosed: {
417
+ x: "-100%",
418
+ transition: { duration: 0.3, type: "spring", bounce: 0, damping: 20 }
419
+ }
420
+ };
421
+ const renderLogo = () => {
422
+ if (logo) {
423
+ if (typeof logo === "string") {
424
+ return /* @__PURE__ */ jsx4(
425
+ "img",
426
+ {
427
+ src: logo,
428
+ alt: title || "Logo",
429
+ className: "w-8 h-8 rounded-lg object-cover shrink-0"
430
+ }
431
+ );
432
+ }
433
+ return logo;
434
+ }
435
+ if (!title) return null;
436
+ const words = title.trim().split(/\s+/);
437
+ let initials = "";
438
+ if (words.length > 1) {
439
+ initials = (words[0][0] + words[1][0]).toUpperCase();
440
+ } else if (words[0].length >= 2) {
441
+ initials = words[0].substring(0, 2).toUpperCase();
442
+ } else if (words[0].length === 1) {
443
+ initials = words[0].toUpperCase();
444
+ }
445
+ return /* @__PURE__ */ jsx4(
446
+ "div",
447
+ {
448
+ className: "flex items-center justify-center w-8 h-8 rounded-lg text-white font-bold text-sm shrink-0 shadow-sm leading-none",
449
+ style: { backgroundColor: primaryColor },
450
+ children: /* @__PURE__ */ jsx4("span", { className: "mt-px", children: initials })
451
+ }
452
+ );
453
+ };
454
+ return /* @__PURE__ */ jsxs2(
455
+ "div",
456
+ {
457
+ 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",
458
+ style: { fontFamily },
459
+ children: [
460
+ /* @__PURE__ */ jsx4(AnimatePresence, { children: !isDesktop && isSidebarOpen && /* @__PURE__ */ jsx4(
461
+ motion.div,
462
+ {
463
+ initial: { opacity: 0 },
464
+ animate: { opacity: 0.5 },
465
+ exit: { opacity: 0 },
466
+ onClick: () => setIsSidebarOpen(false),
467
+ className: "fixed inset-0 bg-black/50 z-40 lg:hidden backdrop-blur-sm"
468
+ }
469
+ ) }),
470
+ /* @__PURE__ */ jsxs2(
471
+ motion.aside,
472
+ {
473
+ 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",
474
+ initial: isDesktop ? "desktopOpen" : "mobileClosed",
475
+ animate: isDesktop ? isSidebarOpen ? "desktopOpen" : "desktopClosed" : isSidebarOpen ? "mobileOpen" : "mobileClosed",
476
+ variants: sidebarVariants,
477
+ children: [
478
+ /* @__PURE__ */ jsx4(
479
+ "div",
480
+ {
481
+ className: cn(
482
+ "h-16 flex items-center border-b border-gray-100 dark:border-gray-800 shrink-0 overflow-hidden transition-all duration-300",
483
+ isCollapsed ? "justify-center px-0" : "px-6"
484
+ ),
485
+ children: /* @__PURE__ */ jsx4(
486
+ "div",
487
+ {
488
+ className: "flex items-center gap-2 max-w-full overflow-hidden",
489
+ style: { color: primaryColor },
490
+ children: isCollapsed ? renderLogo() : /* @__PURE__ */ jsxs2(Fragment, { children: [
491
+ renderLogo(),
492
+ /* @__PURE__ */ jsx4("span", { className: "font-bold text-lg tracking-tight text-gray-900 dark:text-white truncate", children: title })
493
+ ] })
494
+ }
495
+ )
496
+ }
497
+ ),
498
+ /* @__PURE__ */ jsx4("div", { className: "flex-1 p-4 overflow-y-auto overflow-x-hidden scrollbar-hide", children: /* @__PURE__ */ jsx4("nav", { className: "space-y-1", children: navItems.filter((item) => !!item && !item.hidden).map((item) => {
499
+ const isActive = isPathActive(item.path, location.pathname);
500
+ const isChildActive = item.subItems?.some(
501
+ (sub) => sub && !sub.hidden && isPathActive(sub.path, location.pathname)
502
+ );
503
+ const isExpanded = expandedMenus[item.label];
504
+ return /* @__PURE__ */ jsx4(
505
+ SidebarItem,
506
+ {
507
+ item,
508
+ isActive,
509
+ isChildActive: !!isChildActive,
510
+ isExpanded: !!isExpanded,
511
+ isSidebarCollapsed: !!isCollapsed,
512
+ onClick: () => {
513
+ if (item.path) navigate(item.path);
514
+ if (isCollapsed && !item.path) {
515
+ setIsSidebarOpen(true);
516
+ }
517
+ },
518
+ onToggleExpand: () => toggleMenu(item.label)
519
+ },
520
+ item.label
521
+ );
522
+ }) }) }),
523
+ sidebarFooter && !isCollapsed && /* @__PURE__ */ jsx4("div", { className: "shrink-0 p-4 border-t border-gray-100 dark:border-gray-800", children: sidebarFooter })
524
+ ]
525
+ }
526
+ ),
527
+ /* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col min-w-0 h-screen overflow-hidden", children: [
528
+ /* @__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 shrink-0", children: [
529
+ /* @__PURE__ */ jsx4("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsx4(
530
+ "button",
531
+ {
532
+ onClick: toggleSidebar,
533
+ 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",
534
+ children: /* @__PURE__ */ jsx4(Menu, { size: 20 })
535
+ }
536
+ ) }),
537
+ /* @__PURE__ */ jsx4("div", { className: "flex items-center gap-2", children: userProfile && /* @__PURE__ */ jsxs2(Fragment, { children: [
538
+ /* @__PURE__ */ jsx4("div", { className: "w-px h-6 mx-2 bg-gray-200 dark:bg-gray-800" }),
539
+ userProfile
540
+ ] }) })
541
+ ] }),
542
+ /* @__PURE__ */ jsx4("main", { className: "flex-1 p-2 md:p-4 overflow-y-auto", children: /* @__PURE__ */ jsx4("div", { className: "max-w-7xl mx-auto", children }) })
543
+ ] })
544
+ ]
545
+ }
546
+ );
547
+ };
548
+
549
+ // src/components/ThemeToggle.tsx
550
+ import { Sun, Moon } from "lucide-react";
551
+ import { jsx as jsx5 } from "react/jsx-runtime";
552
+ var ThemeToggle = ({
553
+ className
554
+ }) => {
555
+ const { isDarkMode, toggleTheme } = useTheme();
556
+ return /* @__PURE__ */ jsx5(
557
+ "button",
558
+ {
559
+ onClick: toggleTheme,
560
+ className: cn(
561
+ "p-2 rounded-lg transition-all duration-200",
562
+ "text-slate-500 hover:text-blue-600 hover:bg-slate-100",
563
+ "dark:text-yellow-400 dark:hover:text-yellow-300 dark:hover:bg-slate-800",
564
+ className
565
+ ),
566
+ "aria-label": "Toggle dark mode",
567
+ children: isDarkMode ? /* @__PURE__ */ jsx5(
568
+ Sun,
569
+ {
570
+ size: 20,
571
+ className: "stroke-2 transition-transform duration-300 rotate-0 scale-100"
572
+ }
573
+ ) : /* @__PURE__ */ jsx5(
574
+ Moon,
575
+ {
576
+ size: 20,
577
+ className: "stroke-2 transition-transform duration-300 rotate-0 scale-100"
578
+ }
579
+ )
580
+ }
581
+ );
582
+ };
583
+
584
+ // src/hooks/useTheme.ts
585
+ import { useState as useState3, useEffect as useEffect3 } from "react";
586
+
587
+ // src/components/LoadingBox.tsx
588
+ import { jsx as jsx6 } from "react/jsx-runtime";
589
+ var LoadingBox = () => {
590
+ return /* @__PURE__ */ jsx6("div", { children: /* @__PURE__ */ jsx6("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx6("div", { className: "animate-spin rounded-full h-32 w-32 border-b-2 border-primary", children: "aaa" }) }) });
591
+ };
592
+
593
+ // src/components/spins/ClassicSpin.tsx
594
+ import { Loader2 } from "lucide-react";
595
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
596
+ var ClassicSpin = ({ msg = "Please wait..." }) => {
597
+ return /* @__PURE__ */ jsx7("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: [
598
+ /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
599
+ /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 bg-indigo-500 blur-lg opacity-20 animate-pulse" }),
600
+ /* @__PURE__ */ jsx7(Loader2, { className: "h-8 w-8 animate-spin text-indigo-600 dark:text-indigo-400 relative z-10" })
601
+ ] }),
602
+ /* @__PURE__ */ jsx7("p", { className: "mt-3 text-sm font-medium text-gray-900 dark:text-white", children: msg })
603
+ ] }) });
604
+ };
605
+
606
+ // src/components/spins/OverlaySpin.tsx
607
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
608
+ var OverlaySpin = ({ msg = "Processing..." }) => /* @__PURE__ */ jsx8("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: [
609
+ /* @__PURE__ */ jsx8("div", { className: "w-6 h-6 border-2 border-blue-600 border-t-transparent rounded-full animate-spin" }),
610
+ /* @__PURE__ */ jsx8("span", { className: "text-xs font-medium text-gray-500 animate-pulse", children: msg })
611
+ ] }) });
612
+
613
+ // src/components/spins/LoadingSpin.tsx
614
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
615
+ var LoadingSpin = ({
616
+ className,
617
+ size = "md",
618
+ color = "text-current"
619
+ }) => {
620
+ const sizeClasses = {
621
+ sm: "h-4 w-4",
622
+ md: "h-6 w-6",
623
+ lg: "h-10 w-10"
624
+ };
625
+ return /* @__PURE__ */ jsxs5(
626
+ "svg",
627
+ {
628
+ className: cn("animate-spin", sizeClasses[size], color, className),
629
+ fill: "none",
630
+ viewBox: "0 0 24 24",
631
+ xmlns: "http://www.w3.org/2000/svg",
632
+ children: [
633
+ /* @__PURE__ */ jsx9(
634
+ "circle",
635
+ {
636
+ className: "opacity-25",
637
+ cx: "12",
638
+ cy: "12",
639
+ r: "10",
640
+ stroke: "currentColor",
641
+ strokeWidth: "4"
642
+ }
643
+ ),
644
+ /* @__PURE__ */ jsx9(
645
+ "path",
646
+ {
647
+ className: "opacity-75",
648
+ fill: "currentColor",
649
+ 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"
650
+ }
651
+ )
652
+ ]
653
+ }
654
+ );
655
+ };
656
+
657
+ // src/components/CodeBlock.tsx
658
+ import { useState as useState4 } from "react";
659
+ import { Check, Copy } from "lucide-react";
660
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
661
+ var CodeBlock = ({
662
+ code,
663
+ language = "tsx",
664
+ className
665
+ }) => {
666
+ const [copied, setCopied] = useState4(false);
667
+ const handleCopy = () => {
668
+ navigator.clipboard.writeText(code);
669
+ setCopied(true);
670
+ setTimeout(() => setCopied(false), 2e3);
671
+ };
672
+ return /* @__PURE__ */ jsxs6(
673
+ "div",
674
+ {
675
+ className: cn(
676
+ "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",
677
+ className
678
+ ),
679
+ children: [
680
+ /* @__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: [
681
+ /* @__PURE__ */ jsx10("span", { className: "text-[10px] font-bold uppercase tracking-widest text-gray-400", children: language }),
682
+ /* @__PURE__ */ jsx10(
683
+ "button",
684
+ {
685
+ onClick: handleCopy,
686
+ 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",
687
+ children: copied ? /* @__PURE__ */ jsx10(Check, { size: 14, className: "text-green-500" }) : /* @__PURE__ */ jsx10(Copy, { size: 14 })
688
+ }
689
+ )
690
+ ] }),
691
+ /* @__PURE__ */ jsx10("div", { className: "p-4 overflow-x-auto", children: /* @__PURE__ */ jsx10("pre", { className: "text-sm font-mono leading-relaxed text-gray-800 dark:text-gray-300", children: code }) })
692
+ ]
693
+ }
694
+ );
695
+ };
696
+
697
+ // src/components/Card.tsx
698
+ import { jsx as jsx11 } from "react/jsx-runtime";
699
+ var Card = ({
700
+ children,
701
+ className,
702
+ variant = "default",
703
+ ...props
704
+ }) => {
705
+ const variants = {
706
+ default: "bg-white dark:bg-zinc-900 border-gray-200 dark:border-zinc-800 shadow-sm",
707
+ flat: "bg-gray-50/50 dark:bg-zinc-950/50 border-gray-100 dark:border-zinc-900",
708
+ glass: "bg-white/70 dark:bg-black/40 backdrop-blur-md border-white/20 dark:border-white/5 shadow-xl"
709
+ };
710
+ return /* @__PURE__ */ jsx11(
711
+ "div",
712
+ {
713
+ className: cn(
714
+ "rounded-[2rem] border p-6 transition-all duration-300",
715
+ variants[variant],
716
+ className
717
+ ),
718
+ ...props,
719
+ children
720
+ }
721
+ );
722
+ };
723
+ var CardHeader = ({
724
+ children,
725
+ className
726
+ }) => /* @__PURE__ */ jsx11("div", { className: cn("mb-4 space-y-1.5", className), children });
727
+ var CardTitle = ({
728
+ children,
729
+ className
730
+ }) => /* @__PURE__ */ jsx11(
731
+ "h3",
732
+ {
733
+ className: cn(
734
+ "text-lg font-semibold leading-none tracking-tight text-gray-900 dark:text-gray-100",
735
+ className
736
+ ),
737
+ children
738
+ }
739
+ );
740
+ var CardDescription = ({
741
+ children,
742
+ className
743
+ }) => /* @__PURE__ */ jsx11("p", { className: cn("text-sm text-gray-500 dark:text-gray-400", className), children });
744
+ var CardContent = ({
745
+ children,
746
+ className
747
+ }) => /* @__PURE__ */ jsx11("div", { className: cn("", className), children });
748
+ var CardFooter = ({
749
+ children,
750
+ className
751
+ }) => /* @__PURE__ */ jsx11("div", { className: cn("mt-6 flex items-center pt-0", className), children });
752
+ Card.Header = CardHeader;
753
+ Card.Title = CardTitle;
754
+ Card.Description = CardDescription;
755
+ Card.Content = CardContent;
756
+ Card.Footer = CardFooter;
757
+
758
+ // src/components/modal/Modal.tsx
759
+ import { X } from "lucide-react";
760
+ import { motion as motion2, AnimatePresence as AnimatePresence2 } from "framer-motion";
761
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
762
+ var Modal = ({
763
+ isOpen,
764
+ onClose,
765
+ title,
766
+ children,
767
+ isLoading = false,
768
+ width = 500
769
+ }) => {
770
+ return /* @__PURE__ */ jsx12(AnimatePresence2, { children: isOpen && /* @__PURE__ */ jsxs7("div", { className: "fixed inset-0 z-[1000] flex items-center justify-center p-4 sm:p-6", children: [
771
+ /* @__PURE__ */ jsx12(
772
+ motion2.div,
773
+ {
774
+ initial: { opacity: 0 },
775
+ animate: { opacity: 1 },
776
+ exit: { opacity: 0 },
777
+ onClick: isLoading ? void 0 : onClose,
778
+ className: "fixed inset-0 bg-black/40 backdrop-blur-sm transition-all"
779
+ }
780
+ ),
781
+ /* @__PURE__ */ jsxs7(
782
+ motion2.div,
783
+ {
784
+ initial: { opacity: 0, scale: 0.95, y: 10 },
785
+ animate: { opacity: 1, scale: 1, y: 0 },
786
+ exit: { opacity: 0, scale: 0.95, y: 10 },
787
+ transition: { type: "spring", duration: 0.3 },
788
+ style: { maxWidth: width },
789
+ 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]",
790
+ children: [
791
+ /* @__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: [
792
+ /* @__PURE__ */ jsx12("h3", { className: "text-xl font-bold text-gray-900 dark:text-white tracking-tight", children: title }),
793
+ /* @__PURE__ */ jsx12(
794
+ "button",
795
+ {
796
+ onClick: onClose,
797
+ disabled: isLoading,
798
+ 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",
799
+ children: /* @__PURE__ */ jsx12(X, { size: 20 })
800
+ }
801
+ )
802
+ ] }),
803
+ /* @__PURE__ */ jsx12("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" }),
804
+ /* @__PURE__ */ jsxs7("div", { className: "p-8 overflow-y-auto relative flex-1", children: [
805
+ isLoading && /* @__PURE__ */ jsx12(ClassicSpin, {}),
806
+ /* @__PURE__ */ jsx12(
807
+ "div",
808
+ {
809
+ className: isLoading ? "opacity-20 blur-sm transition-all" : "transition-all",
810
+ children
811
+ }
812
+ )
813
+ ] })
814
+ ]
815
+ }
816
+ )
817
+ ] }) });
818
+ };
819
+
820
+ // src/components/PageHeader.tsx
821
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
822
+ var PageHeader = ({
823
+ title,
824
+ description,
825
+ children,
826
+ className
827
+ }) => {
828
+ return /* @__PURE__ */ jsxs8("div", { className: cn("space-y-2 mb-8", className), children: [
829
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between", children: [
830
+ /* @__PURE__ */ jsx13("h1", { className: "text-3xl font-bold text-gray-900 dark:text-white tracking-tight", children: title }),
831
+ children
832
+ ] }),
833
+ description && /* @__PURE__ */ jsx13("p", { className: "text-gray-500 dark:text-gray-400 max-w-2xl leading-relaxed", children: description })
834
+ ] });
835
+ };
836
+
837
+ // src/hooks/useModal.tsx
838
+ import { useState as useState5, useCallback } from "react";
839
+ var useModal = (initialState = false) => {
840
+ const [isOpen, setIsOpen] = useState5(initialState);
841
+ const [state, setState] = useState5(null);
842
+ const open = useCallback(() => setIsOpen(true), []);
843
+ const close = useCallback(() => {
844
+ setIsOpen(false);
845
+ setState(null);
846
+ }, []);
847
+ const toggle = useCallback(() => setIsOpen((prev) => !prev), []);
848
+ const openState = useCallback((data) => {
849
+ setState(data);
850
+ open();
851
+ }, []);
852
+ return {
853
+ isOpen,
854
+ open,
855
+ close,
856
+ toggle,
857
+ openState,
858
+ state,
859
+ Modal
860
+ };
861
+ };
862
+
863
+ // src/components/Fields/Input.tsx
864
+ import { forwardRef, useEffect as useEffect4, useState as useState6 } from "react";
865
+ import { Eye, EyeOff } from "lucide-react";
866
+ import {
867
+ Controller
868
+ } from "react-hook-form";
869
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
870
+ var Input = forwardRef(
871
+ ({
872
+ label,
873
+ icon,
874
+ error,
875
+ containerClassName = "",
876
+ name,
877
+ form,
878
+ onFocus,
879
+ onBlur,
880
+ className = "",
881
+ type,
882
+ variant = "default",
883
+ ...props
884
+ }, ref) => {
885
+ const [isFocused, setIsFocused] = useState6(false);
886
+ const [showPassword, setShowPassword] = useState6(false);
887
+ const { theme } = useWarqadConfig();
888
+ const primaryColor = theme?.primaryColor;
889
+ let message = error;
890
+ if (form && name) {
891
+ const {
892
+ formState: { errors }
893
+ } = form;
894
+ const errorObj = name.split(".").reduce((acc, current) => acc?.[current], errors);
895
+ message = errorObj?.message;
896
+ }
897
+ useEffect4(() => {
898
+ if (form && name) {
899
+ form.clearErrors("root");
900
+ }
901
+ }, [form?.watch(name)]);
902
+ const renderInput = (inputProps, localType = type || "text") => /* @__PURE__ */ jsxs9(
903
+ "div",
904
+ {
905
+ className: `${label ? "space-y-2" : ""} group ${containerClassName} `,
906
+ children: [
907
+ label && /* @__PURE__ */ jsxs9(
908
+ "label",
909
+ {
910
+ htmlFor: props.id,
911
+ className: `block capitalize text-xs font-medium transition-colors duration-200`,
912
+ style: { color: isFocused ? primaryColor : void 0 },
913
+ children: [
914
+ label,
915
+ props.required && /* @__PURE__ */ jsx14("span", { className: "text-red-500 ml-1", children: "*" })
916
+ ]
917
+ }
918
+ ),
919
+ /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
920
+ icon && /* @__PURE__ */ jsx14("div", { className: "absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx14(
921
+ "div",
922
+ {
923
+ className: `transition-colors duration-200`,
924
+ style: { color: isFocused ? primaryColor : "#9ca3af" },
925
+ children: icon
926
+ }
927
+ ) }),
928
+ /* @__PURE__ */ jsx14(
929
+ "input",
930
+ {
931
+ ref,
932
+ onFocus: (e) => {
933
+ setIsFocused(true);
934
+ onFocus?.(e);
935
+ },
936
+ onBlur: (e) => {
937
+ setIsFocused(false);
938
+ onBlur?.(e);
939
+ },
940
+ className: `block w-full ${icon ? "pl-10" : "pl-2.5"} pr-2.5 py-1 text-gray-900 dark:text-white placeholder-gray-400 outline-none focus:outline-none focus:ring-0 transition-all duration-200 text-sm ${variant === "ghost" ? "bg-transparent border-transparent shadow-none h-full" : "rounded-xl border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-900/50 focus:bg-white dark:focus:bg-zinc-900 h-9"} ${className}`,
941
+ style: variant === "default" ? {
942
+ borderColor: isFocused ? primaryColor : void 0,
943
+ boxShadow: isFocused ? `${primaryColor}33 0px 0px 0px 2px` : void 0
944
+ } : void 0,
945
+ ...props,
946
+ ...inputProps,
947
+ type: localType === "password" ? showPassword ? "text" : "password" : localType
948
+ }
949
+ ),
950
+ type === "password" && /* @__PURE__ */ jsx14(
951
+ "button",
952
+ {
953
+ type: "button",
954
+ onClick: () => setShowPassword(!showPassword),
955
+ className: "absolute inset-y-0 right-0 pr-2.5 flex items-center text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 transition-colors focus:outline-none cursor-pointer",
956
+ tabIndex: -1,
957
+ children: showPassword ? /* @__PURE__ */ jsx14(EyeOff, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx14(Eye, { className: "h-5 w-5" })
958
+ }
959
+ )
960
+ ] }),
961
+ message && /* @__PURE__ */ jsx14("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
962
+ ]
963
+ }
964
+ );
965
+ if (form && name && type === "number") {
966
+ return /* @__PURE__ */ jsx14(
967
+ Controller,
968
+ {
969
+ control: form.control,
970
+ name,
971
+ render: ({ field: { onChange, value, ref: fieldRef, onBlur: onBlur2 } }) => renderInput(
972
+ {
973
+ ref: fieldRef,
974
+ onBlur: () => {
975
+ onBlur2();
976
+ },
977
+ value: value ? String(value).split(".").map(
978
+ (part, index) => index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
979
+ ).join(".") : "",
980
+ onChange: (e) => {
981
+ const rawValue = e.target.value.replace(/,/g, "");
982
+ if (!/^\d*\.?\d*$/.test(rawValue)) return;
983
+ if (rawValue === "") {
984
+ onChange("");
985
+ } else {
986
+ const numValue = Number(rawValue);
987
+ if (!isNaN(numValue) && String(numValue) === rawValue) {
988
+ onChange(numValue);
989
+ } else {
990
+ onChange(rawValue);
991
+ }
992
+ }
993
+ props.onChange?.(e);
994
+ }
995
+ },
996
+ "text"
997
+ )
998
+ }
999
+ );
1000
+ }
1001
+ let inputPropsObj = form && name ? form.register(name, type === "number" ? { valueAsNumber: true } : {}) : {};
1002
+ if (type === "number" && (!form || !name)) {
1003
+ const originalOnChange = props.onChange;
1004
+ inputPropsObj = {
1005
+ ...inputPropsObj,
1006
+ value: props.value !== void 0 && props.value !== null ? String(props.value).split(".").map(
1007
+ (part, index) => index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
1008
+ ).join(".") : "",
1009
+ onChange: (e) => {
1010
+ const rawValue = e.target.value.replace(/,/g, "");
1011
+ if (!/^\d*\.?\d*$/.test(rawValue)) return;
1012
+ if (originalOnChange) {
1013
+ const fakeEvent = {
1014
+ ...e,
1015
+ target: {
1016
+ ...e.target,
1017
+ value: rawValue,
1018
+ valueAsNumber: rawValue === "" ? NaN : Number(rawValue)
1019
+ }
1020
+ };
1021
+ originalOnChange(fakeEvent);
1022
+ }
1023
+ }
1024
+ };
1025
+ return renderInput(inputPropsObj, "text");
1026
+ }
1027
+ return renderInput(inputPropsObj, type === "number" ? "text" : type);
1028
+ }
1029
+ );
1030
+
1031
+ // src/components/Fields/PhoneInput.tsx
1032
+ import { forwardRef as forwardRef2, useState as useState7 } from "react";
1033
+ import PhoneInputOriginal, {
1034
+ isValidPhoneNumber
1035
+ } from "react-phone-number-input";
1036
+ import "react-phone-number-input/style.css";
1037
+ import { Controller as Controller2 } from "react-hook-form";
1038
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1039
+ var PhoneInput = forwardRef2(
1040
+ ({
1041
+ label,
1042
+ icon,
1043
+ error,
1044
+ containerClassName = "",
1045
+ name,
1046
+ form,
1047
+ onChange,
1048
+ value,
1049
+ className = "",
1050
+ ...props
1051
+ }, ref) => {
1052
+ const [isFocused, setIsFocused] = useState7(false);
1053
+ const { theme } = useWarqadConfig();
1054
+ const primaryColor = theme?.primaryColor;
1055
+ let message = error;
1056
+ if (form && name) {
1057
+ const {
1058
+ formState: { errors }
1059
+ } = form;
1060
+ const nameParts = name.split(".");
1061
+ let currentError = errors;
1062
+ for (const part of nameParts) {
1063
+ currentError = currentError?.[part];
1064
+ }
1065
+ message = currentError?.message || message;
1066
+ }
1067
+ const renderInput = (onChangeHandler, currentValue) => /* @__PURE__ */ jsxs10("div", { className: `space-y-2 group ${containerClassName}`, children: [
1068
+ /* @__PURE__ */ jsxs10(
1069
+ "label",
1070
+ {
1071
+ className: `block text-xs font-medium transition-colors duration-200`,
1072
+ style: {
1073
+ color: isFocused || currentValue ? primaryColor : void 0
1074
+ },
1075
+ children: [
1076
+ label,
1077
+ props.required && /* @__PURE__ */ jsx15("span", { className: "text-red-500 ml-1", children: "*" })
1078
+ ]
1079
+ }
1080
+ ),
1081
+ /* @__PURE__ */ jsxs10("div", { className: "relative", children: [
1082
+ icon && /* @__PURE__ */ jsx15("div", { className: "absolute inset-y-0 left-0 pl-2.5 flex items-center pointer-events-none z-10", children: /* @__PURE__ */ jsx15(
1083
+ "div",
1084
+ {
1085
+ className: `transition-colors duration-200`,
1086
+ style: { color: isFocused ? primaryColor : "#9ca3af" },
1087
+ children: icon
1088
+ }
1089
+ ) }),
1090
+ /* @__PURE__ */ jsx15(
1091
+ PhoneInputOriginal,
1092
+ {
1093
+ ref,
1094
+ defaultCountry: "KE",
1095
+ international: true,
1096
+ withCountryCallingCode: true,
1097
+ value: currentValue,
1098
+ onChange: (val) => onChangeHandler(val),
1099
+ onFocus: () => setIsFocused(true),
1100
+ onBlur: () => setIsFocused(false),
1101
+ className: `block w-full rounded-xl border-gray-200 dark:border-zinc-800 bg-white 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-2.5"} pr-2.5 h-9 py-1 ${className}`,
1102
+ style: {
1103
+ borderColor: isFocused ? primaryColor : void 0,
1104
+ boxShadow: isFocused ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1105
+ },
1106
+ ...props
1107
+ }
1108
+ )
1109
+ ] }),
1110
+ message && /* @__PURE__ */ jsx15("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1111
+ ] });
1112
+ if (form && name) {
1113
+ return /* @__PURE__ */ jsx15(
1114
+ Controller2,
1115
+ {
1116
+ name,
1117
+ control: form.control,
1118
+ rules: {
1119
+ validate: (value2) => value2 && isValidPhoneNumber(value2) ? true : "Invalid phone number"
1120
+ },
1121
+ render: ({ field: { onChange: onChange2, value: value2 } }) => renderInput(onChange2, value2)
1122
+ }
1123
+ );
1124
+ }
1125
+ return renderInput(onChange || (() => {
1126
+ }), value || "");
1127
+ }
1128
+ );
1129
+ PhoneInput.displayName = "PhoneInput";
1130
+
1131
+ // src/components/Fields/select.tsx
1132
+ import { forwardRef as forwardRef3, useState as useState8, useEffect as useEffect5, useRef as useRef2 } from "react";
1133
+ import { ChevronDown as ChevronDown2, Check as Check2 } from "lucide-react";
1134
+ import { Controller as Controller3 } from "react-hook-form";
1135
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
1136
+ var SelectContent = ({
1137
+ label,
1138
+ options,
1139
+ icon,
1140
+ error,
1141
+ containerClassName = "",
1142
+ name,
1143
+ form,
1144
+ onChangeHandler,
1145
+ currentValue,
1146
+ onFocus,
1147
+ onBlur,
1148
+ className = "",
1149
+ variant = "default",
1150
+ fieldInternalProps,
1151
+ ...props
1152
+ }) => {
1153
+ const [isOpen, setIsOpen] = useState8(false);
1154
+ const [isFocused, setIsFocused] = useState8(false);
1155
+ const { theme } = useWarqadConfig();
1156
+ const primaryColor = theme?.primaryColor;
1157
+ const containerRef = useRef2(null);
1158
+ const dropdownAnchorRef = useRef2(null);
1159
+ const dropdownContentRef = useRef2(null);
1160
+ const lastFocusTime = useRef2(0);
1161
+ useEffect5(() => {
1162
+ const handleClickOutside = (event) => {
1163
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
1164
+ setIsOpen(false);
1165
+ setIsFocused(false);
1166
+ fieldInternalProps?.onBlur?.();
1167
+ }
1168
+ };
1169
+ document.addEventListener("mousedown", handleClickOutside);
1170
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1171
+ }, [fieldInternalProps]);
1172
+ const handleSelect = (option) => {
1173
+ if (option.disabled) return;
1174
+ onChangeHandler(option.value);
1175
+ if (form && name) {
1176
+ form.setValue(name, option.value, {
1177
+ shouldValidate: true,
1178
+ shouldDirty: true
1179
+ });
1180
+ form.clearErrors(name);
1181
+ }
1182
+ setIsOpen(false);
1183
+ fieldInternalProps?.onBlur?.();
1184
+ };
1185
+ const displayValue = options.find((o) => o.value === currentValue)?.label || "Select...";
1186
+ let message = error;
1187
+ if (form && name) {
1188
+ const {
1189
+ formState: { errors }
1190
+ } = form;
1191
+ const nameParts = name.split(".");
1192
+ let currentError = errors;
1193
+ for (const part of nameParts) {
1194
+ currentError = currentError?.[part];
1195
+ }
1196
+ message = currentError?.message || message;
1197
+ }
1198
+ return /* @__PURE__ */ jsxs11(
1199
+ "div",
1200
+ {
1201
+ ref: containerRef,
1202
+ className: `${label ? "space-y-2" : ""} group ${containerClassName}`,
1203
+ children: [
1204
+ label && /* @__PURE__ */ jsxs11(
1205
+ "label",
1206
+ {
1207
+ className: `block text-xs font-medium transition-colors duration-200`,
1208
+ style: { color: isFocused || isOpen ? primaryColor : void 0 },
1209
+ children: [
1210
+ label,
1211
+ props.required && /* @__PURE__ */ jsx16("span", { className: "text-red-500 ml-1", children: "*" })
1212
+ ]
1213
+ }
1214
+ ),
1215
+ /* @__PURE__ */ jsxs11("div", { className: "relative", ref: dropdownAnchorRef, children: [
1216
+ /* @__PURE__ */ jsxs11(
1217
+ "div",
1218
+ {
1219
+ id: props.id,
1220
+ className: `flex items-center w-full select-none text-gray-900 dark:text-white transition-all duration-200 outline-none focus:outline-none focus:ring-0 py-1 ${props.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"} ${variant === "ghost" ? "bg-transparent border-transparent shadow-none px-0 h-full border-none ring-0 focus:border-none focus:ring-0" : isFocused || isOpen ? "ring-0 border rounded-xl h-9" : "border-gray-200 dark:border-zinc-800 border rounded-xl bg-white dark:bg-zinc-900/50 h-9"} ${className}`,
1221
+ style: variant === "default" ? {
1222
+ borderColor: isFocused || isOpen ? primaryColor : void 0,
1223
+ boxShadow: isFocused || isOpen ? `${primaryColor}33 0px 0px 0px 2px` : void 0,
1224
+ backgroundColor: isFocused || isOpen ? "var(--tw-colors-white, white)" : void 0
1225
+ } : void 0,
1226
+ onClick: () => {
1227
+ if (props.disabled) return;
1228
+ if (Date.now() - lastFocusTime.current < 150) {
1229
+ return;
1230
+ }
1231
+ setIsOpen(!isOpen);
1232
+ setIsFocused(true);
1233
+ onFocus?.(null);
1234
+ },
1235
+ onKeyDown: (e) => {
1236
+ if (e.key === "Enter" || e.key === " ") {
1237
+ e.preventDefault();
1238
+ if (props.disabled) return;
1239
+ setIsOpen(!isOpen);
1240
+ setIsFocused(true);
1241
+ } else if (e.key === "ArrowDown" || e.key === "ArrowUp") {
1242
+ e.preventDefault();
1243
+ setIsOpen(true);
1244
+ }
1245
+ },
1246
+ onFocus: () => {
1247
+ setIsFocused(true);
1248
+ setIsOpen(true);
1249
+ lastFocusTime.current = Date.now();
1250
+ },
1251
+ tabIndex: props.disabled ? -1 : 0,
1252
+ onBlur: (e) => {
1253
+ if (!dropdownContentRef.current?.contains(e.relatedTarget) && !containerRef.current?.contains(e.relatedTarget)) {
1254
+ setIsOpen(false);
1255
+ setIsFocused(false);
1256
+ fieldInternalProps?.onBlur?.();
1257
+ onBlur?.(null);
1258
+ }
1259
+ },
1260
+ children: [
1261
+ icon && /* @__PURE__ */ jsx16(
1262
+ "div",
1263
+ {
1264
+ className: `pl-2.5 pr-2 flex items-center transition-colors duration-200`,
1265
+ style: { color: isFocused || isOpen ? primaryColor : "#9ca3af" },
1266
+ children: icon
1267
+ }
1268
+ ),
1269
+ /* @__PURE__ */ jsx16(
1270
+ "div",
1271
+ {
1272
+ className: `flex-1 truncate text-sm ${icon ? "" : "pl-2.5"} ${!currentValue && currentValue !== 0 && currentValue !== false ? "text-gray-400" : ""}`,
1273
+ children: displayValue
1274
+ }
1275
+ ),
1276
+ /* @__PURE__ */ jsx16("div", { className: "pr-2.5 flex items-center gap-1 shrink-0", children: /* @__PURE__ */ jsx16(
1277
+ ChevronDown2,
1278
+ {
1279
+ className: `h-4 w-4 text-gray-400 transition-transform ${isOpen ? "rotate-180" : ""}`
1280
+ }
1281
+ ) })
1282
+ ]
1283
+ }
1284
+ ),
1285
+ isOpen && /* @__PURE__ */ jsx16(
1286
+ "div",
1287
+ {
1288
+ ref: dropdownContentRef,
1289
+ className: "absolute top-full left-0 z-50 mt-1 bg-white dark:bg-zinc-950 rounded-xl border border-gray-200 dark:border-zinc-800 shadow-xl max-h-60 overflow-y-auto p-1.5 w-max min-w-full",
1290
+ children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-0.5", children: [
1291
+ options.map((option, index) => {
1292
+ const isSelected = currentValue === option.value;
1293
+ return /* @__PURE__ */ jsxs11(
1294
+ "button",
1295
+ {
1296
+ type: "button",
1297
+ disabled: option.disabled,
1298
+ className: `w-full text-left px-3 py-2 rounded-md text-sm flex items-center justify-between transition-colors ${option.disabled ? "opacity-50 cursor-not-allowed text-gray-400" : isSelected ? "bg-gray-100 dark:bg-zinc-800 text-gray-900 dark:text-gray-100" : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-zinc-800"}`,
1299
+ style: isSelected && !option.disabled && primaryColor ? {
1300
+ color: primaryColor
1301
+ } : void 0,
1302
+ onClick: (e) => {
1303
+ e.stopPropagation();
1304
+ handleSelect(option);
1305
+ },
1306
+ children: [
1307
+ /* @__PURE__ */ jsx16("span", { className: "whitespace-nowrap", children: option.label }),
1308
+ isSelected && /* @__PURE__ */ jsx16(
1309
+ Check2,
1310
+ {
1311
+ className: "h-4 w-4 shrink-0",
1312
+ style: { color: primaryColor }
1313
+ }
1314
+ )
1315
+ ]
1316
+ },
1317
+ String(option.value) || index
1318
+ );
1319
+ }),
1320
+ options.length === 0 && /* @__PURE__ */ jsx16("div", { className: "p-3 text-center text-sm text-gray-500", children: "No options available" })
1321
+ ] })
1322
+ }
1323
+ )
1324
+ ] }),
1325
+ message && /* @__PURE__ */ jsx16("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1326
+ ]
1327
+ }
1328
+ );
1329
+ };
1330
+ var Select = forwardRef3(
1331
+ (props, ref) => {
1332
+ const { form, name, onChange, value } = props;
1333
+ if (form && name) {
1334
+ return /* @__PURE__ */ jsx16(
1335
+ Controller3,
1336
+ {
1337
+ name,
1338
+ control: form.control,
1339
+ render: ({
1340
+ field: {
1341
+ onChange: formOnChange,
1342
+ value: formValue,
1343
+ ref: fieldRef,
1344
+ onBlur
1345
+ }
1346
+ }) => /* @__PURE__ */ jsx16(
1347
+ SelectContent,
1348
+ {
1349
+ ...props,
1350
+ currentValue: formValue,
1351
+ onChangeHandler: (val) => {
1352
+ formOnChange(val);
1353
+ onChange?.(val);
1354
+ },
1355
+ fieldInternalProps: { ref: fieldRef, onBlur }
1356
+ }
1357
+ )
1358
+ }
1359
+ );
1360
+ }
1361
+ return /* @__PURE__ */ jsx16(
1362
+ SelectContent,
1363
+ {
1364
+ ...props,
1365
+ currentValue: value,
1366
+ onChangeHandler: onChange || (() => {
1367
+ })
1368
+ }
1369
+ );
1370
+ }
1371
+ );
1372
+ Select.displayName = "Select";
1373
+
1374
+ // src/components/Fields/textArea.tsx
1375
+ import { forwardRef as forwardRef4, useState as useState9 } from "react";
1376
+ import {
1377
+ Controller as Controller4
1378
+ } from "react-hook-form";
1379
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
1380
+ var Textarea = forwardRef4(
1381
+ ({
1382
+ label,
1383
+ error,
1384
+ containerClassName = "",
1385
+ name,
1386
+ form,
1387
+ onFocus,
1388
+ onBlur,
1389
+ className = "",
1390
+ ...props
1391
+ }, ref) => {
1392
+ const [isFocused, setIsFocused] = useState9(false);
1393
+ const { theme } = useWarqadConfig();
1394
+ const primaryColor = theme?.primaryColor;
1395
+ let message = error;
1396
+ if (form && name) {
1397
+ const {
1398
+ formState: { errors }
1399
+ } = form;
1400
+ const errorObj = name.split(".").reduce((acc, current) => acc?.[current], errors);
1401
+ message = errorObj?.message;
1402
+ }
1403
+ const renderInput = (inputProps, ref2) => /* @__PURE__ */ jsxs12("div", { className: `space-y-2 group w-full! ${containerClassName}`, children: [
1404
+ /* @__PURE__ */ jsxs12(
1405
+ "label",
1406
+ {
1407
+ htmlFor: props.id,
1408
+ className: `block capitalize text-xs font-medium transition-colors duration-200`,
1409
+ style: { color: isFocused ? primaryColor : void 0 },
1410
+ children: [
1411
+ label,
1412
+ props.required && /* @__PURE__ */ jsx17("span", { className: "text-red-500 ml-1", children: "*" })
1413
+ ]
1414
+ }
1415
+ ),
1416
+ /* @__PURE__ */ jsx17("div", { className: "relative", children: /* @__PURE__ */ jsx17(
1417
+ "textarea",
1418
+ {
1419
+ ref: ref2,
1420
+ onFocus: (e) => {
1421
+ setIsFocused(true);
1422
+ onFocus?.(e);
1423
+ },
1424
+ onBlur: (e) => {
1425
+ setIsFocused(false);
1426
+ onBlur?.(e);
1427
+ },
1428
+ className: `block w-full px-2.5 py-1 rounded-xl border-gray-200 dark:border-zinc-800 bg-white 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}`,
1429
+ style: {
1430
+ borderColor: isFocused ? primaryColor : void 0,
1431
+ boxShadow: isFocused ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1432
+ },
1433
+ ...props,
1434
+ ...inputProps
1435
+ }
1436
+ ) }),
1437
+ message && /* @__PURE__ */ jsx17("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
1438
+ ] });
1439
+ if (form && name) {
1440
+ return /* @__PURE__ */ jsx17(
1441
+ Controller4,
1442
+ {
1443
+ control: form.control,
1444
+ name,
1445
+ render: ({ field: { onChange, value, ref: fieldRef, onBlur: onBlur2 } }) => renderInput(
1446
+ {
1447
+ value: value || "",
1448
+ // Ensure controlled input doesn't warn about uncontrolled
1449
+ onChange: (e) => {
1450
+ onChange(e);
1451
+ props.onChange?.(e);
1452
+ },
1453
+ onBlur: () => {
1454
+ onBlur2();
1455
+ }
1456
+ },
1457
+ fieldRef
1458
+ )
1459
+ }
1460
+ );
1461
+ }
1462
+ return renderInput({}, ref);
1463
+ }
1464
+ );
1465
+
1466
+ // src/components/Fields/searchApi.tsx
1467
+ import { useState as useState11, useEffect as useEffect6, useRef as useRef3, forwardRef as forwardRef5 } from "react";
1468
+ import { createPortal } from "react-dom";
1469
+ import { Search, Loader2 as Loader22, ChevronDown as ChevronDown3, Check as Check3, X as X2 } from "lucide-react";
1470
+
1471
+ // src/hooks/Fetches/useApis.tsx
1472
+ import { useState as useState10, useMemo } from "react";
1473
+ import axios from "axios";
1474
+ var useApi = () => {
1475
+ const { api: configApi } = useWarqadConfig();
1476
+ const api = useMemo(
1477
+ () => axios.create({
1478
+ baseURL: configApi || "/api",
1479
+ withCredentials: true
1480
+ }),
1481
+ [configApi]
1482
+ );
1483
+ const [data, setData] = useState10();
1484
+ const [isLoading, setIsLoading] = useState10(false);
1485
+ const [pdfLoading, setPdfLoading] = useState10(false);
1486
+ const [error, setError] = useState10(null);
1487
+ const get = async ({ url, v = 1, params, delay }) => {
1488
+ setIsLoading(true);
1489
+ try {
1490
+ if (delay) await new Promise((r) => setTimeout(r, delay));
1491
+ const response = await api.get(`/v${v}${url}`, { params });
1492
+ setData(response.data);
1493
+ setError(null);
1494
+ return response.data;
1495
+ } catch (err) {
1496
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1497
+ setError(msg);
1498
+ setData(null);
1499
+ throw new Error(msg);
1500
+ } finally {
1501
+ setIsLoading(false);
1502
+ }
1503
+ };
1504
+ const post = async ({
1505
+ url,
1506
+ v = 1,
1507
+ body,
1508
+ form,
1509
+ multipart = false
1510
+ }) => {
1511
+ setIsLoading(true);
1512
+ try {
1513
+ let response;
1514
+ if (multipart) {
1515
+ const formData = new FormData();
1516
+ if (body) {
1517
+ Object.keys(body).forEach((key) => {
1518
+ if (key === "files") {
1519
+ const files = body[key];
1520
+ if (Array.isArray(files)) {
1521
+ files.forEach((file) => formData.append(key, file));
1522
+ } else {
1523
+ formData.append(key, files);
1524
+ }
1525
+ } else if (Array.isArray(body[key]) || typeof body[key] === "object") {
1526
+ formData.append(key, JSON.stringify(body[key]));
1527
+ } else {
1528
+ formData.append(key, body[key]);
1529
+ }
1530
+ });
1531
+ }
1532
+ response = await api.post(`/v${v}${url}`, formData, {
1533
+ headers: { "Content-Type": "multipart/form-data" }
1534
+ });
1535
+ } else {
1536
+ response = await api.post(`/v${v}${url}`, body);
1537
+ }
1538
+ setData(response.data);
1539
+ return response.data;
1540
+ } catch (err) {
1541
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1542
+ setError(msg);
1543
+ if (form) {
1544
+ if (msg !== "zodError") {
1545
+ form.setError("root", { message: msg });
1546
+ } else {
1547
+ const errors = err?.response?.data?.errors || [];
1548
+ errors.forEach((e) => {
1549
+ form.setError(e.field, { message: e.message });
1550
+ });
1551
+ }
1552
+ }
1553
+ throw new Error(msg);
1554
+ } finally {
1555
+ setIsLoading(false);
1556
+ }
1557
+ };
1558
+ const put = async ({ url, v = 1, body }) => {
1559
+ setIsLoading(true);
1560
+ try {
1561
+ const response = await api.put(`/v${v}${url}`, body);
1562
+ setData(response.data);
1563
+ return response.data;
1564
+ } catch (err) {
1565
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1566
+ setError(msg);
1567
+ throw new Error(msg);
1568
+ } finally {
1569
+ setIsLoading(false);
1570
+ }
1571
+ };
1572
+ const remove = async ({ url, v = 1, params }) => {
1573
+ setIsLoading(true);
1574
+ try {
1575
+ const response = await api.delete(`/v${v}${url}`, { params });
1576
+ setData(response.data);
1577
+ setError(null);
1578
+ return response.data;
1579
+ } catch (err) {
1580
+ const msg = err.response?.data?.message || err.message || "Something went wrong";
1581
+ setError(msg);
1582
+ setData(null);
1583
+ throw new Error(msg);
1584
+ } finally {
1585
+ setIsLoading(false);
1586
+ }
1587
+ };
1588
+ const fetchPdf = async ({
1589
+ url,
1590
+ v = 1,
1591
+ method,
1592
+ body
1593
+ }) => {
1594
+ setPdfLoading(true);
1595
+ try {
1596
+ const response = await api.request({
1597
+ url: `/v${v}${url}`,
1598
+ method,
1599
+ data: body,
1600
+ responseType: "blob"
1601
+ });
1602
+ if (!response.data || response.data.size === 0) {
1603
+ return { ok: false, message: "Received empty PDF file", errors: [] };
1604
+ }
1605
+ setError(null);
1606
+ const pdfObjectUrl = URL.createObjectURL(response.data);
1607
+ return { ok: true, data: pdfObjectUrl };
1608
+ } catch (err) {
1609
+ return {
1610
+ ok: false,
1611
+ message: err.response?.data?.message || err.message || "Server error, something went wrong"
1612
+ };
1613
+ } finally {
1614
+ setPdfLoading(false);
1615
+ }
1616
+ };
1617
+ return {
1618
+ data,
1619
+ error,
1620
+ isLoading,
1621
+ pdfLoading,
1622
+ get,
1623
+ post,
1624
+ put,
1625
+ remove,
1626
+ fetchPdf
1627
+ };
1628
+ };
1629
+ var useApis_default = useApi;
1630
+
1631
+ // src/components/Fields/searchApi.tsx
1632
+ import { Controller as Controller5 } from "react-hook-form";
1633
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
1634
+ var SearchApiContent = ({
1635
+ label,
1636
+ api,
1637
+ placeholder = "Search...",
1638
+ currentValue,
1639
+ onChangeHandler,
1640
+ queryKey = "search",
1641
+ labelKey = "name",
1642
+ valueKey = "_id",
1643
+ error,
1644
+ containerClassName = "",
1645
+ className = "",
1646
+ disabled,
1647
+ name,
1648
+ obj,
1649
+ form,
1650
+ filter = [],
1651
+ required,
1652
+ v = 2,
1653
+ variant = "default",
1654
+ fieldInternalProps,
1655
+ ...props
1656
+ }) => {
1657
+ const [searchTerm, setSearchTerm] = useState11("");
1658
+ const { theme } = useWarqadConfig();
1659
+ const primaryColor = theme?.primaryColor;
1660
+ const [options, setOptions] = useState11([]);
1661
+ const [isOpen, setIsOpen] = useState11(false);
1662
+ const [isFocused, setIsFocused] = useState11(false);
1663
+ const [activeIndex, setActiveIndex] = useState11(-1);
1664
+ const [selectedObject, setSelectedObject] = useState11(void 0);
1665
+ const [hasAttemptedHydration, setHasAttemptedHydration] = useState11(false);
1666
+ const containerRef = useRef3(null);
1667
+ const dropdownAnchorRef = useRef3(null);
1668
+ const dropdownRef = useRef3(null);
1669
+ const inputRef = useRef3(null);
1670
+ const prevApiRef = useRef3(api);
1671
+ const [dropdownStyle, setDropdownStyle] = useState11({});
1672
+ const updateDropdownPosition = () => {
1673
+ if (dropdownAnchorRef.current) {
1674
+ const rect = dropdownAnchorRef.current.getBoundingClientRect();
1675
+ const style = {
1676
+ position: "fixed",
1677
+ top: `${rect.bottom + 4}px`,
1678
+ left: `${rect.left}px`,
1679
+ width: `${rect.width}px`,
1680
+ zIndex: 999999
1681
+ };
1682
+ if (rect.bottom + 240 > window.innerHeight) {
1683
+ style.top = "auto";
1684
+ style.bottom = `${window.innerHeight - rect.top + 4}px`;
1685
+ }
1686
+ setDropdownStyle(style);
1687
+ }
1688
+ };
1689
+ useEffect6(() => {
1690
+ if (isOpen) {
1691
+ updateDropdownPosition();
1692
+ window.addEventListener("scroll", updateDropdownPosition, true);
1693
+ window.addEventListener("resize", updateDropdownPosition);
1694
+ return () => {
1695
+ window.removeEventListener("scroll", updateDropdownPosition, true);
1696
+ window.removeEventListener("resize", updateDropdownPosition);
1697
+ };
1698
+ }
1699
+ }, [isOpen]);
1700
+ const setInputRef = (element) => {
1701
+ inputRef.current = element;
1702
+ if (fieldInternalProps?.ref) {
1703
+ if (typeof fieldInternalProps.ref === "function") {
1704
+ fieldInternalProps.ref(element);
1705
+ } else {
1706
+ fieldInternalProps.ref.current = element;
1707
+ }
1708
+ }
1709
+ };
1710
+ const { get, isLoading, error: errorMessage } = useApis_default();
1711
+ const fetchOptions = async (query) => {
1712
+ try {
1713
+ const params = {};
1714
+ if (query) params[queryKey] = query;
1715
+ const response = await get({
1716
+ url: api,
1717
+ params,
1718
+ v
1719
+ });
1720
+ if (Array.isArray(response)) {
1721
+ setOptions(response);
1722
+ } else if (response?.data && Array.isArray(response.data)) {
1723
+ setOptions(response.data);
1724
+ } else if (response?.items && Array.isArray(response.items)) {
1725
+ setOptions(response.items);
1726
+ } else {
1727
+ setOptions([]);
1728
+ }
1729
+ } catch (err) {
1730
+ console.error("Failed to fetch options:", err);
1731
+ if (form && name) {
1732
+ form.setError(name, {
1733
+ type: "manual",
1734
+ message: err.message || "Failed to fetch options"
1735
+ });
1736
+ }
1737
+ setOptions([]);
1738
+ }
1739
+ };
1740
+ useEffect6(() => {
1741
+ const timer = setTimeout(() => {
1742
+ if (isOpen) {
1743
+ fetchOptions(searchTerm);
1744
+ }
1745
+ }, 300);
1746
+ return () => clearTimeout(timer);
1747
+ }, [searchTerm, api, isOpen]);
1748
+ useEffect6(() => {
1749
+ if (isOpen && options.length === 0) {
1750
+ fetchOptions("");
1751
+ }
1752
+ }, [isOpen]);
1753
+ useEffect6(() => {
1754
+ if (currentValue && !selectedObject) {
1755
+ setHasAttemptedHydration(false);
1756
+ fetchOptions(currentValue).finally(() => {
1757
+ setHasAttemptedHydration(true);
1758
+ });
1759
+ } else if (!currentValue) {
1760
+ setHasAttemptedHydration(true);
1761
+ if (selectedObject) setSelectedObject(void 0);
1762
+ }
1763
+ }, [currentValue, selectedObject]);
1764
+ const getOptionValue = (option) => {
1765
+ if (valueKey === "_id" && option._id === void 0 && option.id !== void 0) {
1766
+ return option.id;
1767
+ }
1768
+ return option[valueKey];
1769
+ };
1770
+ useEffect6(() => {
1771
+ if (currentValue && !selectedObject && options.length > 0) {
1772
+ const found = options.find((o) => getOptionValue(o) === currentValue);
1773
+ if (found) {
1774
+ setSelectedObject(found);
1775
+ if (form && obj) {
1776
+ form.setValue(obj, found);
1777
+ }
1778
+ }
1779
+ }
1780
+ }, [currentValue, options, selectedObject, form, obj]);
1781
+ useEffect6(() => {
1782
+ if (prevApiRef.current !== api) {
1783
+ prevApiRef.current = api;
1784
+ setSearchTerm("");
1785
+ setOptions([]);
1786
+ setSelectedObject(void 0);
1787
+ if (form) {
1788
+ if (name) {
1789
+ form.setValue(name, void 0, {
1790
+ shouldValidate: true,
1791
+ shouldDirty: true
1792
+ });
1793
+ }
1794
+ if (obj) {
1795
+ form.setValue(obj, void 0, {
1796
+ shouldValidate: true,
1797
+ shouldDirty: true
1798
+ });
1799
+ }
1800
+ } else {
1801
+ onChangeHandler(void 0);
1802
+ }
1803
+ fetchOptions("");
1804
+ }
1805
+ }, [api, form, name, obj, onChangeHandler]);
1806
+ useEffect6(() => {
1807
+ const handleClickOutside = (event) => {
1808
+ const target = event.target;
1809
+ if (containerRef.current && !containerRef.current.contains(target) && !(dropdownRef.current && dropdownRef.current.contains(target))) {
1810
+ setIsOpen(false);
1811
+ setIsFocused(false);
1812
+ setSearchTerm("");
1813
+ fieldInternalProps?.onBlur?.();
1814
+ }
1815
+ };
1816
+ document.addEventListener("mousedown", handleClickOutside);
1817
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1818
+ }, [fieldInternalProps]);
1819
+ const getDisplayValue = () => {
1820
+ if (selectedObject) return selectedObject[labelKey];
1821
+ if (options.length > 0 && currentValue) {
1822
+ const found = options.find((o) => getOptionValue(o) === currentValue);
1823
+ if (found) return found[labelKey];
1824
+ }
1825
+ if (isLoading || currentValue && !hasAttemptedHydration)
1826
+ return "Loading...";
1827
+ return currentValue || "";
1828
+ };
1829
+ const handleSelect = (option) => {
1830
+ const value = getOptionValue(option);
1831
+ setSelectedObject(option);
1832
+ onChangeHandler(value);
1833
+ if (form) {
1834
+ if (obj) form.setValue(obj, option);
1835
+ if (name) form.clearErrors(name);
1836
+ }
1837
+ setIsOpen(false);
1838
+ setSearchTerm("");
1839
+ setActiveIndex(-1);
1840
+ fieldInternalProps?.onBlur?.();
1841
+ };
1842
+ const handleKeyDown = (e) => {
1843
+ if (!isOpen) {
1844
+ if (e.key === "ArrowDown" || e.key === "Enter") setIsOpen(true);
1845
+ return;
1846
+ }
1847
+ switch (e.key) {
1848
+ case "ArrowDown":
1849
+ e.preventDefault();
1850
+ setActiveIndex((prev) => prev < options.length - 1 ? prev + 1 : prev);
1851
+ break;
1852
+ case "ArrowUp":
1853
+ e.preventDefault();
1854
+ setActiveIndex((prev) => prev > 0 ? prev - 1 : prev);
1855
+ break;
1856
+ case "Enter":
1857
+ e.preventDefault();
1858
+ if (activeIndex >= 0 && activeIndex < options.length)
1859
+ handleSelect(options[activeIndex]);
1860
+ break;
1861
+ case "Escape":
1862
+ setIsOpen(false);
1863
+ break;
1864
+ }
1865
+ };
1866
+ const clearSelection = (e) => {
1867
+ e.stopPropagation();
1868
+ if (form) {
1869
+ if (name)
1870
+ form.setValue(name, void 0, {
1871
+ shouldValidate: true,
1872
+ shouldDirty: true
1873
+ });
1874
+ if (obj)
1875
+ form.setValue(obj, void 0, {
1876
+ shouldValidate: true,
1877
+ shouldDirty: true
1878
+ });
1879
+ } else {
1880
+ onChangeHandler(void 0);
1881
+ }
1882
+ setSearchTerm("");
1883
+ };
1884
+ const filteredOptions = options.filter(
1885
+ (option) => !filter.includes(getOptionValue(option))
1886
+ );
1887
+ useEffect6(() => {
1888
+ if (form && name && !form.watch(name)) {
1889
+ form.setValue(name, void 0);
1890
+ if (obj) form.setValue(obj, void 0);
1891
+ }
1892
+ }, [form, name, obj]);
1893
+ let message = error;
1894
+ if (form && name) {
1895
+ const {
1896
+ formState: { errors }
1897
+ } = form;
1898
+ const nameParts = name.split(".");
1899
+ let currentError = errors;
1900
+ for (const part of nameParts) {
1901
+ currentError = currentError?.[part];
1902
+ }
1903
+ message = currentError?.message || message;
1904
+ }
1905
+ return /* @__PURE__ */ jsxs13(
1906
+ "div",
1907
+ {
1908
+ ref: containerRef,
1909
+ className: `${label ? "space-y-2" : ""} group ${containerClassName}`,
1910
+ children: [
1911
+ label && /* @__PURE__ */ jsxs13(
1912
+ "label",
1913
+ {
1914
+ className: `block text-xs font-medium transition-colors duration-200`,
1915
+ style: { color: isFocused || isOpen ? primaryColor : void 0 },
1916
+ children: [
1917
+ label,
1918
+ required && /* @__PURE__ */ jsx18("span", { className: "text-red-500 ml-1", children: "*" })
1919
+ ]
1920
+ }
1921
+ ),
1922
+ /* @__PURE__ */ jsxs13("div", { className: "relative", ref: dropdownAnchorRef, children: [
1923
+ /* @__PURE__ */ jsxs13(
1924
+ "div",
1925
+ {
1926
+ className: `flex items-center w-full px-0 text-gray-900 dark:text-white transition-all duration-200 cursor-text py-1 ${variant === "ghost" ? "bg-transparent border-transparent shadow-none px-0 h-full" : isFocused || isOpen ? "ring-2 bg-white dark:bg-zinc-900 border rounded-xl h-9" : "border-gray-200 dark:border-zinc-800 border rounded-xl bg-white dark:bg-zinc-900/50 h-9"} ${className}`,
1927
+ style: variant === "default" ? {
1928
+ borderColor: isFocused || isOpen ? primaryColor : void 0,
1929
+ boxShadow: isFocused || isOpen ? `${primaryColor}33 0px 0px 0px 2px` : void 0
1930
+ } : void 0,
1931
+ onClick: () => {
1932
+ if (disabled) return;
1933
+ inputRef.current?.focus();
1934
+ setIsOpen(true);
1935
+ },
1936
+ children: [
1937
+ /* @__PURE__ */ jsx18(
1938
+ "div",
1939
+ {
1940
+ className: `${variant === "ghost" ? "pl-0" : "pl-2.5"} text-gray-400`,
1941
+ children: /* @__PURE__ */ jsx18(Search, { className: "h-4 w-4" })
1942
+ }
1943
+ ),
1944
+ /* @__PURE__ */ jsxs13("div", { className: "flex-1 relative ms-2", children: [
1945
+ !isOpen && currentValue && /* @__PURE__ */ jsx18("div", { className: "absolute inset-0 flex items-center ms-1 truncate select-none", children: getDisplayValue() }),
1946
+ /* @__PURE__ */ jsx18(
1947
+ "input",
1948
+ {
1949
+ ref: setInputRef,
1950
+ type: "text",
1951
+ className: `block w-full bg-transparent border-none focus:ring-0 py-1 focus:outline-none text-sm ${!isOpen && currentValue ? "opacity-0" : "opacity-100"} ${variant === "ghost" ? "h-full" : "h-9"}`,
1952
+ placeholder: !currentValue ? placeholder : "",
1953
+ value: searchTerm,
1954
+ onChange: (e) => setSearchTerm(e.target.value),
1955
+ onFocus: () => {
1956
+ setIsFocused(true);
1957
+ setIsOpen(true);
1958
+ },
1959
+ onKeyDown: handleKeyDown,
1960
+ disabled,
1961
+ ...props
1962
+ }
1963
+ )
1964
+ ] }),
1965
+ /* @__PURE__ */ jsx18("div", { className: "pr-2.5 w-[60px]! flex items-center gap-1 shrink-0 min-w-[40px] justify-end", children: isLoading ? /* @__PURE__ */ jsx18(Loader22, { className: "h-4 w-4 animate-spin text-blue-500 shrink-0" }) : /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1", children: [
1966
+ currentValue && !disabled && /* @__PURE__ */ jsx18(
1967
+ "button",
1968
+ {
1969
+ onClick: clearSelection,
1970
+ type: "button",
1971
+ 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",
1972
+ children: /* @__PURE__ */ jsx18(X2, { className: "h-3 w-3" })
1973
+ }
1974
+ ),
1975
+ /* @__PURE__ */ jsx18(
1976
+ ChevronDown3,
1977
+ {
1978
+ className: `h-4 w-4 text-gray-400 transition-transform ${isOpen ? "rotate-180" : ""}`
1979
+ }
1980
+ )
1981
+ ] }) })
1982
+ ]
1983
+ }
1984
+ ),
1985
+ isOpen && typeof document !== "undefined" && createPortal(
1986
+ /* @__PURE__ */ jsx18(
1987
+ "div",
1988
+ {
1989
+ ref: dropdownRef,
1990
+ className: "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",
1991
+ style: dropdownStyle,
1992
+ children: isLoading && options.length === 0 ? /* @__PURE__ */ jsxs13("div", { className: "p-4 text-center text-sm text-gray-500", children: [
1993
+ /* @__PURE__ */ jsx18(Loader22, { className: "h-5 w-5 animate-spin mx-auto mb-2" }),
1994
+ "Loading options..."
1995
+ ] }) : filteredOptions.length > 0 ? /* @__PURE__ */ jsx18("div", { className: "py-1", children: filteredOptions.map((option, index) => {
1996
+ const optValue = getOptionValue(option);
1997
+ const isSelected = currentValue === optValue;
1998
+ const isHighlighted = index === activeIndex;
1999
+ return /* @__PURE__ */ jsxs13(
2000
+ "button",
2001
+ {
2002
+ type: "button",
2003
+ 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"}`,
2004
+ style: {
2005
+ backgroundColor: isSelected ? `${primaryColor}1A` : void 0,
2006
+ color: isSelected ? primaryColor : void 0
2007
+ },
2008
+ onClick: () => handleSelect(option),
2009
+ onMouseEnter: () => setActiveIndex(index),
2010
+ children: [
2011
+ /* @__PURE__ */ jsx18("span", { className: "truncate", children: option[labelKey] }),
2012
+ isSelected && /* @__PURE__ */ jsx18(
2013
+ Check3,
2014
+ {
2015
+ className: "h-4 w-4",
2016
+ style: { color: primaryColor }
2017
+ }
2018
+ )
2019
+ ]
2020
+ },
2021
+ optValue || index
2022
+ );
2023
+ }) }) : /* @__PURE__ */ jsx18("div", { className: "p-4 text-center text-sm text-gray-500", children: errorMessage || (searchTerm ? `No results for "${searchTerm}"` : "No options available") })
2024
+ }
2025
+ ),
2026
+ document.body
2027
+ )
2028
+ ] }),
2029
+ message && /* @__PURE__ */ jsx18("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
2030
+ ]
2031
+ }
2032
+ );
2033
+ };
2034
+ var SearchApi = forwardRef5(
2035
+ (props, _) => {
2036
+ const { form, name, onChange, value } = props;
2037
+ if (form && name) {
2038
+ return /* @__PURE__ */ jsx18(
2039
+ Controller5,
2040
+ {
2041
+ name,
2042
+ control: form.control,
2043
+ render: ({
2044
+ field: { onChange: formOnChange, value: formValue, ref, onBlur }
2045
+ }) => /* @__PURE__ */ jsx18(
2046
+ SearchApiContent,
2047
+ {
2048
+ ...props,
2049
+ currentValue: formValue,
2050
+ onChangeHandler: formOnChange,
2051
+ fieldInternalProps: { ref, onBlur }
2052
+ }
2053
+ )
2054
+ }
2055
+ );
2056
+ }
2057
+ return /* @__PURE__ */ jsx18(
2058
+ SearchApiContent,
2059
+ {
2060
+ ...props,
2061
+ currentValue: value,
2062
+ onChangeHandler: onChange || (() => {
2063
+ })
2064
+ }
2065
+ );
2066
+ }
2067
+ );
2068
+ SearchApi.displayName = "SearchApi";
2069
+
2070
+ // src/components/Fields/date.tsx
2071
+ import { forwardRef as forwardRef6, useState as useState12 } from "react";
2072
+ import { DatePicker } from "antd";
2073
+ import {
2074
+ Controller as Controller6
2075
+ } from "react-hook-form";
2076
+ import dayjs from "dayjs";
2077
+ import customParseFormat from "dayjs/plugin/customParseFormat";
2078
+ import { Calendar } from "lucide-react";
2079
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
2080
+ dayjs.extend(customParseFormat);
2081
+ var DateInput = forwardRef6(
2082
+ ({
2083
+ label,
2084
+ error,
2085
+ containerClassName = "",
2086
+ name,
2087
+ form,
2088
+ className = "",
2089
+ value,
2090
+ onBlur = () => {
2091
+ },
2092
+ onChange = () => {
2093
+ },
2094
+ ...props
2095
+ }, ref) => {
2096
+ const { theme } = useWarqadConfig();
2097
+ const primaryColor = theme?.primaryColor;
2098
+ const [isFocused, setIsFocused] = useState12(false);
2099
+ let message = error;
2100
+ if (form && name) {
2101
+ const {
2102
+ formState: { errors }
2103
+ } = form;
2104
+ const errorObj = name.split(".").reduce((acc, current) => acc?.[current], errors);
2105
+ message = errorObj?.message;
2106
+ }
2107
+ const inputStyles = `w-full px-2.5 py-1 rounded-xl! border! shadow-none transition-all! duration-200! outline-none!
2108
+ bg-white! dark:bg-zinc-900!
2109
+ text-gray-900! dark:text-zinc-100!
2110
+ hover:bg-white! dark:hover:bg-zinc-900!
2111
+ ${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"}
2112
+ [&.ant-picker-focused]:bg-white dark:[&.ant-picker-focused]:bg-zinc-900
2113
+ ${className}`;
2114
+ const renderDatePicker = (val, changeHandler, blurHandler, refProps) => {
2115
+ const dateValue = val && typeof val === "string" ? dayjs(val, "DD/MM/YYYY", true) : dayjs.isDayjs(val) ? val : null;
2116
+ return /* @__PURE__ */ jsx19(
2117
+ DatePicker,
2118
+ {
2119
+ ref: refProps,
2120
+ format: "DD/MM/YYYY",
2121
+ value: dateValue && dateValue.isValid() ? dateValue : null,
2122
+ onChange: (date) => {
2123
+ if (date && dayjs.isDayjs(date)) {
2124
+ changeHandler?.(date.format("DD/MM/YYYY"));
2125
+ } else {
2126
+ changeHandler?.("");
2127
+ }
2128
+ },
2129
+ onFocus: () => setIsFocused(true),
2130
+ onBlur: () => {
2131
+ setIsFocused(false);
2132
+ blurHandler?.();
2133
+ },
2134
+ className: ` ${inputStyles} [&>input]:text-gray-900! [&>input]:dark:text-zinc-100! [&>input]:text-base rounded-xl `,
2135
+ placeholder: "DD/MM/YYYY",
2136
+ needConfirm: false,
2137
+ style: {
2138
+ height: "36px",
2139
+ borderColor: isFocused && !message ? primaryColor : void 0,
2140
+ boxShadow: isFocused && !message ? `${primaryColor}33 0px 0px 0px 2px` : void 0
2141
+ },
2142
+ popupClassName: "z-50",
2143
+ suffixIcon: /* @__PURE__ */ jsx19(
2144
+ Calendar,
2145
+ {
2146
+ className: "h-5 w-5 text-gray-400",
2147
+ style: { color: isFocused ? primaryColor : void 0 }
2148
+ }
2149
+ ),
2150
+ allowClear: true,
2151
+ ...props
2152
+ }
2153
+ );
2154
+ };
2155
+ return /* @__PURE__ */ jsxs14("div", { className: `space-y-2 group ${containerClassName}`, children: [
2156
+ /* @__PURE__ */ jsx19(
2157
+ "label",
2158
+ {
2159
+ className: "block text-xs font-medium transition-colors duration-200",
2160
+ style: {
2161
+ color: message ? "#ef4444" : isFocused ? primaryColor : void 0
2162
+ },
2163
+ children: label
2164
+ }
2165
+ ),
2166
+ form && name ? /* @__PURE__ */ jsx19(
2167
+ Controller6,
2168
+ {
2169
+ control: form.control,
2170
+ name,
2171
+ render: ({ field }) => renderDatePicker(
2172
+ field.value,
2173
+ field.onChange,
2174
+ field.onBlur,
2175
+ field.ref
2176
+ )
2177
+ }
2178
+ ) : renderDatePicker(value, onChange, onBlur, ref),
2179
+ message && /* @__PURE__ */ jsx19("p", { className: "text-sm text-red-600 dark:text-red-400", children: message })
2180
+ ] });
2181
+ }
2182
+ );
2183
+
2184
+ // src/components/Fields/index.tsx
2185
+ var Fields = {
2186
+ Input,
2187
+ PhoneInput,
2188
+ Select,
2189
+ Textarea,
2190
+ SearchApi,
2191
+ DateInput
2192
+ };
2193
+ var Fields_default = Fields;
2194
+
2195
+ // src/components/tables/DataTable.tsx
2196
+ import React7, { useState as useState13, useMemo as useMemo2, useEffect as useEffect7 } from "react";
2197
+ import {
2198
+ useReactTable,
2199
+ getCoreRowModel,
2200
+ getPaginationRowModel,
2201
+ getSortedRowModel,
2202
+ getFilteredRowModel,
2203
+ getExpandedRowModel,
2204
+ flexRender
2205
+ } from "@tanstack/react-table";
2206
+ import { ChevronDown as ChevronDown4, Search as Search2 } from "lucide-react";
2207
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
2208
+ function DataTable({
2209
+ columns: userColumns,
2210
+ data,
2211
+ isLoading = false,
2212
+ pageRows,
2213
+ searchPlaceholder = "Search all columns...",
2214
+ className = "",
2215
+ verticalLines = false,
2216
+ rowPadding = "px-4 py-3",
2217
+ index = false,
2218
+ renderSubComponent,
2219
+ hasSubComponent = () => true,
2220
+ // default to true
2221
+ defaultExpanded = false,
2222
+ onChange
2223
+ }) {
2224
+ const { theme } = useWarqadConfig();
2225
+ const primaryColor = theme?.primaryColor;
2226
+ const [sorting, setSorting] = useState13([]);
2227
+ const [columnFilters, setColumnFilters] = useState13([]);
2228
+ const [columnVisibility, setColumnVisibility] = useState13({});
2229
+ const [rowSelection, setRowSelection] = useState13({});
2230
+ const [globalFilter, setGlobalFilter] = useState13("");
2231
+ const [expanded, setExpanded] = useState13(() => {
2232
+ const initialState = {};
2233
+ if (defaultExpanded && renderSubComponent && data) {
2234
+ data.forEach((row, idx) => {
2235
+ if (hasSubComponent(row)) {
2236
+ initialState[idx] = true;
2237
+ }
2238
+ });
2239
+ }
2240
+ return initialState;
2241
+ });
2242
+ const columns = useMemo2(() => {
2243
+ const mappedColumns = userColumns.map((col) => ({
2244
+ ...col,
2245
+ accessorKey: col.key || col.accessorKey,
2246
+ id: col.id || col.key || col.accessorKey
2247
+ }));
2248
+ if (!index) return mappedColumns;
2249
+ return [
2250
+ {
2251
+ id: "_index",
2252
+ header: "#",
2253
+ cell: ({ row }) => /* @__PURE__ */ jsx20("span", { className: "text-gray-500 font-medium ml-1", children: row.index + 1 }),
2254
+ enableSorting: false
2255
+ },
2256
+ ...mappedColumns
2257
+ ];
2258
+ }, [userColumns, index]);
2259
+ const table = useReactTable({
2260
+ data,
2261
+ columns,
2262
+ onSortingChange: setSorting,
2263
+ onColumnFiltersChange: setColumnFilters,
2264
+ getCoreRowModel: getCoreRowModel(),
2265
+ getPaginationRowModel: pageRows ? getPaginationRowModel() : void 0,
2266
+ getSortedRowModel: getSortedRowModel(),
2267
+ getFilteredRowModel: getFilteredRowModel(),
2268
+ getExpandedRowModel: getExpandedRowModel(),
2269
+ onExpandedChange: setExpanded,
2270
+ onColumnVisibilityChange: setColumnVisibility,
2271
+ onRowSelectionChange: setRowSelection,
2272
+ onGlobalFilterChange: setGlobalFilter,
2273
+ globalFilterFn: "includesString",
2274
+ state: {
2275
+ sorting,
2276
+ columnFilters,
2277
+ columnVisibility,
2278
+ rowSelection,
2279
+ globalFilter,
2280
+ expanded,
2281
+ ...pageRows ? { pagination: { pageSize: pageRows, pageIndex: 0 } } : {}
2282
+ },
2283
+ manualPagination: false
2284
+ });
2285
+ useEffect7(() => {
2286
+ if (onChange) {
2287
+ onChange({
2288
+ pagination: {
2289
+ pageIndex: table.getState().pagination.pageIndex,
2290
+ pageSize: table.getState().pagination.pageSize,
2291
+ pageCount: table.getPageCount()
2292
+ },
2293
+ sorting,
2294
+ columnFilters,
2295
+ globalFilter,
2296
+ selectedRows: table.getSelectedRowModel().rows.map((row) => row.original),
2297
+ filteredData: table.getFilteredRowModel().rows.map((row) => row.original)
2298
+ });
2299
+ }
2300
+ }, [
2301
+ sorting,
2302
+ columnFilters,
2303
+ globalFilter,
2304
+ rowSelection,
2305
+ table,
2306
+ onChange,
2307
+ table.getState().pagination.pageIndex,
2308
+ table.getState().pagination.pageSize
2309
+ ]);
2310
+ return /* @__PURE__ */ jsxs15("div", { className: `space-y-4 w-full ${className}`, children: [
2311
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between gap-4", children: [
2312
+ /* @__PURE__ */ jsx20("div", { className: "flex-1 max-w-sm", children: /* @__PURE__ */ jsx20(
2313
+ Fields_default.Input,
2314
+ {
2315
+ label: "Search",
2316
+ placeholder: searchPlaceholder,
2317
+ value: globalFilter,
2318
+ onChange: (e) => setGlobalFilter(e.target.value),
2319
+ icon: /* @__PURE__ */ jsx20(Search2, { size: 16 }),
2320
+ className: "h-9!"
2321
+ }
2322
+ ) }),
2323
+ /* @__PURE__ */ jsx20("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs15("div", { className: "relative group", children: [
2324
+ /* @__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: [
2325
+ "Columns",
2326
+ /* @__PURE__ */ jsx20(ChevronDown4, { size: 14, className: "text-gray-400" })
2327
+ ] }),
2328
+ /* @__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(
2329
+ "label",
2330
+ {
2331
+ 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",
2332
+ children: [
2333
+ /* @__PURE__ */ jsx20(
2334
+ "input",
2335
+ {
2336
+ type: "checkbox",
2337
+ checked: column.getIsVisible(),
2338
+ onChange: (e) => column.toggleVisibility(!!e.target.checked),
2339
+ className: "rounded border-gray-300 text-blue-600 focus:ring-blue-500",
2340
+ style: { accentColor: primaryColor }
2341
+ }
2342
+ ),
2343
+ column.id
2344
+ ]
2345
+ },
2346
+ column.id
2347
+ )) })
2348
+ ] }) })
2349
+ ] }),
2350
+ /* @__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: [
2351
+ /* @__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(
2352
+ "th",
2353
+ {
2354
+ className: `${rowPadding} text-[13px] font-semibold text-gray-900 dark:text-zinc-100 text-left ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""} ${header.id === "_index" ? "w-[1%] whitespace-nowrap" : ""}`,
2355
+ children: header.isPlaceholder ? null : flexRender(
2356
+ header.column.columnDef.header,
2357
+ header.getContext()
2358
+ )
2359
+ },
2360
+ header.id
2361
+ )) }, headerGroup.id)) }),
2362
+ /* @__PURE__ */ jsx20("tbody", { className: "", children: isLoading ? Array.from({ length: pageRows || 5 }).map((_, i) => /* @__PURE__ */ jsx20(
2363
+ "tr",
2364
+ {
2365
+ className: "border-b border-gray-100 dark:border-zinc-800/50",
2366
+ children: columns.map((_2, j) => /* @__PURE__ */ jsx20(
2367
+ "td",
2368
+ {
2369
+ className: `${rowPadding} ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800/50" : ""}`,
2370
+ children: /* @__PURE__ */ jsx20("div", { className: "h-4 bg-gray-100 dark:bg-zinc-800 rounded animate-pulse w-full" })
2371
+ },
2372
+ `skeleton-cell-${j}`
2373
+ ))
2374
+ },
2375
+ `skeleton-${i}`
2376
+ )) : table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsxs15(React7.Fragment, { children: [
2377
+ /* @__PURE__ */ jsx20(
2378
+ "tr",
2379
+ {
2380
+ className: `border-b border-gray-200 dark:border-zinc-800 hover:bg-gray-50/50 dark:hover:bg-zinc-900/50 transition-colors last:border-b-0 ${renderSubComponent && hasSubComponent(row.original) ? "cursor-pointer" : ""}`,
2381
+ "data-state": row.getIsSelected() && "selected",
2382
+ onClick: (e) => {
2383
+ if (renderSubComponent && hasSubComponent(row.original)) {
2384
+ const target = e.target;
2385
+ if (!target.closest(
2386
+ "button, a, input, select, textarea"
2387
+ )) {
2388
+ row.toggleExpanded();
2389
+ }
2390
+ }
2391
+ },
2392
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx20(
2393
+ "td",
2394
+ {
2395
+ className: `${rowPadding} text-sm text-gray-700 dark:text-gray-200 ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""} ${cell.column.id === "_index" ? "w-[1%] whitespace-nowrap" : ""}`,
2396
+ children: flexRender(
2397
+ cell.column.columnDef.cell,
2398
+ cell.getContext()
2399
+ )
2400
+ },
2401
+ cell.id
2402
+ ))
2403
+ }
2404
+ ),
2405
+ renderSubComponent && row.getIsExpanded() && hasSubComponent(row.original) && /* @__PURE__ */ jsx20("tr", { className: "border-b border-gray-200 dark:border-zinc-800 bg-gray-50/20 dark:bg-zinc-900/20", children: /* @__PURE__ */ jsx20("td", { colSpan: columns.length, className: "px-2 py-0", children: /* @__PURE__ */ jsxs15("div", { className: "relative pl-6 pb-2 pr-2 pt-2 h-full", children: [
2406
+ /* @__PURE__ */ jsx20("div", { className: "absolute left-2 top-0 bottom-2 w-6 border-l-2 border-b-2 rounded-bl-xl border-(--theme-primary) dark:border-(--theme-primary) pointer-events-none" }),
2407
+ renderSubComponent({
2408
+ row: row.original,
2409
+ index: row.index
2410
+ })
2411
+ ] }) }) })
2412
+ ] }, row.id)) : /* @__PURE__ */ jsx20("tr", { children: /* @__PURE__ */ jsx20(
2413
+ "td",
2414
+ {
2415
+ colSpan: columns.length,
2416
+ className: "h-32 text-center text-sm text-gray-500",
2417
+ children: "No results found."
2418
+ }
2419
+ ) }) }),
2420
+ table.getFooterGroups().some(
2421
+ (group) => group.headers.some(
2422
+ (header) => header.column.columnDef.footer
2423
+ )
2424
+ ) && /* @__PURE__ */ jsx20("tfoot", { className: "bg-gray-50/50 dark:bg-zinc-900/50 border-t border-gray-200 dark:border-zinc-800", children: table.getFooterGroups().map((footerGroup) => /* @__PURE__ */ jsx20("tr", { children: footerGroup.headers.map((header) => /* @__PURE__ */ jsx20(
2425
+ "td",
2426
+ {
2427
+ className: `${rowPadding} text-[13px] font-semibold text-gray-900 dark:text-zinc-100 text-left ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""} ${header.id === "_index" ? "w-[1%] whitespace-nowrap" : ""}`,
2428
+ children: header.isPlaceholder ? null : flexRender(
2429
+ header.column.columnDef.footer,
2430
+ header.getContext()
2431
+ )
2432
+ },
2433
+ header.id
2434
+ )) }, footerGroup.id)) })
2435
+ ] }) }) }),
2436
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between px-2", children: [
2437
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1 text-xs text-gray-500", children: [
2438
+ table.getFilteredSelectedRowModel().rows.length,
2439
+ " of",
2440
+ " ",
2441
+ table.getFilteredRowModel().rows.length,
2442
+ " row(s) selected."
2443
+ ] }),
2444
+ pageRows && table.getPageCount() > 1 && /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
2445
+ /* @__PURE__ */ jsx20(
2446
+ "button",
2447
+ {
2448
+ onClick: () => table.previousPage(),
2449
+ disabled: !table.getCanPreviousPage(),
2450
+ 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",
2451
+ children: "Previous"
2452
+ }
2453
+ ),
2454
+ /* @__PURE__ */ jsx20(
2455
+ "button",
2456
+ {
2457
+ onClick: () => table.nextPage(),
2458
+ disabled: !table.getCanNextPage(),
2459
+ 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",
2460
+ children: "Next"
2461
+ }
2462
+ )
2463
+ ] })
2464
+ ] })
2465
+ ] });
2466
+ }
2467
+
2468
+ // src/components/tables/PostTable.tsx
2469
+ import React8, { useState as useState14, useMemo as useMemo3, useEffect as useEffect8, useRef as useRef4 } from "react";
2470
+ import {
2471
+ useReactTable as useReactTable2,
2472
+ getCoreRowModel as getCoreRowModel2,
2473
+ getSortedRowModel as getSortedRowModel2,
2474
+ getFilteredRowModel as getFilteredRowModel2,
2475
+ getExpandedRowModel as getExpandedRowModel2,
2476
+ flexRender as flexRender2
2477
+ } from "@tanstack/react-table";
2478
+ import { Plus, Edit2, Trash2, Check as Check4, X as X3, ChevronDown as ChevronDown5 } from "lucide-react";
2479
+ import { Fragment as Fragment2, jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
2480
+ function PostTable({
2481
+ columns: userColumns,
2482
+ data: controlledData,
2483
+ onChange,
2484
+ isLoading = false,
2485
+ className = "",
2486
+ verticalLines = false,
2487
+ rowPadding = "px-4 py-3",
2488
+ index = false,
2489
+ renderAddButton,
2490
+ renderSubComponent,
2491
+ hasSubComponent = () => true,
2492
+ // default to true if renderSubComponent is provided
2493
+ defaultExpanded = false
2494
+ }) {
2495
+ const { theme } = useWarqadConfig();
2496
+ const primaryColor = theme?.primaryColor;
2497
+ const [sorting, setSorting] = useState14([]);
2498
+ const [columnFilters, setColumnFilters] = useState14([]);
2499
+ const [columnVisibility, setColumnVisibility] = useState14({});
2500
+ const [expanded, setExpanded] = useState14(() => {
2501
+ const initialState = {};
2502
+ if (defaultExpanded && renderSubComponent && controlledData) {
2503
+ controlledData.forEach((row, idx) => {
2504
+ if (hasSubComponent(row)) {
2505
+ initialState[idx] = true;
2506
+ }
2507
+ });
2508
+ }
2509
+ return initialState;
2510
+ });
2511
+ const [data, setData] = useState14(controlledData || []);
2512
+ const entryRowRef = useRef4(null);
2513
+ const focusAndScrollEntryRow = () => {
2514
+ setTimeout(() => {
2515
+ if (entryRowRef.current) {
2516
+ entryRowRef.current.scrollIntoView({
2517
+ behavior: "smooth",
2518
+ block: "nearest"
2519
+ });
2520
+ const firstInput = entryRowRef.current.querySelector(
2521
+ "input:not([disabled]), select:not([disabled]), textarea:not([disabled])"
2522
+ );
2523
+ if (firstInput && document.activeElement !== firstInput) {
2524
+ firstInput.focus();
2525
+ }
2526
+ }
2527
+ }, 50);
2528
+ };
2529
+ useEffect8(() => {
2530
+ focusAndScrollEntryRow();
2531
+ }, []);
2532
+ useEffect8(() => {
2533
+ if (controlledData) {
2534
+ setData(controlledData);
2535
+ }
2536
+ }, [controlledData]);
2537
+ const [entryData, setEntryData] = useState14({});
2538
+ const [editingIndex, setEditingIndex] = useState14(null);
2539
+ const [isSavingAsync, setIsSavingAsync] = useState14(false);
2540
+ const [fieldErrors, setFieldErrors] = useState14({});
2541
+ const handleSaveField = async () => {
2542
+ if (Object.keys(entryData).length === 0) return;
2543
+ let newData = [...data];
2544
+ if (editingIndex !== null) {
2545
+ newData[editingIndex] = {
2546
+ ...newData[editingIndex],
2547
+ ...entryData
2548
+ };
2549
+ } else {
2550
+ newData = [...newData, entryData];
2551
+ }
2552
+ if (onChange) {
2553
+ setIsSavingAsync(true);
2554
+ try {
2555
+ const actions = {
2556
+ focus: (columnId) => {
2557
+ if (entryRowRef.current) {
2558
+ const td = entryRowRef.current.querySelector(
2559
+ `td[data-column-id="${columnId}"]`
2560
+ );
2561
+ if (td) {
2562
+ const input = td.querySelector(
2563
+ `input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex='0'], [id*='${columnId}']`
2564
+ );
2565
+ if (input) input.focus();
2566
+ }
2567
+ }
2568
+ },
2569
+ setError: (columnId, hasError) => {
2570
+ setFieldErrors((prev) => ({
2571
+ ...prev,
2572
+ [columnId]: hasError
2573
+ }));
2574
+ }
2575
+ };
2576
+ const type = editingIndex !== null ? "edit" : "add";
2577
+ const result = await onChange(entryData, actions, type, newData);
2578
+ if (result === false) {
2579
+ setIsSavingAsync(false);
2580
+ return;
2581
+ }
2582
+ } catch (error) {
2583
+ setIsSavingAsync(false);
2584
+ return;
2585
+ }
2586
+ }
2587
+ setData(newData);
2588
+ setEntryData({});
2589
+ setFieldErrors({});
2590
+ setIsSavingAsync(false);
2591
+ if (editingIndex !== null) {
2592
+ setEditingIndex(null);
2593
+ } else {
2594
+ focusAndScrollEntryRow();
2595
+ }
2596
+ };
2597
+ const handleCancelEdit = () => {
2598
+ setEditingIndex(null);
2599
+ setEntryData({});
2600
+ setFieldErrors({});
2601
+ };
2602
+ const handleEdit = (index2, rowOriginal) => {
2603
+ setEditingIndex(index2);
2604
+ setEntryData(rowOriginal);
2605
+ };
2606
+ const handleDelete = (index2) => {
2607
+ const newData = data.filter((_, i) => i !== index2);
2608
+ setData(newData);
2609
+ const actions = {
2610
+ focus: (columnId) => {
2611
+ if (entryRowRef.current) {
2612
+ const td = entryRowRef.current.querySelector(
2613
+ `td[data-column-id="${columnId}"]`
2614
+ );
2615
+ if (td) {
2616
+ const input = td.querySelector(
2617
+ `input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex='0'], [id*='${columnId}']`
2618
+ );
2619
+ if (input) input.focus();
2620
+ }
2621
+ }
2622
+ },
2623
+ setError: (columnId, hasError) => {
2624
+ setFieldErrors((prev) => ({
2625
+ ...prev,
2626
+ [columnId]: hasError
2627
+ }));
2628
+ }
2629
+ };
2630
+ onChange?.(data[index2], actions, "delete", newData);
2631
+ if (editingIndex === index2) {
2632
+ handleCancelEdit();
2633
+ } else if (editingIndex !== null && editingIndex > index2) {
2634
+ setEditingIndex(editingIndex - 1);
2635
+ }
2636
+ };
2637
+ const actionColumn = {
2638
+ id: "actions",
2639
+ header: "Actions",
2640
+ cell: ({ row }) => {
2641
+ return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
2642
+ /* @__PURE__ */ jsx21(
2643
+ "button",
2644
+ {
2645
+ onClick: () => handleEdit(row.index, row.original),
2646
+ className: "p-1 px-2 rounded-md hover:bg-gray-100 dark:hover:bg-zinc-800 text-gray-500 hover:text-[var(--theme-primary)] dark:hover:text-[var(--theme-primary)] transition-colors",
2647
+ title: "Edit",
2648
+ children: /* @__PURE__ */ jsx21(Edit2, { size: 16 })
2649
+ }
2650
+ ),
2651
+ /* @__PURE__ */ jsx21(
2652
+ "button",
2653
+ {
2654
+ onClick: () => handleDelete(row.index),
2655
+ className: "p-1 px-2 rounded-md hover:bg-gray-100 dark:hover:bg-zinc-800 text-gray-500 hover:text-red-600 dark:hover:text-red-400 transition-colors",
2656
+ title: "Delete",
2657
+ children: /* @__PURE__ */ jsx21(Trash2, { size: 16 })
2658
+ }
2659
+ )
2660
+ ] });
2661
+ }
2662
+ };
2663
+ const columns = useMemo3(() => {
2664
+ const mappedUserColumns = userColumns.map((col) => ({
2665
+ ...col,
2666
+ accessorKey: col.key || col.accessorKey,
2667
+ id: col.id || col.key || col.accessorKey
2668
+ }));
2669
+ let finalColumns = [...mappedUserColumns, actionColumn];
2670
+ if (index) {
2671
+ finalColumns.unshift({
2672
+ id: "_index",
2673
+ header: "#",
2674
+ cell: ({ row }) => /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
2675
+ /* @__PURE__ */ jsx21("span", { className: "text-gray-500 font-medium ml-1", children: row.index + 1 }),
2676
+ renderSubComponent && hasSubComponent(row.original) && /* @__PURE__ */ jsx21(
2677
+ ChevronDown5,
2678
+ {
2679
+ size: 16,
2680
+ className: `text-gray-400 dark:text-gray-500 transition-transform ${row.getIsExpanded() ? "rotate-180" : ""}`
2681
+ }
2682
+ )
2683
+ ] }),
2684
+ enableSorting: false,
2685
+ meta: {
2686
+ field: () => /* @__PURE__ */ jsx21("span", { className: "text-gray-400 font-medium px-2 block select-none", children: "#" })
2687
+ }
2688
+ });
2689
+ }
2690
+ return finalColumns;
2691
+ }, [userColumns, actionColumn, index]);
2692
+ const table = useReactTable2({
2693
+ data,
2694
+ columns,
2695
+ onSortingChange: setSorting,
2696
+ onColumnFiltersChange: setColumnFilters,
2697
+ getCoreRowModel: getCoreRowModel2(),
2698
+ getSortedRowModel: getSortedRowModel2(),
2699
+ getFilteredRowModel: getFilteredRowModel2(),
2700
+ getExpandedRowModel: getExpandedRowModel2(),
2701
+ onExpandedChange: setExpanded,
2702
+ onColumnVisibilityChange: setColumnVisibility,
2703
+ state: {
2704
+ sorting,
2705
+ columnFilters,
2706
+ columnVisibility,
2707
+ expanded
2708
+ }
2709
+ });
2710
+ return /* @__PURE__ */ jsx21(
2711
+ "div",
2712
+ {
2713
+ className: `space-y-4 w-full ${className}`,
2714
+ style: { "--theme-primary": primaryColor || "#3b82f6" },
2715
+ children: /* @__PURE__ */ jsx21("div", { className: "rounded-lg border border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 relative", children: /* @__PURE__ */ jsx21("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs16("table", { className: "w-full text-left border-collapse", children: [
2716
+ /* @__PURE__ */ jsx21("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__ */ jsx21("tr", { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx21(
2717
+ "th",
2718
+ {
2719
+ className: `${rowPadding} text-[13px] font-semibold text-gray-900 dark:text-zinc-100 text-left ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""} ${header.id === "_index" ? "w-[1%] whitespace-nowrap" : ""}`,
2720
+ children: header.isPlaceholder ? null : flexRender2(
2721
+ header.column.columnDef.header,
2722
+ header.getContext()
2723
+ )
2724
+ },
2725
+ header.id
2726
+ )) }, headerGroup.id)) }),
2727
+ /* @__PURE__ */ jsxs16("tbody", { className: "", children: [
2728
+ isLoading ? Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx21(
2729
+ "tr",
2730
+ {
2731
+ className: "border-b border-gray-100 dark:border-zinc-800/50",
2732
+ children: columns.map((_2, j) => /* @__PURE__ */ jsx21(
2733
+ "td",
2734
+ {
2735
+ className: `${rowPadding} ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800/50" : ""}`,
2736
+ children: /* @__PURE__ */ jsx21("div", { className: "h-4 bg-gray-100 dark:bg-zinc-800 rounded animate-pulse w-full" })
2737
+ },
2738
+ `skeleton-cell-${j}`
2739
+ ))
2740
+ },
2741
+ `skeleton-${i}`
2742
+ )) : table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsxs16(React8.Fragment, { children: [
2743
+ /* @__PURE__ */ jsx21(
2744
+ "tr",
2745
+ {
2746
+ className: `border-b border-gray-200 dark:border-zinc-800 hover:bg-gray-50/50 dark:hover:bg-zinc-900/50 transition-colors last:border-b-0 ${renderSubComponent && hasSubComponent(row.original) ? "cursor-pointer" : ""}`,
2747
+ "data-state": row.getIsSelected() && "selected",
2748
+ onClick: (e) => {
2749
+ if (renderSubComponent && hasSubComponent(row.original)) {
2750
+ const target = e.target;
2751
+ if (!target.closest(
2752
+ "button, a, input, select, textarea"
2753
+ )) {
2754
+ row.toggleExpanded();
2755
+ }
2756
+ }
2757
+ },
2758
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx21(
2759
+ "td",
2760
+ {
2761
+ className: `${rowPadding} text-sm text-gray-700 dark:text-gray-200 ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""} ${cell.column.id === "_index" ? "w-[1%] whitespace-nowrap" : ""}`,
2762
+ children: flexRender2(
2763
+ cell.column.columnDef.cell,
2764
+ cell.getContext()
2765
+ )
2766
+ },
2767
+ cell.id
2768
+ ))
2769
+ }
2770
+ ),
2771
+ renderSubComponent && row.getIsExpanded() && hasSubComponent(row.original) && /* @__PURE__ */ jsx21("tr", { className: "border-b border-gray-200 dark:border-zinc-800 bg-gray-50/20 dark:bg-zinc-900/20", children: /* @__PURE__ */ jsx21("td", { colSpan: columns.length, className: "px-2 py-0", children: /* @__PURE__ */ jsxs16("div", { className: "relative pl-6 pb-2 pr-2 pt-2 h-full", children: [
2772
+ /* @__PURE__ */ jsx21("div", { className: "absolute left-2 top-0 bottom-2 w-6 border-l-2 border-b-2 rounded-bl-xl border-(--theme-primary) dark:border-(--theme-primary) pointer-events-none" }),
2773
+ renderSubComponent({
2774
+ row: row.original,
2775
+ index: row.index
2776
+ })
2777
+ ] }) }) })
2778
+ ] }, row.id)) : /* @__PURE__ */ jsx21("tr", { children: /* @__PURE__ */ jsx21(
2779
+ "td",
2780
+ {
2781
+ colSpan: columns.length,
2782
+ className: "h-32 text-center text-sm text-gray-500",
2783
+ children: "No results found."
2784
+ }
2785
+ ) }),
2786
+ /* @__PURE__ */ jsx21(
2787
+ "tr",
2788
+ {
2789
+ ref: entryRowRef,
2790
+ className: "border-t border-gray-200 dark:border-zinc-800",
2791
+ children: (function() {
2792
+ const visibleColumns = table.getVisibleLeafColumns();
2793
+ const editableColumns = visibleColumns.filter(
2794
+ (c) => c.id !== "actions" && c.id !== "_index"
2795
+ );
2796
+ const finalEditableCol = editableColumns[editableColumns.length - 1];
2797
+ const finalEditableId = finalEditableCol ? finalEditableCol.id || finalEditableCol.columnDef.accessorKey : null;
2798
+ return visibleColumns.map((column) => {
2799
+ const currentId = column.id || column.columnDef.accessorKey;
2800
+ if (column.id === "actions") {
2801
+ return /* @__PURE__ */ jsx21(
2802
+ "td",
2803
+ {
2804
+ className: cn(
2805
+ rowPadding,
2806
+ "py-1! text-sm align-middle transition-colors duration-200",
2807
+ verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""
2808
+ ),
2809
+ children: /* @__PURE__ */ jsx21("div", { className: "flex items-center gap-2", children: editingIndex !== null ? /* @__PURE__ */ jsxs16(Fragment2, { children: [
2810
+ /* @__PURE__ */ jsx21(
2811
+ "button",
2812
+ {
2813
+ onClick: handleSaveField,
2814
+ disabled: isSavingAsync,
2815
+ className: "flex-1 h-8 flex items-center justify-center rounded-lg bg-green-500/10 text-green-600 dark:bg-emerald-500/20 dark:text-emerald-400 hover:bg-green-500 hover:text-white dark:hover:bg-emerald-500 transition-colors shadow-sm active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed",
2816
+ title: "Update",
2817
+ children: isSavingAsync ? /* @__PURE__ */ jsx21("div", { className: "w-3.5 h-3.5 rounded-full border-2 border-emerald-500/30 border-t-emerald-500 animate-spin" }) : /* @__PURE__ */ jsx21(Check4, { size: 16, strokeWidth: 2.5 })
2818
+ }
2819
+ ),
2820
+ /* @__PURE__ */ jsx21(
2821
+ "button",
2822
+ {
2823
+ onClick: handleCancelEdit,
2824
+ disabled: isSavingAsync,
2825
+ className: "flex-1 h-8 flex items-center justify-center rounded-lg bg-red-500/10 text-red-600 dark:bg-red-500/20 dark:text-red-400 hover:bg-red-500 hover:text-white dark:hover:bg-red-500 transition-colors shadow-sm active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed",
2826
+ title: "Cancel",
2827
+ children: /* @__PURE__ */ jsx21(X3, { size: 16, strokeWidth: 2.5 })
2828
+ }
2829
+ )
2830
+ ] }) : /* @__PURE__ */ jsx21(Fragment2, { children: renderAddButton ? renderAddButton(
2831
+ entryData,
2832
+ handleSaveField,
2833
+ isSavingAsync
2834
+ ) : /* @__PURE__ */ jsxs16(
2835
+ "button",
2836
+ {
2837
+ onClick: handleSaveField,
2838
+ disabled: isSavingAsync,
2839
+ className: "w-full cursor-pointer h-8 flex items-center justify-center gap-1.5 rounded-lg text-white text-xs font-medium transition-all shadow-[0_1px_2px_rgba(0,0,0,0.05)] hover:shadow-md hover:-translate-y-px active:scale-[0.98] active:translate-y-0 bg-[var(--theme-primary)] hover:brightness-110 disabled:opacity-50 disabled:cursor-not-allowed",
2840
+ title: "Add Row",
2841
+ children: [
2842
+ isSavingAsync ? /* @__PURE__ */ jsx21("div", { className: "w-3.5 h-3.5 rounded-full border-2 border-white/30 border-t-white animate-spin" }) : /* @__PURE__ */ jsx21(Plus, { size: 14, strokeWidth: 2.5 }),
2843
+ /* @__PURE__ */ jsx21("span", { children: isSavingAsync ? "Adding..." : "Add" })
2844
+ ]
2845
+ }
2846
+ ) }) })
2847
+ },
2848
+ column.id
2849
+ );
2850
+ }
2851
+ const fieldRenderer = column.columnDef.meta?.field;
2852
+ const accessor = column.columnDef.accessorKey || column.id;
2853
+ const value = entryData[accessor] || "";
2854
+ const hasError = !!fieldErrors[accessor];
2855
+ const onChangeValue = (val) => {
2856
+ setEntryData((prev) => ({
2857
+ ...prev,
2858
+ [accessor]: val
2859
+ }));
2860
+ if (fieldErrors[accessor]) {
2861
+ setFieldErrors((prev) => {
2862
+ const next = { ...prev };
2863
+ delete next[accessor];
2864
+ return next;
2865
+ });
2866
+ }
2867
+ };
2868
+ return /* @__PURE__ */ jsx21(
2869
+ "td",
2870
+ {
2871
+ "data-column-id": column.id,
2872
+ onClick: (e) => {
2873
+ const input = e.currentTarget.querySelector(
2874
+ `input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex='0'], [id*='${column.id}']`
2875
+ );
2876
+ if (input && document.activeElement !== input) {
2877
+ input.focus();
2878
+ }
2879
+ },
2880
+ className: cn(
2881
+ rowPadding,
2882
+ "py-1! text-sm align-middle transition-colors duration-200",
2883
+ column.id !== "_index" ? "cursor-text" : "",
2884
+ verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : "",
2885
+ column.id === "_index" ? "w-[1%] whitespace-nowrap" : "",
2886
+ hasError && "ring-1 ring-inset ring-red-500"
2887
+ ),
2888
+ children: /* @__PURE__ */ jsx21(
2889
+ "div",
2890
+ {
2891
+ className: cn(
2892
+ "flex items-center",
2893
+ column.id === "_index" ? "" : "w-full min-w-[120px] h-9"
2894
+ ),
2895
+ onKeyDown: (e) => {
2896
+ if (e.key === "Enter") {
2897
+ e.preventDefault();
2898
+ handleSaveField();
2899
+ }
2900
+ },
2901
+ children: fieldRenderer ? fieldRenderer({
2902
+ value,
2903
+ onChange: onChangeValue,
2904
+ rowData: entryData,
2905
+ setRowData: setEntryData
2906
+ }) : /* @__PURE__ */ jsx21(
2907
+ Fields_default.Input,
2908
+ {
2909
+ id: `pti-${accessor}`,
2910
+ label: "",
2911
+ variant: "ghost",
2912
+ value,
2913
+ onChange: (e) => onChangeValue(e.target.value),
2914
+ className: "px-0! bg-transparent!",
2915
+ placeholder: `${typeof column.columnDef.header === "string" ? column.columnDef.header : column.id}`
2916
+ }
2917
+ )
2918
+ }
2919
+ )
2920
+ },
2921
+ column.id
2922
+ );
2923
+ });
2924
+ })()
2925
+ }
2926
+ )
2927
+ ] }),
2928
+ table.getFooterGroups().some(
2929
+ (group) => group.headers.some(
2930
+ (header) => header.column.columnDef.footer
2931
+ )
2932
+ ) && /* @__PURE__ */ jsx21("tfoot", { className: "bg-gray-50/50 dark:bg-zinc-900/50 border-t border-gray-200 dark:border-zinc-800", children: table.getFooterGroups().map((footerGroup) => /* @__PURE__ */ jsx21("tr", { children: footerGroup.headers.map((header) => /* @__PURE__ */ jsx21(
2933
+ "td",
2934
+ {
2935
+ className: `${rowPadding} text-[13px] font-semibold text-gray-900 dark:text-zinc-100 text-left ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""} ${header.id === "_index" ? "w-[1%] whitespace-nowrap" : ""}`,
2936
+ children: header.isPlaceholder ? null : flexRender2(
2937
+ header.column.columnDef.footer,
2938
+ header.getContext()
2939
+ )
2940
+ },
2941
+ header.id
2942
+ )) }, footerGroup.id)) })
2943
+ ] }) }) })
2944
+ }
2945
+ );
2946
+ }
2947
+
2948
+ // src/components/tables/SimpleTable.tsx
2949
+ import { useMemo as useMemo4 } from "react";
2950
+ import {
2951
+ useReactTable as useReactTable3,
2952
+ getCoreRowModel as getCoreRowModel3,
2953
+ flexRender as flexRender3
2954
+ } from "@tanstack/react-table";
2955
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
2956
+ function SimpleTable({
2957
+ columns: userColumns,
2958
+ data,
2959
+ className = "",
2960
+ renderFooter,
2961
+ rowPadding = "py-3",
2962
+ verticalLines = false
2963
+ }) {
2964
+ const { theme } = useWarqadConfig();
2965
+ const columns = useMemo4(() => {
2966
+ return userColumns.map((col) => ({
2967
+ ...col,
2968
+ accessorKey: col.key || col.accessorKey,
2969
+ id: col.id || col.key || col.accessorKey
2970
+ }));
2971
+ }, [userColumns]);
2972
+ const table = useReactTable3({
2973
+ data,
2974
+ columns,
2975
+ getCoreRowModel: getCoreRowModel3()
2976
+ });
2977
+ return /* @__PURE__ */ jsxs17("div", { className: `w-full overflow-hidden ${className}`, children: [
2978
+ /* @__PURE__ */ jsxs17("table", { className: "w-full text-left border-collapse", children: [
2979
+ /* @__PURE__ */ jsx22("thead", { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx22(
2980
+ "tr",
2981
+ {
2982
+ className: "border-b border-gray-200 dark:border-zinc-800",
2983
+ children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx22(
2984
+ "th",
2985
+ {
2986
+ className: `${rowPadding} font-semibold text-gray-900 dark:text-zinc-100 text-[13px] ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""}`,
2987
+ style: {
2988
+ width: header.column.getSize() !== 150 ? header.column.getSize() : "auto"
2989
+ },
2990
+ children: header.isPlaceholder ? null : flexRender3(
2991
+ header.column.columnDef.header,
2992
+ header.getContext()
2993
+ )
2994
+ },
2995
+ header.id
2996
+ ))
2997
+ },
2998
+ headerGroup.id
2999
+ )) }),
3000
+ /* @__PURE__ */ jsx22("tbody", { className: "text-gray-600 dark:text-zinc-400", children: table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx22(
3001
+ "tr",
3002
+ {
3003
+ className: "border-b border-gray-100 dark:border-zinc-800/60 last:border-0 hover:bg-gray-50/50 dark:hover:bg-zinc-900/30 transition-colors",
3004
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx22(
3005
+ "td",
3006
+ {
3007
+ className: `text-[13px] ${rowPadding} ${verticalLines ? "border-x border-gray-200 dark:border-zinc-800" : ""}`,
3008
+ children: flexRender3(cell.column.columnDef.cell, cell.getContext())
3009
+ },
3010
+ cell.id
3011
+ ))
3012
+ },
3013
+ row.id
3014
+ )) })
3015
+ ] }),
3016
+ renderFooter && /* @__PURE__ */ jsx22("div", { className: "mt-2 pt-3 border-t border-gray-200 dark:border-zinc-800", children: renderFooter() })
3017
+ ] });
3018
+ }
3019
+
3020
+ // src/components/Badge.tsx
3021
+ import React10 from "react";
3022
+ import { jsx as jsx23 } from "react/jsx-runtime";
3023
+ var Badge = React10.forwardRef(
3024
+ ({
3025
+ children,
3026
+ className,
3027
+ variant = "primary",
3028
+ size = "md",
3029
+ outline = false,
3030
+ ...props
3031
+ }, ref) => {
3032
+ const baseStyles = "inline-flex items-center justify-center font-medium rounded-full transition-colors whitespace-nowrap";
3033
+ const variants = {
3034
+ primary: outline ? "border border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400 bg-transparent" : "bg-blue-600 text-white dark:bg-blue-500 border border-transparent",
3035
+ danger: outline ? "border border-red-600 text-red-600 dark:border-red-400 dark:text-red-400 bg-transparent" : "bg-red-600 text-white dark:bg-red-500 border border-transparent",
3036
+ warning: outline ? "border border-yellow-500 text-yellow-700 dark:border-yellow-400 dark:text-yellow-300 bg-transparent" : "bg-yellow-500 text-white dark:bg-yellow-400 border border-transparent",
3037
+ success: outline ? "border border-green-600 text-green-600 dark:border-green-400 dark:text-green-400 bg-transparent" : "bg-green-600 text-white dark:bg-green-500 border border-transparent"
3038
+ };
3039
+ const sizes = {
3040
+ sm: "px-2 py-0.5 text-[0.65rem] leading-none uppercase tracking-wider font-semibold",
3041
+ md: "px-2.5 py-1 text-xs leading-tight font-semibold",
3042
+ lg: "px-3 py-1.5 text-sm leading-tight font-semibold"
3043
+ };
3044
+ return /* @__PURE__ */ jsx23(
3045
+ "span",
3046
+ {
3047
+ ref,
3048
+ className: cn(baseStyles, variants[variant], sizes[size], className),
3049
+ ...props,
3050
+ children
3051
+ }
3052
+ );
3053
+ }
3054
+ );
3055
+ Badge.displayName = "Badge";
3056
+
3057
+ // src/components/Branding.tsx
3058
+ import { jsx as jsx24 } from "react/jsx-runtime";
3059
+ var Branding = ({
3060
+ text,
3061
+ disabled = false,
3062
+ className
3063
+ }) => {
3064
+ return /* @__PURE__ */ jsx24(
3065
+ "p",
3066
+ {
3067
+ className: cn(
3068
+ "text-center text-[10px] font-bold uppercase tracking-widest transition-all duration-300 font-bona",
3069
+ disabled ? "opacity-40 cursor-not-allowed" : "text-slate-900 dark:text-slate-50",
3070
+ className
3071
+ ),
3072
+ children: text
3073
+ }
3074
+ );
3075
+ };
3076
+
3077
+ // src/utils/pdf.ts
3078
+ import html2canvas from "html2canvas-pro";
3079
+ import { jsPDF } from "jspdf";
3080
+ var generatePdf = async (elementId, options = {}) => {
3081
+ const {
3082
+ orientation = "landscape",
3083
+ unit = "mm",
3084
+ format = "a4",
3085
+ filename = "export.pdf",
3086
+ margin = 10,
3087
+ windowWidth = 1200,
3088
+ scale = 1,
3089
+ showPageNumbers = true
3090
+ } = options;
3091
+ const element = document.getElementById(elementId);
3092
+ if (!element) {
3093
+ console.error(
3094
+ `PDF generation failed: Element with ID "${elementId}" not found.`
3095
+ );
3096
+ return;
3097
+ }
3098
+ try {
3099
+ const pdf = new jsPDF({
3100
+ orientation,
3101
+ unit,
3102
+ format,
3103
+ compress: true
3104
+ });
3105
+ const pageWidth = pdf.internal.pageSize.getWidth();
3106
+ const pageHeight = pdf.internal.pageSize.getHeight();
3107
+ window.html2canvas = html2canvas;
3108
+ await pdf.html(element, {
3109
+ callback: function(doc) {
3110
+ if (showPageNumbers) {
3111
+ const pageCount = doc.internal.getNumberOfPages();
3112
+ for (let i = 1; i <= pageCount; i++) {
3113
+ doc.setPage(i);
3114
+ doc.setFontSize(8);
3115
+ doc.setTextColor(150);
3116
+ const text = `Page ${i} of ${pageCount}`;
3117
+ const textWidth = doc.getStringUnitWidth(text) * 8 / doc.internal.scaleFactor;
3118
+ doc.text(text, (pageWidth - textWidth) / 2, pageHeight - 5);
3119
+ }
3120
+ }
3121
+ doc.save(filename);
3122
+ const pdfBlob = doc.output("blob");
3123
+ const url = URL.createObjectURL(pdfBlob);
3124
+ window.open(url, "_blank");
3125
+ },
3126
+ x: margin,
3127
+ y: margin,
3128
+ width: pageWidth - margin * 2,
3129
+ windowWidth,
3130
+ html2canvas: {
3131
+ useCORS: true,
3132
+ scale: Math.max(scale, 2),
3133
+ // Ensure scale is at least 2 for text clarity
3134
+ logging: false,
3135
+ onclone: (clonedDoc) => {
3136
+ const elements = clonedDoc.getElementsByTagName("*");
3137
+ const tempCanvas = clonedDoc.createElement("canvas");
3138
+ tempCanvas.width = 1;
3139
+ tempCanvas.height = 1;
3140
+ const ctx = tempCanvas.getContext("2d");
3141
+ const target = clonedDoc.getElementById(elementId);
3142
+ if (target) {
3143
+ target.style.width = `${windowWidth}px`;
3144
+ target.style.maxWidth = "none";
3145
+ }
3146
+ const toRgb = (color) => {
3147
+ if (!color || !color.includes("oklch") && !color.includes("oklab"))
3148
+ return color;
3149
+ if (!ctx) return "rgb(0,0,0)";
3150
+ try {
3151
+ ctx.fillStyle = color;
3152
+ const result = ctx.fillStyle;
3153
+ return result.includes("ok") ? "rgb(0,0,0)" : result;
3154
+ } catch (e) {
3155
+ return "rgb(0,0,0)";
3156
+ }
3157
+ };
3158
+ for (let i = 0; i < elements.length; i++) {
3159
+ const el = elements[i];
3160
+ const style = window.getComputedStyle(elements[i]);
3161
+ const colorProps = [
3162
+ "color",
3163
+ "backgroundColor",
3164
+ "borderColor",
3165
+ "borderTopColor",
3166
+ "borderBottomColor",
3167
+ "borderLeftColor",
3168
+ "borderRightColor",
3169
+ "fill",
3170
+ "stroke",
3171
+ "outlineColor",
3172
+ "stopColor",
3173
+ "floodColor",
3174
+ "lightingColor"
3175
+ ];
3176
+ colorProps.forEach((prop) => {
3177
+ const val = style[prop];
3178
+ if (val && (val.includes("oklch") || val.includes("oklab"))) {
3179
+ el.style[prop] = toRgb(val);
3180
+ }
3181
+ });
3182
+ }
3183
+ const styleTags = clonedDoc.getElementsByTagName("style");
3184
+ for (let i = 0; i < styleTags.length; i++) {
3185
+ let cssText = styleTags[i].innerHTML;
3186
+ if (cssText.includes("oklch") || cssText.includes("oklab")) {
3187
+ cssText = cssText.replace(/oklch\([^)]+\)/g, "rgb(0,0,0)");
3188
+ cssText = cssText.replace(/oklab\([^)]+\)/g, "rgb(0,0,0)");
3189
+ styleTags[i].innerHTML = cssText;
3190
+ }
3191
+ }
3192
+ }
3193
+ },
3194
+ autoPaging: "text"
3195
+ });
3196
+ } catch (error) {
3197
+ console.error("PDF generation failed:", error);
3198
+ throw error;
3199
+ }
3200
+ };
3201
+ export {
3202
+ Badge,
3203
+ Branding,
3204
+ Button,
3205
+ Card,
3206
+ CardContent,
3207
+ CardDescription,
3208
+ CardFooter,
3209
+ CardHeader,
3210
+ CardTitle,
3211
+ ClassicSpin,
3212
+ CodeBlock,
3213
+ DashboardLayout,
3214
+ DataTable,
3215
+ DateInput,
3216
+ Fields_default as Fields,
3217
+ Input,
3218
+ LoadingBox,
3219
+ LoadingSpin,
3220
+ Modal,
3221
+ OverlaySpin,
3222
+ PageHeader,
3223
+ PhoneInput,
3224
+ PostTable,
3225
+ SearchApi,
3226
+ Select,
3227
+ SimpleTable,
3228
+ Textarea,
3229
+ ThemeProvider,
3230
+ ThemeToggle,
3231
+ WarqadProvider,
3232
+ generatePdf,
3233
+ useApis_default as useApi,
3234
+ useModal,
3235
+ useTheme,
3236
+ useWarqadConfig
3237
+ };