@gravity-ui/aikit 2.25.1-beta.c31bfaac02b26694749dd7a5d2532192c8e5fdc2.0 → 2.26.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/build/cjs/components/templates/History/ChatItem.js +9 -6
- package/build/cjs/components/templates/History/ChatItem.js.map +1 -1
- package/build/cjs/components/templates/History/History.css +17 -3
- package/build/cjs/package.json +1 -1
- package/build/cjs/utils/messageUtils.js +15 -4
- package/build/cjs/utils/messageUtils.js.map +1 -1
- package/build/docs/components/templates/History.md +3 -2
- package/build/esm/components/templates/History/ChatItem.js +9 -6
- package/build/esm/components/templates/History/ChatItem.js.map +1 -1
- package/build/esm/components/templates/History/History.css +17 -3
- package/build/esm/package.json +1 -1
- package/build/esm/utils/messageUtils.js +15 -4
- package/build/esm/utils/messageUtils.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,6 +10,11 @@ const cn_1 = require("../../../utils/cn.js");
|
|
|
10
10
|
const ActionButton_1 = require("../../atoms/ActionButton/index.js");
|
|
11
11
|
const i18n_1 = require("./i18n/index.js");
|
|
12
12
|
const b = (0, cn_1.block)('history');
|
|
13
|
+
function handleActionKeyDown(event) {
|
|
14
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
|
15
|
+
event.stopPropagation();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
13
18
|
/**
|
|
14
19
|
* Chat item component with hover state for actions.
|
|
15
20
|
* In mobile mode there is no hover, so actions are always visible.
|
|
@@ -53,13 +58,11 @@ function ChatItem({ chat, showActions, isActive, onDeleteClick, size, pinned, on
|
|
|
53
58
|
active: isActive,
|
|
54
59
|
mobile: isMobile,
|
|
55
60
|
['is-delete-processing']: isDeleteProccesing,
|
|
56
|
-
}), onClick: handleClick, children: [pinned && ((0, jsx_runtime_1.jsx)("span", { role: "img", "aria-label": (0, i18n_1.i18n)('pinned'), children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Pin, size: 16 }) })), hasOverflow ? ((0, jsx_runtime_1.jsx)(uikit_1.Tooltip, { content: chatLabel, openDelay: 300, children: label })) : (label), showDeleteAction ? ((0, jsx_runtime_1.jsx)(ActionButton_1.ActionButton, { view: "flat", size: deleteButtonSize, color: "secondary", loading: isDeleteProccesing, className: b('delete-button'), onClick: handleDeleteChat, tooltipTitle: (0, i18n_1.i18n)('tooltip-delete'), children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { className: b('icon-button'), data: icons_1.TrashBin, size: deleteIconSize }) })) : null, showActions && onPinnedChange && ((0, jsx_runtime_1.jsx)(ActionButton_1.ActionButton, { view: "flat", size: deleteButtonSize, disabled: pinningDisabled || isDeleteProccesing, "aria-label": (0, i18n_1.i18n)(pinned ? 'action-unpin' : 'action-pin'), tooltipTitle: (0, i18n_1.i18n)(pinned ? 'action-unpin' : 'action-pin'), onKeyDown: (event) => {
|
|
57
|
-
if (event.key === ' ' || event.key === 'Enter') {
|
|
58
|
-
event.stopPropagation();
|
|
59
|
-
}
|
|
60
|
-
}, onClick: (event) => {
|
|
61
|
+
}), onClick: handleClick, children: [pinned && ((0, jsx_runtime_1.jsx)("span", { role: "img", "aria-label": (0, i18n_1.i18n)('pinned'), children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.Pin, size: 16 }) })), hasOverflow ? ((0, jsx_runtime_1.jsx)(uikit_1.Tooltip, { content: chatLabel, openDelay: 300, children: label })) : (label), showDeleteAction ? ((0, jsx_runtime_1.jsx)(ActionButton_1.ActionButton, { view: "flat", size: deleteButtonSize, color: "secondary", loading: isDeleteProccesing, className: b('delete-button'), "aria-label": (0, i18n_1.i18n)('tooltip-delete'), onClick: handleDeleteChat, onKeyDown: handleActionKeyDown, tooltipTitle: (0, i18n_1.i18n)('tooltip-delete'), children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { className: b('icon-button'), data: icons_1.TrashBin, size: deleteIconSize }) })) : null, showActions && onPinnedChange && ((0, jsx_runtime_1.jsx)(ActionButton_1.ActionButton, { view: "flat", size: deleteButtonSize, "aria-disabled": Boolean(pinningDisabled || isDeleteProccesing), className: b('pin-button'), "aria-label": (0, i18n_1.i18n)(pinned ? 'action-unpin' : 'action-pin'), tooltipTitle: (0, i18n_1.i18n)(pinned ? 'action-unpin' : 'action-pin'), onKeyDown: handleActionKeyDown, onClick: (event) => {
|
|
61
62
|
event.stopPropagation();
|
|
62
|
-
|
|
63
|
+
if (!pinningDisabled && !isDeleteProccesing) {
|
|
64
|
+
onPinnedChange(chat.id, !pinned);
|
|
65
|
+
}
|
|
63
66
|
}, children: (0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: pinned ? icons_1.PinSlash : icons_1.Pin, size: deleteIconSize }) }))] }));
|
|
64
67
|
}
|
|
65
68
|
//# sourceMappingURL=ChatItem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatItem.js","sourceRoot":"../../../../../src","sources":["components/templates/History/ChatItem.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"ChatItem.js","sourceRoot":"../../../../../src","sources":["components/templates/History/ChatItem.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, {useEffect, useRef, useState} from 'react';\n\nimport {Pin, PinSlash, TrashBin} from '@gravity-ui/icons';\nimport {Icon, InputControlSize, Text, Tooltip, useMobile} from '@gravity-ui/uikit';\n\nimport {getControlIconSize, resolveMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {ChatType} from '../../../types';\nimport {block} from '../../../utils/cn';\nimport {ActionButton} from '../../atoms/ActionButton';\n\nimport {i18n} from './i18n';\n\nconst b = block('history');\n\nfunction handleActionKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (event.key === ' ' || event.key === 'Enter') {\n event.stopPropagation();\n }\n}\n\n/**\n * Props for ChatItem component\n */\nexport interface ChatItemProps {\n chat: ChatType;\n showActions: boolean;\n pinned?: boolean;\n onPinnedChange?: (chatId: string, pinned: boolean) => void;\n pinningDisabled?: boolean;\n isActive?: boolean;\n onDeleteClick?: (e: React.MouseEvent, chat: ChatType) => Promise<void>;\n /** Size of the row actions (default: `s`, `xl` in mobile mode) */\n size?: InputControlSize;\n}\n\n/**\n * Chat item component with hover state for actions.\n * In mobile mode there is no hover, so actions are always visible.\n *\n * @returns React element\n */\nexport function ChatItem({\n chat,\n showActions,\n isActive,\n onDeleteClick,\n size,\n pinned,\n onPinnedChange,\n pinningDisabled,\n}: ChatItemProps) {\n const [isDeleteProccesing, setIsDeleteProcessing] = useState(false);\n const [hasOverflow, setHasOverflow] = useState(false);\n const labelRef = useRef<HTMLDivElement>(null);\n const chatLabel = chat.lastMessage || chat.name;\n const isMobile = useMobile();\n const deleteButtonSize = resolveMobileControlSize({\n size,\n desktopDefault: 's',\n mobileDefault: 'xl',\n isMobile,\n });\n const deleteIconSize = getControlIconSize(deleteButtonSize);\n\n useEffect(() => {\n const label = labelRef.current;\n setHasOverflow(Boolean(label && label.scrollWidth > label.clientWidth));\n }, [chatLabel, pinned, showActions, onPinnedChange]);\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n if (isDeleteProccesing) {\n e.stopPropagation();\n }\n };\n\n const handleDeleteChat = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n try {\n setIsDeleteProcessing(true);\n await onDeleteClick?.(e, chat);\n } finally {\n setIsDeleteProcessing(false);\n }\n };\n\n const showDeleteAction = isDeleteProccesing || (showActions && onDeleteClick);\n\n const label = (\n <div className={b('chat-content')}>\n <Text variant=\"body-1\" ref={labelRef}>\n {chatLabel}\n </Text>\n </div>\n );\n\n return (\n <div\n className={b('chat-item', {\n active: isActive,\n mobile: isMobile,\n ['is-delete-processing']: isDeleteProccesing,\n })}\n onClick={handleClick}\n >\n {pinned && (\n <span role=\"img\" aria-label={i18n('pinned')}>\n <Icon data={Pin} size={16} />\n </span>\n )}\n {hasOverflow ? (\n <Tooltip content={chatLabel} openDelay={300}>\n {label}\n </Tooltip>\n ) : (\n label\n )}\n\n {showDeleteAction ? (\n <ActionButton\n view=\"flat\"\n size={deleteButtonSize}\n color=\"secondary\"\n loading={isDeleteProccesing}\n className={b('delete-button')}\n aria-label={i18n('tooltip-delete')}\n onClick={handleDeleteChat}\n onKeyDown={handleActionKeyDown}\n tooltipTitle={i18n('tooltip-delete')}\n >\n <Icon className={b('icon-button')} data={TrashBin} size={deleteIconSize} />\n </ActionButton>\n ) : null}\n {showActions && onPinnedChange && (\n <ActionButton\n view=\"flat\"\n size={deleteButtonSize}\n aria-disabled={Boolean(pinningDisabled || isDeleteProccesing)}\n className={b('pin-button')}\n aria-label={i18n(pinned ? 'action-unpin' : 'action-pin')}\n tooltipTitle={i18n(pinned ? 'action-unpin' : 'action-pin')}\n onKeyDown={handleActionKeyDown}\n onClick={(event) => {\n event.stopPropagation();\n if (!pinningDisabled && !isDeleteProccesing) {\n onPinnedChange(chat.id, !pinned);\n }\n }}\n >\n <Icon data={pinned ? PinSlash : Pin} size={deleteIconSize} />\n </ActionButton>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -43,8 +43,14 @@
|
|
|
43
43
|
flex: 1;
|
|
44
44
|
min-width: 0;
|
|
45
45
|
}
|
|
46
|
-
.g-aikit-history__chat-
|
|
47
|
-
|
|
46
|
+
.g-aikit-history__chat-item:hover .g-aikit-history__delete-button,
|
|
47
|
+
.g-aikit-history__chat-item:hover .g-aikit-history__pin-button, .g-aikit-history__chat-item:focus-within .g-aikit-history__delete-button,
|
|
48
|
+
.g-aikit-history__chat-item:focus-within .g-aikit-history__pin-button, .g-aikit-history__chat-item_active .g-aikit-history__delete-button,
|
|
49
|
+
.g-aikit-history__chat-item_active .g-aikit-history__pin-button, .g-aikit-history__chat-item_is-delete-processing .g-aikit-history__delete-button,
|
|
50
|
+
.g-aikit-history__chat-item_is-delete-processing .g-aikit-history__pin-button, .g-aikit-history__chat-item_mobile .g-aikit-history__delete-button,
|
|
51
|
+
.g-aikit-history__chat-item_mobile .g-aikit-history__pin-button {
|
|
52
|
+
opacity: 1;
|
|
53
|
+
pointer-events: auto;
|
|
48
54
|
}
|
|
49
55
|
.g-aikit-history__chat-item_is-delete-processing {
|
|
50
56
|
color: var(--g-color-text-secondary);
|
|
@@ -66,9 +72,17 @@
|
|
|
66
72
|
.g-aikit-history__icon-button {
|
|
67
73
|
color: var(--g-color-text-secondary);
|
|
68
74
|
}
|
|
75
|
+
.g-aikit-history__delete-button, .g-aikit-history__pin-button {
|
|
76
|
+
opacity: 0;
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
flex-shrink: 0;
|
|
79
|
+
}
|
|
80
|
+
.g-aikit-history__pin-button[aria-disabled=true] {
|
|
81
|
+
color: var(--g-color-text-hint);
|
|
82
|
+
cursor: default;
|
|
83
|
+
}
|
|
69
84
|
.g-aikit-history__delete-button {
|
|
70
85
|
margin-left: calc(var(--g-spacing-base) * 2);
|
|
71
|
-
display: none;
|
|
72
86
|
}
|
|
73
87
|
.g-aikit-history__empty {
|
|
74
88
|
display: flex;
|
package/build/cjs/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"2.
|
|
1
|
+
{"version":"2.26.0","type":"commonjs","sideEffects":["*.css","*.scss"]}
|
|
@@ -16,6 +16,9 @@ function normalizeContent(content) {
|
|
|
16
16
|
return [];
|
|
17
17
|
}
|
|
18
18
|
if (typeof content === 'string') {
|
|
19
|
+
if (!content.trim()) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
19
22
|
return [
|
|
20
23
|
{
|
|
21
24
|
type: 'text',
|
|
@@ -25,10 +28,18 @@ function normalizeContent(content) {
|
|
|
25
28
|
},
|
|
26
29
|
];
|
|
27
30
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
const parts = Array.isArray(content) ? content : [content];
|
|
32
|
+
return parts.filter((part) => {
|
|
33
|
+
const data = part.data;
|
|
34
|
+
if (part.type !== 'text' ||
|
|
35
|
+
typeof data !== 'object' ||
|
|
36
|
+
data === null ||
|
|
37
|
+
!('text' in data) ||
|
|
38
|
+
typeof data.text !== 'string') {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return data.text.trim().length > 0;
|
|
42
|
+
});
|
|
32
43
|
}
|
|
33
44
|
/**
|
|
34
45
|
* Check if message content contains ONLY thinking content (no other content types).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageUtils.js","sourceRoot":"../../../src","sources":["utils/messageUtils.ts"],"names":[],"mappings":";;AAaA,sCAKC;AAED,gDAOC;AAED,
|
|
1
|
+
{"version":3,"file":"messageUtils.js","sourceRoot":"../../../src","sources":["utils/messageUtils.ts"],"names":[],"mappings":";;AAaA,sCAKC;AAED,gDAOC;AAED,4CAsCC;AAOD,wDAQC;AAKD,sDA4BC;AAtGD,SAAgB,aAAa,CAG3B,OAAsD;IACpD,OAAO,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC;AACnC,CAAC;AAED,SAAgB,kBAAkB,CAI9B,OAAsD;IAEtD,OAAO,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC;AACxC,CAAC;AAED,SAAgB,gBAAgB,CAC5B,OAA8E;IAE9E,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACd,CAAC;QAED,OAAO;YACH;gBACI,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE;oBACF,IAAI,EAAE,OAAO;iBAChB;aACJ;SACJ,CAAC;IACN,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAEvB,IACI,IAAI,CAAC,IAAI,KAAK,MAAM;YACpB,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAC/B,CAAC;YACC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;GAIG;AACH,SAAgB,sBAAsB,CAClC,OAA8E;IAE9E,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;AAC3D,CAAC;AAKD,SAAgB,qBAAqB,CAGjC,OAAiB,EACjB,cAAiD;IAEjD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACjB,OAAO,cAAc,CAAC,GAAG,CACrB,CAAC,MAAM,EAA2B,EAAE,CAAC,CAAC;YAClC,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EACJ,OAAO,MAAM,CAAC,QAAQ,KAAK,UAAU;gBACjC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC1B,CAAC,CAAC,MAAM,CAAC,QAAQ;YACzB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;YACtC,KAAK,EAAE,MAAM,CAAC,KAAmC;SACpD,CAAC,CACL,CAAC;IACN,CAAC;IAED,OAAO,SAAS,CAAC;AACrB,CAAC","sourcesContent":["import type {\n ActionPopupConfig,\n BaseMessageAction,\n BaseMessageActionConfig,\n DefaultMessageAction,\n TAssistantMessage,\n TChatMessage,\n TMessageContent,\n TMessageContentUnion,\n TMessageMetadata,\n TUserMessage,\n} from '../types';\n\nexport function isUserMessage<\n Metadata = TMessageMetadata,\n TCustomMessageContent extends TMessageContent = never,\n>(message: TChatMessage<TCustomMessageContent, Metadata>): message is TUserMessage<Metadata> {\n return message.role === 'user';\n}\n\nexport function isAssistantMessage<\n Metadata = TMessageMetadata,\n TCustomMessageContent extends TMessageContent = never,\n>(\n message: TChatMessage<TCustomMessageContent, Metadata>,\n): message is TAssistantMessage<TCustomMessageContent, Metadata> {\n return message.role === 'assistant';\n}\n\nexport function normalizeContent<TCustomMessageContent extends TMessageContent = never>(\n content: TAssistantMessage<TCustomMessageContent, TMessageMetadata>['content'],\n): TMessageContentUnion<TCustomMessageContent>[] {\n if (!content) {\n return [];\n }\n\n if (typeof content === 'string') {\n if (!content.trim()) {\n return [];\n }\n\n return [\n {\n type: 'text',\n data: {\n text: content,\n },\n },\n ];\n }\n\n const parts = Array.isArray(content) ? content : [content];\n return parts.filter((part) => {\n const data = part.data;\n\n if (\n part.type !== 'text' ||\n typeof data !== 'object' ||\n data === null ||\n !('text' in data) ||\n typeof data.text !== 'string'\n ) {\n return true;\n }\n\n return data.text.trim().length > 0;\n });\n}\n\n/**\n * Check if message content contains ONLY thinking content (no other content types).\n * @param content - Message content to check\n * @returns true if content contains only thinking parts and nothing else\n */\nexport function hasOnlyThinkingContent<TCustomMessageContent extends TMessageContent = never>(\n content: TAssistantMessage<TCustomMessageContent, TMessageMetadata>['content'],\n): boolean {\n const parts = normalizeContent(content);\n if (parts.length === 0) {\n return false;\n }\n return parts.every((part) => part.type === 'thinking');\n}\n\n// Re-export ActionPopup types for convenience\nexport type {ActionPopupContext, ActionPopupConfig} from '../types';\n\nexport function resolveMessageActions<\n TMessage extends TChatMessage<TMessageContent, TMessageMetadata>,\n>(\n message: TMessage,\n defaultActions?: DefaultMessageAction<TMessage>[],\n): BaseMessageAction[] | undefined {\n if (message.actions) {\n return message.actions;\n }\n\n if (defaultActions) {\n return defaultActions.map(\n (action): BaseMessageActionConfig => ({\n actionType: action.type,\n icon: action.icon,\n children:\n typeof action.children === 'function'\n ? action.children(message)\n : action.children,\n label: action.label,\n view: action.view,\n onClick: () => action.onClick(message),\n popup: action.popup as ActionPopupConfig<unknown>,\n }),\n );\n }\n\n return undefined;\n}\n"]}
|
|
@@ -89,8 +89,9 @@ import ruLocale from 'dayjs/locale/ru.js';
|
|
|
89
89
|
Pinning is opt-in. Pass `pinnedChatIds` and `onPinnedChange` to `History` or
|
|
90
90
|
`HistoryList`. Omit both to retain the existing behavior. Passing only identifiers
|
|
91
91
|
shows read-only pin indicators. `showActions={false}` hides actions, not indicators.
|
|
92
|
-
Pin actions
|
|
93
|
-
|
|
92
|
+
Pin and delete actions appear on hover or keyboard focus on desktop and stay visible
|
|
93
|
+
on mobile. Their space is reserved to avoid shifting the row content. Pending pin
|
|
94
|
+
actions remain focusable and use `aria-disabled` to prevent repeat submissions. Activating a pin does not select the chat or close history.
|
|
94
95
|
|
|
95
96
|
With pinning enabled, pinned chats precede other chats, preserving the application's
|
|
96
97
|
input order within both groups. Pinned rows have no date headers; regular rows keep
|
|
@@ -7,6 +7,11 @@ import { block } from "../../../utils/cn.js";
|
|
|
7
7
|
import { ActionButton } from "../../atoms/ActionButton/index.js";
|
|
8
8
|
import { i18n } from "./i18n/index.js";
|
|
9
9
|
const b = block('history');
|
|
10
|
+
function handleActionKeyDown(event) {
|
|
11
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
|
12
|
+
event.stopPropagation();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
10
15
|
/**
|
|
11
16
|
* Chat item component with hover state for actions.
|
|
12
17
|
* In mobile mode there is no hover, so actions are always visible.
|
|
@@ -50,13 +55,11 @@ export function ChatItem({ chat, showActions, isActive, onDeleteClick, size, pin
|
|
|
50
55
|
active: isActive,
|
|
51
56
|
mobile: isMobile,
|
|
52
57
|
['is-delete-processing']: isDeleteProccesing,
|
|
53
|
-
}), onClick: handleClick, children: [pinned && (_jsx("span", { role: "img", "aria-label": i18n('pinned'), children: _jsx(Icon, { data: Pin, size: 16 }) })), hasOverflow ? (_jsx(Tooltip, { content: chatLabel, openDelay: 300, children: label })) : (label), showDeleteAction ? (_jsx(ActionButton, { view: "flat", size: deleteButtonSize, color: "secondary", loading: isDeleteProccesing, className: b('delete-button'), onClick: handleDeleteChat, tooltipTitle: i18n('tooltip-delete'), children: _jsx(Icon, { className: b('icon-button'), data: TrashBin, size: deleteIconSize }) })) : null, showActions && onPinnedChange && (_jsx(ActionButton, { view: "flat", size: deleteButtonSize, disabled: pinningDisabled || isDeleteProccesing, "aria-label": i18n(pinned ? 'action-unpin' : 'action-pin'), tooltipTitle: i18n(pinned ? 'action-unpin' : 'action-pin'), onKeyDown: (event) => {
|
|
54
|
-
if (event.key === ' ' || event.key === 'Enter') {
|
|
55
|
-
event.stopPropagation();
|
|
56
|
-
}
|
|
57
|
-
}, onClick: (event) => {
|
|
58
|
+
}), onClick: handleClick, children: [pinned && (_jsx("span", { role: "img", "aria-label": i18n('pinned'), children: _jsx(Icon, { data: Pin, size: 16 }) })), hasOverflow ? (_jsx(Tooltip, { content: chatLabel, openDelay: 300, children: label })) : (label), showDeleteAction ? (_jsx(ActionButton, { view: "flat", size: deleteButtonSize, color: "secondary", loading: isDeleteProccesing, className: b('delete-button'), "aria-label": i18n('tooltip-delete'), onClick: handleDeleteChat, onKeyDown: handleActionKeyDown, tooltipTitle: i18n('tooltip-delete'), children: _jsx(Icon, { className: b('icon-button'), data: TrashBin, size: deleteIconSize }) })) : null, showActions && onPinnedChange && (_jsx(ActionButton, { view: "flat", size: deleteButtonSize, "aria-disabled": Boolean(pinningDisabled || isDeleteProccesing), className: b('pin-button'), "aria-label": i18n(pinned ? 'action-unpin' : 'action-pin'), tooltipTitle: i18n(pinned ? 'action-unpin' : 'action-pin'), onKeyDown: handleActionKeyDown, onClick: (event) => {
|
|
58
59
|
event.stopPropagation();
|
|
59
|
-
|
|
60
|
+
if (!pinningDisabled && !isDeleteProccesing) {
|
|
61
|
+
onPinnedChange(chat.id, !pinned);
|
|
62
|
+
}
|
|
60
63
|
}, children: _jsx(Icon, { data: pinned ? PinSlash : Pin, size: deleteIconSize }) }))] }));
|
|
61
64
|
}
|
|
62
65
|
//# sourceMappingURL=ChatItem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatItem.js","sourceRoot":"../../../../../src","sources":["components/templates/History/ChatItem.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAC,IAAI,EAAoB,IAAI,EAAE,OAAO,EAAE,SAAS,EAAC,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAC,kBAAkB,EAAE,wBAAwB,EAAC,+CAA4C;AAEjG,OAAO,EAAC,KAAK,EAAC,6BAA0B;AACxC,OAAO,EAAC,YAAY,EAAC,0CAAiC;AAEtD,OAAO,EAAC,IAAI,EAAC,wBAAe;AAE5B,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"ChatItem.js","sourceRoot":"../../../../../src","sources":["components/templates/History/ChatItem.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAC,IAAI,EAAoB,IAAI,EAAE,OAAO,EAAE,SAAS,EAAC,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAC,kBAAkB,EAAE,wBAAwB,EAAC,+CAA4C;AAEjG,OAAO,EAAC,KAAK,EAAC,6BAA0B;AACxC,OAAO,EAAC,YAAY,EAAC,0CAAiC;AAEtD,OAAO,EAAC,IAAI,EAAC,wBAAe;AAE5B,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;AAE3B,SAAS,mBAAmB,CAAC,KAA6C;IACtE,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;QAC7C,KAAK,CAAC,eAAe,EAAE,CAAC;IAC5B,CAAC;AACL,CAAC;AAiBD;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,EACrB,IAAI,EACJ,WAAW,EACX,QAAQ,EACR,aAAa,EACb,IAAI,EACJ,MAAM,EACN,cAAc,EACd,eAAe,GACH;IACZ,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC;IAChD,MAAM,QAAQ,GAAG,SAAS,EAAE,CAAC;IAC7B,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;QAC9C,IAAI;QACJ,cAAc,EAAE,GAAG;QACnB,aAAa,EAAE,IAAI;QACnB,QAAQ;KACX,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IAE5D,SAAS,CAAC,GAAG,EAAE;QACX,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC/B,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC5E,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IAErD,MAAM,WAAW,GAAG,CAAC,CAA+C,EAAE,EAAE;QACpE,IAAI,kBAAkB,EAAE,CAAC;YACrB,CAAC,CAAC,eAAe,EAAE,CAAC;QACxB,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,KAAK,EAAE,CAAkD,EAAE,EAAE;QAClF,IAAI,CAAC;YACD,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC5B,MAAM,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAG,CAAC,EAAE,IAAI,CAAC,CAAA,CAAC;QACnC,CAAC;gBAAS,CAAC;YACP,qBAAqB,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,kBAAkB,IAAI,CAAC,WAAW,IAAI,aAAa,CAAC,CAAC;IAE9E,MAAM,KAAK,GAAG,CACV,cAAK,SAAS,EAAE,CAAC,CAAC,cAAc,CAAC,YAC7B,KAAC,IAAI,IAAC,OAAO,EAAC,QAAQ,EAAC,GAAG,EAAE,QAAQ,YAC/B,SAAS,GACP,GACL,CACT,CAAC;IAEF,OAAO,CACH,eACI,SAAS,EAAE,CAAC,CAAC,WAAW,EAAE;YACtB,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,CAAC,sBAAsB,CAAC,EAAE,kBAAkB;SAC/C,CAAC,EACF,OAAO,EAAE,WAAW,aAEnB,MAAM,IAAI,CACP,eAAM,IAAI,EAAC,KAAK,gBAAa,IAAI,CAAC,QAAQ,CAAC,YACvC,KAAC,IAAI,IAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,GAAI,GAC1B,CACV,EACA,WAAW,CAAC,CAAC,CAAC,CACX,KAAC,OAAO,IAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,YACtC,KAAK,GACA,CACb,CAAC,CAAC,CAAC,CACA,KAAK,CACR,EAEA,gBAAgB,CAAC,CAAC,CAAC,CAChB,KAAC,YAAY,IACT,IAAI,EAAC,MAAM,EACX,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAC,WAAW,EACjB,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,CAAC,CAAC,eAAe,CAAC,gBACjB,IAAI,CAAC,gBAAgB,CAAC,EAClC,OAAO,EAAE,gBAAgB,EACzB,SAAS,EAAE,mBAAmB,EAC9B,YAAY,EAAE,IAAI,CAAC,gBAAgB,CAAC,YAEpC,KAAC,IAAI,IAAC,SAAS,EAAE,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,GAAI,GAChE,CAClB,CAAC,CAAC,CAAC,IAAI,EACP,WAAW,IAAI,cAAc,IAAI,CAC9B,KAAC,YAAY,IACT,IAAI,EAAC,MAAM,EACX,IAAI,EAAE,gBAAgB,mBACP,OAAO,CAAC,eAAe,IAAI,kBAAkB,CAAC,EAC7D,SAAS,EAAE,CAAC,CAAC,YAAY,CAAC,gBACd,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,EACxD,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,EAC1D,SAAS,EAAE,mBAAmB,EAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;oBACf,KAAK,CAAC,eAAe,EAAE,CAAC;oBACxB,IAAI,CAAC,eAAe,IAAI,CAAC,kBAAkB,EAAE,CAAC;wBAC1C,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;oBACrC,CAAC;gBACL,CAAC,YAED,KAAC,IAAI,IAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,cAAc,GAAI,GAClD,CAClB,IACC,CACT,CAAC;AACN,CAAC","sourcesContent":["import React, {useEffect, useRef, useState} from 'react';\n\nimport {Pin, PinSlash, TrashBin} from '@gravity-ui/icons';\nimport {Icon, InputControlSize, Text, Tooltip, useMobile} from '@gravity-ui/uikit';\n\nimport {getControlIconSize, resolveMobileControlSize} from '../../../hooks/useMobileControlSize';\nimport {ChatType} from '../../../types';\nimport {block} from '../../../utils/cn';\nimport {ActionButton} from '../../atoms/ActionButton';\n\nimport {i18n} from './i18n';\n\nconst b = block('history');\n\nfunction handleActionKeyDown(event: React.KeyboardEvent<HTMLButtonElement>) {\n if (event.key === ' ' || event.key === 'Enter') {\n event.stopPropagation();\n }\n}\n\n/**\n * Props for ChatItem component\n */\nexport interface ChatItemProps {\n chat: ChatType;\n showActions: boolean;\n pinned?: boolean;\n onPinnedChange?: (chatId: string, pinned: boolean) => void;\n pinningDisabled?: boolean;\n isActive?: boolean;\n onDeleteClick?: (e: React.MouseEvent, chat: ChatType) => Promise<void>;\n /** Size of the row actions (default: `s`, `xl` in mobile mode) */\n size?: InputControlSize;\n}\n\n/**\n * Chat item component with hover state for actions.\n * In mobile mode there is no hover, so actions are always visible.\n *\n * @returns React element\n */\nexport function ChatItem({\n chat,\n showActions,\n isActive,\n onDeleteClick,\n size,\n pinned,\n onPinnedChange,\n pinningDisabled,\n}: ChatItemProps) {\n const [isDeleteProccesing, setIsDeleteProcessing] = useState(false);\n const [hasOverflow, setHasOverflow] = useState(false);\n const labelRef = useRef<HTMLDivElement>(null);\n const chatLabel = chat.lastMessage || chat.name;\n const isMobile = useMobile();\n const deleteButtonSize = resolveMobileControlSize({\n size,\n desktopDefault: 's',\n mobileDefault: 'xl',\n isMobile,\n });\n const deleteIconSize = getControlIconSize(deleteButtonSize);\n\n useEffect(() => {\n const label = labelRef.current;\n setHasOverflow(Boolean(label && label.scrollWidth > label.clientWidth));\n }, [chatLabel, pinned, showActions, onPinnedChange]);\n\n const handleClick = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n if (isDeleteProccesing) {\n e.stopPropagation();\n }\n };\n\n const handleDeleteChat = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n try {\n setIsDeleteProcessing(true);\n await onDeleteClick?.(e, chat);\n } finally {\n setIsDeleteProcessing(false);\n }\n };\n\n const showDeleteAction = isDeleteProccesing || (showActions && onDeleteClick);\n\n const label = (\n <div className={b('chat-content')}>\n <Text variant=\"body-1\" ref={labelRef}>\n {chatLabel}\n </Text>\n </div>\n );\n\n return (\n <div\n className={b('chat-item', {\n active: isActive,\n mobile: isMobile,\n ['is-delete-processing']: isDeleteProccesing,\n })}\n onClick={handleClick}\n >\n {pinned && (\n <span role=\"img\" aria-label={i18n('pinned')}>\n <Icon data={Pin} size={16} />\n </span>\n )}\n {hasOverflow ? (\n <Tooltip content={chatLabel} openDelay={300}>\n {label}\n </Tooltip>\n ) : (\n label\n )}\n\n {showDeleteAction ? (\n <ActionButton\n view=\"flat\"\n size={deleteButtonSize}\n color=\"secondary\"\n loading={isDeleteProccesing}\n className={b('delete-button')}\n aria-label={i18n('tooltip-delete')}\n onClick={handleDeleteChat}\n onKeyDown={handleActionKeyDown}\n tooltipTitle={i18n('tooltip-delete')}\n >\n <Icon className={b('icon-button')} data={TrashBin} size={deleteIconSize} />\n </ActionButton>\n ) : null}\n {showActions && onPinnedChange && (\n <ActionButton\n view=\"flat\"\n size={deleteButtonSize}\n aria-disabled={Boolean(pinningDisabled || isDeleteProccesing)}\n className={b('pin-button')}\n aria-label={i18n(pinned ? 'action-unpin' : 'action-pin')}\n tooltipTitle={i18n(pinned ? 'action-unpin' : 'action-pin')}\n onKeyDown={handleActionKeyDown}\n onClick={(event) => {\n event.stopPropagation();\n if (!pinningDisabled && !isDeleteProccesing) {\n onPinnedChange(chat.id, !pinned);\n }\n }}\n >\n <Icon data={pinned ? PinSlash : Pin} size={deleteIconSize} />\n </ActionButton>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -43,8 +43,14 @@
|
|
|
43
43
|
flex: 1;
|
|
44
44
|
min-width: 0;
|
|
45
45
|
}
|
|
46
|
-
.g-aikit-history__chat-
|
|
47
|
-
|
|
46
|
+
.g-aikit-history__chat-item:hover .g-aikit-history__delete-button,
|
|
47
|
+
.g-aikit-history__chat-item:hover .g-aikit-history__pin-button, .g-aikit-history__chat-item:focus-within .g-aikit-history__delete-button,
|
|
48
|
+
.g-aikit-history__chat-item:focus-within .g-aikit-history__pin-button, .g-aikit-history__chat-item_active .g-aikit-history__delete-button,
|
|
49
|
+
.g-aikit-history__chat-item_active .g-aikit-history__pin-button, .g-aikit-history__chat-item_is-delete-processing .g-aikit-history__delete-button,
|
|
50
|
+
.g-aikit-history__chat-item_is-delete-processing .g-aikit-history__pin-button, .g-aikit-history__chat-item_mobile .g-aikit-history__delete-button,
|
|
51
|
+
.g-aikit-history__chat-item_mobile .g-aikit-history__pin-button {
|
|
52
|
+
opacity: 1;
|
|
53
|
+
pointer-events: auto;
|
|
48
54
|
}
|
|
49
55
|
.g-aikit-history__chat-item_is-delete-processing {
|
|
50
56
|
color: var(--g-color-text-secondary);
|
|
@@ -66,9 +72,17 @@
|
|
|
66
72
|
.g-aikit-history__icon-button {
|
|
67
73
|
color: var(--g-color-text-secondary);
|
|
68
74
|
}
|
|
75
|
+
.g-aikit-history__delete-button, .g-aikit-history__pin-button {
|
|
76
|
+
opacity: 0;
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
flex-shrink: 0;
|
|
79
|
+
}
|
|
80
|
+
.g-aikit-history__pin-button[aria-disabled=true] {
|
|
81
|
+
color: var(--g-color-text-hint);
|
|
82
|
+
cursor: default;
|
|
83
|
+
}
|
|
69
84
|
.g-aikit-history__delete-button {
|
|
70
85
|
margin-left: calc(var(--g-spacing-base) * 2);
|
|
71
|
-
display: none;
|
|
72
86
|
}
|
|
73
87
|
.g-aikit-history__empty {
|
|
74
88
|
display: flex;
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"2.
|
|
1
|
+
{"version":"2.26.0","type":"module","sideEffects":["*.css","*.scss"]}
|
|
@@ -9,6 +9,9 @@ export function normalizeContent(content) {
|
|
|
9
9
|
return [];
|
|
10
10
|
}
|
|
11
11
|
if (typeof content === 'string') {
|
|
12
|
+
if (!content.trim()) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
12
15
|
return [
|
|
13
16
|
{
|
|
14
17
|
type: 'text',
|
|
@@ -18,10 +21,18 @@ export function normalizeContent(content) {
|
|
|
18
21
|
},
|
|
19
22
|
];
|
|
20
23
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const parts = Array.isArray(content) ? content : [content];
|
|
25
|
+
return parts.filter((part) => {
|
|
26
|
+
const data = part.data;
|
|
27
|
+
if (part.type !== 'text' ||
|
|
28
|
+
typeof data !== 'object' ||
|
|
29
|
+
data === null ||
|
|
30
|
+
!('text' in data) ||
|
|
31
|
+
typeof data.text !== 'string') {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return data.text.trim().length > 0;
|
|
35
|
+
});
|
|
25
36
|
}
|
|
26
37
|
/**
|
|
27
38
|
* Check if message content contains ONLY thinking content (no other content types).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageUtils.js","sourceRoot":"../../../src","sources":["utils/messageUtils.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,aAAa,CAG3B,OAAsD;IACpD,OAAO,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAI9B,OAAsD;IAEtD,OAAO,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC5B,OAA8E;IAE9E,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO;YACH;gBACI,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE;oBACF,IAAI,EAAE,OAAO;iBAChB;aACJ;SACJ,CAAC;IACN,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"messageUtils.js","sourceRoot":"../../../src","sources":["utils/messageUtils.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,aAAa,CAG3B,OAAsD;IACpD,OAAO,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAI9B,OAAsD;IAEtD,OAAO,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC5B,OAA8E;IAE9E,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;QACd,CAAC;QAED,OAAO;YACH;gBACI,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE;oBACF,IAAI,EAAE,OAAO;iBAChB;aACJ;SACJ,CAAC;IACN,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC3D,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAEvB,IACI,IAAI,CAAC,IAAI,KAAK,MAAM;YACpB,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;YACjB,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAC/B,CAAC;YACC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAClC,OAA8E;IAE9E,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;AAC3D,CAAC;AAKD,MAAM,UAAU,qBAAqB,CAGjC,OAAiB,EACjB,cAAiD;IAEjD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED,IAAI,cAAc,EAAE,CAAC;QACjB,OAAO,cAAc,CAAC,GAAG,CACrB,CAAC,MAAM,EAA2B,EAAE,CAAC,CAAC;YAClC,UAAU,EAAE,MAAM,CAAC,IAAI;YACvB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EACJ,OAAO,MAAM,CAAC,QAAQ,KAAK,UAAU;gBACjC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAC1B,CAAC,CAAC,MAAM,CAAC,QAAQ;YACzB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;YACtC,KAAK,EAAE,MAAM,CAAC,KAAmC;SACpD,CAAC,CACL,CAAC;IACN,CAAC;IAED,OAAO,SAAS,CAAC;AACrB,CAAC","sourcesContent":["import type {\n ActionPopupConfig,\n BaseMessageAction,\n BaseMessageActionConfig,\n DefaultMessageAction,\n TAssistantMessage,\n TChatMessage,\n TMessageContent,\n TMessageContentUnion,\n TMessageMetadata,\n TUserMessage,\n} from '../types';\n\nexport function isUserMessage<\n Metadata = TMessageMetadata,\n TCustomMessageContent extends TMessageContent = never,\n>(message: TChatMessage<TCustomMessageContent, Metadata>): message is TUserMessage<Metadata> {\n return message.role === 'user';\n}\n\nexport function isAssistantMessage<\n Metadata = TMessageMetadata,\n TCustomMessageContent extends TMessageContent = never,\n>(\n message: TChatMessage<TCustomMessageContent, Metadata>,\n): message is TAssistantMessage<TCustomMessageContent, Metadata> {\n return message.role === 'assistant';\n}\n\nexport function normalizeContent<TCustomMessageContent extends TMessageContent = never>(\n content: TAssistantMessage<TCustomMessageContent, TMessageMetadata>['content'],\n): TMessageContentUnion<TCustomMessageContent>[] {\n if (!content) {\n return [];\n }\n\n if (typeof content === 'string') {\n if (!content.trim()) {\n return [];\n }\n\n return [\n {\n type: 'text',\n data: {\n text: content,\n },\n },\n ];\n }\n\n const parts = Array.isArray(content) ? content : [content];\n return parts.filter((part) => {\n const data = part.data;\n\n if (\n part.type !== 'text' ||\n typeof data !== 'object' ||\n data === null ||\n !('text' in data) ||\n typeof data.text !== 'string'\n ) {\n return true;\n }\n\n return data.text.trim().length > 0;\n });\n}\n\n/**\n * Check if message content contains ONLY thinking content (no other content types).\n * @param content - Message content to check\n * @returns true if content contains only thinking parts and nothing else\n */\nexport function hasOnlyThinkingContent<TCustomMessageContent extends TMessageContent = never>(\n content: TAssistantMessage<TCustomMessageContent, TMessageMetadata>['content'],\n): boolean {\n const parts = normalizeContent(content);\n if (parts.length === 0) {\n return false;\n }\n return parts.every((part) => part.type === 'thinking');\n}\n\n// Re-export ActionPopup types for convenience\nexport type {ActionPopupContext, ActionPopupConfig} from '../types';\n\nexport function resolveMessageActions<\n TMessage extends TChatMessage<TMessageContent, TMessageMetadata>,\n>(\n message: TMessage,\n defaultActions?: DefaultMessageAction<TMessage>[],\n): BaseMessageAction[] | undefined {\n if (message.actions) {\n return message.actions;\n }\n\n if (defaultActions) {\n return defaultActions.map(\n (action): BaseMessageActionConfig => ({\n actionType: action.type,\n icon: action.icon,\n children:\n typeof action.children === 'function'\n ? action.children(message)\n : action.children,\n label: action.label,\n view: action.view,\n onClick: () => action.onClick(message),\n popup: action.popup as ActionPopupConfig<unknown>,\n }),\n );\n }\n\n return undefined;\n}\n"]}
|
package/package.json
CHANGED