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