@lobehub/lobehub 2.0.0-next.297 → 2.0.0-next.299
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/CHANGELOG.md +58 -0
- package/changelog/v1.json +18 -0
- package/package.json +2 -2
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/index.tsx +2 -9
- package/src/app/[variants]/(main)/agent/features/Conversation/ConversationArea.tsx +2 -2
- package/src/app/[variants]/(main)/agent/features/Conversation/Header/Tags/KnowledgeTag.tsx +3 -4
- package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/MentionList/types.ts +4 -2
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Nav.tsx +0 -1
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Related/index.tsx +9 -5
- package/src/app/[variants]/(main)/community/(detail)/model/features/Sidebar/ActionButton/ChatWithModel.tsx +3 -8
- package/src/app/[variants]/(main)/community/(list)/assistant/features/MarketSourceSwitch.tsx +44 -23
- package/src/app/[variants]/(main)/community/(list)/features/SortButton/index.tsx +40 -19
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/index.tsx +2 -9
- package/src/app/[variants]/(main)/group/features/Conversation/ConversationArea.tsx +2 -2
- package/src/app/[variants]/(main)/group/features/Conversation/Header/Tags/KnowledgeTag.tsx +3 -4
- package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/AgentBuilderProvider.tsx +2 -2
- package/src/app/[variants]/(main)/group/profile/features/MemberProfile/MentionList/types.ts +4 -2
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/Actions.tsx +3 -11
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Group/Actions.tsx +3 -12
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Group/Item.tsx +2 -9
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/index.tsx +2 -9
- package/src/app/[variants]/(main)/home/_layout/Body/Project/index.tsx +2 -9
- package/src/app/[variants]/(main)/home/_layout/HomeAgentIdSync.tsx +23 -0
- package/src/app/[variants]/(main)/home/_layout/index.tsx +2 -0
- package/src/app/[variants]/(main)/home/features/CommunityAgents/index.tsx +11 -13
- package/src/app/[variants]/(main)/home/features/FeaturedPlugins/index.tsx +11 -13
- package/src/app/[variants]/(main)/home/features/RecentPage/index.tsx +12 -14
- package/src/app/[variants]/(main)/home/features/RecentResource/index.tsx +12 -14
- package/src/app/[variants]/(main)/memory/contexts/features/ContextDropdown.tsx +5 -3
- package/src/app/[variants]/(main)/memory/experiences/features/ExperienceDropdown.tsx +5 -3
- package/src/app/[variants]/(main)/memory/identities/features/IdentityDropdown.tsx +5 -3
- package/src/app/[variants]/(main)/memory/preferences/features/PreferenceDropdown.tsx +5 -3
- package/src/app/[variants]/(main)/page/_layout/Body/Actions.tsx +3 -13
- package/src/app/[variants]/(main)/page/_layout/Body/index.tsx +2 -9
- package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +1 -1
- package/src/app/[variants]/(main)/settings/profile/features/SSOProvidersList/index.tsx +3 -3
- package/src/app/[variants]/(main)/settings/provider/ProviderMenu/Actions.tsx +3 -11
- package/src/app/[variants]/(main)/settings/provider/ProviderMenu/List.tsx +12 -28
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/DisabledModels.tsx +7 -8
- package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelTitle/index.tsx +18 -20
- package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/CollapseGroup/Actions.tsx +10 -14
- package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/List/Item/Actions.tsx +3 -13
- package/src/app/[variants]/share/t/[id]/SharedMessageList.tsx +2 -2
- package/src/business/server/lambda-routers/file.ts +1 -1
- package/src/features/AgentBuilder/AgentBuilderProvider.tsx +2 -2
- package/src/features/ChatInput/ActionBar/History/index.tsx +1 -1
- package/src/features/ChatInput/ActionBar/STT/common.tsx +1 -1
- package/src/features/ChatInput/ActionBar/Search/index.tsx +1 -1
- package/src/features/ChatInput/ActionBar/Upload/ServerMode.tsx +1 -0
- package/src/features/ChatInput/ActionBar/components/Action.tsx +4 -8
- package/src/features/ChatInput/ActionBar/components/ActionDropdown.tsx +225 -37
- package/src/features/Conversation/ConversationProvider.tsx +2 -1
- package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +10 -6
- package/src/features/Conversation/Messages/AssistantGroup/Actions/index.tsx +10 -6
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Intervention/ApprovalActions.tsx +11 -13
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Intervention/ModeSelector.tsx +8 -10
- package/src/features/Conversation/Messages/Supervisor/Actions/index.tsx +10 -6
- package/src/features/Conversation/Messages/Task/Actions/index.tsx +10 -6
- package/src/features/Conversation/Messages/User/Actions/index.tsx +10 -6
- package/src/features/Conversation/StoreUpdater.tsx +1 -1
- package/src/features/Conversation/store/initialState.ts +3 -1
- package/src/features/Conversation/store/slices/data/action.ts +6 -5
- package/src/features/LibraryModal/AssignKnowledgeBase/Item/Action.tsx +23 -26
- package/src/features/ModelSwitchPanel/components/List/MultipleProvidersModelItem.tsx +16 -18
- package/src/features/ModelSwitchPanel/styles.ts +18 -1
- package/src/features/PageEditor/Copilot/AgentSelector/Actions.tsx +6 -13
- package/src/features/PageEditor/PageAgentProvider.tsx +2 -2
- package/src/features/PluginStore/InstalledList/List/Item/Action.tsx +33 -36
- package/src/features/PluginStore/McpList/List/Action.tsx +25 -28
- package/src/features/PluginStore/PluginList/List/Action.tsx +25 -28
- package/src/features/PluginTag/index.tsx +3 -4
- package/src/features/Portal/Artifacts/Body/Renderer/SVG.tsx +14 -11
- package/src/features/Portal/Thread/Chat/index.tsx +2 -2
- package/src/features/ProfileEditor/AgentTool.tsx +1 -1
- package/src/features/ResourceManager/components/Explorer/ToolBar/SortDropdown.tsx +21 -18
- package/src/features/ResourceManager/components/Explorer/ToolBar/ViewSwitcher.tsx +7 -13
- package/src/features/ResourceManager/components/Header/AddButton.tsx +4 -11
- package/src/features/User/UserPanel/LangButton.tsx +56 -44
- package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +1 -1
- package/src/services/discover.ts +6 -4
- package/src/services/document/index.ts +11 -1
- package/src/store/page/slices/crud/action.ts +0 -48
- package/src/store/tool/slices/lobehubSkillStore/action.ts +1 -2
- package/src/styles/global.ts +2 -2
- package/src/types/shim-lobe-ui.d.ts +7 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionIcon,
|
|
1
|
+
import { ActionIcon, DropdownMenu, Flexbox, Icon, Text, TooltipGroup } from '@lobehub/ui';
|
|
2
2
|
import type { ItemType } from 'antd/es/menu/interface';
|
|
3
3
|
import isEqual from 'fast-deep-equal';
|
|
4
4
|
import { ArrowDownUpIcon, LucideCheck } from 'lucide-react';
|
|
@@ -240,9 +240,9 @@ const DisabledModels = memo<DisabledModelsProps>(({ activeTab, providerId }) =>
|
|
|
240
240
|
{t('providerModels.list.disabled')}
|
|
241
241
|
</Text>
|
|
242
242
|
{sourceDisabledModels.length > 1 && (
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
<DropdownMenu
|
|
244
|
+
items={
|
|
245
|
+
[
|
|
246
246
|
{
|
|
247
247
|
icon: sortType === SortType.Default ? <Icon icon={LucideCheck} /> : <div />,
|
|
248
248
|
key: 'default',
|
|
@@ -286,16 +286,15 @@ const DisabledModels = memo<DisabledModelsProps>(({ activeTab, providerId }) =>
|
|
|
286
286
|
label: t('providerModels.list.disabledActions.sortReleasedAtDesc'),
|
|
287
287
|
onClick: () => updateSortType(SortType.ReleasedAtDesc),
|
|
288
288
|
},
|
|
289
|
-
] as ItemType[]
|
|
290
|
-
}
|
|
291
|
-
trigger={['click']}
|
|
289
|
+
] as ItemType[]
|
|
290
|
+
}
|
|
292
291
|
>
|
|
293
292
|
<ActionIcon
|
|
294
293
|
icon={ArrowDownUpIcon}
|
|
295
294
|
size={'small'}
|
|
296
295
|
title={t('providerModels.list.disabledActions.sort')}
|
|
297
296
|
/>
|
|
298
|
-
</
|
|
297
|
+
</DropdownMenu>
|
|
299
298
|
)}
|
|
300
299
|
</Flexbox>
|
|
301
300
|
<TooltipGroup>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionIcon, Button,
|
|
1
|
+
import { ActionIcon, Button, DropdownMenu, Flexbox, Skeleton, Text } from '@lobehub/ui';
|
|
2
2
|
import { App, Space } from 'antd';
|
|
3
3
|
import { cssVar } from 'antd-style';
|
|
4
4
|
import { CircleX, EllipsisVertical, LucideRefreshCcwDot, PlusIcon } from 'lucide-react';
|
|
@@ -137,28 +137,26 @@ const ModelTitle = memo<ModelFetcherProps>(
|
|
|
137
137
|
<CreateNewModelModal open={showModal} setOpen={setShowModal} />
|
|
138
138
|
</>
|
|
139
139
|
)}
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
});
|
|
155
|
-
},
|
|
140
|
+
<DropdownMenu
|
|
141
|
+
items={[
|
|
142
|
+
{
|
|
143
|
+
key: 'reset',
|
|
144
|
+
label: t('providerModels.list.resetAll.title'),
|
|
145
|
+
onClick: async () => {
|
|
146
|
+
modal.confirm({
|
|
147
|
+
content: t('providerModels.list.resetAll.conform'),
|
|
148
|
+
onOk: async () => {
|
|
149
|
+
await clearModelsByProvider(provider);
|
|
150
|
+
message.success(t('providerModels.list.resetAll.success'));
|
|
151
|
+
},
|
|
152
|
+
title: t('providerModels.list.resetAll.title'),
|
|
153
|
+
});
|
|
156
154
|
},
|
|
157
|
-
|
|
158
|
-
}
|
|
155
|
+
},
|
|
156
|
+
]}
|
|
159
157
|
>
|
|
160
158
|
<Button icon={EllipsisVertical} size={'small'} />
|
|
161
|
-
</
|
|
159
|
+
</DropdownMenu>
|
|
162
160
|
</Space.Compact>
|
|
163
161
|
</Flexbox>
|
|
164
162
|
)}
|
package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/CollapseGroup/Actions.tsx
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ActionIcon,
|
|
3
|
+
DropdownMenu,
|
|
4
|
+
type DropdownMenuProps,
|
|
5
|
+
Icon,
|
|
6
|
+
type MenuProps,
|
|
7
|
+
} from '@lobehub/ui';
|
|
2
8
|
import { App } from 'antd';
|
|
3
9
|
import { createStaticStyles } from 'antd-style';
|
|
4
10
|
import { MoreVertical, PencilLine, Plus, Settings2, Trash, UsersRound } from 'lucide-react';
|
|
@@ -15,7 +21,7 @@ const styles = createStaticStyles(({ css }) => ({
|
|
|
15
21
|
z-index: 2000;
|
|
16
22
|
`,
|
|
17
23
|
}));
|
|
18
|
-
interface ActionsProps extends Pick<
|
|
24
|
+
interface ActionsProps extends Pick<DropdownMenuProps, 'onOpenChange'> {
|
|
19
25
|
id?: string;
|
|
20
26
|
isCustomGroup?: boolean;
|
|
21
27
|
isPinned?: boolean;
|
|
@@ -170,17 +176,7 @@ const Actions = memo<ActionsProps>(
|
|
|
170
176
|
|
|
171
177
|
return (
|
|
172
178
|
<>
|
|
173
|
-
<
|
|
174
|
-
arrow={false}
|
|
175
|
-
menu={{
|
|
176
|
-
items: menuItems,
|
|
177
|
-
onClick: ({ domEvent }) => {
|
|
178
|
-
domEvent.stopPropagation();
|
|
179
|
-
},
|
|
180
|
-
}}
|
|
181
|
-
onOpenChange={onOpenChange}
|
|
182
|
-
trigger={['click']}
|
|
183
|
-
>
|
|
179
|
+
<DropdownMenu items={menuItems} onOpenChange={onOpenChange}>
|
|
184
180
|
<ActionIcon
|
|
185
181
|
active={isMobile ? true : false}
|
|
186
182
|
icon={MoreVertical}
|
|
@@ -191,7 +187,7 @@ const Actions = memo<ActionsProps>(
|
|
|
191
187
|
size={{ blockSize: 22, size: 16 }}
|
|
192
188
|
style={{ background: isMobile ? 'transparent' : '', marginRight: -8 }}
|
|
193
189
|
/>
|
|
194
|
-
</
|
|
190
|
+
</DropdownMenu>
|
|
195
191
|
|
|
196
192
|
<MemberSelectionModal
|
|
197
193
|
mode="create"
|
package/src/app/[variants]/(mobile)/(home)/features/SessionListContent/List/Item/Actions.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionIcon,
|
|
1
|
+
import { ActionIcon, DropdownMenu, Icon } from '@lobehub/ui';
|
|
2
2
|
import { App } from 'antd';
|
|
3
3
|
import { createStaticStyles } from 'antd-style';
|
|
4
4
|
import { type ItemType } from 'antd/es/menu/interface';
|
|
@@ -183,17 +183,7 @@ const Actions = memo<ActionProps>(({ group, id, openCreateGroupModal, parentType
|
|
|
183
183
|
);
|
|
184
184
|
|
|
185
185
|
return (
|
|
186
|
-
<
|
|
187
|
-
arrow={false}
|
|
188
|
-
menu={{
|
|
189
|
-
items,
|
|
190
|
-
onClick: ({ domEvent }) => {
|
|
191
|
-
domEvent.stopPropagation();
|
|
192
|
-
},
|
|
193
|
-
}}
|
|
194
|
-
onOpenChange={setOpen}
|
|
195
|
-
trigger={['click']}
|
|
196
|
-
>
|
|
186
|
+
<DropdownMenu items={items} onOpenChange={setOpen}>
|
|
197
187
|
<ActionIcon
|
|
198
188
|
icon={MoreVertical}
|
|
199
189
|
size={{
|
|
@@ -201,7 +191,7 @@ const Actions = memo<ActionProps>(({ group, id, openCreateGroupModal, parentType
|
|
|
201
191
|
size: 16,
|
|
202
192
|
}}
|
|
203
193
|
/>
|
|
204
|
-
</
|
|
194
|
+
</DropdownMenu>
|
|
205
195
|
);
|
|
206
196
|
});
|
|
207
197
|
|
|
@@ -40,8 +40,8 @@ const SharedMessageList = memo<SharedMessageListProps>(({ agentId, groupId, shar
|
|
|
40
40
|
context={context}
|
|
41
41
|
hasInitMessages={!!messages}
|
|
42
42
|
messages={messages}
|
|
43
|
-
onMessagesChange={(messages) => {
|
|
44
|
-
replaceMessages(messages, { context });
|
|
43
|
+
onMessagesChange={(messages, ctx) => {
|
|
44
|
+
replaceMessages(messages, { context: ctx });
|
|
45
45
|
}}
|
|
46
46
|
>
|
|
47
47
|
<Flexbox flex={1}>
|
|
@@ -8,5 +8,5 @@ export interface BusinessFileUploadCheckParams {
|
|
|
8
8
|
|
|
9
9
|
export async function businessFileUploadCheck(
|
|
10
10
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
11
|
-
|
|
11
|
+
_params: BusinessFileUploadCheckParams,
|
|
12
12
|
): Promise<void> {}
|
|
@@ -46,8 +46,8 @@ const AgentBuilderProvider = memo<AgentBuilderProviderProps>(({ agentId, childre
|
|
|
46
46
|
context={context}
|
|
47
47
|
hasInitMessages={!!messages}
|
|
48
48
|
messages={messages}
|
|
49
|
-
onMessagesChange={(msgs) => {
|
|
50
|
-
replaceMessages(msgs, { context });
|
|
49
|
+
onMessagesChange={(msgs, ctx) => {
|
|
50
|
+
replaceMessages(msgs, { context: ctx });
|
|
51
51
|
}}
|
|
52
52
|
operationState={operationState}
|
|
53
53
|
>
|
|
@@ -55,7 +55,7 @@ const History = memo(() => {
|
|
|
55
55
|
popover={{
|
|
56
56
|
content: <Controls setUpdating={setUpdating} updating={updating} />,
|
|
57
57
|
minWidth: 240,
|
|
58
|
-
trigger: isMobile ?
|
|
58
|
+
trigger: isMobile ? 'click' : 'hover',
|
|
59
59
|
}}
|
|
60
60
|
showTooltip={false}
|
|
61
61
|
title={title}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { ActionIcon, type ActionIconProps } from '@lobehub/ui';
|
|
3
|
+
import { ActionIcon, type ActionIconProps, type PopoverTrigger } from '@lobehub/ui';
|
|
4
4
|
import { isUndefined } from 'es-toolkit/compat';
|
|
5
5
|
import { memo } from 'react';
|
|
6
6
|
import useMergeState from 'use-merge-value';
|
|
@@ -12,12 +12,12 @@ import ActionDropdown, { type ActionDropdownProps } from './ActionDropdown';
|
|
|
12
12
|
import ActionPopover, { type ActionPopoverProps } from './ActionPopover';
|
|
13
13
|
|
|
14
14
|
interface ActionProps extends Omit<ActionIconProps, 'popover'> {
|
|
15
|
-
dropdown?: ActionDropdownProps
|
|
15
|
+
dropdown?: Omit<ActionDropdownProps, 'children'>;
|
|
16
16
|
onOpenChange?: (open: boolean) => void;
|
|
17
17
|
open?: boolean;
|
|
18
18
|
popover?: ActionPopoverProps;
|
|
19
19
|
showTooltip?: boolean;
|
|
20
|
-
trigger?:
|
|
20
|
+
trigger?: PopoverTrigger;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const Action = memo<ActionProps>(
|
|
@@ -84,11 +84,7 @@ const Action = memo<ActionProps>(
|
|
|
84
84
|
<ActionPopover
|
|
85
85
|
onOpenChange={setShow}
|
|
86
86
|
open={show}
|
|
87
|
-
trigger={
|
|
88
|
-
Array.isArray(trigger)
|
|
89
|
-
? (trigger.filter((t) => t !== 'contextMenu') as ('click' | 'hover')[])
|
|
90
|
-
: trigger
|
|
91
|
-
}
|
|
87
|
+
trigger={trigger}
|
|
92
88
|
{...popover}
|
|
93
89
|
minWidth={mobile ? '100%' : popover.minWidth}
|
|
94
90
|
placement={mobile ? 'top' : (dropdownPlacement ?? popover.placement)}
|
|
@@ -1,68 +1,256 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenuPopup,
|
|
5
|
+
type DropdownMenuPopupProps,
|
|
6
|
+
DropdownMenuPortal,
|
|
7
|
+
DropdownMenuPositioner,
|
|
8
|
+
type DropdownMenuProps,
|
|
9
|
+
DropdownMenuRoot,
|
|
10
|
+
DropdownMenuTrigger,
|
|
11
|
+
type MenuProps,
|
|
12
|
+
type PopoverTrigger,
|
|
13
|
+
renderDropdownMenuItems,
|
|
14
|
+
} from '@lobehub/ui';
|
|
4
15
|
import { createStaticStyles, cx } from 'antd-style';
|
|
5
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
type CSSProperties,
|
|
18
|
+
type ReactNode,
|
|
19
|
+
memo,
|
|
20
|
+
useCallback,
|
|
21
|
+
useEffect,
|
|
22
|
+
useMemo,
|
|
23
|
+
useRef,
|
|
24
|
+
useState,
|
|
25
|
+
} from 'react';
|
|
6
26
|
|
|
7
27
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
8
28
|
|
|
9
|
-
const prefixCls = 'ant';
|
|
10
|
-
|
|
11
29
|
const styles = createStaticStyles(({ css }) => ({
|
|
12
30
|
dropdownMenu: css`
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
margin: 0;
|
|
16
|
-
}
|
|
17
|
-
.${prefixCls}-avatar {
|
|
18
|
-
margin-inline-end: var(--ant-margin-xs);
|
|
19
|
-
}
|
|
31
|
+
.ant-avatar {
|
|
32
|
+
margin-inline-end: var(--ant-margin-xs);
|
|
20
33
|
}
|
|
21
34
|
`,
|
|
22
35
|
}));
|
|
23
36
|
|
|
24
|
-
|
|
37
|
+
type ActionDropdownMenu = Omit<Pick<MenuProps, 'className' | 'onClick' | 'style'>, 'items'> & {
|
|
38
|
+
items: MenuProps['items'] | (() => MenuProps['items']);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export interface ActionDropdownProps extends Omit<DropdownMenuProps, 'items'> {
|
|
25
42
|
maxHeight?: number | string;
|
|
26
43
|
maxWidth?: number | string;
|
|
44
|
+
menu: ActionDropdownMenu;
|
|
27
45
|
minHeight?: number | string;
|
|
28
46
|
minWidth?: number | string;
|
|
47
|
+
popupRender?: (menu: ReactNode) => ReactNode;
|
|
29
48
|
/**
|
|
30
49
|
* 是否在挂载时预渲染弹层,避免首次触发展开时的渲染卡顿
|
|
31
50
|
*/
|
|
32
51
|
prefetch?: boolean;
|
|
52
|
+
trigger?: PopoverTrigger;
|
|
33
53
|
}
|
|
34
54
|
|
|
35
55
|
const ActionDropdown = memo<ActionDropdownProps>(
|
|
36
|
-
({
|
|
56
|
+
({
|
|
57
|
+
children,
|
|
58
|
+
defaultOpen,
|
|
59
|
+
menu,
|
|
60
|
+
trigger,
|
|
61
|
+
maxHeight,
|
|
62
|
+
maxWidth,
|
|
63
|
+
minHeight,
|
|
64
|
+
minWidth,
|
|
65
|
+
onOpenChange,
|
|
66
|
+
onOpenChangeComplete,
|
|
67
|
+
open,
|
|
68
|
+
placement = 'top',
|
|
69
|
+
popupProps,
|
|
70
|
+
popupRender,
|
|
71
|
+
portalProps,
|
|
72
|
+
positionerProps,
|
|
73
|
+
prefetch,
|
|
74
|
+
|
|
75
|
+
triggerProps,
|
|
76
|
+
...rest
|
|
77
|
+
}) => {
|
|
37
78
|
const isMobile = useIsMobile();
|
|
79
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen));
|
|
80
|
+
const menuItemsRef = useRef<ReactNode[] | null>(null);
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (open === undefined) return;
|
|
84
|
+
setUncontrolledOpen(open);
|
|
85
|
+
}, [open]);
|
|
86
|
+
|
|
87
|
+
const handleOpenChange = useCallback(
|
|
88
|
+
(nextOpen: boolean, details: Parameters<NonNullable<typeof onOpenChange>>[1]) => {
|
|
89
|
+
onOpenChange?.(nextOpen, details);
|
|
90
|
+
if (open === undefined) setUncontrolledOpen(nextOpen);
|
|
91
|
+
},
|
|
92
|
+
[onOpenChange, open],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const handleOpenChangeComplete = useCallback(
|
|
96
|
+
(nextOpen: boolean) => {
|
|
97
|
+
onOpenChangeComplete?.(nextOpen);
|
|
98
|
+
if (!nextOpen) menuItemsRef.current = null;
|
|
99
|
+
},
|
|
100
|
+
[onOpenChangeComplete],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const isOpen = open ?? uncontrolledOpen;
|
|
104
|
+
const openOnHover = useMemo(() => {
|
|
105
|
+
if (!trigger) return undefined;
|
|
106
|
+
if (trigger === 'both') return true;
|
|
107
|
+
if (Array.isArray(trigger)) return trigger.includes('hover');
|
|
108
|
+
return trigger === 'hover';
|
|
109
|
+
}, [trigger]);
|
|
110
|
+
const resolvedTriggerProps = useMemo(() => {
|
|
111
|
+
if (openOnHover === undefined) return triggerProps;
|
|
112
|
+
return {
|
|
113
|
+
...triggerProps,
|
|
114
|
+
openOnHover,
|
|
115
|
+
};
|
|
116
|
+
}, [openOnHover, triggerProps]);
|
|
117
|
+
|
|
118
|
+
const decorateMenuItems = useCallback(
|
|
119
|
+
(items: MenuProps['items']): MenuProps['items'] => {
|
|
120
|
+
if (!items) return items;
|
|
121
|
+
|
|
122
|
+
return items.map((item) => {
|
|
123
|
+
if (!item) return item;
|
|
124
|
+
if ('type' in item && item.type === 'divider') return item;
|
|
125
|
+
if ('type' in item && item.type === 'group') {
|
|
126
|
+
return {
|
|
127
|
+
...item,
|
|
128
|
+
children: item.children ? decorateMenuItems(item.children) : item.children,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if ('children' in item && item.children) {
|
|
133
|
+
return {
|
|
134
|
+
...item,
|
|
135
|
+
children: decorateMenuItems(item.children),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const itemOnClick = 'onClick' in item ? item.onClick : undefined;
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
...item,
|
|
142
|
+
onClick: (info) => {
|
|
143
|
+
info.domEvent.preventDefault();
|
|
144
|
+
menu.onClick?.(info);
|
|
145
|
+
itemOnClick?.(info);
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
[menu],
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const renderedItems = useMemo(() => {
|
|
154
|
+
if (!prefetch && !isOpen) return menuItemsRef.current;
|
|
155
|
+
const sourceItems = typeof menu.items === 'function' ? menu.items() : menu.items;
|
|
156
|
+
const nextItems = renderDropdownMenuItems(decorateMenuItems(sourceItems ?? []));
|
|
157
|
+
|
|
158
|
+
menuItemsRef.current = nextItems;
|
|
159
|
+
|
|
160
|
+
return nextItems;
|
|
161
|
+
}, [decorateMenuItems, isOpen, menu.items, prefetch]);
|
|
162
|
+
|
|
163
|
+
const menuContent = useMemo(() => {
|
|
164
|
+
if (!popupRender) return renderedItems;
|
|
165
|
+
return popupRender(renderedItems ?? null);
|
|
166
|
+
}, [popupRender, renderedItems]);
|
|
167
|
+
|
|
168
|
+
const resolvedPopupClassName = useMemo<DropdownMenuPopupProps['className']>(() => {
|
|
169
|
+
const popupClassName = popupProps?.className;
|
|
170
|
+
if (typeof popupClassName === 'function') {
|
|
171
|
+
return (state) => cx(styles.dropdownMenu, menu.className, popupClassName(state));
|
|
172
|
+
}
|
|
173
|
+
return cx(styles.dropdownMenu, menu.className, popupClassName);
|
|
174
|
+
}, [menu.className, popupProps?.className]);
|
|
175
|
+
|
|
176
|
+
const resolvedPopupStyle = useMemo<DropdownMenuPopupProps['style']>(() => {
|
|
177
|
+
const baseStyle: CSSProperties = {
|
|
178
|
+
maxHeight,
|
|
179
|
+
maxWidth: isMobile ? undefined : maxWidth,
|
|
180
|
+
minHeight,
|
|
181
|
+
minWidth: isMobile ? undefined : minWidth,
|
|
182
|
+
overflowX: 'hidden',
|
|
183
|
+
overflowY: 'scroll',
|
|
184
|
+
width: isMobile ? '100vw' : undefined,
|
|
185
|
+
};
|
|
186
|
+
const popupStyle = popupProps?.style;
|
|
187
|
+
|
|
188
|
+
if (typeof popupStyle === 'function') {
|
|
189
|
+
return (state) => ({
|
|
190
|
+
...baseStyle,
|
|
191
|
+
...menu.style,
|
|
192
|
+
...popupStyle(state),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
...baseStyle,
|
|
198
|
+
...menu.style,
|
|
199
|
+
...popupStyle,
|
|
200
|
+
};
|
|
201
|
+
}, [isMobile, maxHeight, maxWidth, menu.style, minHeight, minWidth, popupProps?.style]);
|
|
202
|
+
|
|
203
|
+
const resolvedPopupProps = useMemo(() => {
|
|
204
|
+
if (!popupProps) {
|
|
205
|
+
return {
|
|
206
|
+
className: resolvedPopupClassName,
|
|
207
|
+
style: resolvedPopupStyle,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
...popupProps,
|
|
213
|
+
className: resolvedPopupClassName,
|
|
214
|
+
style: resolvedPopupStyle,
|
|
215
|
+
};
|
|
216
|
+
}, [popupProps, resolvedPopupClassName, resolvedPopupStyle]);
|
|
217
|
+
|
|
218
|
+
const { container: portalContainer, ...restPortalProps } = portalProps ?? {};
|
|
219
|
+
const resolvedPortalContainer = useMemo<HTMLElement | null | undefined>(() => {
|
|
220
|
+
if (!portalContainer) return portalContainer ?? undefined;
|
|
221
|
+
if (typeof portalContainer === 'object' && 'current' in portalContainer) {
|
|
222
|
+
const current = portalContainer.current;
|
|
223
|
+
if (!current) return null;
|
|
224
|
+
if (typeof ShadowRoot !== 'undefined' && current instanceof ShadowRoot) {
|
|
225
|
+
return current.host as HTMLElement;
|
|
226
|
+
}
|
|
227
|
+
return current as HTMLElement;
|
|
228
|
+
}
|
|
229
|
+
if (typeof ShadowRoot !== 'undefined' && portalContainer instanceof ShadowRoot) {
|
|
230
|
+
return portalContainer.host as HTMLElement;
|
|
231
|
+
}
|
|
232
|
+
return portalContainer as HTMLElement;
|
|
233
|
+
}, [portalContainer]);
|
|
38
234
|
|
|
39
235
|
return (
|
|
40
|
-
<
|
|
41
|
-
arrow={false}
|
|
42
|
-
destroyOnHidden={false}
|
|
43
|
-
menu={{
|
|
44
|
-
...menu,
|
|
45
|
-
className: cx(styles.dropdownMenu, menu.className),
|
|
46
|
-
onClick: (e) => {
|
|
47
|
-
e.domEvent.preventDefault();
|
|
48
|
-
menu.onClick?.(e);
|
|
49
|
-
},
|
|
50
|
-
style: {
|
|
51
|
-
maxHeight,
|
|
52
|
-
maxWidth: isMobile ? undefined : maxWidth,
|
|
53
|
-
minHeight,
|
|
54
|
-
minWidth: isMobile ? undefined : minWidth,
|
|
55
|
-
overflowX: 'hidden',
|
|
56
|
-
overflowY: 'scroll',
|
|
57
|
-
width: isMobile ? '100vw' : undefined,
|
|
58
|
-
...menu.style,
|
|
59
|
-
},
|
|
60
|
-
}}
|
|
61
|
-
placement={isMobile ? 'top' : placement}
|
|
236
|
+
<DropdownMenuRoot
|
|
62
237
|
{...rest}
|
|
238
|
+
defaultOpen={defaultOpen}
|
|
239
|
+
onOpenChange={handleOpenChange}
|
|
240
|
+
onOpenChangeComplete={handleOpenChangeComplete}
|
|
241
|
+
open={open}
|
|
63
242
|
>
|
|
64
|
-
{children}
|
|
65
|
-
|
|
243
|
+
<DropdownMenuTrigger {...resolvedTriggerProps}>{children}</DropdownMenuTrigger>
|
|
244
|
+
<DropdownMenuPortal container={resolvedPortalContainer} {...restPortalProps}>
|
|
245
|
+
<DropdownMenuPositioner
|
|
246
|
+
{...positionerProps}
|
|
247
|
+
hoverTrigger={Boolean(resolvedTriggerProps?.openOnHover)}
|
|
248
|
+
placement={isMobile ? 'top' : placement}
|
|
249
|
+
>
|
|
250
|
+
<DropdownMenuPopup {...resolvedPopupProps}>{menuContent}</DropdownMenuPopup>
|
|
251
|
+
</DropdownMenuPositioner>
|
|
252
|
+
</DropdownMenuPortal>
|
|
253
|
+
</DropdownMenuRoot>
|
|
66
254
|
);
|
|
67
255
|
},
|
|
68
256
|
);
|
|
@@ -42,8 +42,9 @@ export interface ConversationProviderProps {
|
|
|
42
42
|
* Use this to sync messages back to external state (e.g., ChatStore)
|
|
43
43
|
*
|
|
44
44
|
* @param messages - The updated messages array
|
|
45
|
+
* @param context - The context that this data belongs to (prevents race conditions)
|
|
45
46
|
*/
|
|
46
|
-
onMessagesChange?: (messages: UIChatMessage[]) => void;
|
|
47
|
+
onMessagesChange?: (messages: UIChatMessage[], context: ConversationContext) => void;
|
|
47
48
|
/**
|
|
48
49
|
* External operation state (from ChatStore)
|
|
49
50
|
*
|
|
@@ -22,16 +22,20 @@ import { useAssistantActions } from './useAssistantActions';
|
|
|
22
22
|
// Helper to strip handleClick from action items before passing to ActionIconGroup
|
|
23
23
|
const stripHandleClick = (item: MessageActionItemOrDivider): ActionIconGroupItemType => {
|
|
24
24
|
if ('type' in item && item.type === 'divider') return item as unknown as ActionIconGroupItemType;
|
|
25
|
-
|
|
26
|
-
const
|
|
25
|
+
const { children, ...rest } = item as MessageActionItem;
|
|
26
|
+
const baseItem = { ...rest } as MessageActionItem;
|
|
27
|
+
delete (baseItem as { handleClick?: unknown }).handleClick;
|
|
27
28
|
if (children) {
|
|
28
29
|
return {
|
|
29
|
-
...
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
...baseItem,
|
|
31
|
+
children: children.map((child) => {
|
|
32
|
+
const nextChild = { ...child } as MessageActionItem;
|
|
33
|
+
delete (nextChild as { handleClick?: unknown }).handleClick;
|
|
34
|
+
return nextChild;
|
|
35
|
+
}),
|
|
32
36
|
} as ActionIconGroupItemType;
|
|
33
37
|
}
|
|
34
|
-
return
|
|
38
|
+
return baseItem as ActionIconGroupItemType;
|
|
35
39
|
};
|
|
36
40
|
|
|
37
41
|
// Build action items map for handleAction lookup
|
|
@@ -21,16 +21,20 @@ import { useGroupActions } from './useGroupActions';
|
|
|
21
21
|
// Helper to strip handleClick from action items before passing to ActionIconGroup
|
|
22
22
|
const stripHandleClick = (item: MessageActionItemOrDivider): ActionIconGroupItemType => {
|
|
23
23
|
if ('type' in item && item.type === 'divider') return item as unknown as ActionIconGroupItemType;
|
|
24
|
-
|
|
25
|
-
const
|
|
24
|
+
const { children, ...rest } = item as MessageActionItem;
|
|
25
|
+
const baseItem = { ...rest } as MessageActionItem;
|
|
26
|
+
delete (baseItem as { handleClick?: unknown }).handleClick;
|
|
26
27
|
if (children) {
|
|
27
28
|
return {
|
|
28
|
-
...
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
...baseItem,
|
|
30
|
+
children: children.map((child) => {
|
|
31
|
+
const nextChild = { ...child } as MessageActionItem;
|
|
32
|
+
delete (nextChild as { handleClick?: unknown }).handleClick;
|
|
33
|
+
return nextChild;
|
|
34
|
+
}),
|
|
31
35
|
} as ActionIconGroupItemType;
|
|
32
36
|
}
|
|
33
|
-
return
|
|
37
|
+
return baseItem as ActionIconGroupItemType;
|
|
34
38
|
};
|
|
35
39
|
|
|
36
40
|
// Build action items map for handleAction lookup
|