@lobehub/lobehub 2.0.0-next.254 → 2.0.0-next.256

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.
Files changed (148) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/en-US/plugin.json +1 -0
  4. package/locales/zh-CN/plugin.json +1 -0
  5. package/package.json +1 -1
  6. package/packages/builtin-tool-notebook/src/client/Placeholder/CreateDocument.tsx +6 -6
  7. package/packages/builtin-tool-notebook/src/client/Render/CreateDocument/DocumentCard.tsx +23 -10
  8. package/packages/builtin-tool-notebook/src/client/Streaming/CreateDocument/index.tsx +1 -1
  9. package/packages/database/src/models/__tests__/agent.test.ts +91 -4
  10. package/packages/database/src/models/agent.ts +15 -7
  11. package/packages/editor-runtime/src/EditorRuntime.ts +1 -1
  12. package/packages/editor-runtime/src/__tests__/EditorRuntime.real.test.ts +65 -4
  13. package/packages/editor-runtime/src/__tests__/__snapshots__/EditorRuntime.real.test.ts.snap +108 -17
  14. package/packages/editor-runtime/src/__tests__/fixtures/remove-then-add.json +636 -0
  15. package/packages/editor-runtime/src/__tests__/fixtures/remove.json +1 -0
  16. package/packages/types/src/agent/agentConfig.ts +8 -8
  17. package/src/app/[variants]/(main)/chat/features/Portal/_layout/Mobile.tsx +2 -1
  18. package/src/app/[variants]/(main)/group/features/Portal/_layout/Mobile.tsx +2 -1
  19. package/src/app/[variants]/(main)/home/_layout/hooks/useCreateMenuItems.tsx +2 -2
  20. package/src/app/[variants]/(main)/page/{features/PageTitle → PageTitle}/index.tsx +0 -1
  21. package/src/app/[variants]/(main)/page/[id]/index.tsx +43 -1
  22. package/src/app/[variants]/(main)/page/_layout/Body/AllPagesDrawer/Content.tsx +15 -15
  23. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/Editing.tsx +3 -3
  24. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/index.tsx +7 -12
  25. package/src/app/[variants]/(main)/page/_layout/Body/List/Item/useDropdownMenu.tsx +5 -5
  26. package/src/app/[variants]/(main)/page/_layout/Body/List/index.tsx +7 -7
  27. package/src/app/[variants]/(main)/page/_layout/Body/index.tsx +15 -9
  28. package/src/app/[variants]/(main)/page/_layout/Body/useDropdownMenu.tsx +3 -3
  29. package/src/app/[variants]/(main)/page/_layout/DataSync.tsx +15 -0
  30. package/src/app/[variants]/(main)/page/_layout/Header/AddButton.tsx +2 -2
  31. package/src/app/[variants]/(main)/page/_layout/index.tsx +2 -0
  32. package/src/app/[variants]/(main)/page/index.tsx +3 -7
  33. package/src/components/Editor/AutoSaveHint.tsx +1 -1
  34. package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/Intervention/ApprovalActions.tsx +2 -2
  35. package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +18 -15
  36. package/src/features/Conversation/Messages/AssistantGroup/components/Group.tsx +3 -3
  37. package/src/features/Conversation/Messages/Contexts/MessageAggregationContext.ts +15 -0
  38. package/src/features/Conversation/Messages/Supervisor/components/Group.tsx +3 -3
  39. package/src/features/Conversation/Messages/User/Actions/index.tsx +5 -1
  40. package/src/features/EditorCanvas/AutoSaveHint.tsx +37 -0
  41. package/src/features/{PageEditor → EditorCanvas}/DiffAllToolbar.tsx +57 -16
  42. package/src/features/EditorCanvas/DocumentIdMode.tsx +111 -0
  43. package/src/features/EditorCanvas/EditorCanvas.tsx +148 -0
  44. package/src/features/EditorCanvas/EditorDataMode.tsx +64 -0
  45. package/src/features/EditorCanvas/ErrorBoundary.tsx +66 -0
  46. package/src/features/EditorCanvas/InlineToolbar.tsx +245 -0
  47. package/src/features/EditorCanvas/InternalEditor.tsx +134 -0
  48. package/src/features/{PageEditor/EditorCanvas → EditorCanvas}/actions.ts +10 -8
  49. package/src/features/EditorCanvas/index.ts +9 -0
  50. package/src/features/PageEditor/EditorCanvas/index.tsx +14 -111
  51. package/src/features/PageEditor/EditorCanvas/useAskCopilotItem.tsx +95 -0
  52. package/src/features/PageEditor/EditorCanvas/useSlashItems.tsx +1 -1
  53. package/src/features/PageEditor/Header/Breadcrumb.tsx +2 -2
  54. package/src/features/PageEditor/Header/index.tsx +15 -18
  55. package/src/features/PageEditor/Header/useMenu.tsx +12 -9
  56. package/src/features/PageEditor/PageEditor.tsx +45 -21
  57. package/src/features/PageEditor/PageEditorProvider.tsx +13 -1
  58. package/src/features/PageEditor/PageTitle/index.tsx +2 -2
  59. package/src/features/PageEditor/StoreUpdater.tsx +35 -308
  60. package/src/features/PageEditor/{Body/Title.tsx → TitleSection.tsx} +16 -16
  61. package/src/features/PageEditor/store/action.ts +96 -188
  62. package/src/features/PageEditor/store/initialState.ts +16 -21
  63. package/src/features/PageEditor/store/selectors.ts +3 -4
  64. package/src/features/PageExplorer/PageExplorerPlaceholder.tsx +22 -14
  65. package/src/features/PageExplorer/index.tsx +34 -67
  66. package/src/features/Portal/Artifacts/index.ts +0 -2
  67. package/src/features/Portal/Document/AutoSaveHint.tsx +7 -6
  68. package/src/features/Portal/Document/Body.tsx +1 -3
  69. package/src/features/Portal/Document/EditorCanvas.tsx +7 -50
  70. package/src/features/Portal/Document/Header.tsx +13 -10
  71. package/src/features/Portal/Document/TodoList.tsx +6 -4
  72. package/src/features/Portal/Document/Wrapper.tsx +3 -11
  73. package/src/features/Portal/Document/index.ts +0 -2
  74. package/src/features/Portal/FilePreview/index.ts +0 -2
  75. package/src/features/Portal/GroupThread/index.ts +0 -3
  76. package/src/features/Portal/MessageDetail/index.ts +0 -2
  77. package/src/features/Portal/Notebook/index.ts +0 -2
  78. package/src/features/Portal/Plugins/index.ts +0 -2
  79. package/src/features/Portal/Thread/index.ts +0 -3
  80. package/src/features/Portal/components/Header.tsx +18 -6
  81. package/src/features/Portal/router.tsx +34 -97
  82. package/src/features/Portal/type.ts +0 -2
  83. package/src/libs/next/config/define-config.ts +4 -1
  84. package/src/locales/default/plugin.ts +1 -0
  85. package/src/store/chat/slices/portal/action.test.ts +218 -15
  86. package/src/store/chat/slices/portal/action.ts +194 -41
  87. package/src/store/chat/slices/portal/initialState.ts +40 -1
  88. package/src/store/chat/slices/portal/selectors/thread.ts +44 -3
  89. package/src/store/chat/slices/portal/selectors.test.ts +119 -17
  90. package/src/store/chat/slices/portal/selectors.ts +117 -36
  91. package/src/store/document/index.ts +17 -5
  92. package/src/store/document/slices/document/action.ts +209 -0
  93. package/src/store/document/slices/document/index.ts +6 -0
  94. package/src/store/document/slices/editor/action.test.ts +340 -0
  95. package/src/store/document/slices/editor/action.ts +133 -149
  96. package/src/store/document/slices/editor/index.ts +9 -2
  97. package/src/store/document/slices/editor/initialState.ts +66 -29
  98. package/src/store/document/slices/editor/reducer.test.ts +217 -0
  99. package/src/store/document/slices/editor/reducer.ts +67 -0
  100. package/src/store/document/slices/editor/selectors.test.ts +395 -0
  101. package/src/store/document/slices/editor/selectors.ts +107 -5
  102. package/src/store/document/store.ts +12 -13
  103. package/src/store/file/slices/document/action.ts +19 -188
  104. package/src/store/file/slices/document/initialState.ts +0 -30
  105. package/src/store/file/slices/document/selectors.ts +25 -59
  106. package/src/store/notebook/index.ts +5 -4
  107. package/src/store/page/index.ts +2 -0
  108. package/src/store/page/initialState.ts +92 -0
  109. package/src/store/page/selectors.ts +5 -0
  110. package/src/store/page/slices/crud/action.ts +477 -0
  111. package/src/store/page/slices/crud/index.ts +2 -0
  112. package/src/store/page/slices/crud/initialState.ts +7 -0
  113. package/src/store/page/slices/internal/action.ts +32 -0
  114. package/src/store/page/slices/internal/index.ts +2 -0
  115. package/src/store/page/slices/internal/reducer.ts +105 -0
  116. package/src/store/page/slices/list/action.ts +206 -0
  117. package/src/store/page/slices/list/index.ts +3 -0
  118. package/src/store/page/slices/list/initialState.ts +29 -0
  119. package/src/store/page/slices/list/selectors.ts +90 -0
  120. package/src/store/page/slices/selection/action.ts +67 -0
  121. package/src/store/page/slices/selection/index.ts +2 -0
  122. package/src/store/page/slices/selection/initialState.ts +11 -0
  123. package/src/store/page/store.ts +29 -0
  124. package/src/store/tool/slices/lobehubSkillStore/selectors.ts +10 -20
  125. package/src/utils/identifier.ts +8 -2
  126. package/src/features/Conversation/Messages/AssistantGroup/components/GroupContext.ts +0 -15
  127. package/src/features/Conversation/Messages/Supervisor/components/GroupContext.ts +0 -15
  128. package/src/features/PageEditor/Body/index.tsx +0 -68
  129. package/src/features/PageEditor/EditorCanvas/InlineToolbar.tsx +0 -316
  130. package/src/features/PageEditor/Header/AutoSaveHint.tsx +0 -27
  131. package/src/features/Portal/Artifacts/useEnable.ts +0 -4
  132. package/src/features/Portal/Document/DocumentEditorProvider.tsx +0 -34
  133. package/src/features/Portal/Document/StoreUpdater.tsx +0 -80
  134. package/src/features/Portal/Document/Title.tsx +0 -54
  135. package/src/features/Portal/Document/store/action.ts +0 -114
  136. package/src/features/Portal/Document/store/index.ts +0 -21
  137. package/src/features/Portal/Document/store/initialState.ts +0 -24
  138. package/src/features/Portal/Document/useEnable.ts +0 -8
  139. package/src/features/Portal/FilePreview/useEnable.ts +0 -6
  140. package/src/features/Portal/GroupThread/hook.ts +0 -9
  141. package/src/features/Portal/MessageDetail/useEnable.ts +0 -4
  142. package/src/features/Portal/Notebook/useEnable.ts +0 -6
  143. package/src/features/Portal/Plugins/useEnable.ts +0 -6
  144. package/src/features/Portal/Thread/hook.ts +0 -8
  145. package/src/store/document/slices/notebook/action.ts +0 -119
  146. package/src/store/document/slices/notebook/index.ts +0 -3
  147. package/src/store/document/slices/notebook/initialState.ts +0 -12
  148. package/src/store/document/slices/notebook/selectors.ts +0 -26
@@ -1,319 +1,61 @@
1
1
  'use client';
2
2
 
3
- import { useEditorState } from '@lobehub/editor/react';
4
- import debug from 'debug';
5
- import React, { memo, useEffect, useRef } from 'react';
3
+ import { memo, useEffect } from 'react';
6
4
  import { createStoreUpdater } from 'zustand-utils';
7
5
 
8
- import { useFileStore } from '@/store/file';
9
- import { documentSelectors } from '@/store/file/slices/document/selectors';
10
6
  import { pageAgentRuntime } from '@/store/tool/slices/builtin/executors/lobe-page-agent';
11
7
 
12
8
  import { type PublicState, usePageEditorStore, useStoreApi } from './store';
13
9
 
14
- const log = debug('page:store-updater');
15
-
16
- export type StoreUpdaterProps = Partial<PublicState>;
17
-
18
- // State machine types
19
- type InitPhase =
20
- | 'idle' // Initial state
21
- | 'waiting-for-data' // Waiting for SWR to fetch/return cached data
22
- | 'initializing' // Setting metadata (currentDocId, title, emoji)
23
- | 'loading-content' // Loading content into editor
24
- | 'ready' // Initialization complete
25
- | 'error'; // Error occurred
26
-
27
- interface InitState {
28
- error?: Error;
29
- phase: InitPhase;
30
- targetPageId: string | undefined;
10
+ export interface StoreUpdaterProps extends Partial<PublicState> {
11
+ pageId?: string;
31
12
  }
32
13
 
14
+ /**
15
+ * StoreUpdater syncs PageEditorStore props and connects to page agent runtime.
16
+ *
17
+ * Note: Document content loading is handled by EditorCanvas via DocumentStore.
18
+ * Title/emoji are consumed from PageEditorStore (set via setCurrentTitle/setCurrentEmoji).
19
+ */
33
20
  const StoreUpdater = memo<StoreUpdaterProps>(
34
- ({ pageId, knowledgeBaseId, onDocumentIdChange, onSave, onDelete, onBack, parentId }) => {
21
+ ({
22
+ pageId,
23
+ knowledgeBaseId,
24
+ onDocumentIdChange,
25
+ onEmojiChange,
26
+ onSave,
27
+ onTitleChange,
28
+ onDelete,
29
+ onBack,
30
+ parentId,
31
+ title,
32
+ emoji,
33
+ }) => {
35
34
  const storeApi = useStoreApi();
36
35
  const useStoreUpdater = createStoreUpdater(storeApi);
37
36
 
38
37
  const editor = usePageEditorStore((s) => s.editor);
39
- const editorState = useEditorState(editor);
40
- const currentDocId = usePageEditorStore((s) => s.currentDocId);
41
-
42
- // Use SWR hook for document fetching with caching
43
- const { isLoading: isLoadingDetail, error: swrError } = useFileStore((s) =>
44
- s.useFetchDocumentDetail(pageId),
45
- );
46
- const currentPage = useFileStore(documentSelectors.getDocumentById(pageId));
47
-
48
- const [editorInit, setEditorInit] = React.useState(false);
49
- const [contentInit, setContentInit] = React.useState(false);
50
- const [phaseUpdateCounter, setPhaseUpdateCounter] = React.useState(0);
51
- const lastLoadedDocIdRef = useRef<string | undefined>(undefined);
52
- const initStateRef = useRef<InitState>({
53
- phase: 'idle',
54
- targetPageId: undefined,
55
- });
56
-
57
- // Helper to transition phase and trigger re-render
58
- const transitionPhase = React.useCallback((newPhase: InitPhase) => {
59
- log(`Transitioning phase: ${initStateRef.current.phase} -> ${newPhase}`);
60
- initStateRef.current.phase = newPhase;
61
- setPhaseUpdateCounter((n) => n + 1); // Trigger re-render
62
- }, []);
63
-
64
- // Update editorState in store
65
- useEffect(() => {
66
- storeApi.setState({ editorState });
67
- }, [editorState, storeApi]);
38
+ const initMeta = usePageEditorStore((s) => s.initMeta);
68
39
 
69
40
  // Update store with props
70
- useStoreUpdater('pageId', pageId);
41
+ useStoreUpdater('documentId', pageId);
71
42
  useStoreUpdater('knowledgeBaseId', knowledgeBaseId);
72
43
  useStoreUpdater('onDocumentIdChange', onDocumentIdChange);
44
+ useStoreUpdater('onEmojiChange', onEmojiChange);
73
45
  useStoreUpdater('onSave', onSave);
46
+ useStoreUpdater('onTitleChange', onTitleChange);
74
47
  useStoreUpdater('onDelete', onDelete);
75
48
  useStoreUpdater('onBack', onBack);
76
49
  useStoreUpdater('parentId', parentId);
77
50
 
78
- // State machine effect for deterministic initialization
51
+ // Initialize meta (title/emoji) with dirty tracking
79
52
  useEffect(() => {
80
- const state = initStateRef.current;
81
-
82
- // Phase handler functions
83
- const handleIdlePhase = () => {
84
- // Check if we can start initialization
85
- if (!pageId || !editor || !editorInit) {
86
- log('idle: Waiting for prerequisites', { editor: !!editor, editorInit, pageId });
87
- return;
88
- }
89
-
90
- // Transition to waiting-for-data
91
- log('idle -> waiting-for-data:', pageId);
92
-
93
- // Reset UI state
94
- setContentInit(false);
95
- storeApi.setState({
96
- currentTitle: '',
97
- isLoadingContent: true,
98
- wordCount: 0,
99
- });
100
-
101
- transitionPhase('waiting-for-data');
102
- };
103
-
104
- const handleWaitingForDataPhase = () => {
105
- // Check for errors
106
- if (swrError && !isLoadingDetail) {
107
- log('waiting-for-data: Error occurred', swrError);
108
- initStateRef.current.error = swrError as Error;
109
- storeApi.setState({ isLoadingContent: false });
110
- transitionPhase('error');
111
- return;
112
- }
113
-
114
- // Wait for SWR to finish loading
115
- if (isLoadingDetail) {
116
- log('waiting-for-data: Still loading...');
117
- return;
118
- }
119
-
120
- // Check if we have data
121
- if (!currentPage) {
122
- log('waiting-for-data: No data available yet');
123
- return;
124
- }
125
-
126
- // Transition to initializing
127
- log('waiting-for-data -> initializing');
128
- transitionPhase('initializing');
129
- };
130
-
131
- const handleInitializingPhase = () => {
132
- // Check if already initialized for this pageId
133
- if (lastLoadedDocIdRef.current === pageId && currentDocId === pageId) {
134
- log('initializing: Already initialized, moving to loading-content');
135
- transitionPhase('loading-content');
136
- return;
137
- }
138
-
139
- // Set metadata
140
- log('initializing: Setting metadata for pageId:', pageId, {
141
- hasEditorData: !!currentPage?.editorData,
142
- title: currentPage?.title,
143
- });
144
-
145
- lastLoadedDocIdRef.current = pageId;
146
- setContentInit(false);
147
-
148
- storeApi.setState({
149
- currentDocId: pageId,
150
- currentEmoji: currentPage?.metadata?.emoji,
151
- currentTitle: currentPage?.title || '',
152
- });
153
-
154
- // Transition to loading-content
155
- log('initializing -> loading-content');
156
- transitionPhase('loading-content');
157
- };
158
-
159
- const handleLoadingContentPhase = () => {
160
- // Prerequisites check
161
- if (!editor || !editorInit || contentInit) {
162
- log('loading-content: Waiting', { contentInit, editor: !!editor, editorInit });
163
- return;
164
- }
165
-
166
- // Safety check: Prevent loading stale content
167
- const currentState = storeApi.getState();
168
- if (currentState.currentDocId && currentState.currentDocId !== pageId) {
169
- log('loading-content: currentDocId mismatch, aborting', {
170
- currentDocId: currentState.currentDocId,
171
- pageId,
172
- });
173
- initStateRef.current.error = new Error('Document ID mismatch');
174
- storeApi.setState({ isLoadingContent: false });
175
- transitionPhase('error');
176
- return;
177
- }
178
-
179
- // Load content (defer to avoid flushSync warning)
180
- log('loading-content: Queueing content load');
181
-
182
- queueMicrotask(() => {
183
- try {
184
- // Re-check state in case pageId changed during microtask
185
- if (initStateRef.current.targetPageId !== pageId) {
186
- log('loading-content: PageId changed during queue, aborting');
187
- return;
188
- }
189
-
190
- log('Loading content for page:', pageId);
191
-
192
- // Helper to calculate word count
193
- const calculateWordCount = (text: string) =>
194
- text.trim().split(/\s+/).filter(Boolean).length;
195
-
196
- storeApi.setState({ lastUpdatedTime: null });
197
-
198
- // Check if editorData is valid and non-empty
199
- const hasValidEditorData =
200
- currentPage?.editorData &&
201
- typeof currentPage.editorData === 'object' &&
202
- Object.keys(currentPage.editorData).length > 0;
203
-
204
- // Load from editorData if available
205
- if (hasValidEditorData) {
206
- log('Loading from editorData');
207
- editor.setDocument('json', JSON.stringify(currentPage.editorData));
208
- const textContent = currentPage.content || '';
209
- storeApi.setState({ wordCount: calculateWordCount(textContent) });
210
- } else if (currentPage?.content && currentPage.content.trim()) {
211
- log('Loading from content - no valid editorData found');
212
- editor.setDocument('markdown', currentPage.content);
213
- storeApi.setState({ wordCount: calculateWordCount(currentPage.content) });
214
- } else if (currentPage?.pages) {
215
- // Fallback to pages content
216
- const pagesContent = currentPage.pages
217
- .map((page) => page.pageContent)
218
- .join('\n\n')
219
- .trim();
220
- if (pagesContent) {
221
- log('Loading from pages content');
222
- editor.setDocument('markdown', pagesContent);
223
- storeApi.setState({ wordCount: calculateWordCount(pagesContent) });
224
- } else {
225
- log('Clearing editor - empty pages');
226
- editor.setDocument('markdown', ' ');
227
- storeApi.setState({ wordCount: 0 });
228
- }
229
- } else {
230
- // Empty document or temp page - clear editor with minimal content
231
- log('Clearing editor - empty/new page');
232
- editor.setDocument('markdown', ' ');
233
- storeApi.setState({ wordCount: 0 });
234
- }
235
-
236
- setContentInit(true);
237
- storeApi.setState({ isLoadingContent: false });
238
-
239
- // Transition to ready
240
- log('loading-content -> ready');
241
- transitionPhase('ready');
242
- } catch (error) {
243
- log('Failed to load editor content:', error);
244
- storeApi.setState({ isLoadingContent: false });
245
- initStateRef.current.error = error as Error;
246
- transitionPhase('error');
247
- }
248
- });
249
- };
250
-
251
- const handleErrorPhase = () => {
252
- const error = initStateRef.current.error;
253
- log('error phase:', error?.message);
254
- // Error state is sticky until pageId changes
255
- };
256
-
257
- // Reset to idle if pageId changes
258
- if (pageId !== state.targetPageId) {
259
- log('PageId changed, resetting to idle', { from: state.targetPageId, to: pageId });
260
- initStateRef.current = { phase: 'idle', targetPageId: pageId };
261
- setContentInit(false);
262
- return;
263
- }
264
-
265
- // Early exit if already ready
266
- if (state.phase === 'ready') return;
267
-
268
- // Execute phase handler
269
- switch (state.phase) {
270
- case 'idle': {
271
- handleIdlePhase();
272
- break;
273
- }
274
- case 'waiting-for-data': {
275
- handleWaitingForDataPhase();
276
- break;
277
- }
278
- case 'initializing': {
279
- handleInitializingPhase();
280
- break;
281
- }
282
- case 'loading-content': {
283
- handleLoadingContentPhase();
284
- break;
285
- }
286
- case 'error': {
287
- handleErrorPhase();
288
- break;
289
- }
290
- }
291
- }, [
292
- contentInit,
293
- currentDocId,
294
- currentPage,
295
- editor,
296
- editorInit,
297
- isLoadingDetail,
298
- pageId,
299
- phaseUpdateCounter,
300
- storeApi,
301
- swrError,
302
- transitionPhase,
303
- ]);
304
-
305
- // Track editor initialization
306
- useEffect(() => {
307
- if (editor && !editorInit) {
308
- setEditorInit(true);
309
- }
310
- }, [editor, editorInit]);
53
+ initMeta(title, emoji);
54
+ }, [pageId, title, emoji]);
311
55
 
312
56
  // Connect editor to page agent runtime
313
57
  useEffect(() => {
314
58
  if (editor) {
315
- // for easier debug , mount editor instance to window
316
- window.__editor = editor;
317
59
  pageAgentRuntime.setEditor(editor);
318
60
  }
319
61
  return () => {
@@ -321,35 +63,20 @@ const StoreUpdater = memo<StoreUpdaterProps>(
321
63
  };
322
64
  }, [editor]);
323
65
 
324
- // Connect title handlers to page agent runtime
66
+ // Connect title handlers and document ID to page agent runtime
325
67
  useEffect(() => {
326
- const titleSetter = (title: string) => {
327
- storeApi.setState({ currentTitle: title });
328
- };
329
-
330
68
  const titleGetter = () => {
331
- return storeApi.getState().currentTitle;
69
+ return storeApi.getState().title || '';
332
70
  };
333
71
 
334
- pageAgentRuntime.setTitleHandlers(titleSetter, titleGetter);
72
+ pageAgentRuntime.setCurrentDocId(pageId);
73
+ pageAgentRuntime.setTitleHandlers(storeApi.getState().setTitle, titleGetter);
335
74
 
336
75
  return () => {
337
- pageAgentRuntime.setTitleHandlers(null, null);
338
- };
339
- }, [storeApi]);
340
-
341
- // Update current document ID in page agent runtime when page changes
342
- useEffect(() => {
343
- // Use currentDocId (which includes temp docs) or fallback to pageId
344
- const activeId = currentDocId || pageId;
345
- log('Updating currentDocId in page agent runtime:', activeId);
346
- pageAgentRuntime.setCurrentDocId(activeId);
347
-
348
- return () => {
349
- log('Clearing currentDocId on unmount');
350
76
  pageAgentRuntime.setCurrentDocId(undefined);
77
+ pageAgentRuntime.setTitleHandlers(null, null);
351
78
  };
352
- }, [currentDocId, pageId]);
79
+ }, [pageId, storeApi]);
353
80
 
354
81
  return null;
355
82
  },
@@ -11,16 +11,16 @@ import { useGlobalStore } from '@/store/global';
11
11
  import { globalGeneralSelectors } from '@/store/global/selectors';
12
12
  import { truncateByWeightedLength } from '@/utils/textLength';
13
13
 
14
- import { usePageEditorStore } from '../store';
14
+ import { usePageEditorStore } from './store';
15
15
 
16
- const Title = memo(() => {
16
+ const TitleSection = memo(() => {
17
17
  const { t } = useTranslation('file');
18
18
  const locale = useGlobalStore(globalGeneralSelectors.currentLanguage);
19
19
 
20
- const currentEmoji = usePageEditorStore((s) => s.currentEmoji);
21
- const currentTitle = usePageEditorStore((s) => s.currentTitle);
22
- const setCurrentEmoji = usePageEditorStore((s) => s.setCurrentEmoji);
23
- const setCurrentTitle = usePageEditorStore((s) => s.setCurrentTitle);
20
+ const emoji = usePageEditorStore((s) => s.emoji);
21
+ const title = usePageEditorStore((s) => s.title);
22
+ const setEmoji = usePageEditorStore((s) => s.setEmoji);
23
+ const setTitle = usePageEditorStore((s) => s.setTitle);
24
24
  const handleTitleSubmit = usePageEditorStore((s) => s.handleTitleSubmit);
25
25
 
26
26
  const [isHoveringTitle, setIsHoveringTitle] = useState(false);
@@ -41,16 +41,16 @@ const Title = memo(() => {
41
41
  }}
42
42
  >
43
43
  {/* Emoji picker above Choose Icon button */}
44
- {(currentEmoji || showEmojiPicker) && (
44
+ {(emoji || showEmojiPicker) && (
45
45
  <EmojiPicker
46
46
  allowDelete
47
47
  locale={locale}
48
- onChange={(emoji) => {
49
- setCurrentEmoji(emoji);
48
+ onChange={(e) => {
49
+ setEmoji(e);
50
50
  setShowEmojiPicker(false);
51
51
  }}
52
52
  onDelete={() => {
53
- setCurrentEmoji(undefined);
53
+ setEmoji(undefined);
54
54
  setShowEmojiPicker(false);
55
55
  }}
56
56
  onOpenChange={(open) => {
@@ -60,16 +60,16 @@ const Title = memo(() => {
60
60
  shape={'square'}
61
61
  size={72}
62
62
  title={t('pageEditor.chooseIcon')}
63
- value={currentEmoji}
63
+ value={emoji}
64
64
  />
65
65
  )}
66
66
 
67
67
  {/* Choose Icon button - only shown when no emoji */}
68
- {!currentEmoji && !showEmojiPicker && (
68
+ {!emoji && !showEmojiPicker && (
69
69
  <Button
70
70
  icon={<Icon icon={SmilePlus} />}
71
71
  onClick={() => {
72
- setCurrentEmoji('📄');
72
+ setEmoji('📄');
73
73
  setShowEmojiPicker(true);
74
74
  }}
75
75
  size="small"
@@ -89,7 +89,7 @@ const Title = memo(() => {
89
89
  autoSize={{ minRows: 1 }}
90
90
  onChange={(e) => {
91
91
  const truncated = truncateByWeightedLength(e.target.value, 100);
92
- setCurrentTitle(truncated);
92
+ setTitle(truncated);
93
93
  }}
94
94
  onKeyDown={(e) => {
95
95
  if (e.key === 'Enter') {
@@ -105,11 +105,11 @@ const Title = memo(() => {
105
105
  resize: 'none',
106
106
  width: '100%',
107
107
  }}
108
- value={currentTitle}
108
+ value={title}
109
109
  variant={'borderless'}
110
110
  />
111
111
  </Flexbox>
112
112
  );
113
113
  });
114
114
 
115
- export default Title;
115
+ export default TitleSection;