2
0

action-context.tsx 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /**
  2. * ActionContext - json-render 组件交互事件处理
  3. *
  4. * 提供 emit 函数供组件触发交互事件
  5. */
  6. 'use client';
  7. import { createContext, useContext, useCallback } from 'react';
  8. /**
  9. * Action Context 类型
  10. */
  11. interface ActionContextValue {
  12. emit: (eventName: string, payload?: any) => void;
  13. }
  14. /**
  15. * ActionContext - 用于在组件树中传递 emit 函数
  16. */
  17. export const ActionContext = createContext<ActionContextValue | null>(null);
  18. /**
  19. * ActionProvider 处理 json-render 组件的交互事件
  20. * 组件通过 emit() 触发事件,ActionProvider 执行相应的处理函数
  21. */
  22. interface ActionProviderActions {
  23. sendMessage: (message: string) => void;
  24. }
  25. interface ActionProviderProps {
  26. children: React.ReactNode;
  27. actions: ActionProviderActions;
  28. }
  29. /**
  30. * ActionProvider 组件 - 包装 JsonRenderer,提供事件处理能力
  31. */
  32. export function ActionProvider({ children, actions }: ActionProviderProps) {
  33. /**
  34. * emit 函数 - 组件调用此函数触发事件
  35. * @param eventName - 事件名称
  36. * @param payload - 事件负载
  37. */
  38. const emit = useCallback((eventName: string, payload?: any) => {
  39. console.log('[ActionProvider] Event emitted:', eventName, payload);
  40. switch (eventName) {
  41. case 'sendMessage':
  42. // 发送消息到聊天
  43. const message = typeof payload === 'string' ? payload : payload?.message || '';
  44. if (message) {
  45. actions.sendMessage(message);
  46. }
  47. break;
  48. case 'selectNovel':
  49. // 选择小说 - 简洁消息,AI 通过系统提示词知道要调用 get_novel_detail
  50. if (payload?.id) {
  51. const novelTitle = payload.title || payload.id;
  52. actions.sendMessage(`查看小说:${novelTitle}`);
  53. } else if (payload?.title) {
  54. actions.sendMessage(`查看小说:${payload.title}`);
  55. }
  56. break;
  57. case 'copy':
  58. // 复制文本到剪贴板
  59. if (payload?.text) {
  60. navigator.clipboard.writeText(payload.text);
  61. }
  62. break;
  63. default:
  64. console.warn('[ActionProvider] Unknown event:', eventName);
  65. }
  66. }, [actions]);
  67. return (
  68. <ActionContext.Provider value={{ emit }}>
  69. {children}
  70. </ActionContext.Provider>
  71. );
  72. }
  73. /**
  74. * Hook - 在组件中获取 emit 函数
  75. * 如果不在 ActionProvider 内,返回 no-op emit
  76. */
  77. export function useActionEmit() {
  78. const context = useContext(ActionContext);
  79. if (!context) {
  80. console.warn('[useActionEmit] ActionContext not found, returning no-op emit');
  81. return { emit: () => {} };
  82. }
  83. return context;
  84. }