primus-react-ui 1.0.14 → 1.1.1

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/dist/index.mjs CHANGED
@@ -760,7 +760,7 @@ var SecurityDashboard = ({
760
760
  };
761
761
 
762
762
  // src/components/auth/PrimusLogin.tsx
763
- import { useState as useState13 } from "react";
763
+ import { useState as useState14 } from "react";
764
764
 
765
765
  // src/context/PrimusThemeProvider.tsx
766
766
  import { createContext, useContext, useState as useState12, useCallback } from "react";
@@ -844,240 +844,144 @@ function PrimusThemeToggle() {
844
844
  );
845
845
  }
846
846
 
847
- // src/components/auth/PrimusLogin.tsx
848
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
849
- var providerConfigs = {
850
- google: {
851
- name: "Google",
852
- icon: /* @__PURE__ */ jsxs12("svg", { className: "h-5 w-5", viewBox: "0 0 24 24", children: [
853
- /* @__PURE__ */ jsx13("path", { fill: "#4285F4", d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }),
854
- /* @__PURE__ */ jsx13("path", { fill: "#34A853", d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
855
- /* @__PURE__ */ jsx13("path", { fill: "#FBBC05", d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }),
856
- /* @__PURE__ */ jsx13("path", { fill: "#EA4335", d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
857
- ] }),
858
- colors: { light: "bg-white hover:bg-gray-50 text-gray-700 border-gray-300", dark: "bg-white hover:bg-gray-100 text-gray-700 border-gray-300" }
859
- },
860
- azure: {
861
- name: "Microsoft",
862
- icon: /* @__PURE__ */ jsxs12("svg", { className: "h-5 w-5", viewBox: "0 0 23 23", children: [
863
- /* @__PURE__ */ jsx13("path", { fill: "#f35325", d: "M1 1h10v10H1z" }),
864
- /* @__PURE__ */ jsx13("path", { fill: "#81bc06", d: "M12 1h10v10H12z" }),
865
- /* @__PURE__ */ jsx13("path", { fill: "#05a6f0", d: "M1 12h10v10H1z" }),
866
- /* @__PURE__ */ jsx13("path", { fill: "#ffba08", d: "M12 12h10v10H12z" })
867
- ] }),
868
- colors: { light: "bg-white hover:bg-gray-50 text-gray-700 border-gray-300", dark: "bg-white hover:bg-gray-100 text-gray-700 border-gray-300" }
869
- },
870
- github: {
871
- name: "GitHub",
872
- icon: /* @__PURE__ */ jsx13("svg", { className: "h-5 w-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { fillRule: "evenodd", d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z", clipRule: "evenodd" }) }),
873
- colors: { light: "bg-gray-900 hover:bg-gray-800 text-white border-gray-900", dark: "bg-white hover:bg-gray-100 text-gray-900 border-gray-300" }
874
- },
875
- microsoft: {
876
- name: "Microsoft",
877
- icon: /* @__PURE__ */ jsxs12("svg", { className: "h-5 w-5", viewBox: "0 0 24 24", children: [
878
- /* @__PURE__ */ jsx13("path", { fill: "#F25022", d: "M1 1h10v10H1z" }),
879
- /* @__PURE__ */ jsx13("path", { fill: "#00A4EF", d: "M1 13h10v10H1z" }),
880
- /* @__PURE__ */ jsx13("path", { fill: "#7FBA00", d: "M13 1h10v10H13z" }),
881
- /* @__PURE__ */ jsx13("path", { fill: "#FFB900", d: "M13 13h10v10H13z" })
882
- ] }),
883
- colors: { light: "bg-white hover:bg-gray-50 text-gray-700 border-gray-300", dark: "bg-white hover:bg-gray-100 text-gray-700 border-gray-300" }
884
- },
885
- apple: {
886
- name: "Apple",
887
- icon: /* @__PURE__ */ jsx13("svg", { className: "h-5 w-5", fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { d: "M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" }) }),
888
- colors: { light: "bg-black hover:bg-gray-900 text-white border-black", dark: "bg-white hover:bg-gray-100 text-black border-gray-300" }
889
- },
890
- facebook: {
891
- name: "Facebook",
892
- icon: /* @__PURE__ */ jsx13("svg", { className: "h-5 w-5", fill: "white", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { d: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" }) }),
893
- colors: { light: "bg-[#1877F2] hover:bg-[#166FE5] text-white border-[#1877F2]", dark: "bg-[#1877F2] hover:bg-[#166FE5] text-white border-[#1877F2]" }
894
- }
895
- };
896
- function PrimusLogin({
897
- onLogin,
898
- socialProviders = [],
899
- onSocialLogin,
900
- authEndpoint = "/api/auth",
901
- showEmailLogin = true,
902
- title = "Welcome Back",
903
- subtitle = "Enter your credentials to continue",
904
- logo,
905
- theme: themeOverride
906
- }) {
907
- const themeContext = usePrimusTheme();
908
- const theme = themeOverride || themeContext.theme;
909
- const isLight = theme === "light";
910
- const [username, setUsername] = useState13("");
911
- const [password, setPassword] = useState13("");
912
- const [loading, setLoading] = useState13(false);
913
- const handleSubmit = async (e) => {
914
- e.preventDefault();
915
- if (!username || !password) return;
916
- setLoading(true);
917
- try {
918
- onLogin?.({ username, password });
919
- } finally {
920
- setLoading(false);
921
- }
922
- };
923
- const handleSocialClick = (provider) => {
924
- if (onSocialLogin) {
925
- onSocialLogin(provider);
926
- } else {
927
- window.location.href = `${authEndpoint}/${provider}`;
928
- }
929
- };
930
- const bgGradient = isLight ? "bg-gradient-to-br from-gray-50 via-white to-violet-50" : "bg-gray-950";
931
- const cardBg = isLight ? "bg-white border-gray-200 shadow-xl" : "bg-gray-900/50 border-white/10";
932
- const headingColor = isLight ? "text-gray-900" : "text-white";
933
- const subtextColor = isLight ? "text-gray-500" : "text-slate-400";
934
- const labelColor = isLight ? "text-gray-600" : "text-slate-300";
935
- const inputClasses = isLight ? "bg-gray-50 border-gray-300 text-gray-900 placeholder:text-gray-400 focus:border-violet-500 focus:ring-violet-500" : "bg-gray-950/50 border-slate-700 text-white placeholder:text-slate-600 focus:border-blue-500 focus:ring-blue-500";
936
- const buttonGradient = isLight ? "bg-gradient-to-r from-violet-600 to-purple-600" : "bg-gradient-to-r from-blue-600 to-indigo-600";
937
- const logoBg = isLight ? "bg-violet-600 shadow-violet-500/20" : "bg-blue-600 shadow-blue-500/20";
938
- const dividerColor = isLight ? "border-gray-200" : "border-slate-700";
939
- const hasSocial = socialProviders.length > 0;
940
- return /* @__PURE__ */ jsxs12("div", { className: `min-h-screen ${bgGradient} flex items-center justify-center p-4`, children: [
941
- !isLight && /* @__PURE__ */ jsxs12("div", { className: "absolute inset-0 overflow-hidden", children: [
942
- /* @__PURE__ */ jsx13("div", { className: "absolute -top-[20%] -left-[10%] w-[50%] h-[50%] bg-blue-600/20 rounded-full blur-[120px]" }),
943
- /* @__PURE__ */ jsx13("div", { className: "absolute -bottom-[20%] -right-[10%] w-[50%] h-[50%] bg-purple-600/20 rounded-full blur-[120px]" })
944
- ] }),
945
- /* @__PURE__ */ jsxs12("div", { className: `w-full max-w-md ${cardBg} p-8 rounded-2xl border backdrop-blur-xl relative z-10`, children: [
946
- /* @__PURE__ */ jsxs12("div", { className: "text-center mb-8", children: [
947
- logo ? typeof logo === "string" ? /* @__PURE__ */ jsx13("img", { src: logo, alt: "Logo", className: "h-12 w-12 mx-auto mb-4 rounded-xl" }) : /* @__PURE__ */ jsx13("div", { className: "mb-4", children: logo }) : /* @__PURE__ */ jsx13("div", { className: `h-12 w-12 ${logoBg} rounded-xl mx-auto flex items-center justify-center mb-4 shadow-lg`, children: /* @__PURE__ */ jsx13("span", { className: "font-bold text-xl text-white", children: "P" }) }),
948
- /* @__PURE__ */ jsx13("h1", { className: `text-2xl font-bold ${headingColor} tracking-tight`, children: title }),
949
- /* @__PURE__ */ jsx13("p", { className: `${subtextColor} text-sm mt-2`, children: subtitle })
950
- ] }),
951
- hasSocial && /* @__PURE__ */ jsx13("div", { className: "space-y-3 mb-6", children: socialProviders.map((provider) => {
952
- const config = providerConfigs[provider];
953
- if (!config) return null;
954
- return /* @__PURE__ */ jsxs12(
955
- "button",
956
- {
957
- onClick: () => handleSocialClick(provider),
958
- className: `w-full flex items-center justify-center gap-3 px-4 py-2.5 border rounded-lg font-medium text-sm transition-all duration-200 ${isLight ? config.colors.light : config.colors.dark}`,
959
- children: [
960
- config.icon,
961
- /* @__PURE__ */ jsxs12("span", { children: [
962
- "Continue with ",
963
- config.name
964
- ] })
965
- ]
966
- },
967
- provider
968
- );
969
- }) }),
970
- hasSocial && showEmailLogin && /* @__PURE__ */ jsxs12("div", { className: "relative my-6", children: [
971
- /* @__PURE__ */ jsx13("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsx13("div", { className: `w-full border-t ${dividerColor}` }) }),
972
- /* @__PURE__ */ jsx13("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ jsx13("span", { className: `${isLight ? "bg-white" : "bg-gray-900/50"} px-2 ${subtextColor}`, children: "Or continue with email" }) })
973
- ] }),
974
- showEmailLogin && /* @__PURE__ */ jsxs12("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
975
- /* @__PURE__ */ jsxs12("div", { className: "space-y-2", children: [
976
- /* @__PURE__ */ jsx13("label", { className: `text-xs font-medium ${labelColor} ml-1`, children: "EMAIL" }),
977
- /* @__PURE__ */ jsx13(
978
- "input",
979
- {
980
- type: "text",
981
- value: username,
982
- onChange: (e) => setUsername(e.target.value),
983
- className: `w-full px-4 py-2.5 ${inputClasses} border rounded-lg focus:outline-none focus:ring-1 transition-all text-sm`,
984
- placeholder: "you@example.com"
985
- }
986
- )
987
- ] }),
988
- /* @__PURE__ */ jsxs12("div", { className: "space-y-2", children: [
989
- /* @__PURE__ */ jsx13("label", { className: `text-xs font-medium ${labelColor} ml-1`, children: "PASSWORD" }),
990
- /* @__PURE__ */ jsx13(
991
- "input",
992
- {
993
- type: "password",
994
- value: password,
995
- onChange: (e) => setPassword(e.target.value),
996
- className: `w-full px-4 py-2.5 ${inputClasses} border rounded-lg focus:outline-none focus:ring-1 transition-all text-sm`,
997
- placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"
998
- }
999
- )
1000
- ] }),
1001
- /* @__PURE__ */ jsx13(
1002
- "button",
1003
- {
1004
- type: "submit",
1005
- disabled: loading,
1006
- className: `w-full mt-4 py-2.5 ${buttonGradient} text-white font-medium rounded-lg hover:opacity-90 transition-opacity disabled:opacity-50`,
1007
- children: loading ? "Signing in..." : "Sign In"
1008
- }
1009
- )
1010
- ] })
1011
- ] })
1012
- ] });
1013
- }
1014
- var LoginPage = PrimusLogin;
1015
-
1016
847
  // src/context/PrimusProvider.tsx
1017
- import { createContext as createContext2, useContext as useContext2, useEffect as useEffect8, useState as useState14, useCallback as useCallback2 } from "react";
1018
- import { jsx as jsx14 } from "react/jsx-runtime";
848
+ import { createContext as createContext2, useContext as useContext2, useEffect as useEffect8, useState as useState13, useCallback as useCallback2, useRef } from "react";
849
+ import { jsx as jsx13 } from "react/jsx-runtime";
1019
850
  var PrimusAuthContext = createContext2(void 0);
1020
851
  var PrimusProvider = ({
1021
852
  children,
1022
853
  authority,
854
+ authBasePath = "/api/auth",
855
+ csrfCookieName = "XSRF-TOKEN",
856
+ csrfHeaderName = "X-Primus-CSRF",
857
+ seedCsrfOnLoad = true,
1023
858
  clientId,
1024
859
  onLoginSuccess,
1025
- onLoginError
860
+ onLoginError,
861
+ heartbeatInterval = 3e5
862
+ // 5 minutes
1026
863
  }) => {
1027
864
  void clientId;
1028
- const [isAuthenticated, setIsAuthenticated] = useState14(false);
1029
- const [user, setUser] = useState14(null);
1030
- const [token, setToken] = useState14(null);
1031
- const [isLoading, setIsLoading] = useState14(false);
1032
- useEffect8(() => {
1033
- const storedToken = localStorage.getItem("primus_token");
1034
- const storedUser = localStorage.getItem("primus_user");
1035
- if (storedToken && storedUser) {
1036
- try {
1037
- setToken(storedToken);
1038
- setUser(JSON.parse(storedUser));
1039
- setIsAuthenticated(true);
1040
- } catch {
1041
- localStorage.removeItem("primus_token");
1042
- localStorage.removeItem("primus_user");
865
+ const [isAuthenticated, setIsAuthenticated] = useState13(false);
866
+ const [user, setUser] = useState13(null);
867
+ const [token, setToken] = useState13(null);
868
+ const [isLoading, setIsLoading] = useState13(true);
869
+ const heartbeatRef = useRef(null);
870
+ const trimTrailingSlash = (value) => value.replace(/\/+$/, "");
871
+ const ensureLeadingSlash = (value) => value.startsWith("/") ? value : `/${value}`;
872
+ const joinUrl = (base, path) => `${trimTrailingSlash(base)}${ensureLeadingSlash(path)}`;
873
+ const authBaseUrl = trimTrailingSlash(joinUrl(authority, authBasePath));
874
+ const getCookie = (name) => {
875
+ if (typeof document === "undefined") return null;
876
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
877
+ const matches = document.cookie.match(new RegExp(`(?:^|; )${escaped}=([^;]*)`));
878
+ return matches ? decodeURIComponent(matches[1]) : null;
879
+ };
880
+ const fetchSessionUser = useCallback2(async () => {
881
+ const response = await fetch(`${authBaseUrl}/me`, {
882
+ credentials: "include",
883
+ headers: {
884
+ "Accept": "application/json"
1043
885
  }
886
+ });
887
+ if (!response.ok) return null;
888
+ const data = await response.json().catch(() => null);
889
+ if (!data) return null;
890
+ const resolvedUser = data.user ?? data;
891
+ return resolvedUser ?? null;
892
+ }, [authBaseUrl]);
893
+ const startHeartbeat = useCallback2(() => {
894
+ if (typeof window === "undefined") return;
895
+ if (heartbeatRef.current) clearInterval(heartbeatRef.current);
896
+ heartbeatRef.current = setInterval(() => {
897
+ fetchSessionUser().catch(() => {
898
+ });
899
+ }, heartbeatInterval);
900
+ }, [heartbeatInterval, fetchSessionUser]);
901
+ const stopHeartbeat = useCallback2(() => {
902
+ if (heartbeatRef.current) {
903
+ clearInterval(heartbeatRef.current);
904
+ heartbeatRef.current = null;
1044
905
  }
1045
906
  }, []);
907
+ useEffect8(() => {
908
+ return () => stopHeartbeat();
909
+ }, [stopHeartbeat]);
910
+ const seedCsrf = useCallback2(async () => {
911
+ try {
912
+ await fetch(`${authBaseUrl}/providers`, {
913
+ credentials: "include",
914
+ headers: { "Accept": "application/json" }
915
+ });
916
+ } catch {
917
+ }
918
+ }, [authBaseUrl]);
919
+ useEffect8(() => {
920
+ const checkSession = async () => {
921
+ setIsLoading(true);
922
+ try {
923
+ if (seedCsrfOnLoad) {
924
+ await seedCsrf();
925
+ }
926
+ const userData = await fetchSessionUser();
927
+ if (userData) {
928
+ setUser(userData);
929
+ setIsAuthenticated(true);
930
+ setToken("session-active");
931
+ startHeartbeat();
932
+ } else {
933
+ stopHeartbeat();
934
+ }
935
+ } catch (err) {
936
+ console.debug("No active session found", err);
937
+ setIsAuthenticated(false);
938
+ setUser(null);
939
+ stopHeartbeat();
940
+ } finally {
941
+ setIsLoading(false);
942
+ }
943
+ };
944
+ checkSession();
945
+ }, [fetchSessionUser, seedCsrf, seedCsrfOnLoad, startHeartbeat, stopHeartbeat]);
1046
946
  const login = useCallback2(async (credentials) => {
1047
947
  setIsLoading(true);
1048
948
  try {
1049
- let endpoint;
1050
- let body;
1051
949
  if ("provider" in credentials) {
1052
- endpoint = `${authority}/auth/${credentials.provider}`;
1053
- body = {};
1054
- } else {
1055
- endpoint = `${authority}/auth/local`;
1056
- body = { email: credentials.email, password: credentials.password };
950
+ window.location.href = `${authBaseUrl}/${credentials.provider}`;
951
+ return { success: true };
952
+ }
953
+ const csrfToken = getCookie(csrfCookieName);
954
+ const headers = {
955
+ "Content-Type": "application/json"
956
+ };
957
+ if (csrfToken) {
958
+ headers[csrfHeaderName] = csrfToken;
1057
959
  }
1058
- const response = await fetch(endpoint, {
960
+ const response = await fetch(`${authBaseUrl}/login`, {
1059
961
  method: "POST",
1060
- headers: { "Content-Type": "application/json" },
1061
- body: JSON.stringify(body)
962
+ headers,
963
+ credentials: "include",
964
+ // CRITICAL: Persist HttpOnly Cookie
965
+ body: JSON.stringify({ email: credentials.email, password: credentials.password })
1062
966
  });
1063
967
  if (!response.ok) {
1064
968
  const errorData = await response.json().catch(() => ({}));
1065
- const errorMsg = errorData.message || `Login failed (${response.status})`;
969
+ const errorMsg = errorData.message || errorData.title || `Login failed (${response.status})`;
1066
970
  onLoginError?.(errorMsg);
1067
971
  return { success: false, error: errorMsg };
1068
972
  }
1069
- const data = await response.json();
1070
- const accessToken = data.access_token || data.token;
1071
- const userData = data.user || {
1072
- name: "Authenticated User",
1073
- email: "provider" in credentials ? `${credentials.provider}@primus.local` : credentials.email
1074
- };
1075
- localStorage.setItem("primus_token", accessToken);
1076
- localStorage.setItem("primus_user", JSON.stringify(userData));
1077
- setToken(accessToken);
1078
- setUser(userData);
973
+ const data = await response.json().catch(() => null);
974
+ const userData = data ? data.user || data : null;
975
+ const refreshedUser = userData ?? await fetchSessionUser();
976
+ setToken("session-active");
977
+ if (refreshedUser) {
978
+ setUser(refreshedUser);
979
+ startHeartbeat();
980
+ }
1079
981
  setIsAuthenticated(true);
1080
- onLoginSuccess?.(userData, accessToken);
982
+ if (refreshedUser) {
983
+ onLoginSuccess?.(refreshedUser, "session-active");
984
+ }
1081
985
  return { success: true };
1082
986
  } catch (err) {
1083
987
  const errorMsg = err instanceof Error ? err.message : "Network error";
@@ -1086,15 +990,38 @@ var PrimusProvider = ({
1086
990
  } finally {
1087
991
  setIsLoading(false);
1088
992
  }
1089
- }, [authority, onLoginSuccess, onLoginError]);
993
+ }, [authBaseUrl, csrfCookieName, csrfHeaderName, fetchSessionUser, onLoginError, onLoginSuccess, startHeartbeat]);
1090
994
  const logout = useCallback2(async () => {
1091
- localStorage.removeItem("primus_token");
1092
- localStorage.removeItem("primus_user");
1093
- setToken(null);
1094
- setIsAuthenticated(false);
1095
- setUser(null);
1096
- }, []);
1097
- return /* @__PURE__ */ jsx14(PrimusAuthContext.Provider, { value: { isAuthenticated, user, login, logout, token, isLoading }, children });
995
+ try {
996
+ stopHeartbeat();
997
+ const csrfToken = getCookie(csrfCookieName);
998
+ const headers = {};
999
+ if (csrfToken) {
1000
+ headers[csrfHeaderName] = csrfToken;
1001
+ }
1002
+ await fetch(`${authBaseUrl}/logout`, {
1003
+ method: "POST",
1004
+ credentials: "include",
1005
+ headers
1006
+ });
1007
+ } catch (e) {
1008
+ console.error("Logout failed", e);
1009
+ } finally {
1010
+ setToken(null);
1011
+ setIsAuthenticated(false);
1012
+ setUser(null);
1013
+ }
1014
+ }, [authBaseUrl, csrfCookieName, csrfHeaderName, stopHeartbeat]);
1015
+ return /* @__PURE__ */ jsx13(PrimusAuthContext.Provider, { value: {
1016
+ isAuthenticated,
1017
+ user,
1018
+ login,
1019
+ logout,
1020
+ token,
1021
+ isLoading,
1022
+ csrfCookieName,
1023
+ csrfHeaderName
1024
+ }, children });
1098
1025
  };
1099
1026
  var usePrimusAuth = () => {
1100
1027
  const context = useContext2(PrimusAuthContext);
@@ -1106,18 +1033,300 @@ var usePrimusAuth = () => {
1106
1033
  logout: async () => {
1107
1034
  },
1108
1035
  token: null,
1109
- isLoading: false
1036
+ isLoading: false,
1037
+ csrfCookieName: "XSRF-TOKEN",
1038
+ csrfHeaderName: "X-Primus-CSRF"
1110
1039
  };
1111
1040
  }
1112
1041
  return context;
1113
1042
  };
1114
1043
 
1044
+ // src/components/auth/PrimusLogin.tsx
1045
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1046
+ var styles = {
1047
+ container: {
1048
+ minHeight: "100vh",
1049
+ display: "flex",
1050
+ alignItems: "center",
1051
+ justifyContent: "center",
1052
+ padding: "24px",
1053
+ fontFamily: '"Segoe UI", Arial, sans-serif',
1054
+ transition: "background-color 0.3s, color 0.3s"
1055
+ },
1056
+ card: {
1057
+ width: "100%",
1058
+ maxWidth: "420px",
1059
+ borderRadius: "16px",
1060
+ padding: "24px",
1061
+ boxShadow: "0 20px 40px rgba(15, 23, 42, 0.08)",
1062
+ border: "1px solid #e2e8f0",
1063
+ backgroundColor: "#ffffff"
1064
+ },
1065
+ header: {
1066
+ marginBottom: "24px",
1067
+ textAlign: "center"
1068
+ },
1069
+ logoStr: {
1070
+ width: "48px",
1071
+ height: "48px",
1072
+ borderRadius: "12px",
1073
+ marginBottom: "16px",
1074
+ objectFit: "cover"
1075
+ },
1076
+ title: {
1077
+ margin: "12px 0 4px",
1078
+ fontSize: "22px",
1079
+ fontWeight: "600"
1080
+ },
1081
+ subtitle: {
1082
+ margin: 0,
1083
+ fontSize: "13px",
1084
+ color: "#64748b"
1085
+ },
1086
+ socialGrid: {
1087
+ display: "grid",
1088
+ gap: "10px",
1089
+ marginTop: "16px"
1090
+ },
1091
+ socialBtn: {
1092
+ border: "1px solid #cbd5e1",
1093
+ background: "#ffffff",
1094
+ padding: "10px",
1095
+ borderRadius: "10px",
1096
+ fontSize: "13px",
1097
+ cursor: "pointer",
1098
+ color: "#0f172a",
1099
+ display: "flex",
1100
+ alignItems: "center",
1101
+ justifyContent: "center",
1102
+ gap: "8px",
1103
+ width: "100%",
1104
+ fontWeight: 500,
1105
+ transition: "background-color 0.2s"
1106
+ },
1107
+ divider: {
1108
+ margin: "24px 0",
1109
+ textAlign: "center",
1110
+ fontSize: "12px",
1111
+ color: "#94a3b8",
1112
+ position: "relative"
1113
+ },
1114
+ // Form
1115
+ form: {
1116
+ display: "grid",
1117
+ gap: "16px"
1118
+ },
1119
+ label: {
1120
+ display: "block",
1121
+ fontSize: "12px",
1122
+ color: "#64748b",
1123
+ fontWeight: 400,
1124
+ marginBottom: "6px"
1125
+ },
1126
+ input: {
1127
+ width: "100%",
1128
+ border: "1px solid #cbd5e1",
1129
+ borderRadius: "8px",
1130
+ padding: "10px 12px",
1131
+ background: "#ffffff",
1132
+ color: "#0f172a",
1133
+ fontSize: "14px",
1134
+ outline: "none"
1135
+ },
1136
+ submitBtn: {
1137
+ marginTop: "8px",
1138
+ background: "#8b5cf6",
1139
+ // Purple to match Angular
1140
+ color: "#ffffff",
1141
+ border: "none",
1142
+ borderRadius: "8px",
1143
+ padding: "10px",
1144
+ cursor: "pointer",
1145
+ fontWeight: 500,
1146
+ fontSize: "13px",
1147
+ width: "100%"
1148
+ },
1149
+ error: {
1150
+ marginTop: "12px",
1151
+ color: "#dc2626",
1152
+ fontSize: "12px",
1153
+ textAlign: "center"
1154
+ }
1155
+ };
1156
+ var darkStyles = {
1157
+ container: { backgroundColor: "#0f172a", color: "#f8fafc" },
1158
+ card: { backgroundColor: "#1e293b", borderColor: "#334155", boxShadow: "none" },
1159
+ subtitle: { color: "#94a3b8" },
1160
+ socialBtn: { backgroundColor: "#1e293b", borderColor: "#334155", color: "#f8fafc" },
1161
+ label: { color: "#94a3b8" },
1162
+ input: { backgroundColor: "#0f172a", borderColor: "#334155", color: "#f8fafc" },
1163
+ submitBtn: { backgroundColor: "#8b5cf6" }
1164
+ // Purple to match Angular
1165
+ };
1166
+ var Icons = {
1167
+ google: /* @__PURE__ */ jsxs12("svg", { width: "18", height: "18", viewBox: "0 0 18 18", children: [
1168
+ /* @__PURE__ */ jsx14("path", { d: "M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z", fill: "#4285F4" }),
1169
+ /* @__PURE__ */ jsx14("path", { d: "M9 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.258c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332C2.438 15.983 5.482 18 9 18z", fill: "#34A853" }),
1170
+ /* @__PURE__ */ jsx14("path", { d: "M3.964 10.707c-.18-.54-.282-1.117-.282-1.707 0-.593.102-1.17.282-1.709V4.958H.957C.347 6.173 0 7.548 0 9c0 1.452.348 2.827.957 4.042l3.007-2.335z", fill: "#FBBC05" }),
1171
+ /* @__PURE__ */ jsx14("path", { d: "M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0 5.482 0 2.438 2.017.957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58z", fill: "#EA4335" })
1172
+ ] }),
1173
+ microsoft: /* @__PURE__ */ jsxs12("svg", { width: "18", height: "18", viewBox: "0 0 18 18", children: [
1174
+ /* @__PURE__ */ jsx14("path", { d: "M0 0h8.571v8.571H0V0z", fill: "#F25022" }),
1175
+ /* @__PURE__ */ jsx14("path", { d: "M9.429 0H18v8.571H9.429V0z", fill: "#7FBA00" }),
1176
+ /* @__PURE__ */ jsx14("path", { d: "M0 9.429h8.571V18H0V9.429z", fill: "#00A4EF" }),
1177
+ /* @__PURE__ */ jsx14("path", { d: "M9.429 9.429H18V18H9.429V9.429z", fill: "#FFB900" })
1178
+ ] }),
1179
+ github: /* @__PURE__ */ jsx14("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "currentColor", children: /* @__PURE__ */ jsx14("path", { d: "M9 0C4.029 0 0 4.029 0 9c0 3.977 2.578 7.348 6.155 8.537.45.082.615-.195.615-.433 0-.213-.008-.923-.012-1.674-2.505.544-3.034-1.073-3.034-1.073-.41-1.04-1-1.316-1-1.316-.817-.558.062-.547.062-.547.903.064 1.378.927 1.378.927.803 1.376 2.107.978 2.62.748.082-.582.314-.978.572-1.203-2-.227-4.1-1-4.1-4.448 0-.983.35-1.786.927-2.416-.093-.228-.402-1.144.088-2.383 0 0 .756-.242 2.475.923A8.63 8.63 0 019 4.347c.765.004 1.535.103 2.254.303 1.718-1.165 2.473-.923 2.473-.923.491 1.239.182 2.155.089 2.383.578.63.926 1.433.926 2.416 0 3.457-2.104 4.218-4.109 4.44.323.278.611.827.611 1.667 0 1.203-.011 2.173-.011 2.469 0 .24.163.52.619.432C15.424 16.345 18 12.976 18 9c0-4.971-4.029-9-9-9z" }) }),
1180
+ apple: /* @__PURE__ */ jsx14("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "currentColor", children: /* @__PURE__ */ jsx14("path", { d: "M14.94 13.52c-.36.77-.54 1.12-1.01 1.8-.66.95-1.59 2.13-2.74 2.14-1.02.01-1.29-.66-2.68-.65-1.39.01-1.69.66-2.71.65-1.15-.01-2.01-1.07-2.67-2.02-1.85-2.66-2.04-5.78-.9-7.44.81-1.18 2.09-1.87 3.29-1.87 1.22 0 1.99.67 3 .67.98 0 1.58-.67 2.99-.67 1.07 0 2.2.58 3.01 1.58-2.64 1.45-2.21 5.23.42 6.81zM11.53 3.96c.52-.67.92-1.61.77-2.56-.84.04-1.84.59-2.43 1.29-.52.62-.96 1.58-.79 2.5.94.02 1.91-.53 2.45-1.23z" }) }),
1181
+ auth0: /* @__PURE__ */ jsx14("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "#EB5424", children: /* @__PURE__ */ jsx14("path", { d: "M13.98 0L9 7.83 4.02 0H0l9 15.59L18 0h-4.02zM9 10.41L4.02 18h9.96L9 10.41z" }) }),
1182
+ facebook: /* @__PURE__ */ jsx14("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "#1877F2", children: /* @__PURE__ */ jsx14("path", { d: "M18 9.05C18 4.05 13.97 0 9 0S0 4.05 0 9.05C0 13.58 3.29 17.34 7.59 18v-6.28H5.31V9.05h2.28V7.05c0-2.25 1.34-3.49 3.39-3.49.98 0 2.01.18 2.01.18v2.21h-1.13c-1.11 0-1.46.69-1.46 1.4v1.68h2.49l-.4 2.67h-2.09V18C14.71 17.34 18 13.58 18 9.05z" }) })
1183
+ };
1184
+ function PrimusLogin({
1185
+ onLogin,
1186
+ socialProviders = [],
1187
+ onSocialLogin,
1188
+ authEndpoint = "/api/auth",
1189
+ showEmailLogin = true,
1190
+ title = "Welcome Back",
1191
+ subtitle = "Enter your credentials to continue",
1192
+ logo,
1193
+ theme: themeOverride,
1194
+ variant = "standalone",
1195
+ useAuth = false
1196
+ }) {
1197
+ const themeContext = usePrimusTheme();
1198
+ const auth = usePrimusAuth();
1199
+ const theme = themeOverride || themeContext.theme;
1200
+ const isLight = theme === "light";
1201
+ const isDark = !isLight;
1202
+ const [username, setUsername] = useState14("");
1203
+ const [password, setPassword] = useState14("");
1204
+ const [loading, setLoading] = useState14(false);
1205
+ const [errorMessage, setErrorMessage] = useState14("");
1206
+ const currentStyles = {
1207
+ container: { ...styles.container, ...isDark ? darkStyles.container : {} },
1208
+ card: { ...styles.card, ...isDark ? darkStyles.card : {} },
1209
+ title: { ...styles.title, color: isLight ? "#0f172a" : "#f8fafc" },
1210
+ subtitle: { ...styles.subtitle, ...isDark ? darkStyles.subtitle : {} },
1211
+ input: { ...styles.input, ...isDark ? darkStyles.input : {} },
1212
+ socialBtn: { ...styles.socialBtn, ...isDark ? darkStyles.socialBtn : {} },
1213
+ label: { ...styles.label, ...isDark ? darkStyles.label : {} },
1214
+ submitBtn: { ...styles.submitBtn, ...isDark ? darkStyles.submitBtn : {} }
1215
+ };
1216
+ const handleSubmit = async (e) => {
1217
+ e.preventDefault();
1218
+ if (!username || !password) return;
1219
+ setLoading(true);
1220
+ setErrorMessage("");
1221
+ try {
1222
+ if (useAuth) {
1223
+ const result = await auth.login({ email: username, password });
1224
+ if (!result.success) {
1225
+ setErrorMessage(result.error || "Login failed");
1226
+ return;
1227
+ }
1228
+ }
1229
+ onLogin?.({ username, password });
1230
+ } catch (err) {
1231
+ setErrorMessage("Login failed. Please try again.");
1232
+ } finally {
1233
+ setLoading(false);
1234
+ }
1235
+ };
1236
+ const handleSocialClick = (provider) => {
1237
+ if (onSocialLogin) {
1238
+ onSocialLogin(provider);
1239
+ } else {
1240
+ const base = authEndpoint.replace(/\/+$/, "");
1241
+ window.location.href = `${base}/${provider}`;
1242
+ }
1243
+ };
1244
+ const renderSocialIcon = (p) => {
1245
+ const key = p === "azure" ? "microsoft" : p;
1246
+ return Icons[key] || null;
1247
+ };
1248
+ const content = /* @__PURE__ */ jsxs12("div", { style: currentStyles.card, className: "primus-login-card", children: [
1249
+ /* @__PURE__ */ jsxs12("div", { style: styles.header, className: "primus-login-header", children: [
1250
+ logo && (typeof logo === "string" ? /* @__PURE__ */ jsx14("img", { src: logo, alt: "Logo", style: styles.logoStr }) : /* @__PURE__ */ jsx14("div", { style: { marginBottom: "16px", display: "flex", justifyContent: "center" }, children: logo })),
1251
+ /* @__PURE__ */ jsx14("h2", { style: currentStyles.title, children: title }),
1252
+ /* @__PURE__ */ jsx14("p", { style: currentStyles.subtitle, children: subtitle })
1253
+ ] }),
1254
+ socialProviders.length > 0 && /* @__PURE__ */ jsx14("div", { style: styles.socialGrid, className: "primus-social", children: socialProviders.map((provider) => /* @__PURE__ */ jsxs12(
1255
+ "button",
1256
+ {
1257
+ type: "button",
1258
+ onClick: () => handleSocialClick(provider),
1259
+ style: currentStyles.socialBtn,
1260
+ onMouseOver: (e) => {
1261
+ if (isLight) e.currentTarget.style.backgroundColor = "#f1f5f9";
1262
+ else e.currentTarget.style.backgroundColor = "#334155";
1263
+ },
1264
+ onMouseOut: (e) => {
1265
+ if (isLight) e.currentTarget.style.backgroundColor = "#ffffff";
1266
+ else e.currentTarget.style.backgroundColor = "#1e293b";
1267
+ },
1268
+ children: [
1269
+ renderSocialIcon(provider),
1270
+ "Continue with ",
1271
+ provider === "azure" ? "Microsoft" : provider.charAt(0).toUpperCase() + provider.slice(1)
1272
+ ]
1273
+ },
1274
+ provider
1275
+ )) }),
1276
+ socialProviders.length > 0 && showEmailLogin && /* @__PURE__ */ jsxs12("div", { style: styles.divider, className: "primus-divider", children: [
1277
+ /* @__PURE__ */ jsx14("span", { style: { backgroundColor: isLight ? "#fff" : "#1e293b", padding: "0 8px", position: "relative", zIndex: 1 }, children: "Or continue with email" }),
1278
+ /* @__PURE__ */ jsx14("div", { style: { position: "absolute", top: "50%", left: 0, right: 0, borderTop: isLight ? "1px solid #e2e8f0" : "1px solid #334155", zIndex: 0 } })
1279
+ ] }),
1280
+ showEmailLogin && /* @__PURE__ */ jsxs12("form", { onSubmit: handleSubmit, style: styles.form, className: "primus-form", children: [
1281
+ /* @__PURE__ */ jsxs12("div", { children: [
1282
+ /* @__PURE__ */ jsx14("label", { style: currentStyles.label, children: "Email" }),
1283
+ /* @__PURE__ */ jsx14(
1284
+ "input",
1285
+ {
1286
+ type: "email",
1287
+ value: username,
1288
+ onChange: (e) => setUsername(e.target.value),
1289
+ style: currentStyles.input
1290
+ }
1291
+ )
1292
+ ] }),
1293
+ /* @__PURE__ */ jsxs12("div", { children: [
1294
+ /* @__PURE__ */ jsx14("label", { style: currentStyles.label, children: "Password" }),
1295
+ /* @__PURE__ */ jsx14(
1296
+ "input",
1297
+ {
1298
+ type: "password",
1299
+ value: password,
1300
+ onChange: (e) => setPassword(e.target.value),
1301
+ style: currentStyles.input
1302
+ }
1303
+ )
1304
+ ] }),
1305
+ /* @__PURE__ */ jsx14(
1306
+ "button",
1307
+ {
1308
+ type: "submit",
1309
+ disabled: loading,
1310
+ style: { ...currentStyles.submitBtn, opacity: loading ? 0.7 : 1 },
1311
+ children: loading ? "Signing in..." : "Sign In"
1312
+ }
1313
+ )
1314
+ ] }),
1315
+ errorMessage && /* @__PURE__ */ jsx14("p", { style: styles.error, children: errorMessage })
1316
+ ] });
1317
+ if (variant === "embedded") {
1318
+ return content;
1319
+ }
1320
+ return /* @__PURE__ */ jsx14("div", { style: { ...currentStyles.container, background: isLight ? "#f8fafc" : "#0f172a" }, className: `primus-login ${isDark ? "dark" : ""}`, children: content });
1321
+ }
1322
+ var LoginPage = PrimusLogin;
1323
+
1115
1324
  // src/components/shared/Button.tsx
1116
- import React13 from "react";
1325
+ import React14 from "react";
1117
1326
  import { jsx as jsx15 } from "react/jsx-runtime";
1118
- var Button = React13.forwardRef(
1327
+ var Button = React14.forwardRef(
1119
1328
  ({ style, variant = "primary", size = "md", color = "sapphire", disabled, ...props }, ref) => {
1120
- const [isHovered, setIsHovered] = React13.useState(false);
1329
+ const [isHovered, setIsHovered] = React14.useState(false);
1121
1330
  const colorStyles = {
1122
1331
  sapphire: {
1123
1332
  solid: "#1341a7",
@@ -1256,6 +1465,51 @@ var UserProfile = ({
1256
1465
  ] });
1257
1466
  };
1258
1467
 
1468
+ // src/hooks/usePrimusFetch.ts
1469
+ import { useCallback as useCallback3 } from "react";
1470
+ function usePrimusFetch() {
1471
+ const { logout, csrfCookieName = "XSRF-TOKEN", csrfHeaderName = "X-Primus-CSRF" } = usePrimusAuth();
1472
+ const getCookie = useCallback3((name) => {
1473
+ if (typeof document === "undefined") return null;
1474
+ try {
1475
+ const matches = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1") + "=([^;]*)"));
1476
+ return matches ? decodeURIComponent(matches[1]) : null;
1477
+ } catch {
1478
+ return null;
1479
+ }
1480
+ }, []);
1481
+ const primusFetch = useCallback3(async (input, init) => {
1482
+ const { skipAuth, ...fetchInit } = init || {};
1483
+ const config = {
1484
+ ...fetchInit,
1485
+ headers: new Headers(fetchInit.headers)
1486
+ };
1487
+ if (!skipAuth) {
1488
+ config.credentials = "include";
1489
+ }
1490
+ const method = (config.method || "GET").toUpperCase();
1491
+ if (!["GET", "HEAD", "OPTIONS"].includes(method)) {
1492
+ const csrfToken = getCookie(csrfCookieName);
1493
+ if (csrfToken) {
1494
+ config.headers.set(csrfHeaderName, csrfToken);
1495
+ }
1496
+ }
1497
+ try {
1498
+ const response = await window.fetch(input, config);
1499
+ if (response.status === 401 && !skipAuth) {
1500
+ console.debug("[PrimusFetch] 401 Unauthorized detected. triggering logout.");
1501
+ logout();
1502
+ }
1503
+ return response;
1504
+ } catch (error) {
1505
+ throw error;
1506
+ }
1507
+ }, [getCookie, logout, csrfCookieName, csrfHeaderName]);
1508
+ return {
1509
+ fetch: primusFetch
1510
+ };
1511
+ }
1512
+
1259
1513
  // src/hooks/useNotifications.ts
1260
1514
  import { useState as useState15, useEffect as useEffect9, useMemo } from "react";
1261
1515
  var useNotifications = ({
@@ -1399,7 +1653,7 @@ var PrimusNotificationFeed = ({ useMock, mockData, apiUrl, className }) => {
1399
1653
  };
1400
1654
 
1401
1655
  // src/components/notifications/PrimusNotificationCenter.tsx
1402
- import { useState as useState16, useEffect as useEffect10, useCallback as useCallback3 } from "react";
1656
+ import { useState as useState16, useEffect as useEffect10, useCallback as useCallback4 } from "react";
1403
1657
  import { Bell, Send, X, Check, AlertTriangle, Info, AlertCircle } from "lucide-react";
1404
1658
  import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1405
1659
  var API_URL = "http://localhost:5222";
@@ -1421,7 +1675,7 @@ function PrimusNotificationCenter({
1421
1675
  const [newMessage, setNewMessage] = useState16("");
1422
1676
  const [newType, setNewType] = useState16("info");
1423
1677
  const [sending, setSending] = useState16(false);
1424
- const fetchNotifications = useCallback3(async () => {
1678
+ const fetchNotifications = useCallback4(async () => {
1425
1679
  try {
1426
1680
  const response = await fetch(`${apiUrl}/api/notifications`);
1427
1681
  if (response.ok) {
@@ -1645,7 +1899,7 @@ var NotificationBell = PrimusNotificationCenter;
1645
1899
  var PrimusNotifications = PrimusNotificationCenter;
1646
1900
 
1647
1901
  // src/hooks/useRealtimeNotifications.ts
1648
- import { useState as useState17, useEffect as useEffect11, useCallback as useCallback4 } from "react";
1902
+ import { useState as useState17, useEffect as useEffect11, useCallback as useCallback5 } from "react";
1649
1903
  var useRealtimeNotifications = (options) => {
1650
1904
  const { apiUrl, pollInterval = 3e3, userId } = options;
1651
1905
  const [notifications, setNotifications] = useState17([]);
@@ -1653,7 +1907,7 @@ var useRealtimeNotifications = (options) => {
1653
1907
  const [loading, setLoading] = useState17(true);
1654
1908
  const [error, setError] = useState17(null);
1655
1909
  const baseUrl = `${apiUrl}/api/notifications`;
1656
- const fetchNotifications = useCallback4(async () => {
1910
+ const fetchNotifications = useCallback5(async () => {
1657
1911
  try {
1658
1912
  const url = userId ? `${baseUrl}?userId=${userId}` : baseUrl;
1659
1913
  const response = await fetch(url);
@@ -1669,7 +1923,7 @@ var useRealtimeNotifications = (options) => {
1669
1923
  setLoading(false);
1670
1924
  }
1671
1925
  }, [baseUrl, userId]);
1672
- const sendNotification = useCallback4(async (title, message, type = "info") => {
1926
+ const sendNotification = useCallback5(async (title, message, type = "info") => {
1673
1927
  try {
1674
1928
  const response = await fetch(baseUrl, {
1675
1929
  method: "POST",
@@ -1685,7 +1939,7 @@ var useRealtimeNotifications = (options) => {
1685
1939
  return false;
1686
1940
  }
1687
1941
  }, [baseUrl, userId, fetchNotifications]);
1688
- const markAsRead = useCallback4(async (id) => {
1942
+ const markAsRead = useCallback5(async (id) => {
1689
1943
  try {
1690
1944
  await fetch(`${baseUrl}/${id}/read`, { method: "PUT" });
1691
1945
  setNotifications((prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n));
@@ -1693,13 +1947,13 @@ var useRealtimeNotifications = (options) => {
1693
1947
  } catch {
1694
1948
  }
1695
1949
  }, [baseUrl]);
1696
- const markAllAsRead = useCallback4(async () => {
1950
+ const markAllAsRead = useCallback5(async () => {
1697
1951
  const unread = notifications.filter((n) => !n.read);
1698
1952
  await Promise.all(unread.map((n) => fetch(`${baseUrl}/${n.id}/read`, { method: "PUT" })));
1699
1953
  setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
1700
1954
  setUnreadCount(0);
1701
1955
  }, [notifications, baseUrl]);
1702
- const deleteNotification = useCallback4(async (id) => {
1956
+ const deleteNotification = useCallback5(async (id) => {
1703
1957
  try {
1704
1958
  await fetch(`${baseUrl}/${id}`, { method: "DELETE" });
1705
1959
  setNotifications((prev) => prev.filter((n) => n.id !== id));
@@ -1728,7 +1982,7 @@ var useRealtimeNotifications = (options) => {
1728
1982
  import { useState as useState18 } from "react";
1729
1983
 
1730
1984
  // src/components/shared/Input.tsx
1731
- import React14 from "react";
1985
+ import React15 from "react";
1732
1986
  import { clsx as clsx2 } from "clsx";
1733
1987
  import { XMarkIcon } from "@heroicons/react/20/solid";
1734
1988
  import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -1742,20 +1996,48 @@ var iconSizeClasses = {
1742
1996
  md: "w-5 h-5 [&>*]:w-full [&>*]:h-full",
1743
1997
  lg: "w-6 h-6 [&>*]:w-full [&>*]:h-full"
1744
1998
  };
1745
- var Input = React14.forwardRef(
1746
- ({ className, style, label, error, disabled, startIcon, endIcon, onClear, value, onChange, size = "md", loading = false, ...props }, ref) => {
1999
+ var Input = React15.forwardRef(
2000
+ ({
2001
+ className,
2002
+ style,
2003
+ label,
2004
+ error,
2005
+ disabled,
2006
+ startIcon,
2007
+ endIcon,
2008
+ onClear,
2009
+ value,
2010
+ onChange,
2011
+ onValueChange,
2012
+ size = "md",
2013
+ loading = false,
2014
+ autoSelect = false,
2015
+ onFocus,
2016
+ ...props
2017
+ }, ref) => {
2018
+ const handleFocus = (e) => {
2019
+ if (autoSelect) {
2020
+ e.target.select();
2021
+ }
2022
+ onFocus?.(e);
2023
+ };
2024
+ const handleChange = (e) => {
2025
+ onChange?.(e);
2026
+ onValueChange?.(e.target.value);
2027
+ };
1747
2028
  const hasValue = value !== void 0 && value !== "" && value !== null;
2029
+ const isDisabled = disabled || loading;
1748
2030
  return /* @__PURE__ */ jsxs16("div", { className: clsx2("w-full", className), style, children: [
1749
2031
  label && /* @__PURE__ */ jsx19("label", { className: clsx2(
1750
2032
  "block font-medium mb-1.5",
1751
2033
  size === "sm" ? "text-xs" : "text-sm",
1752
- disabled ? "text-gray-400 opacity-70" : "text-gray-700"
2034
+ isDisabled ? "text-gray-400 opacity-70" : "text-gray-700"
1753
2035
  ), children: label }),
1754
2036
  /* @__PURE__ */ jsxs16("div", { className: clsx2(
1755
2037
  "relative flex items-center w-full rounded-lg transition-all duration-200 ease-in-out bg-white overflow-hidden",
1756
2038
  "border",
1757
2039
  error ? "border-red-500 hover:border-red-600 focus-within:ring-2 focus-within:ring-red-500/20 focus-within:border-red-500" : "border-gray-200 hover:border-gray-300 focus-within:ring-2 focus-within:ring-primus-500/20 focus-within:border-primus-500",
1758
- disabled && "bg-gray-50 opacity-60 cursor-not-allowed"
2040
+ isDisabled && "bg-gray-50 opacity-60 cursor-not-allowed"
1759
2041
  ), children: [
1760
2042
  startIcon && /* @__PURE__ */ jsx19("div", { className: clsx2(
1761
2043
  "flex-shrink-0 pl-3 pr-2 text-gray-400 select-none pointer-events-none flex items-center justify-center",
@@ -1765,9 +2047,10 @@ var Input = React14.forwardRef(
1765
2047
  "input",
1766
2048
  {
1767
2049
  ref,
1768
- disabled,
2050
+ disabled: isDisabled,
1769
2051
  value,
1770
- onChange,
2052
+ onChange: handleChange,
2053
+ onFocus: handleFocus,
1771
2054
  className: clsx2(
1772
2055
  "flex-1 w-full border-none bg-transparent p-0 placeholder:text-gray-400 focus:ring-0 outline-none",
1773
2056
  sizeClasses[size],
@@ -1778,7 +2061,7 @@ var Input = React14.forwardRef(
1778
2061
  ...props
1779
2062
  }
1780
2063
  ),
1781
- onClear && hasValue && !disabled && !loading && /* @__PURE__ */ jsx19("div", { className: "flex-shrink-0 pr-2 flex items-center justify-center", children: /* @__PURE__ */ jsx19(
2064
+ onClear && hasValue && !isDisabled && /* @__PURE__ */ jsx19("div", { className: "flex-shrink-0 pr-2 flex items-center justify-center", children: /* @__PURE__ */ jsx19(
1782
2065
  "button",
1783
2066
  {
1784
2067
  type: "button",
@@ -1786,7 +2069,8 @@ var Input = React14.forwardRef(
1786
2069
  e.stopPropagation();
1787
2070
  onClear();
1788
2071
  },
1789
- className: "p-1 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors",
2072
+ className: "p-1 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-primus-500",
2073
+ tabIndex: 0,
1790
2074
  children: /* @__PURE__ */ jsx19(XMarkIcon, { className: "h-4 w-4" })
1791
2075
  }
1792
2076
  ) }),
@@ -2394,7 +2678,7 @@ var PrimusSidebar = ({
2394
2678
  };
2395
2679
 
2396
2680
  // src/components/layout/PrimusHeader.tsx
2397
- import React18 from "react";
2681
+ import React19 from "react";
2398
2682
  import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
2399
2683
  var PrimusHeader = ({
2400
2684
  title,
@@ -2405,7 +2689,7 @@ var PrimusHeader = ({
2405
2689
  }) => {
2406
2690
  return /* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between w-full", children: [
2407
2691
  /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-4", children: [
2408
- breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx30("nav", { className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ jsxs27(React18.Fragment, { children: [
2692
+ breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx30("nav", { className: "flex items-center gap-2 text-sm", children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ jsxs27(React19.Fragment, { children: [
2409
2693
  index > 0 && /* @__PURE__ */ jsx30("span", { className: "text-gray-500", children: "/" }),
2410
2694
  /* @__PURE__ */ jsx30("span", { className: index === breadcrumbs.length - 1 ? "text-white" : "text-gray-400 hover:text-white cursor-pointer", children: crumb.label })
2411
2695
  ] }, index)) }),
@@ -2431,9 +2715,30 @@ var PrimusHeader = ({
2431
2715
  ] });
2432
2716
  };
2433
2717
 
2718
+ // src/components/layout/PrimusSection.tsx
2719
+ import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
2720
+ var PrimusSection = ({
2721
+ title,
2722
+ subtitle,
2723
+ children,
2724
+ className = "",
2725
+ actions
2726
+ }) => {
2727
+ return /* @__PURE__ */ jsxs28("section", { className: `py-6 ${className}`, children: [
2728
+ /* @__PURE__ */ jsxs28("div", { className: "flex items-end justify-between mb-6 border-b border-gray-200 dark:border-gray-800 pb-4", children: [
2729
+ /* @__PURE__ */ jsxs28("div", { children: [
2730
+ /* @__PURE__ */ jsx31("h2", { className: "text-2xl font-bold tracking-tight text-gray-900 dark:text-white", children: title }),
2731
+ subtitle && /* @__PURE__ */ jsx31("p", { className: "mt-1 text-base text-gray-500 dark:text-gray-400", children: subtitle })
2732
+ ] }),
2733
+ actions && /* @__PURE__ */ jsx31("div", { className: "flex items-center gap-2", children: actions })
2734
+ ] }),
2735
+ /* @__PURE__ */ jsx31("div", { children })
2736
+ ] });
2737
+ };
2738
+
2434
2739
  // src/components/crud/PrimusDataTable.tsx
2435
2740
  import { useState as useState21, useMemo as useMemo2 } from "react";
2436
- import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
2741
+ import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
2437
2742
  function PrimusDataTable({
2438
2743
  data,
2439
2744
  columns,
@@ -2512,10 +2817,10 @@ function PrimusDataTable({
2512
2817
  onSelectionChange?.(scopeKeys);
2513
2818
  }
2514
2819
  };
2515
- return /* @__PURE__ */ jsxs28("div", { className: "flex flex-col space-y-4", children: [
2516
- searchable && /* @__PURE__ */ jsx31("div", { className: "flex items-center justify-between px-1", children: /* @__PURE__ */ jsxs28("div", { className: "relative group", children: [
2517
- /* @__PURE__ */ jsx31("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx31("svg", { className: "h-4 w-4 text-gray-500 group-focus-within:text-purple-400 transition-colors", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx31("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }) }),
2518
- /* @__PURE__ */ jsx31(
2820
+ return /* @__PURE__ */ jsxs29("div", { className: "flex flex-col space-y-4", children: [
2821
+ searchable && /* @__PURE__ */ jsx32("div", { className: "flex items-center justify-between px-1", children: /* @__PURE__ */ jsxs29("div", { className: "relative group", children: [
2822
+ /* @__PURE__ */ jsx32("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsx32("svg", { className: "h-4 w-4 text-gray-500 group-focus-within:text-purple-400 transition-colors", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx32("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }) }),
2823
+ /* @__PURE__ */ jsx32(
2519
2824
  "input",
2520
2825
  {
2521
2826
  type: "text",
@@ -2531,9 +2836,9 @@ function PrimusDataTable({
2531
2836
  }
2532
2837
  )
2533
2838
  ] }) }),
2534
- /* @__PURE__ */ jsx31("div", { className: `overflow-hidden rounded-xl border border-white/5 bg-slate-900/40 backdrop-blur-md shadow-xl ring-1 ring-white/5 ${loading ? "opacity-80" : ""}`, children: /* @__PURE__ */ jsx31("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs28("table", { className: "w-full text-left border-collapse", children: [
2535
- /* @__PURE__ */ jsx31("thead", { className: "bg-white/5 border-b border-white/5 backdrop-blur-md sticky top-0 z-20", children: /* @__PURE__ */ jsxs28("tr", { children: [
2536
- selectable && /* @__PURE__ */ jsx31("th", { className: "w-12 px-6 py-4", children: /* @__PURE__ */ jsx31(
2839
+ /* @__PURE__ */ jsx32("div", { className: `overflow-hidden rounded-xl border border-white/5 bg-slate-900/40 backdrop-blur-md shadow-xl ring-1 ring-white/5 ${loading ? "opacity-80" : ""}`, children: /* @__PURE__ */ jsx32("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs29("table", { className: "w-full text-left border-collapse", children: [
2840
+ /* @__PURE__ */ jsx32("thead", { className: "bg-white/5 border-b border-white/5 backdrop-blur-md sticky top-0 z-20", children: /* @__PURE__ */ jsxs29("tr", { children: [
2841
+ selectable && /* @__PURE__ */ jsx32("th", { className: "w-12 px-6 py-4", children: /* @__PURE__ */ jsx32(
2537
2842
  "input",
2538
2843
  {
2539
2844
  type: "checkbox",
@@ -2542,25 +2847,25 @@ function PrimusDataTable({
2542
2847
  className: "rounded border-gray-600 bg-gray-800 text-purple-600 focus:ring-offset-gray-900 focus:ring-purple-500 transition-colors cursor-pointer"
2543
2848
  }
2544
2849
  ) }),
2545
- columns.map((col) => /* @__PURE__ */ jsx31(
2850
+ columns.map((col) => /* @__PURE__ */ jsx32(
2546
2851
  "th",
2547
2852
  {
2548
2853
  className: `px-6 py-4 text-xs font-semibold text-gray-400 uppercase tracking-wider ${col.sortable ? "cursor-pointer hover:text-white group" : ""}`,
2549
2854
  style: { width: col.width },
2550
2855
  onClick: () => col.sortable && handleSort(String(col.key)),
2551
- children: /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-2", children: [
2856
+ children: /* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-2", children: [
2552
2857
  col.header,
2553
- col.sortable && /* @__PURE__ */ jsx31("span", { className: `transition-opacity duration-200 ${sortKey === col.key ? "opacity-100 text-purple-400" : "opacity-0 group-hover:opacity-50"}`, children: sortDir === "asc" ? "\u2191" : "\u2193" })
2858
+ col.sortable && /* @__PURE__ */ jsx32("span", { className: `transition-opacity duration-200 ${sortKey === col.key ? "opacity-100 text-purple-400" : "opacity-0 group-hover:opacity-50"}`, children: sortDir === "asc" ? "\u2191" : "\u2193" })
2554
2859
  ] })
2555
2860
  },
2556
2861
  String(col.key)
2557
2862
  )),
2558
- actions && /* @__PURE__ */ jsx31("th", { className: "w-24 px-6 py-4 text-right text-xs font-semibold text-gray-400 uppercase tracking-wider" })
2863
+ actions && /* @__PURE__ */ jsx32("th", { className: "w-24 px-6 py-4 text-right text-xs font-semibold text-gray-400 uppercase tracking-wider" })
2559
2864
  ] }) }),
2560
- /* @__PURE__ */ jsx31("tbody", { className: "divide-y divide-white/5", children: loading ? /* @__PURE__ */ jsx31("tr", { children: /* @__PURE__ */ jsx31("td", { colSpan: columns.length + (selectable ? 1 : 0) + (actions ? 1 : 0), className: "px-6 py-24 text-center text-gray-500", children: /* @__PURE__ */ jsxs28("div", { className: "flex flex-col items-center justify-center gap-3", children: [
2561
- /* @__PURE__ */ jsx31("div", { className: "w-6 h-6 border-2 border-purple-500/50 border-t-purple-500 rounded-full animate-spin" }),
2562
- /* @__PURE__ */ jsx31("span", { className: "text-sm font-medium", children: "Loading data..." })
2563
- ] }) }) }) : filteredData.length === 0 ? /* @__PURE__ */ jsx31("tr", { children: /* @__PURE__ */ jsx31("td", { colSpan: columns.length + (selectable ? 1 : 0) + (actions ? 1 : 0), className: "px-6 py-24 text-center text-gray-500", children: /* @__PURE__ */ jsx31("p", { className: "text-sm", children: emptyMessage }) }) }) : pageData.map((row) => /* @__PURE__ */ jsxs28(
2865
+ /* @__PURE__ */ jsx32("tbody", { className: "divide-y divide-white/5", children: loading ? /* @__PURE__ */ jsx32("tr", { children: /* @__PURE__ */ jsx32("td", { colSpan: columns.length + (selectable ? 1 : 0) + (actions ? 1 : 0), className: "px-6 py-24 text-center text-gray-500", children: /* @__PURE__ */ jsxs29("div", { className: "flex flex-col items-center justify-center gap-3", children: [
2866
+ /* @__PURE__ */ jsx32("div", { className: "w-6 h-6 border-2 border-purple-500/50 border-t-purple-500 rounded-full animate-spin" }),
2867
+ /* @__PURE__ */ jsx32("span", { className: "text-sm font-medium", children: "Loading data..." })
2868
+ ] }) }) }) : filteredData.length === 0 ? /* @__PURE__ */ jsx32("tr", { children: /* @__PURE__ */ jsx32("td", { colSpan: columns.length + (selectable ? 1 : 0) + (actions ? 1 : 0), className: "px-6 py-24 text-center text-gray-500", children: /* @__PURE__ */ jsx32("p", { className: "text-sm", children: emptyMessage }) }) }) : pageData.map((row) => /* @__PURE__ */ jsxs29(
2564
2869
  "tr",
2565
2870
  {
2566
2871
  onClick: () => onRowClick?.(row),
@@ -2570,7 +2875,7 @@ function PrimusDataTable({
2570
2875
  ${selectedKeys.includes(row[rowKey]) ? "bg-purple-500/10 hover:bg-purple-500/20" : ""}
2571
2876
  `,
2572
2877
  children: [
2573
- selectable && /* @__PURE__ */ jsx31("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx31(
2878
+ selectable && /* @__PURE__ */ jsx32("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx32(
2574
2879
  "input",
2575
2880
  {
2576
2881
  type: "checkbox",
@@ -2579,15 +2884,15 @@ function PrimusDataTable({
2579
2884
  className: "rounded border-gray-600 bg-gray-800 text-purple-600 focus:ring-offset-gray-900 focus:ring-purple-500 cursor-pointer"
2580
2885
  }
2581
2886
  ) }),
2582
- columns.map((col) => /* @__PURE__ */ jsx31("td", { className: "px-6 py-4 text-sm text-gray-300 group-hover:text-white transition-colors", children: col.render ? col.render(row[col.key], row) : String(row[col.key] ?? "") }, String(col.key))),
2583
- actions && /* @__PURE__ */ jsx31("td", { className: "px-6 py-4 text-right", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx31("div", { className: "opacity-0 group-hover:opacity-100 transition-opacity transform translate-x-2 group-hover:translate-x-0", children: actions(row) }) })
2887
+ columns.map((col) => /* @__PURE__ */ jsx32("td", { className: "px-6 py-4 text-sm text-gray-300 group-hover:text-white transition-colors", children: col.render ? col.render(row[col.key], row) : String(row[col.key] ?? "") }, String(col.key))),
2888
+ actions && /* @__PURE__ */ jsx32("td", { className: "px-6 py-4 text-right", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx32("div", { className: "opacity-0 group-hover:opacity-100 transition-opacity transform translate-x-2 group-hover:translate-x-0", children: actions(row) }) })
2584
2889
  ]
2585
2890
  },
2586
2891
  String(row[rowKey])
2587
2892
  )) })
2588
2893
  ] }) }) }),
2589
- paginated && totalPages > 1 && /* @__PURE__ */ jsxs28("div", { className: "flex items-center justify-between text-sm text-gray-400 px-2", children: [
2590
- /* @__PURE__ */ jsx31(
2894
+ paginated && totalPages > 1 && /* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-between text-sm text-gray-400 px-2", children: [
2895
+ /* @__PURE__ */ jsx32(
2591
2896
  "button",
2592
2897
  {
2593
2898
  type: "button",
@@ -2597,13 +2902,13 @@ function PrimusDataTable({
2597
2902
  children: "Previous"
2598
2903
  }
2599
2904
  ),
2600
- /* @__PURE__ */ jsxs28("span", { children: [
2905
+ /* @__PURE__ */ jsxs29("span", { children: [
2601
2906
  "Page ",
2602
2907
  currentPageIndex + 1,
2603
2908
  " of ",
2604
2909
  totalPages
2605
2910
  ] }),
2606
- /* @__PURE__ */ jsx31(
2911
+ /* @__PURE__ */ jsx32(
2607
2912
  "button",
2608
2913
  {
2609
2914
  type: "button",
@@ -2618,7 +2923,7 @@ function PrimusDataTable({
2618
2923
  }
2619
2924
 
2620
2925
  // src/components/crud/PrimusModal.tsx
2621
- import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
2926
+ import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2622
2927
  var PrimusModal = ({
2623
2928
  open,
2624
2929
  onClose,
@@ -2634,34 +2939,34 @@ var PrimusModal = ({
2634
2939
  lg: "max-w-lg",
2635
2940
  xl: "max-w-xl"
2636
2941
  };
2637
- return /* @__PURE__ */ jsxs29("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2638
- /* @__PURE__ */ jsx32(
2942
+ return /* @__PURE__ */ jsxs30("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2943
+ /* @__PURE__ */ jsx33(
2639
2944
  "div",
2640
2945
  {
2641
2946
  className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
2642
2947
  onClick: onClose
2643
2948
  }
2644
2949
  ),
2645
- /* @__PURE__ */ jsxs29("div", { className: `relative w-full ${sizeClasses2[size]} mx-4 bg-gray-800 rounded-xl border border-gray-700 shadow-2xl`, children: [
2646
- title && /* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-700", children: [
2647
- /* @__PURE__ */ jsx32("h2", { className: "text-lg font-semibold text-white", children: title }),
2648
- /* @__PURE__ */ jsx32(
2950
+ /* @__PURE__ */ jsxs30("div", { className: `relative w-full ${sizeClasses2[size]} mx-4 bg-gray-800 rounded-xl border border-gray-700 shadow-2xl`, children: [
2951
+ title && /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-700", children: [
2952
+ /* @__PURE__ */ jsx33("h2", { className: "text-lg font-semibold text-white", children: title }),
2953
+ /* @__PURE__ */ jsx33(
2649
2954
  "button",
2650
2955
  {
2651
2956
  onClick: onClose,
2652
2957
  className: "text-gray-400 hover:text-white transition-colors",
2653
- children: /* @__PURE__ */ jsx32("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx32("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
2958
+ children: /* @__PURE__ */ jsx33("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx33("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
2654
2959
  }
2655
2960
  )
2656
2961
  ] }),
2657
- /* @__PURE__ */ jsx32("div", { className: "p-6", children }),
2658
- footer && /* @__PURE__ */ jsx32("div", { className: "flex justify-end gap-3 px-6 py-4 border-t border-gray-700 bg-gray-800/50", children: footer })
2962
+ /* @__PURE__ */ jsx33("div", { className: "p-6", children }),
2963
+ footer && /* @__PURE__ */ jsx33("div", { className: "flex justify-end gap-3 px-6 py-4 border-t border-gray-700 bg-gray-800/50", children: footer })
2659
2964
  ] })
2660
2965
  ] });
2661
2966
  };
2662
2967
 
2663
2968
  // src/components/dashboard/PrimusDashboard.tsx
2664
- import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2969
+ import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
2665
2970
  var PrimusStatCard = ({
2666
2971
  title,
2667
2972
  value,
@@ -2697,35 +3002,35 @@ var PrimusStatCard = ({
2697
3002
  const linePath = points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
2698
3003
  const areaPath = `${linePath} L 100 100 L 0 100 Z`;
2699
3004
  const gradientId = `gradient-${title.replace(/\s/g, "")}`;
2700
- return /* @__PURE__ */ jsxs30("svg", { className: "w-full h-12 opacity-60 absolute bottom-0 left-0", viewBox: "0 0 100 100", preserveAspectRatio: "none", "data-trend": trend.join(","), children: [
2701
- /* @__PURE__ */ jsx33("defs", { children: /* @__PURE__ */ jsxs30("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
2702
- /* @__PURE__ */ jsx33("stop", { offset: "0%", stopColor: "currentColor", stopOpacity: "0.25" }),
2703
- /* @__PURE__ */ jsx33("stop", { offset: "100%", stopColor: "currentColor", stopOpacity: "0" })
3005
+ return /* @__PURE__ */ jsxs31("svg", { className: "w-full h-12 opacity-60 absolute bottom-0 left-0", viewBox: "0 0 100 100", preserveAspectRatio: "none", "data-trend": trend.join(","), children: [
3006
+ /* @__PURE__ */ jsx34("defs", { children: /* @__PURE__ */ jsxs31("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
3007
+ /* @__PURE__ */ jsx34("stop", { offset: "0%", stopColor: "currentColor", stopOpacity: "0.25" }),
3008
+ /* @__PURE__ */ jsx34("stop", { offset: "100%", stopColor: "currentColor", stopOpacity: "0" })
2704
3009
  ] }) }),
2705
- /* @__PURE__ */ jsx33("path", { d: areaPath, fill: `url(#${gradientId})`, stroke: "none" }),
2706
- /* @__PURE__ */ jsx33("path", { d: linePath, fill: "none", stroke: "currentColor", strokeWidth: "1.8", opacity: "0.6" })
3010
+ /* @__PURE__ */ jsx34("path", { d: areaPath, fill: `url(#${gradientId})`, stroke: "none" }),
3011
+ /* @__PURE__ */ jsx34("path", { d: linePath, fill: "none", stroke: "currentColor", strokeWidth: "1.8", opacity: "0.6" })
2707
3012
  ] });
2708
3013
  };
2709
- return /* @__PURE__ */ jsxs30("div", { className: "relative overflow-hidden bg-slate-900/40 backdrop-blur-md rounded-2xl border border-white/5 hover:border-white/10 transition-all duration-300 group", children: [
2710
- /* @__PURE__ */ jsx33("div", { className: "absolute inset-0 bg-gradient-to-br from-white/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" }),
2711
- /* @__PURE__ */ jsxs30("div", { className: "p-6 relative z-10", children: [
2712
- /* @__PURE__ */ jsxs30("div", { className: "flex items-start justify-between mb-4", children: [
2713
- /* @__PURE__ */ jsx33("div", { className: "p-2.5 rounded-lg bg-white/5 text-gray-300 ring-1 ring-white/10 group-hover:bg-purple-500/20 group-hover:text-purple-300 transition-colors", children: icon || /* @__PURE__ */ jsx33("div", { className: "w-5 h-5 bg-current opacity-20" }) }),
2714
- change && /* @__PURE__ */ jsxs30("span", { className: `px-2 py-0.5 text-xs font-medium rounded-full flex items-center gap-1 ${changeColors[change.type]}`, children: [
3014
+ return /* @__PURE__ */ jsxs31("div", { className: "relative overflow-hidden bg-slate-900/40 backdrop-blur-md rounded-2xl border border-white/5 hover:border-white/10 transition-all duration-300 group", children: [
3015
+ /* @__PURE__ */ jsx34("div", { className: "absolute inset-0 bg-gradient-to-br from-white/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" }),
3016
+ /* @__PURE__ */ jsxs31("div", { className: "p-6 relative z-10", children: [
3017
+ /* @__PURE__ */ jsxs31("div", { className: "flex items-start justify-between mb-4", children: [
3018
+ /* @__PURE__ */ jsx34("div", { className: "p-2.5 rounded-lg bg-white/5 text-gray-300 ring-1 ring-white/10 group-hover:bg-purple-500/20 group-hover:text-purple-300 transition-colors", children: icon || /* @__PURE__ */ jsx34("div", { className: "w-5 h-5 bg-current opacity-20" }) }),
3019
+ change && /* @__PURE__ */ jsxs31("span", { className: `px-2 py-0.5 text-xs font-medium rounded-full flex items-center gap-1 ${changeColors[change.type]}`, children: [
2715
3020
  changeIcons[change.type],
2716
3021
  " ",
2717
3022
  Math.abs(change.value),
2718
3023
  "%"
2719
3024
  ] })
2720
3025
  ] }),
2721
- /* @__PURE__ */ jsxs30("div", { children: [
2722
- /* @__PURE__ */ jsx33("h3", { className: "text-sm font-medium text-gray-400 tracking-wide", children: title }),
2723
- /* @__PURE__ */ jsx33("div", { className: "mt-1 flex items-baseline gap-2", children: /* @__PURE__ */ jsx33("span", { className: "text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-white to-gray-400", children: value }) }),
2724
- description && /* @__PURE__ */ jsx33("p", { className: "text-xs text-gray-500 mt-2 font-medium", children: description })
3026
+ /* @__PURE__ */ jsxs31("div", { children: [
3027
+ /* @__PURE__ */ jsx34("h3", { className: "text-sm font-medium text-gray-400 tracking-wide", children: title }),
3028
+ /* @__PURE__ */ jsx34("div", { className: "mt-1 flex items-baseline gap-2", children: /* @__PURE__ */ jsx34("span", { className: "text-3xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-white to-gray-400", children: value }) }),
3029
+ description && /* @__PURE__ */ jsx34("p", { className: "text-xs text-gray-500 mt-2 font-medium", children: description })
2725
3030
  ] })
2726
3031
  ] }),
2727
3032
  renderSparkline(),
2728
- /* @__PURE__ */ jsx33("div", { className: `absolute -bottom-2 -right-4 w-32 h-32 blur-2xl opacity-20 rounded-full transition-colors duration-500 ${change?.type === "increase" ? "bg-emerald-500" : change?.type === "decrease" ? "bg-rose-500" : "bg-blue-500"}` })
3033
+ /* @__PURE__ */ jsx34("div", { className: `absolute -bottom-2 -right-4 w-32 h-32 blur-2xl opacity-20 rounded-full transition-colors duration-500 ${change?.type === "increase" ? "bg-emerald-500" : change?.type === "decrease" ? "bg-rose-500" : "bg-blue-500"}` })
2729
3034
  ] });
2730
3035
  };
2731
3036
  var PrimusDashboard = ({
@@ -2734,13 +3039,13 @@ var PrimusDashboard = ({
2734
3039
  subtitle,
2735
3040
  actions
2736
3041
  }) => {
2737
- return /* @__PURE__ */ jsxs30("div", { className: "space-y-8 animate-enter", children: [
2738
- (title || actions) && /* @__PURE__ */ jsxs30("div", { className: "flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-white/5 pb-6", children: [
2739
- /* @__PURE__ */ jsxs30("div", { children: [
2740
- title && /* @__PURE__ */ jsx33("h1", { className: "text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-white via-gray-200 to-gray-400 tracking-tight", children: title }),
2741
- subtitle && /* @__PURE__ */ jsx33("p", { className: "text-gray-400 mt-2 text-lg font-light leading-relaxed", children: subtitle })
3042
+ return /* @__PURE__ */ jsxs31("div", { className: "space-y-8 animate-enter", children: [
3043
+ (title || actions) && /* @__PURE__ */ jsxs31("div", { className: "flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-white/5 pb-6", children: [
3044
+ /* @__PURE__ */ jsxs31("div", { children: [
3045
+ title && /* @__PURE__ */ jsx34("h1", { className: "text-3xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-white via-gray-200 to-gray-400 tracking-tight", children: title }),
3046
+ subtitle && /* @__PURE__ */ jsx34("p", { className: "text-gray-400 mt-2 text-lg font-light leading-relaxed", children: subtitle })
2742
3047
  ] }),
2743
- actions && /* @__PURE__ */ jsx33("div", { className: "flex items-center gap-3", children: actions })
3048
+ actions && /* @__PURE__ */ jsx34("div", { className: "flex items-center gap-3", children: actions })
2744
3049
  ] }),
2745
3050
  children
2746
3051
  ] });
@@ -2755,25 +3060,119 @@ var DashboardGrid = ({
2755
3060
  3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
2756
3061
  4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4"
2757
3062
  };
2758
- return /* @__PURE__ */ jsx33("div", { className: `grid gap-6 ${colClasses[columns]}`, children });
3063
+ return /* @__PURE__ */ jsx34("div", { className: `grid gap-6 ${colClasses[columns]}`, children });
2759
3064
  };
2760
3065
 
2761
- // src/components/dashboard/PrimusActivityFeed.tsx
2762
- import { useMemo as useMemo3 } from "react";
2763
- import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
2764
- var statusClasses = {
2765
- success: "bg-emerald-500/10 text-emerald-300 border-emerald-500/30",
2766
- warning: "bg-amber-500/10 text-amber-300 border-amber-500/30",
2767
- error: "bg-rose-500/10 text-rose-300 border-rose-500/30",
2768
- info: "bg-blue-500/10 text-blue-300 border-blue-500/30"
2769
- };
2770
- var PrimusActivityFeed = ({
2771
- items,
2772
- maxItems = 10,
2773
- showTimestamps = true,
2774
- groupByDate = false,
2775
- loading = false
2776
- }) => {
3066
+ // src/components/shared/Card.tsx
3067
+ import React21 from "react";
3068
+ import { jsx as jsx35 } from "react/jsx-runtime";
3069
+ var Card = React21.forwardRef(
3070
+ ({ style, variant = "default", padding = "md", children, ...props }, ref) => {
3071
+ const [isHovered, setIsHovered] = React21.useState(false);
3072
+ const paddingStyles = {
3073
+ none: "0",
3074
+ sm: "0.75rem",
3075
+ md: "1.5rem",
3076
+ lg: "2rem"
3077
+ };
3078
+ const variantStyles = {
3079
+ default: {
3080
+ normal: {
3081
+ backgroundColor: "#ffffff",
3082
+ border: "1px solid #e5e7eb",
3083
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)"
3084
+ },
3085
+ hover: {
3086
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
3087
+ }
3088
+ },
3089
+ outlined: {
3090
+ normal: {
3091
+ backgroundColor: "#ffffff",
3092
+ border: "2px solid #e5e7eb",
3093
+ boxShadow: "none"
3094
+ },
3095
+ hover: {
3096
+ borderColor: "#d1d5db"
3097
+ }
3098
+ },
3099
+ elevated: {
3100
+ normal: {
3101
+ backgroundColor: "#ffffff",
3102
+ border: "none",
3103
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
3104
+ },
3105
+ hover: {
3106
+ boxShadow: "0 10px 15px rgba(0, 0, 0, 0.15)",
3107
+ transform: "translateY(-2px)"
3108
+ }
3109
+ }
3110
+ };
3111
+ const baseStyles = {
3112
+ borderRadius: "0.5rem",
3113
+ padding: paddingStyles[padding],
3114
+ transition: "all 0.2s ease"
3115
+ };
3116
+ const currentVariant = variantStyles[variant];
3117
+ const combinedStyles = {
3118
+ ...baseStyles,
3119
+ ...currentVariant.normal,
3120
+ ...isHovered ? currentVariant.hover : {},
3121
+ ...style
3122
+ };
3123
+ return /* @__PURE__ */ jsx35(
3124
+ "div",
3125
+ {
3126
+ ref,
3127
+ style: combinedStyles,
3128
+ onMouseEnter: () => setIsHovered(true),
3129
+ onMouseLeave: () => setIsHovered(false),
3130
+ ...props,
3131
+ children
3132
+ }
3133
+ );
3134
+ }
3135
+ );
3136
+ Card.displayName = "Card";
3137
+
3138
+ // src/components/dashboard/PrimusSummaryCard.tsx
3139
+ import { jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
3140
+ var PrimusSummaryCard = ({
3141
+ title,
3142
+ subtitle,
3143
+ actionLabel,
3144
+ onAction,
3145
+ children,
3146
+ className
3147
+ }) => {
3148
+ return /* @__PURE__ */ jsx36(Card, { className, children: /* @__PURE__ */ jsxs32("div", { className: "p-6", children: [
3149
+ /* @__PURE__ */ jsxs32("div", { className: "flex items-center justify-between mb-4", children: [
3150
+ /* @__PURE__ */ jsxs32("div", { children: [
3151
+ /* @__PURE__ */ jsx36("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: title }),
3152
+ subtitle && /* @__PURE__ */ jsx36("p", { className: "text-sm text-gray-500 dark:text-gray-400 mt-1", children: subtitle })
3153
+ ] }),
3154
+ actionLabel && onAction && /* @__PURE__ */ jsx36(Button, { variant: "outline", size: "sm", onClick: onAction, children: actionLabel })
3155
+ ] }),
3156
+ /* @__PURE__ */ jsx36("div", { className: "mt-4", children })
3157
+ ] }) });
3158
+ };
3159
+
3160
+ // src/components/dashboard/PrimusActivityFeed.tsx
3161
+ import { useMemo as useMemo3 } from "react";
3162
+ import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
3163
+ var statusClasses = {
3164
+ success: "bg-emerald-500/10 text-emerald-300 border-emerald-500/30",
3165
+ warning: "bg-amber-500/10 text-amber-300 border-amber-500/30",
3166
+ error: "bg-rose-500/10 text-rose-300 border-rose-500/30",
3167
+ info: "bg-blue-500/10 text-blue-300 border-blue-500/30"
3168
+ };
3169
+ var PrimusActivityFeed = ({
3170
+ items,
3171
+ maxItems = 10,
3172
+ showTimestamps = true,
3173
+ groupByDate = false,
3174
+ loading = false
3175
+ }) => {
2777
3176
  const visibleItems = useMemo3(() => items.slice(0, maxItems), [items, maxItems]);
2778
3177
  const groups = useMemo3(() => {
2779
3178
  if (!groupByDate) {
@@ -2789,18 +3188,18 @@ var PrimusActivityFeed = ({
2789
3188
  return Array.from(map.entries()).map(([label, groupItems]) => ({ label, items: groupItems }));
2790
3189
  }, [groupByDate, visibleItems]);
2791
3190
  if (loading) {
2792
- return /* @__PURE__ */ jsx34("div", { className: "rounded-xl border border-white/10 bg-slate-900/40 p-6 text-sm text-gray-400", children: "Loading activity..." });
3191
+ return /* @__PURE__ */ jsx37("div", { className: "rounded-xl border border-white/10 bg-slate-900/40 p-6 text-sm text-gray-400", children: "Loading activity..." });
2793
3192
  }
2794
- return /* @__PURE__ */ jsx34("div", { className: "rounded-xl border border-white/10 bg-slate-900/40 p-6 space-y-6", children: groups.map((group, index) => /* @__PURE__ */ jsxs31("div", { children: [
2795
- group.label && /* @__PURE__ */ jsx34("div", { className: "text-xs uppercase tracking-wide text-gray-500 mb-3", children: group.label }),
2796
- /* @__PURE__ */ jsx34("div", { className: "space-y-4", children: group.items.map((item, itemIndex) => /* @__PURE__ */ jsxs31("div", { className: "flex items-start gap-4", children: [
2797
- /* @__PURE__ */ jsx34("div", { className: `mt-1 h-2.5 w-2.5 rounded-full border ${statusClasses[item.status ?? "info"]}` }),
2798
- /* @__PURE__ */ jsxs31("div", { className: "flex-1", children: [
2799
- /* @__PURE__ */ jsxs31("div", { className: "flex items-center justify-between gap-4", children: [
2800
- /* @__PURE__ */ jsx34("div", { className: "text-sm font-medium text-gray-100", children: item.title }),
2801
- showTimestamps && /* @__PURE__ */ jsx34("div", { className: "text-xs text-gray-500", children: formatTime(item.timestamp) })
3193
+ return /* @__PURE__ */ jsx37("div", { className: "rounded-xl border border-white/10 bg-slate-900/40 p-6 space-y-6", children: groups.map((group, index) => /* @__PURE__ */ jsxs33("div", { children: [
3194
+ group.label && /* @__PURE__ */ jsx37("div", { className: "text-xs uppercase tracking-wide text-gray-500 mb-3", children: group.label }),
3195
+ /* @__PURE__ */ jsx37("div", { className: "space-y-4", children: group.items.map((item, itemIndex) => /* @__PURE__ */ jsxs33("div", { className: "flex items-start gap-4", children: [
3196
+ /* @__PURE__ */ jsx37("div", { className: `mt-1 h-2.5 w-2.5 rounded-full border ${statusClasses[item.status ?? "info"]}` }),
3197
+ /* @__PURE__ */ jsxs33("div", { className: "flex-1", children: [
3198
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between gap-4", children: [
3199
+ /* @__PURE__ */ jsx37("div", { className: "text-sm font-medium text-gray-100", children: item.title }),
3200
+ showTimestamps && /* @__PURE__ */ jsx37("div", { className: "text-xs text-gray-500", children: formatTime(item.timestamp) })
2802
3201
  ] }),
2803
- item.description && /* @__PURE__ */ jsx34("div", { className: "text-xs text-gray-400 mt-1", children: item.description })
3202
+ item.description && /* @__PURE__ */ jsx37("div", { className: "text-xs text-gray-400 mt-1", children: item.description })
2804
3203
  ] })
2805
3204
  ] }, item.id ?? `${itemIndex}-${item.title}`)) })
2806
3205
  ] }, `${group.label}-${index}`)) });
@@ -2827,12 +3226,12 @@ var formatTime = (value) => {
2827
3226
  };
2828
3227
 
2829
3228
  // src/components/charts/PrimusChartBase.tsx
2830
- import { useEffect as useEffect14, useMemo as useMemo4, useRef } from "react";
3229
+ import { useEffect as useEffect14, useMemo as useMemo4, useRef as useRef2 } from "react";
2831
3230
  import {
2832
3231
  Chart,
2833
3232
  registerables
2834
3233
  } from "chart.js";
2835
- import { jsx as jsx35 } from "react/jsx-runtime";
3234
+ import { jsx as jsx38 } from "react/jsx-runtime";
2836
3235
  var registered = false;
2837
3236
  var ensureRegistered = () => {
2838
3237
  if (!registered) {
@@ -2855,8 +3254,8 @@ var PrimusChartBase = ({
2855
3254
  className,
2856
3255
  datasetTransform
2857
3256
  }) => {
2858
- const canvasRef = useRef(null);
2859
- const chartRef = useRef(null);
3257
+ const canvasRef = useRef2(null);
3258
+ const chartRef = useRef2(null);
2860
3259
  const builtData = useMemo4(() => {
2861
3260
  if (data) {
2862
3261
  return data;
@@ -2923,13 +3322,13 @@ var PrimusChartBase = ({
2923
3322
  chartRef.current = null;
2924
3323
  };
2925
3324
  }, [type, builtData, builtOptions]);
2926
- return /* @__PURE__ */ jsx35("div", { className, style: { height, width }, children: /* @__PURE__ */ jsx35("canvas", { ref: canvasRef, "aria-label": ariaLabel, role: "img" }) });
3325
+ return /* @__PURE__ */ jsx38("div", { className, style: { height, width }, children: /* @__PURE__ */ jsx38("canvas", { ref: canvasRef, "aria-label": ariaLabel, role: "img" }) });
2927
3326
  };
2928
3327
 
2929
3328
  // src/components/charts/PrimusLineChart.tsx
2930
- import { jsx as jsx36 } from "react/jsx-runtime";
3329
+ import { jsx as jsx39 } from "react/jsx-runtime";
2931
3330
  var PrimusLineChart = (props) => {
2932
- return /* @__PURE__ */ jsx36(
3331
+ return /* @__PURE__ */ jsx39(
2933
3332
  PrimusChartBase,
2934
3333
  {
2935
3334
  ...props,
@@ -2947,9 +3346,9 @@ var PrimusLineChart = (props) => {
2947
3346
  };
2948
3347
 
2949
3348
  // src/components/charts/PrimusAreaChart.tsx
2950
- import { jsx as jsx37 } from "react/jsx-runtime";
3349
+ import { jsx as jsx40 } from "react/jsx-runtime";
2951
3350
  var PrimusAreaChart = (props) => {
2952
- return /* @__PURE__ */ jsx37(
3351
+ return /* @__PURE__ */ jsx40(
2953
3352
  PrimusChartBase,
2954
3353
  {
2955
3354
  ...props,
@@ -2967,7 +3366,7 @@ var PrimusAreaChart = (props) => {
2967
3366
  };
2968
3367
 
2969
3368
  // src/components/charts/PrimusBarChart.tsx
2970
- import { jsx as jsx38 } from "react/jsx-runtime";
3369
+ import { jsx as jsx41 } from "react/jsx-runtime";
2971
3370
  var PrimusBarChart = ({ stacked = false, options, ...props }) => {
2972
3371
  const mergedOptions = {
2973
3372
  ...options,
@@ -2977,7 +3376,7 @@ var PrimusBarChart = ({ stacked = false, options, ...props }) => {
2977
3376
  ...options?.scales ?? {}
2978
3377
  }
2979
3378
  };
2980
- return /* @__PURE__ */ jsx38(
3379
+ return /* @__PURE__ */ jsx41(
2981
3380
  PrimusChartBase,
2982
3381
  {
2983
3382
  ...props,
@@ -2993,13 +3392,13 @@ var PrimusBarChart = ({ stacked = false, options, ...props }) => {
2993
3392
  };
2994
3393
 
2995
3394
  // src/components/charts/PrimusPieChart.tsx
2996
- import { jsx as jsx39 } from "react/jsx-runtime";
3395
+ import { jsx as jsx42 } from "react/jsx-runtime";
2997
3396
  var PrimusPieChart = ({ donut = false, cutout = "55%", options, ...props }) => {
2998
3397
  const mergedOptions = {
2999
3398
  ...options,
3000
3399
  cutout: donut ? cutout : void 0
3001
3400
  };
3002
- return /* @__PURE__ */ jsx39(
3401
+ return /* @__PURE__ */ jsx42(
3003
3402
  PrimusChartBase,
3004
3403
  {
3005
3404
  ...props,
@@ -3016,7 +3415,7 @@ var PrimusPieChart = ({ donut = false, cutout = "55%", options, ...props }) => {
3016
3415
 
3017
3416
  // src/components/charts/PrimusSparkline.tsx
3018
3417
  import { useMemo as useMemo5 } from "react";
3019
- import { jsx as jsx40, jsxs as jsxs32 } from "react/jsx-runtime";
3418
+ import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
3020
3419
  var PrimusSparkline = ({
3021
3420
  series = [],
3022
3421
  data,
@@ -3049,7 +3448,7 @@ var PrimusSparkline = ({
3049
3448
  if (!values.length) {
3050
3449
  return null;
3051
3450
  }
3052
- return /* @__PURE__ */ jsxs32(
3451
+ return /* @__PURE__ */ jsxs34(
3053
3452
  "svg",
3054
3453
  {
3055
3454
  className,
@@ -3060,17 +3459,17 @@ var PrimusSparkline = ({
3060
3459
  "aria-label": ariaLabel,
3061
3460
  role: "img",
3062
3461
  children: [
3063
- type === "area" && /* @__PURE__ */ jsx40("path", { d: areaPath, fill: color, opacity: 0.2, stroke: "none" }),
3064
- /* @__PURE__ */ jsx40("path", { d: linePath, fill: "none", stroke: color, strokeWidth })
3462
+ type === "area" && /* @__PURE__ */ jsx43("path", { d: areaPath, fill: color, opacity: 0.2, stroke: "none" }),
3463
+ /* @__PURE__ */ jsx43("path", { d: linePath, fill: "none", stroke: color, strokeWidth })
3065
3464
  ]
3066
3465
  }
3067
3466
  );
3068
3467
  };
3069
3468
 
3070
3469
  // src/components/shared/Checkbox.tsx
3071
- import React22 from "react";
3072
- import { jsx as jsx41, jsxs as jsxs33 } from "react/jsx-runtime";
3073
- var Checkbox = React22.forwardRef(
3470
+ import React24 from "react";
3471
+ import { jsx as jsx44, jsxs as jsxs35 } from "react/jsx-runtime";
3472
+ var Checkbox = React24.forwardRef(
3074
3473
  ({ style, label, error, disabled, className, ...props }, ref) => {
3075
3474
  const containerStyles = {
3076
3475
  display: "flex",
@@ -3107,9 +3506,9 @@ var Checkbox = React22.forwardRef(
3107
3506
  marginTop: "0.25rem",
3108
3507
  marginLeft: "1.75rem"
3109
3508
  };
3110
- return /* @__PURE__ */ jsxs33("div", { children: [
3111
- /* @__PURE__ */ jsxs33("div", { style: containerStyles, children: [
3112
- /* @__PURE__ */ jsx41("div", { style: checkboxWrapperStyles, children: /* @__PURE__ */ jsx41(
3509
+ return /* @__PURE__ */ jsxs35("div", { children: [
3510
+ /* @__PURE__ */ jsxs35("div", { style: containerStyles, children: [
3511
+ /* @__PURE__ */ jsx44("div", { style: checkboxWrapperStyles, children: /* @__PURE__ */ jsx44(
3113
3512
  "input",
3114
3513
  {
3115
3514
  ref,
@@ -3122,21 +3521,21 @@ var Checkbox = React22.forwardRef(
3122
3521
  ...props
3123
3522
  }
3124
3523
  ) }),
3125
- label && /* @__PURE__ */ jsx41("label", { style: labelStyles, onClick: (e) => {
3524
+ label && /* @__PURE__ */ jsx44("label", { style: labelStyles, onClick: (e) => {
3126
3525
  if (!disabled) {
3127
3526
  const input = e.currentTarget.previousElementSibling?.querySelector("input");
3128
3527
  input?.click();
3129
3528
  }
3130
3529
  }, children: label })
3131
3530
  ] }),
3132
- error && /* @__PURE__ */ jsx41("p", { style: errorTextStyles, children: error })
3531
+ error && /* @__PURE__ */ jsx44("p", { style: errorTextStyles, children: error })
3133
3532
  ] });
3134
3533
  }
3135
3534
  );
3136
3535
  Checkbox.displayName = "Checkbox";
3137
3536
 
3138
3537
  // src/components/shared/RadioGroup.tsx
3139
- import { jsx as jsx42, jsxs as jsxs34 } from "react/jsx-runtime";
3538
+ import { jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
3140
3539
  var RadioGroup = ({
3141
3540
  name,
3142
3541
  options,
@@ -3176,9 +3575,9 @@ var RadioGroup = ({
3176
3575
  color: "#ef4444",
3177
3576
  marginTop: "0.5rem"
3178
3577
  };
3179
- return /* @__PURE__ */ jsxs34("div", { children: [
3180
- /* @__PURE__ */ jsx42("div", { style: containerStyles, children: options.map((option) => /* @__PURE__ */ jsxs34("div", { style: optionStyles, children: [
3181
- /* @__PURE__ */ jsx42(
3578
+ return /* @__PURE__ */ jsxs36("div", { children: [
3579
+ /* @__PURE__ */ jsx45("div", { style: containerStyles, children: options.map((option) => /* @__PURE__ */ jsxs36("div", { style: optionStyles, children: [
3580
+ /* @__PURE__ */ jsx45(
3182
3581
  "input",
3183
3582
  {
3184
3583
  type: "radio",
@@ -3190,7 +3589,7 @@ var RadioGroup = ({
3190
3589
  style: radioStyles
3191
3590
  }
3192
3591
  ),
3193
- /* @__PURE__ */ jsx42(
3592
+ /* @__PURE__ */ jsx45(
3194
3593
  "label",
3195
3594
  {
3196
3595
  style: {
@@ -3206,17 +3605,17 @@ var RadioGroup = ({
3206
3605
  }
3207
3606
  )
3208
3607
  ] }, option.value)) }),
3209
- error && /* @__PURE__ */ jsx42("p", { style: errorTextStyles, children: error })
3608
+ error && /* @__PURE__ */ jsx45("p", { style: errorTextStyles, children: error })
3210
3609
  ] });
3211
3610
  };
3212
3611
  RadioGroup.displayName = "RadioGroup";
3213
3612
 
3214
3613
  // src/components/shared/Select.tsx
3215
- import React23, { useState as useState22 } from "react";
3614
+ import React25, { useState as useState22 } from "react";
3216
3615
  import { Combobox, Transition as Transition2 } from "@headlessui/react";
3217
3616
  import { CheckIcon as CheckIcon2, ChevronUpDownIcon, XMarkIcon as XMarkIcon3 } from "@heroicons/react/20/solid";
3218
3617
  import { clsx as clsx7 } from "clsx";
3219
- import { Fragment as Fragment5, jsx as jsx43, jsxs as jsxs35 } from "react/jsx-runtime";
3618
+ import { Fragment as Fragment5, jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
3220
3619
  var Select = ({
3221
3620
  label,
3222
3621
  error,
@@ -3238,7 +3637,7 @@ var Select = ({
3238
3637
  onChange?.(value.filter((v) => v !== valToRemove));
3239
3638
  }
3240
3639
  };
3241
- return /* @__PURE__ */ jsx43("div", { className: clsx7("w-full", className), children: /* @__PURE__ */ jsx43(
3640
+ return /* @__PURE__ */ jsx46("div", { className: clsx7("w-full", className), children: /* @__PURE__ */ jsx46(
3242
3641
  Combobox,
3243
3642
  {
3244
3643
  value,
@@ -3247,21 +3646,21 @@ var Select = ({
3247
3646
  },
3248
3647
  multiple,
3249
3648
  disabled,
3250
- children: ({}) => /* @__PURE__ */ jsxs35("div", { className: "relative", children: [
3251
- label && /* @__PURE__ */ jsx43(Combobox.Label, { className: "block text-sm font-medium text-gray-700 mb-1", children: label }),
3252
- /* @__PURE__ */ jsxs35("div", { className: clsx7(
3649
+ children: ({}) => /* @__PURE__ */ jsxs37("div", { className: "relative", children: [
3650
+ label && /* @__PURE__ */ jsx46(Combobox.Label, { className: "block text-sm font-medium text-gray-700 mb-1", children: label }),
3651
+ /* @__PURE__ */ jsxs37("div", { className: clsx7(
3253
3652
  "relative w-full cursor-default overflow-hidden rounded-lg bg-white text-left focus-within:ring-2 focus-within:ring-primus-500",
3254
3653
  "border transition-all duration-200 ease-in-out",
3255
3654
  error ? "border-red-500 focus-within:ring-red-500" : "border-gray-300",
3256
3655
  disabled && "opacity-50 cursor-not-allowed bg-gray-50"
3257
3656
  ), children: [
3258
- /* @__PURE__ */ jsxs35("div", { className: clsx7(
3657
+ /* @__PURE__ */ jsxs37("div", { className: clsx7(
3259
3658
  "flex flex-wrap items-center gap-1.5 w-full py-1.5 pl-3 pr-10 text-sm",
3260
3659
  "min-h-[2.5rem]"
3261
3660
  ), children: [
3262
- multiple && Array.isArray(value) && value.map((val) => /* @__PURE__ */ jsxs35("span", { className: "inline-flex items-center gap-1 rounded bg-primus-50 px-2 py-0.5 text-xs font-medium text-primus-700 ring-1 ring-inset ring-primus-700/10 max-w-[150px]", children: [
3263
- /* @__PURE__ */ jsx43("span", { className: "truncate", children: getLabel(val) }),
3264
- /* @__PURE__ */ jsxs35(
3661
+ multiple && Array.isArray(value) && value.map((val) => /* @__PURE__ */ jsxs37("span", { className: "inline-flex items-center gap-1 rounded bg-primus-50 px-2 py-0.5 text-xs font-medium text-primus-700 ring-1 ring-inset ring-primus-700/10 max-w-[150px]", children: [
3662
+ /* @__PURE__ */ jsx46("span", { className: "truncate", children: getLabel(val) }),
3663
+ /* @__PURE__ */ jsxs37(
3265
3664
  "button",
3266
3665
  {
3267
3666
  type: "button",
@@ -3273,13 +3672,13 @@ var Select = ({
3273
3672
  },
3274
3673
  onMouseDown: (e) => e.preventDefault(),
3275
3674
  children: [
3276
- /* @__PURE__ */ jsx43("span", { className: "sr-only", children: "Remove" }),
3277
- /* @__PURE__ */ jsx43(XMarkIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
3675
+ /* @__PURE__ */ jsx46("span", { className: "sr-only", children: "Remove" }),
3676
+ /* @__PURE__ */ jsx46(XMarkIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
3278
3677
  ]
3279
3678
  }
3280
3679
  )
3281
3680
  ] }, val)),
3282
- /* @__PURE__ */ jsx43(
3681
+ /* @__PURE__ */ jsx46(
3283
3682
  Combobox.Input,
3284
3683
  {
3285
3684
  className: "border-none p-0 text-gray-900 focus:ring-0 outline-none placeholder:text-gray-400 bg-transparent min-w-[50px] flex-1 text-sm leading-5 py-0.5",
@@ -3289,7 +3688,7 @@ var Select = ({
3289
3688
  }
3290
3689
  )
3291
3690
  ] }),
3292
- /* @__PURE__ */ jsx43(Combobox.Button, { className: "absolute inset-y-0 right-0 flex items-center pr-2", children: /* @__PURE__ */ jsx43(
3691
+ /* @__PURE__ */ jsx46(Combobox.Button, { className: "absolute inset-y-0 right-0 flex items-center pr-2", children: /* @__PURE__ */ jsx46(
3293
3692
  ChevronUpDownIcon,
3294
3693
  {
3295
3694
  className: "h-5 w-5 text-gray-400",
@@ -3297,15 +3696,15 @@ var Select = ({
3297
3696
  }
3298
3697
  ) })
3299
3698
  ] }),
3300
- /* @__PURE__ */ jsx43(
3699
+ /* @__PURE__ */ jsx46(
3301
3700
  Transition2,
3302
3701
  {
3303
- as: React23.Fragment,
3702
+ as: React25.Fragment,
3304
3703
  leave: "transition ease-in duration-100",
3305
3704
  leaveFrom: "opacity-100",
3306
3705
  leaveTo: "opacity-0",
3307
3706
  afterLeave: () => setQuery(""),
3308
- children: /* @__PURE__ */ jsx43(Combobox.Options, { className: "absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm", children: filteredOptions.length === 0 && query !== "" ? /* @__PURE__ */ jsx43("div", { className: "relative cursor-default select-none py-2 px-4 text-gray-700", children: "Nothing found." }) : filteredOptions.map((option) => /* @__PURE__ */ jsx43(
3707
+ children: /* @__PURE__ */ jsx46(Combobox.Options, { className: "absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm", children: filteredOptions.length === 0 && query !== "" ? /* @__PURE__ */ jsx46("div", { className: "relative cursor-default select-none py-2 px-4 text-gray-700", children: "Nothing found." }) : filteredOptions.map((option) => /* @__PURE__ */ jsx46(
3309
3708
  Combobox.Option,
3310
3709
  {
3311
3710
  className: ({ active }) => clsx7(
@@ -3314,16 +3713,16 @@ var Select = ({
3314
3713
  ),
3315
3714
  value: option.value,
3316
3715
  disabled: option.disabled,
3317
- children: ({ selected, active }) => /* @__PURE__ */ jsxs35(Fragment5, { children: [
3318
- /* @__PURE__ */ jsx43("span", { className: clsx7("block truncate", selected ? "font-medium" : "font-normal"), children: option.label }),
3319
- selected ? /* @__PURE__ */ jsx43(
3716
+ children: ({ selected, active }) => /* @__PURE__ */ jsxs37(Fragment5, { children: [
3717
+ /* @__PURE__ */ jsx46("span", { className: clsx7("block truncate", selected ? "font-medium" : "font-normal"), children: option.label }),
3718
+ selected ? /* @__PURE__ */ jsx46(
3320
3719
  "span",
3321
3720
  {
3322
3721
  className: clsx7(
3323
3722
  "absolute inset-y-0 left-0 flex items-center pl-3",
3324
3723
  active ? "text-white" : "text-primus-600"
3325
3724
  ),
3326
- children: /* @__PURE__ */ jsx43(CheckIcon2, { className: "h-5 w-5", "aria-hidden": "true" })
3725
+ children: /* @__PURE__ */ jsx46(CheckIcon2, { className: "h-5 w-5", "aria-hidden": "true" })
3327
3726
  }
3328
3727
  ) : null
3329
3728
  ] })
@@ -3332,15 +3731,15 @@ var Select = ({
3332
3731
  )) })
3333
3732
  }
3334
3733
  ),
3335
- error && /* @__PURE__ */ jsx43("p", { className: "mt-1 text-sm text-red-500", children: error })
3734
+ error && /* @__PURE__ */ jsx46("p", { className: "mt-1 text-sm text-red-500", children: error })
3336
3735
  ] })
3337
3736
  }
3338
3737
  ) });
3339
3738
  };
3340
3739
 
3341
3740
  // src/components/shared/Toggle.tsx
3342
- import React24 from "react";
3343
- import { jsx as jsx44, jsxs as jsxs36 } from "react/jsx-runtime";
3741
+ import React26 from "react";
3742
+ import { jsx as jsx47, jsxs as jsxs38 } from "react/jsx-runtime";
3344
3743
  var Toggle = ({
3345
3744
  checked = false,
3346
3745
  onChange,
@@ -3348,7 +3747,7 @@ var Toggle = ({
3348
3747
  label,
3349
3748
  size = "md"
3350
3749
  }) => {
3351
- const [isHovered, setIsHovered] = React24.useState(false);
3750
+ const [isHovered, setIsHovered] = React26.useState(false);
3352
3751
  const sizes = {
3353
3752
  sm: { width: "2.25rem", height: "1.25rem", thumbSize: "0.875rem" },
3354
3753
  md: { width: "2.75rem", height: "1.5rem", thumbSize: "1.125rem" },
@@ -3395,8 +3794,8 @@ var Toggle = ({
3395
3794
  onChange?.(!checked);
3396
3795
  }
3397
3796
  };
3398
- return /* @__PURE__ */ jsxs36("div", { style: containerStyles, children: [
3399
- /* @__PURE__ */ jsx44(
3797
+ return /* @__PURE__ */ jsxs38("div", { style: containerStyles, children: [
3798
+ /* @__PURE__ */ jsx47(
3400
3799
  "div",
3401
3800
  {
3402
3801
  style: switchStyles,
@@ -3412,20 +3811,23 @@ var Toggle = ({
3412
3811
  handleClick();
3413
3812
  }
3414
3813
  },
3415
- children: /* @__PURE__ */ jsx44("div", { style: thumbStyles })
3814
+ children: /* @__PURE__ */ jsx47("div", { style: thumbStyles })
3416
3815
  }
3417
3816
  ),
3418
- label && /* @__PURE__ */ jsx44("label", { style: labelStyles, onClick: handleClick, children: label })
3817
+ label && /* @__PURE__ */ jsx47("label", { style: labelStyles, onClick: handleClick, children: label })
3419
3818
  ] });
3420
3819
  };
3421
3820
  Toggle.displayName = "Toggle";
3422
3821
 
3423
3822
  // src/components/shared/Textarea.tsx
3424
- import React25 from "react";
3425
- import { jsx as jsx45, jsxs as jsxs37 } from "react/jsx-runtime";
3426
- var Textarea = React25.forwardRef(
3427
- ({ style, label, error, disabled, resize = "vertical", ...props }, ref) => {
3428
- const [isFocused, setIsFocused] = React25.useState(false);
3823
+ import React27 from "react";
3824
+ import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
3825
+ var Textarea = React27.forwardRef(
3826
+ ({ style, label, error, disabled, resize = "vertical", onChange, onValueChange, className, ...props }, ref) => {
3827
+ const handleChange = (e) => {
3828
+ onChange?.(e);
3829
+ onValueChange?.(e.target.value);
3830
+ };
3429
3831
  const containerStyles = {
3430
3832
  width: "100%"
3431
3833
  };
@@ -3433,11 +3835,11 @@ var Textarea = React25.forwardRef(
3433
3835
  fontSize: "0.875rem",
3434
3836
  lineHeight: "1.25rem",
3435
3837
  fontWeight: "500",
3436
- marginBottom: "0.5rem",
3838
+ marginBottom: "0.375rem",
3437
3839
  display: "block",
3438
3840
  color: "#374151",
3439
- cursor: disabled ? "not-allowed" : "default",
3440
- opacity: disabled ? 0.7 : 1
3841
+ opacity: disabled ? 0.7 : 1,
3842
+ cursor: disabled ? "not-allowed" : "default"
3441
3843
  };
3442
3844
  const textareaStyles = {
3443
3845
  display: "flex",
@@ -3450,12 +3852,11 @@ var Textarea = React25.forwardRef(
3450
3852
  fontSize: "0.875rem",
3451
3853
  lineHeight: "1.5rem",
3452
3854
  outline: "none",
3453
- transition: "all 0.2s ease",
3454
- cursor: disabled ? "not-allowed" : "text",
3855
+ transition: "border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out",
3455
3856
  opacity: disabled ? 0.5 : 1,
3857
+ cursor: disabled ? "not-allowed" : "text",
3456
3858
  resize,
3457
- fontFamily: "inherit",
3458
- boxShadow: isFocused ? error ? "0 0 0 2px rgba(239, 68, 68, 0.2)" : "0 0 0 2px rgba(3, 7, 18, 0.1)" : "none"
3859
+ fontFamily: "inherit"
3459
3860
  };
3460
3861
  const errorTextStyles = {
3461
3862
  fontSize: "0.875rem",
@@ -3463,9 +3864,9 @@ var Textarea = React25.forwardRef(
3463
3864
  color: "#ef4444",
3464
3865
  marginTop: "0.25rem"
3465
3866
  };
3466
- return /* @__PURE__ */ jsxs37("div", { style: containerStyles, children: [
3467
- label && /* @__PURE__ */ jsx45("label", { style: labelStyles, children: label }),
3468
- /* @__PURE__ */ jsx45(
3867
+ return /* @__PURE__ */ jsxs39("div", { style: containerStyles, className, children: [
3868
+ label && /* @__PURE__ */ jsx48("label", { style: labelStyles, children: label }),
3869
+ /* @__PURE__ */ jsx48(
3469
3870
  "textarea",
3470
3871
  {
3471
3872
  ref,
@@ -3473,94 +3874,28 @@ var Textarea = React25.forwardRef(
3473
3874
  ...textareaStyles,
3474
3875
  ...style
3475
3876
  },
3476
- onFocus: () => setIsFocused(true),
3477
- onBlur: () => setIsFocused(false),
3478
3877
  disabled,
3878
+ onChange: handleChange,
3879
+ className: `primus-textarea ${error ? "error" : ""}`,
3479
3880
  ...props
3480
3881
  }
3481
3882
  ),
3482
- error && /* @__PURE__ */ jsx45("p", { style: errorTextStyles, children: error })
3883
+ /* @__PURE__ */ jsx48("style", { children: `
3884
+ .primus-textarea:focus {
3885
+ border-color: ${error ? "#ef4444" : "#6366f1"};
3886
+ box-shadow: 0 0 0 1px ${error ? "#ef4444" : "#6366f1"};
3887
+ }
3888
+ ` }),
3889
+ error && /* @__PURE__ */ jsx48("p", { style: errorTextStyles, children: error })
3483
3890
  ] });
3484
3891
  }
3485
3892
  );
3486
3893
  Textarea.displayName = "Textarea";
3487
3894
 
3488
- // src/components/shared/Card.tsx
3489
- import React26 from "react";
3490
- import { jsx as jsx46 } from "react/jsx-runtime";
3491
- var Card = React26.forwardRef(
3492
- ({ style, variant = "default", padding = "md", children, ...props }, ref) => {
3493
- const [isHovered, setIsHovered] = React26.useState(false);
3494
- const paddingStyles = {
3495
- none: "0",
3496
- sm: "0.75rem",
3497
- md: "1.5rem",
3498
- lg: "2rem"
3499
- };
3500
- const variantStyles = {
3501
- default: {
3502
- normal: {
3503
- backgroundColor: "#ffffff",
3504
- border: "1px solid #e5e7eb",
3505
- boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)"
3506
- },
3507
- hover: {
3508
- boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
3509
- }
3510
- },
3511
- outlined: {
3512
- normal: {
3513
- backgroundColor: "#ffffff",
3514
- border: "2px solid #e5e7eb",
3515
- boxShadow: "none"
3516
- },
3517
- hover: {
3518
- borderColor: "#d1d5db"
3519
- }
3520
- },
3521
- elevated: {
3522
- normal: {
3523
- backgroundColor: "#ffffff",
3524
- border: "none",
3525
- boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
3526
- },
3527
- hover: {
3528
- boxShadow: "0 10px 15px rgba(0, 0, 0, 0.15)",
3529
- transform: "translateY(-2px)"
3530
- }
3531
- }
3532
- };
3533
- const baseStyles = {
3534
- borderRadius: "0.5rem",
3535
- padding: paddingStyles[padding],
3536
- transition: "all 0.2s ease"
3537
- };
3538
- const currentVariant = variantStyles[variant];
3539
- const combinedStyles = {
3540
- ...baseStyles,
3541
- ...currentVariant.normal,
3542
- ...isHovered ? currentVariant.hover : {},
3543
- ...style
3544
- };
3545
- return /* @__PURE__ */ jsx46(
3546
- "div",
3547
- {
3548
- ref,
3549
- style: combinedStyles,
3550
- onMouseEnter: () => setIsHovered(true),
3551
- onMouseLeave: () => setIsHovered(false),
3552
- ...props,
3553
- children
3554
- }
3555
- );
3556
- }
3557
- );
3558
- Card.displayName = "Card";
3559
-
3560
3895
  // src/components/shared/Badge.tsx
3561
- import React27 from "react";
3562
- import { jsx as jsx47 } from "react/jsx-runtime";
3563
- var Badge = React27.forwardRef(
3896
+ import React28 from "react";
3897
+ import { jsx as jsx49 } from "react/jsx-runtime";
3898
+ var Badge = React28.forwardRef(
3564
3899
  ({ style, variant = "default", size = "md", children, ...props }, ref) => {
3565
3900
  const variantStyles = {
3566
3901
  default: {
@@ -3614,14 +3949,14 @@ var Badge = React27.forwardRef(
3614
3949
  ...sizeStyles[size],
3615
3950
  ...style
3616
3951
  };
3617
- return /* @__PURE__ */ jsx47("span", { ref, style: combinedStyles, ...props, children });
3952
+ return /* @__PURE__ */ jsx49("span", { ref, style: combinedStyles, ...props, children });
3618
3953
  }
3619
3954
  );
3620
3955
  Badge.displayName = "Badge";
3621
3956
 
3622
3957
  // src/components/shared/Table.tsx
3623
- import React28 from "react";
3624
- import { jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
3958
+ import React29 from "react";
3959
+ import { jsx as jsx50, jsxs as jsxs40 } from "react/jsx-runtime";
3625
3960
  function Table({
3626
3961
  columns,
3627
3962
  data,
@@ -3630,7 +3965,7 @@ function Table({
3630
3965
  bordered = true,
3631
3966
  style
3632
3967
  }) {
3633
- const [hoveredRow, setHoveredRow] = React28.useState(null);
3968
+ const [hoveredRow, setHoveredRow] = React29.useState(null);
3634
3969
  const tableStyles = {
3635
3970
  width: "100%",
3636
3971
  borderCollapse: "collapse",
@@ -3655,8 +3990,8 @@ function Table({
3655
3990
  backgroundColor: hoverable && hoveredRow === rowIndex ? "#f9fafb" : striped && rowIndex % 2 === 1 ? "#f9fafb" : "#ffffff",
3656
3991
  transition: "background-color 0.15s ease"
3657
3992
  });
3658
- return /* @__PURE__ */ jsx48("div", { style: { overflowX: "auto", borderRadius: "0.5rem", border: bordered ? "1px solid #e5e7eb" : "none" }, children: /* @__PURE__ */ jsxs38("table", { style: tableStyles, children: [
3659
- /* @__PURE__ */ jsx48("thead", { style: theadStyles, children: /* @__PURE__ */ jsx48("tr", { children: columns.map((column) => /* @__PURE__ */ jsx48(
3993
+ return /* @__PURE__ */ jsx50("div", { style: { overflowX: "auto", borderRadius: "0.5rem", border: bordered ? "1px solid #e5e7eb" : "none" }, children: /* @__PURE__ */ jsxs40("table", { style: tableStyles, children: [
3994
+ /* @__PURE__ */ jsx50("thead", { style: theadStyles, children: /* @__PURE__ */ jsx50("tr", { children: columns.map((column) => /* @__PURE__ */ jsx50(
3660
3995
  "th",
3661
3996
  {
3662
3997
  style: {
@@ -3667,12 +4002,12 @@ function Table({
3667
4002
  },
3668
4003
  column.key
3669
4004
  )) }) }),
3670
- /* @__PURE__ */ jsx48("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsx48(
4005
+ /* @__PURE__ */ jsx50("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsx50(
3671
4006
  "tr",
3672
4007
  {
3673
4008
  onMouseEnter: () => hoverable && setHoveredRow(rowIndex),
3674
4009
  onMouseLeave: () => hoverable && setHoveredRow(null),
3675
- children: columns.map((column) => /* @__PURE__ */ jsx48("td", { style: getTdStyles(rowIndex), children: column.render ? column.render(row) : row[column.key] }, column.key))
4010
+ children: columns.map((column) => /* @__PURE__ */ jsx50("td", { style: getTdStyles(rowIndex), children: column.render ? column.render(row) : row[column.key] }, column.key))
3676
4011
  },
3677
4012
  rowIndex
3678
4013
  )) })
@@ -3681,9 +4016,9 @@ function Table({
3681
4016
  Table.displayName = "Table";
3682
4017
 
3683
4018
  // src/components/shared/Container.tsx
3684
- import React29 from "react";
3685
- import { jsx as jsx49 } from "react/jsx-runtime";
3686
- var Container = React29.forwardRef(
4019
+ import React30 from "react";
4020
+ import { jsx as jsx51 } from "react/jsx-runtime";
4021
+ var Container = React30.forwardRef(
3687
4022
  ({ style, maxWidth = "lg", padding = "md", children, ...props }, ref) => {
3688
4023
  const maxWidthStyles = {
3689
4024
  sm: "640px",
@@ -3708,15 +4043,15 @@ var Container = React29.forwardRef(
3708
4043
  paddingRight: paddingStyles[padding],
3709
4044
  ...style
3710
4045
  };
3711
- return /* @__PURE__ */ jsx49("div", { ref, style: containerStyles, ...props, children });
4046
+ return /* @__PURE__ */ jsx51("div", { ref, style: containerStyles, ...props, children });
3712
4047
  }
3713
4048
  );
3714
4049
  Container.displayName = "Container";
3715
4050
 
3716
4051
  // src/components/shared/Grid.tsx
3717
- import React30 from "react";
3718
- import { jsx as jsx50 } from "react/jsx-runtime";
3719
- var Grid = React30.forwardRef(
4052
+ import React31 from "react";
4053
+ import { jsx as jsx52 } from "react/jsx-runtime";
4054
+ var Grid = React31.forwardRef(
3720
4055
  ({ style, columns = 3, rows, gap = "md", width = "100%", height = "auto", responsive = true, children, ...props }, ref) => {
3721
4056
  const gapStyles = {
3722
4057
  none: "0",
@@ -3734,15 +4069,15 @@ var Grid = React30.forwardRef(
3734
4069
  height,
3735
4070
  ...style
3736
4071
  };
3737
- return /* @__PURE__ */ jsx50("div", { ref, style: gridStyles, ...props, children });
4072
+ return /* @__PURE__ */ jsx52("div", { ref, style: gridStyles, ...props, children });
3738
4073
  }
3739
4074
  );
3740
4075
  Grid.displayName = "Grid";
3741
4076
 
3742
4077
  // src/components/shared/Stack.tsx
3743
- import React31 from "react";
3744
- import { jsx as jsx51 } from "react/jsx-runtime";
3745
- var Stack = React31.forwardRef(
4078
+ import React32 from "react";
4079
+ import { jsx as jsx53 } from "react/jsx-runtime";
4080
+ var Stack = React32.forwardRef(
3746
4081
  ({ style, direction = "vertical", gap = "md", align = "stretch", justify = "start", children, ...props }, ref) => {
3747
4082
  const gapStyles = {
3748
4083
  none: "0",
@@ -3772,14 +4107,14 @@ var Stack = React31.forwardRef(
3772
4107
  justifyContent: justifyStyles[justify],
3773
4108
  ...style
3774
4109
  };
3775
- return /* @__PURE__ */ jsx51("div", { ref, style: stackStyles, ...props, children });
4110
+ return /* @__PURE__ */ jsx53("div", { ref, style: stackStyles, ...props, children });
3776
4111
  }
3777
4112
  );
3778
4113
  Stack.displayName = "Stack";
3779
4114
 
3780
4115
  // src/components/shared/Modal.tsx
3781
- import React32 from "react";
3782
- import { jsx as jsx52, jsxs as jsxs39 } from "react/jsx-runtime";
4116
+ import React33 from "react";
4117
+ import { jsx as jsx54, jsxs as jsxs41 } from "react/jsx-runtime";
3783
4118
  var Modal = ({
3784
4119
  isOpen,
3785
4120
  onClose,
@@ -3788,7 +4123,7 @@ var Modal = ({
3788
4123
  size = "md",
3789
4124
  closeOnOverlayClick = true
3790
4125
  }) => {
3791
- React32.useEffect(() => {
4126
+ React33.useEffect(() => {
3792
4127
  if (isOpen) {
3793
4128
  document.body.style.overflow = "hidden";
3794
4129
  } else {
@@ -3857,20 +4192,20 @@ var Modal = ({
3857
4192
  overflowY: "auto",
3858
4193
  flex: 1
3859
4194
  };
3860
- return /* @__PURE__ */ jsx52(
4195
+ return /* @__PURE__ */ jsx54(
3861
4196
  "div",
3862
4197
  {
3863
4198
  style: overlayStyles,
3864
4199
  onClick: closeOnOverlayClick ? onClose : void 0,
3865
- children: /* @__PURE__ */ jsxs39(
4200
+ children: /* @__PURE__ */ jsxs41(
3866
4201
  "div",
3867
4202
  {
3868
4203
  style: modalStyles,
3869
4204
  onClick: (e) => e.stopPropagation(),
3870
4205
  children: [
3871
- title && /* @__PURE__ */ jsxs39("div", { style: headerStyles, children: [
3872
- /* @__PURE__ */ jsx52("h2", { style: titleStyles, children: title }),
3873
- /* @__PURE__ */ jsx52(
4206
+ title && /* @__PURE__ */ jsxs41("div", { style: headerStyles, children: [
4207
+ /* @__PURE__ */ jsx54("h2", { style: titleStyles, children: title }),
4208
+ /* @__PURE__ */ jsx54(
3874
4209
  "button",
3875
4210
  {
3876
4211
  style: closeButtonStyles,
@@ -3880,7 +4215,7 @@ var Modal = ({
3880
4215
  }
3881
4216
  )
3882
4217
  ] }),
3883
- /* @__PURE__ */ jsx52("div", { style: contentStyles, children })
4218
+ /* @__PURE__ */ jsx54("div", { style: contentStyles, children })
3884
4219
  ]
3885
4220
  }
3886
4221
  )
@@ -3891,7 +4226,7 @@ Modal.displayName = "Modal";
3891
4226
 
3892
4227
  // src/components/shared/DateRangePicker.tsx
3893
4228
  import { useEffect as useEffect15, useMemo as useMemo6, useState as useState23 } from "react";
3894
- import { jsx as jsx53, jsxs as jsxs40 } from "react/jsx-runtime";
4229
+ import { jsx as jsx55, jsxs as jsxs42 } from "react/jsx-runtime";
3895
4230
  var PrimusDateRangePicker = ({
3896
4231
  startDate = null,
3897
4232
  endDate = null,
@@ -3927,8 +4262,8 @@ var PrimusDateRangePicker = ({
3927
4262
  setEnd(nextEnd);
3928
4263
  onRangeChange?.({ startDate: nextStart, endDate: nextEnd, label: range.label });
3929
4264
  };
3930
- return /* @__PURE__ */ jsxs40("div", { className: "space-y-3", children: [
3931
- normalizedRanges.length > 0 && /* @__PURE__ */ jsx53("div", { className: "flex flex-wrap gap-2", children: normalizedRanges.map((range) => /* @__PURE__ */ jsx53(
4265
+ return /* @__PURE__ */ jsxs42("div", { className: "space-y-3", children: [
4266
+ normalizedRanges.length > 0 && /* @__PURE__ */ jsx55("div", { className: "flex flex-wrap gap-2", children: normalizedRanges.map((range) => /* @__PURE__ */ jsx55(
3932
4267
  "button",
3933
4268
  {
3934
4269
  type: "button",
@@ -3939,8 +4274,8 @@ var PrimusDateRangePicker = ({
3939
4274
  },
3940
4275
  range.label
3941
4276
  )) }),
3942
- /* @__PURE__ */ jsxs40("div", { className: "flex flex-col md:flex-row gap-3", children: [
3943
- /* @__PURE__ */ jsx53(
4277
+ /* @__PURE__ */ jsxs42("div", { className: "flex flex-col md:flex-row gap-3", children: [
4278
+ /* @__PURE__ */ jsx55(
3944
4279
  "input",
3945
4280
  {
3946
4281
  type: "date",
@@ -3952,7 +4287,7 @@ var PrimusDateRangePicker = ({
3952
4287
  className: "w-full px-3 py-2 rounded-lg border border-white/10 bg-white/5 text-gray-200 text-sm focus:outline-none focus:ring-1 focus:ring-purple-500/50"
3953
4288
  }
3954
4289
  ),
3955
- /* @__PURE__ */ jsx53(
4290
+ /* @__PURE__ */ jsx55(
3956
4291
  "input",
3957
4292
  {
3958
4293
  type: "date",
@@ -4003,7 +4338,7 @@ var toDateInputValue = (value) => {
4003
4338
  };
4004
4339
 
4005
4340
  // src/components/shared/FilterBar.tsx
4006
- import { jsx as jsx54, jsxs as jsxs41 } from "react/jsx-runtime";
4341
+ import { jsx as jsx56, jsxs as jsxs43 } from "react/jsx-runtime";
4007
4342
  var PrimusFilterBar = ({
4008
4343
  filters,
4009
4344
  activeFilters,
@@ -4017,9 +4352,9 @@ var PrimusFilterBar = ({
4017
4352
  };
4018
4353
  onChange?.(next);
4019
4354
  };
4020
- return /* @__PURE__ */ jsxs41("div", { className: "flex flex-wrap gap-4 items-end", children: [
4021
- filters.map((filter) => /* @__PURE__ */ jsxs41("div", { className: "min-w-[220px]", children: [
4022
- filter.type === "select" && /* @__PURE__ */ jsx54(
4355
+ return /* @__PURE__ */ jsxs43("div", { className: "flex flex-wrap gap-4 items-end", children: [
4356
+ filters.map((filter) => /* @__PURE__ */ jsxs43("div", { className: "min-w-[220px]", children: [
4357
+ filter.type === "select" && /* @__PURE__ */ jsx56(
4023
4358
  Select,
4024
4359
  {
4025
4360
  label: filter.label,
@@ -4029,7 +4364,7 @@ var PrimusFilterBar = ({
4029
4364
  onChange: (value) => updateFilter(filter.key, value)
4030
4365
  }
4031
4366
  ),
4032
- filter.type === "toggle" && /* @__PURE__ */ jsx54(
4367
+ filter.type === "toggle" && /* @__PURE__ */ jsx56(
4033
4368
  Toggle,
4034
4369
  {
4035
4370
  label: filter.label,
@@ -4037,7 +4372,7 @@ var PrimusFilterBar = ({
4037
4372
  onChange: (checked) => updateFilter(filter.key, checked)
4038
4373
  }
4039
4374
  ),
4040
- filter.type === "search" && /* @__PURE__ */ jsx54(
4375
+ filter.type === "search" && /* @__PURE__ */ jsx56(
4041
4376
  Input,
4042
4377
  {
4043
4378
  label: filter.label,
@@ -4053,7 +4388,7 @@ var PrimusFilterBar = ({
4053
4388
 
4054
4389
  // src/components/shared/ExportMenu.tsx
4055
4390
  import { useEffect as useEffect16, useState as useState24 } from "react";
4056
- import { jsx as jsx55, jsxs as jsxs42 } from "react/jsx-runtime";
4391
+ import { jsx as jsx57, jsxs as jsxs44 } from "react/jsx-runtime";
4057
4392
  var PrimusExportMenu = ({
4058
4393
  formats = ["CSV", "PDF", "PNG", "JSON"],
4059
4394
  includeCharts = true,
@@ -4078,29 +4413,29 @@ var PrimusExportMenu = ({
4078
4413
  includeTables: tables
4079
4414
  });
4080
4415
  };
4081
- return /* @__PURE__ */ jsxs42("div", { className: "flex flex-wrap items-center gap-3", children: [
4082
- /* @__PURE__ */ jsx55(
4416
+ return /* @__PURE__ */ jsxs44("div", { className: "flex flex-wrap items-center gap-3", children: [
4417
+ /* @__PURE__ */ jsx57(
4083
4418
  "select",
4084
4419
  {
4085
4420
  value: format,
4086
4421
  onChange: (event) => setFormat(event.target.value),
4087
4422
  className: "px-3 py-2 rounded-lg border border-white/10 bg-white/5 text-gray-200 text-sm",
4088
- children: formats.map((item) => /* @__PURE__ */ jsx55("option", { value: item, children: item }, item))
4423
+ children: formats.map((item) => /* @__PURE__ */ jsx57("option", { value: item, children: item }, item))
4089
4424
  }
4090
4425
  ),
4091
- /* @__PURE__ */ jsxs42("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4092
- /* @__PURE__ */ jsx55("input", { type: "checkbox", checked: charts, onChange: (e) => setCharts(e.target.checked) }),
4426
+ /* @__PURE__ */ jsxs44("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4427
+ /* @__PURE__ */ jsx57("input", { type: "checkbox", checked: charts, onChange: (e) => setCharts(e.target.checked) }),
4093
4428
  "Charts"
4094
4429
  ] }),
4095
- /* @__PURE__ */ jsxs42("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4096
- /* @__PURE__ */ jsx55("input", { type: "checkbox", checked: stats, onChange: (e) => setStats(e.target.checked) }),
4430
+ /* @__PURE__ */ jsxs44("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4431
+ /* @__PURE__ */ jsx57("input", { type: "checkbox", checked: stats, onChange: (e) => setStats(e.target.checked) }),
4097
4432
  "Stats"
4098
4433
  ] }),
4099
- /* @__PURE__ */ jsxs42("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4100
- /* @__PURE__ */ jsx55("input", { type: "checkbox", checked: tables, onChange: (e) => setTables(e.target.checked) }),
4434
+ /* @__PURE__ */ jsxs44("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4435
+ /* @__PURE__ */ jsx57("input", { type: "checkbox", checked: tables, onChange: (e) => setTables(e.target.checked) }),
4101
4436
  "Tables"
4102
4437
  ] }),
4103
- /* @__PURE__ */ jsx55(
4438
+ /* @__PURE__ */ jsx57(
4104
4439
  "button",
4105
4440
  {
4106
4441
  type: "button",
@@ -4114,7 +4449,7 @@ var PrimusExportMenu = ({
4114
4449
 
4115
4450
  // src/components/shared/Search.tsx
4116
4451
  import { useEffect as useEffect17, useMemo as useMemo7, useState as useState25 } from "react";
4117
- import { jsx as jsx56, jsxs as jsxs43 } from "react/jsx-runtime";
4452
+ import { jsx as jsx58, jsxs as jsxs45 } from "react/jsx-runtime";
4118
4453
  var PrimusSearch = ({
4119
4454
  placeholder = "Search...",
4120
4455
  debounce = 300,
@@ -4142,8 +4477,8 @@ var PrimusSearch = ({
4142
4477
  }
4143
4478
  return suggestions.filter((item) => item.toLowerCase().includes(query.toLowerCase())).slice(0, 5);
4144
4479
  }, [suggestions, query, showSuggestions]);
4145
- return /* @__PURE__ */ jsxs43("div", { className: "relative", children: [
4146
- /* @__PURE__ */ jsx56(
4480
+ return /* @__PURE__ */ jsxs45("div", { className: "relative", children: [
4481
+ /* @__PURE__ */ jsx58(
4147
4482
  "input",
4148
4483
  {
4149
4484
  type: "text",
@@ -4153,7 +4488,7 @@ var PrimusSearch = ({
4153
4488
  className: "w-full px-3 py-2 rounded-lg border border-white/10 bg-white/5 text-gray-200 text-sm focus:outline-none focus:ring-1 focus:ring-purple-500/50"
4154
4489
  }
4155
4490
  ),
4156
- visibleSuggestions.length > 0 && /* @__PURE__ */ jsx56("div", { className: "absolute mt-2 w-full rounded-lg border border-white/10 bg-slate-900/90 backdrop-blur-sm shadow-lg z-10", children: visibleSuggestions.map((item) => /* @__PURE__ */ jsx56(
4491
+ visibleSuggestions.length > 0 && /* @__PURE__ */ jsx58("div", { className: "absolute mt-2 w-full rounded-lg border border-white/10 bg-slate-900/90 backdrop-blur-sm shadow-lg z-10", children: visibleSuggestions.map((item) => /* @__PURE__ */ jsx58(
4157
4492
  "button",
4158
4493
  {
4159
4494
  type: "button",
@@ -4165,6 +4500,304 @@ var PrimusSearch = ({
4165
4500
  )) })
4166
4501
  ] });
4167
4502
  };
4503
+
4504
+ // src/components/shared/PrimusWizard.tsx
4505
+ import React37, { useState as useState26 } from "react";
4506
+ import { Fragment as Fragment6, jsx as jsx59, jsxs as jsxs46 } from "react/jsx-runtime";
4507
+ var PrimusStep = ({ children }) => {
4508
+ return /* @__PURE__ */ jsx59(Fragment6, { children });
4509
+ };
4510
+ var PrimusStepper = ({ steps, currentStep }) => {
4511
+ return /* @__PURE__ */ jsx59("nav", { "aria-label": "Progress", className: "mb-8", children: /* @__PURE__ */ jsx59("ol", { role: "list", className: "overflow-hidden rounded-md items-center flex md:border md:border-gray-200 dark:md:border-gray-800", children: steps.map((step, stepIdx) => /* @__PURE__ */ jsx59("li", { className: "relative md:flex-1 md:flex", children: stepIdx < currentStep ? /* @__PURE__ */ jsx59("div", { className: "group flex flex-1 items-center md:border-b-0 md:border-r border-gray-200 dark:border-gray-800 py-2 pl-4 md:py-3 md:pl-6 bg-white dark:bg-gray-900", children: /* @__PURE__ */ jsxs46("span", { className: "flex items-center text-sm font-medium text-purple-600 dark:text-purple-400", children: [
4512
+ /* @__PURE__ */ jsx59("span", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-purple-600 hover:bg-purple-800 text-white dark:bg-purple-500 dark:text-white", children: /* @__PURE__ */ jsx59("svg", { className: "h-5 w-5", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx59("path", { fillRule: "evenodd", d: "M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z", clipRule: "evenodd" }) }) }),
4513
+ /* @__PURE__ */ jsx59("span", { className: "ml-4 text-sm font-medium", children: step.label })
4514
+ ] }) }) : stepIdx === currentStep ? /* @__PURE__ */ jsx59("div", { className: "flex flex-1 items-center md:border-b-0 md:border-r border-gray-200 dark:border-gray-800 py-2 pl-4 md:py-3 md:pl-6 bg-white dark:bg-gray-900", "aria-current": "step", children: /* @__PURE__ */ jsxs46("span", { className: "flex items-center text-sm font-medium text-purple-600 dark:text-purple-400", children: [
4515
+ /* @__PURE__ */ jsx59("span", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full border-2 border-purple-600 dark:border-purple-500", children: /* @__PURE__ */ jsx59("span", { className: "text-purple-600 dark:text-purple-500 font-bold", children: stepIdx + 1 }) }),
4516
+ /* @__PURE__ */ jsx59("span", { className: "ml-4 text-sm font-medium text-gray-900 dark:text-white", children: step.label })
4517
+ ] }) }) : /* @__PURE__ */ jsx59("div", { className: "group flex flex-1 items-center md:border-b-0 md:border-r border-gray-200 dark:border-gray-800 py-2 pl-4 md:py-3 md:pl-6 bg-gray-50 dark:bg-gray-800/50", children: /* @__PURE__ */ jsxs46("span", { className: "flex items-center text-sm font-medium text-gray-500 dark:text-gray-400", children: [
4518
+ /* @__PURE__ */ jsx59("span", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full border-2 border-gray-300 dark:border-gray-700", children: /* @__PURE__ */ jsx59("span", { className: "text-gray-500 dark:text-gray-400 font-medium", children: stepIdx + 1 }) }),
4519
+ /* @__PURE__ */ jsx59("span", { className: "ml-4", children: step.label })
4520
+ ] }) }) }, step.label)) }) });
4521
+ };
4522
+ var PrimusWizard = ({
4523
+ title,
4524
+ subtitle,
4525
+ children,
4526
+ onComplete,
4527
+ className,
4528
+ startStep = 0
4529
+ }) => {
4530
+ const [currentStep, setCurrentStep] = useState26(startStep);
4531
+ const steps = React37.Children.toArray(children).filter(
4532
+ (child) => React37.isValidElement(child) && (child.type === PrimusStep || child.type.name === "PrimusStep")
4533
+ );
4534
+ const totalSteps = steps.length;
4535
+ const isFirstStep = currentStep === 0;
4536
+ const isLastStep = currentStep === totalSteps - 1;
4537
+ const handleNext = () => {
4538
+ if (isLastStep) {
4539
+ onComplete?.();
4540
+ } else {
4541
+ setCurrentStep((prev) => prev + 1);
4542
+ }
4543
+ };
4544
+ const handleBack = () => {
4545
+ if (!isFirstStep) {
4546
+ setCurrentStep((prev) => prev - 1);
4547
+ }
4548
+ };
4549
+ if (totalSteps === 0) {
4550
+ return /* @__PURE__ */ jsx59("div", { className: "text-red-500", children: "Error: PrimusWizard requires PrimusStep children" });
4551
+ }
4552
+ const currentStepConfig = steps[currentStep].props;
4553
+ return /* @__PURE__ */ jsxs46("div", { className: `space-y-6 ${className}`, children: [
4554
+ /* @__PURE__ */ jsxs46("div", { children: [
4555
+ title && /* @__PURE__ */ jsx59("h2", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: title }),
4556
+ subtitle && /* @__PURE__ */ jsx59("p", { className: "mt-1 text-gray-500 dark:text-gray-400", children: subtitle })
4557
+ ] }),
4558
+ /* @__PURE__ */ jsx59(
4559
+ PrimusStepper,
4560
+ {
4561
+ steps: steps.map((s) => ({ label: s.props.label, description: s.props.description })),
4562
+ currentStep
4563
+ }
4564
+ ),
4565
+ /* @__PURE__ */ jsxs46(Card, { className: "p-6 min-h-[300px]", children: [
4566
+ /* @__PURE__ */ jsx59("div", { className: "mb-8", children: steps[currentStep] }),
4567
+ /* @__PURE__ */ jsxs46("div", { className: "flex justify-between pt-6 border-t border-gray-100 dark:border-gray-800", children: [
4568
+ /* @__PURE__ */ jsx59(
4569
+ Button,
4570
+ {
4571
+ variant: "ghost",
4572
+ onClick: handleBack,
4573
+ disabled: isFirstStep,
4574
+ children: "Back"
4575
+ }
4576
+ ),
4577
+ /* @__PURE__ */ jsx59(
4578
+ Button,
4579
+ {
4580
+ onClick: handleNext,
4581
+ disabled: currentStepConfig.isValid === false,
4582
+ children: isLastStep ? "Complete" : "Next"
4583
+ }
4584
+ )
4585
+ ] })
4586
+ ] })
4587
+ ] });
4588
+ };
4589
+
4590
+ // src/components/shared/Field.tsx
4591
+ import React38 from "react";
4592
+ import { clsx as clsx8 } from "clsx";
4593
+ import { ExclamationCircleIcon } from "@heroicons/react/20/solid";
4594
+ import { jsx as jsx60, jsxs as jsxs47 } from "react/jsx-runtime";
4595
+ var FieldContext = React38.createContext(void 0);
4596
+ var useFieldContext = () => React38.useContext(FieldContext);
4597
+ var Field = ({ children, error, disabled, dense, className, ...props }) => {
4598
+ const id = React38.useId();
4599
+ return /* @__PURE__ */ jsx60(FieldContext.Provider, { value: { id, error, disabled }, children: /* @__PURE__ */ jsx60(
4600
+ "div",
4601
+ {
4602
+ className: clsx8(
4603
+ "flex flex-col w-full",
4604
+ dense ? "gap-1" : "gap-1.5",
4605
+ className
4606
+ ),
4607
+ ...props,
4608
+ children
4609
+ }
4610
+ ) });
4611
+ };
4612
+ var Label = ({ className, children, required, indicator, ...props }) => {
4613
+ const context = useFieldContext();
4614
+ return /* @__PURE__ */ jsxs47(
4615
+ "label",
4616
+ {
4617
+ htmlFor: context?.id,
4618
+ className: clsx8(
4619
+ "block text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
4620
+ context?.disabled ? "text-gray-400 opacity-70" : "text-gray-700",
4621
+ props.onClick ? "cursor-pointer" : "cursor-default",
4622
+ className
4623
+ ),
4624
+ ...props,
4625
+ children: [
4626
+ children,
4627
+ required && /* @__PURE__ */ jsx60("span", { className: "ml-0.5 text-red-500", children: "*" }),
4628
+ indicator
4629
+ ]
4630
+ }
4631
+ );
4632
+ };
4633
+ var FieldDescription = ({ className, children, ...props }) => {
4634
+ const context = useFieldContext();
4635
+ return /* @__PURE__ */ jsx60(
4636
+ "p",
4637
+ {
4638
+ className: clsx8(
4639
+ "text-[0.8rem] text-muted-foreground text-gray-500",
4640
+ context?.disabled && "opacity-70",
4641
+ className
4642
+ ),
4643
+ ...props,
4644
+ children
4645
+ }
4646
+ );
4647
+ };
4648
+ var FieldError = ({ className, children, forceVisible, ...props }) => {
4649
+ const context = useFieldContext();
4650
+ const error = context?.error || children;
4651
+ if (!error && !forceVisible) return null;
4652
+ return /* @__PURE__ */ jsxs47(
4653
+ "p",
4654
+ {
4655
+ className: clsx8(
4656
+ "text-[0.8rem] font-medium text-red-500 flex items-center gap-1.5 animate-in slide-in-from-top-1 fade-in-50",
4657
+ className
4658
+ ),
4659
+ ...props,
4660
+ children: [
4661
+ /* @__PURE__ */ jsx60(ExclamationCircleIcon, { className: "h-4 w-4 shrink-0" }),
4662
+ error
4663
+ ]
4664
+ }
4665
+ );
4666
+ };
4667
+
4668
+ // src/components/shared/InputGroup.tsx
4669
+ import React39 from "react";
4670
+ import { clsx as clsx9 } from "clsx";
4671
+ import { jsx as jsx61 } from "react/jsx-runtime";
4672
+ var InputGroup = ({ className, children, size = "md", ...props }) => {
4673
+ return /* @__PURE__ */ jsx61(
4674
+ "div",
4675
+ {
4676
+ className: clsx9(
4677
+ "flex items-stretch w-full rounded-lg shadow-sm",
4678
+ // Target direct children to remove borders and rounded corners where they touch
4679
+ "[&>*:first-child]:rounded-r-none",
4680
+ "[&>*:last-child]:rounded-l-none",
4681
+ "[&>*:not(:first-child):not(:last-child)]:rounded-none",
4682
+ // Handle borders to prevent double borders
4683
+ "[&>*:not(:first-child)]:-ml-px",
4684
+ // Ensure z-index handling for focus rings
4685
+ "[&>*:focus-within]:z-10",
4686
+ className
4687
+ ),
4688
+ ...props,
4689
+ children: React39.Children.map(children, (child) => {
4690
+ if (React39.isValidElement(child)) {
4691
+ return React39.cloneElement(child, { size });
4692
+ }
4693
+ return child;
4694
+ })
4695
+ }
4696
+ );
4697
+ };
4698
+ var InputAddon = ({ className, children, ...props }) => {
4699
+ return /* @__PURE__ */ jsx61(
4700
+ "div",
4701
+ {
4702
+ className: clsx9(
4703
+ "flex items-center px-3 border border-gray-200 bg-gray-50 text-gray-500 text-sm whitespace-nowrap",
4704
+ // These will be overridden by the group's first/last child selectors usually, but good defaults:
4705
+ "first:rounded-l-lg last:rounded-r-lg",
4706
+ className
4707
+ ),
4708
+ ...props,
4709
+ children
4710
+ }
4711
+ );
4712
+ };
4713
+
4714
+ // src/components/shared/PasswordInput.tsx
4715
+ import React40, { useState as useState27 } from "react";
4716
+ import { EyeIcon, EyeSlashIcon } from "@heroicons/react/20/solid";
4717
+ import { jsx as jsx62, jsxs as jsxs48 } from "react/jsx-runtime";
4718
+ var PasswordInput = React40.forwardRef(
4719
+ (props, ref) => {
4720
+ const [showPassword, setShowPassword] = useState27(false);
4721
+ const toggleVisibility = () => {
4722
+ setShowPassword(!showPassword);
4723
+ };
4724
+ return /* @__PURE__ */ jsx62(
4725
+ Input,
4726
+ {
4727
+ ref,
4728
+ type: showPassword ? "text" : "password",
4729
+ endIcon: /* @__PURE__ */ jsxs48(
4730
+ "button",
4731
+ {
4732
+ type: "button",
4733
+ onClick: toggleVisibility,
4734
+ className: "text-gray-400 hover:text-gray-600 focus:outline-none focus:text-primus-600 transition-colors pointer-events-auto cursor-pointer p-0.5 rounded",
4735
+ tabIndex: -1,
4736
+ children: [
4737
+ showPassword ? /* @__PURE__ */ jsx62(EyeSlashIcon, { className: "h-4 w-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx62(EyeIcon, { className: "h-4 w-4", "aria-hidden": "true" }),
4738
+ /* @__PURE__ */ jsx62("span", { className: "sr-only", children: showPassword ? "Hide password" : "Show password" })
4739
+ ]
4740
+ }
4741
+ ),
4742
+ ...props
4743
+ }
4744
+ );
4745
+ }
4746
+ );
4747
+ PasswordInput.displayName = "PasswordInput";
4748
+
4749
+ // src/components/shared/SearchInput.tsx
4750
+ import React41, { useState as useState28, useEffect as useEffect18 } from "react";
4751
+ import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
4752
+ import { jsx as jsx63 } from "react/jsx-runtime";
4753
+ var SearchInput = React41.forwardRef(
4754
+ ({ value, onSearch, debounceMs = 300, className, ...props }, ref) => {
4755
+ const [localValue, setLocalValue] = useState28(value || "");
4756
+ const [isDebouncing, setIsDebouncing] = useState28(false);
4757
+ useEffect18(() => {
4758
+ if (value !== void 0) {
4759
+ setLocalValue(value);
4760
+ }
4761
+ }, [value]);
4762
+ useEffect18(() => {
4763
+ if (debounceMs === 0) {
4764
+ onSearch?.(localValue);
4765
+ return;
4766
+ }
4767
+ const handler = setTimeout(() => {
4768
+ onSearch?.(localValue);
4769
+ setIsDebouncing(false);
4770
+ }, debounceMs);
4771
+ return () => {
4772
+ clearTimeout(handler);
4773
+ };
4774
+ }, [localValue, debounceMs]);
4775
+ const handleChange = (e) => {
4776
+ const newVal = e.target.value;
4777
+ setLocalValue(newVal);
4778
+ if (debounceMs > 0) setIsDebouncing(true);
4779
+ };
4780
+ const handleClear = () => {
4781
+ setLocalValue("");
4782
+ props.onClear?.();
4783
+ };
4784
+ return /* @__PURE__ */ jsx63(
4785
+ Input,
4786
+ {
4787
+ ref,
4788
+ type: "text",
4789
+ startIcon: /* @__PURE__ */ jsx63(MagnifyingGlassIcon, { className: "h-4 w-4" }),
4790
+ value: localValue,
4791
+ onChange: handleChange,
4792
+ onClear: handleClear,
4793
+ loading: props.loading || props.loading === void 0 && isDebouncing,
4794
+ className,
4795
+ ...props
4796
+ }
4797
+ );
4798
+ }
4799
+ );
4800
+ SearchInput.displayName = "SearchInput";
4168
4801
  export {
4169
4802
  AICopilot,
4170
4803
  AccountDashboard,
@@ -4181,17 +4814,24 @@ export {
4181
4814
  DashboardGrid,
4182
4815
  DocumentViewer,
4183
4816
  FeatureFlagToggle,
4817
+ Field,
4818
+ FieldDescription,
4819
+ FieldError,
4184
4820
  FileUploader,
4185
4821
  FraudDetectionDashboard,
4186
4822
  Grid,
4187
4823
  Input,
4824
+ InputAddon,
4825
+ InputGroup,
4188
4826
  KYCVerification,
4827
+ Label,
4189
4828
  LoanCalculator,
4190
4829
  LogViewer,
4191
4830
  LoginPage,
4192
4831
  Modal,
4193
4832
  NotificationBell,
4194
4833
  PrimusNotificationFeed as NotificationFeed,
4834
+ PasswordInput,
4195
4835
  PolicyCard,
4196
4836
  PremiumCalculator,
4197
4837
  PrimusActivityFeed,
@@ -4207,10 +4847,16 @@ export {
4207
4847
  PrimusDataTable,
4208
4848
  PrimusDateRangePicker,
4209
4849
  PrimusExportMenu,
4850
+ Field as PrimusField,
4851
+ FieldDescription as PrimusFieldDescription,
4852
+ FieldError as PrimusFieldError,
4210
4853
  PrimusFilterBar,
4211
4854
  Grid as PrimusGrid,
4212
4855
  PrimusHeader,
4213
4856
  Input as PrimusInput,
4857
+ InputAddon as PrimusInputAddon,
4858
+ InputGroup as PrimusInputGroup,
4859
+ Label as PrimusLabel,
4214
4860
  PrimusLayout,
4215
4861
  PrimusLineChart,
4216
4862
  PrimusLogin,
@@ -4219,22 +4865,31 @@ export {
4219
4865
  PrimusNotificationCenter,
4220
4866
  PrimusNotificationFeed,
4221
4867
  PrimusNotifications,
4868
+ PasswordInput as PrimusPasswordInput,
4222
4869
  PrimusPieChart,
4223
4870
  PrimusProvider,
4224
4871
  RadioGroup as PrimusRadioGroup,
4225
4872
  PrimusSearch,
4873
+ SearchInput as PrimusSearchInput,
4874
+ PrimusSection,
4226
4875
  Select as PrimusSelect,
4227
4876
  PrimusSidebar,
4228
4877
  PrimusSparkline,
4229
4878
  Stack as PrimusStack,
4230
4879
  PrimusStatCard,
4880
+ PrimusStatCard as PrimusStatsCard,
4881
+ PrimusStep,
4882
+ PrimusStepper,
4883
+ PrimusSummaryCard,
4231
4884
  Table as PrimusTable,
4232
4885
  Textarea as PrimusTextarea,
4233
4886
  PrimusThemeProvider,
4234
4887
  PrimusThemeToggle,
4235
4888
  Toggle as PrimusToggle,
4889
+ PrimusWizard,
4236
4890
  QuoteComparison,
4237
4891
  RadioGroup,
4892
+ SearchInput,
4238
4893
  SecurityDashboard,
4239
4894
  Select,
4240
4895
  Stack,
@@ -4246,6 +4901,7 @@ export {
4246
4901
  themeColors,
4247
4902
  useNotifications,
4248
4903
  usePrimusAuth,
4904
+ usePrimusFetch,
4249
4905
  usePrimusTheme,
4250
4906
  useRealtimeNotifications
4251
4907
  };