@schandlergarcia/sf-web-components 1.8.0 → 1.9.1

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 (82) hide show
  1. package/dist/components/library/cards/SemanticTableCard.d.ts +1 -1
  2. package/dist/components/library/chat/ChatBar.d.ts +14 -11
  3. package/dist/components/library/chat/ChatBar.js +2 -3
  4. package/dist/components/library/chat/ChatBar.js.map +1 -1
  5. package/dist/components/library/chat/ChatInput.d.ts +9 -8
  6. package/dist/components/library/chat/ChatInput.js.map +1 -1
  7. package/dist/components/library/chat/ChatMessage.d.ts +18 -4
  8. package/dist/components/library/chat/ChatMessage.js.map +1 -1
  9. package/dist/components/library/chat/ChatMessageList.d.ts +11 -8
  10. package/dist/components/library/chat/ChatMessageList.js.map +1 -1
  11. package/dist/components/library/chat/ChatPanel.d.ts +16 -12
  12. package/dist/components/library/chat/ChatPanel.js +8 -9
  13. package/dist/components/library/chat/ChatPanel.js.map +1 -1
  14. package/dist/components/library/chat/ChatSuggestions.d.ts +5 -4
  15. package/dist/components/library/chat/ChatSuggestions.js +2 -3
  16. package/dist/components/library/chat/ChatSuggestions.js.map +1 -1
  17. package/dist/components/library/chat/ChatToolCall.d.ts +11 -3
  18. package/dist/components/library/chat/ChatToolCall.js.map +1 -1
  19. package/dist/components/library/chat/ChatTypingIndicator.d.ts +4 -3
  20. package/dist/components/library/chat/ChatTypingIndicator.js +2 -3
  21. package/dist/components/library/chat/ChatTypingIndicator.js.map +1 -1
  22. package/dist/components/library/chat/ChatWelcome.d.ts +9 -7
  23. package/dist/components/library/chat/ChatWelcome.js +6 -7
  24. package/dist/components/library/chat/ChatWelcome.js.map +1 -1
  25. package/dist/components/library/chat/index.d.ts +10 -0
  26. package/dist/components/library/chat/useChatState.d.ts +37 -11
  27. package/dist/components/library/chat/useChatState.js +63 -46
  28. package/dist/components/library/chat/useChatState.js.map +1 -1
  29. package/dist/components/library/data/DataModeProvider.d.ts +15 -11
  30. package/dist/components/library/data/DataModeProvider.js +1 -1
  31. package/dist/components/library/data/DataModeProvider.js.map +1 -1
  32. package/dist/components/library/data/DataModeToggle.d.ts +4 -3
  33. package/dist/components/library/data/DataModeToggle.js +4 -5
  34. package/dist/components/library/data/DataModeToggle.js.map +1 -1
  35. package/dist/components/library/data/chartDataProvider.d.ts +41 -3
  36. package/dist/components/library/data/filterUtils.d.ts +38 -9
  37. package/dist/components/library/data/filterUtils.js.map +1 -1
  38. package/dist/components/library/data/useDataSource.d.ts +6 -4
  39. package/dist/components/library/data/useDataSource.js.map +1 -1
  40. package/dist/components/library/data/usePageFilters.d.ts +31 -5
  41. package/dist/components/library/data/usePageFilters.js +6 -2
  42. package/dist/components/library/data/usePageFilters.js.map +1 -1
  43. package/dist/components/library/index.d.ts +92 -73
  44. package/dist/components/library/index.js +25 -25
  45. package/dist/components/library/index.js.map +1 -1
  46. package/dist/components/library/skeletons/CardSkeleton.d.ts +5 -4
  47. package/dist/components/library/skeletons/CardSkeleton.js +2 -3
  48. package/dist/components/library/skeletons/CardSkeleton.js.map +1 -1
  49. package/dist/components/library/theme/AppThemeProvider.d.ts +13 -50
  50. package/dist/components/library/theme/AppThemeProvider.js.map +1 -1
  51. package/dist/components/library/theme/tokens.d.ts +45 -44
  52. package/dist/components/library/theme/tokens.js.map +1 -1
  53. package/dist/components/workspace/ComponentRegistry.d.ts +116 -140
  54. package/dist/components/workspace/ComponentRegistry.js +43 -43
  55. package/dist/components/workspace/ComponentRegistry.js.map +1 -1
  56. package/package.json +2 -2
  57. package/src/components/library/cards/SemanticMetricCard.tsx +1 -1
  58. package/src/components/library/cards/SemanticTableCard.tsx +3 -3
  59. package/src/components/library/chat/{ChatBar.jsx → ChatBar.tsx} +19 -8
  60. package/src/components/library/chat/{ChatInput.jsx → ChatInput.tsx} +13 -11
  61. package/src/components/library/chat/{ChatMessage.jsx → ChatMessage.tsx} +23 -10
  62. package/src/components/library/chat/{ChatMessageList.jsx → ChatMessageList.tsx} +13 -11
  63. package/src/components/library/chat/{ChatPanel.jsx → ChatPanel.tsx} +16 -13
  64. package/src/components/library/chat/{ChatSuggestions.jsx → ChatSuggestions.tsx} +6 -5
  65. package/src/components/library/chat/{ChatToolCall.jsx → ChatToolCall.tsx} +14 -4
  66. package/src/components/library/chat/{ChatTypingIndicator.jsx → ChatTypingIndicator.tsx} +5 -2
  67. package/src/components/library/chat/{ChatWelcome.jsx → ChatWelcome.tsx} +9 -7
  68. package/src/components/library/chat/index.tsx +26 -0
  69. package/src/components/library/chat/useChatState.tsx +182 -0
  70. package/src/components/library/data/{DataModeProvider.jsx → DataModeProvider.tsx} +25 -8
  71. package/src/components/library/data/{DataModeToggle.jsx → DataModeToggle.tsx} +5 -2
  72. package/src/components/library/data/{chartDataProvider.jsx → chartDataProvider.tsx} +49 -5
  73. package/src/components/library/data/{filterUtils.jsx → filterUtils.tsx} +58 -12
  74. package/src/components/library/data/{useDataSource.jsx → useDataSource.tsx} +9 -2
  75. package/src/components/library/data/{usePageFilters.jsx → usePageFilters.tsx} +49 -9
  76. package/src/components/library/{index.jsx → index.ts} +14 -14
  77. package/src/components/library/skeletons/{CardSkeleton.jsx → CardSkeleton.tsx} +5 -4
  78. package/src/components/library/theme/{AppThemeProvider.jsx → AppThemeProvider.tsx} +20 -7
  79. package/src/components/library/theme/{tokens.jsx → tokens.tsx} +37 -3
  80. package/src/components/workspace/{ComponentRegistry.jsx → ComponentRegistry.tsx} +137 -32
  81. package/src/components/library/chat/index.jsx +0 -10
  82. package/src/components/library/chat/useChatState.jsx +0 -130
@@ -1,6 +1,13 @@
1
1
  import { useMemo } from "react";
2
2
  import { useDataMode } from "./DataModeProvider";
3
3
 
4
+ export type DataSourceValue<T> = T | (() => T);
5
+
6
+ export interface UseDataSourceOptions<T> {
7
+ sample: DataSourceValue<T>;
8
+ live: DataSourceValue<T>;
9
+ }
10
+
4
11
  /**
5
12
  * Select between sample and live data based on the global data mode.
6
13
  *
@@ -23,11 +30,11 @@ import { useDataMode } from "./DataModeProvider";
23
30
  * live: () => computeFromAPI(apiData),
24
31
  * });
25
32
  */
26
- export default function useDataSource({ sample, live }) {
33
+ export default function useDataSource<T>({ sample, live }: UseDataSourceOptions<T>): T {
27
34
  const { mode } = useDataMode();
28
35
 
29
36
  return useMemo(() => {
30
37
  const source = mode === "sample" ? sample : live;
31
- return typeof source === "function" ? source() : source;
38
+ return typeof source === "function" ? (source as () => T)() : source;
32
39
  }, [mode, sample, live]);
33
40
  }
@@ -1,5 +1,41 @@
1
1
  import { useState, useMemo, useCallback } from "react";
2
- import { applyFilters, sortByKey } from "./filterUtils";
2
+ import { applyFilters, sortByKey, FilterDefinition } from "./filterUtils";
3
+
4
+ export type SortDirection = "asc" | "desc";
5
+
6
+ export interface SortState {
7
+ key: string;
8
+ direction: SortDirection;
9
+ }
10
+
11
+ export interface DateRange {
12
+ start?: Date | string;
13
+ end?: Date | string;
14
+ }
15
+
16
+ export type FilterValue = string | boolean | DateRange | null;
17
+
18
+ export interface FilterValues {
19
+ [key: string]: FilterValue;
20
+ }
21
+
22
+ export interface UsePageFiltersOptions<T> {
23
+ data?: T[];
24
+ filters?: FilterDefinition[];
25
+ defaultSort?: SortState | null;
26
+ }
27
+
28
+ export interface UsePageFiltersReturn<T> {
29
+ values: FilterValues;
30
+ setFilter: (id: string, value: FilterValue) => void;
31
+ resetFilters: () => void;
32
+ sort: SortState | null;
33
+ setSort: (key: string | null, direction?: SortDirection) => void;
34
+ toggleSort: (key: string) => void;
35
+ filteredData: T[];
36
+ sortedData: T[];
37
+ activeFilterCount: number;
38
+ }
3
39
 
4
40
  /**
5
41
  * Hook for managing page-level filter and sort state.
@@ -21,9 +57,13 @@ import { applyFilters, sortByKey } from "./filterUtils";
21
57
  * defaultSort: { key: "timestamp", direction: "desc" },
22
58
  * });
23
59
  */
24
- export default function usePageFilters({ data = [], filters = [], defaultSort = null } = {}) {
60
+ export default function usePageFilters<T = any>({
61
+ data = [],
62
+ filters = [],
63
+ defaultSort = null,
64
+ }: UsePageFiltersOptions<T> = {}): UsePageFiltersReturn<T> {
25
65
  const initialValues = useMemo(() => {
26
- const v = {};
66
+ const v: FilterValues = {};
27
67
  for (const f of filters) {
28
68
  if (f.defaultValue !== undefined) {
29
69
  v[f.id] = f.defaultValue;
@@ -40,10 +80,10 @@ export default function usePageFilters({ data = [], filters = [], defaultSort =
40
80
  return v;
41
81
  }, [filters]);
42
82
 
43
- const [values, setValues] = useState(initialValues);
44
- const [sort, setSortState] = useState(defaultSort);
83
+ const [values, setValues] = useState<FilterValues>(initialValues);
84
+ const [sort, setSortState] = useState<SortState | null>(defaultSort);
45
85
 
46
- const setFilter = useCallback((id, value) => {
86
+ const setFilter = useCallback((id: string, value: FilterValue) => {
47
87
  setValues((prev) => ({ ...prev, [id]: value }));
48
88
  }, []);
49
89
 
@@ -51,11 +91,11 @@ export default function usePageFilters({ data = [], filters = [], defaultSort =
51
91
  setValues(initialValues);
52
92
  }, [initialValues]);
53
93
 
54
- const setSort = useCallback((key, direction) => {
94
+ const setSort = useCallback((key: string | null, direction?: SortDirection) => {
55
95
  setSortState(key ? { key, direction: direction ?? "asc" } : null);
56
96
  }, []);
57
97
 
58
- const toggleSort = useCallback((key) => {
98
+ const toggleSort = useCallback((key: string) => {
59
99
  setSortState((prev) => {
60
100
  if (prev?.key !== key) return { key, direction: "asc" };
61
101
  if (prev.direction === "asc") return { key, direction: "desc" };
@@ -77,7 +117,7 @@ export default function usePageFilters({ data = [], filters = [], defaultSort =
77
117
  let count = 0;
78
118
  for (const f of filters) {
79
119
  const v = values[f.id];
80
- if (f.type === "search" && v && v.trim()) count++;
120
+ if (f.type === "search" && v && typeof v === "string" && v.trim()) count++;
81
121
  else if (f.type === "select" && v && v !== "all") count++;
82
122
  else if (f.type === "toggle" && v) count++;
83
123
  else if (f.type === "dateRange" && v) count++;
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import * as React from 'react';
2
2
 
3
3
  export { default as AppThemeProvider, useThemeMode } from "./theme/AppThemeProvider";
4
4
 
@@ -105,21 +105,21 @@ export { default as HeroUISeparator, Separator } from "./heroui/Separator";
105
105
  export { default as HeroUIPagination, Pagination } from "./heroui/Pagination";
106
106
 
107
107
  // Breadcrumb subcomponents for shadcn compatibility
108
- export const Breadcrumb = ({ children, ...props }) => React.createElement('nav', { 'aria-label': 'breadcrumb', ...props }, children);
109
- export const BreadcrumbList = ({ children, ...props }) => React.createElement('ol', { className: 'flex flex-wrap items-center gap-1.5 break-words text-sm text-slate-500 dark:text-slate-400', ...props }, children);
110
- export const BreadcrumbItem = ({ children, ...props }) => React.createElement('li', { className: 'inline-flex items-center gap-1.5', ...props }, children);
111
- export const BreadcrumbLink = ({ href, children, asChild, ...props }) => asChild ? React.createElement('span', props, children) : React.createElement('a', { href, className: 'transition-colors hover:text-slate-900 dark:hover:text-slate-50', ...props }, children);
112
- export const BreadcrumbPage = ({ children, ...props }) => React.createElement('span', { role: 'link', 'aria-disabled': 'true', 'aria-current': 'page', className: 'font-normal text-slate-900 dark:text-slate-50', ...props }, children);
113
- export const BreadcrumbSeparator = ({ children, ...props }) => React.createElement('li', { role: 'presentation', 'aria-hidden': 'true', ...props }, children ?? '/');
114
- export const BreadcrumbEllipsis = (props) => React.createElement('span', { role: 'presentation', 'aria-hidden': 'true', ...props }, '...');
108
+ export const Breadcrumb = ({ children, ...props }: { children?: React.ReactNode; [key: string]: any }) => React.createElement('nav', { 'aria-label': 'breadcrumb', ...props }, children);
109
+ export const BreadcrumbList = ({ children, ...props }: { children?: React.ReactNode; [key: string]: any }) => React.createElement('ol', { className: 'flex flex-wrap items-center gap-1.5 break-words text-sm text-slate-500 dark:text-slate-400', ...props }, children);
110
+ export const BreadcrumbItem = ({ children, ...props }: { children?: React.ReactNode; [key: string]: any }) => React.createElement('li', { className: 'inline-flex items-center gap-1.5', ...props }, children);
111
+ export const BreadcrumbLink = ({ href, children, asChild, ...props }: { href?: string; children?: React.ReactNode; asChild?: boolean; [key: string]: any }) => asChild ? React.createElement('span', props, children) : React.createElement('a', { href, className: 'transition-colors hover:text-slate-900 dark:hover:text-slate-50', ...props }, children);
112
+ export const BreadcrumbPage = ({ children, ...props }: { children?: React.ReactNode; [key: string]: any }) => React.createElement('span', { role: 'link', 'aria-disabled': 'true', 'aria-current': 'page', className: 'font-normal text-slate-900 dark:text-slate-50', ...props }, children);
113
+ export const BreadcrumbSeparator = ({ children, ...props }: { children?: React.ReactNode; [key: string]: any }) => React.createElement('li', { role: 'presentation', 'aria-hidden': 'true', ...props }, children ?? '/');
114
+ export const BreadcrumbEllipsis = (props: { [key: string]: any }) => React.createElement('span', { role: 'presentation', 'aria-hidden': 'true', ...props }, '...');
115
115
 
116
116
  // Pagination subcomponents for shadcn compatibility
117
- export const PaginationContent = ({ children, ...props }) => React.createElement('ul', { className: 'flex flex-row items-center gap-1', ...props }, children);
118
- export const PaginationItem = ({ children, ...props }) => React.createElement('li', props, children);
119
- export const PaginationLink = ({ href, isActive, children, ...props }) => React.createElement('a', { href, 'aria-current': isActive ? 'page' : undefined, className: `inline-flex items-center justify-center rounded-md text-sm font-medium h-9 min-w-9 px-4 py-2 ${isActive ? 'bg-slate-900 text-white dark:bg-slate-50 dark:text-slate-900' : 'hover:bg-slate-100 dark:hover:bg-slate-800'}`, ...props }, children);
120
- export const PaginationPrevious = ({ href, ...props }) => React.createElement(PaginationLink, { href, ...props }, 'Previous');
121
- export const PaginationNext = ({ href, ...props }) => React.createElement(PaginationLink, { href, ...props }, 'Next');
122
- export const PaginationEllipsis = (props) => React.createElement('span', { 'aria-hidden': true, ...props }, '...');
117
+ export const PaginationContent = ({ children, ...props }: { children?: React.ReactNode; [key: string]: any }) => React.createElement('ul', { className: 'flex flex-row items-center gap-1', ...props }, children);
118
+ export const PaginationItem = ({ children, ...props }: { children?: React.ReactNode; [key: string]: any }) => React.createElement('li', props, children);
119
+ export const PaginationLink = ({ href, isActive, children, ...props }: { href?: string; isActive?: boolean; children?: React.ReactNode; [key: string]: any }) => React.createElement('a', { href, 'aria-current': isActive ? 'page' : undefined, className: `inline-flex items-center justify-center rounded-md text-sm font-medium h-9 min-w-9 px-4 py-2 ${isActive ? 'bg-slate-900 text-white dark:bg-slate-50 dark:text-slate-900' : 'hover:bg-slate-100 dark:hover:bg-slate-800'}`, ...props }, children);
120
+ export const PaginationPrevious = ({ href, ...props }: { href?: string; [key: string]: any }) => React.createElement(PaginationLink, { href, ...props }, 'Previous');
121
+ export const PaginationNext = ({ href, ...props }: { href?: string; [key: string]: any }) => React.createElement(PaginationLink, { href, ...props }, 'Next');
122
+ export const PaginationEllipsis = (props: { [key: string]: any }) => React.createElement('span', { 'aria-hidden': true, ...props }, '...');
123
123
 
124
124
  // HeroUI wrappers — overlays
125
125
  export { default as HeroUIDrawer } from "./heroui/Drawer";
@@ -1,6 +1,9 @@
1
- import React from "react";
1
+ export interface CardSkeletonProps {
2
+ lines?: number;
3
+ className?: string;
4
+ }
2
5
 
3
- export default function CardSkeleton({ lines = 3, className = "" }) {
6
+ export default function CardSkeleton({ lines = 3, className = "" }: CardSkeletonProps) {
4
7
  return (
5
8
  <div
6
9
  className={[
@@ -26,5 +29,3 @@ export default function CardSkeleton({ lines = 3, className = "" }) {
26
29
  </div>
27
30
  );
28
31
  }
29
-
30
-
@@ -1,7 +1,15 @@
1
1
  import React from "react";
2
- import { tokens, getTokenCSSProperties } from "./tokens";
2
+ import { tokens, getTokenCSSProperties, Tokens } from "./tokens";
3
3
 
4
- const ThemeModeContext = React.createContext({
4
+ export type ThemeMode = "light" | "dark";
5
+
6
+ export interface ThemeModeContextValue {
7
+ mode: ThemeMode;
8
+ theme: Tokens;
9
+ toggle: () => void;
10
+ }
11
+
12
+ const ThemeModeContext = React.createContext<ThemeModeContextValue>({
5
13
  mode: "light",
6
14
  theme: tokens,
7
15
  toggle: () => {}
@@ -9,14 +17,14 @@ const ThemeModeContext = React.createContext({
9
17
 
10
18
  const STORAGE_KEY = "app-color-mode";
11
19
 
12
- function applyHtmlDarkClass(mode) {
20
+ function applyHtmlDarkClass(mode: ThemeMode): void {
13
21
  if (typeof document === "undefined") return;
14
22
  const root = document.documentElement;
15
23
  if (mode === "dark") root.classList.add("dark");
16
24
  else root.classList.remove("dark");
17
25
  }
18
26
 
19
- function applyTokenCSSProperties() {
27
+ function applyTokenCSSProperties(): void {
20
28
  if (typeof document === "undefined") return;
21
29
  const root = document.documentElement;
22
30
  const props = getTokenCSSProperties();
@@ -25,12 +33,17 @@ function applyTokenCSSProperties() {
25
33
  }
26
34
  }
27
35
 
28
- export function useThemeMode() {
36
+ export function useThemeMode(): ThemeModeContextValue {
29
37
  return React.useContext(ThemeModeContext);
30
38
  }
31
39
 
32
- export default function AppThemeProvider({ initialMode = "light", children }) {
33
- const [mode, setMode] = React.useState(initialMode);
40
+ export interface AppThemeProviderProps {
41
+ initialMode?: ThemeMode;
42
+ children: React.ReactNode;
43
+ }
44
+
45
+ export default function AppThemeProvider({ initialMode = "light", children }: AppThemeProviderProps) {
46
+ const [mode, setMode] = React.useState<ThemeMode>(initialMode);
34
47
 
35
48
  React.useEffect(() => {
36
49
  applyTokenCSSProperties();
@@ -10,7 +10,41 @@
10
10
  * and tailwind.config.js references them via var(--color-brand-*).
11
11
  */
12
12
 
13
- export const tokens = {
13
+ export interface ColorShades {
14
+ 50: string;
15
+ 100: string;
16
+ 200: string;
17
+ 300: string;
18
+ 400: string;
19
+ 500: string;
20
+ 600: string;
21
+ 700: string;
22
+ 800: string;
23
+ 900: string;
24
+ 950: string;
25
+ }
26
+
27
+ export interface Tokens {
28
+ colors: {
29
+ brand: ColorShades;
30
+ accent: ColorShades;
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
+ }
46
+
47
+ export const tokens: Tokens = {
14
48
  colors: {
15
49
  brand: {
16
50
  50: "#EEF2FF",
@@ -61,8 +95,8 @@ export const tokens = {
61
95
  * Generates CSS custom property assignments from the token palettes.
62
96
  * Used by AppThemeProvider to inject on :root at runtime.
63
97
  */
64
- export function getTokenCSSProperties() {
65
- const props = {};
98
+ export function getTokenCSSProperties(): Record<string, string> {
99
+ const props: Record<string, string> = {};
66
100
  for (const [palette, shades] of Object.entries(tokens.colors)) {
67
101
  for (const [shade, value] of Object.entries(shades)) {
68
102
  props[`--color-${palette}-${shade}`] = value;
@@ -1,20 +1,125 @@
1
- import React from "react";
1
+ import * as React from "react";
2
2
  import {
3
- BaseCard,
4
3
  MetricCard,
5
4
  TableCard,
6
5
  ChartCard,
7
6
  D3Chart,
8
7
  D3ChartTemplates,
9
8
  StatusCard,
10
- ListCard,
11
9
  UIButton,
12
- UIChip,
13
- UIText
10
+ UIChip
14
11
  } from "@/components/library";
15
12
 
13
+ export interface Metric {
14
+ label: string;
15
+ value: string | number;
16
+ trend?: string | number | null;
17
+ }
18
+
19
+ export interface MetricsStripProps {
20
+ metrics?: Metric[];
21
+ title?: string;
22
+ collapsible?: boolean;
23
+ collapsed?: boolean;
24
+ }
25
+
26
+ export interface ListItem {
27
+ id?: string;
28
+ title?: string;
29
+ name?: string;
30
+ description?: string;
31
+ status?: "critical" | "warning" | string;
32
+ actions?: Array<string | { label: string }>;
33
+ }
34
+
35
+ export interface ItemListProps {
36
+ items?: ListItem[];
37
+ title?: string;
38
+ onItemClick?: (item: ListItem) => void;
39
+ }
40
+
41
+ export interface TableColumn {
42
+ key: string;
43
+ label: string;
44
+ }
45
+
46
+ export interface DataTableProps {
47
+ title?: string;
48
+ subtitle?: string;
49
+ columns?: TableColumn[];
50
+ data?: any[];
51
+ rows?: any[];
52
+ searchable?: boolean;
53
+ sortable?: boolean;
54
+ paginated?: boolean;
55
+ pageSize?: number;
56
+ }
57
+
58
+ export interface DataPoint {
59
+ x: number;
60
+ y: number;
61
+ [key: string]: any;
62
+ }
63
+
64
+ export interface DataChartProps {
65
+ title?: string;
66
+ subtitle?: string;
67
+ chartType?: string;
68
+ data?: DataPoint[];
69
+ height?: number;
70
+ }
71
+
72
+ export interface MetricCardComponentProps {
73
+ title?: string;
74
+ label?: string;
75
+ value?: string | number;
76
+ trend?: string | number;
77
+ change?: string | number;
78
+ changeType?: string;
79
+ color?: string;
80
+ icon?: React.ReactNode;
81
+ description?: string;
82
+ }
83
+
84
+ export interface StatusCardComponentProps {
85
+ title?: string;
86
+ subtitle?: string;
87
+ status?: string;
88
+ items?: any[];
89
+ layout?: string;
90
+ showProgress?: boolean;
91
+ showTimestamp?: boolean;
92
+ }
93
+
94
+ export interface ActionListProps {
95
+ actions?: Array<string | { label: string }>;
96
+ title?: string;
97
+ onAction?: (action: string | { label: string }) => void;
98
+ }
99
+
100
+ export interface CalloutCardProps {
101
+ title?: string;
102
+ message?: string;
103
+ tone?: "neutral" | "success" | "warning" | "danger";
104
+ }
105
+
106
+ export interface SpacerProps {
107
+ size?: "sm" | "md" | "lg";
108
+ }
109
+
110
+ export interface NarrativeSummaryProps {
111
+ summary?: string;
112
+ title?: string;
113
+ }
114
+
115
+ export interface SchemaComponent {
116
+ id?: string;
117
+ type: string;
118
+ props?: Record<string, any>;
119
+ }
120
+
16
121
  const BUILTIN_COMPONENTS = {
17
- NarrativeSummary({ summary, title }) {
122
+ NarrativeSummary({ summary, title }: NarrativeSummaryProps) {
18
123
  return (
19
124
  <div className="text-sm text-slate-600 dark:text-slate-300">
20
125
  {title && <div className="mb-1 font-medium text-slate-900 dark:text-slate-50">{title}</div>}
@@ -23,7 +128,7 @@ const BUILTIN_COMPONENTS = {
23
128
  );
24
129
  },
25
130
 
26
- MetricsStrip({ metrics = [], title, collapsible = false, collapsed: initialCollapsed = false }) {
131
+ MetricsStrip({ metrics = [], title, collapsible = false, collapsed: initialCollapsed = false }: MetricsStripProps) {
27
132
  const [collapsed, setCollapsed] = React.useState(initialCollapsed);
28
133
 
29
134
  const items = metrics.length ? metrics : [
@@ -68,7 +173,7 @@ const BUILTIN_COMPONENTS = {
68
173
  <div className="flex items-baseline gap-1.5">
69
174
  <span className="text-sm font-semibold text-slate-700 dark:text-slate-200">{m.value}</span>
70
175
  {m.trend && (
71
- <span className={`text-xs ${String(m.trend).startsWith?.("+") || m.trend > 0 ? "text-red-500" : "text-emerald-500"}`}>
176
+ <span className={`text-xs ${String(m.trend).startsWith?.("+") || (typeof m.trend === "number" && m.trend > 0) ? "text-red-500" : "text-emerald-500"}`}>
72
177
  {typeof m.trend === "number" ? (m.trend > 0 ? `+${m.trend}` : m.trend) : m.trend}
73
178
  </span>
74
179
  )}
@@ -80,8 +185,8 @@ const BUILTIN_COMPONENTS = {
80
185
  );
81
186
  },
82
187
 
83
- ItemList({ items = [], title, onItemClick }) {
84
- const [expanded, setExpanded] = React.useState(null);
188
+ ItemList({ items = [], title, onItemClick }: ItemListProps) {
189
+ const [expanded, setExpanded] = React.useState<string | number | null>(null);
85
190
  if (!items.length) {
86
191
  return <div className="text-sm text-slate-500 dark:text-slate-400">No items.</div>;
87
192
  }
@@ -146,7 +251,7 @@ const BUILTIN_COMPONENTS = {
146
251
  );
147
252
  },
148
253
 
149
- DataTable({ title, subtitle, columns = [], data = [], rows, searchable = true, sortable = true, paginated = true, pageSize = 5 }) {
254
+ DataTable({ title, subtitle, columns = [], data = [], rows, searchable = true, sortable = true, paginated = true, pageSize = 5 }: DataTableProps) {
150
255
  const tableData = data.length ? data : (rows ?? []);
151
256
  const cols = columns.length ? columns : [
152
257
  { key: "name", label: "Name" },
@@ -167,7 +272,7 @@ const BUILTIN_COMPONENTS = {
167
272
  );
168
273
  },
169
274
 
170
- DataChart({ title, subtitle, chartType = "line", data = [], height = 200 }) {
275
+ DataChart({ title, subtitle, chartType = "line", data = [], height = 200 }: DataChartProps) {
171
276
  const series = data.length ? data : Array.from({ length: 12 }, (_, i) => ({ x: i, y: Math.random() * 100 }));
172
277
  return (
173
278
  <ChartCard
@@ -177,11 +282,11 @@ const BUILTIN_COMPONENTS = {
177
282
  height={height}
178
283
  chart={
179
284
  <D3Chart
180
- data={series}
285
+ data={series as any}
181
286
  responsive
182
287
  height={height}
183
288
  ariaLabel={title}
184
- renderChart={(svg, d, dims, opts) => D3ChartTemplates.lineChart(svg, d, dims, opts)}
289
+ renderChart={(svg, d, dims, opts) => D3ChartTemplates.lineChart(svg, d as any, dims, opts)}
185
290
  options={{ xKey: "x", yKey: "y", showGrid: true, showAxes: true }}
186
291
  />
187
292
  }
@@ -189,36 +294,36 @@ const BUILTIN_COMPONENTS = {
189
294
  );
190
295
  },
191
296
 
192
- MetricCard({ title, label, value, trend, change, changeType, color, icon, description }) {
297
+ MetricCard({ title, label, value, trend, change, changeType, color, icon, description }: MetricCardComponentProps) {
193
298
  return (
194
299
  <MetricCard
195
- title={title ?? label}
300
+ title={(title ?? label) as any}
196
301
  value={value ?? "—"}
197
- trend={trend}
198
- change={change}
199
- changeType={changeType}
200
- color={color}
302
+ trend={trend as any}
303
+ change={change as any}
304
+ changeType={changeType as any}
305
+ color={color as any}
201
306
  icon={icon}
202
- description={description}
307
+ subtitle={description}
203
308
  />
204
309
  );
205
310
  },
206
311
 
207
- StatusCard({ title, subtitle, status, items, layout, showProgress, showTimestamp }) {
312
+ StatusCard({ title, subtitle, status, items, layout, showProgress, showTimestamp }: StatusCardComponentProps) {
208
313
  return (
209
314
  <StatusCard
210
315
  title={title}
211
316
  subtitle={subtitle}
212
317
  status={status}
213
318
  items={items}
214
- layout={layout}
319
+ layout={layout as any}
215
320
  showProgress={showProgress}
216
321
  showTimestamp={showTimestamp}
217
322
  />
218
323
  );
219
324
  },
220
325
 
221
- ActionList({ actions = [], title, onAction }) {
326
+ ActionList({ actions = [], title, onAction }: ActionListProps) {
222
327
  return (
223
328
  <div className="rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-900">
224
329
  {title && <div className="mb-3 text-sm font-medium text-slate-900 dark:text-slate-50">{title}</div>}
@@ -238,7 +343,7 @@ const BUILTIN_COMPONENTS = {
238
343
  );
239
344
  },
240
345
 
241
- CalloutCard({ title, message, tone = "neutral" }) {
346
+ CalloutCard({ title, message, tone = "neutral" }: CalloutCardProps) {
242
347
  const toneClasses = {
243
348
  neutral: "border-slate-200 bg-slate-50 text-slate-700 dark:border-slate-800 dark:bg-slate-950/30 dark:text-slate-200",
244
349
  success: "border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900/40 dark:bg-emerald-950/20 dark:text-emerald-200",
@@ -257,27 +362,27 @@ const BUILTIN_COMPONENTS = {
257
362
  return <div className="h-px bg-slate-200 dark:bg-slate-800" />;
258
363
  },
259
364
 
260
- Spacer({ size = "md" }) {
365
+ Spacer({ size = "md" }: SpacerProps) {
261
366
  const heights = { sm: "h-2", md: "h-4", lg: "h-6" };
262
367
  return <div className={heights[size] ?? heights.md} />;
263
368
  }
264
369
  };
265
370
 
266
- let _registry = { ...BUILTIN_COMPONENTS };
371
+ let _registry: Record<string, React.ComponentType<any>> = { ...BUILTIN_COMPONENTS };
267
372
 
268
- export function getComponentRegistry() {
373
+ export function getComponentRegistry(): Record<string, React.ComponentType<any>> {
269
374
  return _registry;
270
375
  }
271
376
 
272
- export function registerComponent(type, Component) {
377
+ export function registerComponent(type: string, Component: React.ComponentType<any>): void {
273
378
  _registry = { ..._registry, [type]: Component };
274
379
  }
275
380
 
276
- export function registerComponents(map) {
381
+ export function registerComponents(map: Record<string, React.ComponentType<any>>): void {
277
382
  _registry = { ..._registry, ...map };
278
383
  }
279
384
 
280
- export function renderSchemaComponent(component, index) {
385
+ export function renderSchemaComponent(component: SchemaComponent, index: number): React.ReactElement {
281
386
  const registry = getComponentRegistry();
282
387
  const Component = registry[component.type];
283
388
  if (!Component) {
@@ -290,7 +395,7 @@ export function renderSchemaComponent(component, index) {
290
395
  return <Component key={component.id ?? index} {...(component.props ?? {})} />;
291
396
  }
292
397
 
293
- export function renderSchema(components = []) {
398
+ export function renderSchema(components: SchemaComponent[] = []): React.ReactElement[] {
294
399
  return components.map((c, i) => renderSchemaComponent(c, i));
295
400
  }
296
401
 
@@ -1,10 +0,0 @@
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";