@lastbrain/ai-ui-react 1.0.74 → 1.0.75

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AiChipLabel.d.ts","sourceRoot":"","sources":["../../src/components/AiChipLabel.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAA0C,MAAM,OAAO,CAAC;AAS/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAmB,EACnB,IAAW,EACX,MAAe,EACf,SAAS,EACT,KAAK,EAAE,WAAW,GACnB,EAAE,gBAAgB,2CAiBlB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAU,EACV,QAAQ,EACR,WAAW,EACX,OAAO,EACP,QAAQ,EACR,eAAuB,EACvB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,IAAW,EACX,MAAe,GAChB,EAAE,gBAAgB,2CA6MlB"}
1
+ {"version":3,"file":"AiChipLabel.d.ts","sourceRoot":"","sources":["../../src/components/AiChipLabel.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAA0C,MAAM,OAAO,CAAC;AAS/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,OAAmB,EACnB,IAAW,EACX,MAAe,EACf,SAAS,EACT,KAAK,EAAE,WAAW,GACnB,EAAE,gBAAgB,2CAiBlB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAU,EACV,QAAQ,EACR,WAAW,EACX,OAAO,EACP,QAAQ,EACR,eAAuB,EACvB,SAAS,EACT,YAAY,EACZ,aAAa,EACb,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,IAAW,EACX,MAAe,GAChB,EAAE,gBAAgB,2CA0MlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"AiContextButton.d.ts","sourceRoot":"","sources":["../../src/components/AiContextButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,KAAK,WAAW,GACZ,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,EAAE,GACT;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE/B,MAAM,WAAW,oBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,WAAW,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,OAAO,EAAE,QAAQ,EACjB,GAAG,WAAW,EACf,EAAE,oBAAoB,2CAoStB"}
1
+ {"version":3,"file":"AiContextButton.d.ts","sourceRoot":"","sources":["../../src/components/AiContextButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,KAAK,WAAW,GACZ,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,EAAE,GACT;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE/B,MAAM,WAAW,oBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,WAAW,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,CACT,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,OAAO,EAAE,QAAQ,EACjB,GAAG,WAAW,EACf,EAAE,oBAAoB,2CA6StB"}
@@ -142,12 +142,13 @@ export function AiContextButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId,
142
142
  const variantClass = variant === "light" ? "ai-btn--light" : "";
143
143
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative inline-block ai-glow", children: [_jsx("button", { ...buttonProps, onClick: handleOpenPanel, disabled: disabled || loading || !isAuthReady, className: `ai-btn ai-context-btn ${variantClass} ${sizeClass} ${radiusClass} ${className || ""}`, title: !isAuthReady
144
144
  ? t("auth.required", "Authentication required")
145
- : t("ai.analyze", "Analyze with AI"), children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), _jsx("span", { children: t("ai.analyzing", "Analyzing...") })] })) : !isAuthReady ? (_jsxs(_Fragment, { children: [_jsx(Lock, { size: 16 }), children || (_jsx("span", { children: t("auth.connectRequired", "Connection required") }))] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), children || _jsx("span", { children: t("ai.context.buttonAnalyze", "Analyze") })] })) }), isOpen ? (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), onSubmit: handleSubmit, uiMode: uiMode, models: [], enableModelManagement: true, modelCategory: "text", baseUrl: baseUrl, apiKey: apiKeyId })) : null] }), isResultOpen && analysisResult ? (_jsx("div", { className: "ai-signin-overlay ai-overlay-panel", onClick: (e) => {
145
+ : t("ai.analyze", "Analyze with AI"), children: loading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "ai-spinner" }), _jsx("span", { children: t("ai.analyzing", "Analyzing...") })] })) : !isAuthReady ? (_jsxs(_Fragment, { children: [_jsx(Lock, { size: 16 }), children || (_jsx("span", { children: t("auth.connectRequired", "Connection required") }))] })) : (_jsxs(_Fragment, { children: [_jsx(Sparkles, { size: 16 }), children || (_jsx("span", { children: t("ai.context.buttonAnalyze", "Analyze") }))] })) }), isOpen ? (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), onSubmit: handleSubmit, uiMode: uiMode, models: [], enableModelManagement: true, modelCategory: "text", baseUrl: baseUrl, apiKey: apiKeyId })) : null] }), isResultOpen && analysisResult ? (_jsx("div", { className: "ai-signin-overlay ai-overlay-panel", onClick: (e) => {
146
146
  if (e.target === e.currentTarget) {
147
147
  setIsResultOpen(false);
148
148
  setAnalysisResult(null);
149
149
  }
150
- }, children: _jsxs("div", { className: "ai-popover ai-result-modal", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "ai-result-header", children: [_jsxs("div", { className: "ai-row", children: [_jsx(FileText, { size: 18 }), _jsx("h2", { className: "ai-result-title", children: resultModalTitle || t("ai.context.resultTitle", "Analysis result") })] }), _jsxs("div", { className: "ai-row", children: [_jsxs("button", { type: "button", className: `ai-btn ai-btn--ghost ai-btn--compact ${sizeClass} ${radiusClass}`, onClick: saveToFile, children: [_jsx(Download, { size: 14 }), t("common.save", "Save")] }), _jsx("button", { type: "button", className: "ai-icon-btn", onClick: () => {
150
+ }, children: _jsxs("div", { className: "ai-popover ai-result-modal", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "ai-result-header", children: [_jsxs("div", { className: "ai-row", children: [_jsx(FileText, { size: 18 }), _jsx("h2", { className: "ai-result-title", children: resultModalTitle ||
151
+ t("ai.context.resultTitle", "Analysis result") })] }), _jsxs("div", { className: "ai-row", children: [_jsxs("button", { type: "button", className: `ai-btn ai-btn--ghost ai-btn--compact ${sizeClass} ${radiusClass}`, onClick: saveToFile, children: [_jsx(Download, { size: 14 }), t("common.save", "Save")] }), _jsx("button", { type: "button", className: "ai-icon-btn", onClick: () => {
151
152
  setIsResultOpen(false);
152
153
  setAnalysisResult(null);
153
154
  }, "aria-label": t("common.closeLabel", "Close"), children: _jsx(X, { size: 16 }) })] })] }), _jsxs("div", { className: "ai-result-body", children: [_jsxs("div", { className: "ai-result-block", children: [_jsx("h3", { className: "ai-result-subtitle", children: t("common.promptUsed", "Prompt used") }), _jsx("pre", { className: "ai-result-code", children: analysisResult.prompt })] }), _jsxs("div", { className: "ai-result-block", children: [_jsx("h3", { className: "ai-result-subtitle", children: t("common.result", "Result") }), _jsx("div", { className: "ai-result-content", children: analysisResult.content })] }), _jsxs("div", { className: "ai-result-meta ai-between", children: [_jsxs("span", { children: [t("ai.context.cost", "Cost"), ": $", (apiKeyId?.includes("dev")
@@ -1 +1 @@
1
- {"version":3,"file":"AiImageButton.d.ts","sourceRoot":"","sources":["../../src/components/AiImageButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAS5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,MAAM,WAAW,kBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,OAAO,CAAC,EAAE,CACR,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAoB,EACpB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,GAAG,WAAW,EACf,EAAE,kBAAkB,2CA8QpB"}
1
+ {"version":3,"file":"AiImageButton.d.ts","sourceRoot":"","sources":["../../src/components/AiImageButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAS5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAY5D,MAAM,WAAW,kBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACvE,OAAO,CAAC,EAAE,CACR,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAC7C,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,YAAY,EACtB,MAAgB,EAChB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAoB,EACpB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,IAAW,EACX,MAAe,EACf,OAAmB,EACnB,GAAG,WAAW,EACf,EAAE,kBAAkB,2CAoRpB"}
@@ -61,7 +61,10 @@ export function AiImageButton({ baseUrl: propBaseUrl, apiKeyId: propApiKeyId, ui
61
61
  return;
62
62
  try {
63
63
  await onImageSave(generatedImage.url);
64
- onToast?.({ type: "success", message: t("ai.image.savedSuccess", "Image saved") });
64
+ onToast?.({
65
+ type: "success",
66
+ message: t("ai.image.savedSuccess", "Image saved"),
67
+ });
65
68
  }
66
69
  catch (_error) {
67
70
  onToast?.({
@@ -1 +1 @@
1
- {"version":3,"file":"AiModelSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiModelSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,2CAkBpB"}
1
+ {"version":3,"file":"AiModelSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiModelSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,2CAoBpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAmHD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,EACd,IAAW,EACX,MAAe,GAChB,EAAE,mBAAmB,2CAyhBrB"}
1
+ {"version":3,"file":"AiStatusButton.d.ts","sourceRoot":"","sources":["../../src/components/AiStatusButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAU,MAAM,uBAAuB,CAAC;AAuB9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGjD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAmHD,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,OAAe,EACf,SAAc,EACd,IAAW,EACX,MAAe,GAChB,EAAE,mBAAmB,2CA2iBrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAO5B,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,2CAyDtB;AAED;;;GAGG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAExD"}
1
+ {"version":3,"file":"LBConnectButton.d.ts","sourceRoot":"","sources":["../../src/components/LBConnectButton.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAO5B,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,SAAc,EACd,WAAW,EACX,WAAW,GACZ,EAAE,oBAAoB,2CAuDtB;AAED;;;GAGG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAExD"}
@@ -25,9 +25,7 @@ export function LBConnectButton({ label, className = "", onConnected, onOpenModa
25
25
  onOpenModal?.();
26
26
  };
27
27
  const connectLabel = label || t("auth.signIn", "Sign in");
28
- const buttonLabel = status === "ready" && user
29
- ? t("auth.signOut", "Sign out")
30
- : connectLabel;
28
+ const buttonLabel = status === "ready" && user ? t("auth.signOut", "Sign out") : connectLabel;
31
29
  return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleClick, className: className || "ai-btn ai-btn--auth", disabled: status === "loading", children: status === "loading" ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 16, className: "animate-spin" }), t("common.loading", "Loading...")] })) : status === "ready" && user ? (_jsxs(_Fragment, { children: [_jsx(LogOut, { size: 16 }), buttonLabel] })) : (_jsxs(_Fragment, { children: [_jsx(LogIn, { size: 16 }), buttonLabel] })) }), _jsx(LBSigninModal, { isOpen: showModal, onClose: () => setShowModal(false) })] }));
32
30
  }
33
31
  export function LBAuthModal({ onClose }) {
@@ -1 +1 @@
1
- {"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,sCAoPpE"}
1
+ {"version":3,"file":"LBSigninModal.d.ts","sourceRoot":"","sources":["../../src/components/LBSigninModal.tsx"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAQ5B,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,sCAsPpE"}
@@ -9,7 +9,7 @@ export interface I18nProviderProps {
9
9
  children: ReactNode;
10
10
  lang?: LBSupportedLang;
11
11
  }
12
- export declare function I18nProvider({ children, lang }: I18nProviderProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function I18nProvider({ children, lang, }: I18nProviderProps): import("react/jsx-runtime").JSX.Element;
13
13
  export declare function useI18n(): I18nContextValue;
14
14
  export {};
15
15
  //# sourceMappingURL=I18nContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"I18nContext.d.ts","sourceRoot":"","sources":["../../src/context/I18nContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ3E,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAatE,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvD,UAAU,gBAAgB;IACxB,IAAI,EAAE,eAAe,CAAC;IACtB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,KAAK,MAAM,CAAC;CACzE;AAeD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,IAAkB,EAAE,EAAE,iBAAiB,2CAkB/E;AAED,wBAAgB,OAAO,qBAEtB"}
1
+ {"version":3,"file":"I18nContext.d.ts","sourceRoot":"","sources":["../../src/context/I18nContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAQ3E,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAatE,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEvD,UAAU,gBAAgB;IACxB,IAAI,EAAE,eAAe,CAAC;IACtB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,KAAK,MAAM,CAAC;CACzE;AAeD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,eAAe,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,IAAkB,GACnB,EAAE,iBAAiB,2CAmBnB;AAED,wBAAgB,OAAO,qBAEtB"}
@@ -25,7 +25,7 @@ const I18nContext = createContext({
25
25
  return template.replace(/\{(\w+)\}/g, (_, p) => params[p] !== undefined ? String(params[p]) : `{${p}}`);
26
26
  },
27
27
  });
28
- export function I18nProvider({ children, lang = defaultLang }) {
28
+ export function I18nProvider({ children, lang = defaultLang, }) {
29
29
  const safeLang = dictionaries[lang] ? lang : defaultLang;
30
30
  const value = useMemo(() => {
31
31
  const dict = dictionaries[safeLang] || dictionaries[defaultLang];
@@ -1 +1 @@
1
- {"version":3,"file":"useLoadingTimer.d.ts","sourceRoot":"","sources":["../../src/hooks/useLoadingTimer.ts"],"names":[],"mappings":"AAWA,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO;;;EAmB9C"}
1
+ {"version":3,"file":"useLoadingTimer.d.ts","sourceRoot":"","sources":["../../src/hooks/useLoadingTimer.ts"],"names":[],"mappings":"AAWA,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO;;;EA0B9C"}
@@ -11,17 +11,21 @@ export function useLoadingTimer(active) {
11
11
  const [seconds, setSeconds] = useState(0);
12
12
  useEffect(() => {
13
13
  if (!active) {
14
- setSeconds(0);
15
- return;
14
+ const timeoutId = window.setTimeout(() => setSeconds(0), 0);
15
+ return () => window.clearTimeout(timeoutId);
16
16
  }
17
- setSeconds(0);
18
- const id = window.setInterval(() => {
17
+ const resetId = window.setTimeout(() => setSeconds(0), 0);
18
+ const intervalId = window.setInterval(() => {
19
19
  setSeconds((prev) => prev + 1);
20
20
  }, 1000);
21
- return () => window.clearInterval(id);
21
+ return () => {
22
+ window.clearTimeout(resetId);
23
+ window.clearInterval(intervalId);
24
+ };
22
25
  }, [active]);
26
+ const displaySeconds = active ? seconds : 0;
23
27
  return {
24
- seconds,
25
- formatted: formatElapsed(seconds),
28
+ seconds: displaySeconds,
29
+ formatted: formatElapsed(displaySeconds),
26
30
  };
27
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/ai-ui-react",
3
- "version": "1.0.74",
3
+ "version": "1.0.75",
4
4
  "description": "Headless React components for LastBrain AI UI Kit",
5
5
  "private": false,
6
6
  "type": "module",
@@ -212,10 +212,7 @@ Exemple de réponse attendue: javascript, react, frontend, api, development`;
212
212
  onKeyDown={handleKeyDown}
213
213
  placeholder={
214
214
  placeholder ||
215
- t(
216
- "ai.chips.placeholder",
217
- "Type and press Enter to add tags..."
218
- )
215
+ t("ai.chips.placeholder", "Type and press Enter to add tags...")
219
216
  }
220
217
  className={`ai-control ai-control-input ai-control-input--with-action ${sizeClass} ${radiusClass}`}
221
218
  />
@@ -208,7 +208,9 @@ export function AiContextButton({
208
208
  )
209
209
  ? 0
210
210
  : analysisResult.cost
211
- ).toFixed(6)}\n${t("ai.context.requestId", "Request ID")}: ${analysisResult.requestId || "N/A"}`;
211
+ ).toFixed(
212
+ 6
213
+ )}\n${t("ai.context.requestId", "Request ID")}: ${analysisResult.requestId || "N/A"}`;
212
214
 
213
215
  const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
214
216
  const url = URL.createObjectURL(blob);
@@ -254,7 +256,9 @@ export function AiContextButton({
254
256
  ) : (
255
257
  <>
256
258
  <Sparkles size={16} />
257
- {children || <span>{t("ai.context.buttonAnalyze", "Analyze")}</span>}
259
+ {children || (
260
+ <span>{t("ai.context.buttonAnalyze", "Analyze")}</span>
261
+ )}
258
262
  </>
259
263
  )}
260
264
  </button>
@@ -292,7 +296,8 @@ export function AiContextButton({
292
296
  <div className="ai-row">
293
297
  <FileText size={18} />
294
298
  <h2 className="ai-result-title">
295
- {resultModalTitle || t("ai.context.resultTitle", "Analysis result")}
299
+ {resultModalTitle ||
300
+ t("ai.context.resultTitle", "Analysis result")}
296
301
  </h2>
297
302
  </div>
298
303
  <div className="ai-row">
@@ -320,12 +325,16 @@ export function AiContextButton({
320
325
 
321
326
  <div className="ai-result-body">
322
327
  <div className="ai-result-block">
323
- <h3 className="ai-result-subtitle">{t("common.promptUsed", "Prompt used")}</h3>
328
+ <h3 className="ai-result-subtitle">
329
+ {t("common.promptUsed", "Prompt used")}
330
+ </h3>
324
331
  <pre className="ai-result-code">{analysisResult.prompt}</pre>
325
332
  </div>
326
333
 
327
334
  <div className="ai-result-block">
328
- <h3 className="ai-result-subtitle">{t("common.result", "Result")}</h3>
335
+ <h3 className="ai-result-subtitle">
336
+ {t("common.result", "Result")}
337
+ </h3>
329
338
  <div className="ai-result-content">
330
339
  {analysisResult.content}
331
340
  </div>
@@ -122,7 +122,10 @@ export function AiImageButton({
122
122
  if (!generatedImage || !onImageSave) return;
123
123
  try {
124
124
  await onImageSave(generatedImage.url);
125
- onToast?.({ type: "success", message: t("ai.image.savedSuccess", "Image saved") });
125
+ onToast?.({
126
+ type: "success",
127
+ message: t("ai.image.savedSuccess", "Image saved"),
128
+ });
126
129
  } catch (_error) {
127
130
  onToast?.({
128
131
  type: "error",
@@ -174,7 +177,10 @@ export function AiImageButton({
174
177
  });
175
178
  onToast?.({
176
179
  type: "success",
177
- message: t("ai.image.generatedSuccess", "Image generated successfully"),
180
+ message: t(
181
+ "ai.image.generatedSuccess",
182
+ "Image generated successfully"
183
+ ),
178
184
  });
179
185
 
180
186
  // Afficher le toast de coût même en mode dev
@@ -29,7 +29,9 @@ export function AiModelSelect({
29
29
  disabled={disabled}
30
30
  data-ai-model-select
31
31
  >
32
- <option value="">{t("ai.select.modelPlaceholder", "Select a model")}</option>
32
+ <option value="">
33
+ {t("ai.select.modelPlaceholder", "Select a model")}
34
+ </option>
33
35
  {models.map((model) => (
34
36
  <option key={model.id} value={model.id}>
35
37
  {model.name}
@@ -570,7 +570,10 @@ function AiPromptPanelInternal({
570
570
  AI Model
571
571
  </label>
572
572
  {isModelsLoading ? (
573
- <span className="ai-inline-skeleton" aria-hidden="true" />
573
+ <span
574
+ className="ai-inline-skeleton"
575
+ aria-hidden="true"
576
+ />
574
577
  ) : effectiveAvailableModels.length > 0 ? (
575
578
  <button
576
579
  onClick={() => setIsModelManagementOpen(true)}
@@ -747,17 +750,17 @@ function AiPromptPanelInternal({
747
750
  onChange={(e) => setPrompt(e.target.value)}
748
751
  onFocus={() => setPromptFocused(true)}
749
752
  onBlur={() => setPromptFocused(false)}
750
- placeholder={
751
- sourceText
752
- ? t(
753
- "prompt.modal.promptPlaceholderWithSource",
754
- "Enter your AI prompt... e.g., 'Fix grammar', 'Make it more professional', 'Translate to English'"
755
- )
756
- : t(
757
- "prompt.modal.promptPlaceholderNoSource",
758
- "Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'"
759
- )
760
- }
753
+ placeholder={
754
+ sourceText
755
+ ? t(
756
+ "prompt.modal.promptPlaceholderWithSource",
757
+ "Enter your AI prompt... e.g., 'Fix grammar', 'Make it more professional', 'Translate to English'"
758
+ )
759
+ : t(
760
+ "prompt.modal.promptPlaceholderNoSource",
761
+ "Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'"
762
+ )
763
+ }
761
764
  rows={6}
762
765
  style={{
763
766
  ...aiStyles.textarea,
@@ -889,7 +892,10 @@ function AiPromptPanelInternal({
889
892
  }}
890
893
  >
891
894
  {Array.from({ length: 4 }).map((_, idx) => (
892
- <div key={`prompt-skeleton-${idx}`} className="ai-list-skeleton">
895
+ <div
896
+ key={`prompt-skeleton-${idx}`}
897
+ className="ai-list-skeleton"
898
+ >
893
899
  <div className="ai-list-skeleton__line ai-list-skeleton__line--lg" />
894
900
  <div className="ai-list-skeleton__line ai-list-skeleton__line--md" />
895
901
  </div>
@@ -1260,7 +1266,10 @@ function AiPromptPanelInternal({
1260
1266
  {isModelsLoading ? (
1261
1267
  <>
1262
1268
  {Array.from({ length: 4 }).map((_, idx) => (
1263
- <div key={`model-skeleton-${idx}`} className="ai-list-skeleton">
1269
+ <div
1270
+ key={`model-skeleton-${idx}`}
1271
+ className="ai-list-skeleton"
1272
+ >
1264
1273
  <div className="ai-list-skeleton__line ai-list-skeleton__line--lg" />
1265
1274
  <div className="ai-list-skeleton__line ai-list-skeleton__line--md" />
1266
1275
  </div>
@@ -1365,35 +1374,35 @@ function AiPromptPanelInternal({
1365
1374
  );
1366
1375
  })}
1367
1376
  {!isModelsLoading &&
1368
- effectiveAvailableModels.filter((model) => {
1369
- if (model.category !== modelCategory) return false;
1370
- if (!modelSearchQuery.trim()) return true;
1371
- const query = modelSearchQuery.toLowerCase();
1372
- return (
1373
- model.name.toLowerCase().includes(query) ||
1374
- model.provider.toLowerCase().includes(query) ||
1375
- model.description?.toLowerCase().includes(query)
1376
- );
1377
- }).length === 0 && (
1378
- <div
1379
- style={{
1380
- textAlign: "center",
1381
- padding: "32px 16px",
1382
- color: "var(--ai-text-tertiary)",
1383
- fontSize: "14px",
1384
- }}
1385
- >
1386
- {modelSearchQuery.trim()
1387
- ? t(
1388
- "prompt.modal.noModelMatch",
1389
- "No model matches your search"
1390
- )
1391
- : t(
1392
- "prompt.modal.noModelAvailable",
1393
- "No models available"
1394
- )}
1395
- </div>
1396
- )}
1377
+ effectiveAvailableModels.filter((model) => {
1378
+ if (model.category !== modelCategory) return false;
1379
+ if (!modelSearchQuery.trim()) return true;
1380
+ const query = modelSearchQuery.toLowerCase();
1381
+ return (
1382
+ model.name.toLowerCase().includes(query) ||
1383
+ model.provider.toLowerCase().includes(query) ||
1384
+ model.description?.toLowerCase().includes(query)
1385
+ );
1386
+ }).length === 0 && (
1387
+ <div
1388
+ style={{
1389
+ textAlign: "center",
1390
+ padding: "32px 16px",
1391
+ color: "var(--ai-text-tertiary)",
1392
+ fontSize: "14px",
1393
+ }}
1394
+ >
1395
+ {modelSearchQuery.trim()
1396
+ ? t(
1397
+ "prompt.modal.noModelMatch",
1398
+ "No model matches your search"
1399
+ )
1400
+ : t(
1401
+ "prompt.modal.noModelAvailable",
1402
+ "No models available"
1403
+ )}
1404
+ </div>
1405
+ )}
1397
1406
  </div>
1398
1407
  </div>
1399
1408
 
@@ -229,8 +229,7 @@ export function AiStatusButton({
229
229
  : undefined;
230
230
  const requiresApiKeySelection =
231
231
  lbStatus === "ready" && !hasApiKeySelected && apiKeys.length > 0;
232
- const isApiKeyAuthMode =
233
- authTypeValue === "api_key";
232
+ const isApiKeyAuthMode = authTypeValue === "api_key";
234
233
 
235
234
  const [tooltipStyle, setTooltipStyle] = useState<Record<string, string>>({});
236
235
 
@@ -328,11 +327,11 @@ export function AiStatusButton({
328
327
 
329
328
  const hasApiKeyMeta = Boolean(
330
329
  effectiveStatus?.apiKey?.name ||
331
- effectiveStatus?.api_key?.name ||
332
- effectiveStatus?.apiKey?.env ||
333
- effectiveStatus?.api_key?.env ||
334
- effectiveStatus?.apiKey?.rate_limit_rpm ||
335
- effectiveStatus?.api_key?.rate_limit_rpm
330
+ effectiveStatus?.api_key?.name ||
331
+ effectiveStatus?.apiKey?.env ||
332
+ effectiveStatus?.api_key?.env ||
333
+ effectiveStatus?.apiKey?.rate_limit_rpm ||
334
+ effectiveStatus?.api_key?.rate_limit_rpm
336
335
  );
337
336
  const hasBalanceMeta = Boolean(effectiveStatus?.balance);
338
337
  const hasStorageMeta = Boolean(effectiveStatus?.storage);
@@ -422,10 +421,14 @@ export function AiStatusButton({
422
421
  {lbStatus === "ready" && user ? (
423
422
  <>
424
423
  <div className="ai-popover-body">
425
- <div className="ai-popover-header">{t("status.title", "API Status")}</div>
424
+ <div className="ai-popover-header">
425
+ {t("status.title", "API Status")}
426
+ </div>
426
427
  <div className="ai-popover-section ai-popover-section--first">
427
428
  <div className="ai-popover-row">
428
- <span className="ai-popover-label">{t("status.user", "User")}</span>
429
+ <span className="ai-popover-label">
430
+ {t("status.user", "User")}
431
+ </span>
429
432
  <span
430
433
  className="ai-popover-value ai-truncate"
431
434
  style={{ maxWidth: 200 }}
@@ -437,7 +440,9 @@ export function AiStatusButton({
437
440
 
438
441
  <div className="ai-popover-section">
439
442
  <div className="ai-popover-row">
440
- <span className="ai-popover-label">{t("status.apiKey", "API Key")}</span>
443
+ <span className="ai-popover-label">
444
+ {t("status.apiKey", "API Key")}
445
+ </span>
441
446
  <div className="ai-row">
442
447
  {lbIsLoadingStatus || isImplicitStatusLoading ? (
443
448
  <div className="ai-kv-skeleton ai-kv-skeleton--110" />
@@ -468,7 +473,9 @@ export function AiStatusButton({
468
473
  </div>
469
474
 
470
475
  <div className="ai-popover-row">
471
- <span className="ai-popover-label">{t("status.env", "Env")}</span>
476
+ <span className="ai-popover-label">
477
+ {t("status.env", "Env")}
478
+ </span>
472
479
  {(lbIsLoadingStatus || isImplicitStatusLoading) &&
473
480
  !effectiveStatus?.apiKey?.env ? (
474
481
  <div className="ai-kv-skeleton ai-kv-skeleton--48" />
@@ -482,7 +489,9 @@ export function AiStatusButton({
482
489
  </div>
483
490
 
484
491
  <div className="ai-popover-row">
485
- <span className="ai-popover-label">{t("status.rateLimit", "Rate Limit")}</span>
492
+ <span className="ai-popover-label">
493
+ {t("status.rateLimit", "Rate Limit")}
494
+ </span>
486
495
  {(lbIsLoadingStatus || isImplicitStatusLoading) &&
487
496
  !effectiveStatus?.apiKey?.rate_limit_rpm ? (
488
497
  <div className="ai-kv-skeleton ai-kv-skeleton--92" />
@@ -490,14 +499,16 @@ export function AiStatusButton({
490
499
  <span className="ai-popover-value">
491
500
  {effectiveStatus?.apiKey?.rate_limit_rpm ||
492
501
  effectiveStatus?.api_key?.rate_limit_rpm ||
493
- 0}{" "}
502
+ 0}{" "}
494
503
  req/min
495
504
  </span>
496
505
  )}
497
506
  </div>
498
507
 
499
508
  <div className="ai-popover-row">
500
- <span className="ai-popover-label">{t("status.auth", "Auth")}</span>
509
+ <span className="ai-popover-label">
510
+ {t("status.auth", "Auth")}
511
+ </span>
501
512
  <span className="ai-popover-value">
502
513
  {lbIsLoadingStatus || isImplicitStatusLoading
503
514
  ? "..."
@@ -513,7 +524,9 @@ export function AiStatusButton({
513
524
  {t("status.wallet", "Wallet")}
514
525
  </div>
515
526
  <div className="ai-popover-row">
516
- <span className="ai-popover-label">{t("status.total", "Total")}</span>
527
+ <span className="ai-popover-label">
528
+ {t("status.total", "Total")}
529
+ </span>
517
530
  {(lbIsLoadingStatus || isImplicitStatusLoading) &&
518
531
  !effectiveStatus?.balance ? (
519
532
  <div className="ai-row">
@@ -536,7 +549,9 @@ export function AiStatusButton({
536
549
  {t("status.storage", "Storage")}
537
550
  </div>
538
551
  <div className="ai-popover-row">
539
- <span className="ai-popover-label">{t("status.total", "Total")}</span>
552
+ <span className="ai-popover-label">
553
+ {t("status.total", "Total")}
554
+ </span>
540
555
  {lbIsLoadingStorage || isImplicitStorageLoading ? (
541
556
  <div className="ai-row">
542
557
  <div className="ai-kv-skeleton ai-kv-skeleton--120" />
@@ -564,8 +579,8 @@ export function AiStatusButton({
564
579
  type="button"
565
580
  className="ai-status-action-btn"
566
581
  onClick={() => window.open(item.href, "_blank")}
567
- title={label}
568
- data-ai-tip={label}
582
+ title={label}
583
+ data-ai-tip={label}
569
584
  >
570
585
  <Icon size={17} />
571
586
  </button>
@@ -602,7 +617,10 @@ export function AiStatusButton({
602
617
  {t("status.lastbrainAuth", "LastBrain Authentication")}
603
618
  </div>
604
619
  <p className="ai-signin-subtitle" style={{ marginTop: 0 }}>
605
- {t("status.connectToAccess", "Sign in to access AI features.")}
620
+ {t(
621
+ "status.connectToAccess",
622
+ "Sign in to access AI features."
623
+ )}
606
624
  </p>
607
625
  <button
608
626
  type="button"
@@ -122,11 +122,11 @@ export function LBApiKeySelector({
122
122
  {t("common.active", "Active")}
123
123
  </span>
124
124
  ) : (
125
- <span className="ai-pill ai-pill--cost">
126
- <XCircle size={12} />
127
- {t("common.inactive", "Inactive")}
128
- </span>
129
- )}
125
+ <span className="ai-pill ai-pill--cost">
126
+ <XCircle size={12} />
127
+ {t("common.inactive", "Inactive")}
128
+ </span>
129
+ )}
130
130
  </label>
131
131
  );
132
132
  })}
@@ -43,9 +43,7 @@ export function LBConnectButton({
43
43
 
44
44
  const connectLabel = label || t("auth.signIn", "Sign in");
45
45
  const buttonLabel =
46
- status === "ready" && user
47
- ? t("auth.signOut", "Sign out")
48
- : connectLabel;
46
+ status === "ready" && user ? t("auth.signOut", "Sign out") : connectLabel;
49
47
 
50
48
  return (
51
49
  <>
@@ -64,9 +64,7 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
64
64
  }
65
65
 
66
66
  if (!fetchApiKeys || !result.accessToken) {
67
- setError(
68
- t("auth.modal.tokenMissing", "Access token unavailable")
69
- );
67
+ setError(t("auth.modal.tokenMissing", "Access token unavailable"));
70
68
  return;
71
69
  }
72
70
 
@@ -76,9 +74,7 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
76
74
  setShowKeySelector(true);
77
75
  } catch (keyError) {
78
76
  console.error("Failed to fetch API keys:", keyError);
79
- setError(
80
- t("auth.modal.apiKeysFetchError", "Failed to fetch API keys")
81
- );
77
+ setError(t("auth.modal.apiKeysFetchError", "Failed to fetch API keys"));
82
78
  }
83
79
  } catch (err) {
84
80
  setError(
@@ -186,7 +182,10 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
186
182
  required
187
183
  autoFocus
188
184
  autoComplete="email"
189
- placeholder={t("auth.modal.emailPlaceholder", "your@email.com")}
185
+ placeholder={t(
186
+ "auth.modal.emailPlaceholder",
187
+ "your@email.com"
188
+ )}
190
189
  />
191
190
  </div>
192
191
  </div>
@@ -210,7 +209,10 @@ export function LBSigninModal({ isOpen, onClose }: LBSigninModalProps) {
210
209
  onChange={(e) => setPassword(e.target.value)}
211
210
  required
212
211
  autoComplete="current-password"
213
- placeholder={t("auth.modal.passwordPlaceholder", "••••••••")}
212
+ placeholder={t(
213
+ "auth.modal.passwordPlaceholder",
214
+ "••••••••"
215
+ )}
214
216
  />
215
217
  </div>
216
218
  </div>
@@ -46,14 +46,18 @@ export interface I18nProviderProps {
46
46
  lang?: LBSupportedLang;
47
47
  }
48
48
 
49
- export function I18nProvider({ children, lang = defaultLang }: I18nProviderProps) {
49
+ export function I18nProvider({
50
+ children,
51
+ lang = defaultLang,
52
+ }: I18nProviderProps) {
50
53
  const safeLang: LBSupportedLang = dictionaries[lang] ? lang : defaultLang;
51
54
 
52
55
  const value = useMemo<I18nContextValue>(() => {
53
56
  const dict = dictionaries[safeLang] || dictionaries[defaultLang];
54
57
 
55
58
  const t = (key: string, fallback?: string, params?: TranslateParams) => {
56
- const template = dict[key] || dictionaries[defaultLang][key] || fallback || key;
59
+ const template =
60
+ dict[key] || dictionaries[defaultLang][key] || fallback || key;
57
61
  if (!params) return template;
58
62
  return template.replace(/\{(\w+)\}/g, (_, p: string) =>
59
63
  params[p] !== undefined ? String(params[p]) : `{${p}}`
@@ -14,19 +14,25 @@ export function useLoadingTimer(active: boolean) {
14
14
 
15
15
  useEffect(() => {
16
16
  if (!active) {
17
- setSeconds(0);
18
- return;
17
+ const timeoutId = window.setTimeout(() => setSeconds(0), 0);
18
+ return () => window.clearTimeout(timeoutId);
19
19
  }
20
- setSeconds(0);
21
- const id = window.setInterval(() => {
20
+
21
+ const resetId = window.setTimeout(() => setSeconds(0), 0);
22
+ const intervalId = window.setInterval(() => {
22
23
  setSeconds((prev) => prev + 1);
23
24
  }, 1000);
24
- return () => window.clearInterval(id);
25
+
26
+ return () => {
27
+ window.clearTimeout(resetId);
28
+ window.clearInterval(intervalId);
29
+ };
25
30
  }, [active]);
26
31
 
32
+ const displaySeconds = active ? seconds : 0;
33
+
27
34
  return {
28
- seconds,
29
- formatted: formatElapsed(seconds),
35
+ seconds: displaySeconds,
36
+ formatted: formatElapsed(displaySeconds),
30
37
  };
31
38
  }
32
-