@schandlergarcia/sf-web-components 1.8.0 → 1.9.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/components/library/cards/SemanticTableCard.d.ts +1 -1
- package/dist/components/library/chat/ChatBar.d.ts +14 -11
- package/dist/components/library/chat/ChatBar.js +2 -3
- package/dist/components/library/chat/ChatBar.js.map +1 -1
- package/dist/components/library/chat/ChatInput.d.ts +9 -8
- package/dist/components/library/chat/ChatInput.js.map +1 -1
- package/dist/components/library/chat/ChatMessage.d.ts +17 -4
- package/dist/components/library/chat/ChatMessage.js.map +1 -1
- package/dist/components/library/chat/ChatMessageList.d.ts +11 -8
- package/dist/components/library/chat/ChatMessageList.js.map +1 -1
- package/dist/components/library/chat/ChatPanel.d.ts +16 -12
- package/dist/components/library/chat/ChatPanel.js +8 -9
- package/dist/components/library/chat/ChatPanel.js.map +1 -1
- package/dist/components/library/chat/ChatSuggestions.d.ts +5 -4
- package/dist/components/library/chat/ChatSuggestions.js +2 -3
- package/dist/components/library/chat/ChatSuggestions.js.map +1 -1
- package/dist/components/library/chat/ChatToolCall.d.ts +11 -3
- package/dist/components/library/chat/ChatToolCall.js.map +1 -1
- package/dist/components/library/chat/ChatTypingIndicator.d.ts +4 -3
- package/dist/components/library/chat/ChatTypingIndicator.js +2 -3
- package/dist/components/library/chat/ChatTypingIndicator.js.map +1 -1
- package/dist/components/library/chat/ChatWelcome.d.ts +9 -7
- package/dist/components/library/chat/ChatWelcome.js +6 -7
- package/dist/components/library/chat/ChatWelcome.js.map +1 -1
- package/dist/components/library/chat/index.d.ts +10 -0
- package/dist/components/library/chat/useChatState.d.ts +36 -11
- package/dist/components/library/chat/useChatState.js +63 -46
- package/dist/components/library/chat/useChatState.js.map +1 -1
- package/dist/components/library/data/DataModeProvider.d.ts +15 -11
- package/dist/components/library/data/DataModeProvider.js +1 -1
- package/dist/components/library/data/DataModeProvider.js.map +1 -1
- package/dist/components/library/data/DataModeToggle.d.ts +4 -3
- package/dist/components/library/data/DataModeToggle.js +4 -5
- package/dist/components/library/data/DataModeToggle.js.map +1 -1
- package/dist/components/library/data/chartDataProvider.d.ts +41 -3
- package/dist/components/library/data/filterUtils.d.ts +38 -9
- package/dist/components/library/data/filterUtils.js.map +1 -1
- package/dist/components/library/data/useDataSource.d.ts +6 -4
- package/dist/components/library/data/useDataSource.js.map +1 -1
- package/dist/components/library/data/usePageFilters.d.ts +31 -5
- package/dist/components/library/data/usePageFilters.js +6 -2
- package/dist/components/library/data/usePageFilters.js.map +1 -1
- package/dist/components/library/index.d.ts +92 -73
- package/dist/components/library/index.js +25 -25
- package/dist/components/library/index.js.map +1 -1
- package/dist/components/library/skeletons/CardSkeleton.d.ts +5 -4
- package/dist/components/library/skeletons/CardSkeleton.js +2 -3
- package/dist/components/library/skeletons/CardSkeleton.js.map +1 -1
- package/dist/components/library/theme/AppThemeProvider.d.ts +13 -50
- package/dist/components/library/theme/AppThemeProvider.js.map +1 -1
- package/dist/components/library/theme/tokens.d.ts +45 -44
- package/dist/components/library/theme/tokens.js.map +1 -1
- package/package.json +1 -1
- package/src/components/library/cards/SemanticMetricCard.tsx +1 -1
- package/src/components/library/cards/SemanticTableCard.tsx +3 -3
- package/src/components/library/chat/{ChatBar.jsx → ChatBar.tsx} +19 -8
- package/src/components/library/chat/{ChatInput.jsx → ChatInput.tsx} +13 -11
- package/src/components/library/chat/{ChatMessage.jsx → ChatMessage.tsx} +22 -9
- package/src/components/library/chat/{ChatMessageList.jsx → ChatMessageList.tsx} +13 -11
- package/src/components/library/chat/{ChatPanel.jsx → ChatPanel.tsx} +16 -13
- package/src/components/library/chat/{ChatSuggestions.jsx → ChatSuggestions.tsx} +6 -5
- package/src/components/library/chat/{ChatToolCall.jsx → ChatToolCall.tsx} +14 -4
- package/src/components/library/chat/{ChatTypingIndicator.jsx → ChatTypingIndicator.tsx} +5 -2
- package/src/components/library/chat/{ChatWelcome.jsx → ChatWelcome.tsx} +9 -7
- package/src/components/library/chat/index.tsx +26 -0
- package/src/components/library/chat/useChatState.tsx +181 -0
- package/src/components/library/data/{DataModeProvider.jsx → DataModeProvider.tsx} +25 -8
- package/src/components/library/data/{DataModeToggle.jsx → DataModeToggle.tsx} +5 -2
- package/src/components/library/data/{chartDataProvider.jsx → chartDataProvider.tsx} +49 -5
- package/src/components/library/data/{filterUtils.jsx → filterUtils.tsx} +58 -12
- package/src/components/library/data/{useDataSource.jsx → useDataSource.tsx} +9 -2
- package/src/components/library/data/{usePageFilters.jsx → usePageFilters.tsx} +49 -9
- package/src/components/library/{index.jsx → index.ts} +14 -14
- package/src/components/library/skeletons/{CardSkeleton.jsx → CardSkeleton.tsx} +5 -4
- package/src/components/library/theme/{AppThemeProvider.jsx → AppThemeProvider.tsx} +20 -7
- package/src/components/library/theme/{tokens.jsx → tokens.tsx} +37 -3
- package/src/components/library/chat/index.jsx +0 -10
- package/src/components/library/chat/useChatState.jsx +0 -130
|
@@ -1,51 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
100: string;
|
|
8
|
-
200: string;
|
|
9
|
-
300: string;
|
|
10
|
-
400: string;
|
|
11
|
-
500: string;
|
|
12
|
-
600: string;
|
|
13
|
-
700: string;
|
|
14
|
-
800: string;
|
|
15
|
-
900: string;
|
|
16
|
-
950: string;
|
|
17
|
-
};
|
|
18
|
-
accent: {
|
|
19
|
-
50: string;
|
|
20
|
-
100: string;
|
|
21
|
-
200: string;
|
|
22
|
-
300: string;
|
|
23
|
-
400: string;
|
|
24
|
-
500: string;
|
|
25
|
-
600: string;
|
|
26
|
-
700: string;
|
|
27
|
-
800: string;
|
|
28
|
-
900: string;
|
|
29
|
-
950: string;
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
fonts: {
|
|
33
|
-
sans: string;
|
|
34
|
-
mono: string;
|
|
35
|
-
};
|
|
36
|
-
radius: {
|
|
37
|
-
sm: string;
|
|
38
|
-
md: string;
|
|
39
|
-
lg: string;
|
|
40
|
-
};
|
|
41
|
-
spacing: {
|
|
42
|
-
pageX: string;
|
|
43
|
-
pageY: string;
|
|
44
|
-
};
|
|
45
|
-
};
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Tokens } from "./tokens";
|
|
3
|
+
export type ThemeMode = "light" | "dark";
|
|
4
|
+
export interface ThemeModeContextValue {
|
|
5
|
+
mode: ThemeMode;
|
|
6
|
+
theme: Tokens;
|
|
46
7
|
toggle: () => void;
|
|
47
|
-
}
|
|
48
|
-
export
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
8
|
+
}
|
|
9
|
+
export declare function useThemeMode(): ThemeModeContextValue;
|
|
10
|
+
export interface AppThemeProviderProps {
|
|
11
|
+
initialMode?: ThemeMode;
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
export default function AppThemeProvider({ initialMode, children }: AppThemeProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppThemeProvider.js","sources":["../../../../src/components/library/theme/AppThemeProvider.
|
|
1
|
+
{"version":3,"file":"AppThemeProvider.js","sources":["../../../../src/components/library/theme/AppThemeProvider.tsx"],"sourcesContent":["import React from \"react\";\nimport { tokens, getTokenCSSProperties, Tokens } from \"./tokens\";\n\nexport type ThemeMode = \"light\" | \"dark\";\n\nexport interface ThemeModeContextValue {\n mode: ThemeMode;\n theme: Tokens;\n toggle: () => void;\n}\n\nconst ThemeModeContext = React.createContext<ThemeModeContextValue>({\n mode: \"light\",\n theme: tokens,\n toggle: () => {}\n});\n\nconst STORAGE_KEY = \"app-color-mode\";\n\nfunction applyHtmlDarkClass(mode: ThemeMode): void {\n if (typeof document === \"undefined\") return;\n const root = document.documentElement;\n if (mode === \"dark\") root.classList.add(\"dark\");\n else root.classList.remove(\"dark\");\n}\n\nfunction applyTokenCSSProperties(): void {\n if (typeof document === \"undefined\") return;\n const root = document.documentElement;\n const props = getTokenCSSProperties();\n for (const [key, value] of Object.entries(props)) {\n root.style.setProperty(key, value);\n }\n}\n\nexport function useThemeMode(): ThemeModeContextValue {\n return React.useContext(ThemeModeContext);\n}\n\nexport interface AppThemeProviderProps {\n initialMode?: ThemeMode;\n children: React.ReactNode;\n}\n\nexport default function AppThemeProvider({ initialMode = \"light\", children }: AppThemeProviderProps) {\n const [mode, setMode] = React.useState<ThemeMode>(initialMode);\n\n React.useEffect(() => {\n applyTokenCSSProperties();\n }, []);\n\n React.useEffect(() => {\n try {\n const stored = window.localStorage.getItem(STORAGE_KEY);\n if (stored === \"light\" || stored === \"dark\") setMode(stored);\n } catch {\n // ignore\n }\n }, []);\n\n React.useEffect(() => {\n applyHtmlDarkClass(mode);\n try {\n window.localStorage.setItem(STORAGE_KEY, mode);\n } catch {\n // ignore\n }\n }, [mode]);\n\n const value = React.useMemo(\n () => ({\n mode,\n theme: tokens,\n toggle: () => setMode((m) => (m === \"dark\" ? \"light\" : \"dark\"))\n }),\n [mode]\n );\n\n return <ThemeModeContext.Provider value={value}>{children}</ThemeModeContext.Provider>;\n}\n"],"names":["ThemeModeContext","React","tokens","STORAGE_KEY","applyHtmlDarkClass","mode","root","applyTokenCSSProperties","props","getTokenCSSProperties","key","value","useThemeMode","AppThemeProvider","initialMode","children","setMode","stored","m","jsx"],"mappings":";;;AAWA,MAAMA,IAAmBC,EAAM,cAAqC;AAAA,EAClE,MAAM;AAAA,EACN,OAAOC;AAAA,EACP,QAAQ,MAAM;AAAA,EAAC;AACjB,CAAC,GAEKC,IAAc;AAEpB,SAASC,EAAmBC,GAAuB;AACjD,MAAI,OAAO,WAAa,IAAa;AACrC,QAAMC,IAAO,SAAS;AACtB,EAAID,MAAS,SAAQC,EAAK,UAAU,IAAI,MAAM,IACzCA,EAAK,UAAU,OAAO,MAAM;AACnC;AAEA,SAASC,IAAgC;AACvC,MAAI,OAAO,WAAa,IAAa;AACrC,QAAMD,IAAO,SAAS,iBAChBE,IAAQC,EAAA;AACd,aAAW,CAACC,GAAKC,CAAK,KAAK,OAAO,QAAQH,CAAK;AAC7C,IAAAF,EAAK,MAAM,YAAYI,GAAKC,CAAK;AAErC;AAEO,SAASC,IAAsC;AACpD,SAAOX,EAAM,WAAWD,CAAgB;AAC1C;AAOA,SAAwBa,EAAiB,EAAE,aAAAC,IAAc,SAAS,UAAAC,KAAmC;AACnG,QAAM,CAACV,GAAMW,CAAO,IAAIf,EAAM,SAAoBa,CAAW;AAE7Db,EAAAA,EAAM,UAAU,MAAM;AACpB,IAAAM,EAAA;AAAA,EACF,GAAG,CAAA,CAAE,GAELN,EAAM,UAAU,MAAM;AACpB,QAAI;AACF,YAAMgB,IAAS,OAAO,aAAa,QAAQd,CAAW;AACtD,OAAIc,MAAW,WAAWA,MAAW,aAAgBA,CAAM;AAAA,IAC7D,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAA,CAAE,GAELhB,EAAM,UAAU,MAAM;AACpB,IAAAG,EAAmBC,CAAI;AACvB,QAAI;AACF,aAAO,aAAa,QAAQF,GAAaE,CAAI;AAAA,IAC/C,QAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAACA,CAAI,CAAC;AAET,QAAMM,IAAQV,EAAM;AAAA,IAClB,OAAO;AAAA,MACL,MAAAI;AAAA,MACA,OAAOH;AAAA,MACP,QAAQ,MAAMc,EAAQ,CAACE,MAAOA,MAAM,SAAS,UAAU,MAAO;AAAA,IAAA;AAAA,IAEhE,CAACb,CAAI;AAAA,EAAA;AAGP,SAAO,gBAAAc,EAACnB,EAAiB,UAAjB,EAA0B,OAAAW,GAAe,UAAAI,EAAA,CAAS;AAC5D;"}
|
|
@@ -1,48 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design tokens — single source of truth for branding.
|
|
3
|
+
*
|
|
4
|
+
* To rebrand a command center:
|
|
5
|
+
* 1. Swap the `brand` palette (use any Tailwind-style color scale)
|
|
6
|
+
* 2. Swap the `accent` palette
|
|
7
|
+
* 3. Change `fonts.sans` in _app.js (next/font import)
|
|
8
|
+
*
|
|
9
|
+
* AppThemeProvider injects these as CSS custom properties on :root,
|
|
10
|
+
* and tailwind.config.js references them via var(--color-brand-*).
|
|
11
|
+
*/
|
|
12
|
+
export interface ColorShades {
|
|
13
|
+
50: string;
|
|
14
|
+
100: string;
|
|
15
|
+
200: string;
|
|
16
|
+
300: string;
|
|
17
|
+
400: string;
|
|
18
|
+
500: string;
|
|
19
|
+
600: string;
|
|
20
|
+
700: string;
|
|
21
|
+
800: string;
|
|
22
|
+
900: string;
|
|
23
|
+
950: string;
|
|
24
|
+
}
|
|
25
|
+
export interface Tokens {
|
|
26
|
+
colors: {
|
|
27
|
+
brand: ColorShades;
|
|
28
|
+
accent: ColorShades;
|
|
29
|
+
};
|
|
30
|
+
fonts: {
|
|
31
|
+
sans: string;
|
|
32
|
+
mono: string;
|
|
33
|
+
};
|
|
34
|
+
radius: {
|
|
35
|
+
sm: string;
|
|
36
|
+
md: string;
|
|
37
|
+
lg: string;
|
|
38
|
+
};
|
|
39
|
+
spacing: {
|
|
40
|
+
pageX: string;
|
|
41
|
+
pageY: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export declare const tokens: Tokens;
|
|
1
45
|
/**
|
|
2
46
|
* Generates CSS custom property assignments from the token palettes.
|
|
3
47
|
* Used by AppThemeProvider to inject on :root at runtime.
|
|
4
48
|
*/
|
|
5
|
-
export function getTokenCSSProperties():
|
|
6
|
-
export namespace tokens {
|
|
7
|
-
namespace colors {
|
|
8
|
-
let brand: {
|
|
9
|
-
50: string;
|
|
10
|
-
100: string;
|
|
11
|
-
200: string;
|
|
12
|
-
300: string;
|
|
13
|
-
400: string;
|
|
14
|
-
500: string;
|
|
15
|
-
600: string;
|
|
16
|
-
700: string;
|
|
17
|
-
800: string;
|
|
18
|
-
900: string;
|
|
19
|
-
950: string;
|
|
20
|
-
};
|
|
21
|
-
let accent: {
|
|
22
|
-
50: string;
|
|
23
|
-
100: string;
|
|
24
|
-
200: string;
|
|
25
|
-
300: string;
|
|
26
|
-
400: string;
|
|
27
|
-
500: string;
|
|
28
|
-
600: string;
|
|
29
|
-
700: string;
|
|
30
|
-
800: string;
|
|
31
|
-
900: string;
|
|
32
|
-
950: string;
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
namespace fonts {
|
|
36
|
-
let sans: string;
|
|
37
|
-
let mono: string;
|
|
38
|
-
}
|
|
39
|
-
namespace radius {
|
|
40
|
-
let sm: string;
|
|
41
|
-
let md: string;
|
|
42
|
-
let lg: string;
|
|
43
|
-
}
|
|
44
|
-
namespace spacing {
|
|
45
|
-
let pageX: string;
|
|
46
|
-
let pageY: string;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
+
export declare function getTokenCSSProperties(): Record<string, string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sources":["../../../../src/components/library/theme/tokens.
|
|
1
|
+
{"version":3,"file":"tokens.js","sources":["../../../../src/components/library/theme/tokens.tsx"],"sourcesContent":["/**\n * Design tokens — single source of truth for branding.\n *\n * To rebrand a command center:\n * 1. Swap the `brand` palette (use any Tailwind-style color scale)\n * 2. Swap the `accent` palette\n * 3. Change `fonts.sans` in _app.js (next/font import)\n *\n * AppThemeProvider injects these as CSS custom properties on :root,\n * and tailwind.config.js references them via var(--color-brand-*).\n */\n\nexport interface ColorShades {\n 50: string;\n 100: string;\n 200: string;\n 300: string;\n 400: string;\n 500: string;\n 600: string;\n 700: string;\n 800: string;\n 900: string;\n 950: string;\n}\n\nexport interface Tokens {\n colors: {\n brand: ColorShades;\n accent: ColorShades;\n };\n fonts: {\n sans: string;\n mono: string;\n };\n radius: {\n sm: string;\n md: string;\n lg: string;\n };\n spacing: {\n pageX: string;\n pageY: string;\n };\n}\n\nexport const tokens: Tokens = {\n colors: {\n brand: {\n 50: \"#EEF2FF\",\n 100: \"#E0E7FF\",\n 200: \"#C7D2FE\",\n 300: \"#A5B4FC\",\n 400: \"#818CF8\",\n 500: \"#6366F1\",\n 600: \"#4F46E5\",\n 700: \"#4338CA\",\n 800: \"#3730A3\",\n 900: \"#312E81\",\n 950: \"#1E1B4E\",\n },\n accent: {\n 50: \"#ECFEFF\",\n 100: \"#CFFAFE\",\n 200: \"#A5F3FC\",\n 300: \"#67E8F9\",\n 400: \"#22D3EE\",\n 500: \"#06B6D4\",\n 600: \"#0891B2\",\n 700: \"#0E7490\",\n 800: \"#155E75\",\n 900: \"#164E63\",\n 950: \"#083344\",\n },\n },\n\n fonts: {\n sans: \"Inter\",\n mono: \"JetBrains Mono\",\n },\n\n radius: {\n sm: \"0.5rem\",\n md: \"0.75rem\",\n lg: \"1rem\",\n },\n\n spacing: {\n pageX: \"1.25rem\",\n pageY: \"1.25rem\",\n },\n};\n\n/**\n * Generates CSS custom property assignments from the token palettes.\n * Used by AppThemeProvider to inject on :root at runtime.\n */\nexport function getTokenCSSProperties(): Record<string, string> {\n const props: Record<string, string> = {};\n for (const [palette, shades] of Object.entries(tokens.colors)) {\n for (const [shade, value] of Object.entries(shades)) {\n props[`--color-${palette}-${shade}`] = value;\n }\n }\n return props;\n}\n"],"names":["tokens","getTokenCSSProperties","props","palette","shades","shade","value"],"mappings":"AA8CO,MAAMA,IAAiB;AAAA,EAC5B,QAAQ;AAAA,IACN,OAAO;AAAA,MACL,IAAI;AAAA,MACJ,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IAAA;AAAA,IAEP,QAAQ;AAAA,MACN,IAAI;AAAA,MACJ,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IAAA;AAAA,EACP;AAAA,EAGF,OAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,EAAA;AAAA,EAGR,QAAQ;AAAA,IACN,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA;AAAA,EAGN,SAAS;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EAAA;AAEX;AAMO,SAASC,IAAgD;AAC9D,QAAMC,IAAgC,CAAA;AACtC,aAAW,CAACC,GAASC,CAAM,KAAK,OAAO,QAAQJ,EAAO,MAAM;AAC1D,eAAW,CAACK,GAAOC,CAAK,KAAK,OAAO,QAAQF,CAAM;AAChD,MAAAF,EAAM,WAAWC,CAAO,IAAIE,CAAK,EAAE,IAAIC;AAG3C,SAAOJ;AACT;"}
|
package/package.json
CHANGED
|
@@ -36,7 +36,7 @@ export default function SemanticMetricCard({
|
|
|
36
36
|
loading = false,
|
|
37
37
|
...rest
|
|
38
38
|
}: SemanticMetricCardProps) {
|
|
39
|
-
const metric = React.useMemo(() => getSemanticMetric(semanticId, metricId), [semanticId, metricId]);
|
|
39
|
+
const metric = React.useMemo(() => getSemanticMetric(semanticId, metricId ?? ""), [semanticId, metricId]);
|
|
40
40
|
|
|
41
41
|
const resolvedTitle = title ?? metric?.title ?? metricId ?? "Metric";
|
|
42
42
|
const resolvedSubtitle = subtitle ?? metric?.subtitle;
|
|
@@ -4,7 +4,7 @@ import { getSemanticDataset } from "../data/chartDataProvider";
|
|
|
4
4
|
|
|
5
5
|
export interface SemanticTableCardProps extends Omit<TableCardProps, "data" | "columns"> {
|
|
6
6
|
semanticId: string;
|
|
7
|
-
dataOverride?: unknown[];
|
|
7
|
+
dataOverride?: Record<string, unknown>[];
|
|
8
8
|
columnsOverride?: TableColumn[];
|
|
9
9
|
compact?: boolean;
|
|
10
10
|
striped?: boolean;
|
|
@@ -35,8 +35,8 @@ export default function SemanticTableCard({
|
|
|
35
35
|
const ds = React.useMemo(() => getSemanticDataset(semanticId), [semanticId]);
|
|
36
36
|
const table = ds?.table;
|
|
37
37
|
|
|
38
|
-
const resolvedColumns = columnsOverride ?? table?.columns ?? [];
|
|
39
|
-
const resolvedData = dataOverride ?? table?.rows ?? [];
|
|
38
|
+
const resolvedColumns = (columnsOverride ?? table?.columns ?? []) as TableColumn[];
|
|
39
|
+
const resolvedData = (dataOverride ?? table?.rows ?? []) as Record<string, unknown>[];
|
|
40
40
|
const resolvedTitle = title ?? table?.title ?? ds?.title ?? "Table";
|
|
41
41
|
const resolvedSubtitle = subtitle ?? table?.subtitle;
|
|
42
42
|
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
} from "@heroicons/react/24/outline";
|
|
10
10
|
import ChatMessageList from "./ChatMessageList";
|
|
11
11
|
import ChatInput from "./ChatInput";
|
|
12
|
-
import useChatState from "./useChatState";
|
|
12
|
+
import useChatState, { UseChatStateOptions, ChatMessage } from "./useChatState";
|
|
13
|
+
import { ChatMessageData } from "./ChatMessage";
|
|
13
14
|
|
|
14
15
|
const BACKDROP_VARIANTS = {
|
|
15
16
|
hidden: { opacity: 0 },
|
|
@@ -23,11 +24,22 @@ const PANEL_VARIANTS = {
|
|
|
23
24
|
opacity: 1,
|
|
24
25
|
y: 0,
|
|
25
26
|
scale: 1,
|
|
26
|
-
transition: { type: "spring", damping: 28, stiffness: 380 },
|
|
27
|
+
transition: { type: "spring" as const, damping: 28, stiffness: 380 },
|
|
27
28
|
},
|
|
28
29
|
exit: { opacity: 0, y: 10, scale: 0.97, transition: { duration: 0.12 } },
|
|
29
30
|
};
|
|
30
31
|
|
|
32
|
+
export interface ChatBarProps {
|
|
33
|
+
onSend?: UseChatStateOptions["onSend"];
|
|
34
|
+
suggestions?: string[];
|
|
35
|
+
placeholder?: string;
|
|
36
|
+
title?: string;
|
|
37
|
+
initialMessages?: UseChatStateOptions["initialMessages"];
|
|
38
|
+
className?: string;
|
|
39
|
+
renderAvatar?: (message: ChatMessageData) => React.ReactNode;
|
|
40
|
+
onOpenInTab?: (messages: ChatMessage[]) => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
31
43
|
/**
|
|
32
44
|
* Command-palette style AI chat bar.
|
|
33
45
|
*
|
|
@@ -41,17 +53,16 @@ const PANEL_VARIANTS = {
|
|
|
41
53
|
export default function ChatBar({
|
|
42
54
|
onSend,
|
|
43
55
|
suggestions = [],
|
|
44
|
-
placeholder = "Ask a question
|
|
56
|
+
placeholder = "Ask a question…",
|
|
45
57
|
title = "AI Assistant",
|
|
46
58
|
initialMessages = [],
|
|
47
59
|
className = "",
|
|
48
|
-
panelHeight,
|
|
49
60
|
renderAvatar,
|
|
50
61
|
onOpenInTab,
|
|
51
|
-
}) {
|
|
62
|
+
}: ChatBarProps) {
|
|
52
63
|
const [open, setOpen] = useState(false);
|
|
53
64
|
const [portalVisible, setPortalVisible] = useState(false);
|
|
54
|
-
const panelRef = useRef(null);
|
|
65
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
55
66
|
const chat = useChatState({ initialMessages, onSend });
|
|
56
67
|
const isEmpty = chat.messages.length === 0;
|
|
57
68
|
|
|
@@ -62,7 +73,7 @@ export default function ChatBar({
|
|
|
62
73
|
}, [open]);
|
|
63
74
|
|
|
64
75
|
useEffect(() => {
|
|
65
|
-
function onKey(e) {
|
|
76
|
+
function onKey(e: KeyboardEvent) {
|
|
66
77
|
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
67
78
|
e.preventDefault();
|
|
68
79
|
setOpen((prev) => !prev);
|
|
@@ -79,7 +90,7 @@ export default function ChatBar({
|
|
|
79
90
|
return () => { document.body.style.overflow = ""; };
|
|
80
91
|
}, [open]);
|
|
81
92
|
|
|
82
|
-
function handleSend(content) {
|
|
93
|
+
function handleSend(content: string) {
|
|
83
94
|
if (!open) setOpen(true);
|
|
84
95
|
chat.sendMessage(content);
|
|
85
96
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState, useRef, useEffect } from "react";
|
|
2
2
|
import { PaperAirplaneIcon, StopCircleIcon } from "@heroicons/react/24/solid";
|
|
3
3
|
|
|
4
|
+
export interface ChatInputProps {
|
|
5
|
+
onSend?: (content: string) => void;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
isLoading?: boolean;
|
|
8
|
+
onStop?: () => void;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
maxRows?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* Chat input with auto-resize textarea, Send button, and keyboard shortcuts.
|
|
6
15
|
* Enter sends, Shift+Enter inserts newline.
|
|
7
|
-
*
|
|
8
|
-
* @param {Function} onSend — (content: string) => void
|
|
9
|
-
* @param {boolean} disabled — disable input while agent is processing
|
|
10
|
-
* @param {boolean} isLoading — show stop button instead of send
|
|
11
|
-
* @param {Function} onStop — optional: called when stop is clicked
|
|
12
|
-
* @param {string} placeholder
|
|
13
|
-
* @param {number} maxRows — max visible rows before scroll (default 6)
|
|
14
16
|
*/
|
|
15
17
|
export default function ChatInput({
|
|
16
18
|
onSend,
|
|
@@ -19,9 +21,9 @@ export default function ChatInput({
|
|
|
19
21
|
onStop,
|
|
20
22
|
placeholder = "Type a message…",
|
|
21
23
|
maxRows = 6,
|
|
22
|
-
}) {
|
|
24
|
+
}: ChatInputProps) {
|
|
23
25
|
const [value, setValue] = useState("");
|
|
24
|
-
const textareaRef = useRef(null);
|
|
26
|
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
25
27
|
|
|
26
28
|
useEffect(() => {
|
|
27
29
|
const ta = textareaRef.current;
|
|
@@ -41,7 +43,7 @@ export default function ChatInput({
|
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
function handleKeyDown(e) {
|
|
46
|
+
function handleKeyDown(e: React.KeyboardEvent<HTMLTextAreaElement>) {
|
|
45
47
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
46
48
|
e.preventDefault();
|
|
47
49
|
handleSend();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { renderSchemaComponent } from "@/components/workspace/ComponentRegistry";
|
|
3
|
-
import ChatToolCall from "./ChatToolCall";
|
|
3
|
+
import ChatToolCall, { ToolCall } from "./ChatToolCall";
|
|
4
4
|
import { UserCircleIcon, CpuChipIcon } from "@heroicons/react/24/solid";
|
|
5
5
|
|
|
6
|
-
function cx(...classes) {
|
|
6
|
+
function cx(...classes: (string | boolean | undefined)[]): string {
|
|
7
7
|
return classes.filter(Boolean).join(" ");
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -11,9 +11,9 @@ function cx(...classes) {
|
|
|
11
11
|
* Lightweight inline formatter for assistant messages.
|
|
12
12
|
* Handles code blocks, inline code, bold, italic, and line breaks.
|
|
13
13
|
*/
|
|
14
|
-
function formatContent(text) {
|
|
14
|
+
function formatContent(text: string): React.ReactNode {
|
|
15
15
|
if (!text) return null;
|
|
16
|
-
const parts = [];
|
|
16
|
+
const parts: React.ReactNode[] = [];
|
|
17
17
|
let key = 0;
|
|
18
18
|
|
|
19
19
|
const codeBlockRegex = /```(\w*)\n?([\s\S]*?)```/g;
|
|
@@ -46,7 +46,7 @@ function formatContent(text) {
|
|
|
46
46
|
return parts;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function formatInline(text) {
|
|
49
|
+
function formatInline(text: string): React.ReactNode {
|
|
50
50
|
const tokens = text.split(/(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*)/g);
|
|
51
51
|
return tokens.map((token, i) => {
|
|
52
52
|
if (token.startsWith("**") && token.endsWith("**")) {
|
|
@@ -74,13 +74,26 @@ function formatInline(text) {
|
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
export interface ChatMessageData {
|
|
78
|
+
id: string;
|
|
79
|
+
role: "user" | "assistant" | "system";
|
|
80
|
+
content?: string;
|
|
81
|
+
components?: unknown[];
|
|
82
|
+
toolCalls?: ToolCall[];
|
|
83
|
+
isError?: boolean;
|
|
84
|
+
isStreaming?: boolean;
|
|
85
|
+
timestamp?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface ChatMessageProps {
|
|
89
|
+
message: ChatMessageData;
|
|
90
|
+
avatar?: React.ReactNode;
|
|
91
|
+
}
|
|
92
|
+
|
|
77
93
|
/**
|
|
78
94
|
* Renders a single chat message.
|
|
79
|
-
*
|
|
80
|
-
* @param {Object} message — { id, role, content, components?, toolCalls?, isError?, isStreaming?, timestamp? }
|
|
81
|
-
* @param {React.ReactNode} avatar — custom avatar override
|
|
82
95
|
*/
|
|
83
|
-
export default function ChatMessage({ message, avatar }) {
|
|
96
|
+
export default function ChatMessage({ message, avatar }: ChatMessageProps) {
|
|
84
97
|
const isUser = message.role === "user";
|
|
85
98
|
const isSystem = message.role === "system";
|
|
86
99
|
const isAssistant = message.role === "assistant";
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import React, { useRef, useEffect } from "react";
|
|
2
|
-
import ChatMessage from "./ChatMessage";
|
|
2
|
+
import ChatMessage, { ChatMessageData } from "./ChatMessage";
|
|
3
3
|
import ChatTypingIndicator from "./ChatTypingIndicator";
|
|
4
4
|
import ChatSuggestions from "./ChatSuggestions";
|
|
5
5
|
|
|
6
|
+
export interface ChatMessageListProps {
|
|
7
|
+
messages?: ChatMessageData[];
|
|
8
|
+
isLoading?: boolean;
|
|
9
|
+
isStreaming?: boolean;
|
|
10
|
+
suggestions?: string[];
|
|
11
|
+
onSuggestion?: (text: string) => void;
|
|
12
|
+
renderAvatar?: (message: ChatMessageData) => React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
/**
|
|
7
16
|
* Scrollable message area with auto-scroll to latest message.
|
|
8
|
-
*
|
|
9
|
-
* @param {Array} messages — array of message objects
|
|
10
|
-
* @param {boolean} isLoading — show typing indicator
|
|
11
|
-
* @param {boolean} isStreaming — agent is streaming (show different indicator text)
|
|
12
|
-
* @param {string[]} suggestions — follow-up suggestions shown after last assistant message
|
|
13
|
-
* @param {Function} onSuggestion — (text) => void
|
|
14
|
-
* @param {Function} renderAvatar — (message) => ReactNode, optional per-message avatar
|
|
15
17
|
*/
|
|
16
18
|
export default function ChatMessageList({
|
|
17
19
|
messages = [],
|
|
@@ -20,9 +22,9 @@ export default function ChatMessageList({
|
|
|
20
22
|
suggestions = [],
|
|
21
23
|
onSuggestion,
|
|
22
24
|
renderAvatar,
|
|
23
|
-
}) {
|
|
24
|
-
const bottomRef = useRef(null);
|
|
25
|
-
const containerRef = useRef(null);
|
|
25
|
+
}: ChatMessageListProps) {
|
|
26
|
+
const bottomRef = useRef<HTMLDivElement>(null);
|
|
27
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
26
28
|
|
|
27
29
|
useEffect(() => {
|
|
28
30
|
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
@@ -2,23 +2,26 @@ import React from "react";
|
|
|
2
2
|
import ChatMessageList from "./ChatMessageList";
|
|
3
3
|
import ChatInput from "./ChatInput";
|
|
4
4
|
import ChatWelcome from "./ChatWelcome";
|
|
5
|
-
import useChatState from "./useChatState";
|
|
5
|
+
import useChatState, { UseChatStateOptions } from "./useChatState";
|
|
6
|
+
import { ChatMessageData } from "./ChatMessage";
|
|
6
7
|
import { TrashIcon } from "@heroicons/react/24/outline";
|
|
7
8
|
|
|
9
|
+
export interface ChatPanelProps {
|
|
10
|
+
title?: string;
|
|
11
|
+
onSend?: UseChatStateOptions["onSend"];
|
|
12
|
+
initialMessages?: UseChatStateOptions["initialMessages"];
|
|
13
|
+
welcomeTitle?: string;
|
|
14
|
+
welcomeSubtitle?: string;
|
|
15
|
+
suggestions?: string[];
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
renderAvatar?: (message: ChatMessageData) => React.ReactNode;
|
|
19
|
+
showHeader?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
8
22
|
/**
|
|
9
23
|
* All-in-one chat panel. Composes ChatMessageList, ChatInput, ChatWelcome,
|
|
10
24
|
* and useChatState into a single drop-in component.
|
|
11
|
-
*
|
|
12
|
-
* @param {string} title — panel header title
|
|
13
|
-
* @param {Function} onSend — async (userMessage, history, helpers) => assistantMessage?
|
|
14
|
-
* @param {Array} initialMessages — seed messages
|
|
15
|
-
* @param {string} welcomeTitle — welcome screen heading
|
|
16
|
-
* @param {string} welcomeSubtitle — welcome screen description
|
|
17
|
-
* @param {string[]} suggestions — starter and follow-up prompts
|
|
18
|
-
* @param {string} placeholder — input placeholder
|
|
19
|
-
* @param {string} className — additional classes on the root container
|
|
20
|
-
* @param {Function} renderAvatar — (message) => ReactNode
|
|
21
|
-
* @param {boolean} showHeader — show the title bar (default true)
|
|
22
25
|
*/
|
|
23
26
|
export default function ChatPanel({
|
|
24
27
|
title = "AI Assistant",
|
|
@@ -31,7 +34,7 @@ export default function ChatPanel({
|
|
|
31
34
|
className = "",
|
|
32
35
|
renderAvatar,
|
|
33
36
|
showHeader = true,
|
|
34
|
-
}) {
|
|
37
|
+
}: ChatPanelProps) {
|
|
35
38
|
const chat = useChatState({ initialMessages, onSend });
|
|
36
39
|
|
|
37
40
|
const isEmpty = chat.messages.length === 0;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { SparklesIcon } from "@heroicons/react/24/outline";
|
|
3
2
|
|
|
3
|
+
export interface ChatSuggestionsProps {
|
|
4
|
+
suggestions?: string[];
|
|
5
|
+
onSelect?: (suggestion: string) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
/**
|
|
5
9
|
* Quick-action prompt buttons. Place above the input or after an assistant message.
|
|
6
|
-
*
|
|
7
|
-
* @param {string[]} suggestions — prompt strings
|
|
8
|
-
* @param {Function} onSelect — (suggestion) => void
|
|
9
10
|
*/
|
|
10
|
-
export default function ChatSuggestions({ suggestions = [], onSelect }) {
|
|
11
|
+
export default function ChatSuggestions({ suggestions = [], onSelect }: ChatSuggestionsProps) {
|
|
11
12
|
if (!suggestions.length) return null;
|
|
12
13
|
|
|
13
14
|
return (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
import Spinner from "../ui/Spinner";
|
|
3
3
|
import {
|
|
4
4
|
WrenchScrewdriverIcon,
|
|
@@ -7,6 +7,18 @@ import {
|
|
|
7
7
|
ChevronDownIcon,
|
|
8
8
|
} from "@heroicons/react/24/outline";
|
|
9
9
|
|
|
10
|
+
export interface ToolCall {
|
|
11
|
+
id?: string;
|
|
12
|
+
name: string;
|
|
13
|
+
args?: unknown;
|
|
14
|
+
status: "running" | "complete" | "error";
|
|
15
|
+
result?: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ChatToolCallProps {
|
|
19
|
+
toolCall: ToolCall;
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
const STATUS_CONFIG = {
|
|
11
23
|
running: {
|
|
12
24
|
icon: <Spinner size="xs" tone="brand" label="Running" />,
|
|
@@ -30,10 +42,8 @@ const STATUS_CONFIG = {
|
|
|
30
42
|
|
|
31
43
|
/**
|
|
32
44
|
* Displays an agent tool call / function execution step.
|
|
33
|
-
*
|
|
34
|
-
* @param {Object} toolCall — { id?, name, args?, status: "running"|"complete"|"error", result? }
|
|
35
45
|
*/
|
|
36
|
-
export default function ChatToolCall({ toolCall }) {
|
|
46
|
+
export default function ChatToolCall({ toolCall }: ChatToolCallProps) {
|
|
37
47
|
const [expanded, setExpanded] = useState(false);
|
|
38
48
|
const config = STATUS_CONFIG[toolCall.status] ?? STATUS_CONFIG.running;
|
|
39
49
|
const hasDetails = toolCall.args || toolCall.result;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { CpuChipIcon } from "@heroicons/react/24/solid";
|
|
3
2
|
|
|
3
|
+
export interface ChatTypingIndicatorProps {
|
|
4
|
+
label?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
4
7
|
/**
|
|
5
8
|
* Animated typing indicator shown while the agent is processing.
|
|
6
9
|
*/
|
|
7
|
-
export default function ChatTypingIndicator({ label = "Thinking" }) {
|
|
10
|
+
export default function ChatTypingIndicator({ label = "Thinking" }: ChatTypingIndicatorProps) {
|
|
8
11
|
return (
|
|
9
12
|
<div className="flex items-start gap-3">
|
|
10
13
|
<div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-brand-100 dark:bg-brand-900/40">
|
|
@@ -2,14 +2,16 @@ import React from "react";
|
|
|
2
2
|
import { CpuChipIcon } from "@heroicons/react/24/solid";
|
|
3
3
|
import ChatSuggestions from "./ChatSuggestions";
|
|
4
4
|
|
|
5
|
+
export interface ChatWelcomeProps {
|
|
6
|
+
title?: string;
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
suggestions?: string[];
|
|
9
|
+
onSuggestion?: (text: string) => void;
|
|
10
|
+
icon?: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
/**
|
|
6
14
|
* Empty-state welcome screen shown before the first message.
|
|
7
|
-
*
|
|
8
|
-
* @param {string} title — welcome heading
|
|
9
|
-
* @param {string} subtitle — description text
|
|
10
|
-
* @param {string[]} suggestions — starter prompt suggestions
|
|
11
|
-
* @param {Function} onSuggestion — (text) => void
|
|
12
|
-
* @param {React.ReactNode} icon — custom icon override
|
|
13
15
|
*/
|
|
14
16
|
export default function ChatWelcome({
|
|
15
17
|
title = "How can I help?",
|
|
@@ -17,7 +19,7 @@ export default function ChatWelcome({
|
|
|
17
19
|
suggestions = [],
|
|
18
20
|
onSuggestion,
|
|
19
21
|
icon,
|
|
20
|
-
}) {
|
|
22
|
+
}: ChatWelcomeProps) {
|
|
21
23
|
return (
|
|
22
24
|
<div className="flex flex-1 flex-col items-center justify-center gap-4 px-6 py-12 text-center">
|
|
23
25
|
{icon ?? (
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export { default as ChatPanel } from "./ChatPanel";
|
|
2
|
+
export { default as ChatBar } from "./ChatBar";
|
|
3
|
+
export { default as ChatMessageList } from "./ChatMessageList";
|
|
4
|
+
export { default as ChatMessage } from "./ChatMessage";
|
|
5
|
+
export { default as ChatInput } from "./ChatInput";
|
|
6
|
+
export { default as ChatTypingIndicator } from "./ChatTypingIndicator";
|
|
7
|
+
export { default as ChatSuggestions } from "./ChatSuggestions";
|
|
8
|
+
export { default as ChatToolCall } from "./ChatToolCall";
|
|
9
|
+
export { default as ChatWelcome } from "./ChatWelcome";
|
|
10
|
+
export { default as useChatState } from "./useChatState";
|
|
11
|
+
|
|
12
|
+
export type { ChatPanelProps } from "./ChatPanel";
|
|
13
|
+
export type { ChatBarProps } from "./ChatBar";
|
|
14
|
+
export type { ChatMessageListProps } from "./ChatMessageList";
|
|
15
|
+
export type { ChatMessageProps, ChatMessageData } from "./ChatMessage";
|
|
16
|
+
export type { ChatInputProps } from "./ChatInput";
|
|
17
|
+
export type { ChatTypingIndicatorProps } from "./ChatTypingIndicator";
|
|
18
|
+
export type { ChatSuggestionsProps } from "./ChatSuggestions";
|
|
19
|
+
export type { ChatToolCallProps, ToolCall } from "./ChatToolCall";
|
|
20
|
+
export type { ChatWelcomeProps } from "./ChatWelcome";
|
|
21
|
+
export type {
|
|
22
|
+
UseChatStateOptions,
|
|
23
|
+
UseChatStateReturn,
|
|
24
|
+
ChatMessage as ChatMessageType,
|
|
25
|
+
ChatStateHelpers,
|
|
26
|
+
} from "./useChatState";
|