primus-react-ui 1.0.14 → 1.1.0

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,304 @@ 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: 600,
1124
+ marginBottom: "6px",
1125
+ textTransform: "uppercase",
1126
+ letterSpacing: "0.5px"
1127
+ },
1128
+ input: {
1129
+ width: "100%",
1130
+ border: "1px solid #cbd5e1",
1131
+ borderRadius: "8px",
1132
+ padding: "10px 12px",
1133
+ background: "#ffffff",
1134
+ color: "#0f172a",
1135
+ fontSize: "14px",
1136
+ outline: "none"
1137
+ },
1138
+ submitBtn: {
1139
+ marginTop: "8px",
1140
+ background: "#0f172a",
1141
+ // Slate-900
1142
+ color: "#ffffff",
1143
+ border: "none",
1144
+ borderRadius: "8px",
1145
+ padding: "12px",
1146
+ cursor: "pointer",
1147
+ fontWeight: 600,
1148
+ fontSize: "14px",
1149
+ width: "100%"
1150
+ },
1151
+ error: {
1152
+ marginTop: "12px",
1153
+ color: "#dc2626",
1154
+ fontSize: "12px",
1155
+ textAlign: "center"
1156
+ }
1157
+ };
1158
+ var darkStyles = {
1159
+ container: { backgroundColor: "#0f172a", color: "#f8fafc" },
1160
+ card: { backgroundColor: "#1e293b", borderColor: "#334155", boxShadow: "none" },
1161
+ subtitle: { color: "#94a3b8" },
1162
+ socialBtn: { backgroundColor: "#1e293b", borderColor: "#334155", color: "#f8fafc" },
1163
+ label: { color: "#94a3b8" },
1164
+ input: { backgroundColor: "#0f172a", borderColor: "#334155", color: "#f8fafc" },
1165
+ submitBtn: { backgroundColor: "#8b5cf6" }
1166
+ // Violet for dark mode
1167
+ };
1168
+ var Icons = {
1169
+ google: /* @__PURE__ */ jsxs12("svg", { width: "18", height: "18", viewBox: "0 0 18 18", children: [
1170
+ /* @__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" }),
1171
+ /* @__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" }),
1172
+ /* @__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" }),
1173
+ /* @__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" })
1174
+ ] }),
1175
+ microsoft: /* @__PURE__ */ jsxs12("svg", { width: "18", height: "18", viewBox: "0 0 18 18", children: [
1176
+ /* @__PURE__ */ jsx14("path", { d: "M0 0h8.571v8.571H0V0z", fill: "#F25022" }),
1177
+ /* @__PURE__ */ jsx14("path", { d: "M9.429 0H18v8.571H9.429V0z", fill: "#7FBA00" }),
1178
+ /* @__PURE__ */ jsx14("path", { d: "M0 9.429h8.571V18H0V9.429z", fill: "#00A4EF" }),
1179
+ /* @__PURE__ */ jsx14("path", { d: "M9.429 9.429H18V18H9.429V9.429z", fill: "#FFB900" })
1180
+ ] }),
1181
+ 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" }) }),
1182
+ 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" }) }),
1183
+ 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" }) }),
1184
+ 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" }) })
1185
+ };
1186
+ function PrimusLogin({
1187
+ onLogin,
1188
+ socialProviders = [],
1189
+ onSocialLogin,
1190
+ authEndpoint = "/api/auth",
1191
+ showEmailLogin = true,
1192
+ title = "Welcome Back",
1193
+ subtitle = "Enter your credentials to continue",
1194
+ logo,
1195
+ theme: themeOverride,
1196
+ variant = "standalone",
1197
+ useAuth = false
1198
+ }) {
1199
+ const themeContext = usePrimusTheme();
1200
+ const auth = usePrimusAuth();
1201
+ const theme = themeOverride || themeContext.theme;
1202
+ const isLight = theme === "light";
1203
+ const isDark = !isLight;
1204
+ const [username, setUsername] = useState14("");
1205
+ const [password, setPassword] = useState14("");
1206
+ const [loading, setLoading] = useState14(false);
1207
+ const [errorMessage, setErrorMessage] = useState14("");
1208
+ const currentStyles = {
1209
+ container: { ...styles.container, ...isDark ? darkStyles.container : {} },
1210
+ card: { ...styles.card, ...isDark ? darkStyles.card : {} },
1211
+ title: { ...styles.title, color: isLight ? "#0f172a" : "#f8fafc" },
1212
+ subtitle: { ...styles.subtitle, ...isDark ? darkStyles.subtitle : {} },
1213
+ input: { ...styles.input, ...isDark ? darkStyles.input : {} },
1214
+ socialBtn: { ...styles.socialBtn, ...isDark ? darkStyles.socialBtn : {} },
1215
+ label: { ...styles.label, ...isDark ? darkStyles.label : {} },
1216
+ submitBtn: { ...styles.submitBtn, ...isDark ? darkStyles.submitBtn : {} }
1217
+ };
1218
+ const handleSubmit = async (e) => {
1219
+ e.preventDefault();
1220
+ if (!username || !password) return;
1221
+ setLoading(true);
1222
+ setErrorMessage("");
1223
+ try {
1224
+ if (useAuth) {
1225
+ const result = await auth.login({ email: username, password });
1226
+ if (!result.success) {
1227
+ setErrorMessage(result.error || "Login failed");
1228
+ return;
1229
+ }
1230
+ }
1231
+ onLogin?.({ username, password });
1232
+ } catch (err) {
1233
+ setErrorMessage("Login failed. Please try again.");
1234
+ } finally {
1235
+ setLoading(false);
1236
+ }
1237
+ };
1238
+ const handleSocialClick = (provider) => {
1239
+ if (onSocialLogin) {
1240
+ onSocialLogin(provider);
1241
+ } else {
1242
+ const base = authEndpoint.replace(/\/+$/, "");
1243
+ window.location.href = `${base}/${provider}`;
1244
+ }
1245
+ };
1246
+ const renderSocialIcon = (p) => {
1247
+ const key = p === "azure" ? "microsoft" : p;
1248
+ return Icons[key] || null;
1249
+ };
1250
+ const content = /* @__PURE__ */ jsxs12("div", { style: currentStyles.card, className: "primus-login-card", children: [
1251
+ /* @__PURE__ */ jsxs12("div", { style: styles.header, className: "primus-login-header", children: [
1252
+ 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 })),
1253
+ /* @__PURE__ */ jsx14("h2", { style: currentStyles.title, children: title }),
1254
+ /* @__PURE__ */ jsx14("p", { style: currentStyles.subtitle, children: subtitle })
1255
+ ] }),
1256
+ socialProviders.length > 0 && /* @__PURE__ */ jsx14("div", { style: styles.socialGrid, className: "primus-social", children: socialProviders.map((provider) => /* @__PURE__ */ jsxs12(
1257
+ "button",
1258
+ {
1259
+ type: "button",
1260
+ onClick: () => handleSocialClick(provider),
1261
+ style: currentStyles.socialBtn,
1262
+ onMouseOver: (e) => {
1263
+ if (isLight) e.currentTarget.style.backgroundColor = "#f1f5f9";
1264
+ else e.currentTarget.style.backgroundColor = "#334155";
1265
+ },
1266
+ onMouseOut: (e) => {
1267
+ if (isLight) e.currentTarget.style.backgroundColor = "#ffffff";
1268
+ else e.currentTarget.style.backgroundColor = "#1e293b";
1269
+ },
1270
+ children: [
1271
+ renderSocialIcon(provider),
1272
+ "Continue with ",
1273
+ provider === "azure" ? "Microsoft" : provider.charAt(0).toUpperCase() + provider.slice(1)
1274
+ ]
1275
+ },
1276
+ provider
1277
+ )) }),
1278
+ socialProviders.length > 0 && showEmailLogin && /* @__PURE__ */ jsxs12("div", { style: styles.divider, className: "primus-divider", children: [
1279
+ /* @__PURE__ */ jsx14("span", { style: { backgroundColor: isLight ? "#fff" : "#1e293b", padding: "0 8px", position: "relative", zIndex: 1 }, children: "Or continue with email" }),
1280
+ /* @__PURE__ */ jsx14("div", { style: { position: "absolute", top: "50%", left: 0, right: 0, borderTop: isLight ? "1px solid #e2e8f0" : "1px solid #334155", zIndex: 0 } })
1281
+ ] }),
1282
+ showEmailLogin && /* @__PURE__ */ jsxs12("form", { onSubmit: handleSubmit, style: styles.form, className: "primus-form", children: [
1283
+ /* @__PURE__ */ jsxs12("div", { children: [
1284
+ /* @__PURE__ */ jsx14("label", { style: currentStyles.label, children: "Email" }),
1285
+ /* @__PURE__ */ jsx14(
1286
+ "input",
1287
+ {
1288
+ type: "text",
1289
+ value: username,
1290
+ onChange: (e) => setUsername(e.target.value),
1291
+ style: currentStyles.input,
1292
+ placeholder: "you@example.com"
1293
+ }
1294
+ )
1295
+ ] }),
1296
+ /* @__PURE__ */ jsxs12("div", { children: [
1297
+ /* @__PURE__ */ jsx14("label", { style: currentStyles.label, children: "Password" }),
1298
+ /* @__PURE__ */ jsx14(
1299
+ "input",
1300
+ {
1301
+ type: "password",
1302
+ value: password,
1303
+ onChange: (e) => setPassword(e.target.value),
1304
+ style: currentStyles.input,
1305
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"
1306
+ }
1307
+ )
1308
+ ] }),
1309
+ /* @__PURE__ */ jsx14(
1310
+ "button",
1311
+ {
1312
+ type: "submit",
1313
+ disabled: loading,
1314
+ style: { ...currentStyles.submitBtn, opacity: loading ? 0.7 : 1 },
1315
+ children: loading ? "Signing in..." : "Sign In"
1316
+ }
1317
+ )
1318
+ ] }),
1319
+ errorMessage && /* @__PURE__ */ jsx14("p", { style: styles.error, children: errorMessage })
1320
+ ] });
1321
+ if (variant === "embedded") {
1322
+ return content;
1323
+ }
1324
+ return /* @__PURE__ */ jsx14("div", { style: { ...currentStyles.container, background: isLight ? "#f8fafc" : "#0f172a" }, className: `primus-login ${isDark ? "dark" : ""}`, children: content });
1325
+ }
1326
+ var LoginPage = PrimusLogin;
1327
+
1115
1328
  // src/components/shared/Button.tsx
1116
- import React13 from "react";
1329
+ import React14 from "react";
1117
1330
  import { jsx as jsx15 } from "react/jsx-runtime";
1118
- var Button = React13.forwardRef(
1331
+ var Button = React14.forwardRef(
1119
1332
  ({ style, variant = "primary", size = "md", color = "sapphire", disabled, ...props }, ref) => {
1120
- const [isHovered, setIsHovered] = React13.useState(false);
1333
+ const [isHovered, setIsHovered] = React14.useState(false);
1121
1334
  const colorStyles = {
1122
1335
  sapphire: {
1123
1336
  solid: "#1341a7",
@@ -1256,6 +1469,51 @@ var UserProfile = ({
1256
1469
  ] });
1257
1470
  };
1258
1471
 
1472
+ // src/hooks/usePrimusFetch.ts
1473
+ import { useCallback as useCallback3 } from "react";
1474
+ function usePrimusFetch() {
1475
+ const { logout, csrfCookieName = "XSRF-TOKEN", csrfHeaderName = "X-Primus-CSRF" } = usePrimusAuth();
1476
+ const getCookie = useCallback3((name) => {
1477
+ if (typeof document === "undefined") return null;
1478
+ try {
1479
+ const matches = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1") + "=([^;]*)"));
1480
+ return matches ? decodeURIComponent(matches[1]) : null;
1481
+ } catch {
1482
+ return null;
1483
+ }
1484
+ }, []);
1485
+ const primusFetch = useCallback3(async (input, init) => {
1486
+ const { skipAuth, ...fetchInit } = init || {};
1487
+ const config = {
1488
+ ...fetchInit,
1489
+ headers: new Headers(fetchInit.headers)
1490
+ };
1491
+ if (!skipAuth) {
1492
+ config.credentials = "include";
1493
+ }
1494
+ const method = (config.method || "GET").toUpperCase();
1495
+ if (!["GET", "HEAD", "OPTIONS"].includes(method)) {
1496
+ const csrfToken = getCookie(csrfCookieName);
1497
+ if (csrfToken) {
1498
+ config.headers.set(csrfHeaderName, csrfToken);
1499
+ }
1500
+ }
1501
+ try {
1502
+ const response = await window.fetch(input, config);
1503
+ if (response.status === 401 && !skipAuth) {
1504
+ console.debug("[PrimusFetch] 401 Unauthorized detected. triggering logout.");
1505
+ logout();
1506
+ }
1507
+ return response;
1508
+ } catch (error) {
1509
+ throw error;
1510
+ }
1511
+ }, [getCookie, logout, csrfCookieName, csrfHeaderName]);
1512
+ return {
1513
+ fetch: primusFetch
1514
+ };
1515
+ }
1516
+
1259
1517
  // src/hooks/useNotifications.ts
1260
1518
  import { useState as useState15, useEffect as useEffect9, useMemo } from "react";
1261
1519
  var useNotifications = ({
@@ -1399,7 +1657,7 @@ var PrimusNotificationFeed = ({ useMock, mockData, apiUrl, className }) => {
1399
1657
  };
1400
1658
 
1401
1659
  // src/components/notifications/PrimusNotificationCenter.tsx
1402
- import { useState as useState16, useEffect as useEffect10, useCallback as useCallback3 } from "react";
1660
+ import { useState as useState16, useEffect as useEffect10, useCallback as useCallback4 } from "react";
1403
1661
  import { Bell, Send, X, Check, AlertTriangle, Info, AlertCircle } from "lucide-react";
1404
1662
  import { Fragment as Fragment4, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1405
1663
  var API_URL = "http://localhost:5222";
@@ -1421,7 +1679,7 @@ function PrimusNotificationCenter({
1421
1679
  const [newMessage, setNewMessage] = useState16("");
1422
1680
  const [newType, setNewType] = useState16("info");
1423
1681
  const [sending, setSending] = useState16(false);
1424
- const fetchNotifications = useCallback3(async () => {
1682
+ const fetchNotifications = useCallback4(async () => {
1425
1683
  try {
1426
1684
  const response = await fetch(`${apiUrl}/api/notifications`);
1427
1685
  if (response.ok) {
@@ -1645,7 +1903,7 @@ var NotificationBell = PrimusNotificationCenter;
1645
1903
  var PrimusNotifications = PrimusNotificationCenter;
1646
1904
 
1647
1905
  // src/hooks/useRealtimeNotifications.ts
1648
- import { useState as useState17, useEffect as useEffect11, useCallback as useCallback4 } from "react";
1906
+ import { useState as useState17, useEffect as useEffect11, useCallback as useCallback5 } from "react";
1649
1907
  var useRealtimeNotifications = (options) => {
1650
1908
  const { apiUrl, pollInterval = 3e3, userId } = options;
1651
1909
  const [notifications, setNotifications] = useState17([]);
@@ -1653,7 +1911,7 @@ var useRealtimeNotifications = (options) => {
1653
1911
  const [loading, setLoading] = useState17(true);
1654
1912
  const [error, setError] = useState17(null);
1655
1913
  const baseUrl = `${apiUrl}/api/notifications`;
1656
- const fetchNotifications = useCallback4(async () => {
1914
+ const fetchNotifications = useCallback5(async () => {
1657
1915
  try {
1658
1916
  const url = userId ? `${baseUrl}?userId=${userId}` : baseUrl;
1659
1917
  const response = await fetch(url);
@@ -1669,7 +1927,7 @@ var useRealtimeNotifications = (options) => {
1669
1927
  setLoading(false);
1670
1928
  }
1671
1929
  }, [baseUrl, userId]);
1672
- const sendNotification = useCallback4(async (title, message, type = "info") => {
1930
+ const sendNotification = useCallback5(async (title, message, type = "info") => {
1673
1931
  try {
1674
1932
  const response = await fetch(baseUrl, {
1675
1933
  method: "POST",
@@ -1685,7 +1943,7 @@ var useRealtimeNotifications = (options) => {
1685
1943
  return false;
1686
1944
  }
1687
1945
  }, [baseUrl, userId, fetchNotifications]);
1688
- const markAsRead = useCallback4(async (id) => {
1946
+ const markAsRead = useCallback5(async (id) => {
1689
1947
  try {
1690
1948
  await fetch(`${baseUrl}/${id}/read`, { method: "PUT" });
1691
1949
  setNotifications((prev) => prev.map((n) => n.id === id ? { ...n, read: true } : n));
@@ -1693,13 +1951,13 @@ var useRealtimeNotifications = (options) => {
1693
1951
  } catch {
1694
1952
  }
1695
1953
  }, [baseUrl]);
1696
- const markAllAsRead = useCallback4(async () => {
1954
+ const markAllAsRead = useCallback5(async () => {
1697
1955
  const unread = notifications.filter((n) => !n.read);
1698
1956
  await Promise.all(unread.map((n) => fetch(`${baseUrl}/${n.id}/read`, { method: "PUT" })));
1699
1957
  setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));
1700
1958
  setUnreadCount(0);
1701
1959
  }, [notifications, baseUrl]);
1702
- const deleteNotification = useCallback4(async (id) => {
1960
+ const deleteNotification = useCallback5(async (id) => {
1703
1961
  try {
1704
1962
  await fetch(`${baseUrl}/${id}`, { method: "DELETE" });
1705
1963
  setNotifications((prev) => prev.filter((n) => n.id !== id));
@@ -1728,7 +1986,7 @@ var useRealtimeNotifications = (options) => {
1728
1986
  import { useState as useState18 } from "react";
1729
1987
 
1730
1988
  // src/components/shared/Input.tsx
1731
- import React14 from "react";
1989
+ import React15 from "react";
1732
1990
  import { clsx as clsx2 } from "clsx";
1733
1991
  import { XMarkIcon } from "@heroicons/react/20/solid";
1734
1992
  import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -1742,20 +2000,48 @@ var iconSizeClasses = {
1742
2000
  md: "w-5 h-5 [&>*]:w-full [&>*]:h-full",
1743
2001
  lg: "w-6 h-6 [&>*]:w-full [&>*]:h-full"
1744
2002
  };
1745
- var Input = React14.forwardRef(
1746
- ({ className, style, label, error, disabled, startIcon, endIcon, onClear, value, onChange, size = "md", loading = false, ...props }, ref) => {
2003
+ var Input = React15.forwardRef(
2004
+ ({
2005
+ className,
2006
+ style,
2007
+ label,
2008
+ error,
2009
+ disabled,
2010
+ startIcon,
2011
+ endIcon,
2012
+ onClear,
2013
+ value,
2014
+ onChange,
2015
+ onValueChange,
2016
+ size = "md",
2017
+ loading = false,
2018
+ autoSelect = false,
2019
+ onFocus,
2020
+ ...props
2021
+ }, ref) => {
2022
+ const handleFocus = (e) => {
2023
+ if (autoSelect) {
2024
+ e.target.select();
2025
+ }
2026
+ onFocus?.(e);
2027
+ };
2028
+ const handleChange = (e) => {
2029
+ onChange?.(e);
2030
+ onValueChange?.(e.target.value);
2031
+ };
1747
2032
  const hasValue = value !== void 0 && value !== "" && value !== null;
2033
+ const isDisabled = disabled || loading;
1748
2034
  return /* @__PURE__ */ jsxs16("div", { className: clsx2("w-full", className), style, children: [
1749
2035
  label && /* @__PURE__ */ jsx19("label", { className: clsx2(
1750
2036
  "block font-medium mb-1.5",
1751
2037
  size === "sm" ? "text-xs" : "text-sm",
1752
- disabled ? "text-gray-400 opacity-70" : "text-gray-700"
2038
+ isDisabled ? "text-gray-400 opacity-70" : "text-gray-700"
1753
2039
  ), children: label }),
1754
2040
  /* @__PURE__ */ jsxs16("div", { className: clsx2(
1755
2041
  "relative flex items-center w-full rounded-lg transition-all duration-200 ease-in-out bg-white overflow-hidden",
1756
2042
  "border",
1757
2043
  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"
2044
+ isDisabled && "bg-gray-50 opacity-60 cursor-not-allowed"
1759
2045
  ), children: [
1760
2046
  startIcon && /* @__PURE__ */ jsx19("div", { className: clsx2(
1761
2047
  "flex-shrink-0 pl-3 pr-2 text-gray-400 select-none pointer-events-none flex items-center justify-center",
@@ -1765,9 +2051,10 @@ var Input = React14.forwardRef(
1765
2051
  "input",
1766
2052
  {
1767
2053
  ref,
1768
- disabled,
2054
+ disabled: isDisabled,
1769
2055
  value,
1770
- onChange,
2056
+ onChange: handleChange,
2057
+ onFocus: handleFocus,
1771
2058
  className: clsx2(
1772
2059
  "flex-1 w-full border-none bg-transparent p-0 placeholder:text-gray-400 focus:ring-0 outline-none",
1773
2060
  sizeClasses[size],
@@ -1778,7 +2065,7 @@ var Input = React14.forwardRef(
1778
2065
  ...props
1779
2066
  }
1780
2067
  ),
1781
- onClear && hasValue && !disabled && !loading && /* @__PURE__ */ jsx19("div", { className: "flex-shrink-0 pr-2 flex items-center justify-center", children: /* @__PURE__ */ jsx19(
2068
+ onClear && hasValue && !isDisabled && /* @__PURE__ */ jsx19("div", { className: "flex-shrink-0 pr-2 flex items-center justify-center", children: /* @__PURE__ */ jsx19(
1782
2069
  "button",
1783
2070
  {
1784
2071
  type: "button",
@@ -1786,7 +2073,8 @@ var Input = React14.forwardRef(
1786
2073
  e.stopPropagation();
1787
2074
  onClear();
1788
2075
  },
1789
- className: "p-1 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors",
2076
+ 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",
2077
+ tabIndex: 0,
1790
2078
  children: /* @__PURE__ */ jsx19(XMarkIcon, { className: "h-4 w-4" })
1791
2079
  }
1792
2080
  ) }),
@@ -2394,7 +2682,7 @@ var PrimusSidebar = ({
2394
2682
  };
2395
2683
 
2396
2684
  // src/components/layout/PrimusHeader.tsx
2397
- import React18 from "react";
2685
+ import React19 from "react";
2398
2686
  import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
2399
2687
  var PrimusHeader = ({
2400
2688
  title,
@@ -2405,7 +2693,7 @@ var PrimusHeader = ({
2405
2693
  }) => {
2406
2694
  return /* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between w-full", children: [
2407
2695
  /* @__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: [
2696
+ 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
2697
  index > 0 && /* @__PURE__ */ jsx30("span", { className: "text-gray-500", children: "/" }),
2410
2698
  /* @__PURE__ */ jsx30("span", { className: index === breadcrumbs.length - 1 ? "text-white" : "text-gray-400 hover:text-white cursor-pointer", children: crumb.label })
2411
2699
  ] }, index)) }),
@@ -2431,9 +2719,30 @@ var PrimusHeader = ({
2431
2719
  ] });
2432
2720
  };
2433
2721
 
2722
+ // src/components/layout/PrimusSection.tsx
2723
+ import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
2724
+ var PrimusSection = ({
2725
+ title,
2726
+ subtitle,
2727
+ children,
2728
+ className = "",
2729
+ actions
2730
+ }) => {
2731
+ return /* @__PURE__ */ jsxs28("section", { className: `py-6 ${className}`, children: [
2732
+ /* @__PURE__ */ jsxs28("div", { className: "flex items-end justify-between mb-6 border-b border-gray-200 dark:border-gray-800 pb-4", children: [
2733
+ /* @__PURE__ */ jsxs28("div", { children: [
2734
+ /* @__PURE__ */ jsx31("h2", { className: "text-2xl font-bold tracking-tight text-gray-900 dark:text-white", children: title }),
2735
+ subtitle && /* @__PURE__ */ jsx31("p", { className: "mt-1 text-base text-gray-500 dark:text-gray-400", children: subtitle })
2736
+ ] }),
2737
+ actions && /* @__PURE__ */ jsx31("div", { className: "flex items-center gap-2", children: actions })
2738
+ ] }),
2739
+ /* @__PURE__ */ jsx31("div", { children })
2740
+ ] });
2741
+ };
2742
+
2434
2743
  // src/components/crud/PrimusDataTable.tsx
2435
2744
  import { useState as useState21, useMemo as useMemo2 } from "react";
2436
- import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
2745
+ import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
2437
2746
  function PrimusDataTable({
2438
2747
  data,
2439
2748
  columns,
@@ -2512,10 +2821,10 @@ function PrimusDataTable({
2512
2821
  onSelectionChange?.(scopeKeys);
2513
2822
  }
2514
2823
  };
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(
2824
+ return /* @__PURE__ */ jsxs29("div", { className: "flex flex-col space-y-4", children: [
2825
+ searchable && /* @__PURE__ */ jsx32("div", { className: "flex items-center justify-between px-1", children: /* @__PURE__ */ jsxs29("div", { className: "relative group", children: [
2826
+ /* @__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" }) }) }),
2827
+ /* @__PURE__ */ jsx32(
2519
2828
  "input",
2520
2829
  {
2521
2830
  type: "text",
@@ -2531,9 +2840,9 @@ function PrimusDataTable({
2531
2840
  }
2532
2841
  )
2533
2842
  ] }) }),
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(
2843
+ /* @__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: [
2844
+ /* @__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: [
2845
+ selectable && /* @__PURE__ */ jsx32("th", { className: "w-12 px-6 py-4", children: /* @__PURE__ */ jsx32(
2537
2846
  "input",
2538
2847
  {
2539
2848
  type: "checkbox",
@@ -2542,25 +2851,25 @@ function PrimusDataTable({
2542
2851
  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
2852
  }
2544
2853
  ) }),
2545
- columns.map((col) => /* @__PURE__ */ jsx31(
2854
+ columns.map((col) => /* @__PURE__ */ jsx32(
2546
2855
  "th",
2547
2856
  {
2548
2857
  className: `px-6 py-4 text-xs font-semibold text-gray-400 uppercase tracking-wider ${col.sortable ? "cursor-pointer hover:text-white group" : ""}`,
2549
2858
  style: { width: col.width },
2550
2859
  onClick: () => col.sortable && handleSort(String(col.key)),
2551
- children: /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-2", children: [
2860
+ children: /* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-2", children: [
2552
2861
  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" })
2862
+ 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
2863
  ] })
2555
2864
  },
2556
2865
  String(col.key)
2557
2866
  )),
2558
- actions && /* @__PURE__ */ jsx31("th", { className: "w-24 px-6 py-4 text-right text-xs font-semibold text-gray-400 uppercase tracking-wider" })
2867
+ actions && /* @__PURE__ */ jsx32("th", { className: "w-24 px-6 py-4 text-right text-xs font-semibold text-gray-400 uppercase tracking-wider" })
2559
2868
  ] }) }),
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(
2869
+ /* @__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: [
2870
+ /* @__PURE__ */ jsx32("div", { className: "w-6 h-6 border-2 border-purple-500/50 border-t-purple-500 rounded-full animate-spin" }),
2871
+ /* @__PURE__ */ jsx32("span", { className: "text-sm font-medium", children: "Loading data..." })
2872
+ ] }) }) }) : 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
2873
  "tr",
2565
2874
  {
2566
2875
  onClick: () => onRowClick?.(row),
@@ -2570,7 +2879,7 @@ function PrimusDataTable({
2570
2879
  ${selectedKeys.includes(row[rowKey]) ? "bg-purple-500/10 hover:bg-purple-500/20" : ""}
2571
2880
  `,
2572
2881
  children: [
2573
- selectable && /* @__PURE__ */ jsx31("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx31(
2882
+ selectable && /* @__PURE__ */ jsx32("td", { className: "px-6 py-4", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx32(
2574
2883
  "input",
2575
2884
  {
2576
2885
  type: "checkbox",
@@ -2579,15 +2888,15 @@ function PrimusDataTable({
2579
2888
  className: "rounded border-gray-600 bg-gray-800 text-purple-600 focus:ring-offset-gray-900 focus:ring-purple-500 cursor-pointer"
2580
2889
  }
2581
2890
  ) }),
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) }) })
2891
+ 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))),
2892
+ 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
2893
  ]
2585
2894
  },
2586
2895
  String(row[rowKey])
2587
2896
  )) })
2588
2897
  ] }) }) }),
2589
- paginated && totalPages > 1 && /* @__PURE__ */ jsxs28("div", { className: "flex items-center justify-between text-sm text-gray-400 px-2", children: [
2590
- /* @__PURE__ */ jsx31(
2898
+ paginated && totalPages > 1 && /* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-between text-sm text-gray-400 px-2", children: [
2899
+ /* @__PURE__ */ jsx32(
2591
2900
  "button",
2592
2901
  {
2593
2902
  type: "button",
@@ -2597,13 +2906,13 @@ function PrimusDataTable({
2597
2906
  children: "Previous"
2598
2907
  }
2599
2908
  ),
2600
- /* @__PURE__ */ jsxs28("span", { children: [
2909
+ /* @__PURE__ */ jsxs29("span", { children: [
2601
2910
  "Page ",
2602
2911
  currentPageIndex + 1,
2603
2912
  " of ",
2604
2913
  totalPages
2605
2914
  ] }),
2606
- /* @__PURE__ */ jsx31(
2915
+ /* @__PURE__ */ jsx32(
2607
2916
  "button",
2608
2917
  {
2609
2918
  type: "button",
@@ -2618,7 +2927,7 @@ function PrimusDataTable({
2618
2927
  }
2619
2928
 
2620
2929
  // src/components/crud/PrimusModal.tsx
2621
- import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
2930
+ import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2622
2931
  var PrimusModal = ({
2623
2932
  open,
2624
2933
  onClose,
@@ -2634,34 +2943,34 @@ var PrimusModal = ({
2634
2943
  lg: "max-w-lg",
2635
2944
  xl: "max-w-xl"
2636
2945
  };
2637
- return /* @__PURE__ */ jsxs29("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2638
- /* @__PURE__ */ jsx32(
2946
+ return /* @__PURE__ */ jsxs30("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2947
+ /* @__PURE__ */ jsx33(
2639
2948
  "div",
2640
2949
  {
2641
2950
  className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
2642
2951
  onClick: onClose
2643
2952
  }
2644
2953
  ),
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(
2954
+ /* @__PURE__ */ jsxs30("div", { className: `relative w-full ${sizeClasses2[size]} mx-4 bg-gray-800 rounded-xl border border-gray-700 shadow-2xl`, children: [
2955
+ title && /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between px-6 py-4 border-b border-gray-700", children: [
2956
+ /* @__PURE__ */ jsx33("h2", { className: "text-lg font-semibold text-white", children: title }),
2957
+ /* @__PURE__ */ jsx33(
2649
2958
  "button",
2650
2959
  {
2651
2960
  onClick: onClose,
2652
2961
  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" }) })
2962
+ 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
2963
  }
2655
2964
  )
2656
2965
  ] }),
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 })
2966
+ /* @__PURE__ */ jsx33("div", { className: "p-6", children }),
2967
+ 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
2968
  ] })
2660
2969
  ] });
2661
2970
  };
2662
2971
 
2663
2972
  // src/components/dashboard/PrimusDashboard.tsx
2664
- import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2973
+ import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
2665
2974
  var PrimusStatCard = ({
2666
2975
  title,
2667
2976
  value,
@@ -2697,35 +3006,35 @@ var PrimusStatCard = ({
2697
3006
  const linePath = points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
2698
3007
  const areaPath = `${linePath} L 100 100 L 0 100 Z`;
2699
3008
  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" })
3009
+ 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: [
3010
+ /* @__PURE__ */ jsx34("defs", { children: /* @__PURE__ */ jsxs31("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
3011
+ /* @__PURE__ */ jsx34("stop", { offset: "0%", stopColor: "currentColor", stopOpacity: "0.25" }),
3012
+ /* @__PURE__ */ jsx34("stop", { offset: "100%", stopColor: "currentColor", stopOpacity: "0" })
2704
3013
  ] }) }),
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" })
3014
+ /* @__PURE__ */ jsx34("path", { d: areaPath, fill: `url(#${gradientId})`, stroke: "none" }),
3015
+ /* @__PURE__ */ jsx34("path", { d: linePath, fill: "none", stroke: "currentColor", strokeWidth: "1.8", opacity: "0.6" })
2707
3016
  ] });
2708
3017
  };
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: [
3018
+ 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: [
3019
+ /* @__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" }),
3020
+ /* @__PURE__ */ jsxs31("div", { className: "p-6 relative z-10", children: [
3021
+ /* @__PURE__ */ jsxs31("div", { className: "flex items-start justify-between mb-4", children: [
3022
+ /* @__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" }) }),
3023
+ 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
3024
  changeIcons[change.type],
2716
3025
  " ",
2717
3026
  Math.abs(change.value),
2718
3027
  "%"
2719
3028
  ] })
2720
3029
  ] }),
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 })
3030
+ /* @__PURE__ */ jsxs31("div", { children: [
3031
+ /* @__PURE__ */ jsx34("h3", { className: "text-sm font-medium text-gray-400 tracking-wide", children: title }),
3032
+ /* @__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 }) }),
3033
+ description && /* @__PURE__ */ jsx34("p", { className: "text-xs text-gray-500 mt-2 font-medium", children: description })
2725
3034
  ] })
2726
3035
  ] }),
2727
3036
  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"}` })
3037
+ /* @__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
3038
  ] });
2730
3039
  };
2731
3040
  var PrimusDashboard = ({
@@ -2734,13 +3043,13 @@ var PrimusDashboard = ({
2734
3043
  subtitle,
2735
3044
  actions
2736
3045
  }) => {
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 })
3046
+ return /* @__PURE__ */ jsxs31("div", { className: "space-y-8 animate-enter", children: [
3047
+ (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: [
3048
+ /* @__PURE__ */ jsxs31("div", { children: [
3049
+ 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 }),
3050
+ subtitle && /* @__PURE__ */ jsx34("p", { className: "text-gray-400 mt-2 text-lg font-light leading-relaxed", children: subtitle })
2742
3051
  ] }),
2743
- actions && /* @__PURE__ */ jsx33("div", { className: "flex items-center gap-3", children: actions })
3052
+ actions && /* @__PURE__ */ jsx34("div", { className: "flex items-center gap-3", children: actions })
2744
3053
  ] }),
2745
3054
  children
2746
3055
  ] });
@@ -2755,25 +3064,119 @@ var DashboardGrid = ({
2755
3064
  3: "grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
2756
3065
  4: "grid-cols-1 md:grid-cols-2 lg:grid-cols-4"
2757
3066
  };
2758
- return /* @__PURE__ */ jsx33("div", { className: `grid gap-6 ${colClasses[columns]}`, children });
3067
+ return /* @__PURE__ */ jsx34("div", { className: `grid gap-6 ${colClasses[columns]}`, children });
2759
3068
  };
2760
3069
 
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
- }) => {
3070
+ // src/components/shared/Card.tsx
3071
+ import React21 from "react";
3072
+ import { jsx as jsx35 } from "react/jsx-runtime";
3073
+ var Card = React21.forwardRef(
3074
+ ({ style, variant = "default", padding = "md", children, ...props }, ref) => {
3075
+ const [isHovered, setIsHovered] = React21.useState(false);
3076
+ const paddingStyles = {
3077
+ none: "0",
3078
+ sm: "0.75rem",
3079
+ md: "1.5rem",
3080
+ lg: "2rem"
3081
+ };
3082
+ const variantStyles = {
3083
+ default: {
3084
+ normal: {
3085
+ backgroundColor: "#ffffff",
3086
+ border: "1px solid #e5e7eb",
3087
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)"
3088
+ },
3089
+ hover: {
3090
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
3091
+ }
3092
+ },
3093
+ outlined: {
3094
+ normal: {
3095
+ backgroundColor: "#ffffff",
3096
+ border: "2px solid #e5e7eb",
3097
+ boxShadow: "none"
3098
+ },
3099
+ hover: {
3100
+ borderColor: "#d1d5db"
3101
+ }
3102
+ },
3103
+ elevated: {
3104
+ normal: {
3105
+ backgroundColor: "#ffffff",
3106
+ border: "none",
3107
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)"
3108
+ },
3109
+ hover: {
3110
+ boxShadow: "0 10px 15px rgba(0, 0, 0, 0.15)",
3111
+ transform: "translateY(-2px)"
3112
+ }
3113
+ }
3114
+ };
3115
+ const baseStyles = {
3116
+ borderRadius: "0.5rem",
3117
+ padding: paddingStyles[padding],
3118
+ transition: "all 0.2s ease"
3119
+ };
3120
+ const currentVariant = variantStyles[variant];
3121
+ const combinedStyles = {
3122
+ ...baseStyles,
3123
+ ...currentVariant.normal,
3124
+ ...isHovered ? currentVariant.hover : {},
3125
+ ...style
3126
+ };
3127
+ return /* @__PURE__ */ jsx35(
3128
+ "div",
3129
+ {
3130
+ ref,
3131
+ style: combinedStyles,
3132
+ onMouseEnter: () => setIsHovered(true),
3133
+ onMouseLeave: () => setIsHovered(false),
3134
+ ...props,
3135
+ children
3136
+ }
3137
+ );
3138
+ }
3139
+ );
3140
+ Card.displayName = "Card";
3141
+
3142
+ // src/components/dashboard/PrimusSummaryCard.tsx
3143
+ import { jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
3144
+ var PrimusSummaryCard = ({
3145
+ title,
3146
+ subtitle,
3147
+ actionLabel,
3148
+ onAction,
3149
+ children,
3150
+ className
3151
+ }) => {
3152
+ return /* @__PURE__ */ jsx36(Card, { className, children: /* @__PURE__ */ jsxs32("div", { className: "p-6", children: [
3153
+ /* @__PURE__ */ jsxs32("div", { className: "flex items-center justify-between mb-4", children: [
3154
+ /* @__PURE__ */ jsxs32("div", { children: [
3155
+ /* @__PURE__ */ jsx36("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white", children: title }),
3156
+ subtitle && /* @__PURE__ */ jsx36("p", { className: "text-sm text-gray-500 dark:text-gray-400 mt-1", children: subtitle })
3157
+ ] }),
3158
+ actionLabel && onAction && /* @__PURE__ */ jsx36(Button, { variant: "outline", size: "sm", onClick: onAction, children: actionLabel })
3159
+ ] }),
3160
+ /* @__PURE__ */ jsx36("div", { className: "mt-4", children })
3161
+ ] }) });
3162
+ };
3163
+
3164
+ // src/components/dashboard/PrimusActivityFeed.tsx
3165
+ import { useMemo as useMemo3 } from "react";
3166
+ import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
3167
+ var statusClasses = {
3168
+ success: "bg-emerald-500/10 text-emerald-300 border-emerald-500/30",
3169
+ warning: "bg-amber-500/10 text-amber-300 border-amber-500/30",
3170
+ error: "bg-rose-500/10 text-rose-300 border-rose-500/30",
3171
+ info: "bg-blue-500/10 text-blue-300 border-blue-500/30"
3172
+ };
3173
+ var PrimusActivityFeed = ({
3174
+ items,
3175
+ maxItems = 10,
3176
+ showTimestamps = true,
3177
+ groupByDate = false,
3178
+ loading = false
3179
+ }) => {
2777
3180
  const visibleItems = useMemo3(() => items.slice(0, maxItems), [items, maxItems]);
2778
3181
  const groups = useMemo3(() => {
2779
3182
  if (!groupByDate) {
@@ -2789,18 +3192,18 @@ var PrimusActivityFeed = ({
2789
3192
  return Array.from(map.entries()).map(([label, groupItems]) => ({ label, items: groupItems }));
2790
3193
  }, [groupByDate, visibleItems]);
2791
3194
  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..." });
3195
+ 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
3196
  }
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) })
3197
+ 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: [
3198
+ group.label && /* @__PURE__ */ jsx37("div", { className: "text-xs uppercase tracking-wide text-gray-500 mb-3", children: group.label }),
3199
+ /* @__PURE__ */ jsx37("div", { className: "space-y-4", children: group.items.map((item, itemIndex) => /* @__PURE__ */ jsxs33("div", { className: "flex items-start gap-4", children: [
3200
+ /* @__PURE__ */ jsx37("div", { className: `mt-1 h-2.5 w-2.5 rounded-full border ${statusClasses[item.status ?? "info"]}` }),
3201
+ /* @__PURE__ */ jsxs33("div", { className: "flex-1", children: [
3202
+ /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between gap-4", children: [
3203
+ /* @__PURE__ */ jsx37("div", { className: "text-sm font-medium text-gray-100", children: item.title }),
3204
+ showTimestamps && /* @__PURE__ */ jsx37("div", { className: "text-xs text-gray-500", children: formatTime(item.timestamp) })
2802
3205
  ] }),
2803
- item.description && /* @__PURE__ */ jsx34("div", { className: "text-xs text-gray-400 mt-1", children: item.description })
3206
+ item.description && /* @__PURE__ */ jsx37("div", { className: "text-xs text-gray-400 mt-1", children: item.description })
2804
3207
  ] })
2805
3208
  ] }, item.id ?? `${itemIndex}-${item.title}`)) })
2806
3209
  ] }, `${group.label}-${index}`)) });
@@ -2827,12 +3230,12 @@ var formatTime = (value) => {
2827
3230
  };
2828
3231
 
2829
3232
  // src/components/charts/PrimusChartBase.tsx
2830
- import { useEffect as useEffect14, useMemo as useMemo4, useRef } from "react";
3233
+ import { useEffect as useEffect14, useMemo as useMemo4, useRef as useRef2 } from "react";
2831
3234
  import {
2832
3235
  Chart,
2833
3236
  registerables
2834
3237
  } from "chart.js";
2835
- import { jsx as jsx35 } from "react/jsx-runtime";
3238
+ import { jsx as jsx38 } from "react/jsx-runtime";
2836
3239
  var registered = false;
2837
3240
  var ensureRegistered = () => {
2838
3241
  if (!registered) {
@@ -2855,8 +3258,8 @@ var PrimusChartBase = ({
2855
3258
  className,
2856
3259
  datasetTransform
2857
3260
  }) => {
2858
- const canvasRef = useRef(null);
2859
- const chartRef = useRef(null);
3261
+ const canvasRef = useRef2(null);
3262
+ const chartRef = useRef2(null);
2860
3263
  const builtData = useMemo4(() => {
2861
3264
  if (data) {
2862
3265
  return data;
@@ -2923,13 +3326,13 @@ var PrimusChartBase = ({
2923
3326
  chartRef.current = null;
2924
3327
  };
2925
3328
  }, [type, builtData, builtOptions]);
2926
- return /* @__PURE__ */ jsx35("div", { className, style: { height, width }, children: /* @__PURE__ */ jsx35("canvas", { ref: canvasRef, "aria-label": ariaLabel, role: "img" }) });
3329
+ return /* @__PURE__ */ jsx38("div", { className, style: { height, width }, children: /* @__PURE__ */ jsx38("canvas", { ref: canvasRef, "aria-label": ariaLabel, role: "img" }) });
2927
3330
  };
2928
3331
 
2929
3332
  // src/components/charts/PrimusLineChart.tsx
2930
- import { jsx as jsx36 } from "react/jsx-runtime";
3333
+ import { jsx as jsx39 } from "react/jsx-runtime";
2931
3334
  var PrimusLineChart = (props) => {
2932
- return /* @__PURE__ */ jsx36(
3335
+ return /* @__PURE__ */ jsx39(
2933
3336
  PrimusChartBase,
2934
3337
  {
2935
3338
  ...props,
@@ -2947,9 +3350,9 @@ var PrimusLineChart = (props) => {
2947
3350
  };
2948
3351
 
2949
3352
  // src/components/charts/PrimusAreaChart.tsx
2950
- import { jsx as jsx37 } from "react/jsx-runtime";
3353
+ import { jsx as jsx40 } from "react/jsx-runtime";
2951
3354
  var PrimusAreaChart = (props) => {
2952
- return /* @__PURE__ */ jsx37(
3355
+ return /* @__PURE__ */ jsx40(
2953
3356
  PrimusChartBase,
2954
3357
  {
2955
3358
  ...props,
@@ -2967,7 +3370,7 @@ var PrimusAreaChart = (props) => {
2967
3370
  };
2968
3371
 
2969
3372
  // src/components/charts/PrimusBarChart.tsx
2970
- import { jsx as jsx38 } from "react/jsx-runtime";
3373
+ import { jsx as jsx41 } from "react/jsx-runtime";
2971
3374
  var PrimusBarChart = ({ stacked = false, options, ...props }) => {
2972
3375
  const mergedOptions = {
2973
3376
  ...options,
@@ -2977,7 +3380,7 @@ var PrimusBarChart = ({ stacked = false, options, ...props }) => {
2977
3380
  ...options?.scales ?? {}
2978
3381
  }
2979
3382
  };
2980
- return /* @__PURE__ */ jsx38(
3383
+ return /* @__PURE__ */ jsx41(
2981
3384
  PrimusChartBase,
2982
3385
  {
2983
3386
  ...props,
@@ -2993,13 +3396,13 @@ var PrimusBarChart = ({ stacked = false, options, ...props }) => {
2993
3396
  };
2994
3397
 
2995
3398
  // src/components/charts/PrimusPieChart.tsx
2996
- import { jsx as jsx39 } from "react/jsx-runtime";
3399
+ import { jsx as jsx42 } from "react/jsx-runtime";
2997
3400
  var PrimusPieChart = ({ donut = false, cutout = "55%", options, ...props }) => {
2998
3401
  const mergedOptions = {
2999
3402
  ...options,
3000
3403
  cutout: donut ? cutout : void 0
3001
3404
  };
3002
- return /* @__PURE__ */ jsx39(
3405
+ return /* @__PURE__ */ jsx42(
3003
3406
  PrimusChartBase,
3004
3407
  {
3005
3408
  ...props,
@@ -3016,7 +3419,7 @@ var PrimusPieChart = ({ donut = false, cutout = "55%", options, ...props }) => {
3016
3419
 
3017
3420
  // src/components/charts/PrimusSparkline.tsx
3018
3421
  import { useMemo as useMemo5 } from "react";
3019
- import { jsx as jsx40, jsxs as jsxs32 } from "react/jsx-runtime";
3422
+ import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
3020
3423
  var PrimusSparkline = ({
3021
3424
  series = [],
3022
3425
  data,
@@ -3049,7 +3452,7 @@ var PrimusSparkline = ({
3049
3452
  if (!values.length) {
3050
3453
  return null;
3051
3454
  }
3052
- return /* @__PURE__ */ jsxs32(
3455
+ return /* @__PURE__ */ jsxs34(
3053
3456
  "svg",
3054
3457
  {
3055
3458
  className,
@@ -3060,17 +3463,17 @@ var PrimusSparkline = ({
3060
3463
  "aria-label": ariaLabel,
3061
3464
  role: "img",
3062
3465
  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 })
3466
+ type === "area" && /* @__PURE__ */ jsx43("path", { d: areaPath, fill: color, opacity: 0.2, stroke: "none" }),
3467
+ /* @__PURE__ */ jsx43("path", { d: linePath, fill: "none", stroke: color, strokeWidth })
3065
3468
  ]
3066
3469
  }
3067
3470
  );
3068
3471
  };
3069
3472
 
3070
3473
  // 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(
3474
+ import React24 from "react";
3475
+ import { jsx as jsx44, jsxs as jsxs35 } from "react/jsx-runtime";
3476
+ var Checkbox = React24.forwardRef(
3074
3477
  ({ style, label, error, disabled, className, ...props }, ref) => {
3075
3478
  const containerStyles = {
3076
3479
  display: "flex",
@@ -3107,9 +3510,9 @@ var Checkbox = React22.forwardRef(
3107
3510
  marginTop: "0.25rem",
3108
3511
  marginLeft: "1.75rem"
3109
3512
  };
3110
- return /* @__PURE__ */ jsxs33("div", { children: [
3111
- /* @__PURE__ */ jsxs33("div", { style: containerStyles, children: [
3112
- /* @__PURE__ */ jsx41("div", { style: checkboxWrapperStyles, children: /* @__PURE__ */ jsx41(
3513
+ return /* @__PURE__ */ jsxs35("div", { children: [
3514
+ /* @__PURE__ */ jsxs35("div", { style: containerStyles, children: [
3515
+ /* @__PURE__ */ jsx44("div", { style: checkboxWrapperStyles, children: /* @__PURE__ */ jsx44(
3113
3516
  "input",
3114
3517
  {
3115
3518
  ref,
@@ -3122,21 +3525,21 @@ var Checkbox = React22.forwardRef(
3122
3525
  ...props
3123
3526
  }
3124
3527
  ) }),
3125
- label && /* @__PURE__ */ jsx41("label", { style: labelStyles, onClick: (e) => {
3528
+ label && /* @__PURE__ */ jsx44("label", { style: labelStyles, onClick: (e) => {
3126
3529
  if (!disabled) {
3127
3530
  const input = e.currentTarget.previousElementSibling?.querySelector("input");
3128
3531
  input?.click();
3129
3532
  }
3130
3533
  }, children: label })
3131
3534
  ] }),
3132
- error && /* @__PURE__ */ jsx41("p", { style: errorTextStyles, children: error })
3535
+ error && /* @__PURE__ */ jsx44("p", { style: errorTextStyles, children: error })
3133
3536
  ] });
3134
3537
  }
3135
3538
  );
3136
3539
  Checkbox.displayName = "Checkbox";
3137
3540
 
3138
3541
  // src/components/shared/RadioGroup.tsx
3139
- import { jsx as jsx42, jsxs as jsxs34 } from "react/jsx-runtime";
3542
+ import { jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
3140
3543
  var RadioGroup = ({
3141
3544
  name,
3142
3545
  options,
@@ -3176,9 +3579,9 @@ var RadioGroup = ({
3176
3579
  color: "#ef4444",
3177
3580
  marginTop: "0.5rem"
3178
3581
  };
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(
3582
+ return /* @__PURE__ */ jsxs36("div", { children: [
3583
+ /* @__PURE__ */ jsx45("div", { style: containerStyles, children: options.map((option) => /* @__PURE__ */ jsxs36("div", { style: optionStyles, children: [
3584
+ /* @__PURE__ */ jsx45(
3182
3585
  "input",
3183
3586
  {
3184
3587
  type: "radio",
@@ -3190,7 +3593,7 @@ var RadioGroup = ({
3190
3593
  style: radioStyles
3191
3594
  }
3192
3595
  ),
3193
- /* @__PURE__ */ jsx42(
3596
+ /* @__PURE__ */ jsx45(
3194
3597
  "label",
3195
3598
  {
3196
3599
  style: {
@@ -3206,17 +3609,17 @@ var RadioGroup = ({
3206
3609
  }
3207
3610
  )
3208
3611
  ] }, option.value)) }),
3209
- error && /* @__PURE__ */ jsx42("p", { style: errorTextStyles, children: error })
3612
+ error && /* @__PURE__ */ jsx45("p", { style: errorTextStyles, children: error })
3210
3613
  ] });
3211
3614
  };
3212
3615
  RadioGroup.displayName = "RadioGroup";
3213
3616
 
3214
3617
  // src/components/shared/Select.tsx
3215
- import React23, { useState as useState22 } from "react";
3618
+ import React25, { useState as useState22 } from "react";
3216
3619
  import { Combobox, Transition as Transition2 } from "@headlessui/react";
3217
3620
  import { CheckIcon as CheckIcon2, ChevronUpDownIcon, XMarkIcon as XMarkIcon3 } from "@heroicons/react/20/solid";
3218
3621
  import { clsx as clsx7 } from "clsx";
3219
- import { Fragment as Fragment5, jsx as jsx43, jsxs as jsxs35 } from "react/jsx-runtime";
3622
+ import { Fragment as Fragment5, jsx as jsx46, jsxs as jsxs37 } from "react/jsx-runtime";
3220
3623
  var Select = ({
3221
3624
  label,
3222
3625
  error,
@@ -3238,7 +3641,7 @@ var Select = ({
3238
3641
  onChange?.(value.filter((v) => v !== valToRemove));
3239
3642
  }
3240
3643
  };
3241
- return /* @__PURE__ */ jsx43("div", { className: clsx7("w-full", className), children: /* @__PURE__ */ jsx43(
3644
+ return /* @__PURE__ */ jsx46("div", { className: clsx7("w-full", className), children: /* @__PURE__ */ jsx46(
3242
3645
  Combobox,
3243
3646
  {
3244
3647
  value,
@@ -3247,21 +3650,21 @@ var Select = ({
3247
3650
  },
3248
3651
  multiple,
3249
3652
  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(
3653
+ children: ({}) => /* @__PURE__ */ jsxs37("div", { className: "relative", children: [
3654
+ label && /* @__PURE__ */ jsx46(Combobox.Label, { className: "block text-sm font-medium text-gray-700 mb-1", children: label }),
3655
+ /* @__PURE__ */ jsxs37("div", { className: clsx7(
3253
3656
  "relative w-full cursor-default overflow-hidden rounded-lg bg-white text-left focus-within:ring-2 focus-within:ring-primus-500",
3254
3657
  "border transition-all duration-200 ease-in-out",
3255
3658
  error ? "border-red-500 focus-within:ring-red-500" : "border-gray-300",
3256
3659
  disabled && "opacity-50 cursor-not-allowed bg-gray-50"
3257
3660
  ), children: [
3258
- /* @__PURE__ */ jsxs35("div", { className: clsx7(
3661
+ /* @__PURE__ */ jsxs37("div", { className: clsx7(
3259
3662
  "flex flex-wrap items-center gap-1.5 w-full py-1.5 pl-3 pr-10 text-sm",
3260
3663
  "min-h-[2.5rem]"
3261
3664
  ), 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(
3665
+ 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: [
3666
+ /* @__PURE__ */ jsx46("span", { className: "truncate", children: getLabel(val) }),
3667
+ /* @__PURE__ */ jsxs37(
3265
3668
  "button",
3266
3669
  {
3267
3670
  type: "button",
@@ -3273,13 +3676,13 @@ var Select = ({
3273
3676
  },
3274
3677
  onMouseDown: (e) => e.preventDefault(),
3275
3678
  children: [
3276
- /* @__PURE__ */ jsx43("span", { className: "sr-only", children: "Remove" }),
3277
- /* @__PURE__ */ jsx43(XMarkIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
3679
+ /* @__PURE__ */ jsx46("span", { className: "sr-only", children: "Remove" }),
3680
+ /* @__PURE__ */ jsx46(XMarkIcon3, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
3278
3681
  ]
3279
3682
  }
3280
3683
  )
3281
3684
  ] }, val)),
3282
- /* @__PURE__ */ jsx43(
3685
+ /* @__PURE__ */ jsx46(
3283
3686
  Combobox.Input,
3284
3687
  {
3285
3688
  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 +3692,7 @@ var Select = ({
3289
3692
  }
3290
3693
  )
3291
3694
  ] }),
3292
- /* @__PURE__ */ jsx43(Combobox.Button, { className: "absolute inset-y-0 right-0 flex items-center pr-2", children: /* @__PURE__ */ jsx43(
3695
+ /* @__PURE__ */ jsx46(Combobox.Button, { className: "absolute inset-y-0 right-0 flex items-center pr-2", children: /* @__PURE__ */ jsx46(
3293
3696
  ChevronUpDownIcon,
3294
3697
  {
3295
3698
  className: "h-5 w-5 text-gray-400",
@@ -3297,15 +3700,15 @@ var Select = ({
3297
3700
  }
3298
3701
  ) })
3299
3702
  ] }),
3300
- /* @__PURE__ */ jsx43(
3703
+ /* @__PURE__ */ jsx46(
3301
3704
  Transition2,
3302
3705
  {
3303
- as: React23.Fragment,
3706
+ as: React25.Fragment,
3304
3707
  leave: "transition ease-in duration-100",
3305
3708
  leaveFrom: "opacity-100",
3306
3709
  leaveTo: "opacity-0",
3307
3710
  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(
3711
+ 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
3712
  Combobox.Option,
3310
3713
  {
3311
3714
  className: ({ active }) => clsx7(
@@ -3314,16 +3717,16 @@ var Select = ({
3314
3717
  ),
3315
3718
  value: option.value,
3316
3719
  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(
3720
+ children: ({ selected, active }) => /* @__PURE__ */ jsxs37(Fragment5, { children: [
3721
+ /* @__PURE__ */ jsx46("span", { className: clsx7("block truncate", selected ? "font-medium" : "font-normal"), children: option.label }),
3722
+ selected ? /* @__PURE__ */ jsx46(
3320
3723
  "span",
3321
3724
  {
3322
3725
  className: clsx7(
3323
3726
  "absolute inset-y-0 left-0 flex items-center pl-3",
3324
3727
  active ? "text-white" : "text-primus-600"
3325
3728
  ),
3326
- children: /* @__PURE__ */ jsx43(CheckIcon2, { className: "h-5 w-5", "aria-hidden": "true" })
3729
+ children: /* @__PURE__ */ jsx46(CheckIcon2, { className: "h-5 w-5", "aria-hidden": "true" })
3327
3730
  }
3328
3731
  ) : null
3329
3732
  ] })
@@ -3332,15 +3735,15 @@ var Select = ({
3332
3735
  )) })
3333
3736
  }
3334
3737
  ),
3335
- error && /* @__PURE__ */ jsx43("p", { className: "mt-1 text-sm text-red-500", children: error })
3738
+ error && /* @__PURE__ */ jsx46("p", { className: "mt-1 text-sm text-red-500", children: error })
3336
3739
  ] })
3337
3740
  }
3338
3741
  ) });
3339
3742
  };
3340
3743
 
3341
3744
  // src/components/shared/Toggle.tsx
3342
- import React24 from "react";
3343
- import { jsx as jsx44, jsxs as jsxs36 } from "react/jsx-runtime";
3745
+ import React26 from "react";
3746
+ import { jsx as jsx47, jsxs as jsxs38 } from "react/jsx-runtime";
3344
3747
  var Toggle = ({
3345
3748
  checked = false,
3346
3749
  onChange,
@@ -3348,7 +3751,7 @@ var Toggle = ({
3348
3751
  label,
3349
3752
  size = "md"
3350
3753
  }) => {
3351
- const [isHovered, setIsHovered] = React24.useState(false);
3754
+ const [isHovered, setIsHovered] = React26.useState(false);
3352
3755
  const sizes = {
3353
3756
  sm: { width: "2.25rem", height: "1.25rem", thumbSize: "0.875rem" },
3354
3757
  md: { width: "2.75rem", height: "1.5rem", thumbSize: "1.125rem" },
@@ -3395,8 +3798,8 @@ var Toggle = ({
3395
3798
  onChange?.(!checked);
3396
3799
  }
3397
3800
  };
3398
- return /* @__PURE__ */ jsxs36("div", { style: containerStyles, children: [
3399
- /* @__PURE__ */ jsx44(
3801
+ return /* @__PURE__ */ jsxs38("div", { style: containerStyles, children: [
3802
+ /* @__PURE__ */ jsx47(
3400
3803
  "div",
3401
3804
  {
3402
3805
  style: switchStyles,
@@ -3412,20 +3815,23 @@ var Toggle = ({
3412
3815
  handleClick();
3413
3816
  }
3414
3817
  },
3415
- children: /* @__PURE__ */ jsx44("div", { style: thumbStyles })
3818
+ children: /* @__PURE__ */ jsx47("div", { style: thumbStyles })
3416
3819
  }
3417
3820
  ),
3418
- label && /* @__PURE__ */ jsx44("label", { style: labelStyles, onClick: handleClick, children: label })
3821
+ label && /* @__PURE__ */ jsx47("label", { style: labelStyles, onClick: handleClick, children: label })
3419
3822
  ] });
3420
3823
  };
3421
3824
  Toggle.displayName = "Toggle";
3422
3825
 
3423
3826
  // 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);
3827
+ import React27 from "react";
3828
+ import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
3829
+ var Textarea = React27.forwardRef(
3830
+ ({ style, label, error, disabled, resize = "vertical", onChange, onValueChange, className, ...props }, ref) => {
3831
+ const handleChange = (e) => {
3832
+ onChange?.(e);
3833
+ onValueChange?.(e.target.value);
3834
+ };
3429
3835
  const containerStyles = {
3430
3836
  width: "100%"
3431
3837
  };
@@ -3433,11 +3839,11 @@ var Textarea = React25.forwardRef(
3433
3839
  fontSize: "0.875rem",
3434
3840
  lineHeight: "1.25rem",
3435
3841
  fontWeight: "500",
3436
- marginBottom: "0.5rem",
3842
+ marginBottom: "0.375rem",
3437
3843
  display: "block",
3438
3844
  color: "#374151",
3439
- cursor: disabled ? "not-allowed" : "default",
3440
- opacity: disabled ? 0.7 : 1
3845
+ opacity: disabled ? 0.7 : 1,
3846
+ cursor: disabled ? "not-allowed" : "default"
3441
3847
  };
3442
3848
  const textareaStyles = {
3443
3849
  display: "flex",
@@ -3450,12 +3856,11 @@ var Textarea = React25.forwardRef(
3450
3856
  fontSize: "0.875rem",
3451
3857
  lineHeight: "1.5rem",
3452
3858
  outline: "none",
3453
- transition: "all 0.2s ease",
3454
- cursor: disabled ? "not-allowed" : "text",
3859
+ transition: "border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out",
3455
3860
  opacity: disabled ? 0.5 : 1,
3861
+ cursor: disabled ? "not-allowed" : "text",
3456
3862
  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"
3863
+ fontFamily: "inherit"
3459
3864
  };
3460
3865
  const errorTextStyles = {
3461
3866
  fontSize: "0.875rem",
@@ -3463,9 +3868,9 @@ var Textarea = React25.forwardRef(
3463
3868
  color: "#ef4444",
3464
3869
  marginTop: "0.25rem"
3465
3870
  };
3466
- return /* @__PURE__ */ jsxs37("div", { style: containerStyles, children: [
3467
- label && /* @__PURE__ */ jsx45("label", { style: labelStyles, children: label }),
3468
- /* @__PURE__ */ jsx45(
3871
+ return /* @__PURE__ */ jsxs39("div", { style: containerStyles, className, children: [
3872
+ label && /* @__PURE__ */ jsx48("label", { style: labelStyles, children: label }),
3873
+ /* @__PURE__ */ jsx48(
3469
3874
  "textarea",
3470
3875
  {
3471
3876
  ref,
@@ -3473,94 +3878,28 @@ var Textarea = React25.forwardRef(
3473
3878
  ...textareaStyles,
3474
3879
  ...style
3475
3880
  },
3476
- onFocus: () => setIsFocused(true),
3477
- onBlur: () => setIsFocused(false),
3478
3881
  disabled,
3882
+ onChange: handleChange,
3883
+ className: `primus-textarea ${error ? "error" : ""}`,
3479
3884
  ...props
3480
3885
  }
3481
3886
  ),
3482
- error && /* @__PURE__ */ jsx45("p", { style: errorTextStyles, children: error })
3887
+ /* @__PURE__ */ jsx48("style", { children: `
3888
+ .primus-textarea:focus {
3889
+ border-color: ${error ? "#ef4444" : "#6366f1"};
3890
+ box-shadow: 0 0 0 1px ${error ? "#ef4444" : "#6366f1"};
3891
+ }
3892
+ ` }),
3893
+ error && /* @__PURE__ */ jsx48("p", { style: errorTextStyles, children: error })
3483
3894
  ] });
3484
3895
  }
3485
3896
  );
3486
3897
  Textarea.displayName = "Textarea";
3487
3898
 
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
3899
  // src/components/shared/Badge.tsx
3561
- import React27 from "react";
3562
- import { jsx as jsx47 } from "react/jsx-runtime";
3563
- var Badge = React27.forwardRef(
3900
+ import React28 from "react";
3901
+ import { jsx as jsx49 } from "react/jsx-runtime";
3902
+ var Badge = React28.forwardRef(
3564
3903
  ({ style, variant = "default", size = "md", children, ...props }, ref) => {
3565
3904
  const variantStyles = {
3566
3905
  default: {
@@ -3614,14 +3953,14 @@ var Badge = React27.forwardRef(
3614
3953
  ...sizeStyles[size],
3615
3954
  ...style
3616
3955
  };
3617
- return /* @__PURE__ */ jsx47("span", { ref, style: combinedStyles, ...props, children });
3956
+ return /* @__PURE__ */ jsx49("span", { ref, style: combinedStyles, ...props, children });
3618
3957
  }
3619
3958
  );
3620
3959
  Badge.displayName = "Badge";
3621
3960
 
3622
3961
  // src/components/shared/Table.tsx
3623
- import React28 from "react";
3624
- import { jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
3962
+ import React29 from "react";
3963
+ import { jsx as jsx50, jsxs as jsxs40 } from "react/jsx-runtime";
3625
3964
  function Table({
3626
3965
  columns,
3627
3966
  data,
@@ -3630,7 +3969,7 @@ function Table({
3630
3969
  bordered = true,
3631
3970
  style
3632
3971
  }) {
3633
- const [hoveredRow, setHoveredRow] = React28.useState(null);
3972
+ const [hoveredRow, setHoveredRow] = React29.useState(null);
3634
3973
  const tableStyles = {
3635
3974
  width: "100%",
3636
3975
  borderCollapse: "collapse",
@@ -3655,8 +3994,8 @@ function Table({
3655
3994
  backgroundColor: hoverable && hoveredRow === rowIndex ? "#f9fafb" : striped && rowIndex % 2 === 1 ? "#f9fafb" : "#ffffff",
3656
3995
  transition: "background-color 0.15s ease"
3657
3996
  });
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(
3997
+ return /* @__PURE__ */ jsx50("div", { style: { overflowX: "auto", borderRadius: "0.5rem", border: bordered ? "1px solid #e5e7eb" : "none" }, children: /* @__PURE__ */ jsxs40("table", { style: tableStyles, children: [
3998
+ /* @__PURE__ */ jsx50("thead", { style: theadStyles, children: /* @__PURE__ */ jsx50("tr", { children: columns.map((column) => /* @__PURE__ */ jsx50(
3660
3999
  "th",
3661
4000
  {
3662
4001
  style: {
@@ -3667,12 +4006,12 @@ function Table({
3667
4006
  },
3668
4007
  column.key
3669
4008
  )) }) }),
3670
- /* @__PURE__ */ jsx48("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsx48(
4009
+ /* @__PURE__ */ jsx50("tbody", { children: data.map((row, rowIndex) => /* @__PURE__ */ jsx50(
3671
4010
  "tr",
3672
4011
  {
3673
4012
  onMouseEnter: () => hoverable && setHoveredRow(rowIndex),
3674
4013
  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))
4014
+ children: columns.map((column) => /* @__PURE__ */ jsx50("td", { style: getTdStyles(rowIndex), children: column.render ? column.render(row) : row[column.key] }, column.key))
3676
4015
  },
3677
4016
  rowIndex
3678
4017
  )) })
@@ -3681,9 +4020,9 @@ function Table({
3681
4020
  Table.displayName = "Table";
3682
4021
 
3683
4022
  // src/components/shared/Container.tsx
3684
- import React29 from "react";
3685
- import { jsx as jsx49 } from "react/jsx-runtime";
3686
- var Container = React29.forwardRef(
4023
+ import React30 from "react";
4024
+ import { jsx as jsx51 } from "react/jsx-runtime";
4025
+ var Container = React30.forwardRef(
3687
4026
  ({ style, maxWidth = "lg", padding = "md", children, ...props }, ref) => {
3688
4027
  const maxWidthStyles = {
3689
4028
  sm: "640px",
@@ -3708,15 +4047,15 @@ var Container = React29.forwardRef(
3708
4047
  paddingRight: paddingStyles[padding],
3709
4048
  ...style
3710
4049
  };
3711
- return /* @__PURE__ */ jsx49("div", { ref, style: containerStyles, ...props, children });
4050
+ return /* @__PURE__ */ jsx51("div", { ref, style: containerStyles, ...props, children });
3712
4051
  }
3713
4052
  );
3714
4053
  Container.displayName = "Container";
3715
4054
 
3716
4055
  // src/components/shared/Grid.tsx
3717
- import React30 from "react";
3718
- import { jsx as jsx50 } from "react/jsx-runtime";
3719
- var Grid = React30.forwardRef(
4056
+ import React31 from "react";
4057
+ import { jsx as jsx52 } from "react/jsx-runtime";
4058
+ var Grid = React31.forwardRef(
3720
4059
  ({ style, columns = 3, rows, gap = "md", width = "100%", height = "auto", responsive = true, children, ...props }, ref) => {
3721
4060
  const gapStyles = {
3722
4061
  none: "0",
@@ -3734,15 +4073,15 @@ var Grid = React30.forwardRef(
3734
4073
  height,
3735
4074
  ...style
3736
4075
  };
3737
- return /* @__PURE__ */ jsx50("div", { ref, style: gridStyles, ...props, children });
4076
+ return /* @__PURE__ */ jsx52("div", { ref, style: gridStyles, ...props, children });
3738
4077
  }
3739
4078
  );
3740
4079
  Grid.displayName = "Grid";
3741
4080
 
3742
4081
  // src/components/shared/Stack.tsx
3743
- import React31 from "react";
3744
- import { jsx as jsx51 } from "react/jsx-runtime";
3745
- var Stack = React31.forwardRef(
4082
+ import React32 from "react";
4083
+ import { jsx as jsx53 } from "react/jsx-runtime";
4084
+ var Stack = React32.forwardRef(
3746
4085
  ({ style, direction = "vertical", gap = "md", align = "stretch", justify = "start", children, ...props }, ref) => {
3747
4086
  const gapStyles = {
3748
4087
  none: "0",
@@ -3772,14 +4111,14 @@ var Stack = React31.forwardRef(
3772
4111
  justifyContent: justifyStyles[justify],
3773
4112
  ...style
3774
4113
  };
3775
- return /* @__PURE__ */ jsx51("div", { ref, style: stackStyles, ...props, children });
4114
+ return /* @__PURE__ */ jsx53("div", { ref, style: stackStyles, ...props, children });
3776
4115
  }
3777
4116
  );
3778
4117
  Stack.displayName = "Stack";
3779
4118
 
3780
4119
  // src/components/shared/Modal.tsx
3781
- import React32 from "react";
3782
- import { jsx as jsx52, jsxs as jsxs39 } from "react/jsx-runtime";
4120
+ import React33 from "react";
4121
+ import { jsx as jsx54, jsxs as jsxs41 } from "react/jsx-runtime";
3783
4122
  var Modal = ({
3784
4123
  isOpen,
3785
4124
  onClose,
@@ -3788,7 +4127,7 @@ var Modal = ({
3788
4127
  size = "md",
3789
4128
  closeOnOverlayClick = true
3790
4129
  }) => {
3791
- React32.useEffect(() => {
4130
+ React33.useEffect(() => {
3792
4131
  if (isOpen) {
3793
4132
  document.body.style.overflow = "hidden";
3794
4133
  } else {
@@ -3857,20 +4196,20 @@ var Modal = ({
3857
4196
  overflowY: "auto",
3858
4197
  flex: 1
3859
4198
  };
3860
- return /* @__PURE__ */ jsx52(
4199
+ return /* @__PURE__ */ jsx54(
3861
4200
  "div",
3862
4201
  {
3863
4202
  style: overlayStyles,
3864
4203
  onClick: closeOnOverlayClick ? onClose : void 0,
3865
- children: /* @__PURE__ */ jsxs39(
4204
+ children: /* @__PURE__ */ jsxs41(
3866
4205
  "div",
3867
4206
  {
3868
4207
  style: modalStyles,
3869
4208
  onClick: (e) => e.stopPropagation(),
3870
4209
  children: [
3871
- title && /* @__PURE__ */ jsxs39("div", { style: headerStyles, children: [
3872
- /* @__PURE__ */ jsx52("h2", { style: titleStyles, children: title }),
3873
- /* @__PURE__ */ jsx52(
4210
+ title && /* @__PURE__ */ jsxs41("div", { style: headerStyles, children: [
4211
+ /* @__PURE__ */ jsx54("h2", { style: titleStyles, children: title }),
4212
+ /* @__PURE__ */ jsx54(
3874
4213
  "button",
3875
4214
  {
3876
4215
  style: closeButtonStyles,
@@ -3880,7 +4219,7 @@ var Modal = ({
3880
4219
  }
3881
4220
  )
3882
4221
  ] }),
3883
- /* @__PURE__ */ jsx52("div", { style: contentStyles, children })
4222
+ /* @__PURE__ */ jsx54("div", { style: contentStyles, children })
3884
4223
  ]
3885
4224
  }
3886
4225
  )
@@ -3891,7 +4230,7 @@ Modal.displayName = "Modal";
3891
4230
 
3892
4231
  // src/components/shared/DateRangePicker.tsx
3893
4232
  import { useEffect as useEffect15, useMemo as useMemo6, useState as useState23 } from "react";
3894
- import { jsx as jsx53, jsxs as jsxs40 } from "react/jsx-runtime";
4233
+ import { jsx as jsx55, jsxs as jsxs42 } from "react/jsx-runtime";
3895
4234
  var PrimusDateRangePicker = ({
3896
4235
  startDate = null,
3897
4236
  endDate = null,
@@ -3927,8 +4266,8 @@ var PrimusDateRangePicker = ({
3927
4266
  setEnd(nextEnd);
3928
4267
  onRangeChange?.({ startDate: nextStart, endDate: nextEnd, label: range.label });
3929
4268
  };
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(
4269
+ return /* @__PURE__ */ jsxs42("div", { className: "space-y-3", children: [
4270
+ normalizedRanges.length > 0 && /* @__PURE__ */ jsx55("div", { className: "flex flex-wrap gap-2", children: normalizedRanges.map((range) => /* @__PURE__ */ jsx55(
3932
4271
  "button",
3933
4272
  {
3934
4273
  type: "button",
@@ -3939,8 +4278,8 @@ var PrimusDateRangePicker = ({
3939
4278
  },
3940
4279
  range.label
3941
4280
  )) }),
3942
- /* @__PURE__ */ jsxs40("div", { className: "flex flex-col md:flex-row gap-3", children: [
3943
- /* @__PURE__ */ jsx53(
4281
+ /* @__PURE__ */ jsxs42("div", { className: "flex flex-col md:flex-row gap-3", children: [
4282
+ /* @__PURE__ */ jsx55(
3944
4283
  "input",
3945
4284
  {
3946
4285
  type: "date",
@@ -3952,7 +4291,7 @@ var PrimusDateRangePicker = ({
3952
4291
  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
4292
  }
3954
4293
  ),
3955
- /* @__PURE__ */ jsx53(
4294
+ /* @__PURE__ */ jsx55(
3956
4295
  "input",
3957
4296
  {
3958
4297
  type: "date",
@@ -4003,7 +4342,7 @@ var toDateInputValue = (value) => {
4003
4342
  };
4004
4343
 
4005
4344
  // src/components/shared/FilterBar.tsx
4006
- import { jsx as jsx54, jsxs as jsxs41 } from "react/jsx-runtime";
4345
+ import { jsx as jsx56, jsxs as jsxs43 } from "react/jsx-runtime";
4007
4346
  var PrimusFilterBar = ({
4008
4347
  filters,
4009
4348
  activeFilters,
@@ -4017,9 +4356,9 @@ var PrimusFilterBar = ({
4017
4356
  };
4018
4357
  onChange?.(next);
4019
4358
  };
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(
4359
+ return /* @__PURE__ */ jsxs43("div", { className: "flex flex-wrap gap-4 items-end", children: [
4360
+ filters.map((filter) => /* @__PURE__ */ jsxs43("div", { className: "min-w-[220px]", children: [
4361
+ filter.type === "select" && /* @__PURE__ */ jsx56(
4023
4362
  Select,
4024
4363
  {
4025
4364
  label: filter.label,
@@ -4029,7 +4368,7 @@ var PrimusFilterBar = ({
4029
4368
  onChange: (value) => updateFilter(filter.key, value)
4030
4369
  }
4031
4370
  ),
4032
- filter.type === "toggle" && /* @__PURE__ */ jsx54(
4371
+ filter.type === "toggle" && /* @__PURE__ */ jsx56(
4033
4372
  Toggle,
4034
4373
  {
4035
4374
  label: filter.label,
@@ -4037,7 +4376,7 @@ var PrimusFilterBar = ({
4037
4376
  onChange: (checked) => updateFilter(filter.key, checked)
4038
4377
  }
4039
4378
  ),
4040
- filter.type === "search" && /* @__PURE__ */ jsx54(
4379
+ filter.type === "search" && /* @__PURE__ */ jsx56(
4041
4380
  Input,
4042
4381
  {
4043
4382
  label: filter.label,
@@ -4053,7 +4392,7 @@ var PrimusFilterBar = ({
4053
4392
 
4054
4393
  // src/components/shared/ExportMenu.tsx
4055
4394
  import { useEffect as useEffect16, useState as useState24 } from "react";
4056
- import { jsx as jsx55, jsxs as jsxs42 } from "react/jsx-runtime";
4395
+ import { jsx as jsx57, jsxs as jsxs44 } from "react/jsx-runtime";
4057
4396
  var PrimusExportMenu = ({
4058
4397
  formats = ["CSV", "PDF", "PNG", "JSON"],
4059
4398
  includeCharts = true,
@@ -4078,29 +4417,29 @@ var PrimusExportMenu = ({
4078
4417
  includeTables: tables
4079
4418
  });
4080
4419
  };
4081
- return /* @__PURE__ */ jsxs42("div", { className: "flex flex-wrap items-center gap-3", children: [
4082
- /* @__PURE__ */ jsx55(
4420
+ return /* @__PURE__ */ jsxs44("div", { className: "flex flex-wrap items-center gap-3", children: [
4421
+ /* @__PURE__ */ jsx57(
4083
4422
  "select",
4084
4423
  {
4085
4424
  value: format,
4086
4425
  onChange: (event) => setFormat(event.target.value),
4087
4426
  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))
4427
+ children: formats.map((item) => /* @__PURE__ */ jsx57("option", { value: item, children: item }, item))
4089
4428
  }
4090
4429
  ),
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) }),
4430
+ /* @__PURE__ */ jsxs44("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4431
+ /* @__PURE__ */ jsx57("input", { type: "checkbox", checked: charts, onChange: (e) => setCharts(e.target.checked) }),
4093
4432
  "Charts"
4094
4433
  ] }),
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) }),
4434
+ /* @__PURE__ */ jsxs44("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4435
+ /* @__PURE__ */ jsx57("input", { type: "checkbox", checked: stats, onChange: (e) => setStats(e.target.checked) }),
4097
4436
  "Stats"
4098
4437
  ] }),
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) }),
4438
+ /* @__PURE__ */ jsxs44("label", { className: "flex items-center gap-2 text-xs text-gray-300", children: [
4439
+ /* @__PURE__ */ jsx57("input", { type: "checkbox", checked: tables, onChange: (e) => setTables(e.target.checked) }),
4101
4440
  "Tables"
4102
4441
  ] }),
4103
- /* @__PURE__ */ jsx55(
4442
+ /* @__PURE__ */ jsx57(
4104
4443
  "button",
4105
4444
  {
4106
4445
  type: "button",
@@ -4114,7 +4453,7 @@ var PrimusExportMenu = ({
4114
4453
 
4115
4454
  // src/components/shared/Search.tsx
4116
4455
  import { useEffect as useEffect17, useMemo as useMemo7, useState as useState25 } from "react";
4117
- import { jsx as jsx56, jsxs as jsxs43 } from "react/jsx-runtime";
4456
+ import { jsx as jsx58, jsxs as jsxs45 } from "react/jsx-runtime";
4118
4457
  var PrimusSearch = ({
4119
4458
  placeholder = "Search...",
4120
4459
  debounce = 300,
@@ -4142,8 +4481,8 @@ var PrimusSearch = ({
4142
4481
  }
4143
4482
  return suggestions.filter((item) => item.toLowerCase().includes(query.toLowerCase())).slice(0, 5);
4144
4483
  }, [suggestions, query, showSuggestions]);
4145
- return /* @__PURE__ */ jsxs43("div", { className: "relative", children: [
4146
- /* @__PURE__ */ jsx56(
4484
+ return /* @__PURE__ */ jsxs45("div", { className: "relative", children: [
4485
+ /* @__PURE__ */ jsx58(
4147
4486
  "input",
4148
4487
  {
4149
4488
  type: "text",
@@ -4153,7 +4492,7 @@ var PrimusSearch = ({
4153
4492
  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
4493
  }
4155
4494
  ),
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(
4495
+ 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
4496
  "button",
4158
4497
  {
4159
4498
  type: "button",
@@ -4165,6 +4504,304 @@ var PrimusSearch = ({
4165
4504
  )) })
4166
4505
  ] });
4167
4506
  };
4507
+
4508
+ // src/components/shared/PrimusWizard.tsx
4509
+ import React37, { useState as useState26 } from "react";
4510
+ import { Fragment as Fragment6, jsx as jsx59, jsxs as jsxs46 } from "react/jsx-runtime";
4511
+ var PrimusStep = ({ children }) => {
4512
+ return /* @__PURE__ */ jsx59(Fragment6, { children });
4513
+ };
4514
+ var PrimusStepper = ({ steps, currentStep }) => {
4515
+ 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: [
4516
+ /* @__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" }) }) }),
4517
+ /* @__PURE__ */ jsx59("span", { className: "ml-4 text-sm font-medium", children: step.label })
4518
+ ] }) }) : 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: [
4519
+ /* @__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 }) }),
4520
+ /* @__PURE__ */ jsx59("span", { className: "ml-4 text-sm font-medium text-gray-900 dark:text-white", children: step.label })
4521
+ ] }) }) : /* @__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: [
4522
+ /* @__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 }) }),
4523
+ /* @__PURE__ */ jsx59("span", { className: "ml-4", children: step.label })
4524
+ ] }) }) }, step.label)) }) });
4525
+ };
4526
+ var PrimusWizard = ({
4527
+ title,
4528
+ subtitle,
4529
+ children,
4530
+ onComplete,
4531
+ className,
4532
+ startStep = 0
4533
+ }) => {
4534
+ const [currentStep, setCurrentStep] = useState26(startStep);
4535
+ const steps = React37.Children.toArray(children).filter(
4536
+ (child) => React37.isValidElement(child) && (child.type === PrimusStep || child.type.name === "PrimusStep")
4537
+ );
4538
+ const totalSteps = steps.length;
4539
+ const isFirstStep = currentStep === 0;
4540
+ const isLastStep = currentStep === totalSteps - 1;
4541
+ const handleNext = () => {
4542
+ if (isLastStep) {
4543
+ onComplete?.();
4544
+ } else {
4545
+ setCurrentStep((prev) => prev + 1);
4546
+ }
4547
+ };
4548
+ const handleBack = () => {
4549
+ if (!isFirstStep) {
4550
+ setCurrentStep((prev) => prev - 1);
4551
+ }
4552
+ };
4553
+ if (totalSteps === 0) {
4554
+ return /* @__PURE__ */ jsx59("div", { className: "text-red-500", children: "Error: PrimusWizard requires PrimusStep children" });
4555
+ }
4556
+ const currentStepConfig = steps[currentStep].props;
4557
+ return /* @__PURE__ */ jsxs46("div", { className: `space-y-6 ${className}`, children: [
4558
+ /* @__PURE__ */ jsxs46("div", { children: [
4559
+ title && /* @__PURE__ */ jsx59("h2", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: title }),
4560
+ subtitle && /* @__PURE__ */ jsx59("p", { className: "mt-1 text-gray-500 dark:text-gray-400", children: subtitle })
4561
+ ] }),
4562
+ /* @__PURE__ */ jsx59(
4563
+ PrimusStepper,
4564
+ {
4565
+ steps: steps.map((s) => ({ label: s.props.label, description: s.props.description })),
4566
+ currentStep
4567
+ }
4568
+ ),
4569
+ /* @__PURE__ */ jsxs46(Card, { className: "p-6 min-h-[300px]", children: [
4570
+ /* @__PURE__ */ jsx59("div", { className: "mb-8", children: steps[currentStep] }),
4571
+ /* @__PURE__ */ jsxs46("div", { className: "flex justify-between pt-6 border-t border-gray-100 dark:border-gray-800", children: [
4572
+ /* @__PURE__ */ jsx59(
4573
+ Button,
4574
+ {
4575
+ variant: "ghost",
4576
+ onClick: handleBack,
4577
+ disabled: isFirstStep,
4578
+ children: "Back"
4579
+ }
4580
+ ),
4581
+ /* @__PURE__ */ jsx59(
4582
+ Button,
4583
+ {
4584
+ onClick: handleNext,
4585
+ disabled: currentStepConfig.isValid === false,
4586
+ children: isLastStep ? "Complete" : "Next"
4587
+ }
4588
+ )
4589
+ ] })
4590
+ ] })
4591
+ ] });
4592
+ };
4593
+
4594
+ // src/components/shared/Field.tsx
4595
+ import React38 from "react";
4596
+ import { clsx as clsx8 } from "clsx";
4597
+ import { ExclamationCircleIcon } from "@heroicons/react/20/solid";
4598
+ import { jsx as jsx60, jsxs as jsxs47 } from "react/jsx-runtime";
4599
+ var FieldContext = React38.createContext(void 0);
4600
+ var useFieldContext = () => React38.useContext(FieldContext);
4601
+ var Field = ({ children, error, disabled, dense, className, ...props }) => {
4602
+ const id = React38.useId();
4603
+ return /* @__PURE__ */ jsx60(FieldContext.Provider, { value: { id, error, disabled }, children: /* @__PURE__ */ jsx60(
4604
+ "div",
4605
+ {
4606
+ className: clsx8(
4607
+ "flex flex-col w-full",
4608
+ dense ? "gap-1" : "gap-1.5",
4609
+ className
4610
+ ),
4611
+ ...props,
4612
+ children
4613
+ }
4614
+ ) });
4615
+ };
4616
+ var Label = ({ className, children, required, indicator, ...props }) => {
4617
+ const context = useFieldContext();
4618
+ return /* @__PURE__ */ jsxs47(
4619
+ "label",
4620
+ {
4621
+ htmlFor: context?.id,
4622
+ className: clsx8(
4623
+ "block text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
4624
+ context?.disabled ? "text-gray-400 opacity-70" : "text-gray-700",
4625
+ props.onClick ? "cursor-pointer" : "cursor-default",
4626
+ className
4627
+ ),
4628
+ ...props,
4629
+ children: [
4630
+ children,
4631
+ required && /* @__PURE__ */ jsx60("span", { className: "ml-0.5 text-red-500", children: "*" }),
4632
+ indicator
4633
+ ]
4634
+ }
4635
+ );
4636
+ };
4637
+ var FieldDescription = ({ className, children, ...props }) => {
4638
+ const context = useFieldContext();
4639
+ return /* @__PURE__ */ jsx60(
4640
+ "p",
4641
+ {
4642
+ className: clsx8(
4643
+ "text-[0.8rem] text-muted-foreground text-gray-500",
4644
+ context?.disabled && "opacity-70",
4645
+ className
4646
+ ),
4647
+ ...props,
4648
+ children
4649
+ }
4650
+ );
4651
+ };
4652
+ var FieldError = ({ className, children, forceVisible, ...props }) => {
4653
+ const context = useFieldContext();
4654
+ const error = context?.error || children;
4655
+ if (!error && !forceVisible) return null;
4656
+ return /* @__PURE__ */ jsxs47(
4657
+ "p",
4658
+ {
4659
+ className: clsx8(
4660
+ "text-[0.8rem] font-medium text-red-500 flex items-center gap-1.5 animate-in slide-in-from-top-1 fade-in-50",
4661
+ className
4662
+ ),
4663
+ ...props,
4664
+ children: [
4665
+ /* @__PURE__ */ jsx60(ExclamationCircleIcon, { className: "h-4 w-4 shrink-0" }),
4666
+ error
4667
+ ]
4668
+ }
4669
+ );
4670
+ };
4671
+
4672
+ // src/components/shared/InputGroup.tsx
4673
+ import React39 from "react";
4674
+ import { clsx as clsx9 } from "clsx";
4675
+ import { jsx as jsx61 } from "react/jsx-runtime";
4676
+ var InputGroup = ({ className, children, size = "md", ...props }) => {
4677
+ return /* @__PURE__ */ jsx61(
4678
+ "div",
4679
+ {
4680
+ className: clsx9(
4681
+ "flex items-stretch w-full rounded-lg shadow-sm",
4682
+ // Target direct children to remove borders and rounded corners where they touch
4683
+ "[&>*:first-child]:rounded-r-none",
4684
+ "[&>*:last-child]:rounded-l-none",
4685
+ "[&>*:not(:first-child):not(:last-child)]:rounded-none",
4686
+ // Handle borders to prevent double borders
4687
+ "[&>*:not(:first-child)]:-ml-px",
4688
+ // Ensure z-index handling for focus rings
4689
+ "[&>*:focus-within]:z-10",
4690
+ className
4691
+ ),
4692
+ ...props,
4693
+ children: React39.Children.map(children, (child) => {
4694
+ if (React39.isValidElement(child)) {
4695
+ return React39.cloneElement(child, { size });
4696
+ }
4697
+ return child;
4698
+ })
4699
+ }
4700
+ );
4701
+ };
4702
+ var InputAddon = ({ className, children, ...props }) => {
4703
+ return /* @__PURE__ */ jsx61(
4704
+ "div",
4705
+ {
4706
+ className: clsx9(
4707
+ "flex items-center px-3 border border-gray-200 bg-gray-50 text-gray-500 text-sm whitespace-nowrap",
4708
+ // These will be overridden by the group's first/last child selectors usually, but good defaults:
4709
+ "first:rounded-l-lg last:rounded-r-lg",
4710
+ className
4711
+ ),
4712
+ ...props,
4713
+ children
4714
+ }
4715
+ );
4716
+ };
4717
+
4718
+ // src/components/shared/PasswordInput.tsx
4719
+ import React40, { useState as useState27 } from "react";
4720
+ import { EyeIcon, EyeSlashIcon } from "@heroicons/react/20/solid";
4721
+ import { jsx as jsx62, jsxs as jsxs48 } from "react/jsx-runtime";
4722
+ var PasswordInput = React40.forwardRef(
4723
+ (props, ref) => {
4724
+ const [showPassword, setShowPassword] = useState27(false);
4725
+ const toggleVisibility = () => {
4726
+ setShowPassword(!showPassword);
4727
+ };
4728
+ return /* @__PURE__ */ jsx62(
4729
+ Input,
4730
+ {
4731
+ ref,
4732
+ type: showPassword ? "text" : "password",
4733
+ endIcon: /* @__PURE__ */ jsxs48(
4734
+ "button",
4735
+ {
4736
+ type: "button",
4737
+ onClick: toggleVisibility,
4738
+ 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",
4739
+ tabIndex: -1,
4740
+ children: [
4741
+ showPassword ? /* @__PURE__ */ jsx62(EyeSlashIcon, { className: "h-4 w-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx62(EyeIcon, { className: "h-4 w-4", "aria-hidden": "true" }),
4742
+ /* @__PURE__ */ jsx62("span", { className: "sr-only", children: showPassword ? "Hide password" : "Show password" })
4743
+ ]
4744
+ }
4745
+ ),
4746
+ ...props
4747
+ }
4748
+ );
4749
+ }
4750
+ );
4751
+ PasswordInput.displayName = "PasswordInput";
4752
+
4753
+ // src/components/shared/SearchInput.tsx
4754
+ import React41, { useState as useState28, useEffect as useEffect18 } from "react";
4755
+ import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
4756
+ import { jsx as jsx63 } from "react/jsx-runtime";
4757
+ var SearchInput = React41.forwardRef(
4758
+ ({ value, onSearch, debounceMs = 300, className, ...props }, ref) => {
4759
+ const [localValue, setLocalValue] = useState28(value || "");
4760
+ const [isDebouncing, setIsDebouncing] = useState28(false);
4761
+ useEffect18(() => {
4762
+ if (value !== void 0) {
4763
+ setLocalValue(value);
4764
+ }
4765
+ }, [value]);
4766
+ useEffect18(() => {
4767
+ if (debounceMs === 0) {
4768
+ onSearch?.(localValue);
4769
+ return;
4770
+ }
4771
+ const handler = setTimeout(() => {
4772
+ onSearch?.(localValue);
4773
+ setIsDebouncing(false);
4774
+ }, debounceMs);
4775
+ return () => {
4776
+ clearTimeout(handler);
4777
+ };
4778
+ }, [localValue, debounceMs]);
4779
+ const handleChange = (e) => {
4780
+ const newVal = e.target.value;
4781
+ setLocalValue(newVal);
4782
+ if (debounceMs > 0) setIsDebouncing(true);
4783
+ };
4784
+ const handleClear = () => {
4785
+ setLocalValue("");
4786
+ props.onClear?.();
4787
+ };
4788
+ return /* @__PURE__ */ jsx63(
4789
+ Input,
4790
+ {
4791
+ ref,
4792
+ type: "text",
4793
+ startIcon: /* @__PURE__ */ jsx63(MagnifyingGlassIcon, { className: "h-4 w-4" }),
4794
+ value: localValue,
4795
+ onChange: handleChange,
4796
+ onClear: handleClear,
4797
+ loading: props.loading || props.loading === void 0 && isDebouncing,
4798
+ className,
4799
+ ...props
4800
+ }
4801
+ );
4802
+ }
4803
+ );
4804
+ SearchInput.displayName = "SearchInput";
4168
4805
  export {
4169
4806
  AICopilot,
4170
4807
  AccountDashboard,
@@ -4181,17 +4818,24 @@ export {
4181
4818
  DashboardGrid,
4182
4819
  DocumentViewer,
4183
4820
  FeatureFlagToggle,
4821
+ Field,
4822
+ FieldDescription,
4823
+ FieldError,
4184
4824
  FileUploader,
4185
4825
  FraudDetectionDashboard,
4186
4826
  Grid,
4187
4827
  Input,
4828
+ InputAddon,
4829
+ InputGroup,
4188
4830
  KYCVerification,
4831
+ Label,
4189
4832
  LoanCalculator,
4190
4833
  LogViewer,
4191
4834
  LoginPage,
4192
4835
  Modal,
4193
4836
  NotificationBell,
4194
4837
  PrimusNotificationFeed as NotificationFeed,
4838
+ PasswordInput,
4195
4839
  PolicyCard,
4196
4840
  PremiumCalculator,
4197
4841
  PrimusActivityFeed,
@@ -4207,10 +4851,16 @@ export {
4207
4851
  PrimusDataTable,
4208
4852
  PrimusDateRangePicker,
4209
4853
  PrimusExportMenu,
4854
+ Field as PrimusField,
4855
+ FieldDescription as PrimusFieldDescription,
4856
+ FieldError as PrimusFieldError,
4210
4857
  PrimusFilterBar,
4211
4858
  Grid as PrimusGrid,
4212
4859
  PrimusHeader,
4213
4860
  Input as PrimusInput,
4861
+ InputAddon as PrimusInputAddon,
4862
+ InputGroup as PrimusInputGroup,
4863
+ Label as PrimusLabel,
4214
4864
  PrimusLayout,
4215
4865
  PrimusLineChart,
4216
4866
  PrimusLogin,
@@ -4219,22 +4869,31 @@ export {
4219
4869
  PrimusNotificationCenter,
4220
4870
  PrimusNotificationFeed,
4221
4871
  PrimusNotifications,
4872
+ PasswordInput as PrimusPasswordInput,
4222
4873
  PrimusPieChart,
4223
4874
  PrimusProvider,
4224
4875
  RadioGroup as PrimusRadioGroup,
4225
4876
  PrimusSearch,
4877
+ SearchInput as PrimusSearchInput,
4878
+ PrimusSection,
4226
4879
  Select as PrimusSelect,
4227
4880
  PrimusSidebar,
4228
4881
  PrimusSparkline,
4229
4882
  Stack as PrimusStack,
4230
4883
  PrimusStatCard,
4884
+ PrimusStatCard as PrimusStatsCard,
4885
+ PrimusStep,
4886
+ PrimusStepper,
4887
+ PrimusSummaryCard,
4231
4888
  Table as PrimusTable,
4232
4889
  Textarea as PrimusTextarea,
4233
4890
  PrimusThemeProvider,
4234
4891
  PrimusThemeToggle,
4235
4892
  Toggle as PrimusToggle,
4893
+ PrimusWizard,
4236
4894
  QuoteComparison,
4237
4895
  RadioGroup,
4896
+ SearchInput,
4238
4897
  SecurityDashboard,
4239
4898
  Select,
4240
4899
  Stack,
@@ -4246,6 +4905,7 @@ export {
4246
4905
  themeColors,
4247
4906
  useNotifications,
4248
4907
  usePrimusAuth,
4908
+ usePrimusFetch,
4249
4909
  usePrimusTheme,
4250
4910
  useRealtimeNotifications
4251
4911
  };