@reltio/design 0.0.3 → 0.1.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/components/AssistantLoader/AssistantLoader.d.ts +7 -0
- package/components/AssistantLoader/AssistantLoader.js +15 -0
- package/components/AssistantLoader/AssistantLoader.module.css.d.ts +2 -0
- package/components/AssistantLoader/AssistantLoader.module.css.js +101 -0
- package/components/AssistantLoader/AssistantLoader.module.css.json +1 -0
- package/components/AssistantLoader/AssistantLoader.types.d.ts +16 -0
- package/components/AssistantLoader/AssistantLoader.types.js +1 -0
- package/components/AssistantLoader/index.d.ts +2 -0
- package/components/AssistantLoader/index.js +1 -0
- package/components/Chat/Chat.d.ts +14 -0
- package/components/Chat/Chat.js +84 -0
- package/components/Chat/Chat.module.css.d.ts +2 -0
- package/components/Chat/Chat.module.css.js +78 -0
- package/components/Chat/Chat.module.css.json +1 -0
- package/components/Chat/Chat.types.d.ts +58 -0
- package/components/Chat/Chat.types.js +1 -0
- package/components/Chat/components/AssistantMessage/AssistantMessage.d.ts +7 -0
- package/components/Chat/components/AssistantMessage/AssistantMessage.js +24 -0
- package/components/Chat/components/AssistantMessage/AssistantMessage.module.css.d.ts +2 -0
- package/components/Chat/components/AssistantMessage/AssistantMessage.module.css.js +26 -0
- package/components/Chat/components/AssistantMessage/AssistantMessage.module.css.json +1 -0
- package/components/Chat/components/AssistantMessage/AssistantMessage.types.d.ts +20 -0
- package/components/Chat/components/AssistantMessage/AssistantMessage.types.js +1 -0
- package/components/Chat/components/AssistantMessage/index.d.ts +2 -0
- package/components/Chat/components/AssistantMessage/index.js +1 -0
- package/components/Chat/components/UserMessage/UserMessage.d.ts +6 -0
- package/components/Chat/components/UserMessage/UserMessage.js +12 -0
- package/components/Chat/components/UserMessage/UserMessage.module.css.d.ts +2 -0
- package/components/Chat/components/UserMessage/UserMessage.module.css.js +11 -0
- package/components/Chat/components/UserMessage/UserMessage.module.css.json +1 -0
- package/components/Chat/components/UserMessage/UserMessage.types.d.ts +16 -0
- package/components/Chat/components/UserMessage/UserMessage.types.js +1 -0
- package/components/Chat/components/UserMessage/index.d.ts +2 -0
- package/components/Chat/components/UserMessage/index.js +1 -0
- package/components/Chat/index.d.ts +2 -0
- package/components/Chat/index.js +1 -0
- package/components/Details/Details.d.ts +7 -0
- package/components/Details/Details.js +40 -0
- package/components/Details/Details.module.css.d.ts +2 -0
- package/components/Details/Details.module.css.js +105 -0
- package/components/Details/Details.module.css.json +1 -0
- package/components/Details/Details.types.d.ts +55 -0
- package/components/Details/Details.types.js +1 -0
- package/components/Details/index.d.ts +2 -0
- package/components/Details/index.js +1 -0
- package/components/ErrorBoundary/ErrorBoundary.d.ts +12 -0
- package/components/ErrorBoundary/ErrorBoundary.js +23 -0
- package/components/ErrorBoundary/ErrorBoundary.types.d.ts +25 -0
- package/components/ErrorBoundary/ErrorBoundary.types.js +1 -0
- package/components/ErrorBoundary/index.d.ts +2 -0
- package/components/ErrorBoundary/index.js +1 -0
- package/components/ErrorMessage/ErrorMessage.d.ts +6 -0
- package/components/ErrorMessage/ErrorMessage.js +12 -0
- package/components/ErrorMessage/ErrorMessage.module.css.d.ts +2 -0
- package/components/ErrorMessage/ErrorMessage.module.css.js +50 -0
- package/components/ErrorMessage/ErrorMessage.module.css.json +1 -0
- package/components/ErrorMessage/ErrorMessage.types.d.ts +14 -0
- package/components/ErrorMessage/ErrorMessage.types.js +1 -0
- package/components/ErrorMessage/index.d.ts +2 -0
- package/components/ErrorMessage/index.js +1 -0
- package/components/Markdown/Markdown.d.ts +8 -0
- package/components/Markdown/Markdown.js +26 -0
- package/components/Markdown/Markdown.module.css.d.ts +2 -0
- package/components/Markdown/Markdown.module.css.js +228 -0
- package/components/Markdown/Markdown.module.css.json +1 -0
- package/components/Markdown/Markdown.types.d.ts +54 -0
- package/components/Markdown/Markdown.types.js +1 -0
- package/components/Markdown/index.d.ts +2 -0
- package/components/Markdown/index.js +1 -0
- package/components/Markdown/markdownOverrides.d.ts +19 -0
- package/components/Markdown/markdownOverrides.js +36 -0
- package/components/Skeleton/Skeleton.d.ts +7 -0
- package/components/Skeleton/Skeleton.js +16 -0
- package/components/Skeleton/Skeleton.module.css.d.ts +2 -0
- package/components/Skeleton/Skeleton.module.css.js +73 -0
- package/components/Skeleton/Skeleton.module.css.json +1 -0
- package/components/Skeleton/Skeleton.types.d.ts +31 -0
- package/components/Skeleton/Skeleton.types.js +1 -0
- package/components/Skeleton/index.d.ts +2 -0
- package/components/Skeleton/index.js +1 -0
- package/components/TextArea/TextArea.d.ts +22 -0
- package/components/TextArea/TextArea.js +13 -0
- package/components/TextArea/TextArea.module.css.d.ts +2 -0
- package/components/TextArea/TextArea.module.css.js +159 -0
- package/components/TextArea/TextArea.module.css.json +1 -0
- package/components/TextArea/TextArea.types.d.ts +39 -0
- package/components/TextArea/TextArea.types.js +1 -0
- package/components/TextArea/index.d.ts +2 -0
- package/components/TextArea/index.js +1 -0
- package/components/TreeList/TreeList.types.d.ts +1 -1
- package/components/TreeList/components/TreeNode/TreeNode.js +2 -2
- package/components/TreeList/components/TreeNode/TreeNode.module.css.js +16 -8
- package/components/TreeList/components/TreeNode/TreeNode.module.css.json +1 -1
- package/components/index.d.ts +10 -0
- package/components/index.js +10 -0
- package/icons/AccountCircle.d.ts +2 -0
- package/icons/AccountCircle.js +6 -0
- package/icons/Add.d.ts +2 -0
- package/icons/Add.js +6 -0
- package/icons/ArrowBack.d.ts +2 -0
- package/icons/ArrowBack.js +6 -0
- package/icons/ArrowDropDown.d.ts +2 -0
- package/icons/ArrowDropDown.js +6 -0
- package/icons/ArrowDropUp.d.ts +2 -0
- package/icons/ArrowDropUp.js +6 -0
- package/icons/ArrowForward.d.ts +2 -0
- package/icons/ArrowForward.js +6 -0
- package/icons/ArrowLeft.d.ts +2 -0
- package/icons/ArrowLeft.js +6 -0
- package/icons/ArrowRight.d.ts +2 -0
- package/icons/ArrowRight.js +6 -0
- package/icons/Attachment.d.ts +2 -0
- package/icons/Attachment.js +6 -0
- package/icons/Chat.d.ts +2 -0
- package/icons/Chat.js +6 -0
- package/icons/Check.d.ts +2 -0
- package/icons/Check.js +6 -0
- package/icons/CheckCircle.d.ts +2 -0
- package/icons/CheckCircle.js +6 -0
- package/icons/ChevronLeft.d.ts +2 -0
- package/icons/ChevronLeft.js +6 -0
- package/icons/ChevronRight.d.ts +2 -0
- package/icons/ChevronRight.js +6 -0
- package/icons/Close.d.ts +2 -0
- package/icons/Close.js +6 -0
- package/icons/CodeBrackets.d.ts +2 -0
- package/icons/CodeBrackets.js +6 -0
- package/icons/Comment.d.ts +2 -0
- package/icons/Comment.js +6 -0
- package/icons/ContentCopy.d.ts +2 -0
- package/icons/ContentCopy.js +6 -0
- package/icons/ContentPaste.d.ts +2 -0
- package/icons/ContentPaste.js +6 -0
- package/icons/Delete.d.ts +2 -0
- package/icons/Delete.js +6 -0
- package/icons/Description.d.ts +2 -0
- package/icons/Description.js +6 -0
- package/icons/Download.d.ts +2 -0
- package/icons/Download.js +6 -0
- package/icons/Edit.d.ts +2 -0
- package/icons/Edit.js +6 -0
- package/icons/Email.d.ts +2 -0
- package/icons/Email.js +6 -0
- package/icons/ErrorCircle.d.ts +2 -0
- package/icons/ErrorCircle.js +6 -0
- package/icons/ExpandLess.d.ts +2 -0
- package/icons/ExpandLess.js +6 -0
- package/icons/ExpandMore.d.ts +2 -0
- package/icons/ExpandMore.js +6 -0
- package/icons/FilterList.d.ts +2 -0
- package/icons/FilterList.js +6 -0
- package/icons/Folder.d.ts +2 -0
- package/icons/Folder.js +6 -0
- package/icons/Help.d.ts +2 -0
- package/icons/Help.js +6 -0
- package/icons/Icon.module.css.d.ts +2 -0
- package/icons/Icon.module.css.js +70 -0
- package/icons/Icon.module.css.json +1 -0
- package/icons/Icon.types.d.ts +13 -0
- package/icons/Icon.types.js +1 -0
- package/icons/Info.d.ts +2 -0
- package/icons/Info.js +6 -0
- package/icons/KeyboardArrowDown.d.ts +2 -0
- package/icons/KeyboardArrowDown.js +6 -0
- package/icons/KeyboardArrowUp.d.ts +2 -0
- package/icons/KeyboardArrowUp.js +6 -0
- package/icons/Logout.d.ts +2 -0
- package/icons/Logout.js +6 -0
- package/icons/Menu.d.ts +2 -0
- package/icons/Menu.js +6 -0
- package/icons/Notifications.d.ts +2 -0
- package/icons/Notifications.js +6 -0
- package/icons/People.d.ts +2 -0
- package/icons/People.js +6 -0
- package/icons/Person.d.ts +2 -0
- package/icons/Person.js +6 -0
- package/icons/Refresh.d.ts +2 -0
- package/icons/Refresh.js +6 -0
- package/icons/Remove.d.ts +2 -0
- package/icons/Remove.js +6 -0
- package/icons/Save.d.ts +2 -0
- package/icons/Save.js +6 -0
- package/icons/Search.d.ts +2 -0
- package/icons/Search.js +6 -0
- package/icons/Settings.d.ts +2 -0
- package/icons/Settings.js +6 -0
- package/icons/Share.d.ts +2 -0
- package/icons/Share.js +6 -0
- package/icons/Sort.d.ts +2 -0
- package/icons/Sort.js +6 -0
- package/icons/Upload.d.ts +2 -0
- package/icons/Upload.js +6 -0
- package/icons/Visibility.d.ts +2 -0
- package/icons/Visibility.js +6 -0
- package/icons/VisibilityOff.d.ts +2 -0
- package/icons/VisibilityOff.js +6 -0
- package/icons/Warning.d.ts +2 -0
- package/icons/Warning.js +6 -0
- package/icons/index.d.ts +52 -0
- package/icons/index.js +101 -0
- package/package.json +8 -7
- package/packages/design/index.d.ts +1 -2
- package/packages/design/index.js +1 -2
- package/components/TreeList/components/ChevronIcon.d.ts +0 -5
- package/components/TreeList/components/ChevronIcon.js +0 -8
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AssistantLoaderProps } from "./AssistantLoader.types";
|
|
2
|
+
/**
|
|
3
|
+
* Displays a standardized loading indicator for assistant responses using a GIF animation.
|
|
4
|
+
* Size is controlled via the `--reltio-assistant-loader-size` CSS variable (default: 32px).
|
|
5
|
+
* Includes accessibility attributes (aria-busy, aria-label, role="status").
|
|
6
|
+
*/
|
|
7
|
+
export declare const AssistantLoader: ({ className, ...rest }: AssistantLoaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { classNames } from "../../utils/classNames";
|
|
3
|
+
import styles from "./AssistantLoader.module.css";
|
|
4
|
+
const LOADING_GIF_SRC = "/icons/loading.gif";
|
|
5
|
+
const DEFAULT_LABEL = "thinking";
|
|
6
|
+
/**
|
|
7
|
+
* Displays a standardized loading indicator for assistant responses using a GIF animation.
|
|
8
|
+
* Size is controlled via the `--reltio-assistant-loader-size` CSS variable (default: 32px).
|
|
9
|
+
* Includes accessibility attributes (aria-busy, aria-label, role="status").
|
|
10
|
+
*/
|
|
11
|
+
export const AssistantLoader = ({ className, ...rest }) => {
|
|
12
|
+
return (
|
|
13
|
+
// biome-ignore lint/a11y/useSemanticElements: status role is correct for loading placeholder; output is for calculation results
|
|
14
|
+
_jsxs("div", { className: classNames(styles.root, className), "aria-busy": "true", "aria-label": DEFAULT_LABEL, role: "status", ...rest, children: [_jsx("img", { src: LOADING_GIF_SRC, alt: "", className: styles.indicator, "aria-hidden": "true" }), _jsx("div", { className: classNames(styles.dotFlashing), "aria-hidden": "true" })] }));
|
|
15
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import styleInject from 'style-inject';
|
|
2
|
+
import json from './AssistantLoader.module.css.json';
|
|
3
|
+
styleInject(`
|
|
4
|
+
/* CSS Custom Properties - All defined on .root with --reltio-assistant-loader- prefix */
|
|
5
|
+
._root_lj6wo_1 {
|
|
6
|
+
--reltio-assistant-loader-size: 32px;
|
|
7
|
+
|
|
8
|
+
/* Dot dimensions scale with size */
|
|
9
|
+
--reltio-assistant-loader-dot-size: calc(
|
|
10
|
+
var(--reltio-assistant-loader-size, 32px) *
|
|
11
|
+
0.25
|
|
12
|
+
);
|
|
13
|
+
--reltio-assistant-loader-dot-radius: calc(
|
|
14
|
+
var(--reltio-assistant-loader-size, 32px) *
|
|
15
|
+
0.15625
|
|
16
|
+
);
|
|
17
|
+
--reltio-assistant-loader-dot-color: #8d8dc8;
|
|
18
|
+
--reltio-assistant-loader-dot-color-dimmed: rgba(152, 128, 255, 0.2);
|
|
19
|
+
--reltio-assistant-loader-dot-gap: calc(
|
|
20
|
+
var(--reltio-assistant-loader-size, 32px) *
|
|
21
|
+
0.375
|
|
22
|
+
);
|
|
23
|
+
--reltio-assistant-loader-dot-margin-left: calc(
|
|
24
|
+
var(--reltio-assistant-loader-size, 32px) *
|
|
25
|
+
0.625
|
|
26
|
+
);
|
|
27
|
+
--reltio-assistant-loader-dot-duration: 1s;
|
|
28
|
+
--reltio-assistant-loader-dot-delay-middle: 0.5s;
|
|
29
|
+
--reltio-assistant-loader-dot-delay-last: 1s;
|
|
30
|
+
|
|
31
|
+
position: relative;
|
|
32
|
+
display: inline-flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
box-sizing: border-box;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* GIF container - uses CSS variable for size with fallback */
|
|
39
|
+
._indicator_lj6wo_36 {
|
|
40
|
+
width: var(--reltio-assistant-loader-size, 32px);
|
|
41
|
+
height: var(--reltio-assistant-loader-size, 32px);
|
|
42
|
+
display: block;
|
|
43
|
+
object-fit: contain;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Dot flashing indicator - uses CSS variables from .root */
|
|
47
|
+
._dotFlashing_lj6wo_44 {
|
|
48
|
+
position: absolute;
|
|
49
|
+
left: calc(
|
|
50
|
+
var(--reltio-assistant-loader-size, 32px) +
|
|
51
|
+
var(--reltio-assistant-loader-dot-margin-left, 20px)
|
|
52
|
+
);
|
|
53
|
+
bottom: 20%;
|
|
54
|
+
transform: translateY(50%);
|
|
55
|
+
width: var(--reltio-assistant-loader-dot-size, 8px);
|
|
56
|
+
height: var(--reltio-assistant-loader-dot-size, 8px);
|
|
57
|
+
border-radius: var(--reltio-assistant-loader-dot-radius, 5px);
|
|
58
|
+
background-color: var(--reltio-assistant-loader-dot-color, #8d8dc8);
|
|
59
|
+
animation: _dotFlashing_lj6wo_44 var(--reltio-assistant-loader-dot-duration, 1s)
|
|
60
|
+
infinite linear alternate;
|
|
61
|
+
animation-delay: var(--reltio-assistant-loader-dot-delay-middle, 0.5s);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
._dotFlashing_lj6wo_44::before,
|
|
65
|
+
._dotFlashing_lj6wo_44::after {
|
|
66
|
+
content: "";
|
|
67
|
+
position: absolute;
|
|
68
|
+
top: 0;
|
|
69
|
+
display: block;
|
|
70
|
+
width: var(--reltio-assistant-loader-dot-size, 8px);
|
|
71
|
+
height: var(--reltio-assistant-loader-dot-size, 8px);
|
|
72
|
+
border-radius: var(--reltio-assistant-loader-dot-radius, 5px);
|
|
73
|
+
background-color: var(--reltio-assistant-loader-dot-color, #8d8dc8);
|
|
74
|
+
animation: _dotFlashing_lj6wo_44 var(--reltio-assistant-loader-dot-duration, 1s)
|
|
75
|
+
infinite alternate;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
._dotFlashing_lj6wo_44::before {
|
|
79
|
+
left: calc(-1 * var(--reltio-assistant-loader-dot-gap, 12px));
|
|
80
|
+
animation-delay: 0s;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
._dotFlashing_lj6wo_44::after {
|
|
84
|
+
left: var(--reltio-assistant-loader-dot-gap, 12px);
|
|
85
|
+
animation-delay: var(--reltio-assistant-loader-dot-delay-last, 1s);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@keyframes _dotFlashing_lj6wo_44 {
|
|
89
|
+
0% {
|
|
90
|
+
background-color: var(--reltio-assistant-loader-dot-color, #8d8dc8);
|
|
91
|
+
}
|
|
92
|
+
50%,
|
|
93
|
+
100% {
|
|
94
|
+
background-color: var(
|
|
95
|
+
--reltio-assistant-loader-dot-color-dimmed,
|
|
96
|
+
rgba(152, 128, 255, 0.2)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
`);
|
|
101
|
+
export default json;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "root": "_root_lj6wo_1", "indicator": "_indicator_lj6wo_36", "dotFlashing": "_dotFlashing_lj6wo_44" }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props for the AssistantLoader component
|
|
4
|
+
*/
|
|
5
|
+
export type AssistantLoaderProps = {
|
|
6
|
+
/**
|
|
7
|
+
* Additional CSS class names
|
|
8
|
+
*/
|
|
9
|
+
className?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Inline styles (e.g. for CSS variable overrides)
|
|
12
|
+
*/
|
|
13
|
+
style?: React.CSSProperties & {
|
|
14
|
+
"--reltio-assistant-loader-size"?: string;
|
|
15
|
+
};
|
|
16
|
+
} & Omit<React.ComponentPropsWithoutRef<"div">, "children" | "className" | "style">;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./AssistantLoader";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ChatProps } from "./Chat.types";
|
|
2
|
+
/**
|
|
3
|
+
* Scrollable chat window that renders a conversation between a user and an AI assistant.
|
|
4
|
+
*
|
|
5
|
+
* **Loading behavior (`initialLoading → false`):**
|
|
6
|
+
* The last user message is pinned to the top edge of the visible chat area;
|
|
7
|
+
* all subsequent assistant messages are displayed below it.
|
|
8
|
+
*
|
|
9
|
+
* **Thinking behavior (`thinking → true`):**
|
|
10
|
+
* The chat automatically scrolls to the last user message and shows
|
|
11
|
+
* a loader (AssistantLoader) directly beneath it, indicating the assistant
|
|
12
|
+
* is generating a response.
|
|
13
|
+
*/
|
|
14
|
+
export declare const Chat: ({ messages, thinking, initialLoading, className, ...rest }: ChatProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { AssistantLoader } from "../../components/AssistantLoader";
|
|
4
|
+
import { Skeleton } from "../../components/Skeleton";
|
|
5
|
+
import { KeyboardArrowDown } from "../../icons/KeyboardArrowDown";
|
|
6
|
+
import { classNames } from "../../utils/classNames";
|
|
7
|
+
import styles from "./Chat.module.css";
|
|
8
|
+
import { AssistantMessage } from "./components/AssistantMessage";
|
|
9
|
+
import { UserMessage } from "./components/UserMessage";
|
|
10
|
+
const SCROLL_THRESHOLD = 100;
|
|
11
|
+
const isUserMessage = (m) => m.role === "user";
|
|
12
|
+
const isAssistantMessage = (m) => m.role === "assistant";
|
|
13
|
+
const ChatMessage = memo(({ message }) => {
|
|
14
|
+
if (isUserMessage(message)) {
|
|
15
|
+
return (_jsx(UserMessage, { className: styles.userMessage, children: message.content }));
|
|
16
|
+
}
|
|
17
|
+
if (isAssistantMessage(message)) {
|
|
18
|
+
return _jsx(AssistantMessage, { children: message.content });
|
|
19
|
+
}
|
|
20
|
+
return _jsx(_Fragment, { children: message.content ?? null });
|
|
21
|
+
});
|
|
22
|
+
const isScrolledToBottom = (el) => el.scrollHeight - el.scrollTop - el.clientHeight < SCROLL_THRESHOLD;
|
|
23
|
+
/**
|
|
24
|
+
* Scrollable chat window that renders a conversation between a user and an AI assistant.
|
|
25
|
+
*
|
|
26
|
+
* **Loading behavior (`initialLoading → false`):**
|
|
27
|
+
* The last user message is pinned to the top edge of the visible chat area;
|
|
28
|
+
* all subsequent assistant messages are displayed below it.
|
|
29
|
+
*
|
|
30
|
+
* **Thinking behavior (`thinking → true`):**
|
|
31
|
+
* The chat automatically scrolls to the last user message and shows
|
|
32
|
+
* a loader (AssistantLoader) directly beneath it, indicating the assistant
|
|
33
|
+
* is generating a response.
|
|
34
|
+
*/
|
|
35
|
+
export const Chat = ({ messages, thinking = false, initialLoading = false, className, ...rest }) => {
|
|
36
|
+
const containerRef = useRef(null);
|
|
37
|
+
const [showScrollButton, setShowScrollButton] = useState(false);
|
|
38
|
+
const handleScroll = useCallback(() => {
|
|
39
|
+
const el = containerRef.current;
|
|
40
|
+
if (!el)
|
|
41
|
+
return;
|
|
42
|
+
setShowScrollButton(!isScrolledToBottom(el));
|
|
43
|
+
}, []);
|
|
44
|
+
const scrollToBottom = useCallback((behavior = "smooth") => {
|
|
45
|
+
const el = containerRef.current;
|
|
46
|
+
if (!el)
|
|
47
|
+
return;
|
|
48
|
+
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
49
|
+
}, []);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const el = containerRef.current;
|
|
52
|
+
if (!el)
|
|
53
|
+
return;
|
|
54
|
+
el.addEventListener("scroll", handleScroll, { passive: true });
|
|
55
|
+
return () => el.removeEventListener("scroll", handleScroll);
|
|
56
|
+
}, [handleScroll]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const el = containerRef.current;
|
|
59
|
+
if (!el)
|
|
60
|
+
return;
|
|
61
|
+
scrollToBottom("instant");
|
|
62
|
+
setShowScrollButton(!isScrolledToBottom(el));
|
|
63
|
+
}, [scrollToBottom]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const el = containerRef.current;
|
|
66
|
+
if (!el)
|
|
67
|
+
return;
|
|
68
|
+
if (thinking) {
|
|
69
|
+
scrollToBottom("smooth");
|
|
70
|
+
}
|
|
71
|
+
}, [thinking, scrollToBottom]);
|
|
72
|
+
const [topMessages, lastMessages] = useMemo(() => {
|
|
73
|
+
if (messages.length <= 2)
|
|
74
|
+
return [messages, []];
|
|
75
|
+
const lastUserMessageIndex = messages.findLastIndex(isUserMessage);
|
|
76
|
+
return [
|
|
77
|
+
messages.slice(0, lastUserMessageIndex),
|
|
78
|
+
messages.slice(lastUserMessageIndex),
|
|
79
|
+
];
|
|
80
|
+
}, [messages]);
|
|
81
|
+
return (_jsxs("div", { ref: containerRef, className: classNames(styles.root, className), role: "log", "aria-live": "polite", "aria-label": "Chat messages",
|
|
82
|
+
// biome-ignore lint/a11y/noNoninteractiveTabindex: scrollable region must be keyboard-focusable (WCAG 2.1.1)
|
|
83
|
+
tabIndex: 0, ...rest, children: [initialLoading ? (_jsx(Skeleton, { rows: 5 })) : (_jsxs(_Fragment, { children: [topMessages.map((msg, i) => (_jsx(ChatMessage, { message: msg }, msg.messageId ?? `${i}-${msg.role}`))), lastMessages.length > 0 && (_jsxs("div", { className: styles.lastMessageWrapper, children: [lastMessages.map((msg, i) => (_jsx(ChatMessage, { message: msg }, msg.messageId ?? `${i}-${msg.role}`))), thinking && _jsx(AssistantLoader, {})] }))] })), showScrollButton && (_jsx("button", { type: "button", className: classNames(styles.scrollToBottom), onClick: () => scrollToBottom("smooth"), "aria-label": "Scroll to bottom", children: _jsx(KeyboardArrowDown, { size: "small" }) }))] }));
|
|
84
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import styleInject from 'style-inject';
|
|
2
|
+
import json from './Chat.module.css.json';
|
|
3
|
+
styleInject(`
|
|
4
|
+
/* CSS Custom Properties - All defined on .root with --reltio-chat- prefix */
|
|
5
|
+
._root_d5cr4_1 {
|
|
6
|
+
--reltio-chat-padding: 16px;
|
|
7
|
+
--reltio-chat-message-gap: 16px;
|
|
8
|
+
--reltio-chat-scroll-button-size: 36px;
|
|
9
|
+
--reltio-chat-scroll-button-bg: #ffffff;
|
|
10
|
+
--reltio-chat-scroll-button-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
11
|
+
--reltio-chat-scroll-button-color: #5f6368;
|
|
12
|
+
--reltio-chat-scroll-button-hover-bg: #f1f3f4;
|
|
13
|
+
--reltio-chat-scroll-button-bottom: 16px;
|
|
14
|
+
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
position: relative;
|
|
18
|
+
height: 100%;
|
|
19
|
+
width: 100%;
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
overflow: auto;
|
|
22
|
+
align-items: start;
|
|
23
|
+
padding: var(--reltio-chat-padding);
|
|
24
|
+
gap: var(--reltio-chat-message-gap);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
._userMessage_d5cr4_24 {
|
|
28
|
+
margin-left: auto;
|
|
29
|
+
max-width: 80%;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
._userMessageSkeletonWrapper_d5cr4_29 {
|
|
33
|
+
width: 40%;
|
|
34
|
+
margin-left: auto;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
._scrollToBottom_d5cr4_34 {
|
|
38
|
+
position: sticky;
|
|
39
|
+
bottom: var(--reltio-chat-scroll-button-bottom, 16px);
|
|
40
|
+
align-self: center;
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
width: var(--reltio-chat-scroll-button-size, 36px);
|
|
45
|
+
height: var(--reltio-chat-scroll-button-size, 36px);
|
|
46
|
+
border-radius: 50%;
|
|
47
|
+
border: none;
|
|
48
|
+
background: var(--reltio-chat-scroll-button-bg, #ffffff);
|
|
49
|
+
box-shadow: var(
|
|
50
|
+
--reltio-chat-scroll-button-shadow,
|
|
51
|
+
0 2px 8px rgba(0, 0, 0, 0.15)
|
|
52
|
+
);
|
|
53
|
+
color: var(--reltio-chat-scroll-button-color, #5f6368);
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
transition: background 0.15s ease;
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
._scrollToBottom_d5cr4_34:hover {
|
|
60
|
+
background: var(--reltio-chat-scroll-button-hover-bg);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
._scrollToBottom_d5cr4_34:focus-visible {
|
|
64
|
+
outline: 2px solid #1a73e8;
|
|
65
|
+
outline-offset: 2px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
._lastMessageWrapper_d5cr4_65 {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
position: relative;
|
|
72
|
+
align-items: start;
|
|
73
|
+
gap: var(--reltio-chat-message-gap);
|
|
74
|
+
min-height: 100%;
|
|
75
|
+
width: 100%;
|
|
76
|
+
}
|
|
77
|
+
`);
|
|
78
|
+
export default json;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "root": "_root_d5cr4_1", "userMessage": "_userMessage_d5cr4_24", "userMessageSkeletonWrapper": "_userMessageSkeletonWrapper_d5cr4_29", "scrollToBottom": "_scrollToBottom_d5cr4_34", "lastMessageWrapper": "_lastMessageWrapper_d5cr4_65" }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* User message payload for Chat. Renders via UserMessage component.
|
|
4
|
+
*/
|
|
5
|
+
export type UserChatMessage = {
|
|
6
|
+
type: "user";
|
|
7
|
+
content?: string | null;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Assistant message payload for Chat. Renders via AssistantMessage component.
|
|
11
|
+
*/
|
|
12
|
+
export type AssistantChatMessage = {
|
|
13
|
+
type: "assistant";
|
|
14
|
+
content?: string | null;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Union of known chat message types. Extensible: add new variants (e.g. system, tool)
|
|
18
|
+
* by extending this type and the message renderer in Chat.tsx.
|
|
19
|
+
*/
|
|
20
|
+
export type ChatMessage = UserChatMessage | AssistantChatMessage;
|
|
21
|
+
/**
|
|
22
|
+
* Message received from the API.
|
|
23
|
+
*/
|
|
24
|
+
export type Message = {
|
|
25
|
+
messageId?: string;
|
|
26
|
+
role: "user" | "assistant" | "system";
|
|
27
|
+
content: string;
|
|
28
|
+
timestamp?: Date;
|
|
29
|
+
createdAt?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Props for the Chat component
|
|
33
|
+
*/
|
|
34
|
+
export type ChatProps = {
|
|
35
|
+
/**
|
|
36
|
+
* List of messages to display in order. Each message is rendered by type (user → UserMessage, assistant → AssistantMessage).
|
|
37
|
+
*/
|
|
38
|
+
messages: Message[];
|
|
39
|
+
/**
|
|
40
|
+
* When true, shows the AssistantLoader below the message list to indicate the assistant is generating a response.
|
|
41
|
+
* Fully controlled from outside — no internal logic derives this state.
|
|
42
|
+
* @default false
|
|
43
|
+
*/
|
|
44
|
+
thinking?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* When true, chat data is initially loading. The Skeleton component is shown in place of the message list until data is available.
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
initialLoading?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Additional CSS class names
|
|
52
|
+
*/
|
|
53
|
+
className?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Inline styles (e.g. for CSS variable overrides)
|
|
56
|
+
*/
|
|
57
|
+
style?: React.CSSProperties;
|
|
58
|
+
} & Omit<React.ComponentPropsWithoutRef<"div">, "children" | "className" | "style">;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import type { AssistantMessageProps } from "./AssistantMessage.types";
|
|
3
|
+
/**
|
|
4
|
+
* Displays assistant-authored message content with Markdown and MDX support via the Markdown component.
|
|
5
|
+
* When error is true, shows ErrorMessage and hides content.
|
|
6
|
+
*/
|
|
7
|
+
export declare const AssistantMessage: ({ children, errorMessage, className, style, ...rest }: React.PropsWithChildren<AssistantMessageProps>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ErrorMessage } from "../../../../components/ErrorMessage";
|
|
3
|
+
import { Markdown } from "../../../../components/Markdown";
|
|
4
|
+
import { classNames } from "../../../../utils/classNames";
|
|
5
|
+
import styles from "./AssistantMessage.module.css";
|
|
6
|
+
const normalizeError = (errorMessage) => {
|
|
7
|
+
if (errorMessage == null) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
if (typeof errorMessage === "string") {
|
|
11
|
+
const trimmed = errorMessage.trim();
|
|
12
|
+
return trimmed ? _jsx(ErrorMessage, { children: trimmed }) : null;
|
|
13
|
+
}
|
|
14
|
+
return errorMessage;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Displays assistant-authored message content with Markdown and MDX support via the Markdown component.
|
|
18
|
+
* When error is true, shows ErrorMessage and hides content.
|
|
19
|
+
*/
|
|
20
|
+
export const AssistantMessage = ({ children, errorMessage, className, style, ...rest }) => {
|
|
21
|
+
const errorNode = normalizeError(errorMessage);
|
|
22
|
+
const content = children.trim();
|
|
23
|
+
return (_jsxs("div", { className: classNames(styles.assistantMessageRoot, className), style: style, ...rest, children: [errorNode && errorNode, !errorNode && content && _jsx(Markdown, { children: content })] }));
|
|
24
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import styleInject from 'style-inject';
|
|
2
|
+
import json from './AssistantMessage.module.css.json';
|
|
3
|
+
styleInject(`
|
|
4
|
+
/* CSS Custom Properties - All defined on .root with --reltio-assistant-message- prefix */
|
|
5
|
+
._assistantMessageRoot_qtch8_2 {
|
|
6
|
+
--reltio-assistant-message-background: transparent;
|
|
7
|
+
--reltio-assistant-message-padding: 0;
|
|
8
|
+
--reltio-assistant-message-border-radius: 8px;
|
|
9
|
+
--reltio-assistant-message-content-color: #0e0e25;
|
|
10
|
+
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
background-color: var(--reltio-assistant-message-background);
|
|
14
|
+
padding: var(--reltio-assistant-message-padding);
|
|
15
|
+
border-radius: var(--reltio-assistant-message-border-radius);
|
|
16
|
+
box-sizing: border-box;
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
._content_qtch8_17 {
|
|
21
|
+
flex: 1;
|
|
22
|
+
min-width: 0;
|
|
23
|
+
color: var(--reltio-assistant-message-content-color);
|
|
24
|
+
}
|
|
25
|
+
`);
|
|
26
|
+
export default json;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "assistantMessageRoot": "_assistantMessageRoot_qtch8_2", "content": "_content_qtch8_17" }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props for the AssistantMessage component
|
|
4
|
+
*/
|
|
5
|
+
export type AssistantMessageProps = {
|
|
6
|
+
/**
|
|
7
|
+
* Error content: string is passed to ErrorMessage; custom ReactNode is rendered as is.
|
|
8
|
+
*/
|
|
9
|
+
errorMessage?: React.ReactNode | null;
|
|
10
|
+
/**
|
|
11
|
+
* Additional CSS class names
|
|
12
|
+
*/
|
|
13
|
+
className?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Inline styles (e.g. for CSS variable overrides)
|
|
16
|
+
*/
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
/** We expect assistant message source as a string */
|
|
19
|
+
children: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./AssistantMessage";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { UserMessageProps } from "./UserMessage.types";
|
|
2
|
+
/**
|
|
3
|
+
* Displays user-authored message content with Markdown support via Markdown component.
|
|
4
|
+
* Empty or null content renders an empty container; invalid Markdown is handled by Markdown component.
|
|
5
|
+
*/
|
|
6
|
+
export declare const UserMessage: ({ children, className, style, ...rest }: UserMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Markdown } from "../../../../components/Markdown";
|
|
3
|
+
import { classNames } from "../../../../utils/classNames";
|
|
4
|
+
import styles from "./UserMessage.module.css";
|
|
5
|
+
/**
|
|
6
|
+
* Displays user-authored message content with Markdown support via Markdown component.
|
|
7
|
+
* Empty or null content renders an empty container; invalid Markdown is handled by Markdown component.
|
|
8
|
+
*/
|
|
9
|
+
export const UserMessage = ({ children, className, style, ...rest }) => {
|
|
10
|
+
const hasContent = children != null && String(children).trim() !== "";
|
|
11
|
+
return (_jsx("div", { className: classNames(styles.userMessageRoot, className), style: style, ...rest, children: hasContent && _jsx(Markdown, { children: children }) }));
|
|
12
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import styleInject from 'style-inject';
|
|
2
|
+
import json from './UserMessage.module.css.json';
|
|
3
|
+
styleInject(`
|
|
4
|
+
._userMessageRoot_11l9d_1 {
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
background-color: var(--reltio-user-message-background, #f5f5fa);
|
|
7
|
+
padding: var(--reltio-user-message-padding, 12px 16px);
|
|
8
|
+
border-radius: var(--reltio-user-message-border-radius, 12px);
|
|
9
|
+
}
|
|
10
|
+
`);
|
|
11
|
+
export default json;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "userMessageRoot": "_userMessageRoot_11l9d_1" }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props for the UserMessage component
|
|
4
|
+
*/
|
|
5
|
+
export type UserMessageProps = {
|
|
6
|
+
/**
|
|
7
|
+
* Additional CSS class names
|
|
8
|
+
*/
|
|
9
|
+
className?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Inline styles (e.g. for CSS variable overrides)
|
|
12
|
+
*/
|
|
13
|
+
style?: React.CSSProperties;
|
|
14
|
+
/** We expect user message source as a string */
|
|
15
|
+
children: string;
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./UserMessage";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Chat";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DetailsProps } from "./Details.types";
|
|
2
|
+
/**
|
|
3
|
+
* Enhanced details component for rendering collapsible content blocks
|
|
4
|
+
* with improved visual design, accessibility, and consistent styling
|
|
5
|
+
* aligned with the design system.
|
|
6
|
+
*/
|
|
7
|
+
export declare const Details: ({ open: initialOpen, children, className, style, ...rest }: DetailsProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect, useState } from "react";
|
|
3
|
+
import { CodeBrackets } from "../../icons/CodeBrackets";
|
|
4
|
+
import { ExpandLess } from "../../icons/ExpandLess";
|
|
5
|
+
import { ExpandMore } from "../../icons/ExpandMore";
|
|
6
|
+
import { classNames } from "../../utils/classNames";
|
|
7
|
+
import styles from "./Details.module.css";
|
|
8
|
+
/**
|
|
9
|
+
* Enhanced details component for rendering collapsible content blocks
|
|
10
|
+
* with improved visual design, accessibility, and consistent styling
|
|
11
|
+
* aligned with the design system.
|
|
12
|
+
*/
|
|
13
|
+
export const Details = ({ open: initialOpen = false, children, className, style, ...rest }) => {
|
|
14
|
+
const [isOpen, setIsOpen] = useState(initialOpen);
|
|
15
|
+
// Update internal state when open prop changes
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
setIsOpen(initialOpen);
|
|
18
|
+
}, [initialOpen]);
|
|
19
|
+
// Extract summary from children
|
|
20
|
+
let summary = "Details";
|
|
21
|
+
const contentChildren = [];
|
|
22
|
+
React.Children.forEach(children, (child) => {
|
|
23
|
+
if (React.isValidElement(child) &&
|
|
24
|
+
typeof child.type === "string" &&
|
|
25
|
+
child.type === "summary") {
|
|
26
|
+
summary = child.props.children;
|
|
27
|
+
}
|
|
28
|
+
else if (child != null) {
|
|
29
|
+
contentChildren.push(child);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
// Handle toggle
|
|
33
|
+
const handleToggle = (event) => {
|
|
34
|
+
const detailsElement = event.currentTarget;
|
|
35
|
+
setIsOpen(detailsElement.open);
|
|
36
|
+
};
|
|
37
|
+
// Compose className using classNames utility
|
|
38
|
+
const composedClassName = classNames(styles.root, className);
|
|
39
|
+
return (_jsxs("details", { className: composedClassName, style: style, onToggle: handleToggle, open: initialOpen, ...rest, children: [_jsxs("summary", { className: styles.summary, children: [_jsx("span", { className: styles.icon, "aria-hidden": "true", children: _jsx(CodeBrackets, { size: "small" }) }), _jsx("span", { className: styles.summaryText, children: summary }), _jsx("span", { className: classNames(styles.chevron, isOpen && styles.chevronOpen), children: isOpen ? (_jsx(ExpandLess, { size: "small", "aria-hidden": "true" })) : (_jsx(ExpandMore, { size: "small", "aria-hidden": "true" })) })] }), _jsx("div", { className: styles.content, children: contentChildren })] }));
|
|
40
|
+
};
|