@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.
- 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 +18 -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 +37 -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/dist/components/workspace/ComponentRegistry.d.ts +116 -140
- package/dist/components/workspace/ComponentRegistry.js +43 -43
- package/dist/components/workspace/ComponentRegistry.js.map +1 -1
- package/package.json +2 -2
- 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} +23 -10
- 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 +182 -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/workspace/{ComponentRegistry.jsx → ComponentRegistry.tsx} +137 -32
- package/src/components/library/chat/index.jsx +0 -10
- 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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
33
|
-
|
|
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
|
|
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
|
-
|
|
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";
|