Socket
Socket
Sign inDemoInstall

@lexical/table

Package Overview
Dependencies
Maintainers
2
Versions
160
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lexical/table - npm Package Compare versions

Comparing version 0.1.9 to 0.1.10

22

LexicalTable.dev.js

@@ -35,13 +35,13 @@ /**

*/
class TableCellNode extends lexical.ElementNode {
class TableCellNode extends lexical.GridCellNode {
static getType() {
return 'table-cell';
return 'tablecell';
}
static clone(node) {
return new TableCellNode(false, node.__key);
return new TableCellNode(false, node.__colSpan, node.__key);
}
constructor(isHeader = false, key) {
super(key);
constructor(isHeader = false, colSpan = 1, key) {
super(colSpan, key);
this.__isHeader = isHeader;

@@ -402,3 +402,3 @@ }

if (selection === null) {
if (!lexical.$isRangeSelection(selection)) {
selection = lexical.$createRangeSelection();

@@ -516,3 +516,3 @@ } // This is to make Flow play ball.

if (selection == null) {
if (!lexical.$isRangeSelection(selection)) {
return false;

@@ -561,3 +561,3 @@ }

class TableNode extends lexical.ElementNode {
class TableNode extends lexical.GridNode {
static getType() {

@@ -568,2 +568,4 @@ return 'table';

static clone(node, selectionShape, grid) {
// TODO: selectionShape and grid aren't being deeply cloned?
// They shouldn't really be on the table node IMO.
return new TableNode(node.__key, node.__selectionShape, node.__grid);

@@ -706,5 +708,5 @@ }

*/
class TableRowNode extends lexical.ElementNode {
class TableRowNode extends lexical.GridRowNode {
static getType() {
return 'table-row';
return 'tablerow';
}

@@ -711,0 +713,0 @@

@@ -7,24 +7,24 @@ /**

*/
var q=require("lexical");function x(a,...b){b.forEach(c=>{null!=c&&"string"===typeof c&&a.classList.add(...c.split(" "))})}
class y extends q.ElementNode{static getType(){return"table-cell"}static clone(a){return new y(!1,a.__key)}constructor(a=!1,b){super(b);this.__isHeader=a}getTag(){return this.__isHeader?"th":"td"}createDOM(a){const b=document.createElement(this.getTag());x(b,a.theme.tableCell,!0===this.__isHeader&&a.theme.tableCellHeader);return b}updateDOM(){return!1}collapseAtStart(){return!0}canBeEmpty(){return!1}}function z(a){return new y(a)}function B(a){return a instanceof y}
function C(a){throw Error(`Minified Lexical error #${a}; see codes.json for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function D(a,b){for(;a!==q.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}const F=document.createElement("style");F.appendChild(document.createTextNode("::selection{background-color: transparent}"));
var p=require("lexical");function x(a,...b){b.forEach(c=>{null!=c&&"string"===typeof c&&a.classList.add(...c.split(" "))})}
class y extends p.GridCellNode{static getType(){return"tablecell"}static clone(a){return new y(!1,a.__colSpan,a.__key)}constructor(a=!1,b=1,c){super(b,c);this.__isHeader=a}getTag(){return this.__isHeader?"th":"td"}createDOM(a){const b=document.createElement(this.getTag());x(b,a.theme.tableCell,!0===this.__isHeader&&a.theme.tableCellHeader);return b}updateDOM(){return!1}collapseAtStart(){return!0}canBeEmpty(){return!1}}function z(a){return new y(a)}function B(a){return a instanceof y}
function C(a){throw Error(`Minified Lexical error #${a}; see codes.json for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function D(a,b){for(;a!==p.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}const F=document.createElement("style");F.appendChild(document.createTextNode("::selection{background-color: transparent}"));
function G(a){for(;null!=a;){const b=a.nodeName;if("TD"===b||"TH"===b){a=a._cell;if(void 0===a)break;return a}a=a.parentNode}return null}
function H(a,b,c){const g=[],d={cells:g,columns:0,rows:0};(new MutationObserver(n=>{c.update(()=>{var e=b.firstChild;let p=0,m=0;var h=!1;for(let r=0;r<n.length;r++){const w=n[r].target.nodeName;if("TABLE"===w||"TR"===w){h=!0;break}}if(h){for(g.length=0;null!=e;){h=e.nodeName;if("TD"===h||"TH"===h)h={elem:e,highlighted:!1,x:p,y:m},e._cell=h,void 0===g[m]&&(g[m]=[]),g[m][p]=h;else if(h=e.firstChild,null!=h){e=h;continue}h=e.nextSibling;if(null!=h)p++,e=h;else if(h=e.parentNode,null!=h){e=h.nextSibling;
if(null==e)break;m++;p=0}}d.columns=p+1;d.rows=m+1;a.setGrid(d)}})})).observe(b,{childList:!0,subtree:!0});a.setGrid(d);return d}
function I(a,b,c,g,d){const n=[];for(let e=0;e<d.length;e++){const p=d[e];for(let m=0;m<p.length;m++){const h=p[m],r=h.elem.style;m>=a&&m<=b&&e>=c&&e<=g?(h.highlighted||(h.highlighted=!0,r.setProperty("background-color","rgb(163, 187, 255)"),r.setProperty("caret-color","transparent")),n.push(h)):h.highlighted&&(h.highlighted=!1,r.removeProperty("background-color"),r.removeProperty("caret-color"))}}return n}
function J(a,b,c){if(null!==c.getRootElement()){H(a,b,c);var g=a.getGrid(),d=!1,n=!1,e=-1,p=-1,m=-1,h=-1,r=[];if(null==g)throw Error("Table grid not found.");b.addEventListener("mousemove",k=>{if(d){var f=G(k.target);if(null!==f){const l=f.x;f=f.y;if(!n&&(e!==l||p!==f))k.preventDefault(),k=window.getSelection(),k.setBaseAndExtent(k.anchorNode,0,k.anchorNode,0),n=!0,document.body&&document.body.appendChild(F),null===A&&(A=c.addListener("command",(u,v)=>{if("deleteCharacter"===u){if(r.length===g.columns*
g.rows)return a.selectPrevious(),a.remove(),w(),!0;r.forEach(({elem:t})=>{t=q.$getNearestNodeFromDOMNode(t);if(q.$isElementNode(t)){t.clear();const E=q.$createParagraphNode(),T=q.$createTextNode();E.append(T);t.append(E)}});a.setSelectionState(null);q.$setSelection(null);return!0}if("formatText"===u)return U(v),!0;"insertText"===u&&w();return!1},1));else if(l===m&&f===h)return;m=l;h=f;if(n){const u=Math.min(e,m),v=Math.max(e,m),t=Math.min(p,h),E=Math.max(p,h);c.update(()=>{r=a.setSelectionState({fromX:u,
fromY:t,toX:v,toY:E})})}}}});var w=()=>{c.update(()=>{d=n=!1;h=m=p=e=-1;c.update(()=>{a.setSelectionState(null)});r=[];null!==A&&(A(),A=null);const k=F.parentNode;null!=k&&k.removeChild(F)})};b.addEventListener("mouseleave",()=>{});var U=k=>{let f=q.$getSelection();null===f&&(f=q.$createRangeSelection());const l=f,u=l.anchor,v=l.focus;r.forEach(t=>{t=q.$getNearestNodeFromDOMNode(t.elem);q.$isElementNode(t)&&(u.set(t.getKey(),0,"element"),v.set(t.getKey(),t.getChildrenSize(),"element"),l.formatText(k))});
f.anchor.set(f.anchor.key,f.anchor.offset,f.anchor.type);f.focus.set(f.anchor.key,f.anchor.offset,f.anchor.type);q.$setSelection(f)},A=null;b.addEventListener("mousedown",k=>{d?n&&w():setTimeout(()=>{n&&w();const f=G(k.target);null!==f&&(d=!0,e=f.x,p=f.y,document.addEventListener("mouseup",()=>{d=!1},{capture:!0,once:!0}))},0)});window.addEventListener("click",k=>{0<r.length&&!b.contains(k.target)&&c.update(()=>{a.setSelectionState(null)})});var O=(k,f,l)=>{switch(l){case "backward":case "forward":return l=
"forward"===l,f!==(l?g.columns-1:0)?a.getCellNodeFromCords(k,f+(l?1:-1)).select():k!==(l?g.rows-1:0)?a.getCellNodeFromCords(k+(l?1:-1),l?0:g.columns-1).select():l?a.selectNext():a.selectPrevious(),!0;case "up":return 0!==k?a.getCellNodeFromCords(k-1,f).select():a.selectPrevious(),!0;case "down":return k!==g.rows-1?a.getCellNodeFromCords(k+1,f).select():a.selectNext(),!0}return!1};c.addListener("command",(k,f)=>{var l=q.$getSelection();if(null==l)return!1;const u=D(l.anchor.getNode(),v=>B(v));if(!B(u))return!1;
if("deleteCharacter"===k&&0===r.length&&l.isCollapsed()&&0===l.anchor.offset)return!0;if(("indentContent"===k||"outdentContent"===k)&&l.isCollapsed()&&0===r.length)return f=a.getCordsFromCellNode(u),O(f.x,f.y,"indentContent"===k?"forward":"backward"),!0;if(("keyArrowDown"===k||"keyArrowUp"===k)&&l.isCollapsed()&&0===r.length){const v=a.getCordsFromCellNode(u);l=D(l.anchor.getNode(),t=>q.$isElementNode(t));if("keyArrowUp"===k&&l===u.getFirstChild()||"keyArrowDown"===k&&l===u.getLastChild())return f.preventDefault(),
f.stopImmediatePropagation(),O(v.x,v.y,"keyArrowUp"===k?"up":"down"),!0}return!1},4)}}
class K extends q.ElementNode{static getType(){return"table"}static clone(a){return new K(a.__key,a.__selectionShape,a.__grid)}constructor(a,b,c){super(a);this.__selectionShape=b;this.__grid=c}createDOM(a,b){const c=document.createElement("table");x(c,a.theme.table);J(this,c,b);return c}updateDOM(){return!1}canExtractContents(){return!1}canBeEmpty(){return!1}setSelectionState(a){this.getWritable().__selectionShape=a;return null==this.__grid?[]:a?I(a.fromX,a.toX,a.fromY,a.toY,this.__grid.cells):I(-1,
-1,-1,-1,this.__grid.cells)}getSelectionState(){return this.__selectionShape}getCordsFromCellNode(a){this.__grid||C(55);const {rows:b,cells:c}=this.__grid;for(let d=0;d<b;d++){var g=c[d];if(null==g)throw Error(`Row not found at x:${d}`);g=g.findIndex(({elem:n})=>q.$getNearestNodeFromDOMNode(n)===a);if(-1!==g)return{x:d,y:g}}throw Error("Cell not found in table.");}getCellNodeFromCords(a,b){this.__grid||C(55);var {cells:c}=this.__grid;c=c[a];if(null==c)throw Error(`Table row x:"${a}" not found.`);
c=c[b];if(null==c)throw Error(`Table cell y:"${b}" in row x:"${a}" not found.`);a=q.$getNearestNodeFromDOMNode(c.elem);if(B(a))return a;throw Error("Node at cords not TableCellNode.");}setGrid(a){this.getWritable().__grid=a}getGrid(){return this.__grid}canSelectBefore(){return!0}}function L(){return new K}function M(a){return a instanceof K}
class N extends q.ElementNode{static getType(){return"table-row"}static clone(a){return new N(a.__key)}constructor(a){super(a)}createDOM(a){const b=document.createElement("tr");x(b,a.theme.tableRow);return b}updateDOM(){return!1}canBeEmpty(){return!1}}function P(){return new N}function Q(a){return a instanceof N}function R(a){a=D(a,b=>Q(b));if(Q(a))return a;throw Error("Expected table cell to be inside of table row.");}
function S(a){a=D(a,b=>M(b));if(M(a))return a;throw Error("Expected table cell to be inside of table.");}exports.$createTableCellNode=z;exports.$createTableNode=L;exports.$createTableNodeWithDimensions=function(a,b,c=!0){const g=L();for(let d=0;d<a;d++){const n=P();for(let e=0;e<b;e++){const p=z(0===d&&c),m=q.$createParagraphNode();m.append(q.$createTextNode());p.append(m);n.append(p)}g.append(n)}return g};exports.$createTableRowNode=P;
function H(a,b,c){const g=[],d={cells:g,columns:0,rows:0};(new MutationObserver(n=>{c.update(()=>{var e=b.firstChild;let q=0,m=0;var h=!1;for(let r=0;r<n.length;r++){const w=n[r].target.nodeName;if("TABLE"===w||"TR"===w){h=!0;break}}if(h){for(g.length=0;null!=e;){h=e.nodeName;if("TD"===h||"TH"===h)h={elem:e,highlighted:!1,x:q,y:m},e._cell=h,void 0===g[m]&&(g[m]=[]),g[m][q]=h;else if(h=e.firstChild,null!=h){e=h;continue}h=e.nextSibling;if(null!=h)q++,e=h;else if(h=e.parentNode,null!=h){e=h.nextSibling;
if(null==e)break;m++;q=0}}d.columns=q+1;d.rows=m+1;a.setGrid(d)}})})).observe(b,{childList:!0,subtree:!0});a.setGrid(d);return d}
function I(a,b,c,g,d){const n=[];for(let e=0;e<d.length;e++){const q=d[e];for(let m=0;m<q.length;m++){const h=q[m],r=h.elem.style;m>=a&&m<=b&&e>=c&&e<=g?(h.highlighted||(h.highlighted=!0,r.setProperty("background-color","rgb(163, 187, 255)"),r.setProperty("caret-color","transparent")),n.push(h)):h.highlighted&&(h.highlighted=!1,r.removeProperty("background-color"),r.removeProperty("caret-color"))}}return n}
function J(a,b,c){if(null!==c.getRootElement()){H(a,b,c);var g=a.getGrid(),d=!1,n=!1,e=-1,q=-1,m=-1,h=-1,r=[];if(null==g)throw Error("Table grid not found.");b.addEventListener("mousemove",k=>{if(d){var f=G(k.target);if(null!==f){const l=f.x;f=f.y;if(!n&&(e!==l||q!==f))k.preventDefault(),k=window.getSelection(),k.setBaseAndExtent(k.anchorNode,0,k.anchorNode,0),n=!0,document.body&&document.body.appendChild(F),null===A&&(A=c.addListener("command",(u,v)=>{if("deleteCharacter"===u){if(r.length===g.columns*
g.rows)return a.selectPrevious(),a.remove(),w(),!0;r.forEach(({elem:t})=>{t=p.$getNearestNodeFromDOMNode(t);if(p.$isElementNode(t)){t.clear();const E=p.$createParagraphNode(),T=p.$createTextNode();E.append(T);t.append(E)}});a.setSelectionState(null);p.$setSelection(null);return!0}if("formatText"===u)return U(v),!0;"insertText"===u&&w();return!1},1));else if(l===m&&f===h)return;m=l;h=f;if(n){const u=Math.min(e,m),v=Math.max(e,m),t=Math.min(q,h),E=Math.max(q,h);c.update(()=>{r=a.setSelectionState({fromX:u,
fromY:t,toX:v,toY:E})})}}}});var w=()=>{c.update(()=>{d=n=!1;h=m=q=e=-1;c.update(()=>{a.setSelectionState(null)});r=[];null!==A&&(A(),A=null);const k=F.parentNode;null!=k&&k.removeChild(F)})};b.addEventListener("mouseleave",()=>{});var U=k=>{let f=p.$getSelection();p.$isRangeSelection(f)||(f=p.$createRangeSelection());const l=f,u=l.anchor,v=l.focus;r.forEach(t=>{t=p.$getNearestNodeFromDOMNode(t.elem);p.$isElementNode(t)&&(u.set(t.getKey(),0,"element"),v.set(t.getKey(),t.getChildrenSize(),"element"),
l.formatText(k))});f.anchor.set(f.anchor.key,f.anchor.offset,f.anchor.type);f.focus.set(f.anchor.key,f.anchor.offset,f.anchor.type);p.$setSelection(f)},A=null;b.addEventListener("mousedown",k=>{d?n&&w():setTimeout(()=>{n&&w();const f=G(k.target);null!==f&&(d=!0,e=f.x,q=f.y,document.addEventListener("mouseup",()=>{d=!1},{capture:!0,once:!0}))},0)});window.addEventListener("click",k=>{0<r.length&&!b.contains(k.target)&&c.update(()=>{a.setSelectionState(null)})});var O=(k,f,l)=>{switch(l){case "backward":case "forward":return l=
"forward"===l,f!==(l?g.columns-1:0)?a.getCellNodeFromCords(k,f+(l?1:-1)).select():k!==(l?g.rows-1:0)?a.getCellNodeFromCords(k+(l?1:-1),l?0:g.columns-1).select():l?a.selectNext():a.selectPrevious(),!0;case "up":return 0!==k?a.getCellNodeFromCords(k-1,f).select():a.selectPrevious(),!0;case "down":return k!==g.rows-1?a.getCellNodeFromCords(k+1,f).select():a.selectNext(),!0}return!1};c.addListener("command",(k,f)=>{var l=p.$getSelection();if(!p.$isRangeSelection(l))return!1;const u=D(l.anchor.getNode(),
v=>B(v));if(!B(u))return!1;if("deleteCharacter"===k&&0===r.length&&l.isCollapsed()&&0===l.anchor.offset)return!0;if(("indentContent"===k||"outdentContent"===k)&&l.isCollapsed()&&0===r.length)return f=a.getCordsFromCellNode(u),O(f.x,f.y,"indentContent"===k?"forward":"backward"),!0;if(("keyArrowDown"===k||"keyArrowUp"===k)&&l.isCollapsed()&&0===r.length){const v=a.getCordsFromCellNode(u);l=D(l.anchor.getNode(),t=>p.$isElementNode(t));if("keyArrowUp"===k&&l===u.getFirstChild()||"keyArrowDown"===k&&l===
u.getLastChild())return f.preventDefault(),f.stopImmediatePropagation(),O(v.x,v.y,"keyArrowUp"===k?"up":"down"),!0}return!1},4)}}
class K extends p.GridNode{static getType(){return"table"}static clone(a){return new K(a.__key,a.__selectionShape,a.__grid)}constructor(a,b,c){super(a);this.__selectionShape=b;this.__grid=c}createDOM(a,b){const c=document.createElement("table");x(c,a.theme.table);J(this,c,b);return c}updateDOM(){return!1}canExtractContents(){return!1}canBeEmpty(){return!1}setSelectionState(a){this.getWritable().__selectionShape=a;return null==this.__grid?[]:a?I(a.fromX,a.toX,a.fromY,a.toY,this.__grid.cells):I(-1,
-1,-1,-1,this.__grid.cells)}getSelectionState(){return this.__selectionShape}getCordsFromCellNode(a){this.__grid||C(55);const {rows:b,cells:c}=this.__grid;for(let d=0;d<b;d++){var g=c[d];if(null==g)throw Error(`Row not found at x:${d}`);g=g.findIndex(({elem:n})=>p.$getNearestNodeFromDOMNode(n)===a);if(-1!==g)return{x:d,y:g}}throw Error("Cell not found in table.");}getCellNodeFromCords(a,b){this.__grid||C(55);var {cells:c}=this.__grid;c=c[a];if(null==c)throw Error(`Table row x:"${a}" not found.`);
c=c[b];if(null==c)throw Error(`Table cell y:"${b}" in row x:"${a}" not found.`);a=p.$getNearestNodeFromDOMNode(c.elem);if(B(a))return a;throw Error("Node at cords not TableCellNode.");}setGrid(a){this.getWritable().__grid=a}getGrid(){return this.__grid}canSelectBefore(){return!0}}function L(){return new K}function M(a){return a instanceof K}
class N extends p.GridRowNode{static getType(){return"tablerow"}static clone(a){return new N(a.__key)}constructor(a){super(a)}createDOM(a){const b=document.createElement("tr");x(b,a.theme.tableRow);return b}updateDOM(){return!1}canBeEmpty(){return!1}}function P(){return new N}function Q(a){return a instanceof N}function R(a){a=D(a,b=>Q(b));if(Q(a))return a;throw Error("Expected table cell to be inside of table row.");}
function S(a){a=D(a,b=>M(b));if(M(a))return a;throw Error("Expected table cell to be inside of table.");}exports.$createTableCellNode=z;exports.$createTableNode=L;exports.$createTableNodeWithDimensions=function(a,b,c=!0){const g=L();for(let d=0;d<a;d++){const n=P();for(let e=0;e<b;e++){const q=z(0===d&&c),m=p.$createParagraphNode();m.append(p.$createTextNode());q.append(m);n.append(q)}g.append(n)}return g};exports.$createTableRowNode=P;
exports.$deleteTableColumn=function(a,b){const c=a.getChildren();for(let d=0;d<c.length;d++){var g=c[d];if(Q(g)){g=g.getChildren();if(b>=g.length||0>b)throw Error("Table column target index out of range");g[b].remove()}}return a};exports.$getTableCellNodeFromLexicalNode=function(a){a=D(a,b=>B(b));return B(a)?a:null};exports.$getTableColumnIndexFromTableCellNode=function(a){return R(a).getChildren().findIndex(b=>b.is(a))};exports.$getTableNodeFromLexicalNodeOrThrow=S;
exports.$getTableRowIndexFromTableCellNode=function(a){const b=R(a);return S(b).getChildren().findIndex(c=>c.is(b))};exports.$getTableRowNodeFromTableCellNodeOrThrow=R;exports.$insertTableColumn=function(a,b,c=!0,g){const d=a.getChildren();for(let e=0;e<d.length;e++){const p=d[e];if(Q(p))for(let m=0;m<g;m++){const h=z(0===e);h.append(q.$createTextNode());var n=p.getChildren();if(b>=n.length||0>b)throw Error("Table column target index out of range");n=n[b];c?n.insertAfter(h):n.insertBefore(h)}}return a};
exports.$insertTableRow=function(a,b,c=!0,g){var d=a.getChildren();if(b>=d.length||0>b)throw Error("Table row target index out of range");b=d[b];if(Q(b))for(d=0;d<g;d++){const n=b.getChildren().length,e=P();for(let p=0;p<n;p++){const m=z(!1);m.append(q.$createTextNode());e.append(m)}c?b.insertAfter(e):b.insertBefore(e)}else throw Error("Row before insertion index does not exist.");return a};exports.$isTableCellNode=B;exports.$isTableNode=M;exports.$isTableRowNode=Q;
exports.$getTableRowIndexFromTableCellNode=function(a){const b=R(a);return S(b).getChildren().findIndex(c=>c.is(b))};exports.$getTableRowNodeFromTableCellNodeOrThrow=R;exports.$insertTableColumn=function(a,b,c=!0,g){const d=a.getChildren();for(let e=0;e<d.length;e++){const q=d[e];if(Q(q))for(let m=0;m<g;m++){const h=z(0===e);h.append(p.$createTextNode());var n=q.getChildren();if(b>=n.length||0>b)throw Error("Table column target index out of range");n=n[b];c?n.insertAfter(h):n.insertBefore(h)}}return a};
exports.$insertTableRow=function(a,b,c=!0,g){var d=a.getChildren();if(b>=d.length||0>b)throw Error("Table row target index out of range");b=d[b];if(Q(b))for(d=0;d<g;d++){const n=b.getChildren().length,e=P();for(let q=0;q<n;q++){const m=z(!1);m.append(p.$createTextNode());e.append(m)}c?b.insertAfter(e):b.insertBefore(e)}else throw Error("Row before insertion index does not exist.");return a};exports.$isTableCellNode=B;exports.$isTableNode=M;exports.$isTableRowNode=Q;
exports.$removeTableRowAtIndex=function(a,b){const c=a.getChildren();if(b>=c.length||0>b)throw Error("Expected table cell to be inside of table row.");c[b].remove();return a};exports.TableCellNode=y;exports.TableNode=K;exports.TableRowNode=N;

@@ -15,6 +15,6 @@ {

"license": "MIT",
"version": "0.1.9",
"version": "0.1.10",
"main": "LexicalTable.js",
"peerDependencies": {
"lexical": "0.1.9"
"lexical": "0.1.10"
},

@@ -21,0 +21,0 @@ "repository": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc