xertica-ui 2.9.7 → 2.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/bin/language-config.ts +17 -9
  4. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +19 -5
  5. package/components/pages/login-page/LoginPage.tsx +19 -5
  6. package/components/pages/reset-password-page/ResetPasswordPage.tsx +15 -2
  7. package/components/pages/verify-email-page/VerifyEmailPage.tsx +17 -3
  8. package/dist/AssistenteContext-Bm8_RJTB.js +200 -0
  9. package/dist/AssistenteContext-CLK8tgdt.cjs +205 -0
  10. package/dist/BrandColorsContext-D3Y0CYZF.js +643 -0
  11. package/dist/BrandColorsContext-SeOZd2Cq.cjs +646 -0
  12. package/dist/VerifyEmailPage-BInYcjRd.cjs +3305 -0
  13. package/dist/VerifyEmailPage-Z-cA_IIo.js +3295 -0
  14. package/dist/XerticaProvider-Ck996htf.cjs +47 -0
  15. package/dist/XerticaProvider-kE5l0MQn.js +45 -0
  16. package/dist/brand.cjs.js +1 -1
  17. package/dist/brand.es.js +1 -1
  18. package/dist/cli.js +12 -7
  19. package/dist/components/pages/forgot-password-page/ForgotPasswordPage.d.ts +4 -3
  20. package/dist/components/pages/login-page/LoginPage.d.ts +4 -3
  21. package/dist/components/pages/verify-email-page/VerifyEmailPage.d.ts +2 -1
  22. package/dist/hooks.cjs.js +6 -5
  23. package/dist/hooks.es.js +2 -1
  24. package/dist/index.cjs.js +2 -2
  25. package/dist/index.es.js +2 -2
  26. package/dist/pages.cjs.js +1 -1
  27. package/dist/pages.es.js +1 -1
  28. package/package.json +1 -1
  29. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +15 -2
  30. package/templates/src/features/auth/ui/LoginContent.tsx +15 -2
  31. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +15 -2
  32. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +15 -2
  33. package/templates/src/styles/index.css +5 -0
  34. package/templates/tsconfig.node.json +1 -0
package/CHANGELOG.md CHANGED
@@ -11,6 +11,24 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
11
11
 
12
12
  ---
13
13
 
14
+ ## [2.9.9] — 2026-07-14
15
+
16
+ ### Fixed
17
+
18
+ - **Isotipo da marca e a inversão de cores apareciam nas telas de auth em qualquer tema, não só no "Xertica"** — os commits que introduziram o isotipo (`31e3bb51`, `7f047240`) trocaram o `leftPanel` do `AuthPageShell` para `"isotype"` de forma incondicional nas 4 páginas de autenticação (`LoginPage`, `ForgotPasswordPage`, `ResetPasswordPage`, `VerifyEmailPage`), então o painel esquerdo sempre exibia a marca e a inversão de cores (`bg-card`/`bg-muted`) associada a ela, mesmo com qualquer outro tema de cor ativo — inclusive o `xertica-original`, o tema clássico padrão. Corrigido lendo `currentTheme` via `useBrandColors()` em cada página e só usando `leftPanel="isotype"` quando `currentTheme === 'xertica'`; para os demais temas, o painel volta a exibir a imagem de capa e o gradiente originais (recuperados do histórico do git, anteriores ao rebranding). Aplicado tanto nos componentes reais (`components/pages/*-page`) quanto nos templates espelho usados pelo CLI (`templates/src/features/auth/ui/*Content.tsx`).
19
+
20
+ ---
21
+
22
+ ## [2.9.8] — 2026-07-14
23
+
24
+ ### Fixed
25
+
26
+ - **Projeto gerado pelo scaffold "Web page" não compilava — erros de tipo de bibliotecas de terceiros** — `tsconfig.node.json` não tinha `skipLibCheck`, então o type-check processava as definições de tipo de dependências transitivas usadas internamente pelo Vite (`d3-array`, `prismjs`, etc.), e qualquer inconsistência nelas quebrava a compilação do projeto gerado, mesmo sem nenhum erro real no código do usuário. Corrigido adicionando `"skipLibCheck": true` a `templates/tsconfig.node.json`, usado tanto pelo scaffold "Web page" quanto pelo "Full system".
27
+ - **Tela em branco no scaffold "Web page" — `Error: No QueryClient set, use QueryClientProvider to set one`** — o `App.tsx` gerado por `generateLandingAppTsx` (`bin/language-config.ts`) renderizava `<LandingPage>` direto dentro de `<XerticaProvider>`, sem `QueryClientProvider`, partindo do pressuposto de que a landing page não dependia de React Query. Só que `XerticaProvider` monta `LanguageProvider` internamente, e este chama `useQueryClient()` para invalidar queries traduzíveis na troca de idioma — sem um `QueryClientProvider` acima na árvore, o app quebra no primeiro render. Corrigido envolvendo o `App.tsx` gerado em `<QueryClientProvider client={queryClient}>` (com `queryClient = new QueryClient()`), o mesmo padrão que o scaffold "Full system" (`generateAppTsx`) já usava.
28
+ - **Scroll não funcionava no scaffold "Web page"** — o CSS da própria lib (`styles/xertica/base.css`) define `html, body { height: 100%; overflow: hidden; }`, delegando o scroll a um container interno com altura própria resolvida. Como o `#root` gerado pelo Vite não tinha altura definida, a `LandingPage` (que usa `h-full overflow-y-auto`) não tinha em relação a que altura calcular seu próprio limite de scroll. Corrigido adicionando `#root { height: 100%; }` a `templates/src/styles/index.css`.
29
+
30
+ ---
31
+
14
32
  ## [2.9.7] — 2026-07-14
15
33
 
16
34
  ### Fixed
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Enterprise-grade React design system** built on Tailwind CSS v4, Radix UI, and Lucide Icons — with a robust AI-first documentation layer for precise LLM-driven composition and autonomous agent interaction.
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-2.9.7-blue)](https://www.npmjs.com/package/xertica-ui)
5
+ [![npm version](https://img.shields.io/badge/npm-2.9.9-blue)](https://www.npmjs.com/package/xertica-ui)
6
6
  [![license](https://img.shields.io/badge/license-proprietary-red)](./LICENSE)
7
7
 
8
8
  ---
@@ -362,27 +362,35 @@ export default function App() {
362
362
  /**
363
363
  * Generate the App.tsx source for a minimal "web page" project — renders the
364
364
  * marketing `LandingPage` directly under `XerticaProvider`, with none of the
365
- * router/query-client/auth machinery the full system scaffold needs (the
366
- * landing page itself has no dependency on any of it).
365
+ * router/auth machinery the full system scaffold needs. `QueryClientProvider`
366
+ * is still required, though: `XerticaProvider` mounts `LanguageProvider`
367
+ * internally, which calls `useQueryClient()` to invalidate translated queries
368
+ * on language change — without a provider above it, the app throws "No
369
+ * QueryClient set" at render time.
367
370
  */
368
371
  export function generateLandingAppTsx(
369
372
  selectedCodes: string[],
370
373
  disableDarkMode: boolean = false
371
374
  ): string {
372
- const disableDarkModeProp = disableDarkMode ? `\n disableDarkMode={true}` : '';
373
- const availableLanguagesProp = buildAvailableLanguagesProp(selectedCodes, ' ');
375
+ const disableDarkModeProp = disableDarkMode ? `\n disableDarkMode={true}` : '';
376
+ const availableLanguagesProp = buildAvailableLanguagesProp(selectedCodes, ' ');
374
377
 
375
378
  return `import React from 'react';
379
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
376
380
  import { XerticaProvider } from 'xertica-ui/brand';
377
381
  import { LandingPage } from '../pages/LandingPage';
378
382
 
383
+ const queryClient = new QueryClient();
384
+
379
385
  export default function App() {
380
386
  return (
381
- <XerticaProvider
382
- useCustomTokens={true}${availableLanguagesProp}${disableDarkModeProp}
383
- >
384
- <LandingPage />
385
- </XerticaProvider>
387
+ <QueryClientProvider client={queryClient}>
388
+ <XerticaProvider
389
+ useCustomTokens={true}${availableLanguagesProp}${disableDarkModeProp}
390
+ >
391
+ <LandingPage />
392
+ </XerticaProvider>
393
+ </QueryClientProvider>
386
394
  );
387
395
  }
388
396
  `;
@@ -7,22 +7,25 @@ import { AuthPageShell, SocialLoginButtons } from '../../blocks/auth';
7
7
  import { ArrowLeft } from 'lucide-react';
8
8
  import { useNavigate } from 'react-router-dom';
9
9
  import { useTranslation } from 'react-i18next';
10
+ import { useBrandColors } from '../../../contexts/BrandColorsContext';
10
11
 
11
12
  /**
12
13
  * Forgot Password Page component.
13
14
  *
14
15
  * @description
15
16
  * A screen that allows users to request a password reset link via email.
16
- * Includes the shared brand isotype side-panel (desktop) and alternative
17
- * social login options similar to the main Login page.
17
+ * Includes a side-panel (desktop) and alternative social login options
18
+ * similar to the main Login page.
18
19
  *
19
20
  * @ai-rules
20
21
  * 1. Navigation: Successfully submitting the email triggers a navigation to `/verify-email`.
21
- * 2. Visuals: Keeps consistency with `LoginPage` in terms of layout and branding.
22
+ * 2. Visuals: Keeps consistency with `LoginPage` in terms of layout and branding, including
23
+ * the theme-conditional isotype/hero-image left panel.
22
24
  */
23
25
  export function ForgotPasswordPage() {
24
26
  const navigate = useNavigate();
25
27
  const { t } = useTranslation();
28
+ const { currentTheme } = useBrandColors();
26
29
  const [email, setEmail] = useState('');
27
30
  const [isLoading, setIsLoading] = useState(false);
28
31
 
@@ -43,8 +46,8 @@ export function ForgotPasswordPage() {
43
46
  // Wire your SSO/social provider integration here
44
47
  };
45
48
 
46
- return (
47
- <AuthPageShell leftPanel="isotype">
49
+ const content = (
50
+ <>
48
51
  <div className="text-center">
49
52
  <div className="flex items-center justify-center mb-4">
50
53
  <XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
@@ -86,6 +89,17 @@ export function ForgotPasswordPage() {
86
89
  </form>
87
90
 
88
91
  <SocialLoginButtons onSocialLogin={handleSocialLogin} />
92
+ </>
93
+ );
94
+
95
+ return currentTheme === 'xertica' ? (
96
+ <AuthPageShell leftPanel="isotype">{content}</AuthPageShell>
97
+ ) : (
98
+ <AuthPageShell
99
+ imageSrc="https://images.unsplash.com/photo-1557804506-669a67965ba0?w=1200&h=800&fit=crop&auto=format"
100
+ imageAlt={t('forgotPassword.heroImageAlt')}
101
+ >
102
+ {content}
89
103
  </AuthPageShell>
90
104
  );
91
105
  }
@@ -6,6 +6,7 @@ import { XerticaLogo } from '../../brand/xertica-logo';
6
6
  import { AuthPageShell, SocialLoginButtons } from '../../blocks/auth';
7
7
  import { useNavigate } from 'react-router-dom';
8
8
  import { useTranslation } from 'react-i18next';
9
+ import { useBrandColors } from '../../../contexts/BrandColorsContext';
9
10
 
10
11
  /**
11
12
  * Props for the LoginPage component.
@@ -22,18 +23,20 @@ interface LoginPageProps {
22
23
  * Standard Login Page component.
23
24
  *
24
25
  * @description
25
- * A complete, responsive login screen featuring a brand isotype side-panel (on desktop)
26
- * and a focused authentication form. Supports email/password login and placeholders
26
+ * A complete, responsive login screen featuring a side-panel (on desktop) and a
27
+ * focused authentication form. Supports email/password login and placeholders
27
28
  * for Social/SSO providers (Google, MT Login, gov.br).
28
29
  *
29
30
  * @ai-rules
30
31
  * 1. State Management: You must provide the `onLogin` callback to handle the actual authentication logic.
31
- * 2. Visuals: Left panel renders `IsotypeTwist` via `AuthPageShell`'s `leftPanel="isotype"` no hero image on this page.
32
+ * 2. Visuals: Left panel renders the brand isotype only when the `xertica` theme is active
33
+ * (`AuthPageShell`'s `leftPanel="isotype"`); every other theme shows the original hero image.
32
34
  * 3. Routing: Uses `react-router` for navigation to the forgot-password flow.
33
35
  */
34
36
  export function LoginPage({ onLogin }: LoginPageProps) {
35
37
  const navigate = useNavigate();
36
38
  const { t } = useTranslation();
39
+ const { currentTheme } = useBrandColors();
37
40
  const [email, setEmail] = useState('');
38
41
  const [password, setPassword] = useState('');
39
42
  const [isLoading, setIsLoading] = useState(false);
@@ -61,8 +64,8 @@ export function LoginPage({ onLogin }: LoginPageProps) {
61
64
  onLogin('social@user.com', 'social-auth');
62
65
  };
63
66
 
64
- return (
65
- <AuthPageShell leftPanel="isotype">
67
+ const content = (
68
+ <>
66
69
  <div className="text-center">
67
70
  <div className="flex items-center justify-center mb-4">
68
71
  <XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
@@ -117,6 +120,17 @@ export function LoginPage({ onLogin }: LoginPageProps) {
117
120
  </form>
118
121
 
119
122
  <SocialLoginButtons onSocialLogin={handleSocialLogin} />
123
+ </>
124
+ );
125
+
126
+ return currentTheme === 'xertica' ? (
127
+ <AuthPageShell leftPanel="isotype">{content}</AuthPageShell>
128
+ ) : (
129
+ <AuthPageShell
130
+ imageSrc="https://images.unsplash.com/photo-1551434678-e076c223a692?w=1200&h=800&fit=crop&auto=format"
131
+ imageAlt={t('login.heroImageAlt')}
132
+ >
133
+ {content}
120
134
  </AuthPageShell>
121
135
  );
122
136
  }
@@ -7,6 +7,7 @@ import { AuthPageShell, usePasswordStrength, PasswordStrengthMeter } from '../..
7
7
  import { ArrowLeft, CheckCircle2, AlertCircle } from 'lucide-react';
8
8
  import { useNavigate } from 'react-router-dom';
9
9
  import { useTranslation } from 'react-i18next';
10
+ import { useBrandColors } from '../../../contexts/BrandColorsContext';
10
11
 
11
12
  /**
12
13
  * Reset Password Page component.
@@ -24,6 +25,7 @@ import { useTranslation } from 'react-i18next';
24
25
  export function ResetPasswordPage() {
25
26
  const navigate = useNavigate();
26
27
  const { t } = useTranslation();
28
+ const { currentTheme } = useBrandColors();
27
29
  const [password, setPassword] = useState('');
28
30
  const [confirmPassword, setConfirmPassword] = useState('');
29
31
  const [isLoading, setIsLoading] = useState(false);
@@ -61,8 +63,8 @@ export function ResetPasswordPage() {
61
63
  setIsLoading(false);
62
64
  };
63
65
 
64
- return (
65
- <AuthPageShell leftPanel="isotype">
66
+ const content = (
67
+ <>
66
68
  <button
67
69
  onClick={() => navigate('/login')}
68
70
  className="flex items-center gap-2 text-muted-foreground hover:text-foreground transition-colors"
@@ -145,6 +147,17 @@ export function ResetPasswordPage() {
145
147
  {isLoading ? t('resetPassword.submitting') : t('resetPassword.submit')}
146
148
  </Button>
147
149
  </form>
150
+ </>
151
+ );
152
+
153
+ return currentTheme === 'xertica' ? (
154
+ <AuthPageShell leftPanel="isotype">{content}</AuthPageShell>
155
+ ) : (
156
+ <AuthPageShell
157
+ imageSrc="https://images.unsplash.com/photo-1555949963-aa79dcee981c?w=1200&h=800&fit=crop&auto=format"
158
+ imageAlt={t('resetPassword.heroImageAlt')}
159
+ >
160
+ {content}
148
161
  </AuthPageShell>
149
162
  );
150
163
  }
@@ -5,6 +5,7 @@ import { AuthPageShell, SocialLoginButtons } from '../../blocks/auth';
5
5
  import { ArrowLeft, Mail, CheckCircle2 } from 'lucide-react';
6
6
  import { useNavigate, useLocation } from 'react-router-dom';
7
7
  import { useTranslation } from 'react-i18next';
8
+ import { useBrandColors } from '../../../contexts/BrandColorsContext';
8
9
 
9
10
  /**
10
11
  * Email Verification Page component.
@@ -12,7 +13,8 @@ import { useTranslation } from 'react-i18next';
12
13
  * @description
13
14
  * An informative screen shown after a password reset request. It instructs
14
15
  * the user to check their email and provides a "Resend email" feature.
15
- * Includes the same consistent layout with the shared brand isotype side-panel.
16
+ * Includes the same consistent layout as the other auth pages, including the
17
+ * theme-conditional isotype/hero-image left panel.
16
18
  *
17
19
  * @ai-rules
18
20
  * 1. Data Source: It retrieves the email from the router's `location.state`.
@@ -23,6 +25,7 @@ export function VerifyEmailPage() {
23
25
  const navigate = useNavigate();
24
26
  const location = useLocation();
25
27
  const { t } = useTranslation();
28
+ const { currentTheme } = useBrandColors();
26
29
  const email = location.state?.email || 'your@email.com';
27
30
  const [isResending, setIsResending] = useState(false);
28
31
  const [resendSuccess, setResendSuccess] = useState(false);
@@ -45,8 +48,8 @@ export function VerifyEmailPage() {
45
48
  // Wire your SSO/social provider integration here
46
49
  };
47
50
 
48
- return (
49
- <AuthPageShell leftPanel="isotype">
51
+ const content = (
52
+ <>
50
53
  <div className="text-center">
51
54
  <div className="flex items-center justify-center mb-4">
52
55
  <XerticaLogo className="h-12 w-auto text-primary dark:text-foreground" variant="theme" />
@@ -96,6 +99,17 @@ export function VerifyEmailPage() {
96
99
  </div>
97
100
 
98
101
  <SocialLoginButtons onSocialLogin={handleSocialLogin} />
102
+ </>
103
+ );
104
+
105
+ return currentTheme === 'xertica' ? (
106
+ <AuthPageShell leftPanel="isotype">{content}</AuthPageShell>
107
+ ) : (
108
+ <AuthPageShell
109
+ imageSrc="https://images.unsplash.com/photo-1563986768609-322da13575f3?w=1200&h=800&fit=crop&auto=format"
110
+ imageAlt={t('verifyEmail.heroImageAlt')}
111
+ >
112
+ {content}
99
113
  </AuthPageShell>
100
114
  );
101
115
  }
@@ -0,0 +1,200 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { createContext, useState, useEffect, useContext } from 'react';
3
+
4
+ const ApiKeyContext = createContext(void 0);
5
+ const readStorage = (key) => typeof window !== "undefined" ? window.localStorage?.getItem(key) : null;
6
+ const writeStorage = (key, value) => {
7
+ if (typeof window === "undefined") return;
8
+ window.localStorage?.setItem(key, value);
9
+ };
10
+ const removeStorage = (key) => {
11
+ if (typeof window === "undefined") return;
12
+ window.localStorage?.removeItem(key);
13
+ };
14
+ function ApiKeyProvider({
15
+ children,
16
+ initialApiKey,
17
+ initialGeminiApiKey,
18
+ initialGoogleMapsApiKey
19
+ }) {
20
+ const LEAKED_KEYS = [
21
+ "AIzaSyCMsAMytBeOK0Qd7RKFyA5IW9eWt2WTJg",
22
+ "AIzaSyAiYWEIEmx212Up9zfM8kqyMXB4jLs8gq0"
23
+ ];
24
+ const [apiKey, setApiKeyState] = useState(() => {
25
+ if (initialApiKey) return initialApiKey;
26
+ const saved = readStorage("xertica-api-key");
27
+ return saved || "";
28
+ });
29
+ const [geminiApiKey, setGeminiApiKeyState] = useState(() => {
30
+ if (initialGeminiApiKey) return initialGeminiApiKey;
31
+ const saved = readStorage("xertica-gemini-api-key");
32
+ if (saved && LEAKED_KEYS.includes(saved)) {
33
+ removeStorage("xertica-gemini-api-key");
34
+ return "";
35
+ }
36
+ return saved || "";
37
+ });
38
+ const [googleMapsApiKey, setGoogleMapsApiKeyState] = useState(() => {
39
+ if (initialGoogleMapsApiKey) return initialGoogleMapsApiKey;
40
+ const saved = readStorage("xertica-googlemaps-api-key");
41
+ return saved || "";
42
+ });
43
+ const [isApiKeyValid, setIsApiKeyValid] = useState(false);
44
+ const [isGoogleMapsKeyValid, setIsGoogleMapsKeyValid] = useState(false);
45
+ useEffect(() => {
46
+ if (initialApiKey !== void 0) {
47
+ setApiKeyState(initialApiKey.trim());
48
+ }
49
+ }, [initialApiKey]);
50
+ useEffect(() => {
51
+ if (initialGeminiApiKey !== void 0) {
52
+ setGeminiApiKeyState(initialGeminiApiKey.trim());
53
+ }
54
+ }, [initialGeminiApiKey]);
55
+ useEffect(() => {
56
+ if (initialGoogleMapsApiKey !== void 0) {
57
+ setGoogleMapsApiKeyState(initialGoogleMapsApiKey.trim());
58
+ }
59
+ }, [initialGoogleMapsApiKey]);
60
+ useEffect(() => {
61
+ if (apiKey) {
62
+ writeStorage("xertica-api-key", apiKey);
63
+ setIsApiKeyValid(apiKey.length > 0);
64
+ } else {
65
+ removeStorage("xertica-api-key");
66
+ setIsApiKeyValid(false);
67
+ }
68
+ }, [apiKey]);
69
+ useEffect(() => {
70
+ if (geminiApiKey) {
71
+ writeStorage("xertica-gemini-api-key", geminiApiKey);
72
+ setIsApiKeyValid(geminiApiKey.startsWith("AIzaSy") && geminiApiKey.length > 20);
73
+ } else {
74
+ removeStorage("xertica-gemini-api-key");
75
+ setIsApiKeyValid(false);
76
+ }
77
+ }, [geminiApiKey]);
78
+ useEffect(() => {
79
+ if (googleMapsApiKey) {
80
+ writeStorage("xertica-googlemaps-api-key", googleMapsApiKey);
81
+ setIsGoogleMapsKeyValid(
82
+ googleMapsApiKey.startsWith("AIzaSy") && googleMapsApiKey.length > 20
83
+ );
84
+ const reloadMaps = async () => {
85
+ if (googleMapsApiKey.length < 10) return;
86
+ try {
87
+ const { reloadGoogleMaps } = await import('./index-Bei5DzAL.js');
88
+ await reloadGoogleMaps(googleMapsApiKey);
89
+ console.log("[ApiKeyContext] Google Maps recarregado com sucesso");
90
+ } catch (error) {
91
+ console.error("[ApiKeyContext] Erro ao recarregar Google Maps:", error);
92
+ }
93
+ };
94
+ reloadMaps();
95
+ } else {
96
+ removeStorage("xertica-googlemaps-api-key");
97
+ setIsGoogleMapsKeyValid(false);
98
+ }
99
+ }, [googleMapsApiKey]);
100
+ const setApiKey = (key) => {
101
+ setApiKeyState(key.trim());
102
+ };
103
+ const setGeminiApiKey = (key) => {
104
+ setGeminiApiKeyState(key.trim());
105
+ };
106
+ const setGoogleMapsApiKey = (key) => {
107
+ setGoogleMapsApiKeyState(key.trim());
108
+ };
109
+ const reloadMapsApi = async () => {
110
+ if (!googleMapsApiKey || googleMapsApiKey.length < 10) {
111
+ return;
112
+ }
113
+ try {
114
+ const { reloadGoogleMaps } = await import('./index-Bei5DzAL.js');
115
+ await reloadGoogleMaps(googleMapsApiKey);
116
+ console.log("[ApiKeyContext] Google Maps recarregado manualmente");
117
+ } catch (error) {
118
+ console.error("[ApiKeyContext] Erro ao recarregar Google Maps:", error);
119
+ }
120
+ };
121
+ return /* @__PURE__ */ jsx(
122
+ ApiKeyContext.Provider,
123
+ {
124
+ value: {
125
+ apiKey,
126
+ setApiKey,
127
+ geminiApiKey,
128
+ setGeminiApiKey,
129
+ isApiKeyValid,
130
+ googleMapsApiKey,
131
+ setGoogleMapsApiKey,
132
+ isGoogleMapsKeyValid,
133
+ reloadMapsApi
134
+ },
135
+ children
136
+ }
137
+ );
138
+ }
139
+ function useApiKey() {
140
+ const context = useContext(ApiKeyContext);
141
+ if (!context) {
142
+ throw new Error("useApiKey must be used within ApiKeyProvider");
143
+ }
144
+ return context;
145
+ }
146
+
147
+ const AssistenteContext = createContext(void 0);
148
+ function AssistenteProvider({ children }) {
149
+ const [conversaAtual, setConversaAtual] = useState("1");
150
+ const [conversas, setConversas] = useState([
151
+ {
152
+ id: "1",
153
+ titulo: "Nova Conversa",
154
+ mensagens: [],
155
+ ultimaMensagem: "",
156
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
157
+ favorita: false
158
+ }
159
+ ]);
160
+ const [isTyping, setIsTyping] = useState(false);
161
+ const [abaSelecionada, setAbaSelecionada] = useState("chat");
162
+ const [editingDocument, setEditingDocument] = useState(
163
+ null
164
+ );
165
+ const [searchFilter, setSearchFilter] = useState("all");
166
+ const [savedSearches, setSavedSearches] = useState([]);
167
+ const historico = conversas.find((c) => c.id === conversaAtual)?.mensagens || [];
168
+ return /* @__PURE__ */ jsx(
169
+ AssistenteContext.Provider,
170
+ {
171
+ value: {
172
+ historico,
173
+ conversaAtual,
174
+ setConversaAtual,
175
+ conversas,
176
+ setConversas,
177
+ isTyping,
178
+ setIsTyping,
179
+ abaSelecionada,
180
+ setAbaSelecionada,
181
+ editingDocument,
182
+ setEditingDocument,
183
+ searchFilter,
184
+ setSearchFilter,
185
+ savedSearches,
186
+ setSavedSearches
187
+ },
188
+ children
189
+ }
190
+ );
191
+ }
192
+ function useAssistente() {
193
+ const context = useContext(AssistenteContext);
194
+ if (!context) {
195
+ throw new Error("useAssistente must be used within AssistenteProvider");
196
+ }
197
+ return context;
198
+ }
199
+
200
+ export { ApiKeyProvider as A, AssistenteProvider as a, useAssistente as b, useApiKey as u };