@zjlab-fe/data-hub-ui 0.10.6 → 0.11.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/dist/types/components/file-uploader/context/action-registry.d.ts +59 -0
- package/dist/types/components/file-uploader/engine/queue-callbacks.d.ts +10 -1
- package/dist/types/components/file-uploader/index.d.ts +1 -1
- package/dist/types/components/file-uploader/types.d.ts +47 -11
- package/dist/types/components/menu/demo/index.d.ts +1 -0
- package/dist/types/components/menu/index.d.ts +16 -0
- package/dist/types/components/tip-tap/extensions/index.d.ts +1 -1
- package/dist/types/demo/router/index.d.ts +14 -10
- package/es/index.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { HandlerContext } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Global action registry for providing fresh context to handlers.
|
|
4
|
+
*
|
|
5
|
+
* This registry stores references to the latest upload actions (removeFile, start, etc.)
|
|
6
|
+
* and state (files). It's updated on every render by useUpload hook, ensuring that
|
|
7
|
+
* when handlers are invoked, they receive always-current references.
|
|
8
|
+
*
|
|
9
|
+
* This solves the stale closure problem where handlers registered at file-add time
|
|
10
|
+
* would capture outdated versions of functions and state.
|
|
11
|
+
*
|
|
12
|
+
* Flow:
|
|
13
|
+
* 1. useUpload hook updates actionRegistry on every render with fresh refs
|
|
14
|
+
* 2. QueueManager callbacks (queue-callbacks.ts) invoke handlers
|
|
15
|
+
* 3. Before invoking, they call actionRegistry.getContext() to get fresh utilities
|
|
16
|
+
* 4. Handler receives fresh context, avoiding stale closure issues
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // In useUpload hook (automatic):
|
|
21
|
+
* useEffect(() => {
|
|
22
|
+
* actionRegistry.update({ files, removeFile, start, ... });
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // In queue-callbacks.ts:
|
|
26
|
+
* const ctx = actionRegistry.getContext();
|
|
27
|
+
* handlers.onUploadSuccess?.(file, ctx);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare class ActionRegistry {
|
|
31
|
+
private context;
|
|
32
|
+
/**
|
|
33
|
+
* Update the stored context with fresh references.
|
|
34
|
+
* Called by useUpload hook on every render.
|
|
35
|
+
*/
|
|
36
|
+
update(context: HandlerContext): void;
|
|
37
|
+
/**
|
|
38
|
+
* Get the current context with fresh references.
|
|
39
|
+
* Returns null if context hasn't been initialized yet.
|
|
40
|
+
*/
|
|
41
|
+
getContext(): HandlerContext | null;
|
|
42
|
+
/**
|
|
43
|
+
* Check if context is available.
|
|
44
|
+
*/
|
|
45
|
+
hasContext(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Clear the context.
|
|
48
|
+
* Mainly for testing or complete reset.
|
|
49
|
+
*/
|
|
50
|
+
clear(): void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Singleton instance of the action registry.
|
|
54
|
+
* This is intentionally a module-level singleton, similar to handlerRegistry,
|
|
55
|
+
* because it needs to be accessible from queue-callbacks.ts which operates
|
|
56
|
+
* outside the React component tree.
|
|
57
|
+
*/
|
|
58
|
+
export declare const actionRegistry: ActionRegistry;
|
|
59
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Dispatch } from 'react';
|
|
2
2
|
import type { QueueCallbacks } from './queue-types';
|
|
3
|
-
import type { UploadAction } from '../types';
|
|
3
|
+
import type { UploadAction, HandlerContext } from '../types';
|
|
4
4
|
/**
|
|
5
5
|
* Dependencies required to create queue callbacks.
|
|
6
6
|
* These are injected from the React hook to maintain reactivity.
|
|
@@ -19,3 +19,12 @@ export interface QueueCallbackDeps {
|
|
|
19
19
|
* - onFileComplete: When all chunks of a file are uploaded
|
|
20
20
|
*/
|
|
21
21
|
export declare function createQueueCallbacks({ dispatch }: QueueCallbackDeps): QueueCallbacks;
|
|
22
|
+
/**
|
|
23
|
+
* Get fresh handler context from the action registry.
|
|
24
|
+
* This provides always-current references to files and upload utilities,
|
|
25
|
+
* solving the stale closure problem in handler callbacks.
|
|
26
|
+
*
|
|
27
|
+
* @returns HandlerContext with fresh references
|
|
28
|
+
* @throws Error if context not available (useUpload hook not mounted)
|
|
29
|
+
*/
|
|
30
|
+
export declare function getHandlerContext(): HandlerContext;
|
|
@@ -4,7 +4,7 @@ export { UploaderDropZone } from './components/uploader-drop-zone';
|
|
|
4
4
|
export { UploaderFileListLayout } from './components/uploader-file-list';
|
|
5
5
|
export { UploaderFileItem } from './components/uploader-file-item';
|
|
6
6
|
export { useUpload } from './hooks/use-upload';
|
|
7
|
-
export type { UploadFile, ChunkState, UploadHandlers, CallbackResult, GetUploadUrlsResult, UploadUrl, UploadConfig, AddFilesOptions, } from './types';
|
|
7
|
+
export type { UploadFile, ChunkState, UploadHandlers, HandlerContext, CallbackResult, GetUploadUrlsResult, UploadUrl, UploadConfig, AddFilesOptions, } from './types';
|
|
8
8
|
export type { DropZoneError, UploaderDropZoneClassNames, UploaderDropZoneProps, } from './components/uploader-drop-zone';
|
|
9
9
|
export type { FileWithPath } from './components/utils/directory-reader';
|
|
10
10
|
export type { FileListClassNames } from './components/uploader-file-list';
|
|
@@ -45,37 +45,73 @@ export type CallbackResult = {
|
|
|
45
45
|
success: false;
|
|
46
46
|
reason?: string;
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Context object passed to handler callbacks with fresh utilities.
|
|
50
|
+
* This solves the stale closure problem by providing always-current references.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* addFiles(files, {
|
|
55
|
+
* getHandlers: () => ({
|
|
56
|
+
* onUploadSuccess: (file, ctx) => {
|
|
57
|
+
* // Use ctx instead of closed-over values - always fresh!
|
|
58
|
+
* console.log('Current files:', ctx.files.length);
|
|
59
|
+
* ctx.removeFile(file.id);
|
|
60
|
+
* }
|
|
61
|
+
* })
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export interface HandlerContext {
|
|
66
|
+
/** Current files in the upload queue (always fresh) */
|
|
67
|
+
files: UploadFile[];
|
|
68
|
+
/** Remove a file from the queue (always fresh) */
|
|
69
|
+
removeFile: (id: string) => Promise<void>;
|
|
70
|
+
/** Start uploading a pending file (always fresh) */
|
|
71
|
+
start: (id: string) => Promise<void>;
|
|
72
|
+
/** Pause an uploading file (always fresh) */
|
|
73
|
+
pause: (id: string) => void;
|
|
74
|
+
/** Resume a paused file (always fresh) */
|
|
75
|
+
resume: (id: string) => Promise<void>;
|
|
76
|
+
/** Cancel a file upload (always fresh) */
|
|
77
|
+
cancel: (id: string) => void;
|
|
78
|
+
/** Get a specific file by ID (always fresh) */
|
|
79
|
+
getFileById: (id: string) => UploadFile | undefined;
|
|
80
|
+
}
|
|
48
81
|
/**
|
|
49
82
|
* Upload lifecycle handler callbacks
|
|
50
|
-
* These hooks allow consumers to integrate with the upload process at various stages
|
|
83
|
+
* These hooks allow consumers to integrate with the upload process at various stages.
|
|
84
|
+
*
|
|
85
|
+
* All callbacks that receive a file also receive a `ctx` (HandlerContext) parameter
|
|
86
|
+
* with fresh references to upload utilities, solving the stale closure problem.
|
|
51
87
|
*/
|
|
52
88
|
export interface UploadHandlers {
|
|
53
|
-
/** Called before requesting upload URLs. Return {
|
|
54
|
-
onBeforeUpload?: (file: UploadFile) => Promise<CallbackResult>;
|
|
89
|
+
/** Called before requesting upload URLs. Return { success: false } to cancel upload */
|
|
90
|
+
onBeforeUpload?: (file: UploadFile, ctx: HandlerContext) => Promise<CallbackResult>;
|
|
55
91
|
/** Request upload URLs from server (required) */
|
|
56
92
|
onGetUploadUrls: (fileName: string, partCount: number) => Promise<GetUploadUrlsResult>;
|
|
57
93
|
/** Called after URLs received, before chunk uploads begin */
|
|
58
|
-
onUploadStart?: (file: UploadFile) => void;
|
|
94
|
+
onUploadStart?: (file: UploadFile, ctx: HandlerContext) => void;
|
|
59
95
|
/** Called when file progress updates (0-100) */
|
|
60
|
-
onProgress?: (file: UploadFile, progress: number) => void;
|
|
96
|
+
onProgress?: (file: UploadFile, progress: number, ctx: HandlerContext) => void;
|
|
61
97
|
/** Called when a chunk upload completes (required) */
|
|
62
98
|
onPartComplete: (fileName: string, uploadId: string, partNum: number) => Promise<CallbackResult>;
|
|
63
99
|
/** Called when upload is paused */
|
|
64
|
-
onPause?: (file: UploadFile) => void;
|
|
100
|
+
onPause?: (file: UploadFile, ctx: HandlerContext) => void;
|
|
65
101
|
/** Called when upload is resumed */
|
|
66
|
-
onResume?: (file: UploadFile) => void;
|
|
102
|
+
onResume?: (file: UploadFile, ctx: HandlerContext) => void;
|
|
67
103
|
/** Called when entire file upload completes (required) */
|
|
68
104
|
onFileComplete: (fileName: string, uploadId: string) => Promise<CallbackResult>;
|
|
69
105
|
/** Called when upload is successful */
|
|
70
|
-
onUploadSuccess?: (file: UploadFile) => void;
|
|
106
|
+
onUploadSuccess?: (file: UploadFile, ctx: HandlerContext) => void;
|
|
71
107
|
/** Called when upload is cancelled */
|
|
72
108
|
onUploadCancel?: (fileName: string, uploadId: string) => Promise<CallbackResult>;
|
|
73
109
|
/** Called when file is deleted */
|
|
74
|
-
onDeleteFile?: (file: UploadFile) => Promise<CallbackResult>;
|
|
110
|
+
onDeleteFile?: (file: UploadFile, ctx: HandlerContext) => Promise<CallbackResult>;
|
|
75
111
|
/** Called when upload is retried (smart or full retry) */
|
|
76
|
-
onRetry?: (file: UploadFile, retryType: 'smart' | 'full') => void;
|
|
112
|
+
onRetry?: (file: UploadFile, retryType: 'smart' | 'full', ctx: HandlerContext) => void;
|
|
77
113
|
/** Called when an error occurs during upload */
|
|
78
|
-
onError?: (file: UploadFile, error: Error) => void;
|
|
114
|
+
onError?: (file: UploadFile, error: Error, ctx: HandlerContext) => void;
|
|
79
115
|
}
|
|
80
116
|
export interface UploadConfig {
|
|
81
117
|
/** Maximum chunk size in bytes */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function Demo(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import './index.css';
|
|
2
|
+
import type { ItemType } from 'antd/es/menu/interface';
|
|
3
|
+
export interface IProps {
|
|
4
|
+
menus: ItemType[];
|
|
5
|
+
collapsed: boolean;
|
|
6
|
+
onCollapse: (collapsed: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 左侧菜单
|
|
10
|
+
* @param menus {MenuItem[]} 菜单项目
|
|
11
|
+
* @param collapsed {boolean} 是否折叠
|
|
12
|
+
* @param onCollapse {function} 折叠回调
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
declare const MainLayoutSider: (props: IProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export default MainLayoutSider;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const editorExtensions: (placeholder?: string) => (import("@tiptap/core").Extension<import("@tiptap/starter-kit").StarterKitOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-text-style").TextStyleOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extension-text-style").ColorOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extension-text-align").TextAlignOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-highlight").HighlightOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-image").ImageOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-table").TableOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-table").TableRowOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-code-block-lowlight").CodeBlockLowlightOptions, any> | import("@tiptap/core").Extension<
|
|
1
|
+
export declare const editorExtensions: (placeholder?: string) => (import("@tiptap/core").Extension<import("@tiptap/starter-kit").StarterKitOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extension-placeholder").PlaceholderOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-text-style").TextStyleOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extension-text-style").ColorOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extension-text-align").TextAlignOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-highlight").HighlightOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-image").ImageOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-table").TableOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-table").TableRowOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-code-block-lowlight").CodeBlockLowlightOptions, any> | import("@tiptap/core").Extension<import("@tiptap/markdown").MarkdownExtensionOptions, import("@tiptap/markdown").MarkdownExtensionStorage> | import("@tiptap/core").Extension<any, any>)[];
|
|
2
2
|
export declare const readerExtensions: () => (import("@tiptap/core").Extension<import("@tiptap/starter-kit").StarterKitOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-text-style").TextStyleOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extension-text-style").ColorOptions, any> | import("@tiptap/core").Extension<import("@tiptap/extension-text-align").TextAlignOptions, any> | import("@tiptap/core").Mark<import("@tiptap/extension-highlight").HighlightOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-image").ImageOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-table").TableOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-table").TableRowOptions, any> | import("@tiptap/core").Node<import("@tiptap/extension-code-block-lowlight").CodeBlockLowlightOptions, any>)[];
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import { createBrowserRouter } from 'react-router-dom';
|
|
2
|
-
export declare const routerConfig:
|
|
3
|
-
path: string;
|
|
4
|
-
children: never[];
|
|
5
|
-
element?: undefined;
|
|
6
|
-
} | {
|
|
1
|
+
import { createBrowserRouter, createHashRouter } from 'react-router-dom';
|
|
2
|
+
export declare const routerConfig: {
|
|
7
3
|
path: string;
|
|
8
4
|
element: import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
children: {
|
|
5
|
+
children: ({
|
|
6
|
+
path: string;
|
|
7
|
+
element: import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
children?: undefined;
|
|
9
|
+
} | {
|
|
10
10
|
path: string;
|
|
11
11
|
element: import("react/jsx-runtime").JSX.Element;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
children: {
|
|
13
|
+
path: string;
|
|
14
|
+
element: import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
}[];
|
|
16
|
+
})[];
|
|
17
|
+
}[];
|
|
18
|
+
export declare const router: ReturnType<typeof createBrowserRouter | typeof createHashRouter>;
|