@chalabi/svelte-sheets 2.0.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/Readme.md ADDED
@@ -0,0 +1,110 @@
1
+ # Svelte Spreadsheets
2
+
3
+ Ultra fast excel sheets in the browser. Hugely inspired by JExcel, built on XLSX shoulders.
4
+
5
+ => Find a live example [Here](https://ticruz38.github.io/svelte-sheets/)
6
+
7
+ ### Motivation
8
+
9
+ Making excel sheets a reality in the browser can be incredibly difficult, keeping good performance while drawing and editing large amount of data in the DOM is the ultimate challenge for a web developper.
10
+ The best implementation I could find was the awesome vanillajs [jexcel](https://github.com/jspreadsheet/jexcel) by Paul Hodel. <br/>
11
+ However, opening really big spreadsheet would still block the JS thread for a minute or two.
12
+ Following Rich Harris talk about reactivity, I decided to take the idea behind Jexcel and adapt it to Svelte, making use of a Virtual List to keep the DOM small and light at all times.
13
+
14
+ ### Known limitation
15
+
16
+ You will need to have typescript svelte-preprocess enabled in your webpack/rollup configuration
17
+
18
+ ### Installation
19
+
20
+ `npm i -S @chalabi/svelte-sheets`
21
+
22
+ ### Example
23
+
24
+ ```html
25
+ <script>
26
+ import { Sheet } from "@chalabi/svelte-sheets";
27
+
28
+ let style = {
29
+ A1: "background-color: red",
30
+ };
31
+ let mergeCells = {
32
+ A1: [5, 0], // 5 horizontally merged cell (colspan), 0 vertically merged cells (rowspan)
33
+ };
34
+ let columns = [{ width: "50px" }];
35
+ let data = [
36
+ ["mazda", "renault", "volkswagen"][("10000km", "20000km", "300000km")],
37
+ ];
38
+ </script>
39
+
40
+ <Sheet {style} {mergeCells} {columns} {data} />
41
+ ```
42
+
43
+ Alternatively you can use the toolbar to open any kind of excel files
44
+
45
+ ```html
46
+ <script>
47
+ import { Sheet, Toolbar } from "@chalabi/svelte-sheets";
48
+
49
+ let sheetNames;
50
+ let sheets;
51
+ let active;
52
+ let data;
53
+ let columns;
54
+ let mergeCells;
55
+ let style;
56
+
57
+ $: {
58
+ data = sheets[active].data;
59
+ columns = sheets[active].columns;
60
+ mergeCells = sheets[active].mergeCells;
61
+ style = sheets[active].style;
62
+ }
63
+ </script>
64
+
65
+ <Toolbar bind:sheetNames bind:sheets bind:active />
66
+ <Sheet {style} {mergeCells} {columns} {data} />
67
+ ```
68
+
69
+ You can configure the table such as height and many other things with the options props:
70
+
71
+ ```js
72
+ let options = {
73
+ tableHeight: "90vh",
74
+ defaultColWidth: "50px",
75
+ readOnly: true,
76
+ };
77
+ ```
78
+
79
+ Common flags:
80
+
81
+ - `readOnly`: true to disable all edits and resizing
82
+ - `editable`: false to disable edits (equivalent to readOnly)
83
+ - `disableHover`: true to disable hover-based selection updates
84
+
85
+ Theme:
86
+
87
+ - `theme`: set to `"dark"` for the bundled dark tokens (default is `"light"`)
88
+ - `class` / `className`: pass a custom class to the root element to override CSS variables
89
+
90
+ Many of these options will be implemented later, so expect most of them to be unresponsive.
91
+
92
+ ### Development
93
+
94
+ - The demo app lives in `src/routes/+page.svelte`
95
+ - `npm run dev` for the demo
96
+ - `npm test` to run unit tests
97
+ - `npm run package` to build the library output
98
+
99
+ ### Things yet to be done
100
+
101
+ - Make a svelte REPL demonstrating the library (awaiting repl typescript support)
102
+ - ✅ Undo/Redo (mapping keyboard shortcuts)
103
+ - ✅ shift+click should extend the selection
104
+ - ✅ Resizing rows/columns
105
+ - Filtering
106
+ - ✅ Copy/Paste
107
+ - Comments on cells
108
+ - Support more that number, string or boolean in cells. let's say charts, datepickers etc...
109
+ - ✅ Implement a tooltip when right clicking a cell with a list of actions
110
+ - All other excel features you can think of
@@ -0,0 +1,97 @@
1
+ <script lang="ts">export let show = false;
2
+ export let x;
3
+ export let y;
4
+ export let data = [];
5
+ export let selected;
6
+ export let copy;
7
+ export let cut;
8
+ export let paste;
9
+ export let clear;
10
+ // delete is a reserved word...
11
+ export let delet;
12
+ export let readOnly = false;
13
+ </script>
14
+
15
+ <div class="menu" class:hidden={!show} style={`top: ${y}px; left: ${x}px`}>
16
+ <div
17
+ class="item flex justify-between"
18
+ class:disabled={readOnly}
19
+ on:click={(e) => !readOnly && cut(e)}
20
+ >
21
+ <div>Cut</div>
22
+ <div class="disabled">⌘X</div>
23
+ </div>
24
+ <div class="item flex justify-between" on:click={(e) => copy(e)}>
25
+ <div>Copy</div>
26
+ <div class="disabled">⌘C</div>
27
+ </div>
28
+ <div
29
+ class="item flex justify-between"
30
+ class:disabled={readOnly}
31
+ on:click={(e) => !readOnly && paste(e)}
32
+ >
33
+ <div>Paste</div>
34
+ <div class="disabled">⌘P</div>
35
+ </div>
36
+ <div class="divider" />
37
+ <div class="item" class:disabled={readOnly}>Insert</div>
38
+ <div
39
+ class="item"
40
+ class:disabled={readOnly}
41
+ on:click={(e) => !readOnly && delet(e)}
42
+ >
43
+ Delete
44
+ </div>
45
+ <div
46
+ class="item"
47
+ class:disabled={readOnly}
48
+ on:click={(e) => !readOnly && clear(e)}
49
+ >
50
+ Clear contents
51
+ </div>
52
+ </div>
53
+
54
+ <style>
55
+ .menu {
56
+ padding: 0.5rem 0.25rem;
57
+ position: fixed;
58
+ z-index: 20;
59
+ min-width: 10rem;
60
+ background: var(--sheet-menu-bg);
61
+ border-radius: 10px;
62
+ color: var(--sheet-text);
63
+ }
64
+ .disabled {
65
+ color: var(--sheet-muted);
66
+ }
67
+ .divider {
68
+ padding-top: 0.5rem;
69
+ margin-bottom: 0.5rem;
70
+ border-bottom: 1px solid #aaa;
71
+ }
72
+ .hidden {
73
+ display: none;
74
+ }
75
+ .flex {
76
+ display: flex;
77
+ }
78
+ .justify-between {
79
+ justify-content: space-between;
80
+ }
81
+ .item {
82
+ cursor: pointer;
83
+ padding: 0.25rem 0.5rem;
84
+ border-radius: 0.25rem;
85
+ }
86
+ .item:hover {
87
+ background-color: var(--sheet-accent);
88
+ color: var(--sheet-bg);
89
+ }
90
+ .item.disabled {
91
+ cursor: not-allowed;
92
+ opacity: 0.6;
93
+ }
94
+ .item.disabled:hover {
95
+ background-color: transparent;
96
+ }
97
+ </style>
@@ -0,0 +1,30 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: Props & {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const Menu: $$__sveltets_2_IsomorphicComponent<{
15
+ show?: boolean;
16
+ x: any;
17
+ y: any;
18
+ data?: (string | number | boolean)[][];
19
+ selected: string;
20
+ copy: (e: any) => void;
21
+ cut: (e: any) => void;
22
+ paste: (e: any) => any[][];
23
+ clear: (e: any) => any[][];
24
+ delet: (e: any) => any[][];
25
+ readOnly?: boolean;
26
+ }, {
27
+ [evt: string]: CustomEvent<any>;
28
+ }, {}, {}, string>;
29
+ type Menu = InstanceType<typeof Menu>;
30
+ export default Menu;
@@ -0,0 +1,35 @@
1
+ <script lang="ts">import XLSX from "xlsx";
2
+ import { convert } from "./convert.js";
3
+ export let onload;
4
+ export let sheetNames;
5
+ export let sheets = [];
6
+ export let open;
7
+ // declare all possible table object
8
+ let files;
9
+ $: files && files[0] && reader && reader.readAsArrayBuffer(files[0]);
10
+ let reader;
11
+ if (typeof FileReader != "undefined") {
12
+ reader = new FileReader();
13
+ reader.onload = () => {
14
+ sheets = [];
15
+ const wb = XLSX.read(new Uint8Array(reader.result), {
16
+ type: "array",
17
+ cellFormula: true,
18
+ cellStyles: true,
19
+ });
20
+ sheets = convert(wb);
21
+ sheetNames = sheets.map((s) => s.sheetName);
22
+ onload && onload(sheets, sheetNames);
23
+ };
24
+ }
25
+ </script>
26
+
27
+ <input type="file" class="hidden" name="file" bind:this={open} bind:files />
28
+
29
+ <style>
30
+ .hidden {
31
+ height: 0;
32
+ width: 0;
33
+ opacity: 0;
34
+ }
35
+ </style>
@@ -0,0 +1,23 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: Props & {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const Open: $$__sveltets_2_IsomorphicComponent<{
15
+ onload: (sheets: any[], sheetNames: any[]) => void;
16
+ sheetNames: any;
17
+ sheets?: any[];
18
+ open: any;
19
+ }, {
20
+ [evt: string]: CustomEvent<any>;
21
+ }, {}, {}, string>;
22
+ type Open = InstanceType<typeof Open>;
23
+ export default Open;