├── .DS_Store
├── .gitignore
├── Readme.md
├── docs
├── .nojekyll
├── _app
│ ├── assets
│ │ └── pages
│ │ │ └── index.svelte-f7e4ec4a.css
│ ├── chunks
│ │ └── index-54ee1bf0.js
│ ├── error.svelte-1f93263e.js
│ ├── layout.svelte-da045ec5.js
│ ├── manifest.json
│ ├── pages
│ │ └── index.svelte-d17e7ba4.js
│ ├── start-869b4509.js
│ └── version.json
├── favicon.png
├── github.png
├── global.css
└── index.html
├── package-lock.json
├── package.json
├── package
├── .gitignore
├── Menu.svelte
├── Menu.svelte.d.ts
├── Open.svelte
├── Open.svelte.d.ts
├── Readme.md
├── Sheet.svelte
├── Sheet.svelte.d.ts
├── Toolbar.svelte
├── Toolbar.svelte.d.ts
├── actions
│ ├── copypaste.d.ts
│ ├── copypaste.js
│ ├── draggable.d.ts
│ ├── draggable.js
│ ├── index.d.ts
│ ├── index.js
│ ├── resizable.d.ts
│ ├── resizable.js
│ ├── rightclick.d.ts
│ ├── rightclick.js
│ ├── selected.d.ts
│ └── selected.js
├── convert.d.ts
├── convert.js
├── defaultconfig.d.ts
├── defaultconfig.js
├── index.d.ts
├── index.js
├── package.json
├── utilities.d.ts
└── utilities.js
├── src
├── app.d.ts
├── app.html
├── lib
│ ├── Menu.svelte
│ ├── Open.svelte
│ ├── Sheet.svelte
│ ├── Toolbar.svelte
│ ├── actions
│ │ ├── copypaste.ts
│ │ ├── draggable.ts
│ │ ├── index.ts
│ │ ├── resizable.ts
│ │ ├── rightclick.ts
│ │ └── selected.ts
│ ├── convert.ts
│ ├── defaultconfig.ts
│ ├── index.ts
│ └── utilities.ts
└── routes
│ ├── _example.json
│ └── index.svelte
├── static
├── .nojekyll
├── favicon.png
├── github.png
└── global.css
├── svelte.config.js
└── tsconfig.json
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ticruz38/svelte-sheets/b126f663574e991f2e6a102047ee57f96c65fb7a/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .svelte-kit
3 | .DS_Store
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
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.
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 svelte-sheets`
21 |
22 | ### Example
23 |
24 | ```html
25 |
39 |
40 |
41 | ```
42 |
43 | Alternatively you can use the toolbar to open any kind of excel files
44 |
45 | ```html
46 |
64 |
65 |
66 |
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 | };
76 | ```
77 |
78 | Many of this options will be implemented later, so expect most of them to be unresponsible.
79 |
80 | ### Things yet to be done
81 |
82 | - Make a svelte REPL demonstrating the library (awaiting repl typescript support)
83 | - ✅ Undo/Redo (mapping keyboard shortcuts)
84 | - ✅ shift+click should extend the selection
85 | - ✅ Resizing rows/columns
86 | - Filtering
87 | - ✅ Copy/Paste
88 | - Comments on cells
89 | - Support more that number, string or boolean in cells. let's say charts, datepickers etc...
90 | - ✅ Implement a tooltip when right clicking a cell with a list of actions
91 | - All other excel features you can think of
92 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ticruz38/svelte-sheets/b126f663574e991f2e6a102047ee57f96c65fb7a/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/_app/assets/pages/index.svelte-f7e4ec4a.css:
--------------------------------------------------------------------------------
1 | .menu.svelte-194m42e{padding:.5rem .25rem;position:fixed;z-index:20;min-width:10rem;background:#ddd;border-radius:10px}.disabled.svelte-194m42e{color:#aaa}.divider.svelte-194m42e{padding-top:.5rem;margin-bottom:.5rem;border-bottom:1px solid #aaa}.hidden.svelte-194m42e{display:none}.flex.svelte-194m42e{display:flex}.justify-between.svelte-194m42e{justify-content:space-between}.item.svelte-194m42e{cursor:pointer;padding:.25rem .5rem;border-radius:.25rem}.item.svelte-194m42e:hover{background-color:#4fc2c2}.hidden.svelte-74gt44{height:0;width:0;opacity:0}.svelte-10iujif.svelte-10iujif.svelte-10iujif,.svelte-10iujif.svelte-10iujif.svelte-10iujif:before,.svelte-10iujif.svelte-10iujif.svelte-10iujif:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}:root{tab-size:4}.jexcel_content.svelte-10iujif.svelte-10iujif.svelte-10iujif{overflow-x:auto;overflow-y:auto;max-width:100vw;max-height:100vh}.sheet_container.svelte-10iujif.svelte-10iujif.svelte-10iujif{display:block;padding-right:2px;box-sizing:border-box;overscroll-behavior:contain;outline:none;position:relative;user-select:none}table.svelte-10iujif.svelte-10iujif.svelte-10iujif{border-collapse:separate;table-layout:fixed;white-space:nowrap;empty-cells:show;border:0px;background-color:#fff;width:0;border-top:1px solid transparent;border-left:1px solid transparent;border-right:1px solid #ccc;border-bottom:1px solid #ccc;text-indent:0}thead.svelte-10iujif>tr.svelte-10iujif>td.selected.svelte-10iujif{background-color:#dcdcdc;color:teal}thead.svelte-10iujif>tr.svelte-10iujif>td.svelte-10iujif{background-color:#f3f3f3;padding:2px;cursor:s-resize;box-sizing:border-box;overflow:hidden;position:sticky;top:0;z-index:2}td.svelte-10iujif.svelte-10iujif.svelte-10iujif{outline:none;cursor:default;line-height:14px;font-size:14px;border-top:1px solid #ccc;border-left:1px solid #ccc;border-right:1px solid transparent;border-bottom:1px solid transparent}tbody.svelte-10iujif>tr.svelte-10iujif>td.svelte-10iujif{padding:4px;white-space:nowrap;box-sizing:border-box;line-height:1em;text-align:end;cursor:cell}tbody.svelte-10iujif>tr.svelte-10iujif>td.selected.svelte-10iujif{background-color:#ddd;transition:all .1s linear}tbody.svelte-10iujif>tr.svelte-10iujif>th.svelte-10iujif,thead.svelte-10iujif>tr.svelte-10iujif>th.svelte-10iujif{position:sticky;left:0;cursor:e-resize;top:auto;background:#f3f3f3;border-top:1px solid #ccc;border-left:1px solid #ccc;border-right:1px solid #ccc;z-index:10;font-weight:400;height:27px}tbody.svelte-10iujif>tr.svelte-10iujif>th.selected.svelte-10iujif{background-color:#dcdcdc!important;color:teal}div.col-resize.svelte-10iujif.svelte-10iujif.svelte-10iujif{position:absolute;top:0;cursor:col-resize;width:1rem;height:100%}div.col-resize.right.svelte-10iujif.svelte-10iujif.svelte-10iujif{right:0}div.col-resize.left.svelte-10iujif.svelte-10iujif.svelte-10iujif{left:0}div.row-resize.svelte-10iujif.svelte-10iujif.svelte-10iujif{position:absolute;left:0;cursor:row-resize;width:100%;height:.5rem}div.row-resize.top.svelte-10iujif.svelte-10iujif.svelte-10iujif{top:0}div.row-resize.bottom.svelte-10iujif.svelte-10iujif.svelte-10iujif{bottom:0}input.svelte-10iujif.svelte-10iujif.svelte-10iujif{background:none;margin:-4px 0;outline:none}.absolute.svelte-10iujif.svelte-10iujif.svelte-10iujif{position:absolute;z-index:10;transition:all .1s linear}.top-select.svelte-10iujif.svelte-10iujif.svelte-10iujif,.bottom-select.svelte-10iujif.svelte-10iujif.svelte-10iujif,.col-line.svelte-10iujif.svelte-10iujif.svelte-10iujif{border-bottom:2px solid teal}.left-select.svelte-10iujif.svelte-10iujif.svelte-10iujif,.right-select.svelte-10iujif.svelte-10iujif.svelte-10iujif{border-left:2px solid teal}.top-extend.svelte-10iujif.svelte-10iujif.svelte-10iujif,.bottom-extend.svelte-10iujif.svelte-10iujif.svelte-10iujif{border-bottom:2px solid #aaa}.left-extend.svelte-10iujif.svelte-10iujif.svelte-10iujif,.right-extend.svelte-10iujif.svelte-10iujif.svelte-10iujif{border-left:2px solid #aaa}.row-line.svelte-10iujif.svelte-10iujif.svelte-10iujif{border-right:1px solid teal}.square.svelte-10iujif.svelte-10iujif.svelte-10iujif{height:8px;width:8px;cursor:crosshair;border:1px solid white;background:teal;transform:translate3D(-40%,-40%,0)}.hidden.svelte-10iujif.svelte-10iujif.svelte-10iujif{display:none}.hidden.svelte-1oyjtb6{height:0;width:0;opacity:0}.active.svelte-1oyjtb6{border-bottom:1px solid teal}.flex.svelte-1oyjtb6{display:flex;justify-content:center;align-items:center}.ml-4.svelte-1oyjtb6{margin-left:1rem}.cursor-pointer.svelte-1oyjtb6{cursor:pointer}.sheet-names.svelte-57i5ub{text-align:center;position:fixed;bottom:0;width:100%;padding:1rem}.github-link.svelte-57i5ub{position:fixed;top:.5rem;right:.5rem;background-image:url(/github.png);height:2rem;width:2rem;background-position:center;background-repeat:none;background-size:cover}.selected.svelte-57i5ub{text-decoration:underline}
2 |
--------------------------------------------------------------------------------
/docs/_app/chunks/index-54ee1bf0.js:
--------------------------------------------------------------------------------
1 | function P(){}function nt(t,e){for(const n in e)t[n]=e[n];return t}function K(t){return t()}function H(){return Object.create(null)}function $(t){t.forEach(K)}function Q(t){return typeof t=="function"}function xt(t,e){return t!=t?e==e:t!==e||t&&typeof t=="object"||typeof t=="function"}function it(t){return Object.keys(t).length===0}function wt(t,e,n,i){if(t){const o=R(t,e,n,i);return t[0](o)}}function R(t,e,n,i){return t[1]&&i?nt(n.ctx.slice(),t[1](i(e))):n.ctx}function bt(t,e,n,i){if(t[2]&&i){const o=t[2](i(n));if(e.dirty===void 0)return o;if(typeof o=="object"){const l=[],r=Math.max(e.dirty.length,o.length);for(let c=0;c32){const e=[],n=t.ctx.length/32;for(let i=0;i>1);n(o)<=i?t=o+1:e=o}return t}function ct(t){if(t.hydrate_init)return;t.hydrate_init=!0;let e=t.childNodes;if(t.nodeName==="HEAD"){const s=[];for(let a=0;a0&&e[n[o]].claim_order<=a?o+1:st(1,o,d=>e[n[d]].claim_order,a))-1;i[s]=n[f]+1;const _=f+1;n[_]=s,o=Math.max(_,o)}const l=[],r=[];let c=e.length-1;for(let s=n[o]+1;s!=0;s=i[s-1]){for(l.push(e[s-1]);c>=s;c--)r.push(e[c]);c--}for(;c>=0;c--)r.push(e[c]);l.reverse(),r.sort((s,a)=>s.claim_order-a.claim_order);for(let s=0,a=0;s=l[a].claim_order;)a++;const f=at.removeEventListener(e,n,i)}function Mt(t,e,n){n==null?t.removeAttribute(e):t.getAttribute(e)!==n&&t.setAttribute(e,n)}function ut(t){return Array.from(t.childNodes)}function ft(t){t.claim_info===void 0&&(t.claim_info={last_index:0,total_claimed:0})}function X(t,e,n,i,o=!1){ft(t);const l=(()=>{for(let r=t.claim_info.last_index;r=0;r--){const c=t[r];if(e(c)){const s=n(c);return s===void 0?t.splice(r,1):t[r]=s,o?s===void 0&&t.claim_info.last_index--:t.claim_info.last_index=r,c}}return i()})();return l.claim_order=t.claim_info.total_claimed,t.claim_info.total_claimed+=1,l}function dt(t,e,n,i){return X(t,o=>o.nodeName===e,o=>{const l=[];for(let r=0;ro.removeAttribute(r))},()=>i(e))}function Nt(t,e,n){return dt(t,e,n,V)}function _t(t,e){return X(t,n=>n.nodeType===3,n=>{const i=""+e;if(n.data.startsWith(i)){if(n.data.length!==i.length)return n.splitText(i.length)}else n.data=i},()=>I(e),!0)}function Ct(t){return _t(t," ")}function zt(t,e){e=""+e,t.wholeText!==e&&(t.data=e)}function Lt(t,e){t.value=e==null?"":e}function Tt(t,e,n,i){n===null?t.style.removeProperty(e):t.style.setProperty(e,n,i?"important":"")}let E;function ht(){if(E===void 0){E=!1;try{typeof window!="undefined"&&window.parent&&window.parent.document}catch{E=!0}}return E}function Wt(t,e){getComputedStyle(t).position==="static"&&(t.style.position="relative");const i=V("iframe");i.setAttribute("style","display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: -1;"),i.setAttribute("aria-hidden","true"),i.tabIndex=-1;const o=ht();let l;return o?(i.src="data:text/html,
26 |