@lastbrain/ai-ui-react 1.0.74 → 1.0.76

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 (63) hide show
  1. package/dist/components/AiChipLabel.d.ts.map +1 -1
  2. package/dist/components/AiContextButton.d.ts +1 -1
  3. package/dist/components/AiContextButton.d.ts.map +1 -1
  4. package/dist/components/AiContextButton.js +3 -2
  5. package/dist/components/AiImageButton.d.ts.map +1 -1
  6. package/dist/components/AiImageButton.js +6 -3
  7. package/dist/components/AiInput.d.ts +1 -1
  8. package/dist/components/AiInput.d.ts.map +1 -1
  9. package/dist/components/AiInput.js +4 -4
  10. package/dist/components/AiModelSelect.d.ts.map +1 -1
  11. package/dist/components/AiPromptPanel.js +30 -6
  12. package/dist/components/AiSelect.d.ts +1 -1
  13. package/dist/components/AiSelect.d.ts.map +1 -1
  14. package/dist/components/AiSelect.js +1 -1
  15. package/dist/components/AiStatusButton.d.ts.map +1 -1
  16. package/dist/components/AiStatusButton.js +2 -2
  17. package/dist/components/AiTextarea.d.ts +2 -1
  18. package/dist/components/AiTextarea.d.ts.map +1 -1
  19. package/dist/components/AiTextarea.js +16 -6
  20. package/dist/components/ErrorToast.js +3 -3
  21. package/dist/components/LBConnectButton.d.ts.map +1 -1
  22. package/dist/components/LBConnectButton.js +1 -3
  23. package/dist/components/LBKeyPicker.js +9 -9
  24. package/dist/components/LBSigninModal.d.ts.map +1 -1
  25. package/dist/components/UsageToast.d.ts +3 -3
  26. package/dist/components/UsageToast.d.ts.map +1 -1
  27. package/dist/context/I18nContext.d.ts +1 -1
  28. package/dist/context/I18nContext.d.ts.map +1 -1
  29. package/dist/context/I18nContext.js +1 -1
  30. package/dist/context/LBAuthProvider.d.ts.map +1 -1
  31. package/dist/context/LBAuthProvider.js +12 -5
  32. package/dist/examples/AiImageGenerator.js +1 -1
  33. package/dist/hooks/useAiStatus.d.ts.map +1 -1
  34. package/dist/hooks/useAiStatus.js +43 -5
  35. package/dist/hooks/useLoadingTimer.d.ts.map +1 -1
  36. package/dist/hooks/useLoadingTimer.js +11 -7
  37. package/dist/styles.css +3 -3
  38. package/dist/utils/errorHandler.d.ts +2 -2
  39. package/dist/utils/errorHandler.d.ts.map +1 -1
  40. package/package.json +2 -2
  41. package/src/components/AiChipLabel.tsx +1 -4
  42. package/src/components/AiContextButton.tsx +15 -6
  43. package/src/components/AiImageButton.tsx +10 -4
  44. package/src/components/AiInput.tsx +9 -4
  45. package/src/components/AiModelSelect.tsx +3 -1
  46. package/src/components/AiPromptPanel.tsx +83 -49
  47. package/src/components/AiSelect.tsx +2 -2
  48. package/src/components/AiStatusButton.tsx +48 -27
  49. package/src/components/AiTextarea.tsx +25 -9
  50. package/src/components/ErrorToast.tsx +3 -3
  51. package/src/components/LBApiKeySelector.tsx +5 -5
  52. package/src/components/LBConnectButton.tsx +1 -3
  53. package/src/components/LBKeyPicker.tsx +10 -10
  54. package/src/components/LBSigninModal.tsx +12 -9
  55. package/src/components/UsageToast.tsx +4 -4
  56. package/src/context/I18nContext.tsx +6 -2
  57. package/src/context/LBAuthProvider.tsx +12 -5
  58. package/src/examples/AiImageGenerator.tsx +1 -1
  59. package/src/hooks/useAiStatus.ts +47 -5
  60. package/src/hooks/useLoadingTimer.ts +14 -8
  61. package/src/styles.css +3 -3
  62. package/src/utils/errorHandler.ts +3 -3
  63. package/src/utils/modelManagement.ts +3 -3
@@ -1,12 +1,40 @@
1
1
  "use client";
2
- import { useState, useEffect, useCallback } from "react";
2
+ import { useState, useEffect, useCallback, useContext, useMemo } from "react";
3
3
  import { useAiClient } from "./useAiClient";
4
+ import { LBContext } from "../context/LBAuthProvider";
4
5
  export function useAiStatus(options) {
5
6
  const client = useAiClient(options);
7
+ const lbContext = useContext(LBContext);
6
8
  const [status, setStatus] = useState(null);
7
9
  const [loading, setLoading] = useState(false);
8
10
  const [error, setError] = useState(null);
11
+ const statusFromLB = useMemo(() => {
12
+ if (!lbContext || lbContext.status !== "ready") {
13
+ return null;
14
+ }
15
+ if (lbContext.apiStatus) {
16
+ return lbContext.apiStatus;
17
+ }
18
+ if (lbContext.basicStatus) {
19
+ return {
20
+ ...lbContext.basicStatus,
21
+ storage: lbContext.storageStatus?.storage ||
22
+ lbContext.basicStatus?.storage,
23
+ };
24
+ }
25
+ return null;
26
+ }, [lbContext]);
9
27
  const fetchStatus = useCallback(async () => {
28
+ // If LBProvider is available, it already handles fast status + storage split.
29
+ if (lbContext && lbContext.status === "ready") {
30
+ try {
31
+ await lbContext.refreshBasicStatus();
32
+ }
33
+ catch {
34
+ // Ignore: provider already tracks errors/status
35
+ }
36
+ return;
37
+ }
10
38
  console.log("[useAiStatus] Starting status fetch");
11
39
  setLoading(true);
12
40
  setError(null);
@@ -22,13 +50,23 @@ export function useAiStatus(options) {
22
50
  finally {
23
51
  setLoading(false);
24
52
  }
25
- }, [client]);
53
+ }, [client, lbContext]);
26
54
  useEffect(() => {
55
+ if (statusFromLB) {
56
+ setStatus(statusFromLB);
57
+ setLoading(false);
58
+ setError(null);
59
+ return;
60
+ }
27
61
  fetchStatus();
28
- }, [fetchStatus]);
62
+ }, [fetchStatus, statusFromLB]);
63
+ const isLoadingFromLB = !!lbContext &&
64
+ lbContext.status === "ready" &&
65
+ !statusFromLB &&
66
+ (lbContext.isLoadingStatus || lbContext.isLoadingStorage);
29
67
  return {
30
- status,
31
- loading,
68
+ status: statusFromLB || status,
69
+ loading: isLoadingFromLB || loading,
32
70
  error,
33
71
  refetch: fetchStatus,
34
72
  };
@@ -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/dist/styles.css CHANGED
@@ -195,7 +195,7 @@
195
195
  align-items: center;
196
196
  gap: 10px;
197
197
  min-height: var(--ai-control-h, var(--ai-size-md-h));
198
- padding: 0 12px;
198
+ padding: 0 8px;
199
199
  border-radius: var(--ai-radius-current, var(--ai-radius-full));
200
200
  border: 1px solid var(--ai-border);
201
201
  background:
@@ -362,8 +362,8 @@
362
362
  .ai-shell--textarea .ai-control-action,
363
363
  .ai-shell--textarea .ai-spark {
364
364
  position: absolute;
365
- right: 12px;
366
- bottom: 12px;
365
+ right: 8px;
366
+ bottom: 8px;
367
367
  }
368
368
 
369
369
  /* Generic buttons */
@@ -6,7 +6,7 @@ export interface ParsedError {
6
6
  /**
7
7
  * Parse et uniformise la gestion des erreurs des composants AI
8
8
  */
9
- export declare function parseAIError(error: unknown): ParsedError;
9
+ export declare function parseAIError(error: any): ParsedError;
10
10
  /**
11
11
  * Interface pour la callback de gestion d'erreur uniforme
12
12
  */
@@ -23,7 +23,7 @@ export interface ErrorToastCallback {
23
23
  * @param onToast Callback externe optionnelle fournie par le parent
24
24
  * @param showInternalToast Callback interne optionnelle pour afficher un toast dans le composant
25
25
  */
26
- export declare function handleAIError(error: unknown, onToast?: ErrorToastCallback, showInternalToast?: (error: {
26
+ export declare function handleAIError(error: any, onToast?: ErrorToastCallback, showInternalToast?: (error: {
27
27
  message: string;
28
28
  code?: string;
29
29
  }) => void): void;
@@ -1 +1 @@
1
- {"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/utils/errorHandler.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;CACzB;AAeD;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CA8CxD;AAyFD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,kBAAkB,EAC5B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,GACtE,IAAI,CAuBN"}
1
+ {"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/utils/errorHandler.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;CACzB;AAeD;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG,WAAW,CA8CpD;AAyFD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,GAAG,EACV,OAAO,CAAC,EAAE,kBAAkB,EAC5B,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,GACtE,IAAI,CAuBN"}
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.76",
4
4
  "description": "Headless React components for LastBrain AI UI Kit",
5
5
  "private": false,
6
6
  "type": "module",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "lucide-react": "^0.257.0",
54
- "@lastbrain/ai-ui-core": "1.0.54"
54
+ "@lastbrain/ai-ui-core": "1.0.55"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/react": "^19.2.0",
@@ -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
  />
@@ -22,7 +22,7 @@ type ContextData =
22
22
  | boolean
23
23
  | object
24
24
  | unknown[]
25
- | { [key: string]: unknown };
25
+ | { [key: string]: any };
26
26
 
27
27
  export interface AiContextButtonProps
28
28
  extends
@@ -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>
@@ -74,7 +74,7 @@ export function AiImageButton({
74
74
  requestId: string;
75
75
  tokens: number;
76
76
  } | null>(null);
77
- const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
77
+ const { showUsageToast } = useUsageToast();
78
78
  const { showErrorToast, errorData, errorKey, clearError } = useErrorToast();
79
79
 
80
80
  // Rendre l'authentification optionnelle
@@ -122,8 +122,11 @@ 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") });
126
- } catch (_error) {
125
+ onToast?.({
126
+ type: "success",
127
+ message: t("ai.image.savedSuccess", "Image saved"),
128
+ });
129
+ } catch {
127
130
  onToast?.({
128
131
  type: "error",
129
132
  message: t("ai.image.saveError", "Error while saving"),
@@ -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
@@ -34,7 +34,7 @@ export function AiInput({
34
34
  context,
35
35
  model,
36
36
  prompt,
37
- editMode = false,
37
+ editMode: _editMode = false,
38
38
  enableModelManagement = true,
39
39
  storeOutputs,
40
40
  artifactTitle,
@@ -51,7 +51,12 @@ export function AiInput({
51
51
  inputProps.value?.toString() || inputProps.defaultValue?.toString() || ""
52
52
  );
53
53
  const inputRef = useRef<HTMLInputElement>(null);
54
- const { showUsageToast, toastData, toastKey, clearToast } = useUsageToast();
54
+ const {
55
+ showUsageToast: _showUsageToast,
56
+ toastData,
57
+ toastKey,
58
+ clearToast,
59
+ } = useUsageToast();
55
60
 
56
61
  // Rendre l'authentification optionnelle
57
62
  let lbStatus: string | undefined;
@@ -77,7 +82,7 @@ export function AiInput({
77
82
  const baseUrl = propBaseUrl ?? ctxBaseUrl;
78
83
  const apiKeyId = propApiKeyId ?? ctxApiKeyId;
79
84
 
80
- const { models } = useAiModels({
85
+ const { models: _models } = useAiModels({
81
86
  baseUrl,
82
87
  apiKeyId,
83
88
  modelType: "text-or-language",
@@ -104,7 +109,7 @@ export function AiInput({
104
109
  const handleSubmit = async (
105
110
  selectedModel: string,
106
111
  selectedPrompt: string,
107
- promptId?: string
112
+ _promptId?: string
108
113
  ) => {
109
114
  try {
110
115
  const resolvedContext = inputValue || context || undefined;
@@ -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}
@@ -102,7 +102,7 @@ function AiPromptPanelInternal({
102
102
  isOpen,
103
103
  onClose,
104
104
  onSubmit,
105
- uiMode: _uiMode = "modal",
105
+ uiMode = "modal",
106
106
  models = [],
107
107
  sourceText,
108
108
  children,
@@ -405,9 +405,29 @@ function AiPromptPanelInternal({
405
405
  return null;
406
406
  }
407
407
 
408
+ const isDrawer = uiMode === "drawer";
409
+ const panelContainerStyle = isDrawer
410
+ ? {
411
+ ...aiStyles.modal,
412
+ alignItems: "stretch",
413
+ justifyContent: "flex-end",
414
+ padding: "0",
415
+ }
416
+ : aiStyles.modal;
417
+ const panelContentStyle = isDrawer
418
+ ? {
419
+ ...aiStyles.modalContent,
420
+ width: "min(92vw, 640px)",
421
+ maxWidth: "640px",
422
+ maxHeight: "100vh",
423
+ height: "100vh",
424
+ borderRadius: "16px 0 0 16px",
425
+ }
426
+ : aiStyles.modalContent;
427
+
408
428
  if (children) {
409
429
  return createPortal(
410
- <div style={aiStyles.modal} onKeyDown={handleKeyDown}>
430
+ <div style={panelContainerStyle} onKeyDown={handleKeyDown}>
411
431
  {children(renderProps)}
412
432
  </div>,
413
433
  portalRoot
@@ -415,7 +435,7 @@ function AiPromptPanelInternal({
415
435
  }
416
436
 
417
437
  return createPortal(
418
- <div style={aiStyles.modal} onKeyDown={handleKeyDown}>
438
+ <div style={panelContainerStyle} onKeyDown={handleKeyDown}>
419
439
  <div
420
440
  style={{
421
441
  ...aiStyles.modalOverlay,
@@ -426,13 +446,18 @@ function AiPromptPanelInternal({
426
446
  />
427
447
  <div
428
448
  style={{
429
- ...aiStyles.modalContent,
449
+ ...panelContentStyle,
430
450
  opacity: isClosing ? 0 : 1,
431
- transform: isClosing ? "translateY(12px)" : "translateY(0)",
451
+ transform: isClosing
452
+ ? isDrawer
453
+ ? "translateX(16px)"
454
+ : "translateY(12px)"
455
+ : isDrawer
456
+ ? "translateX(0)"
457
+ : "translateY(0)",
432
458
  transition: "opacity 200ms ease, transform 200ms ease",
433
459
  display: "flex",
434
460
  flexDirection: "column",
435
- maxHeight: "85vh",
436
461
  overflow: "hidden",
437
462
  }}
438
463
  >
@@ -570,7 +595,10 @@ function AiPromptPanelInternal({
570
595
  AI Model
571
596
  </label>
572
597
  {isModelsLoading ? (
573
- <span className="ai-inline-skeleton" aria-hidden="true" />
598
+ <span
599
+ className="ai-inline-skeleton"
600
+ aria-hidden="true"
601
+ />
574
602
  ) : effectiveAvailableModels.length > 0 ? (
575
603
  <button
576
604
  onClick={() => setIsModelManagementOpen(true)}
@@ -747,17 +775,17 @@ function AiPromptPanelInternal({
747
775
  onChange={(e) => setPrompt(e.target.value)}
748
776
  onFocus={() => setPromptFocused(true)}
749
777
  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
- }
778
+ placeholder={
779
+ sourceText
780
+ ? t(
781
+ "prompt.modal.promptPlaceholderWithSource",
782
+ "Enter your AI prompt... e.g., 'Fix grammar', 'Make it more professional', 'Translate to English'"
783
+ )
784
+ : t(
785
+ "prompt.modal.promptPlaceholderNoSource",
786
+ "Enter your AI prompt... e.g., 'Write a blog post about AI', 'Generate product description'"
787
+ )
788
+ }
761
789
  rows={6}
762
790
  style={{
763
791
  ...aiStyles.textarea,
@@ -889,7 +917,10 @@ function AiPromptPanelInternal({
889
917
  }}
890
918
  >
891
919
  {Array.from({ length: 4 }).map((_, idx) => (
892
- <div key={`prompt-skeleton-${idx}`} className="ai-list-skeleton">
920
+ <div
921
+ key={`prompt-skeleton-${idx}`}
922
+ className="ai-list-skeleton"
923
+ >
893
924
  <div className="ai-list-skeleton__line ai-list-skeleton__line--lg" />
894
925
  <div className="ai-list-skeleton__line ai-list-skeleton__line--md" />
895
926
  </div>
@@ -1260,7 +1291,10 @@ function AiPromptPanelInternal({
1260
1291
  {isModelsLoading ? (
1261
1292
  <>
1262
1293
  {Array.from({ length: 4 }).map((_, idx) => (
1263
- <div key={`model-skeleton-${idx}`} className="ai-list-skeleton">
1294
+ <div
1295
+ key={`model-skeleton-${idx}`}
1296
+ className="ai-list-skeleton"
1297
+ >
1264
1298
  <div className="ai-list-skeleton__line ai-list-skeleton__line--lg" />
1265
1299
  <div className="ai-list-skeleton__line ai-list-skeleton__line--md" />
1266
1300
  </div>
@@ -1365,35 +1399,35 @@ function AiPromptPanelInternal({
1365
1399
  );
1366
1400
  })}
1367
1401
  {!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
- )}
1402
+ effectiveAvailableModels.filter((model) => {
1403
+ if (model.category !== modelCategory) return false;
1404
+ if (!modelSearchQuery.trim()) return true;
1405
+ const query = modelSearchQuery.toLowerCase();
1406
+ return (
1407
+ model.name.toLowerCase().includes(query) ||
1408
+ model.provider.toLowerCase().includes(query) ||
1409
+ model.description?.toLowerCase().includes(query)
1410
+ );
1411
+ }).length === 0 && (
1412
+ <div
1413
+ style={{
1414
+ textAlign: "center",
1415
+ padding: "32px 16px",
1416
+ color: "var(--ai-text-tertiary)",
1417
+ fontSize: "14px",
1418
+ }}
1419
+ >
1420
+ {modelSearchQuery.trim()
1421
+ ? t(
1422
+ "prompt.modal.noModelMatch",
1423
+ "No model matches your search"
1424
+ )
1425
+ : t(
1426
+ "prompt.modal.noModelAvailable",
1427
+ "No models available"
1428
+ )}
1429
+ </div>
1430
+ )}
1397
1431
  </div>
1398
1432
  </div>
1399
1433
 
@@ -31,8 +31,8 @@ export function AiSelect({
31
31
  size = "md",
32
32
  radius = "full",
33
33
  context,
34
- model,
35
- prompt,
34
+ model: _model,
35
+ prompt: _prompt,
36
36
  storeOutputs,
37
37
  artifactTitle,
38
38
  onValue,