@sybilion/uilib 1.3.73 → 1.3.75
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/esm/components/ui/AppHeader/AppHeader.js +2 -2
- package/dist/esm/components/ui/AppHeader/AppHeader.styl.js +2 -2
- package/dist/esm/components/ui/Chat/ChatChrome/ChatChrome.js +2 -2
- package/dist/esm/components/ui/Chat/ChatSheet/useChatPanelChromeModel.js +11 -3
- package/dist/esm/components/ui/Chat/buildChatSendMessagePayload.js +5 -1
- package/dist/esm/components/ui/Page/AppShell/AppShell.js +1 -1
- package/dist/esm/components/widgets/SybilionAppHeader/SybilionAppHeader.styl.js +1 -1
- package/dist/esm/contexts/chat-context.js +1 -1
- package/dist/esm/types/src/components/ui/AppHeader/AppHeader.d.ts +7 -1
- package/dist/esm/types/src/components/ui/Chat/Chat.types.d.ts +4 -0
- package/dist/esm/types/src/components/ui/Chat/ChatChrome/ChatChrome.d.ts +1 -1
- package/dist/esm/types/src/components/ui/Chat/ChatChrome/ChatChrome.types.d.ts +2 -0
- package/dist/esm/types/src/components/ui/Chat/buildChatSendMessagePayload.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/ui/AppHeader/AppHeader.styl +10 -1
- package/src/components/ui/AppHeader/AppHeader.styl.d.ts +1 -0
- package/src/components/ui/AppHeader/AppHeader.tsx +13 -1
- package/src/components/ui/Chat/Chat.types.ts +4 -0
- package/src/components/ui/Chat/ChatChrome/ChatChrome.tsx +3 -2
- package/src/components/ui/Chat/ChatChrome/ChatChrome.types.ts +2 -0
- package/src/components/ui/Chat/ChatSheet/useChatPanelChromeModel.tsx +12 -2
- package/src/components/ui/Chat/buildChatSendMessagePayload.ts +7 -0
- package/src/components/ui/Page/AppShell/AppShell.tsx +8 -1
- package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.styl +15 -3
- package/src/contexts/chat-context.tsx +1 -1
- package/src/docs/DocsShell.tsx +14 -2
- package/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.styl +3 -0
- package/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.tsx +54 -54
- package/src/docs/registry.ts +0 -6
|
@@ -5,8 +5,8 @@ import { createPortal } from 'react-dom';
|
|
|
5
5
|
import S from './AppHeader.styl.js';
|
|
6
6
|
import { PAGE_HEADER_ID } from './appChromeAnchors.js';
|
|
7
7
|
|
|
8
|
-
function AppHeaderHost({ className, anchorId = PAGE_HEADER_ID, }) {
|
|
9
|
-
return jsx("header", { className: cn(S.root, className), id: anchorId });
|
|
8
|
+
function AppHeaderHost({ className, anchorId = PAGE_HEADER_ID, sticky, }) {
|
|
9
|
+
return (jsx("header", { className: cn(S.root, sticky && S.sticky, className), id: anchorId }));
|
|
10
10
|
}
|
|
11
11
|
function AppHeaderPortal({ children, pageHeaderId = PAGE_HEADER_ID, }) {
|
|
12
12
|
const [container, setContainer] = useState(null);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
2
|
|
|
3
|
-
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.AppHeader_root__SdbDv{align-items:center;align-self:flex-end;background-color:var(--color-background);display:flex;max-width:calc(100vw - var(--sidebar-width) - var(--p-
|
|
4
|
-
var S = {"root":"AppHeader_root__SdbDv","content":"AppHeader_content__kyxem","logo":"AppHeader_logo__v31FX","nav":"AppHeader_nav__ahN1p","navLink":"AppHeader_navLink__z43jY","actions":"AppHeader_actions__QuxEF","pageHeaderActionsAnchor":"AppHeader_pageHeaderActionsAnchor__qzQMs"};
|
|
3
|
+
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.AppHeader_root__SdbDv{align-items:center;align-self:flex-end;background-color:var(--color-background);display:flex;max-width:calc(100vw - var(--sidebar-width) - var(--p-2));min-height:var(--header-height);padding-right:var(--p-2);position:relative;width:100%}@media (max-width:768px){.AppHeader_root__SdbDv{max-width:100%;padding-left:200px}}@media (min-width:768px){[data-slot=sidebar-wrapper][data-state=collapsed] .AppHeader_root__SdbDv{max-width:100%;padding-left:200px}}.AppHeader_sticky__qFWuq{backdrop-filter:blur(10px);background-color:color-mix(in srgb,var(--background) 80%,transparent);box-shadow:inset 0 40px 50px 20px var(--background);position:sticky;top:0;z-index:100}.AppHeader_content__kyxem{align-items:center;display:flex;gap:2rem;justify-content:flex-end;padding:0 var(--p-9);width:100%}.AppHeader_logo__v31FX{align-items:center;color:var(--color-foreground);display:flex;font-size:1.5rem;font-weight:400;gap:.5rem;text-decoration:none;white-space:nowrap}.AppHeader_logo__v31FX svg{display:inline-flex;height:32px;transition:transform .1s ease-in-out;width:auto}.AppHeader_logo__v31FX:hover svg{transform:scale(1.05)}.AppHeader_nav__ahN1p{align-items:center;display:flex;flex:1;gap:1.5rem;justify-content:center}@media (max-width:units(768px,\"px\")){.AppHeader_nav__ahN1p{display:none}}.AppHeader_navLink__z43jY{color:var(--color-muted-foreground);font-size:.875rem;font-weight:400;text-decoration:none;transition:color .2s ease}.AppHeader_navLink__z43jY:hover{color:var(--color-foreground)}.AppHeader_actions__QuxEF{align-items:center;display:flex;gap:var(--p-4);margin-right:var(--p-2)}@media (max-width:units(768px,\"px\")){.AppHeader_actions__QuxEF{gap:var(--p-1)}}.AppHeader_pageHeaderActionsAnchor__qzQMs{align-items:center;display:flex;flex-shrink:0;gap:var(--p-4)}";
|
|
4
|
+
var S = {"root":"AppHeader_root__SdbDv","sticky":"AppHeader_sticky__qFWuq","content":"AppHeader_content__kyxem","logo":"AppHeader_logo__v31FX","nav":"AppHeader_nav__ahN1p","navLink":"AppHeader_navLink__z43jY","actions":"AppHeader_actions__QuxEF","pageHeaderActionsAnchor":"AppHeader_pageHeaderActionsAnchor__qzQMs"};
|
|
5
5
|
styleInject(css_248z);
|
|
6
6
|
|
|
7
7
|
export { S as default };
|
|
@@ -14,7 +14,7 @@ import { filterToTextAttachments, isAttachmentsDropzoneEnabled, buildAcceptAttr
|
|
|
14
14
|
import { extractChatAttachmentItems } from '../chatAttachmentExtract.js';
|
|
15
15
|
import S from './ChatChrome.styl.js';
|
|
16
16
|
|
|
17
|
-
function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, scriptContinueLabel, onScriptContinue, renderMessageChart, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, emptyState, allowedAttachments, allowPdfAttachments = false, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, }) {
|
|
17
|
+
function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, loadingLabel, scriptContinueLabel, onScriptContinue, renderMessageChart, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, emptyState, allowedAttachments, allowPdfAttachments = false, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, }) {
|
|
18
18
|
const filteredAllowedAttachments = useMemo(() => filterToTextAttachments(allowedAttachments), [allowedAttachments]);
|
|
19
19
|
const attachmentsDropzoneEnabled = isAttachmentsDropzoneEnabled(allowedAttachments, allowPdfAttachments);
|
|
20
20
|
const attachmentAccept = useMemo(() => buildAcceptAttr(filteredAllowedAttachments, allowPdfAttachments), [filteredAllowedAttachments, allowPdfAttachments]);
|
|
@@ -77,7 +77,7 @@ function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPr
|
|
|
77
77
|
const label = displayLabelForBranchKeyFromMessages(key, messages) ??
|
|
78
78
|
humanizeBranchKey(key);
|
|
79
79
|
return (jsx("span", { className: S.branchBtnWrap, children: jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: isLoading, onClick: () => onQuickReply(key, label), children: [jsx(PaperPlaneRightIcon, {}), label] }) }, key));
|
|
80
|
-
}) })) : null, showInlinePresets && renderPresets('inline'), isLoading && isLastMessageFromUser && (jsx(TextShimmer, { duration: 1, spread: 5, className: S.loader, children:
|
|
80
|
+
}) })) : null, showInlinePresets && renderPresets('inline'), isLoading && (isLastMessageFromUser || loadingLabel) && (jsx(TextShimmer, { duration: 1, spread: 5, className: S.loader, children: loadingLabel ?? 'Thinking...' }))] }) })), jsxs("div", { className: cn(S.footer, footerClassName), children: [isEmpty ? (jsx("div", { className: S.notice, children: "Forecast Assistant can make mistakes." })) : null, jsx(Chat.Prompt, { onSubmit: handlePromptSubmitWithAttachments, disabled: promptDisabled, attachments: pendingAttachments, onRemoveAttachment: handleRemoveAttachment, prefillMessage: promptPrefill ?? undefined, placeholder: promptPlaceholder, slashCommandItems: slashCommandItems, onSlashItemCommand: onSlashItemCommand, attachmentAccept: attachmentsDropzoneEnabled ? attachmentAccept : undefined, onAttachmentFiles: attachmentsDropzoneEnabled ? handleAttachmentFiles : undefined })] })] })] })] }));
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
export { ChatChrome };
|
|
@@ -2,7 +2,7 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
|
3
3
|
import { MessageRole } from '../Chat.types.js';
|
|
4
4
|
import { isGraphIntakeAssistantStepComplete, matchUserTextToQuickReply, isPresetScriptGraph, branchesFromPresetScriptGraph, parseScriptLine, textHasQuickReplyMarkers, branchKeysUsedFromChatHistory, branchKeysUsedByUserMessages, extractQuickReplyLabelKeyPairsFromText, entryBranchKeyBeforeLastAssistant } from '../ChatMessage/presetScript.js';
|
|
5
|
-
import { displayTextFromSendPayload, buildChatSendMessagePayload } from '../buildChatSendMessagePayload.js';
|
|
5
|
+
import { displayTextFromSendPayload, buildChatSendMessagePayload, loadingLabelFromSendPayload } from '../buildChatSendMessagePayload.js';
|
|
6
6
|
import { usedPresetIdsFromMessages } from '../chat-preset-utils.js';
|
|
7
7
|
import { useChatsForScopeId, useChat, useChatOutboundPending, useSyncChatPanelBusy, isChatEmpty } from '../../../../contexts/chat-context.js';
|
|
8
8
|
import { shellFitsSidebarsLayout } from '../../../../hooks/panelWidth.js';
|
|
@@ -27,6 +27,7 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
|
|
|
27
27
|
const isMobile = useIsMobile();
|
|
28
28
|
const { chatPanelContainer, isOpen: sidebarNavOpen, setOpen: setSidebarNavOpen, sidebarWidthPx, chatWidthPx, setChatWidthPx, getShellWidth, chatPanelOpen: shellChatPanelOpen, setChatPanelOpen, } = useSidebar();
|
|
29
29
|
const [localUiBusy, setLocalUiBusy] = useState(false);
|
|
30
|
+
const [outboundLoadingLabel, setOutboundLoadingLabel] = useState();
|
|
30
31
|
const { chats, currentChatId, setCurrentChatId, newChat, sendMessage, addMessage, removeMessageById, } = useChatsForScopeId(effectiveScopeId);
|
|
31
32
|
const chat = useChat(effectiveScopeId, currentChatId);
|
|
32
33
|
const isOutboundPending = useChatOutboundPending(effectiveScopeId, currentChatId);
|
|
@@ -464,8 +465,14 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
|
|
|
464
465
|
if (transformSendPayload) {
|
|
465
466
|
payload = await transformSendPayload(message, stagedAttachments, payload);
|
|
466
467
|
}
|
|
467
|
-
|
|
468
|
-
|
|
468
|
+
setOutboundLoadingLabel(loadingLabelFromSendPayload(payload));
|
|
469
|
+
try {
|
|
470
|
+
const assistantResponse = await sendMessage(payload);
|
|
471
|
+
onMessage?.(displayTextFromSendPayload(payload), assistantResponse);
|
|
472
|
+
}
|
|
473
|
+
finally {
|
|
474
|
+
setOutboundLoadingLabel(undefined);
|
|
475
|
+
}
|
|
469
476
|
}
|
|
470
477
|
catch (error) {
|
|
471
478
|
logger.error('Error sending chat message:', error);
|
|
@@ -895,6 +902,7 @@ function useChatPanelChromeModel({ embedAsPage, presets, scopeId, onMessage, onS
|
|
|
895
902
|
onQuickReply,
|
|
896
903
|
suppressedQuickReplyKeys,
|
|
897
904
|
isLoading,
|
|
905
|
+
loadingLabel: outboundLoadingLabel,
|
|
898
906
|
scriptContinueLabel,
|
|
899
907
|
onScriptContinue,
|
|
900
908
|
renderMessageChart,
|
|
@@ -66,5 +66,9 @@ function buildChatSendMessagePayload(displayText, attachments) {
|
|
|
66
66
|
function displayTextFromSendPayload(message) {
|
|
67
67
|
return typeof message === 'string' ? message : message.displayText;
|
|
68
68
|
}
|
|
69
|
+
/** Optional loading shimmer label from a structured send payload. */
|
|
70
|
+
function loadingLabelFromSendPayload(message) {
|
|
71
|
+
return typeof message === 'string' ? undefined : message.loadingLabel;
|
|
72
|
+
}
|
|
69
73
|
|
|
70
|
-
export { buildChatSendMessagePayload, displayTextFromSendPayload, normalizeUserTextFileAttachments };
|
|
74
|
+
export { buildChatSendMessagePayload, displayTextFromSendPayload, loadingLabelFromSendPayload, normalizeUserTextFileAttachments };
|
|
@@ -8,7 +8,7 @@ function AppShellMainContent({ className, bodyClassName, children, header, foote
|
|
|
8
8
|
return (jsxs("div", { className: cn(S.mainColumn, className), children: [header, jsx("div", { className: cn(S.mainBody, bodyClassName), children: children }), footer] }));
|
|
9
9
|
}
|
|
10
10
|
const AppShell = forwardRef(function AppShell({ className, ...props }, ref) {
|
|
11
|
-
return jsx("div", { ref: ref, className: cn(S.root, className), ...props });
|
|
11
|
+
return (jsx("div", { ref: ref, "data-slot": "app-shell", className: cn(S.root, className), ...props }));
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
export { AppShell, AppShellMainContent };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
2
|
|
|
3
|
-
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.SybilionAppHeader_actionsAnchor__ress2,.SybilionAppHeader_pageActionsPortal__9C5ww{align-items:center;display:flex;flex-shrink:0;gap:var(--p-4)}.SybilionAppHeader_pageActionsPortal__9C5ww:empty{display:none}.SybilionAppHeader_logoArea__3HAhG{align-items:center;display:flex;gap:var(--p-2);left:40px;position:absolute;top:22px;z-index:10}@media (max-width:768px){.SybilionAppHeader_logoArea__3HAhG{left:32px}}@media (min-width:768px){[data-slot=sidebar-wrapper][data-state=expanded] .SybilionAppHeader_logoArea__3HAhG{position:
|
|
3
|
+
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.SybilionAppHeader_actionsAnchor__ress2,.SybilionAppHeader_pageActionsPortal__9C5ww{align-items:center;display:flex;flex-shrink:0;gap:var(--p-4)}.SybilionAppHeader_pageActionsPortal__9C5ww:empty{display:none}.SybilionAppHeader_logoArea__3HAhG{align-items:center;display:flex;gap:var(--p-2);left:40px;position:absolute;top:22px;z-index:10}@media (max-width:768px){.SybilionAppHeader_logoArea__3HAhG{left:32px}}@media (min-width:768px){[data-slot=sidebar-wrapper][data-state=expanded]:not([data-slot=app-shell] [data-slot=sidebar-wrapper]) [data-slot=app-shell]:not([data-slot=app-shell] [data-slot=app-shell]) .SybilionAppHeader_logoArea__3HAhG:not([data-slot=app-shell] [data-slot=app-shell] *){left:calc(var(--sidebar-width)*-1 + 52px);position:absolute}[data-slot=app-shell] [data-slot=sidebar-wrapper][data-state=expanded] [data-slot=app-shell] .SybilionAppHeader_logoArea__3HAhG{left:calc(var(--sidebar-width)*-1 + 44px);position:absolute}[data-slot=app-shell] [data-slot=sidebar-wrapper][data-state=collapsed] [data-slot=app-shell] .SybilionAppHeader_logoArea__3HAhG{left:var(--p-8);position:absolute}}.SybilionAppHeader_logoAreaWithBanner__7Iy78{top:22px;top:calc(22px + var(--welcome-banner-height, 0px))}@media (min-width:768px){[data-slot=sidebar-wrapper][data-state=collapsed]:not([data-slot=app-shell] [data-slot=sidebar-wrapper]) [data-slot=app-shell]:not([data-slot=app-shell] [data-slot=app-shell]) .SybilionAppHeader_logoAreaWithBanner__7Iy78{top:22px}}.SybilionAppHeader_logoLink__bH-KX{align-items:center;color:var(--color-foreground);display:flex;font-size:1.5rem;font-weight:400;gap:.5rem;text-decoration:none;white-space:nowrap;width:-moz-fit-content;width:fit-content}.SybilionAppHeader_logoLink__bH-KX svg{display:inline-flex;flex-shrink:0;height:32px;transition:transform .1s ease-in-out;width:auto}.SybilionAppHeader_logoLink__bH-KX:hover svg{transform:scale(1.05)}";
|
|
4
4
|
var S = {"actionsAnchor":"SybilionAppHeader_actionsAnchor__ress2","pageActionsPortal":"SybilionAppHeader_pageActionsPortal__9C5ww","logoArea":"SybilionAppHeader_logoArea__3HAhG","logoAreaWithBanner":"SybilionAppHeader_logoAreaWithBanner__7Iy78","logoLink":"SybilionAppHeader_logoLink__bH-KX"};
|
|
5
5
|
styleInject(css_248z);
|
|
6
6
|
|
|
@@ -312,7 +312,7 @@ function ChatProvider({ children, userSwitchKey, sendChatMessage: sendChatMessag
|
|
|
312
312
|
if (typeof message === 'string') {
|
|
313
313
|
addMessage(scopeId, targetChatId, MessageRole.USER, message);
|
|
314
314
|
}
|
|
315
|
-
else {
|
|
315
|
+
else if (!message.omitUserMessage) {
|
|
316
316
|
addMessage(scopeId, targetChatId, MessageRole.USER, message.displayText, {
|
|
317
317
|
userTextFileAttachments: normalizeUserTextFileAttachments(message),
|
|
318
318
|
});
|
|
@@ -3,8 +3,14 @@ export type AppHeaderProps = {
|
|
|
3
3
|
className?: string;
|
|
4
4
|
/** Override default anchor id when multiple headers exist (e.g. docs demos). */
|
|
5
5
|
anchorId?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Pins the host to the top of its scroll container (`position: sticky; top: 0`).
|
|
8
|
+
* Use with `PageScroll` or any ancestor that scrolls; portaled header content
|
|
9
|
+
* from `AppHeaderPortal` / `SybilionAppHeader` stays inside this element.
|
|
10
|
+
*/
|
|
11
|
+
sticky?: boolean;
|
|
6
12
|
};
|
|
7
|
-
export declare function AppHeaderHost({ className, anchorId, }: AppHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function AppHeaderHost({ className, anchorId, sticky, }: AppHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
8
14
|
export type AppHeaderPortalProps = {
|
|
9
15
|
children: ReactNode;
|
|
10
16
|
pageHeaderId?: string;
|
|
@@ -17,6 +17,10 @@ export type ChatSendMessagePayload = {
|
|
|
17
17
|
apiMessage: string;
|
|
18
18
|
displayText: string;
|
|
19
19
|
userTextFileAttachments?: UserTextFileAttachment[];
|
|
20
|
+
/** When true, skip adding a USER bubble before the API call (e.g. slash-command actions). */
|
|
21
|
+
omitUserMessage?: boolean;
|
|
22
|
+
/** Shimmer label while waiting on the API; defaults to "Thinking...". */
|
|
23
|
+
loadingLabel?: string;
|
|
20
24
|
};
|
|
21
25
|
export interface Message {
|
|
22
26
|
id: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ChatChromeProps } from './ChatChrome.types';
|
|
2
|
-
export declare function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, scriptContinueLabel, onScriptContinue, renderMessageChart, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, emptyState, allowedAttachments, allowPdfAttachments, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, }: ChatChromeProps): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare function ChatChrome({ showResizeHandle, resizeHandle, onClose, isEmpty, renderPresets, messages, onQuickReply, suppressedQuickReplyKeys, isLoading, loadingLabel, scriptContinueLabel, onScriptContinue, renderMessageChart, showSyntheticBranchButtons, unusedBranchKeys, showInlinePresets, isLastMessageFromUser, scrollRef, effectiveScopeId, onPromptSubmit, onChatDeleted, onNewChat, promptPrefill, footerClassName, emptyState, allowedAttachments, allowPdfAttachments, onAttachmentsDropped, slashCommandItems, onSlashItemCommand, promptPlaceholder, }: ChatChromeProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -23,6 +23,8 @@ export interface ChatChromeProps {
|
|
|
23
23
|
onQuickReply: (branchKey: string, displayLabel: string) => void;
|
|
24
24
|
suppressedQuickReplyKeys: ReadonlySet<string>;
|
|
25
25
|
isLoading: boolean;
|
|
26
|
+
/** Overrides default "Thinking..." shimmer while waiting on the API. */
|
|
27
|
+
loadingLabel?: string;
|
|
26
28
|
scriptContinueLabel: string | undefined;
|
|
27
29
|
onScriptContinue: (() => void) | undefined;
|
|
28
30
|
renderMessageChart?: () => React.ReactNode;
|
|
@@ -8,3 +8,5 @@ export declare function normalizeUserTextFileAttachments(payload: ChatSendMessag
|
|
|
8
8
|
export declare function buildChatSendMessagePayload(displayText: string, attachments: readonly ChatAttachmentDropItem[]): string | ChatSendMessagePayload;
|
|
9
9
|
/** Display text from a string or structured send payload. */
|
|
10
10
|
export declare function displayTextFromSendPayload(message: string | ChatSendMessagePayload): string;
|
|
11
|
+
/** Optional loading shimmer label from a structured send payload. */
|
|
12
|
+
export declare function loadingLabelFromSendPayload(message: string | ChatSendMessagePayload): string | undefined;
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
@import '../../../lib/theme.styl'
|
|
2
2
|
|
|
3
3
|
.root
|
|
4
|
+
position relative
|
|
4
5
|
display flex
|
|
5
6
|
align-items center
|
|
6
7
|
align-self flex-end
|
|
7
8
|
width 100%
|
|
8
|
-
max-width calc(100vw - var(--sidebar-width) - var(--p-
|
|
9
|
+
max-width calc(100vw - var(--sidebar-width) - var(--p-2))
|
|
9
10
|
min-height var(--header-height)
|
|
10
11
|
padding-right var(--p-2)
|
|
11
12
|
|
|
@@ -20,6 +21,14 @@
|
|
|
20
21
|
padding-left 200px
|
|
21
22
|
max-width 100%
|
|
22
23
|
|
|
24
|
+
.sticky
|
|
25
|
+
z-index 100
|
|
26
|
+
position sticky
|
|
27
|
+
top 0
|
|
28
|
+
background-color unquote('color-mix(in srgb, var(--background) 80%, transparent)')
|
|
29
|
+
backdrop-filter blur(10px)
|
|
30
|
+
box-shadow inset 0 40px 50px 20px var(--background)
|
|
31
|
+
|
|
23
32
|
.content
|
|
24
33
|
display flex
|
|
25
34
|
align-items center
|
|
@@ -9,13 +9,25 @@ export type AppHeaderProps = {
|
|
|
9
9
|
className?: string;
|
|
10
10
|
/** Override default anchor id when multiple headers exist (e.g. docs demos). */
|
|
11
11
|
anchorId?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Pins the host to the top of its scroll container (`position: sticky; top: 0`).
|
|
14
|
+
* Use with `PageScroll` or any ancestor that scrolls; portaled header content
|
|
15
|
+
* from `AppHeaderPortal` / `SybilionAppHeader` stays inside this element.
|
|
16
|
+
*/
|
|
17
|
+
sticky?: boolean;
|
|
12
18
|
};
|
|
13
19
|
|
|
14
20
|
export function AppHeaderHost({
|
|
15
21
|
className,
|
|
16
22
|
anchorId = PAGE_HEADER_ID,
|
|
23
|
+
sticky,
|
|
17
24
|
}: AppHeaderProps) {
|
|
18
|
-
return
|
|
25
|
+
return (
|
|
26
|
+
<header
|
|
27
|
+
className={cn(S.root, sticky && S.sticky, className)}
|
|
28
|
+
id={anchorId}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
export type AppHeaderPortalProps = {
|
|
@@ -25,6 +25,10 @@ export type ChatSendMessagePayload = {
|
|
|
25
25
|
apiMessage: string;
|
|
26
26
|
displayText: string;
|
|
27
27
|
userTextFileAttachments?: UserTextFileAttachment[];
|
|
28
|
+
/** When true, skip adding a USER bubble before the API call (e.g. slash-command actions). */
|
|
29
|
+
omitUserMessage?: boolean;
|
|
30
|
+
/** Shimmer label while waiting on the API; defaults to "Thinking...". */
|
|
31
|
+
loadingLabel?: string;
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
export interface Message {
|
|
@@ -34,6 +34,7 @@ export function ChatChrome({
|
|
|
34
34
|
onQuickReply,
|
|
35
35
|
suppressedQuickReplyKeys,
|
|
36
36
|
isLoading,
|
|
37
|
+
loadingLabel,
|
|
37
38
|
scriptContinueLabel,
|
|
38
39
|
onScriptContinue,
|
|
39
40
|
renderMessageChart,
|
|
@@ -248,9 +249,9 @@ export function ChatChrome({
|
|
|
248
249
|
|
|
249
250
|
{showInlinePresets && renderPresets('inline')}
|
|
250
251
|
|
|
251
|
-
{isLoading && isLastMessageFromUser && (
|
|
252
|
+
{isLoading && (isLastMessageFromUser || loadingLabel) && (
|
|
252
253
|
<TextShimmer duration={1} spread={5} className={S.loader}>
|
|
253
|
-
Thinking...
|
|
254
|
+
{loadingLabel ?? 'Thinking...'}
|
|
254
255
|
</TextShimmer>
|
|
255
256
|
)}
|
|
256
257
|
</Scroll>
|
|
@@ -33,6 +33,8 @@ export interface ChatChromeProps {
|
|
|
33
33
|
onQuickReply: (branchKey: string, displayLabel: string) => void;
|
|
34
34
|
suppressedQuickReplyKeys: ReadonlySet<string>;
|
|
35
35
|
isLoading: boolean;
|
|
36
|
+
/** Overrides default "Thinking..." shimmer while waiting on the API. */
|
|
37
|
+
loadingLabel?: string;
|
|
36
38
|
scriptContinueLabel: string | undefined;
|
|
37
39
|
onScriptContinue: (() => void) | undefined;
|
|
38
40
|
renderMessageChart?: () => React.ReactNode;
|
|
@@ -22,6 +22,7 @@ import type { ChatPresetsLayout } from '#uilib/components/ui/Chat/ChatPresets';
|
|
|
22
22
|
import {
|
|
23
23
|
buildChatSendMessagePayload,
|
|
24
24
|
displayTextFromSendPayload,
|
|
25
|
+
loadingLabelFromSendPayload,
|
|
25
26
|
} from '#uilib/components/ui/Chat/buildChatSendMessagePayload';
|
|
26
27
|
import { usedPresetIdsFromMessages } from '#uilib/components/ui/Chat/chat-preset-utils';
|
|
27
28
|
import {
|
|
@@ -166,6 +167,9 @@ export function useChatPanelChromeModel({
|
|
|
166
167
|
setChatPanelOpen,
|
|
167
168
|
} = useSidebar();
|
|
168
169
|
const [localUiBusy, setLocalUiBusy] = useState(false);
|
|
170
|
+
const [outboundLoadingLabel, setOutboundLoadingLabel] = useState<
|
|
171
|
+
string | undefined
|
|
172
|
+
>();
|
|
169
173
|
const {
|
|
170
174
|
chats,
|
|
171
175
|
currentChatId,
|
|
@@ -708,8 +712,13 @@ export function useChatPanelChromeModel({
|
|
|
708
712
|
payload,
|
|
709
713
|
);
|
|
710
714
|
}
|
|
711
|
-
|
|
712
|
-
|
|
715
|
+
setOutboundLoadingLabel(loadingLabelFromSendPayload(payload));
|
|
716
|
+
try {
|
|
717
|
+
const assistantResponse = await sendMessage(payload);
|
|
718
|
+
onMessage?.(displayTextFromSendPayload(payload), assistantResponse);
|
|
719
|
+
} finally {
|
|
720
|
+
setOutboundLoadingLabel(undefined);
|
|
721
|
+
}
|
|
713
722
|
} catch (error) {
|
|
714
723
|
logger.error('Error sending chat message:', error);
|
|
715
724
|
}
|
|
@@ -1222,6 +1231,7 @@ export function useChatPanelChromeModel({
|
|
|
1222
1231
|
onQuickReply,
|
|
1223
1232
|
suppressedQuickReplyKeys,
|
|
1224
1233
|
isLoading,
|
|
1234
|
+
loadingLabel: outboundLoadingLabel,
|
|
1225
1235
|
scriptContinueLabel,
|
|
1226
1236
|
onScriptContinue,
|
|
1227
1237
|
renderMessageChart,
|
|
@@ -80,3 +80,10 @@ export function displayTextFromSendPayload(
|
|
|
80
80
|
): string {
|
|
81
81
|
return typeof message === 'string' ? message : message.displayText;
|
|
82
82
|
}
|
|
83
|
+
|
|
84
|
+
/** Optional loading shimmer label from a structured send payload. */
|
|
85
|
+
export function loadingLabelFromSendPayload(
|
|
86
|
+
message: string | ChatSendMessagePayload,
|
|
87
|
+
): string | undefined {
|
|
88
|
+
return typeof message === 'string' ? undefined : message.loadingLabel;
|
|
89
|
+
}
|
|
@@ -33,6 +33,13 @@ export function AppShellMainContent({
|
|
|
33
33
|
|
|
34
34
|
export const AppShell = forwardRef<HTMLDivElement, AppShellProps>(
|
|
35
35
|
function AppShell({ className, ...props }, ref) {
|
|
36
|
-
return
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
ref={ref}
|
|
39
|
+
data-slot="app-shell"
|
|
40
|
+
className={cn(S.root, className)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
37
44
|
},
|
|
38
45
|
);
|
|
@@ -27,15 +27,27 @@
|
|
|
27
27
|
|
|
28
28
|
@media (max-width MOBILE)
|
|
29
29
|
left 32px
|
|
30
|
+
|
|
31
|
+
// Top-level shell: offset logo into sidebar column (same math as nested embed, but absolute — not fixed).
|
|
30
32
|
@media (min-width MOBILE)
|
|
31
|
-
:global([data-slot='sidebar-wrapper'][data-state='expanded'])
|
|
32
|
-
position
|
|
33
|
+
:global([data-slot='sidebar-wrapper'][data-state='expanded']:not([data-slot='app-shell'] [data-slot='sidebar-wrapper']) [data-slot='app-shell']:not([data-slot='app-shell'] [data-slot='app-shell'])) &:global(:not([data-slot='app-shell'] [data-slot='app-shell'] *))
|
|
34
|
+
position absolute
|
|
35
|
+
left calc(-1 * var(--sidebar-width) + 52px)
|
|
36
|
+
|
|
37
|
+
// Nested shell (e.g. docs embed): absolute within header; offset into sidebar when expanded.
|
|
38
|
+
:global([data-slot='app-shell'] [data-slot='sidebar-wrapper'][data-state='expanded'] [data-slot='app-shell']) &
|
|
39
|
+
position absolute
|
|
40
|
+
left calc(-1 * var(--sidebar-width) + 44px)
|
|
41
|
+
|
|
42
|
+
:global([data-slot='app-shell'] [data-slot='sidebar-wrapper'][data-state='collapsed'] [data-slot='app-shell']) &
|
|
43
|
+
position absolute
|
|
44
|
+
left var(--p-8)
|
|
33
45
|
|
|
34
46
|
.logoAreaWithBanner
|
|
35
47
|
top calc(22px + var(--welcome-banner-height, 0px))
|
|
36
48
|
|
|
37
49
|
@media (min-width MOBILE)
|
|
38
|
-
:global([data-slot='sidebar-wrapper'][data-state='collapsed']) &
|
|
50
|
+
:global([data-slot='sidebar-wrapper'][data-state='collapsed']:not([data-slot='app-shell'] [data-slot='sidebar-wrapper']) [data-slot='app-shell']:not([data-slot='app-shell'] [data-slot='app-shell'])) &
|
|
39
51
|
top 22px
|
|
40
52
|
|
|
41
53
|
.logoLink
|
package/src/docs/DocsShell.tsx
CHANGED
|
@@ -20,7 +20,7 @@ export function DocsShell() {
|
|
|
20
20
|
<DocsSidebar />
|
|
21
21
|
|
|
22
22
|
<AppShellMainContent
|
|
23
|
-
header={<AppHeaderHost />}
|
|
23
|
+
header={<AppHeaderHost sticky />}
|
|
24
24
|
footer={
|
|
25
25
|
<PageFooter versionLink="/releases" versionLabel="1.0.0-docs" />
|
|
26
26
|
}
|
|
@@ -30,10 +30,22 @@ export function DocsShell() {
|
|
|
30
30
|
onNavigate={href => {
|
|
31
31
|
void navigate(href);
|
|
32
32
|
}}
|
|
33
|
-
authenticated
|
|
33
|
+
authenticated
|
|
34
34
|
isAuthenticated={false}
|
|
35
35
|
onLogout={() => undefined}
|
|
36
36
|
signInSlot={<ThemeToggle />}
|
|
37
|
+
defaultApps={[
|
|
38
|
+
{
|
|
39
|
+
id: 'docs-home',
|
|
40
|
+
displayName: 'Home',
|
|
41
|
+
subtitle: 'Home',
|
|
42
|
+
iconKey: 'grid-four',
|
|
43
|
+
accent: '#0d9488',
|
|
44
|
+
accentMuted: 'rgba(13, 148, 136, 0.12)',
|
|
45
|
+
href: '/',
|
|
46
|
+
matchPathPrefixes: ['/'],
|
|
47
|
+
},
|
|
48
|
+
]}
|
|
37
49
|
/>
|
|
38
50
|
<Outlet />
|
|
39
51
|
</AppShellMainContent>
|
|
@@ -113,7 +113,7 @@ function DemoMainBody({ panel }: { panel: PreviewPanel }) {
|
|
|
113
113
|
</PageContentSection>
|
|
114
114
|
<PageContentSection title="Scroll test">
|
|
115
115
|
<div className={S.scrollTestBlock}>
|
|
116
|
-
Placeholder region with <code>min-height:
|
|
116
|
+
Placeholder region with <code>min-height: 160vh</code> — scroll the
|
|
117
117
|
main column to verify PageScroll / AppShell behavior.
|
|
118
118
|
</div>
|
|
119
119
|
</PageContentSection>
|
|
@@ -130,55 +130,60 @@ function StandaloneLayoutPreview() {
|
|
|
130
130
|
>();
|
|
131
131
|
|
|
132
132
|
return (
|
|
133
|
-
<div className={S.preview}>
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
<div className={S.preview} data-standalone-layout-preview>
|
|
134
|
+
<SidebarProvider
|
|
135
|
+
sidebarWidthStorageKey="uilib.docs.standaloneLayout.sidebarWidthPx"
|
|
136
|
+
persistSidebarWidthWithoutConsent
|
|
137
|
+
>
|
|
138
|
+
<PageScroll rootClassName={S.previewScrollRoot}>
|
|
139
|
+
<AppShell>
|
|
140
|
+
<DemoAppSidebar
|
|
141
|
+
panel={panel}
|
|
142
|
+
onSelectPanel={setPanel}
|
|
143
|
+
selectedDatasetId={selectedDatasetId}
|
|
144
|
+
onSelectDatasetId={setSelectedDatasetId}
|
|
145
|
+
/>
|
|
142
146
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
>
|
|
152
|
-
<SybilionAppHeader
|
|
153
|
-
pageHeaderId={TEST_HEADER_ID}
|
|
154
|
-
pathname={previewPath}
|
|
155
|
-
onNavigate={setPreviewPath}
|
|
156
|
-
authenticated
|
|
157
|
-
appsStorageKey={DOCS_WORKSPACE_APPS_LS_KEY}
|
|
158
|
-
defaultApps={DOCS_PREVIEW_APPS}
|
|
159
|
-
user={{
|
|
160
|
-
name: 'Example User',
|
|
161
|
-
email: 'user@example.com',
|
|
162
|
-
avatar: '',
|
|
163
|
-
}}
|
|
164
|
-
onLogout={() => undefined}
|
|
165
|
-
menuItems={
|
|
166
|
-
<>
|
|
167
|
-
<DropdownMenuItem>
|
|
168
|
-
<UserCircleIcon />
|
|
169
|
-
Account (preview)
|
|
170
|
-
</DropdownMenuItem>
|
|
171
|
-
<DropdownMenuItem>
|
|
172
|
-
<GearSixIcon />
|
|
173
|
-
Settings (preview)
|
|
174
|
-
</DropdownMenuItem>
|
|
175
|
-
</>
|
|
147
|
+
<AppShellMainContent
|
|
148
|
+
header={<AppHeaderHost sticky anchorId={TEST_HEADER_ID} />}
|
|
149
|
+
footer={
|
|
150
|
+
<PageFooter
|
|
151
|
+
versionLink="#standalone-layout-preview"
|
|
152
|
+
versionLabel="0.0.0-preview"
|
|
153
|
+
/>
|
|
176
154
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
155
|
+
>
|
|
156
|
+
<SybilionAppHeader
|
|
157
|
+
pageHeaderId={TEST_HEADER_ID}
|
|
158
|
+
pathname={previewPath}
|
|
159
|
+
onNavigate={setPreviewPath}
|
|
160
|
+
authenticated
|
|
161
|
+
appsStorageKey={DOCS_WORKSPACE_APPS_LS_KEY}
|
|
162
|
+
defaultApps={DOCS_PREVIEW_APPS}
|
|
163
|
+
user={{
|
|
164
|
+
name: 'Example User',
|
|
165
|
+
email: 'user@example.com',
|
|
166
|
+
avatar: '',
|
|
167
|
+
}}
|
|
168
|
+
onLogout={() => undefined}
|
|
169
|
+
menuItems={
|
|
170
|
+
<>
|
|
171
|
+
<DropdownMenuItem>
|
|
172
|
+
<UserCircleIcon />
|
|
173
|
+
Account (preview)
|
|
174
|
+
</DropdownMenuItem>
|
|
175
|
+
<DropdownMenuItem>
|
|
176
|
+
<GearSixIcon />
|
|
177
|
+
Settings (preview)
|
|
178
|
+
</DropdownMenuItem>
|
|
179
|
+
</>
|
|
180
|
+
}
|
|
181
|
+
/>
|
|
182
|
+
<DemoMainBody panel={panel} />
|
|
183
|
+
</AppShellMainContent>
|
|
184
|
+
</AppShell>
|
|
185
|
+
</PageScroll>
|
|
186
|
+
</SidebarProvider>
|
|
182
187
|
</div>
|
|
183
188
|
);
|
|
184
189
|
}
|
|
@@ -199,12 +204,7 @@ export default function StandaloneAppLayoutPage() {
|
|
|
199
204
|
actions={<DocsHeaderActions />}
|
|
200
205
|
/>
|
|
201
206
|
<PageContentSection title="Embedded mini-app (layout preview)">
|
|
202
|
-
<
|
|
203
|
-
sidebarWidthStorageKey="uilib.docs.standaloneLayout.sidebarWidthPx"
|
|
204
|
-
persistSidebarWidthWithoutConsent
|
|
205
|
-
>
|
|
206
|
-
<StandaloneLayoutPreview />
|
|
207
|
-
</SidebarProvider>
|
|
207
|
+
<StandaloneLayoutPreview />
|
|
208
208
|
</PageContentSection>
|
|
209
209
|
</>
|
|
210
210
|
);
|
package/src/docs/registry.ts
CHANGED
|
@@ -43,12 +43,6 @@ export const DOC_REGISTRY: DocEntry[] = [
|
|
|
43
43
|
section: 'Data display',
|
|
44
44
|
load: () => import('./pages/AnalysisLineIconPage'),
|
|
45
45
|
},
|
|
46
|
-
// {
|
|
47
|
-
// slug: 'app-header',
|
|
48
|
-
// title: 'AppHeader',
|
|
49
|
-
// section: 'Layout',
|
|
50
|
-
// load: () => import('./pages/AppHeaderPage'),
|
|
51
|
-
// },
|
|
52
46
|
{
|
|
53
47
|
slug: 'avatar',
|
|
54
48
|
title: 'Avatar',
|