@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 +1 -1
- package/dist/Sheet.svelte +169 -133
- package/package.json +1 -1
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://
|
|
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 =
|
|
86
|
-
export let endX =
|
|
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 (
|
|
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 (
|
|
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
|
|
433
|
-
|
|
434
|
-
|
|
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
|
-
|
|
437
|
-
if (
|
|
438
|
-
return;
|
|
439
|
-
e.preventDefault();
|
|
440
|
-
cmdz = true;
|
|
441
|
-
if (historyIndex == 0)
|
|
505
|
+
function updateSelectionOverlays() {
|
|
506
|
+
if (!mounted)
|
|
442
507
|
return;
|
|
443
|
-
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
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
|
-
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
style =
|
|
465
|
-
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
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
|
-
|
|
478
|
-
|
|
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
|
-
|
|
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 (
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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 (
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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"
|
|
871
|
+
<tbody class="draggable" on:scroll={handle_scroll}>
|
|
836
872
|
{#each visibleY as r}
|
|
837
873
|
<tr
|
|
838
874
|
class="virtual-row"
|