@chalabi/svelte-sheets 2.0.1 → 2.0.3

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/Readme.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Ultra fast excel sheets in the browser. Hugely inspired by JExcel, built on XLSX shoulders.
4
4
 
5
- => Find a live example [Here](https://ticruz38.github.io/svelte-sheets/)
5
+ => Find a live example [Here](https://chalabi2.github.io/svelte-sheets/)
6
6
 
7
7
  ### Motivation
8
8
 
package/dist/Sheet.svelte CHANGED
@@ -74,6 +74,8 @@ let hoverRaf = null;
74
74
  let pendingHover = null;
75
75
  let lastHover = null;
76
76
  let lastDrag = null;
77
+ let selectionRaf = null;
78
+ let extendRaf = null;
77
79
  // $: ((_) => {
78
80
  // history = history.slice(0, historyIndex);
79
81
  // history.push(data);
@@ -82,8 +84,8 @@ let lastDrag = null;
82
84
  // implement virtual list
83
85
  export let startY = 0;
84
86
  export let startX = 0;
85
- export let endY = 0;
86
- export let endX = 0;
87
+ export let endY = 50; // Initial render batch
88
+ export let endX = 20; // Initial render batch
87
89
  // virtual list state
88
90
  let height_map = [];
89
91
  let width_map = [];
@@ -225,7 +227,7 @@ function refresh(data, viewport_height, viewport_width) {
225
227
  let scrollLeft;
226
228
  let scrollTop;
227
229
  $: (function scrollX() {
228
- if (!scrollLeft || !colElements)
230
+ if (scrollLeft === undefined || !colElements)
229
231
  return;
230
232
  // if (!scrollLeft) ;
231
233
  // horizontal scrolling
@@ -259,7 +261,7 @@ $: (function scrollX() {
259
261
  right = remaining * average_width;
260
262
  })();
261
263
  $: (function scrollY() {
262
- if (!scrollTop || !rowElements)
264
+ if (scrollTop === undefined || !rowElements)
263
265
  return;
264
266
  // vertical scrolling
265
267
  for (let v = 0; v < rowElements.length; v += 1) {
@@ -313,6 +315,53 @@ onMount(() => {
313
315
  // document.addEventListener("touchmove", jexcel.touchEndControls);
314
316
  document === null || document === void 0 ? void 0 : document.addEventListener("keydown", onKeyDown);
315
317
  document === null || document === void 0 ? void 0 : document.addEventListener("keyup", onKeyUp);
318
+ // Initialize hotkeys in browser only
319
+ hotkeys("ctrl+z, command+z", function (e) {
320
+ if (isReadOnly)
321
+ return;
322
+ e.preventDefault();
323
+ cmdz = true;
324
+ if (historyIndex == 0)
325
+ return;
326
+ historyIndex -= 1;
327
+ const res = JSON.parse(history[historyIndex]);
328
+ data = res.data;
329
+ columns = res.columns;
330
+ rows = res.rows;
331
+ style = res.style;
332
+ setTimeout((_) => (cmdz = false), 10);
333
+ });
334
+ hotkeys("ctrl+shift+z, command+shift+z", function (e) {
335
+ if (isReadOnly)
336
+ return;
337
+ console.log("redo");
338
+ e.preventDefault();
339
+ cmdz = true;
340
+ if (history.length - 1 == historyIndex)
341
+ return;
342
+ historyIndex = historyIndex + 1;
343
+ const res = JSON.parse(history[historyIndex]);
344
+ data = res.data;
345
+ columns = res.columns;
346
+ rows = res.rows;
347
+ style = res.style;
348
+ setTimeout((_) => (cmdz = false), 10);
349
+ });
350
+ hotkeys("ctrl+c, command+c, ctrl+x, command+x", function (e, handler) {
351
+ var _a;
352
+ if (isReadOnly && ((_a = handler === null || handler === void 0 ? void 0 : handler.key) === null || _a === void 0 ? void 0 : _a.includes("x")))
353
+ return;
354
+ e.preventDefault();
355
+ clipboard = JSON.stringify(selected);
356
+ });
357
+ hotkeys("ctrl+v, command+v", function (e) {
358
+ if (isReadOnly)
359
+ return;
360
+ e.preventDefault();
361
+ if (!clipboard)
362
+ return;
363
+ data = pasteSelection(data, JSON.parse(clipboard), selected);
364
+ });
316
365
  }
317
366
  });
318
367
  function onMouseDown(e) {
@@ -429,56 +478,96 @@ function onMouseOver(e) {
429
478
  });
430
479
  return;
431
480
  }
432
- function onKeyUp(e) {
433
- // on keyup just reinitialize everything
434
- keypressed[e.keyCode] = false;
481
+ function getSelectionRect(start, end) {
482
+ if (!contents || !viewport)
483
+ return null;
484
+ const endC = Math.max(end.c - 1, start.c);
485
+ const endR = Math.max(end.r - 1, start.r);
486
+ const tlCell = contents.querySelector(`td[data-x="${start.c}"][data-y="${start.r}"]`);
487
+ const brCell = contents.querySelector(`td[data-x="${endC}"][data-y="${endR}"]`);
488
+ if (!tlCell || !brCell)
489
+ return null;
490
+ const containerRect = viewport.getBoundingClientRect();
491
+ const tlRect = tlCell.getBoundingClientRect();
492
+ const brRect = brCell.getBoundingClientRect();
493
+ const left = tlRect.left - containerRect.left + viewport.scrollLeft;
494
+ const top = tlRect.top - containerRect.top + viewport.scrollTop;
495
+ const right = brRect.right - containerRect.left + viewport.scrollLeft;
496
+ const bottom = brRect.bottom - containerRect.top + viewport.scrollTop;
497
+ if (!Number.isFinite(left) ||
498
+ !Number.isFinite(top) ||
499
+ !Number.isFinite(right) ||
500
+ !Number.isFinite(bottom)) {
501
+ return null;
502
+ }
503
+ return { left, top, right, bottom };
435
504
  }
436
- hotkeys("ctrl+z, command+z", function (e) {
437
- if (isReadOnly)
438
- return;
439
- e.preventDefault();
440
- cmdz = true;
441
- if (historyIndex == 0)
505
+ function updateSelectionOverlays() {
506
+ if (!mounted)
442
507
  return;
443
- historyIndex -= 1;
444
- const res = JSON.parse(history[historyIndex]);
445
- data = res.data;
446
- columns = res.columns;
447
- rows = res.rows;
448
- style = res.style;
449
- setTimeout((_) => (cmdz = false), 10);
450
- });
451
- hotkeys("ctrl+shift+z, command+shift+z", function (e) {
452
- if (isReadOnly)
453
- return;
454
- console.log("redo");
455
- e.preventDefault();
456
- cmdz = true;
457
- if (history.length - 1 == historyIndex)
508
+ const tl = (selected && decode(selected[0])) || { c: 0, r: 0 };
509
+ const br = (selected && decode(selected[1])) || { c: 0, r: 0 };
510
+ topLeft = {
511
+ c: br.c < tl.c ? br.c : tl.c,
512
+ r: br.r < tl.r ? br.r : tl.r,
513
+ };
514
+ bottomRight = {
515
+ c: br.c > tl.c ? br.c + 1 : tl.c + 1,
516
+ r: br.r > tl.r ? br.r + 1 : tl.r + 1,
517
+ };
518
+ const rect = getSelectionRect(topLeft, bottomRight);
519
+ if (!rect) {
520
+ tops.style = "display: none";
521
+ rights.style = "display: none";
522
+ bottoms.style = "display: none";
523
+ lefts.style = "display: none";
524
+ colLine.style = "display: none";
525
+ rowLine.style = "display: none";
526
+ square.style = "display: none";
458
527
  return;
459
- historyIndex = historyIndex + 1;
460
- const res = JSON.parse(history[historyIndex]);
461
- data = res.data;
462
- columns = res.columns;
463
- rows = res.rows;
464
- style = res.style;
465
- setTimeout((_) => (cmdz = false), 10);
466
- });
467
- hotkeys("ctrl+c, command+c, ctrl+x, command+x", function (e, handler) {
468
- var _a;
469
- if (isReadOnly && ((_a = handler === null || handler === void 0 ? void 0 : handler.key) === null || _a === void 0 ? void 0 : _a.includes("x")))
470
- return;
471
- e.preventDefault();
472
- clipboard = JSON.stringify(selected);
473
- });
474
- hotkeys("ctrl+v, command+v", function (e) {
475
- if (isReadOnly)
528
+ }
529
+ const { left, top, right, bottom } = rect;
530
+ tops.style = `display: block; width: ${right - left}px; left: ${left}px; top: ${top}px`;
531
+ rights.style = `display: block; height: ${bottom - top}px; left: ${right}px; top: ${top}px`;
532
+ bottoms.style = `display: block; width: ${right - left}px; left: ${left}px; top: ${bottom}px`;
533
+ lefts.style = `display: block; height: ${bottom - top}px; left: ${left}px; top: ${top}px`;
534
+ colLine.style = `display: block; width: ${right - left}px; left: ${left}px; top: ${top}px;`;
535
+ rowLine.style = `display: block; height: ${bottom - top}px; left: ${left}px; top: ${top}px`;
536
+ square.style = `display: block; left:${right}px; top:${bottom}px`;
537
+ selectWidth = right - left;
538
+ selectHeight = bottom - top;
539
+ }
540
+ function updateExtendOverlays() {
541
+ if (!extension || !extended)
476
542
  return;
477
- e.preventDefault();
478
- if (!clipboard)
543
+ const tl = (selected && decode(extended[0])) || { c: 0, r: 0 };
544
+ const br = (selected && decode(extended[1])) || { c: 0, r: 0 };
545
+ topLeft = {
546
+ c: br.c < tl.c ? br.c : tl.c,
547
+ r: br.r < tl.r ? br.r : tl.r,
548
+ };
549
+ bottomRight = {
550
+ c: br.c > tl.c ? br.c + 1 : tl.c + 1,
551
+ r: br.r > tl.r ? br.r + 1 : tl.r + 1,
552
+ };
553
+ const rect = getSelectionRect(topLeft, bottomRight);
554
+ if (!rect) {
555
+ topextend.style = "display: none";
556
+ rightextend.style = "display: none";
557
+ bottomextend.style = "display: none";
558
+ leftextend.style = "display: none";
479
559
  return;
480
- data = pasteSelection(data, JSON.parse(clipboard), selected);
481
- });
560
+ }
561
+ const { left, top, right, bottom } = rect;
562
+ topextend.style = `display: block; width: ${right - left}px; left: ${left}px; top: ${top}px`;
563
+ rightextend.style = `display: block; height: ${bottom - top}px; left: ${right}px; top: ${top}px`;
564
+ bottomextend.style = `display: block; width: ${right - left}px; left: ${left}px; top: ${bottom}px`;
565
+ leftextend.style = `display: block; height: ${bottom - top}px; left: ${left}px; top: ${top}px`;
566
+ }
567
+ function onKeyUp(e) {
568
+ // on keyup just reinitialize everything
569
+ keypressed[e.keyCode] = false;
570
+ }
482
571
  function onKeyDown(e) {
483
572
  keypressed[e.keyCode] = true;
484
573
  if (!!edition) {
@@ -546,6 +635,9 @@ $: (() => {
546
635
  }
547
636
  data = d;
548
637
  }
638
+ else if (!columns.length) {
639
+ columns = Array.from({ length: data[0].length }, () => ({}));
640
+ }
549
641
  }
550
642
  // Adjust minimal dimensions
551
643
  var j = 0;
@@ -581,82 +673,25 @@ let rowLine;
581
673
  let square;
582
674
  let squareX;
583
675
  let squareY;
584
- let topLeft;
585
- let bottomRight;
586
- $: {
587
- if (extension && extended) {
588
- let tl = (selected && decode(extended[0])) || { c: 0, r: 0 };
589
- let br = (selected && decode(extended[1])) || { c: 0, r: 0 };
590
- topLeft = {
591
- c: br.c < tl.c ? br.c : tl.c,
592
- r: br.r < tl.r ? br.r : tl.r,
593
- };
594
- bottomRight = {
595
- c: br.c > tl.c ? br.c + 1 : tl.c + 1,
596
- r: br.r > tl.r ? br.r + 1 : tl.r + 1,
597
- };
598
- let top = 28;
599
- let right = 51;
600
- let bottom = 28;
601
- let left = 51;
602
- for (let i = 0; i < topLeft.r; i++) {
603
- top = top + getRowHeight(i);
604
- }
605
- for (let i = 0; i < topLeft.c; i++) {
606
- left = left + getColumnsWidth(i);
607
- }
608
- for (let i = 0; i < bottomRight.r; i++) {
609
- bottom = bottom + getRowHeight(i);
610
- }
611
- for (let i = 0; i < bottomRight.c; i++) {
612
- right = right + getColumnsWidth(i);
613
- }
614
- topextend.style = `width: ${right - left}px; left: ${left}px; top: ${top}px`;
615
- rightextend.style = `height: ${bottom - top}px; left: ${right}px; top: ${top}px`;
616
- bottomextend.style = `width: ${right - left}px; left: ${left}px; top: ${bottom}px`;
617
- leftextend.style = `height: ${bottom - top}px; left: ${left}px; top: ${top}px`;
618
- }
676
+ let topLeft = { c: 0, r: 0 };
677
+ let bottomRight = { c: 0, r: 0 };
678
+ $: if (mounted) {
679
+ if (extendRaf)
680
+ cancelAnimationFrame(extendRaf);
681
+ extendRaf = requestAnimationFrame(() => {
682
+ extendRaf = null;
683
+ updateExtendOverlays();
684
+ });
619
685
  }
620
686
  let selectWidth;
621
687
  let selectHeight;
622
- $: {
623
- if (mounted) {
624
- let tl = (selected && decode(selected[0])) || { c: 0, r: 0 };
625
- let br = (selected && decode(selected[1])) || { c: 0, r: 0 };
626
- topLeft = {
627
- c: br.c < tl.c ? br.c : tl.c,
628
- r: br.r < tl.r ? br.r : tl.r,
629
- };
630
- bottomRight = {
631
- c: br.c > tl.c ? br.c + 1 : tl.c + 1,
632
- r: br.r > tl.r ? br.r + 1 : tl.r + 1,
633
- };
634
- let top = 28;
635
- let right = 51;
636
- let bottom = 28;
637
- let left = 51;
638
- for (let i = 0; i < topLeft.r; i++) {
639
- top = top + getRowHeight(i);
640
- }
641
- for (let i = 0; i < topLeft.c; i++) {
642
- left = left + getColumnsWidth(i);
643
- }
644
- for (let i = 0; i < bottomRight.r; i++) {
645
- bottom = bottom + getRowHeight(i);
646
- }
647
- for (let i = 0; i < bottomRight.c; i++) {
648
- right = right + getColumnsWidth(i);
649
- }
650
- tops.style = `width: ${right - left}px; left: ${left}px; top: ${top}px`;
651
- rights.style = `height: ${bottom - top}px; left: ${right}px; top: ${top}px`;
652
- bottoms.style = `width: ${right - left}px; left: ${left}px; top: ${bottom}px`;
653
- lefts.style = `height: ${bottom - top}px; left: ${left}px; top: ${top}px`;
654
- colLine.style = `width: ${right - left}px; left: ${left}px; top: 28px;`;
655
- rowLine.style = `height: ${bottom - top}px; left: 51px; top: ${top}px`;
656
- square.style = `left:${right}px; top:${bottom}px`;
657
- selectWidth = right - left;
658
- selectHeight = bottom - top;
659
- }
688
+ $: if (mounted) {
689
+ if (selectionRaf)
690
+ cancelAnimationFrame(selectionRaf);
691
+ selectionRaf = requestAnimationFrame(() => {
692
+ selectionRaf = null;
693
+ updateSelectionOverlays();
694
+ });
660
695
  }
661
696
  // history logic
662
697
  function historyPush(data, rows, columns, style) {
@@ -723,17 +758,18 @@ function historyPush(data, rows, columns, style) {
723
758
  <div class="row-line absolute" bind:this={rowLine} />
724
759
  <div
725
760
  tabindex={-1}
726
- use:draggable
727
- on:dragging={(e) => {
728
- if (isReadOnly) return;
729
- if (lastDrag && lastDrag.x === e.detail.x && lastDrag.y === e.detail.y) {
730
- return;
731
- }
732
- lastDrag = { x: e.detail.x, y: e.detail.y };
733
- squareX = e.detail.x;
734
- squareY = e.detail.y;
735
- }}
761
+ use:draggable
762
+ on:dragging={(e) => {
763
+ if (isReadOnly) return;
764
+ if (lastDrag && lastDrag.x === e.detail.x && lastDrag.y === e.detail.y) {
765
+ return;
766
+ }
767
+ lastDrag = { x: e.detail.x, y: e.detail.y };
768
+ squareX = e.detail.x;
769
+ squareY = e.detail.y;
770
+ }}
736
771
  class="square absolute interactive"
772
+ class:hidden={isReadOnly || config.disableHover || !config.selectionCopy}
737
773
  id="square"
738
774
  bind:this={square}
739
775
  />
@@ -832,7 +868,7 @@ function historyPush(data, rows, columns, style) {
832
868
  {/each}
833
869
  </tr>
834
870
  </thead>
835
- <tbody class="draggable" bind:this={viewport} on:scroll={handle_scroll}>
871
+ <tbody class="draggable" on:scroll={handle_scroll}>
836
872
  {#each visibleY as r}
837
873
  <tr
838
874
  class="virtual-row"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chalabi/svelte-sheets",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Run your excel sheet in the browser!",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",