@bsg-export/solid 1.0.10

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.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * ExportButton - 开箱即用的导出按钮组件 (Solid.js)
3
+ *
4
+ * 自动管理 WASM 初始化、导出状态和进度显示。
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { ExportButton, ExportFormat } from '@bsg-export/solid';
9
+ *
10
+ * <ExportButton tableId="my-table" filename="报表.xlsx" format={ExportFormat.Xlsx}>
11
+ * 导出 Excel
12
+ * </ExportButton>
13
+ * ```
14
+ */
15
+ import { type JSX, type ParentProps } from 'solid-js';
16
+ import type { ExportFormat } from '@bsg-export/types';
17
+ /** ExportButton 组件的 Props */
18
+ export interface ExportButtonProps {
19
+ /** 要导出的 HTML 表格元素的 ID */
20
+ tableId: string;
21
+ /** 导出文件名 */
22
+ filename?: string;
23
+ /** 导出格式 */
24
+ format?: ExportFormat;
25
+ /** 是否排除隐藏行/列 */
26
+ excludeHidden?: boolean;
27
+ /** 是否添加 UTF-8 BOM(仅 CSV 有效) */
28
+ withBom?: boolean;
29
+ /** 是否禁用按钮 */
30
+ disabled?: boolean;
31
+ /** 导出成功回调 */
32
+ onExportSuccess?: () => void;
33
+ /** 导出失败回调 */
34
+ onExportError?: (error: Error) => void;
35
+ /** 进度变化回调 */
36
+ onExportProgress?: (progress: number) => void;
37
+ /** 初始化中的提示文本 */
38
+ initializingText?: string;
39
+ /** 导出中的提示文本(支持 {progress} 占位符) */
40
+ loadingText?: string;
41
+ /** 按钮的 CSS class */
42
+ class?: string;
43
+ /** 按钮的内联样式 */
44
+ style?: string | JSX.CSSProperties;
45
+ }
46
+ /**
47
+ * 导出按钮组件
48
+ *
49
+ * 封装了 WASM 初始化和导出逻辑,通过 props 配置导出参数。
50
+ */
51
+ export declare function ExportButton(props: ParentProps<ExportButtonProps>): JSX.Element;
52
+ //# sourceMappingURL=ExportButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportButton.d.ts","sourceRoot":"","sources":["../src/ExportButton.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAgB,KAAK,GAAG,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,6BAA6B;AAC7B,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,gBAAgB;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa;IACb,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,aAAa;IACb,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACvC,aAAa;IACb,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,gBAAgB;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC;CACpC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,iBAAiB,CAAC,eAsDjE"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * ExportButton - 开箱即用的导出按钮组件 (Solid.js)
3
+ *
4
+ * 自动管理 WASM 初始化、导出状态和进度显示。
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { ExportButton, ExportFormat } from '@bsg-export/solid';
9
+ *
10
+ * <ExportButton tableId="my-table" filename="报表.xlsx" format={ExportFormat.Xlsx}>
11
+ * 导出 Excel
12
+ * </ExportButton>
13
+ * ```
14
+ */
15
+ import { createEffect } from 'solid-js';
16
+ import { createExporter } from './create-exporter';
17
+ /**
18
+ * 导出按钮组件
19
+ *
20
+ * 封装了 WASM 初始化和导出逻辑,通过 props 配置导出参数。
21
+ */
22
+ export function ExportButton(props) {
23
+ const { initialized, loading, progress, error, exportTable } = createExporter();
24
+ const initText = () => props.initializingText ?? '初始化中...';
25
+ const loadText = () => props.loadingText ?? '导出中 {progress}%';
26
+ // 监听错误并触发回调
27
+ createEffect(() => {
28
+ const err = error();
29
+ if (err && props.onExportError) {
30
+ props.onExportError(err);
31
+ }
32
+ });
33
+ // 监听进度变化并触发回调
34
+ createEffect(() => {
35
+ const p = progress();
36
+ if (props.onExportProgress) {
37
+ props.onExportProgress(p);
38
+ }
39
+ });
40
+ /** 处理点击 */
41
+ const handleClick = () => {
42
+ const success = exportTable({
43
+ tableId: props.tableId,
44
+ filename: props.filename,
45
+ format: props.format,
46
+ excludeHidden: props.excludeHidden,
47
+ withBom: props.withBom,
48
+ });
49
+ if (success && props.onExportSuccess) {
50
+ props.onExportSuccess();
51
+ }
52
+ };
53
+ /** 渲染按钮文本 */
54
+ const renderText = () => {
55
+ if (!initialized())
56
+ return initText();
57
+ if (loading())
58
+ return loadText().replace('{progress}', Math.round(progress()).toString());
59
+ return props.children ?? '导出';
60
+ };
61
+ return (<button class={props.class} style={props.style} disabled={props.disabled || !initialized() || loading()} onClick={handleClick}>
62
+ {renderText()}
63
+ </button>);
64
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * createExporter - WASM 导出管理 Primitive
3
+ *
4
+ * 自动管理 WASM 初始化生命周期,提供类型安全的导出方法和响应式信号。
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { createExporter } from '@bsg-export/solid';
9
+ *
10
+ * function App() {
11
+ * const { initialized, loading, progress, exportTable } = createExporter();
12
+ *
13
+ * return (
14
+ * <button onClick={() => exportTable({ tableId: 'my-table', filename: '报表.xlsx' })}
15
+ * disabled={!initialized() || loading()}>
16
+ * {loading() ? `导出中 ${progress()}%` : '导出 Excel'}
17
+ * </button>
18
+ * );
19
+ * }
20
+ * ```
21
+ */
22
+ import { type Accessor } from 'solid-js';
23
+ import type { ExportDataOptions, ExportTableOptions, ExportTablesXlsxOptions, ExportCsvBatchOptions, ExportXlsxBatchOptions, ExportTablesBatchOptions, DataRow } from '@bsg-export/types';
24
+ /** createExporter 返回值 */
25
+ export interface CreateExporterReturn {
26
+ /** WASM 是否已初始化完成 */
27
+ initialized: Accessor<boolean>;
28
+ /** 是否正在导出 */
29
+ loading: Accessor<boolean>;
30
+ /** 导出进度 (0-100) */
31
+ progress: Accessor<number>;
32
+ /** 错误信息 */
33
+ error: Accessor<Error | null>;
34
+ /** 导出 HTML 表格 */
35
+ exportTable: (options: ExportTableOptions) => boolean;
36
+ /** 从 JS 数组直接导出 */
37
+ exportData: (data: DataRow[], options?: ExportDataOptions) => boolean;
38
+ /** 多工作表同步导出 */
39
+ exportTablesXlsx: (options: ExportTablesXlsxOptions) => boolean;
40
+ /** 分批异步导出 CSV */
41
+ exportCsvBatch: (options: ExportCsvBatchOptions) => Promise<boolean>;
42
+ /** 分批异步导出 XLSX */
43
+ exportXlsxBatch: (options: ExportXlsxBatchOptions) => Promise<boolean>;
44
+ /** 多工作表分批异步导出 */
45
+ exportTablesBatch: (options: ExportTablesBatchOptions) => Promise<boolean>;
46
+ }
47
+ /**
48
+ * WASM 导出管理 Primitive
49
+ *
50
+ * 自动初始化 WASM 模块,提供类型安全的导出方法,
51
+ * 管理 loading / progress / error 响应式信号。
52
+ */
53
+ export declare function createExporter(): CreateExporterReturn;
54
+ //# sourceMappingURL=create-exporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-exporter.d.ts","sourceRoot":"","sources":["../src/create-exporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAoC,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EAExB,OAAO,EACR,MAAM,mBAAmB,CAAC;AAE3B,yBAAyB;AACzB,MAAM,WAAW,oBAAoB;IACnC,oBAAoB;IACpB,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,aAAa;IACb,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,mBAAmB;IACnB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3B,WAAW;IACX,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,iBAAiB;IACjB,WAAW,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC;IACtD,kBAAkB;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACtE,eAAe;IACf,gBAAgB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC;IAChE,iBAAiB;IACjB,cAAc,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,kBAAkB;IAClB,eAAe,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvE,iBAAiB;IACjB,iBAAiB,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5E;AA6BD;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,oBAAoB,CA6JrD"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * createExporter - WASM 导出管理 Primitive
3
+ *
4
+ * 自动管理 WASM 初始化生命周期,提供类型安全的导出方法和响应式信号。
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { createExporter } from '@bsg-export/solid';
9
+ *
10
+ * function App() {
11
+ * const { initialized, loading, progress, exportTable } = createExporter();
12
+ *
13
+ * return (
14
+ * <button onClick={() => exportTable({ tableId: 'my-table', filename: '报表.xlsx' })}
15
+ * disabled={!initialized() || loading()}>
16
+ * {loading() ? `导出中 ${progress()}%` : '导出 Excel'}
17
+ * </button>
18
+ * );
19
+ * }
20
+ * ```
21
+ */
22
+ import { createSignal, onMount, onCleanup } from 'solid-js';
23
+ /** WASM 模块缓存 */
24
+ let wasmModule = null;
25
+ let wasmInitPromise = null;
26
+ /**
27
+ * 初始化 WASM 模块(单例模式)
28
+ */
29
+ async function initWasm() {
30
+ if (wasmModule)
31
+ return wasmModule;
32
+ if (!wasmInitPromise) {
33
+ wasmInitPromise = import('belobog-stellar-grid')
34
+ .then(async (mod) => {
35
+ await mod.default();
36
+ wasmModule = mod;
37
+ return mod;
38
+ })
39
+ .catch((err) => {
40
+ // 初始化失败时重置 Promise,允许后续调用重试
41
+ wasmInitPromise = null;
42
+ throw err;
43
+ });
44
+ }
45
+ return wasmInitPromise;
46
+ }
47
+ /**
48
+ * WASM 导出管理 Primitive
49
+ *
50
+ * 自动初始化 WASM 模块,提供类型安全的导出方法,
51
+ * 管理 loading / progress / error 响应式信号。
52
+ */
53
+ export function createExporter() {
54
+ const [initialized, setInitialized] = createSignal(false);
55
+ const [loading, setLoading] = createSignal(false);
56
+ const [progress, setProgress] = createSignal(0);
57
+ const [error, setError] = createSignal(null);
58
+ let alive = true;
59
+ onMount(() => {
60
+ initWasm()
61
+ .then(() => {
62
+ if (alive)
63
+ setInitialized(true);
64
+ })
65
+ .catch((err) => {
66
+ if (alive)
67
+ setError(err instanceof Error ? err : new Error(String(err)));
68
+ });
69
+ });
70
+ onCleanup(() => {
71
+ alive = false;
72
+ });
73
+ /** 创建进度回调(自动更新 progress 状态) */
74
+ const createProgressCallback = () => {
75
+ return (p) => {
76
+ if (alive)
77
+ setProgress(p);
78
+ };
79
+ };
80
+ /** 包装同步导出操作 */
81
+ const wrapSync = (fn) => {
82
+ if (!initialized() || !wasmModule)
83
+ return false;
84
+ setLoading(true);
85
+ setProgress(0);
86
+ setError(null);
87
+ try {
88
+ fn();
89
+ if (alive)
90
+ setProgress(100);
91
+ return true;
92
+ }
93
+ catch (err) {
94
+ if (alive)
95
+ setError(err instanceof Error ? err : new Error(String(err)));
96
+ return false;
97
+ }
98
+ finally {
99
+ if (alive)
100
+ setLoading(false);
101
+ }
102
+ };
103
+ /** 包装异步导出操作 */
104
+ const wrapAsync = async (fn) => {
105
+ if (!initialized() || !wasmModule)
106
+ return false;
107
+ setLoading(true);
108
+ setProgress(0);
109
+ setError(null);
110
+ try {
111
+ await fn();
112
+ if (alive)
113
+ setProgress(100);
114
+ return true;
115
+ }
116
+ catch (err) {
117
+ if (alive)
118
+ setError(err instanceof Error ? err : new Error(String(err)));
119
+ return false;
120
+ }
121
+ finally {
122
+ if (alive)
123
+ setLoading(false);
124
+ }
125
+ };
126
+ /** 导出 HTML 表格 */
127
+ const exportTable = (options) => {
128
+ return wrapSync(() => {
129
+ wasmModule.export_table(options.tableId, options.filename, options.format, options.excludeHidden, createProgressCallback(), options.withBom, options.strictProgressCallback);
130
+ });
131
+ };
132
+ /** 从 JS 数组直接导出 */
133
+ const exportData = (data, options) => {
134
+ return wrapSync(() => {
135
+ const opts = options
136
+ ? { ...options, progressCallback: options.progressCallback ?? createProgressCallback() }
137
+ : { progressCallback: createProgressCallback() };
138
+ wasmModule.export_data(data, opts);
139
+ });
140
+ };
141
+ /** 多工作表同步导出 */
142
+ const exportTablesXlsx = (options) => {
143
+ return wrapSync(() => {
144
+ wasmModule.export_tables_xlsx(options.sheets, options.filename, createProgressCallback(), options.strictProgressCallback);
145
+ });
146
+ };
147
+ /** 分批异步导出 CSV */
148
+ const exportCsvBatch = async (options) => {
149
+ return await wrapAsync(async () => {
150
+ await wasmModule.export_table_to_csv_batch(options.tableId, options.tbodyId, options.filename, options.batchSize, options.excludeHidden, createProgressCallback(), options.withBom, options.strictProgressCallback);
151
+ });
152
+ };
153
+ /** 分批异步导出 XLSX */
154
+ const exportXlsxBatch = async (options) => {
155
+ return await wrapAsync(async () => {
156
+ await wasmModule.export_table_to_xlsx_batch(options.tableId, options.tbodyId, options.filename, options.batchSize, options.excludeHidden, createProgressCallback(), options.strictProgressCallback);
157
+ });
158
+ };
159
+ /** 多工作表分批异步导出 */
160
+ const exportTablesBatch = async (options) => {
161
+ return await wrapAsync(async () => {
162
+ await wasmModule.export_tables_to_xlsx_batch(options.sheets, options.filename, options.batchSize, createProgressCallback(), options.strictProgressCallback);
163
+ });
164
+ };
165
+ return {
166
+ initialized,
167
+ loading,
168
+ progress,
169
+ error,
170
+ exportTable,
171
+ exportData,
172
+ exportTablesXlsx,
173
+ exportCsvBatch,
174
+ exportXlsxBatch,
175
+ exportTablesBatch,
176
+ };
177
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * createWorkerExporter - Worker 线程导出管理 Primitive
3
+ *
4
+ * 将 CSV/XLSX 生成移至 Worker 线程,主线程不阻塞。
5
+ * 用户需要传入一个创建 Worker 实例的工厂函数。
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { createWorkerExporter } from '@bsg-export/solid';
10
+ *
11
+ * // Vite
12
+ * import ExportWorkerScript from '@bsg-export/worker/worker?worker';
13
+ *
14
+ * function App() {
15
+ * const { initialized, loading, progress, exportData } =
16
+ * createWorkerExporter(() => new ExportWorkerScript());
17
+ *
18
+ * return (
19
+ * <button disabled={!initialized() || loading()}
20
+ * onClick={() => exportData(data, { columns, filename: '报表.xlsx', format: 1 })}>
21
+ * {loading() ? `导出中 ${Math.round(progress())}%` : '导出'}
22
+ * </button>
23
+ * );
24
+ * }
25
+ * ```
26
+ */
27
+ import { type Accessor } from 'solid-js';
28
+ import type { ExportDataOptions, DataRow } from '@bsg-export/types';
29
+ /** createWorkerExporter 返回值 */
30
+ export interface CreateWorkerExporterReturn {
31
+ /** Worker 中的 WASM 是否已初始化完成 */
32
+ initialized: Accessor<boolean>;
33
+ /** 是否正在导出 */
34
+ loading: Accessor<boolean>;
35
+ /** 导出进度 (0-100) */
36
+ progress: Accessor<number>;
37
+ /** 错误信息 */
38
+ error: Accessor<Error | null>;
39
+ /** 在 Worker 中生成文件并触发下载 */
40
+ exportData: (data: DataRow[], options?: Omit<ExportDataOptions, 'progressCallback'>) => Promise<boolean>;
41
+ /** 在 Worker 中生成文件字节(不触发下载) */
42
+ generateBytes: (data: DataRow[], options?: Omit<ExportDataOptions, 'progressCallback'>) => Promise<Uint8Array | null>;
43
+ /** 销毁 Worker */
44
+ terminate: () => void;
45
+ }
46
+ /**
47
+ * Worker 线程导出管理 Primitive
48
+ *
49
+ * 接收一个 Worker 工厂函数,自动管理 Worker 生命周期和 WASM 初始化。
50
+ * 导出计算在 Worker 线程执行,主线程保持响应。
51
+ *
52
+ * @param createWorker - 创建 Worker 实例的工厂函数
53
+ */
54
+ export declare function createWorkerExporter(createWorker: () => Worker): CreateWorkerExporterReturn;
55
+ //# sourceMappingURL=create-worker-exporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-worker-exporter.d.ts","sourceRoot":"","sources":["../src/create-worker-exporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAoC,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,KAAK,EACV,iBAAiB,EAEjB,OAAO,EACR,MAAM,mBAAmB,CAAC;AAE3B,+BAA+B;AAC/B,MAAM,WAAW,0BAA0B;IACzC,8BAA8B;IAC9B,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC/B,aAAa;IACb,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,mBAAmB;IACnB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3B,WAAW;IACX,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,0BAA0B;IAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzG,8BAA8B;IAC9B,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACtH,gBAAgB;IAChB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAiCD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,MAAM,GAAG,0BAA0B,CAuM3F"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * createWorkerExporter - Worker 线程导出管理 Primitive
3
+ *
4
+ * 将 CSV/XLSX 生成移至 Worker 线程,主线程不阻塞。
5
+ * 用户需要传入一个创建 Worker 实例的工厂函数。
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * import { createWorkerExporter } from '@bsg-export/solid';
10
+ *
11
+ * // Vite
12
+ * import ExportWorkerScript from '@bsg-export/worker/worker?worker';
13
+ *
14
+ * function App() {
15
+ * const { initialized, loading, progress, exportData } =
16
+ * createWorkerExporter(() => new ExportWorkerScript());
17
+ *
18
+ * return (
19
+ * <button disabled={!initialized() || loading()}
20
+ * onClick={() => exportData(data, { columns, filename: '报表.xlsx', format: 1 })}>
21
+ * {loading() ? `导出中 ${Math.round(progress())}%` : '导出'}
22
+ * </button>
23
+ * );
24
+ * }
25
+ * ```
26
+ */
27
+ import { createSignal, onMount, onCleanup } from 'solid-js';
28
+ let requestCounter = 0;
29
+ function generateId() {
30
+ return `req_${++requestCounter}_${Date.now()}`;
31
+ }
32
+ /**
33
+ * Worker 线程导出管理 Primitive
34
+ *
35
+ * 接收一个 Worker 工厂函数,自动管理 Worker 生命周期和 WASM 初始化。
36
+ * 导出计算在 Worker 线程执行,主线程保持响应。
37
+ *
38
+ * @param createWorker - 创建 Worker 实例的工厂函数
39
+ */
40
+ export function createWorkerExporter(createWorker) {
41
+ const [initialized, setInitialized] = createSignal(false);
42
+ const [loading, setLoading] = createSignal(false);
43
+ const [progress, setProgress] = createSignal(0);
44
+ const [error, setError] = createSignal(null);
45
+ let worker = null;
46
+ const pending = new Map();
47
+ let alive = true;
48
+ /** 处理 Worker 消息 */
49
+ const handleMessage = (event) => {
50
+ if (!alive)
51
+ return;
52
+ const { type, id, bytes, message, progress: prog } = event.data;
53
+ const req = pending.get(id);
54
+ if (!req)
55
+ return;
56
+ switch (type) {
57
+ case 'ready':
58
+ pending.delete(id);
59
+ req.resolve(new ArrayBuffer(0));
60
+ break;
61
+ case 'result':
62
+ pending.delete(id);
63
+ req.resolve(bytes);
64
+ break;
65
+ case 'error':
66
+ pending.delete(id);
67
+ req.reject(new Error(message ?? '未知错误'));
68
+ break;
69
+ case 'progress':
70
+ if (req.onProgress && prog !== undefined) {
71
+ req.onProgress(prog);
72
+ }
73
+ break;
74
+ }
75
+ };
76
+ /** 处理 Worker 错误 */
77
+ const handleError = (event) => {
78
+ if (!alive)
79
+ return;
80
+ const err = new Error(`Worker 错误: ${event.message}`);
81
+ for (const [id, req] of pending) {
82
+ req.reject(err);
83
+ pending.delete(id);
84
+ }
85
+ setError(err);
86
+ };
87
+ onMount(() => {
88
+ worker = createWorker();
89
+ worker.addEventListener('message', handleMessage);
90
+ worker.addEventListener('error', handleError);
91
+ // 发送 init 消息
92
+ const id = generateId();
93
+ const initPromise = new Promise((resolve, reject) => {
94
+ pending.set(id, { resolve, reject });
95
+ });
96
+ const request = { type: 'init', id };
97
+ worker.postMessage(request);
98
+ initPromise
99
+ .then(() => {
100
+ if (alive)
101
+ setInitialized(true);
102
+ })
103
+ .catch((err) => {
104
+ if (alive)
105
+ setError(err instanceof Error ? err : new Error(String(err)));
106
+ });
107
+ });
108
+ onCleanup(() => {
109
+ alive = false;
110
+ // 拒绝所有待处理请求
111
+ for (const [, req] of pending) {
112
+ req.reject(new Error('组件已卸载'));
113
+ }
114
+ pending.clear();
115
+ worker?.terminate();
116
+ worker = null;
117
+ });
118
+ /** 向 Worker 发送生成请求 */
119
+ const sendGenerate = (data, options) => {
120
+ if (!worker)
121
+ return Promise.reject(new Error('Worker 未创建'));
122
+ return new Promise((resolve, reject) => {
123
+ const id = generateId();
124
+ pending.set(id, {
125
+ resolve,
126
+ reject,
127
+ onProgress: (p) => {
128
+ if (alive)
129
+ setProgress(p);
130
+ },
131
+ });
132
+ const request = {
133
+ type: 'generate',
134
+ id,
135
+ data,
136
+ options: (options ?? {}),
137
+ };
138
+ worker.postMessage(request);
139
+ });
140
+ };
141
+ /** 在主线程触发文件下载 */
142
+ const downloadFile = (bytes, filename, format) => {
143
+ const isXlsx = format === 1;
144
+ const mimeType = isXlsx
145
+ ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
146
+ : 'text/csv;charset=utf-8';
147
+ const defaultExt = isXlsx ? 'xlsx' : 'csv';
148
+ let finalFilename = filename ?? `export.${defaultExt}`;
149
+ if (!finalFilename.endsWith(`.${defaultExt}`)) {
150
+ finalFilename = `${finalFilename}.${defaultExt}`;
151
+ }
152
+ const blob = new Blob([bytes.buffer], { type: mimeType });
153
+ const url = URL.createObjectURL(blob);
154
+ const anchor = document.createElement('a');
155
+ anchor.href = url;
156
+ anchor.download = finalFilename;
157
+ anchor.click();
158
+ setTimeout(() => URL.revokeObjectURL(url), 10_000);
159
+ };
160
+ /** 在 Worker 中生成文件并触发下载 */
161
+ const exportData = async (data, options) => {
162
+ if (!initialized())
163
+ return false;
164
+ setLoading(true);
165
+ setProgress(0);
166
+ setError(null);
167
+ try {
168
+ const buffer = await sendGenerate(data, options);
169
+ const bytes = new Uint8Array(buffer);
170
+ downloadFile(bytes, options?.filename, options?.format);
171
+ if (alive)
172
+ setProgress(100);
173
+ return true;
174
+ }
175
+ catch (err) {
176
+ if (alive)
177
+ setError(err instanceof Error ? err : new Error(String(err)));
178
+ return false;
179
+ }
180
+ finally {
181
+ if (alive)
182
+ setLoading(false);
183
+ }
184
+ };
185
+ /** 在 Worker 中生成文件字节(不触发下载) */
186
+ const generateBytes = async (data, options) => {
187
+ if (!initialized())
188
+ return null;
189
+ setLoading(true);
190
+ setProgress(0);
191
+ setError(null);
192
+ try {
193
+ const buffer = await sendGenerate(data, options);
194
+ if (alive)
195
+ setProgress(100);
196
+ return new Uint8Array(buffer);
197
+ }
198
+ catch (err) {
199
+ if (alive)
200
+ setError(err instanceof Error ? err : new Error(String(err)));
201
+ return null;
202
+ }
203
+ finally {
204
+ if (alive)
205
+ setLoading(false);
206
+ }
207
+ };
208
+ /** 手动销毁 Worker */
209
+ const terminate = () => {
210
+ for (const [, req] of pending) {
211
+ req.reject(new Error('Worker 已被手动销毁'));
212
+ }
213
+ pending.clear();
214
+ worker?.terminate();
215
+ worker = null;
216
+ if (alive)
217
+ setInitialized(false);
218
+ };
219
+ return {
220
+ initialized,
221
+ loading,
222
+ progress,
223
+ error,
224
+ exportData,
225
+ generateBytes,
226
+ terminate,
227
+ };
228
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @bsg-export/solid - belobog-stellar-grid 的 Solid.js 官方封装
3
+ *
4
+ * 提供基于 Solid.js 信号的导出功能封装,简化在 Solid.js 项目中使用表格导出功能。
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { createExporter } from './create-exporter';
9
+ export type { CreateExporterReturn } from './create-exporter';
10
+ export { createWorkerExporter } from './create-worker-exporter';
11
+ export type { CreateWorkerExporterReturn } from './create-worker-exporter';
12
+ export { ExportButton } from './ExportButton';
13
+ export type { ExportButtonProps } from './ExportButton';
14
+ export type { Column, MergeCellValue, CellValue, MergeableCellValue, DataRow, ExportDataOptions, SheetConfig, BatchSheetConfig, ProgressCallback, ExportTableOptions, ExportTablesXlsxOptions, ExportCsvBatchOptions, ExportXlsxBatchOptions, ExportTablesBatchOptions, } from '@bsg-export/types';
15
+ export { ExportFormat } from '@bsg-export/types';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,YAAY,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAG3E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,YAAY,EACV,MAAM,EACN,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,OAAO,EACP,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @bsg-export/solid - belobog-stellar-grid 的 Solid.js 官方封装
3
+ *
4
+ * 提供基于 Solid.js 信号的导出功能封装,简化在 Solid.js 项目中使用表格导出功能。
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ // Hook
9
+ export { createExporter } from './create-exporter';
10
+ export { createWorkerExporter } from './create-worker-exporter';
11
+ // 组件
12
+ export { ExportButton } from './ExportButton';
13
+ export { ExportFormat } from '@bsg-export/types';
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@bsg-export/solid",
3
+ "version": "1.0.10",
4
+ "description": "belobog-stellar-grid 的 Solid.js 官方封装组件",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "typecheck": "tsc --noEmit"
20
+ },
21
+ "keywords": [
22
+ "belobog",
23
+ "stellar-grid",
24
+ "solid",
25
+ "solidjs",
26
+ "export",
27
+ "table"
28
+ ],
29
+ "author": "Kurisu <makise_kurisuu@outlook.jp>",
30
+ "license": "MIT OR Apache-2.0",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/kurisu994/belobog-stellar-grid",
34
+ "directory": "packages/solid"
35
+ },
36
+ "peerDependencies": {
37
+ "belobog-stellar-grid": ">=1.0.0",
38
+ "solid-js": ">=1.8.0"
39
+ },
40
+ "dependencies": {
41
+ "@bsg-export/types": "file:../types"
42
+ },
43
+ "devDependencies": {
44
+ "solid-js": "^1.9.7",
45
+ "typescript": "^5.9.3"
46
+ }
47
+ }