@canvas-components/utils 0.2.3 → 0.2.5

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/index.cjs CHANGED
@@ -33,7 +33,10 @@ var __export = (target, all) => {
33
33
  };
34
34
 
35
35
  // src/export/xlsx-runtime.ts
36
- function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
36
+ function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576, merges = []) {
37
+ const headerRows = Array.isArray(header[0]) ? header : [header];
38
+ if (headerRows.length >= maxRows)
39
+ throw new Error("XLSX \u8868\u5934\u884C\u6570\u8D85\u8FC7\u5DE5\u4F5C\u8868\u5BB9\u91CF");
37
40
  const workbook = xlsx.utils.book_new();
38
41
  let worksheet;
39
42
  let rowCount = 0;
@@ -41,7 +44,7 @@ function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
41
44
  const baseName = sheetName.replace(/[\\/?*[\]:]/g, "_").replace(/^'+|'+$/g, "") || "Sheet1";
42
45
  const addSheet = () => {
43
46
  const suffix = sheetIndex === 0 ? "" : `_${sheetIndex + 1}`;
44
- worksheet = xlsx.utils.aoa_to_sheet([header], {
47
+ worksheet = xlsx.utils.aoa_to_sheet(headerRows, {
45
48
  dense: true
46
49
  });
47
50
  xlsx.utils.book_append_sheet(
@@ -49,7 +52,8 @@ function createXlsxWriter(xlsx, header, sheetName, maxRows = 1048576) {
49
52
  worksheet,
50
53
  baseName.slice(0, 31 - suffix.length) + suffix
51
54
  );
52
- rowCount = 1;
55
+ if (merges.length && sheetIndex === 0) worksheet["!merges"] = merges;
56
+ rowCount = headerRows.length;
53
57
  sheetIndex += 1;
54
58
  };
55
59
  addSheet();
@@ -125,7 +129,7 @@ let writer;
125
129
  self.onmessage = function(event) {
126
130
  try {
127
131
  const message = event.data;
128
- if (message.type === 'init') writer = createWriter(XLSX, message.header, message.sheetName);
132
+ if (message.type === 'init') writer = createWriter(XLSX, message.header, message.sheetName, undefined, message.merges);
129
133
  else if (message.type === 'append') writer.append(message.rows);
130
134
  else if (message.type === 'finish') {
131
135
  const buffer = writer.finish();
@@ -228,8 +232,22 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
228
232
  throw new Error(
229
233
  "\u5355\u4EFD XLSX \u6570\u636E\u8D85\u8FC7\u5B89\u5168\u9650\u5236\uFF0C\u8BF7\u4F7F\u7528 exportTableToXlsx \u81EA\u52A8\u5206\u6587\u4EF6\u5BFC\u51FA"
230
234
  );
231
- const header = columns.map((column) => column.title);
232
- let textSize = header.reduce((size, title) => size + title.length, 0);
235
+ const header = params.headerRows?.length ? params.headerRows : [columns.map((column) => column.title)];
236
+ const headerRowCount = header.length;
237
+ const merges = (params.merges ?? []).flatMap((merge) => {
238
+ if (merge.e.r < headerRowCount) return [merge];
239
+ const start = Math.max(merge.s.r, headerRowCount + rangeStart);
240
+ const end = Math.min(merge.e.r, headerRowCount + rangeEnd - 1);
241
+ return end < start || end === start && merge.s.c === merge.e.c ? [] : [
242
+ {
243
+ s: { r: start - rangeStart, c: merge.s.c },
244
+ e: { r: end - rangeStart, c: merge.e.c }
245
+ }
246
+ ];
247
+ });
248
+ if (header.some((row) => row.length > columns.length))
249
+ throw new Error("XLSX \u8868\u5934\u5355\u5143\u683C\u6570\u4E0D\u80FD\u8D85\u8FC7\u5BFC\u51FA\u5217\u6570");
250
+ let textSize = header.flat().reduce((size, title) => size + title.length, 0);
233
251
  const normalizeExportCell = (value) => {
234
252
  const cell = normalizeCell(value);
235
253
  if (typeof cell === "string") {
@@ -243,7 +261,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
243
261
  }
244
262
  return cell;
245
263
  };
246
- header.forEach((title) => {
264
+ header.flat().forEach((title) => {
247
265
  if (title.length > 32767) throw new Error("XLSX \u8868\u5934\u8D85\u8FC7 32767 \u5B57\u7B26");
248
266
  });
249
267
  if (textSize > XLSX_MAX_TEXT_CHARS_PER_FILE)
@@ -295,7 +313,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
295
313
  () => fail(new Error("XLSX Worker \u542F\u52A8\u8D85\u65F6")),
296
314
  1e4
297
315
  );
298
- await request({ type: "init", header, sheetName });
316
+ await request({ type: "init", header, sheetName, merges });
299
317
  } catch {
300
318
  worker?.terminate();
301
319
  worker = void 0;
@@ -305,7 +323,7 @@ async function buildXlsxPart(params, rangeStart, rangeEnd) {
305
323
  }
306
324
  }
307
325
  checkAbort();
308
- const writer = worker ? void 0 : createXlsxWriter(XLSX__namespace, header, sheetName);
326
+ const writer = worker ? void 0 : createXlsxWriter(XLSX__namespace, header, sheetName, void 0, merges);
309
327
  const totalRows = rangeEnd - rangeStart;
310
328
  const report = (phase, completedRows) => params.onProgress?.({
311
329
  phase,
@@ -436,7 +454,7 @@ function getXlsxRowsPerFile(params) {
436
454
  throw new Error("XLSX \u5206\u6587\u4EF6\u4E0A\u9650\u5FC5\u987B\u4E3A\u6B63\u6574\u6570");
437
455
  const byCells = Math.floor(
438
456
  Math.min(cellLimit, XLSX_MAX_CELLS_PER_FILE) / Math.max(1, params.columns.length)
439
- ) - 1;
457
+ ) - (params.headerRows?.length || 1);
440
458
  if (byCells < 1) throw new Error("XLSX \u5355\u5143\u683C\u9884\u7B97\u4E0D\u8DB3\u4EE5\u5BB9\u7EB3\u8868\u5934\u548C\u4E00\u884C\u6570\u636E");
441
459
  return Math.min(rowLimit, XLSX_MAX_ROWS_PER_FILE, byCells);
442
460
  }
@@ -458,7 +476,8 @@ function buildCsvContent(params) {
458
476
  columns.map((column) => column.title),
459
477
  ...rows.map(
460
478
  (row, rowIndex) => columns.map((column) => column.value(row, rowIndex))
461
- )
479
+ ),
480
+ ...params.footerRows ?? []
462
481
  ]);
463
482
  }
464
483
  function serializeCsvRows(rows, lineBreak = "\n") {
@@ -470,7 +489,13 @@ function buildTxtContent(params) {
470
489
  const body = rows.map(
471
490
  (row, rowIndex) => columns.map((column) => normalizeTextCell(column.value(row, rowIndex))).join(" ")
472
491
  );
473
- return [header, ...body].join("\n");
492
+ return [
493
+ header,
494
+ ...body,
495
+ ...(params.footerRows ?? []).map(
496
+ (row) => row.map(normalizeTextCell).join(" ")
497
+ )
498
+ ].join("\n");
474
499
  }
475
500
  async function downloadJsonFile(params) {
476
501
  const { data, fileName, space = 2 } = params;
@@ -482,8 +507,8 @@ async function downloadJsonFile(params) {
482
507
  });
483
508
  }
484
509
  async function exportTableToCsv(params) {
485
- const { fileName, rows, columns } = params;
486
- const content = await buildCsvContentAsync({ rows, columns });
510
+ const { fileName, rows, columns, footerRows } = params;
511
+ const content = await buildCsvContentAsync({ rows, columns, footerRows });
487
512
  downloadTextFile({
488
513
  fileName: ensureExtension(fileName, "csv"),
489
514
  content,
@@ -491,8 +516,8 @@ async function exportTableToCsv(params) {
491
516
  });
492
517
  }
493
518
  async function exportTableToTxt(params) {
494
- const { fileName, rows, columns } = params;
495
- const content = await buildTxtContentAsync({ rows, columns });
519
+ const { fileName, rows, columns, footerRows } = params;
520
+ const content = await buildTxtContentAsync({ rows, columns, footerRows });
496
521
  downloadTextFile({
497
522
  fileName: ensureExtension(fileName, "txt"),
498
523
  content,
@@ -536,6 +561,9 @@ async function buildCsvContentAsync(params) {
536
561
  }
537
562
  await yieldToMainThread();
538
563
  }
564
+ for (const footer of params.footerRows ?? []) {
565
+ parts.push("\n", footer.map(escapeCsvCell).join(","));
566
+ }
539
567
  return parts.join("");
540
568
  }
541
569
  async function buildTxtContentAsync(params) {
@@ -551,6 +579,9 @@ async function buildTxtContentAsync(params) {
551
579
  }
552
580
  await yieldToMainThread();
553
581
  }
582
+ for (const footer of params.footerRows ?? []) {
583
+ parts.push("\n", footer.map(normalizeTextCell).join(" "));
584
+ }
554
585
  return parts.join("");
555
586
  }
556
587
  function escapeCsvCell(value) {
@@ -775,6 +806,34 @@ function isPointInRect(x, y, rect) {
775
806
  return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
776
807
  }
777
808
 
809
+ // src/canvas-scrollbar.ts
810
+ function resolveCanvasScrollbarAxis(options, axis) {
811
+ const override = options?.[axis];
812
+ const merged = { ...options, ...override };
813
+ const axisSize = axis === "vertical" ? merged.width : merged.height;
814
+ const requestedThickness = axisSize ?? merged.thickness;
815
+ const thickness = Number.isFinite(requestedThickness) ? Math.max(requestedThickness, 6) : 10;
816
+ return {
817
+ mode: merged.mode === "button" ? "button" : "scrollbar",
818
+ visible: options?.visible !== false && override !== false && merged.visible !== false,
819
+ thickness,
820
+ maxScrollSpeed: Number.isFinite(merged.maxScrollSpeed) && merged.maxScrollSpeed > 0 ? merged.maxScrollSpeed : 1800,
821
+ thumbColor: merged.thumbColor ?? "rgba(100, 116, 139, 0.8)",
822
+ trackColor: merged.trackColor,
823
+ buttonColor: merged.buttonColor ?? "rgba(71, 85, 105, 0.88)",
824
+ buttonBackgroundColor: merged.buttonBackgroundColor,
825
+ buttonHoverBackgroundColor: merged.buttonHoverBackgroundColor ?? "rgba(71, 85, 105, 0.09)",
826
+ buttonPressedBackgroundColor: merged.buttonPressedBackgroundColor ?? "rgba(37, 99, 235, 0.18)",
827
+ thumbRadius: Number.isFinite(merged.thumbRadius) ? Math.max(merged.thumbRadius, 0) : void 0
828
+ };
829
+ }
830
+ function resolveCanvasScrollbarHoldSpeed(elapsedMs, maxScrollSpeed) {
831
+ const maximum = Math.max(maxScrollSpeed, 1);
832
+ const initial = Math.min(240, maximum);
833
+ const progress = Math.min(Math.max(elapsedMs, 0) / 2500, 1);
834
+ return initial + (maximum - initial) * progress * progress;
835
+ }
836
+
778
837
  // src/number/precise.ts
779
838
  function addPreciseNumbers(left, right) {
780
839
  const leftParts = parseDecimal(left);
@@ -1186,6 +1245,8 @@ exports.mapRowsToExportRecords = mapRowsToExportRecords;
1186
1245
  exports.normalizeDecimalPlaces = normalizeDecimalPlaces;
1187
1246
  exports.parseChineseNumber = parseChineseNumber;
1188
1247
  exports.parseNumberValue = parseNumberValue;
1248
+ exports.resolveCanvasScrollbarAxis = resolveCanvasScrollbarAxis;
1249
+ exports.resolveCanvasScrollbarHoldSpeed = resolveCanvasScrollbarHoldSpeed;
1189
1250
  exports.resolveDateValue = resolveDateValue;
1190
1251
  exports.roundPreciseNumber = roundPreciseNumber;
1191
1252
  exports.serializeCsvRows = serializeCsvRows;