diff --git a/figma-to-lit/tsconfig.json b/figma-to-lit/tsconfig.json deleted file mode 100644 index de8f042..0000000 --- a/figma-to-lit/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "lib": ["es2017"], - "strict": true, - "moduleResolution": "node", - "typeRoots": [ - "./node_modules/@types", - "./node_modules/@figma" - ] - } -} diff --git a/figma_lit_example/assembly/tsconfig.json b/figma_lit_example/assembly/tsconfig.json deleted file mode 100644 index e28fcf2..0000000 --- a/figma_lit_example/assembly/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "assemblyscript/std/assembly.json", - "include": [ - "./**/*.ts" - ] -} \ No newline at end of file diff --git a/figma_lit_example/tsconfig.json b/figma_lit_example/tsconfig.json deleted file mode 100644 index 7539ac5..0000000 --- a/figma_lit_example/tsconfig.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "compilerOptions": { - "target": "es2017", - "module": "esNext", - "moduleResolution": "node", - "lib": ["es2017", "dom", "dom.iterable"], - "typeRoots": ["./node_modules/@types", "./node_modules/@figma"], - "declaration": true, - "sourceMap": true, - "inlineSources": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "experimentalDecorators": true, - "skipLibCheck": true, - "strict": true, - "noImplicitAny": false, - "outDir": "./lib", - "baseUrl": "./packages", - "importHelpers": true, - "plugins": [ - { - "name": "ts-lit-plugin", - "rules": { - "no-unknown-tag-name": "error", - "no-unclosed-tag": "error", - "no-unknown-property": "error", - "no-unintended-mixed-binding": "error", - "no-invalid-boolean-binding": "error", - "no-expressionless-property-binding": "error", - "no-noncallable-event-binding": "error", - "no-boolean-in-attribute-binding": "error", - "no-complex-attribute-binding": "error", - "no-nullable-attribute-binding": "error", - "no-incompatible-type-binding": "error", - "no-invalid-directive-binding": "error", - "no-incompatible-property-type": "error", - "no-unknown-property-converter": "error", - "no-invalid-attribute-name": "error", - "no-invalid-tag-name": "error", - "no-unknown-attribute": "off", - "no-unknown-event": "off", - "no-unknown-slot": "off", - "no-invalid-css": "off" - } - } - ] - }, - "include": ["src/**/*.ts"], - "references": [] -} diff --git a/index.html b/index.html index 3b0ef7d..7f8d5c8 100644 --- a/index.html +++ b/index.html @@ -1,705 +1,12 @@ - + - - - Lit Web Components Showcase - - - - + + - - - - - -
- - -
-
- -

Lit Showcase Hub

-

Explore a rich collection of modular Lit Web Components, prototypes, interactive instruments, databases, and custom UI modules. Select any example from the sidebar to preview in real-time with responsive viewport sandboxing.

-
-
-
20
-
Projects
-
-
-
100%
-
Vite MPA
-
-
-
Nginx
-
Deploy
-
-
-
-
- - -
-
-
- - Project Name -
-
- - - - 🌐 Open Tab -
-
-
- -
-
- -
- - + Redirecting to Lit Web Components Showcase... - + \ No newline at end of file diff --git a/lit-3d-piano/.gitignore b/lit-3d-piano/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-3d-piano/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-3d-piano/README.md b/lit-3d-piano/README.md deleted file mode 100644 index b4617ff..0000000 --- a/lit-3d-piano/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# 3D Piano - -[![Demo](https://github.com/rodydavis/lit-3d-piano/actions/workflows/ci.yml/badge.svg)](https://github.com/rodydavis/lit-3d-piano/actions/workflows/ci.yml) - -3D Piano built with Lit, Three.js and Tone.js - -Online demo [here](https://rodydavis.github.io/lit-3d-piano/). - -![](/screenshot.png) \ No newline at end of file diff --git a/lit-3d-piano/index.html b/lit-3d-piano/index.html deleted file mode 100644 index 61168b4..0000000 --- a/lit-3d-piano/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - 3D Piano - - - - - - - diff --git a/lit-3d-piano/screenshot.png b/lit-3d-piano/screenshot.png deleted file mode 100644 index 3240ba2..0000000 Binary files a/lit-3d-piano/screenshot.png and /dev/null differ diff --git a/lit-3d-piano/src/favicon.svg b/lit-3d-piano/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-3d-piano/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-3d-piano/src/vite-env.d.ts b/lit-3d-piano/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-3d-piano/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-3d-piano/tsconfig.json b/lit-3d-piano/tsconfig.json deleted file mode 100644 index 3c7c385..0000000 --- a/lit-3d-piano/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "target": "esnext", - "lib": [ - "esnext", - "dom" - ], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [] -} \ No newline at end of file diff --git a/lit-calculator/.bazelignore b/lit-calculator/.bazelignore deleted file mode 100644 index 3c3629e..0000000 --- a/lit-calculator/.bazelignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/lit-calculator/.bazelrc b/lit-calculator/.bazelrc deleted file mode 100644 index 0a284db..0000000 --- a/lit-calculator/.bazelrc +++ /dev/null @@ -1 +0,0 @@ -common --@aspect_rules_ts//ts:skipLibCheck=honor_tsconfig diff --git a/lit-calculator/.gitattributes b/lit-calculator/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/lit-calculator/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/lit-calculator/.gitignore b/lit-calculator/.gitignore deleted file mode 100644 index f04a3d2..0000000 --- a/lit-calculator/.gitignore +++ /dev/null @@ -1,55 +0,0 @@ -# ========================================== -# 🌌 Federated Workspaces - Ultimate Ignores -# ========================================== - -# --- System & Editor Files --- -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db -.vscode/ -.idea/ -*.swp -*.swo - -# --- Bazel Convenience Symlinks & Outputs --- -bazel-* -bazel_out/ - -# --- C/C++ Outputs --- -*.o -*.obj -*.a -*.lib -*.so -*.dylib -*.dll -*.out -*.exe - -# --- Go Outputs --- -*.test -*.prof -__debug_bin -MODULE.bazel.lock - -# --- Node / JavaScript / pnpm --- -node_modules/ -.npm/ -.pnpm-store/ -.pnpm-debug.log* -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# --- Dart / Flutter --- -.dart_tool/ -.packages -.pub-cache/ -.pub/ -/build/ -*.flutter-plugins -*.flutter-plugins-dependencies diff --git a/lit-calculator/.nojekyll b/lit-calculator/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/lit-calculator/BUILD.bazel b/lit-calculator/BUILD.bazel deleted file mode 100644 index 35e6320..0000000 --- a/lit-calculator/BUILD.bazel +++ /dev/null @@ -1,24 +0,0 @@ -load("@aspect_rules_js//npm:defs.bzl", "npm_link_package") -load("@npm//:defs.bzl", "npm_link_all_packages") -load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") - -npm_link_all_packages(name = "node_modules") - -ts_config( - name = "tsconfig", - src = "tsconfig.json", - visibility = ["//visibility:public"], -) - -ts_project( - name = "build", - srcs = glob(["docs/**/*.ts"]), - declaration = True, - source_map = True, - transpiler = "tsc", - tsconfig = ":tsconfig", - deps = [ - "//:node_modules", - ], - visibility = ["//visibility:public"], -) diff --git a/lit-calculator/Dockerfile b/lit-calculator/Dockerfile deleted file mode 100644 index fbf53b6..0000000 --- a/lit-calculator/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM nginx:alpine -COPY docs /usr/share/nginx/html -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] diff --git a/lit-calculator/MODULE.bazel b/lit-calculator/MODULE.bazel deleted file mode 100644 index 7a6bd1e..0000000 --- a/lit-calculator/MODULE.bazel +++ /dev/null @@ -1,22 +0,0 @@ -module( - name = "lit_calculator", - version = "1.0.0", -) - -bazel_dep(name = "aspect_rules_js", version = "3.1.1") -bazel_dep(name = "aspect_rules_ts", version = "3.1.0") -bazel_dep(name = "rules_nodejs", version = "6.7.3") - -npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm") - -npm.npm_translate_lock( - name = "npm", - pnpm_lock = "//:pnpm-lock.yaml", - verify_node_modules_ignored = "//:.bazelignore", -) - -use_repo(npm, "npm") - -rules_ts_ext = use_extension("@aspect_rules_ts//ts:extensions.bzl", "ext", dev_dependency = True) -rules_ts_ext.deps() -use_repo(rules_ts_ext, "npm_typescript") diff --git a/lit-calculator/README.md b/lit-calculator/README.md deleted file mode 100644 index 0558a02..0000000 --- a/lit-calculator/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Lit Calculator - -Reactive calculator made with LitElement and no build system or framework. - -Demo: https://rodydavis.github.io/lit-calculator/ diff --git a/lit-calculator/docs/calculator.js b/lit-calculator/docs/calculator.js deleted file mode 100644 index 7e90a6f..0000000 --- a/lit-calculator/docs/calculator.js +++ /dev/null @@ -1,272 +0,0 @@ -var at=Object.defineProperty;var St=Object.getOwnPropertyDescriptor;var Ct=(o,t,e)=>t in o?at(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var c=(o,t,e,s)=>{for(var i=s>1?void 0:s?St(t,e):t,r=o.length-1,n;r>=0;r--)(n=o[r])&&(i=(s?n(t,e,i):n(i))||i);return s&&i&&at(t,e,i),i};var v=(o,t,e)=>(Ct(o,typeof t!="symbol"?t+"":t,e),e);var I=globalThis,V=I.ShadowRoot&&(I.ShadyCSS===void 0||I.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,G=Symbol(),lt=new WeakMap,R=class{constructor(t,e,s){if(this._$cssResult$=!0,s!==G)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o,e=this.t;if(V&&t===void 0){let s=e!==void 0&&e.length===1;s&&(t=lt.get(e)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),s&<.set(e,t))}return t}toString(){return this.cssText}},ht=o=>new R(typeof o=="string"?o:o+"",void 0,G),g=(o,...t)=>{let e=o.length===1?o[0]:t.reduce((s,i,r)=>s+(n=>{if(n._$cssResult$===!0)return n.cssText;if(typeof n=="number")return n;throw Error("Value passed to 'css' function must be a 'css' function result: "+n+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+o[r+1],o[0]);return new R(e,o,G)},ct=(o,t)=>{if(V)o.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(let e of t){let s=document.createElement("style"),i=I.litNonce;i!==void 0&&s.setAttribute("nonce",i),s.textContent=e.cssText,o.appendChild(s)}},Q=V?o=>o:o=>o instanceof CSSStyleSheet?(t=>{let e="";for(let s of t.cssRules)e+=s.cssText;return ht(e)})(o):o;var{is:wt,defineProperty:kt,getOwnPropertyDescriptor:Pt,getOwnPropertyNames:Ut,getOwnPropertySymbols:Ot,getPrototypeOf:Tt}=Object,W=globalThis,dt=W.trustedTypes,Mt=dt?dt.emptyScript:"",Rt=W.reactiveElementPolyfillSupport,H=(o,t)=>o,N={toAttribute(o,t){switch(t){case Boolean:o=o?Mt:null;break;case Object:case Array:o=o==null?o:JSON.stringify(o)}return o},fromAttribute(o,t){let e=o;switch(t){case Boolean:e=o!==null;break;case Number:e=o===null?null:Number(o);break;case Object:case Array:try{e=JSON.parse(o)}catch{e=null}}return e}},F=(o,t)=>!wt(o,t),pt={attribute:!0,type:String,converter:N,reflect:!1,useDefault:!1,hasChanged:F};Symbol.metadata??=Symbol("metadata"),W.litPropertyMetadata??=new WeakMap;var _=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=pt){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){let s=Symbol(),i=this.getPropertyDescriptor(t,s,e);i!==void 0&&kt(this.prototype,t,i)}}static getPropertyDescriptor(t,e,s){let{get:i,set:r}=Pt(this.prototype,t)??{get(){return this[e]},set(n){this[e]=n}};return{get:i,set(n){let l=i?.call(this);r?.call(this,n),this.requestUpdate(t,l,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??pt}static _$Ei(){if(this.hasOwnProperty(H("elementProperties")))return;let t=Tt(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(H("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(H("properties"))){let e=this.properties,s=[...Ut(e),...Ot(e)];for(let i of s)this.createProperty(i,e[i])}let t=this[Symbol.metadata];if(t!==null){let e=litPropertyMetadata.get(t);if(e!==void 0)for(let[s,i]of e)this.elementProperties.set(s,i)}this._$Eh=new Map;for(let[e,s]of this.elementProperties){let i=this._$Eu(e,s);i!==void 0&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){let e=[];if(Array.isArray(t)){let s=new Set(t.flat(1/0).reverse());for(let i of s)e.unshift(Q(i))}else t!==void 0&&e.push(Q(t));return e}static _$Eu(t,e){let s=e.attribute;return s===!1?void 0:typeof s=="string"?s:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){let t=new Map,e=this.constructor.elementProperties;for(let s of e.keys())this.hasOwnProperty(s)&&(t.set(s,this[s]),delete this[s]);t.size>0&&(this._$Ep=t)}createRenderRoot(){let t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return ct(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,s){this._$AK(t,s)}_$ET(t,e){let s=this.constructor.elementProperties.get(t),i=this.constructor._$Eu(t,s);if(i!==void 0&&s.reflect===!0){let r=(s.converter?.toAttribute!==void 0?s.converter:N).toAttribute(e,s.type);this._$Em=t,r==null?this.removeAttribute(i):this.setAttribute(i,r),this._$Em=null}}_$AK(t,e){let s=this.constructor,i=s._$Eh.get(t);if(i!==void 0&&this._$Em!==i){let r=s.getPropertyOptions(i),n=typeof r.converter=="function"?{fromAttribute:r.converter}:r.converter?.fromAttribute!==void 0?r.converter:N;this._$Em=i;let l=n.fromAttribute(e,r.type);this[i]=l??this._$Ej?.get(i)??l,this._$Em=null}}requestUpdate(t,e,s,i=!1,r){if(t!==void 0){let n=this.constructor;if(i===!1&&(r=this[t]),s??=n.getPropertyOptions(t),!((s.hasChanged??F)(r,e)||s.useDefault&&s.reflect&&r===this._$Ej?.get(t)&&!this.hasAttribute(n._$Eu(t,s))))return;this.C(t,e,s)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,e,{useDefault:s,reflect:i,wrapped:r},n){s&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,n??e??this[t]),r!==!0||n!==void 0)||(this._$AL.has(t)||(this.hasUpdated||s||(e=void 0),this._$AL.set(t,e)),i===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}let t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(let[i,r]of this._$Ep)this[i]=r;this._$Ep=void 0}let s=this.constructor.elementProperties;if(s.size>0)for(let[i,r]of s){let{wrapped:n}=r,l=this[i];n!==!0||this._$AL.has(i)||l===void 0||this.C(i,void 0,r,l)}}let t=!1,e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(s=>s.hostUpdate?.()),this.update(e)):this._$EM()}catch(s){throw t=!1,this._$EM(),s}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(t){}firstUpdated(t){}};_.elementStyles=[],_.shadowRootOptions={mode:"open"},_[H("elementProperties")]=new Map,_[H("finalized")]=new Map,Rt?.({ReactiveElement:_}),(W.reactiveElementVersions??=[]).push("2.1.2");var it=globalThis,ut=o=>o,J=it.trustedTypes,mt=J?J.createPolicy("lit-html",{createHTML:o=>o}):void 0,bt="$lit$",A=`lit$${Math.random().toFixed(9).slice(2)}$`,vt="?"+A,Ht=`<${vt}>`,U=document,q=()=>U.createComment(""),j=o=>o===null||typeof o!="object"&&typeof o!="function",ot=Array.isArray,Nt=o=>ot(o)||typeof o?.[Symbol.iterator]=="function",X=`[ -\f\r]`,L=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,$t=/-->/g,ft=/>/g,k=RegExp(`>|${X}(?:([^\\s"'>=/]+)(${X}*=${X}*(?:[^ -\f\r"'\`<>=]|("|')|))|$)`,"g"),gt=/'/g,_t=/"/g,At=/^(?:script|style|textarea|title)$/i,rt=o=>(t,...e)=>({_$litType$:o,strings:t,values:e}),x=rt(1),Jt=rt(2),Zt=rt(3),O=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),yt=new WeakMap,P=U.createTreeWalker(U,129);function xt(o,t){if(!ot(o)||!o.hasOwnProperty("raw"))throw Error("invalid template strings array");return mt!==void 0?mt.createHTML(t):t}var Lt=(o,t)=>{let e=o.length-1,s=[],i,r=t===2?"":t===3?"":"",n=L;for(let l=0;l"?(n=i??L,h=-1):m[1]===void 0?h=-2:(h=n.lastIndex-m[2].length,d=m[1],n=m[3]===void 0?k:m[3]==='"'?_t:gt):n===_t||n===gt?n=k:n===$t||n===ft?n=L:(n=k,i=void 0);let b=n===k&&o[l+1].startsWith("/>")?" ":"";r+=n===L?a+Ht:h>=0?(s.push(d),a.slice(0,h)+bt+a.slice(h)+A+b):a+A+(h===-2?l:b)}return[xt(o,r+(o[e]||"")+(t===2?"":t===3?"":"")),s]},z=class o{constructor({strings:t,_$litType$:e},s){let i;this.parts=[];let r=0,n=0,l=t.length-1,a=this.parts,[d,m]=Lt(t,e);if(this.el=o.createElement(d,s),P.currentNode=this.el.content,e===2||e===3){let h=this.el.content.firstChild;h.replaceWith(...h.childNodes)}for(;(i=P.nextNode())!==null&&a.length0){i.textContent=J?J.emptyScript:"";for(let b=0;b2||s[0]!==""||s[1]!==""?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=p}_$AI(t,e=this,s,i){let r=this.strings,n=!1;if(r===void 0)t=T(this,t,e,0),n=!j(t)||t!==this._$AH&&t!==O,n&&(this._$AH=t);else{let l=t,a,d;for(t=r[0],a=0;a{let s=e?.renderBefore??t,i=s._$litPart$;if(i===void 0){let r=e?.renderBefore??null;s._$litPart$=i=new B(t.insertBefore(q(),r),r,void 0,e??{})}return i._$AI(o),i};var nt=globalThis,$=class extends _{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){let t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){let e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=Et(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return O}};$._$litElement$=!0,$.finalized=!0,nt.litElementHydrateSupport?.({LitElement:$});var jt=nt.litElementPolyfillSupport;jt?.({LitElement:$});(nt.litElementVersions??=[]).push("4.2.2");var E=o=>(t,e)=>{e!==void 0?e.addInitializer(()=>{customElements.define(o,t)}):customElements.define(o,t)};var zt={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:F},Bt=(o=zt,t,e)=>{let{kind:s,metadata:i}=e,r=globalThis.litPropertyMetadata.get(i);if(r===void 0&&globalThis.litPropertyMetadata.set(i,r=new Map),s==="setter"&&((o=Object.create(o)).wrapped=!0),r.set(e.name,o),s==="accessor"){let{name:n}=e;return{set(l){let a=t.get.call(this);t.set.call(this,l),this.requestUpdate(n,a,o,!0,l)},init(l){return l!==void 0&&this.C(n,void 0,o,l),l}}}if(s==="setter"){let{name:n}=e;return function(l){let a=this[n];t.call(this,l),this.requestUpdate(n,a,o,!0,l)}}throw Error("Unsupported decorator location: "+s)};function u(o){return(t,e)=>typeof e=="object"?Bt(o,t,e):((s,i,r)=>{let n=i.hasOwnProperty(r);return i.constructor.createProperty(r,s),n?Object.getOwnPropertyDescriptor(i,r):void 0})(o,t,e)}var S=class extends ${number="0";color="black";textColor="white";_onTap(t){t.preventDefault();let e=new CustomEvent("select-number",{detail:{value:this.number},bubbles:!0,cancelable:!0});window.dispatchEvent(e)}render(){return x` `}};v(S,"styles",g` - #base { - width: 100%; - height: 100%; - border-radius: 10px; - text-align: center; - float: left; - } - - #base:hover { - box-shadow: 0 0 11px rgba(33, 33, 33, 0.2); - } - - #base:active { - background-color: lightgrey; - } - - button { - outline: 0 none; - color: white; - margin-top: 10px; - margin-bottom: 10px; - font-size: 20px; - } - `),c([u()],S.prototype,"number",2),c([u()],S.prototype,"color",2),c([u()],S.prototype,"textColor",2),S=c([E("keypad-input")],S);var y=class extends ${accentColor="blue";textColor="white";actionColor="black";actionTextColor="white";render(){return x`
- - - - - - - - - - - - -
`}};v(y,"styles",g` - #base { - display: grid; - grid-template-columns: 33% 33% 33%; - padding-left: calc(var(--base-padding) / 2); - padding-right: calc(var(--base-padding) / 2); - } - - keypad-input { - display: inline-grid; - margin: 5px; - } - `),c([u()],y.prototype,"accentColor",2),c([u()],y.prototype,"textColor",2),c([u()],y.prototype,"actionColor",2),c([u()],y.prototype,"actionTextColor",2),y=c([E("key-pad")],y);var C=class extends ${color="black";textColor="white";value="";render(){return x`
-
- ${this.value||"0"} -
-
`}};v(C,"styles",g` - #base { - background-color: black; - text-align: end; - display: inline-block; - margin: var(--base-padding); - width: calc(100% - calc(var(--base-padding) * 2)); - border-bottom: 2px solid black; - } - - #text-display { - color: white; - margin: 0px; - padding-top: 40px; - padding-right: 10px; - padding-bottom: 10px; - font-size: 36px; - } - `),c([u()],C.prototype,"color",2),c([u()],C.prototype,"textColor",2),c([u()],C.prototype,"value",2),C=c([E("display-output")],C);var w=class extends ${width="500px";primaryColor="red";accentColor="black";connectedCallback(){super.connectedCallback(),window.addEventListener("select-number",this._handleNumber)}disconnectedCallback(){window.removeEventListener("select-number",this._handleNumber),super.disconnectedCallback()}_staging="";_value="";_mode="";get mode(){return this._mode}set mode(t){let e=this._mode,s=this.value;this._mode=t,this.requestUpdate("mode",e),this.requestUpdate("value",s)}get value(){return this.mode==""?this._value:this._staging}set value(t){var e="";this.mode==""?(e=this._value,this._value=t):(e=this._staging,this._staging=t),this.requestUpdate("value",e)}_handleNumber=t=>{let e=t.detail.value;if(t.stopPropagation(),e==="="){this.calculate();return}this.value==="0"&&(this.value=""),!(e==="."&&this.value.includes("."))&&(this.value+=e)};clear=()=>{this.value="",this._staging="",this._value="",this.mode=""};calculate=()=>{let t=Number(this._staging||"0"),e=Number(this._value||"0");var s=0;switch(this.mode){case"+":s=t+e;break;case"-":s=t-e;break;case"/":s=t/e;break;case"*":s=t*e;break;default:break}let i=s.toString();this.value=i,this._staging=i};render(){return x`
- -
- - - - - -
- -
`}};v(w,"styles",g` - #base { - border: 2px solid black; - padding-bottom: 20px; - --base-padding: 10px; - } - - #actions { - padding-top: var(--base-padding); - padding-left: var(--base-padding); - } - - button { - font-size: 17px; - } - `),c([u()],w.prototype,"width",2),c([u()],w.prototype,"primaryColor",2),c([u()],w.prototype,"accentColor",2),w=c([E("app-calculator")],w);export{w as AppCalculator}; -/*! Bundled license information: - -@lit/reactive-element/css-tag.js: - (** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/reactive-element.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -lit-html/lit-html.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -lit-element/lit-element.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -lit-html/is-server.js: - (** - * @license - * Copyright 2022 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/custom-element.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/property.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/state.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/event-options.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/base.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/query.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/query-all.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/query-async.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/query-assigned-elements.js: - (** - * @license - * Copyright 2021 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) - -@lit/reactive-element/decorators/query-assigned-nodes.js: - (** - * @license - * Copyright 2017 Google LLC - * SPDX-License-Identifier: BSD-3-Clause - *) -*/ diff --git a/lit-calculator/docs/calculator.ts b/lit-calculator/docs/calculator.ts deleted file mode 100644 index 5cd92a5..0000000 --- a/lit-calculator/docs/calculator.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { LitElement, html, css } from "lit"; -import { customElement, property } from "lit/decorators.js"; -import "./keypad-input.js"; -import "./key-pad.js"; -import "./display-output.js"; - -@customElement("app-calculator") -export class AppCalculator extends LitElement { - @property() - width = "500px"; - - @property() - primaryColor = "red"; - - @property() - accentColor = "black"; - - static styles = css` - #base { - border: 2px solid black; - padding-bottom: 20px; - --base-padding: 10px; - } - - #actions { - padding-top: var(--base-padding); - padding-left: var(--base-padding); - } - - button { - font-size: 17px; - } - `; - - connectedCallback() { - super.connectedCallback(); - // @ts-ignore - window.addEventListener("select-number", this._handleNumber); - } - disconnectedCallback() { - // @ts-ignore - window.removeEventListener("select-number", this._handleNumber); - super.disconnectedCallback(); - } - - _staging: string = ""; - _value: string = ""; - _mode: string = ""; - - public get mode(): string { - return this._mode; - } - - public set mode(v: string) { - const oldMode = this._mode; - const oldVal = this.value; - this._mode = v; - - // @ts-ignore - this.requestUpdate("mode", oldMode); - // @ts-ignore - this.requestUpdate("value", oldVal); - } - - private get value(): string { - if (this.mode == "") return this._value; - return this._staging; - } - - private set value(v: string) { - var oldVal = ""; - if (this.mode == "") { - oldVal = this._value; - this._value = v; - } else { - oldVal = this._staging; - this._staging = v; - } - // @ts-ignore - this.requestUpdate("value", oldVal); - } - - _handleNumber = (event: CustomEvent) => { - const num = event.detail.value; - event.stopPropagation(); - if (num === "=") { - this.calculate(); - return; - } - if (this.value === "0") { - this.value = ""; - } - if (num === "." && this.value.includes(".")) { - return; - } - this.value += num; - }; - - clear = () => { - this.value = ""; - this._staging = ""; - this._value = ""; - this.mode = ""; - }; - - calculate = () => { - const staging = Number(this._staging || "0"); - const current = Number(this._value || "0"); - var result: number = 0; - // Calculate - switch (this.mode) { - case "+": - result = staging + current; - break; - case "-": - result = staging - current; - break; - case "/": - result = staging / current; - break; - case "*": - result = staging * current; - break; - default: - break; - } - const output = result.toString(); - this.value = output; - this._staging = output; - }; - - // Render element DOM by returning a `lit-html` template. - render() { - return html`
- -
- - - - - -
- -
`; - } -} diff --git a/lit-calculator/docs/display-output.ts b/lit-calculator/docs/display-output.ts deleted file mode 100644 index bccfff9..0000000 --- a/lit-calculator/docs/display-output.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { LitElement, html, css } from "lit"; -import { customElement, property } from "lit/decorators.js"; - -@customElement("display-output") -export class CalcDisplay extends LitElement { - @property() - color = "black"; - - @property() - textColor = "white"; - - @property() - value = ""; - - static styles = css` - #base { - background-color: black; - text-align: end; - display: inline-block; - margin: var(--base-padding); - width: calc(100% - calc(var(--base-padding) * 2)); - border-bottom: 2px solid black; - } - - #text-display { - color: white; - margin: 0px; - padding-top: 40px; - padding-right: 10px; - padding-bottom: 10px; - font-size: 36px; - } - `; - - // Render element DOM by returning a `lit-html` template. - render() { - return html`
-
- ${this.value || "0"} -
-
`; - } -} diff --git a/lit-calculator/tsconfig.json b/lit-calculator/tsconfig.json deleted file mode 100644 index d6a7d71..0000000 --- a/lit-calculator/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "node", - "lib": ["esnext", "dom"], - "declaration": true, - "sourceMap": true, - "inlineSources": false, - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitThis": true, - "skipLibCheck": true, - "experimentalDecorators": true - }, - "include": ["docs/**/*"], - "exclude": ["node_modules", "**/*.spec.ts"] -} diff --git a/lit-code-editor/.gitignore b/lit-code-editor/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-code-editor/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-code-editor/README.md b/lit-code-editor/README.md deleted file mode 100644 index a77440d..0000000 --- a/lit-code-editor/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Lit Code Editor - -[![Demo](https://github.com/rodydavis/lit-code-editor/actions/workflows/ci.yml/badge.svg)](https://github.com/rodydavis/lit-code-editor/actions/workflows/ci.yml) - -Simple example of Lit + Vite + Monaco Editor as a web component that can be embedded in pages. - -Online demo: https://rodydavis.github.io/lit-code-editor/ - -Another version to look at: https://github.com/vanillawc/wc-monaco-editor diff --git a/lit-code-editor/index.html b/lit-code-editor/index.html deleted file mode 100644 index 18b51c4..0000000 --- a/lit-code-editor/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - Lit Code Editor - - - - - - - - - diff --git a/lit-code-editor/src/favicon.svg b/lit-code-editor/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-code-editor/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-code-editor/src/vite-env.d.ts b/lit-code-editor/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-code-editor/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-code-editor/tsconfig.json b/lit-code-editor/tsconfig.json deleted file mode 100644 index d17e916..0000000 --- a/lit-code-editor/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/lit-3d-piano/src/piano-component.ts b/lit-components/lit-3d-piano/piano-component.ts similarity index 89% rename from lit-3d-piano/src/piano-component.ts rename to lit-components/lit-3d-piano/piano-component.ts index b0ea6d0..e6c95b5 100644 --- a/lit-3d-piano/src/piano-component.ts +++ b/lit-components/lit-3d-piano/piano-component.ts @@ -14,7 +14,7 @@ export class PianoComponent extends LitElement { scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera( 70, - window.innerWidth / window.innerHeight, + 1, 0.001, 10 ); @@ -34,15 +34,17 @@ export class PianoComponent extends LitElement { user-select: none; -webkit-user-select: none; -moz-user-select: none; + position: relative; } canvas { width: 100%; height: 100%; z-index: 0; + display: block; } .controls { z-index: 1; - position: fixed; + position: absolute; color: white; font-size: 18px; right: 10px; @@ -50,7 +52,7 @@ export class PianoComponent extends LitElement { } .note { z-index: 1; - position: fixed; + position: absolute; color: white; font-size: 18px; left: 10px; @@ -59,9 +61,12 @@ export class PianoComponent extends LitElement { `; render() { - const tapNote = (x: number, y: number) => { - const dx = (x / window.innerWidth) * 2 - 1; - const dy = -(y / window.innerHeight) * 2 + 1; + const tapNote = (clientX: number, clientY: number) => { + const rect = this.canvas.getBoundingClientRect(); + const localX = clientX - rect.left; + const localY = clientY - rect.top; + const dx = (localX / rect.width) * 2 - 1; + const dy = -(localY / rect.height) * 2 + 1; this.findNote(new THREE.Vector2(dx, dy)); }; return html`
@@ -233,7 +238,14 @@ export class PianoComponent extends LitElement { this.controls = new OrbitControls(this.camera, this.renderer.domElement); this.controls.screenSpacePanning = true; this.controls.enableKeys = true; - this.renderer!.setSize(window.innerWidth, window.innerHeight); + + // Size relative to current component offset bounds + const width = this.offsetWidth || window.innerWidth; + const height = this.offsetHeight || window.innerHeight; + this.renderer.setSize(width, height); + this.camera.aspect = width / height; + this.camera.updateProjectionMatrix(); + this.renderer.setAnimationLoop(() => this.paint()); this.renderer.setClearColor("red", 1); @@ -284,7 +296,11 @@ export class PianoComponent extends LitElement { window.addEventListener( "resize", () => { - this.renderer!.setSize(window.innerWidth, window.innerHeight); + const w = this.offsetWidth || window.innerWidth; + const h = this.offsetHeight || window.innerHeight; + this.renderer!.setSize(w, h); + this.camera.aspect = w / h; + this.camera.updateProjectionMatrix(); }, false ); diff --git a/lit-components/lit-3d-piano/piano.test.ts b/lit-components/lit-3d-piano/piano.test.ts new file mode 100644 index 0000000..6abc7b8 --- /dev/null +++ b/lit-components/lit-3d-piano/piano.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./piano-component"; + +describe("Lit 3D Piano Component", () => { + test("registers piano-component custom element successfully", () => { + expect(customElements.get("piano-component")).toBeDefined(); + }); + + test("mounts piano-component to document body", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("piano-component"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-components/lit-calculator/calculator.test.ts b/lit-components/lit-calculator/calculator.test.ts new file mode 100644 index 0000000..5b62561 --- /dev/null +++ b/lit-components/lit-calculator/calculator.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, test } from "vitest"; +import { AppCalculator } from "./calculator"; +import "./display-output"; +import "./keypad-input"; + +describe("Lit Calculator Component Logic", () => { + test("registers calculator custom elements successfully", () => { + expect(customElements.get("app-calculator")).toBeDefined(); + expect(customElements.get("display-output")).toBeDefined(); + expect(customElements.get("keypad-input")).toBeDefined(); + }); + + test("calculates addition correctly", () => { + const calc = new AppCalculator(); + calc._value = "12"; + calc.mode = "+"; + calc._staging = "8"; + calc.calculate(); + expect(calc._value).toBe("20"); + expect(calc.mode).toBe(""); + expect(calc._staging).toBe(""); + }); + + test("calculates subtraction correctly", () => { + const calc = new AppCalculator(); + calc._value = "15"; + calc.mode = "-"; + calc._staging = "6"; + calc.calculate(); + expect(calc._value).toBe("9"); + expect(calc.mode).toBe(""); + }); + + test("calculates multiplication correctly", () => { + const calc = new AppCalculator(); + calc._value = "4"; + calc.mode = "*"; + calc._staging = "5"; + calc.calculate(); + expect(calc._value).toBe("20"); + }); + + test("calculates division correctly", () => { + const calc = new AppCalculator(); + calc._value = "20"; + calc.mode = "/"; + calc._staging = "4"; + calc.calculate(); + expect(calc._value).toBe("5"); + }); + + test("handles division by zero gracefully", () => { + const calc = new AppCalculator(); + calc._value = "10"; + calc.mode = "/"; + calc._staging = "0"; + calc.calculate(); + expect(calc._value).toBe("0"); + }); +}); diff --git a/lit-components/lit-calculator/calculator.ts b/lit-components/lit-calculator/calculator.ts new file mode 100644 index 0000000..971d280 --- /dev/null +++ b/lit-components/lit-calculator/calculator.ts @@ -0,0 +1,242 @@ +import { LitElement, html, css } from "lit"; +import { customElement, property } from "lit/decorators.js"; +import "./keypad-input.js"; +import "./key-pad.js"; +import "./display-output.js"; + +@customElement("app-calculator") +export class AppCalculator extends LitElement { + @property() + width = "500px"; + + @property() + primaryColor = "#1a1f2c"; + + @property() + accentColor = "black"; + + static styles = css` + :host { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + min-height: 500px; + box-sizing: border-box; + } + + #base { + border: 3px solid #1a1b1f; + border-radius: 20px; + padding: 24px; + background: #2a2c33; + box-shadow: + 0 25px 50px -12px rgba(0, 0, 0, 0.7), + inset 0 1px 0 rgba(255, 255, 255, 0.15); + box-sizing: border-box; + display: flex; + flex-direction: column; + gap: 18px; + } + + #actions { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 12px; + padding: 0 5px; + } + + button { + background: #3e424b; + border: none; + border-bottom: 3px solid #1a1b1f; + color: #fff; + padding: 12px; + font-size: 18px; + font-weight: 700; + border-radius: 8px; + cursor: pointer; + transition: all 0.08s ease; + box-shadow: 0 4px 6px rgba(0,0,0,0.3); + display: flex; + align-items: center; + justify-content: center; + } + + button:hover { + background: #4a4f59; + } + + button:active { + transform: translateY(2px); + border-bottom-width: 1px; + box-shadow: 0 1px 3px rgba(0,0,0,0.2); + } + + button.operator { + background: #e76f51; + border-bottom-color: #9d3f27; + color: #ffffff; + } + + button.operator:hover { + background: #f4a261; + } + + button.clear-btn { + background: #d62828; + border-bottom-color: #7a1212; + color: #ffffff; + } + + button.clear-btn:hover { + background: #e63946; + } + + button:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none !important; + border-bottom-width: 3px !important; + box-shadow: 0 4px 6px rgba(0,0,0,0.3) !important; + } + `; + + connectedCallback() { + super.connectedCallback(); + // @ts-ignore + window.addEventListener("select-number", this._handleNumber); + } + disconnectedCallback() { + // @ts-ignore + window.removeEventListener("select-number", this._handleNumber); + super.disconnectedCallback(); + } + + _staging: string = ""; + _value: string = ""; + _mode: string = ""; + + public get mode(): string { + return this._mode; + } + + public set mode(v: string) { + const oldMode = this._mode; + const oldVal = this.value; + this._mode = v; + + // @ts-ignore + this.requestUpdate("mode", oldMode); + // @ts-ignore + this.requestUpdate("value", oldVal); + } + + public get value(): string { + if (this.mode === "") return this._value; + return this._staging; + } + + public set value(v: string) { + var oldVal = ""; + if (this.mode === "") { + oldVal = this._value; + this._value = v; + } else { + oldVal = this._staging; + this._staging = v; + } + // @ts-ignore + this.requestUpdate("value", oldVal); + } + + public get displayValue(): string { + if (this.mode !== "" && this._staging === "") { + return this._value || "0"; + } + return this.value || "0"; + } + + _handleNumber = (event: CustomEvent) => { + const num = event.detail.value; + event.stopPropagation(); + if (num === "=") { + this.calculate(); + return; + } + if (this.value === "0") { + this.value = ""; + } + if (num === "." && this.value.includes(".")) { + return; + } + this.value += num; + }; + + clear = () => { + this.value = ""; + this._staging = ""; + this._value = ""; + this.mode = ""; + }; + + calculate = () => { + console.log("DEBUG: calculate entered! mode =", this.mode, "_value =", this._value, "_staging =", this._staging); + if (this.mode === "") return; + + const op1 = Number(this._value || "0"); + const op2 = Number(this._staging || "0"); + let result: number = 0; + + switch (this.mode) { + case "+": + result = op1 + op2; + break; + case "-": + result = op1 - op2; + break; + case "/": + result = op2 === 0 ? 0 : op1 / op2; + break; + case "*": + result = op1 * op2; + break; + default: + break; + } + + const output = result.toString(); + console.log("DEBUG: calculation result =", result, "output =", output); + this._value = output; + this._staging = ""; + this.mode = ""; + }; + + render() { + return html`
+ +
+ + + + + +
+ +
`; + } +} diff --git a/lit-components/lit-calculator/display-output.ts b/lit-components/lit-calculator/display-output.ts new file mode 100644 index 0000000..4cb2e62 --- /dev/null +++ b/lit-components/lit-calculator/display-output.ts @@ -0,0 +1,70 @@ +import { LitElement, html, css } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +@customElement("display-output") +export class CalcDisplay extends LitElement { + @property() + color = "black"; + + @property() + textColor = "white"; + + @property() + value = ""; + + static styles = css` + @import url('https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap'); + + #base { + text-align: end; + display: block; + padding: 16px 20px; + border: 3px solid #1a1b1f; + border-radius: 8px; + box-shadow: + inset 0 4px 10px rgba(0, 0, 0, 0.4), + 0 1px 0 rgba(255, 255, 255, 0.08); + position: relative; + overflow: hidden; + box-sizing: border-box; + width: 100%; + } + + /* Glossy vintage glass glare */ + #base::after { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 50%; + background: linear-gradient( + to bottom, + rgba(255, 255, 255, 0.12), + rgba(255, 255, 255, 0) + ); + pointer-events: none; + } + + #text-display { + font-family: 'Share Tech Mono', 'Courier New', monospace; + font-weight: 700; + font-size: 40px; + letter-spacing: 2px; + text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.12); + margin: 0; + line-height: 1.1; + word-wrap: break-word; + word-break: break-all; + } + `; + + // Render element DOM by returning a `lit-html` template. + render() { + return html`
+
+ ${this.value || "0"} +
+
`; + } +} diff --git a/lit-calculator/docs/index.html b/lit-components/lit-calculator/index.html similarity index 100% rename from lit-calculator/docs/index.html rename to lit-components/lit-calculator/index.html diff --git a/lit-calculator/docs/key-pad.ts b/lit-components/lit-calculator/key-pad.ts similarity index 91% rename from lit-calculator/docs/key-pad.ts rename to lit-components/lit-calculator/key-pad.ts index 4228e1d..4d2559e 100644 --- a/lit-calculator/docs/key-pad.ts +++ b/lit-components/lit-calculator/key-pad.ts @@ -18,14 +18,13 @@ export class CalcKeyPad extends LitElement { static styles = css` #base { display: grid; - grid-template-columns: 33% 33% 33%; - padding-left: calc(var(--base-padding) / 2); - padding-right: calc(var(--base-padding) / 2); + grid-template-columns: repeat(3, 1fr); + gap: 12px; + padding: 0 5px; } keypad-input { - display: inline-grid; - margin: 5px; + display: flex; } `; diff --git a/lit-calculator/docs/keypad-input.ts b/lit-components/lit-calculator/keypad-input.ts similarity index 64% rename from lit-calculator/docs/keypad-input.ts rename to lit-components/lit-calculator/keypad-input.ts index 92ce673..e1505af 100644 --- a/lit-calculator/docs/keypad-input.ts +++ b/lit-components/lit-calculator/keypad-input.ts @@ -16,25 +16,32 @@ export class CalcNumber extends LitElement { #base { width: 100%; height: 100%; - border-radius: 10px; + border-radius: 50%; text-align: center; - float: left; + border: none; + border-bottom: 3px solid rgba(0, 0, 0, 0.45); + font-weight: 700; + font-size: 20px; + cursor: pointer; + aspect-ratio: 1; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.08s ease; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.25); + outline: none; + box-sizing: border-box; + padding: 0; } #base:hover { - box-shadow: 0 0 11px rgba(33, 33, 33, 0.2); + filter: brightness(1.1); } #base:active { - background-color: lightgrey; - } - - button { - outline: 0 none; - color: white; - margin-top: 10px; - margin-bottom: 10px; - font-size: 20px; + transform: translateY(2px); + border-bottom-width: 1px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); } `; diff --git a/lit-calculator/docs/style.css b/lit-components/lit-calculator/style.css similarity index 100% rename from lit-calculator/docs/style.css rename to lit-components/lit-calculator/style.css diff --git a/lit-code-editor/src/code-editor.d.ts b/lit-components/lit-code-editor/code-editor.d.ts similarity index 100% rename from lit-code-editor/src/code-editor.d.ts rename to lit-components/lit-code-editor/code-editor.d.ts diff --git a/lit-components/lit-code-editor/code-editor.test.ts b/lit-components/lit-code-editor/code-editor.test.ts new file mode 100644 index 0000000..29654fe --- /dev/null +++ b/lit-components/lit-code-editor/code-editor.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./code-editor"; + +describe("Lit Code Editor Component", () => { + test("registers code-editor custom element successfully", () => { + expect(customElements.get("code-editor")).toBeDefined(); + }); + + test("mounts code-editor successfully", async () => { + document.body.innerHTML = ''; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("code-editor"); + expect(element).toBeDefined(); + expect(element?.getAttribute("code")).toBe("console.log(1);"); + }); +}); diff --git a/lit-code-editor/src/code-editor.ts b/lit-components/lit-code-editor/code-editor.ts similarity index 100% rename from lit-code-editor/src/code-editor.ts rename to lit-components/lit-code-editor/code-editor.ts diff --git a/lit-components/lit-draggable-dom/draggable-dom.test.ts b/lit-components/lit-draggable-dom/draggable-dom.test.ts new file mode 100644 index 0000000..a1a3d15 --- /dev/null +++ b/lit-components/lit-draggable-dom/draggable-dom.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, test } from "vitest"; +import "./draggable-dom"; + +describe("Lit Draggable DOM Component", () => { + test("registers draggable-dom custom element successfully", () => { + expect(customElements.get("draggable-dom")).toBeDefined(); + }); + + test("mounts draggable-dom successfully and accepts slots", async () => { + document.body.innerHTML = ` + + Grab me + + `; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("draggable-dom"); + expect(element).toBeDefined(); + expect(document.getElementById("drag")?.textContent).toBe("Grab me"); + }); +}); diff --git a/lit-draggable-dom/src/draggable-dom.ts b/lit-components/lit-draggable-dom/draggable-dom.ts similarity index 61% rename from lit-draggable-dom/src/draggable-dom.ts rename to lit-components/lit-draggable-dom/draggable-dom.ts index 60ec9ce..4f4c886 100644 --- a/lit-draggable-dom/src/draggable-dom.ts +++ b/lit-components/lit-draggable-dom/draggable-dom.ts @@ -15,17 +15,33 @@ export class DraggableDOM extends LitElement { static styles = css` :host { + display: block; + width: 100%; + height: 100%; + position: relative; + overflow: hidden; --offset-x: 0; --offset-y: 0; --grid-background-color: white; - --grid-color: black; + --grid-color: rgba(0, 0, 0, 0.1); --grid-size: 40px; - --grid-dot-size: 1px; + --grid-dot-size: 2px; } main { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; overflow: hidden; + touch-action: none; } canvas { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; background-size: var(--grid-size) var(--grid-size); background-image: radial-gradient( circle, @@ -34,25 +50,33 @@ export class DraggableDOM extends LitElement { ); background-position: var(--offset-x) var(--offset-y); z-index: 0; + pointer-events: none; } - .full-size { + #children { width: 100%; height: 100%; - position: fixed; - transform: translate(var(--dx), var(--dy)); + position: absolute; + top: 0; + left: 0; + transform: translate(var(--pan-x, 0), var(--pan-y, 0)); + pointer-events: none; } .child { - --dx: 0px; - --dy: 0px; - position: fixed; - flex-shrink: 1; - z-index: var(--layer, 0); - transform: translate(var(--dx), var(--dy)); + display: block; + pointer-events: auto; + } + ::slotted(*) { + position: absolute !important; + top: 0; + left: 0; + transform: translate(var(--dx, 0), var(--dy, 0)); + pointer-events: auto; + touch-action: none; } @media (prefers-color-scheme: dark) { - main { - --grid-background-color: black; - --grid-color: grey; + :host { + --grid-background-color: #0d1117; + --grid-color: rgba(255, 255, 255, 0.1); } } `; @@ -60,40 +84,23 @@ export class DraggableDOM extends LitElement { render() { return html`
this.handleDown(e, "canvas")} @pointermove=${(e: any) => this.handleMove(e, "canvas", (delta) => this.moveCanvas(delta))} - @touchstart=${(e: any) => this.handleDown(e, "canvas")} - @touchmove=${(e: any) => - this.handleMove(e, "canvas", (delta) => this.moveCanvas(delta))} @pointerup=${(e: any) => this.handleUp(e)} + @pointercancel=${(e: any) => this.handleUp(e)} > - -
+ +
this.handleDown(e, "element")} @pointermove=${(e: any) => this.handleMove(e, "element", (delta) => { - this.moveElement( - e.target.parentElement === this - ? e.target - : e.target.parentElement, - delta - ); + const target = e.target as HTMLElement; + const child = target.assignedSlot ? target : target.closest('[slot]') || target; + this.moveElement(child as SupportedNode, delta); })} - @touchstart=${(e: any) => this.handleDown(e, "element")} - @touchmove=${(e: any) => - this.handleMove(e, "element", (delta) => - this.moveElement( - e.target.parentElement === this - ? e.target - : e.target.parentElement, - delta - ) - )} >
@@ -139,25 +146,24 @@ export class DraggableDOM extends LitElement { moveCanvas(delta: Offset) { this.offset.x += delta.x; this.offset.y += delta.y; - this.root.style.setProperty("--offset-x", `${this.offset.x}px`); - this.root.style.setProperty("--offset-y", `${this.offset.y}px`); - this.container.style.setProperty("--dx", `${this.offset.x}px`); - this.container.style.setProperty("--dy", `${this.offset.y}px`); + this.style.setProperty("--offset-x", `${this.offset.x}px`); + this.style.setProperty("--offset-y", `${this.offset.y}px`); + this.container.style.setProperty("--pan-x", `${this.offset.x}px`); + this.container.style.setProperty("--pan-y", `${this.offset.y}px`); } moveElement(child: SupportedNode, delta: Offset) { - const getNumber = (key: "--dx" | "--dy", fallback: number) => { - const saved = child.style.getPropertyValue(key); + const getNumber = (key: string) => { + const saved = (child as HTMLElement).style.getPropertyValue(key); if (saved.length > 0) { return parseFloat(saved.replace("px", "")); } - return fallback; + return 0; }; - const dx = getNumber("--dx", 0) + delta.x; - const dy = getNumber("--dy", 0) + delta.y; - child.style.transform = `translate(${dx}px, ${dy}px)`; - child.style.setProperty("--dx", `${dx}px`); - child.style.setProperty("--dy", `${dy}px`); + const dx = getNumber("--dx") + delta.x; + const dy = getNumber("--dy") + delta.y; + (child as HTMLElement).style.setProperty("--dx", `${dx}px`); + (child as HTMLElement).style.setProperty("--dy", `${dy}px`); } } diff --git a/lit-file-based-routing/src/components/menu-button.ts b/lit-components/lit-file-based-routing/components/menu-button.ts similarity index 100% rename from lit-file-based-routing/src/components/menu-button.ts rename to lit-components/lit-file-based-routing/components/menu-button.ts diff --git a/lit-file-based-routing/src/generated-app.ts b/lit-components/lit-file-based-routing/generated-app.ts similarity index 100% rename from lit-file-based-routing/src/generated-app.ts rename to lit-components/lit-file-based-routing/generated-app.ts diff --git a/lit-file-based-routing/src/pages/404.ts b/lit-components/lit-file-based-routing/pages/404.ts similarity index 100% rename from lit-file-based-routing/src/pages/404.ts rename to lit-components/lit-file-based-routing/pages/404.ts diff --git a/lit-file-based-routing/src/pages/custom.not.nested.route.ts b/lit-components/lit-file-based-routing/pages/custom.not.nested.route.ts similarity index 100% rename from lit-file-based-routing/src/pages/custom.not.nested.route.ts rename to lit-components/lit-file-based-routing/pages/custom.not.nested.route.ts diff --git a/lit-file-based-routing/src/pages/dashboard.ts b/lit-components/lit-file-based-routing/pages/dashboard.ts similarity index 100% rename from lit-file-based-routing/src/pages/dashboard.ts rename to lit-components/lit-file-based-routing/pages/dashboard.ts diff --git a/lit-file-based-routing/src/pages/dashboard/account.ts b/lit-components/lit-file-based-routing/pages/dashboard/account.ts similarity index 100% rename from lit-file-based-routing/src/pages/dashboard/account.ts rename to lit-components/lit-file-based-routing/pages/dashboard/account.ts diff --git a/lit-file-based-routing/src/pages/dashboard/account/:id.ts b/lit-components/lit-file-based-routing/pages/dashboard/account/:id.ts similarity index 100% rename from lit-file-based-routing/src/pages/dashboard/account/:id.ts rename to lit-components/lit-file-based-routing/pages/dashboard/account/:id.ts diff --git a/lit-file-based-routing/src/pages/dashboard/account/index.ts b/lit-components/lit-file-based-routing/pages/dashboard/account/index.ts similarity index 100% rename from lit-file-based-routing/src/pages/dashboard/account/index.ts rename to lit-components/lit-file-based-routing/pages/dashboard/account/index.ts diff --git a/lit-file-based-routing/src/pages/dashboard/index.ts b/lit-components/lit-file-based-routing/pages/dashboard/index.ts similarity index 100% rename from lit-file-based-routing/src/pages/dashboard/index.ts rename to lit-components/lit-file-based-routing/pages/dashboard/index.ts diff --git a/lit-file-based-routing/src/pages/dashboard/overview.ts b/lit-components/lit-file-based-routing/pages/dashboard/overview.ts similarity index 100% rename from lit-file-based-routing/src/pages/dashboard/overview.ts rename to lit-components/lit-file-based-routing/pages/dashboard/overview.ts diff --git a/lit-file-based-routing/src/pages/index.ts b/lit-components/lit-file-based-routing/pages/index.ts similarity index 100% rename from lit-file-based-routing/src/pages/index.ts rename to lit-components/lit-file-based-routing/pages/index.ts diff --git a/lit-file-based-routing/src/pages/root.ts b/lit-components/lit-file-based-routing/pages/root.ts similarity index 100% rename from lit-file-based-routing/src/pages/root.ts rename to lit-components/lit-file-based-routing/pages/root.ts diff --git a/lit-file-based-routing/src/pages/settings.ts b/lit-components/lit-file-based-routing/pages/settings.ts similarity index 100% rename from lit-file-based-routing/src/pages/settings.ts rename to lit-components/lit-file-based-routing/pages/settings.ts diff --git a/lit-file-based-routing/src/pages/settings/admin.ts b/lit-components/lit-file-based-routing/pages/settings/admin.ts similarity index 100% rename from lit-file-based-routing/src/pages/settings/admin.ts rename to lit-components/lit-file-based-routing/pages/settings/admin.ts diff --git a/lit-file-based-routing/src/pages/settings/index.ts b/lit-components/lit-file-based-routing/pages/settings/index.ts similarity index 100% rename from lit-file-based-routing/src/pages/settings/index.ts rename to lit-components/lit-file-based-routing/pages/settings/index.ts diff --git a/lit-components/lit-file-based-routing/router.test.ts b/lit-components/lit-file-based-routing/router.test.ts new file mode 100644 index 0000000..82da738 --- /dev/null +++ b/lit-components/lit-file-based-routing/router.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, test } from "vitest"; +import "./generated-app"; + +describe("Lit File-Based Router Component", () => { + test("registers generated-app custom element successfully", () => { + expect(customElements.get("generated-app")).toBeDefined(); + }); + + test("mounts router application container successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("generated-app"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + + // Await lazy route imports to complete before ending test and tearing down Happy DOM context + await new Promise((resolve) => setTimeout(resolve, 150)); + }); +}); diff --git a/lit-force-graph/src/classes/context.ts b/lit-components/lit-force-graph/classes/context.ts similarity index 69% rename from lit-force-graph/src/classes/context.ts rename to lit-components/lit-force-graph/classes/context.ts index c427ed9..d8d8111 100644 --- a/lit-force-graph/src/classes/context.ts +++ b/lit-components/lit-force-graph/classes/context.ts @@ -4,6 +4,7 @@ export interface RenderContext { data: GraphData; element: HTMLElement; onHover: (node?: GraphNode) => void; + instance?: any; } -export type Renderer = (context: RenderContext) => void; +export type Renderer = (context: RenderContext) => any; diff --git a/lit-force-graph/src/classes/graph.ts b/lit-components/lit-force-graph/classes/graph.ts similarity index 100% rename from lit-force-graph/src/classes/graph.ts rename to lit-components/lit-force-graph/classes/graph.ts diff --git a/lit-components/lit-force-graph/force-graph.test.ts b/lit-components/lit-force-graph/force-graph.test.ts new file mode 100644 index 0000000..0b35cb8 --- /dev/null +++ b/lit-components/lit-force-graph/force-graph.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./lit-force-graph"; + +describe("Lit Force Graph Component", () => { + test("registers lit-force-graph custom element successfully", () => { + expect(customElements.get("lit-force-graph")).toBeDefined(); + }); + + test("mounts lit-force-graph container successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("lit-force-graph"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-force-graph/src/lit-force-graph.ts b/lit-components/lit-force-graph/lit-force-graph.ts similarity index 56% rename from lit-force-graph/src/lit-force-graph.ts rename to lit-components/lit-force-graph/lit-force-graph.ts index 80ae0d0..f992696 100644 --- a/lit-force-graph/src/lit-force-graph.ts +++ b/lit-components/lit-force-graph/lit-force-graph.ts @@ -1,9 +1,7 @@ -import { html, css, LitElement } from "lit"; +import { html, css, LitElement, PropertyValues } from "lit"; import { customElement, property, query, state } from "lit/decorators.js"; import { Renderer } from "./classes/context"; import { GraphData, GraphNode } from "./classes/graph"; -import { render as render2D } from "./modes/mode-2d"; -import { render as render3D } from "./modes/mode-3d"; export const tagName = "lit-force-graph"; @@ -11,24 +9,24 @@ export const tagName = "lit-force-graph"; export class LitForceGraph extends LitElement { static styles = css` :host { + display: block; background-color: var(--graph-background-color, #000011); color: var(--graph-foreground-color, #ffffff); width: var(--graph-width, 100%); height: var(--graph-height, 100vh); + position: relative; } #graph { width: 100%; height: 100%; - width: var(--graph-width, 100%); - height: var(--graph-height, 100vh); } #controls { position: absolute; top: 20px; right: 20px; - z-index: 100 !important; + z-index: 100; display: flex; flex-direction: column; align-items: flex-end; @@ -41,10 +39,11 @@ export class LitForceGraph extends LitElement { position: absolute; top: 10px; left: 10px; - z-index: 100 !important; + z-index: 100; display: flex; flex-direction: column; align-items: flex-start; + pointer-events: none; } #tooltips { @@ -57,6 +56,7 @@ export class LitForceGraph extends LitElement { align-items: center; text-align: center; justify-content: center; + pointer-events: none; } .node-tooltip { @@ -65,18 +65,12 @@ export class LitForceGraph extends LitElement { border-radius: 5px; font-size: 12px; padding: 5px; - opacity: 0.67; + opacity: 0.8; } #graph-description { opacity: 0.67; } - - .scene-tooltip { - color: var(--graph-foreground-color, #ffffff); - background-color: transparent; - display: none; - } `; @query("#graph") graph!: HTMLElement; @@ -84,15 +78,17 @@ export class LitForceGraph extends LitElement { @property() mode = "2D"; @property({ type: Object }) data?: GraphData; @state() hovered?: GraphNode; + @state() private _instance?: any; - renderers = new Map([ - ["2D", render2D], - ["3D", render3D], + renderers = new Map Promise>([ + ["2D", () => import("./modes/mode-2d").then((m) => m.render)], + ["3D", () => import("./modes/mode-3d").then((m) => m.render)], + ["AR", () => import("./modes/mode-ar").then((m) => m.render)], + ["VR", () => import("./modes/mode-vr").then((m) => m.render)], ]); render() { return html`
@@ -100,16 +96,16 @@ export class LitForceGraph extends LitElement {
- ${Array.from(this.renderers.keys()).map((mode) => { - return html` `; + return html` `; })}

${this.data?.name}

-
${this?.data?.description}
+
${this.data?.description}
${this.hovered @@ -125,10 +121,25 @@ export class LitForceGraph extends LitElement { await this.refresh(); const prefersDark = window.matchMedia("(prefers-color-scheme: dark)"); prefersDark.addEventListener("change", () => { - this.refresh(); + this._updateGraph(); }); } + protected updated(changedProperties: PropertyValues) { + if (changedProperties.has("mode")) { + if (this._instance) { + this.graph.innerHTML = ""; + this._instance = undefined; + } + } + if (changedProperties.has("data") || changedProperties.has("mode")) { + this._updateGraph(); + } + if (changedProperties.has("src") && this.src) { + this.refresh(); + } + } + /** * Set the graph data and update the renderer * @@ -136,12 +147,24 @@ export class LitForceGraph extends LitElement { */ setData(data: GraphData) { this.data = data; - const renderer = this.renderers.get(this.mode); - renderer?.({ - element: this.graph, - data, - onHover: (node) => (this.hovered = node), - }); + } + + private async _updateGraph() { + if (!this.data || !this.graph) return; + const rendererFactory = this.renderers.get(this.mode); + if (rendererFactory) { + try { + const renderer = await rendererFactory(); + this._instance = renderer({ + element: this.graph, + data: this.data, + onHover: (node) => (this.hovered = node), + instance: this._instance, + }); + } catch (e) { + console.error("Failed to load or run renderer for mode", this.mode, e); + } + } } private async refresh() { @@ -149,28 +172,34 @@ export class LitForceGraph extends LitElement { const children = Array.from(this.children); const elem = children.find((child) => child.tagName === "SCRIPT"); if (elem) { - // Render from script tag contents if (elem.textContent) { - const data = JSON.parse(elem.textContent); - if (data) this.setData(data); - // Render from script tag src + try { + const data = JSON.parse(elem.textContent); + if (data) this.setData(data); + } catch (e) { + console.error("Failed to parse graph data from script tag", e); + } } else if (elem.hasAttribute("src")) { const url = elem.getAttribute("src")!; - const data = await fetch(url).then((res) => res.json()); - if (data) this.setData(data); + try { + const data = await fetch(url).then((res) => res.json()); + if (data) this.setData(data); + } catch (e) { + console.error("Failed to fetch graph data from script src", url, e); + } + } + } else if (this.src) { + try { + const data = await fetch(this.src).then((res) => res.json()); + if (data) this.setData(data); + } catch (e) { + console.error("Failed to fetch graph data from src property", this.src, e); } - } else if (this.src.length > 0) { - // Render from src attribute - const data = await fetch(this.src).then((res) => res.json()); - if (data) this.setData(data); } } private onChangeMode(e: Event) { - const mode = (e.target as HTMLSelectElement).value; - this.mode = mode; - if (!this.data) return; - this.setData({ ...this.data! }); + this.mode = (e.target as HTMLSelectElement).value; } private onDrop(e: DragEvent) { @@ -180,34 +209,23 @@ export class LitForceGraph extends LitElement { const file = files[0]; const reader = new FileReader(); reader.onload = () => { - const json = JSON.parse(reader.result as string); - this.data = json; - this.setData(json); + try { + const json = JSON.parse(reader.result as string); + this.setData(json); + } catch (e) { + console.error("Failed to parse dropped graph data", e); + } }; reader.readAsText(file); } return false; } - - attributeChangedCallback( - name: string, - _old: string | null, - value: string | null - ): void { - if (name === "src" && value) { - this.refresh(); - } - if (name === "data" && value) { - this.setData(JSON.parse(value)); - } - if (name === "mode" && value) { - this.mode = value; - if (this.data) { - this.setData({ ...this.data! }); - } - } - super.attributeChangedCallback(name, _old, value); - } +} + +declare global { + interface HTMLElementTagNameMap { + "lit-force-graph": LitForceGraph; + } } declare global { diff --git a/lit-force-graph/src/modes/mode-2d.ts b/lit-components/lit-force-graph/modes/mode-2d.ts similarity index 78% rename from lit-force-graph/src/modes/mode-2d.ts rename to lit-components/lit-force-graph/modes/mode-2d.ts index d99b7ac..b1a1cf9 100644 --- a/lit-force-graph/src/modes/mode-2d.ts +++ b/lit-components/lit-force-graph/modes/mode-2d.ts @@ -2,16 +2,23 @@ import ForceGraph from "force-graph"; import { RenderContext } from "../classes/context"; export function render(context: RenderContext) { - const graph = ForceGraph(); + const graph = context.instance || ForceGraph(); const style = getComputedStyle(context.element); - const lineColor = style.getPropertyValue("--graph-line-color").trim(); - const bgColor = style.getPropertyValue("--graph-background-color").trim(); - const fgColor = style.getPropertyValue("--graph-foreground-color").trim(); - const nodeColor = style.getPropertyValue("--graph-node-color").trim(); - graph(context.element) + const lineColor = style.getPropertyValue("--graph-line-color").trim() || "#555"; + const bgColor = style.getPropertyValue("--graph-background-color").trim() || "#000011"; + const fgColor = style.getPropertyValue("--graph-foreground-color").trim() || "#ffffff"; + const nodeColor = style.getPropertyValue("--graph-node-color").trim() || "#999"; + const width = context.element.clientWidth || Number(style.width.slice(0, -2)) || window.innerWidth; + const height = context.element.clientHeight || Number(style.height.slice(0, -2)) || window.innerHeight; + + if (!context.instance) { + graph(context.element); + } + + graph .graphData(context.data) - .width(Number(style.width.slice(0, -2))) - .height(Number(style.height.slice(0, -2))) + .width(width) + .height(height) .cooldownTicks(100) .backgroundColor(bgColor) .linkColor(() => lineColor) @@ -21,7 +28,6 @@ export function render(context: RenderContext) { ctx.beginPath(); const size = 5 / globalScale; ctx.arc(node.x, node.y, size, 0, 2 * Math.PI); - // ctx.fillStyle = nodeColor(node, groupColors); ctx.fillStyle = nodeColor; ctx.fill(); ctx.lineWidth = 1 / globalScale; @@ -55,4 +61,6 @@ export function render(context: RenderContext) { context.onHover(undefined); } }); + + return graph; } diff --git a/lit-force-graph/src/modes/mode-3d.ts b/lit-components/lit-force-graph/modes/mode-3d.ts similarity index 70% rename from lit-force-graph/src/modes/mode-3d.ts rename to lit-components/lit-force-graph/modes/mode-3d.ts index 0b6adfd..b211ddf 100644 --- a/lit-force-graph/src/modes/mode-3d.ts +++ b/lit-components/lit-force-graph/modes/mode-3d.ts @@ -2,18 +2,25 @@ import ForceGraph from "3d-force-graph"; import { RenderContext } from "../classes/context.js"; export function render(context: RenderContext) { - const graph = ForceGraph({ + const graph = context.instance || ForceGraph({ controlType: "trackball", rendererConfig: { antialias: true, alpha: true }, }); const style = getComputedStyle(context.element); - const lineColor = style.getPropertyValue("--graph-line-color").trim(); - const bgColor = style.getPropertyValue("--graph-background-color").trim(); - const nodeColor = style.getPropertyValue("--graph-node-color").trim(); - graph(context.element) + const lineColor = style.getPropertyValue("--graph-line-color").trim() || "#555"; + const bgColor = style.getPropertyValue("--graph-background-color").trim() || "#000011"; + const nodeColor = style.getPropertyValue("--graph-node-color").trim() || "#999"; + const width = context.element.clientWidth || Number(style.width.slice(0, -2)) || window.innerWidth; + const height = context.element.clientHeight || Number(style.height.slice(0, -2)) || window.innerHeight; + + if (!context.instance) { + graph(context.element); + } + + graph .graphData(context.data) - .width(Number(style.width.slice(0, -2))) - .height(Number(style.height.slice(0, -2))) + .width(width) + .height(height) .showNavInfo(false) .linkColor(() => lineColor) .backgroundColor(bgColor) @@ -33,4 +40,6 @@ export function render(context: RenderContext) { } }) .cooldownTicks(100); + + return graph; } diff --git a/lit-components/lit-force-graph/modes/mode-ar.ts b/lit-components/lit-force-graph/modes/mode-ar.ts new file mode 100644 index 0000000..7d1b4b6 --- /dev/null +++ b/lit-components/lit-force-graph/modes/mode-ar.ts @@ -0,0 +1,21 @@ +import "aframe"; +import "@ar-js-org/ar.js"; +import ForceGraph from "3d-force-graph-ar"; +import { RenderContext } from "../classes/context.js"; + +export function render(context: RenderContext) { + const graph = context.instance || ForceGraph(); + const style = getComputedStyle(context.element); + + if (!context.instance) { + graph(context.element); + } + + graph + .graphData(context.data) + .width(Number(style.width.slice(0, -2)) || window.innerWidth) + .height(Number(style.height.slice(0, -2)) || window.innerHeight) + .cooldownTicks(100); + + return graph; +} diff --git a/lit-components/lit-force-graph/modes/mode-vr.ts b/lit-components/lit-force-graph/modes/mode-vr.ts new file mode 100644 index 0000000..d5fa729 --- /dev/null +++ b/lit-components/lit-force-graph/modes/mode-vr.ts @@ -0,0 +1,20 @@ +import ForceGraph from "3d-force-graph-vr"; +import { RenderContext } from "../classes/context.js"; + +export function render(context: RenderContext) { + const graph = context.instance || ForceGraph(); + const style = getComputedStyle(context.element); + + if (!context.instance) { + graph(context.element); + } + + graph + .graphData(context.data) + .width(Number(style.width.slice(0, -2)) || window.innerWidth) + .height(Number(style.height.slice(0, -2)) || window.innerHeight) + .showNavInfo(false) + .cooldownTicks(100); + + return graph; +} diff --git a/lit-html-editor/src/components/rich-action.ts b/lit-components/lit-html-editor/components/rich-action.ts similarity index 100% rename from lit-html-editor/src/components/rich-action.ts rename to lit-components/lit-html-editor/components/rich-action.ts diff --git a/lit-html-editor/src/components/rich-text.ts b/lit-components/lit-html-editor/components/rich-text.ts similarity index 100% rename from lit-html-editor/src/components/rich-text.ts rename to lit-components/lit-html-editor/components/rich-text.ts diff --git a/lit-html-editor/src/components/rich-toolbar.ts b/lit-components/lit-html-editor/components/rich-toolbar.ts similarity index 100% rename from lit-html-editor/src/components/rich-toolbar.ts rename to lit-components/lit-html-editor/components/rich-toolbar.ts diff --git a/lit-html-editor/src/components/rich-viewer.ts b/lit-components/lit-html-editor/components/rich-viewer.ts similarity index 100% rename from lit-html-editor/src/components/rich-viewer.ts rename to lit-components/lit-html-editor/components/rich-viewer.ts diff --git a/lit-components/lit-html-editor/html-editor.test.ts b/lit-components/lit-html-editor/html-editor.test.ts new file mode 100644 index 0000000..de23875 --- /dev/null +++ b/lit-components/lit-html-editor/html-editor.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from "vitest"; +import "./components/rich-text"; +import "./components/rich-viewer"; + +describe("Lit HTML Editor Components", () => { + test("registers rich markdown/HTML custom elements successfully", () => { + expect(customElements.get("rich-text")).toBeDefined(); + expect(customElements.get("rich-viewer")).toBeDefined(); + }); + + test("mounts rich-viewer correctly and accepts markdown content", async () => { + document.body.innerHTML = ''; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("rich-viewer"); + expect(element).toBeDefined(); + expect(element?.getAttribute("value")).toBe("# Hello World"); + }); +}); diff --git a/lit-html-editor/src/rich-text-editor.ts b/lit-components/lit-html-editor/rich-text-editor.ts similarity index 100% rename from lit-html-editor/src/rich-text-editor.ts rename to lit-components/lit-html-editor/rich-text-editor.ts diff --git a/lit-html-editor/src/utils/check-fonts.ts b/lit-components/lit-html-editor/utils/check-fonts.ts similarity index 100% rename from lit-html-editor/src/utils/check-fonts.ts rename to lit-components/lit-html-editor/utils/check-fonts.ts diff --git a/lit-html-editor/src/utils/live.ts b/lit-components/lit-html-editor/utils/live.ts similarity index 100% rename from lit-html-editor/src/utils/live.ts rename to lit-components/lit-html-editor/utils/live.ts diff --git a/lit-components/lit-html-table/html-table.test.ts b/lit-components/lit-html-table/html-table.test.ts new file mode 100644 index 0000000..b4518a4 --- /dev/null +++ b/lit-components/lit-html-table/html-table.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./lit-html-table"; + +describe("Lit HTML Table Component", () => { + test("registers lit-html-table custom element successfully", () => { + expect(customElements.get("lit-html-table")).toBeDefined(); + }); + + test("mounts lit-html-table spreadsheet grid successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("lit-html-table"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-components/lit-html-table/lit-html-table.ts b/lit-components/lit-html-table/lit-html-table.ts new file mode 100644 index 0000000..11f4336 --- /dev/null +++ b/lit-components/lit-html-table/lit-html-table.ts @@ -0,0 +1,173 @@ +import { html, css, LitElement } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +type ObjectData = { [key: string]: any }; + +@customElement("lit-html-table") +export class LitHtmlTable extends LitElement { + @property() src = ""; + @property({ type: Boolean }) editable = false; + + values?: ObjectData[]; + + static styles = css` + :host { + display: block; + width: 100%; + overflow-x: auto; + font-family: var(--table-font-family, sans-serif); + background-color: var(--table-background-color, #ffffff); + color: var(--table-text-color, #1f2937); + border-radius: var(--table-border-radius, 8px); + box-shadow: var(--table-box-shadow, 0 1px 3px 0 rgba(0, 0, 0, 0.1)); + } + + table { + width: 100%; + border-collapse: collapse; + text-align: left; + } + + thead { + background-color: var(--table-header-bg, #f9fafb); + border-bottom: 2px solid var(--table-border-color, #e5e7eb); + } + + th { + padding: var(--table-padding, 12px 16px); + font-weight: 600; + text-transform: uppercase; + font-size: 0.75rem; + letter-spacing: 0.05em; + color: var(--table-header-color, #4b5563); + } + + tr { + border-bottom: 1px solid var(--table-border-color, #e5e7eb); + transition: background-color 0.2s; + } + + tr:last-child { + border-bottom: none; + } + + tbody tr:hover { + background-color: var(--table-row-hover-bg, #f3f4f6); + } + + td { + padding: var(--table-padding, 12px 16px); + vertical-align: middle; + font-size: 0.875rem; + } + + td > input { + width: 100%; + padding: 8px; + border: 1px solid transparent; + border-radius: 4px; + background: transparent; + font-family: inherit; + font-size: inherit; + color: inherit; + transition: all 0.2s; + } + + td > input:focus { + outline: none; + border-color: var(--table-focus-color, #6366f1); + background-color: #ffffff; + box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1); + } + + .loading, .empty { + padding: 32px; + text-align: center; + color: var(--table-text-secondary, #6b7280); + font-style: italic; + } + `; + + render() { + // Check if data is loaded + if (!this.values) { + return html`
Loading data...
`; + } + // Check if items are not empty + if (this.values.length === 0) { + return html`
No items found.
`; + } + // Convert JSON to HTML Table + return html` + + + + ${Object.keys(this.values[0]).map((key) => { + const name = key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()); + return html``; + })} + + + + ${this.values.map((item, index) => { + return html` + + ${Object.entries(item).map(([key, value]) => { + return html``; + })} + + `; + })} + +
+ ${name} +
+ ${this.editable + ? html` { + const newValue = e.target.value; + const current = { ...this.values![index] }; + current[key] = newValue; + this.values![index] = current; + this.requestUpdate(); + this.dispatchEvent( + new CustomEvent("input-cell", { + detail: { + index: index, + data: current, + }, + }) + ); + }} + />` + : html`${value}`} +
+ `; + } + + async firstUpdated() { + await this.fetchData(); + } + + async fetchData() { + if (this.values && this.values.length > 0) return; + let _data: any; + if (this.src.length > 0) { + _data = await fetch(this.src).then((res) => res.json()); + } else { + const elem = this.parentElement?.querySelector( + 'script[type="application/json"]' + ) as HTMLScriptElement; + if (elem) _data = JSON.parse(elem.innerHTML); + } + _data ??= []; + this.values = this.transform(_data); + this.requestUpdate(); + } + + transform(data: any) { + return data; + } +} diff --git a/lit-components/lit-modules/app.test.ts b/lit-components/lit-modules/app.test.ts new file mode 100644 index 0000000..62ff642 --- /dev/null +++ b/lit-components/lit-modules/app.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, test } from "vitest"; +import "./modules/app"; +import "./modules/header"; +import "./modules/counter"; + +describe("Lit Modules App Component", () => { + test("registers modules custom elements successfully", () => { + expect(customElements.get("app-module")).toBeDefined(); + expect(customElements.get("header-module")).toBeDefined(); + expect(customElements.get("counter-module")).toBeDefined(); + }); + + test("mounts app-module successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("app-module"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-modules/src/modules/app.ts b/lit-components/lit-modules/modules/app.ts similarity index 100% rename from lit-modules/src/modules/app.ts rename to lit-components/lit-modules/modules/app.ts diff --git a/lit-modules/src/modules/counter.ts b/lit-components/lit-modules/modules/counter.ts similarity index 100% rename from lit-modules/src/modules/counter.ts rename to lit-components/lit-modules/modules/counter.ts diff --git a/lit-modules/src/modules/header.ts b/lit-components/lit-modules/modules/header.ts similarity index 100% rename from lit-modules/src/modules/header.ts rename to lit-components/lit-modules/modules/header.ts diff --git a/lit-node-editor/src/canvas/index.ts b/lit-components/lit-node-editor/canvas/index.ts similarity index 100% rename from lit-node-editor/src/canvas/index.ts rename to lit-components/lit-node-editor/canvas/index.ts diff --git a/lit-node-editor/src/canvas/label.ts b/lit-components/lit-node-editor/canvas/label.ts similarity index 100% rename from lit-node-editor/src/canvas/label.ts rename to lit-components/lit-node-editor/canvas/label.ts diff --git a/lit-node-editor/src/canvas/line.ts b/lit-components/lit-node-editor/canvas/line.ts similarity index 100% rename from lit-node-editor/src/canvas/line.ts rename to lit-components/lit-node-editor/canvas/line.ts diff --git a/lit-node-editor/src/canvas/matrix.ts b/lit-components/lit-node-editor/canvas/matrix.ts similarity index 100% rename from lit-node-editor/src/canvas/matrix.ts rename to lit-components/lit-node-editor/canvas/matrix.ts diff --git a/lit-node-editor/src/canvas/rect.ts b/lit-components/lit-node-editor/canvas/rect.ts similarity index 100% rename from lit-node-editor/src/canvas/rect.ts rename to lit-components/lit-node-editor/canvas/rect.ts diff --git a/lit-node-editor/src/canvas/utils.ts b/lit-components/lit-node-editor/canvas/utils.ts similarity index 100% rename from lit-node-editor/src/canvas/utils.ts rename to lit-components/lit-node-editor/canvas/utils.ts diff --git a/lit-components/lit-node-editor/editor.test.ts b/lit-components/lit-node-editor/editor.test.ts new file mode 100644 index 0000000..8491d30 --- /dev/null +++ b/lit-components/lit-node-editor/editor.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from "vitest"; +import "./node-editor"; +import "./ui/tree-view"; + +describe("Lit Node Editor Component", () => { + test("registers visual node editor custom elements successfully", () => { + expect(customElements.get("node-editor")).toBeDefined(); + expect(customElements.get("tree-view")).toBeDefined(); + }); + + test("mounts node-editor to the body successfully", async () => { + document.body.innerHTML = ""; + await new Promise((r) => setTimeout(r, 100)); + + const element = document.body.querySelector("node-editor"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-node-editor/src/node-editor.ts b/lit-components/lit-node-editor/node-editor.ts similarity index 100% rename from lit-node-editor/src/node-editor.ts rename to lit-components/lit-node-editor/node-editor.ts diff --git a/lit-node-editor/src/store.ts b/lit-components/lit-node-editor/store.ts similarity index 100% rename from lit-node-editor/src/store.ts rename to lit-components/lit-node-editor/store.ts diff --git a/lit-node-editor/src/styles.css b/lit-components/lit-node-editor/styles.css similarity index 100% rename from lit-node-editor/src/styles.css rename to lit-components/lit-node-editor/styles.css diff --git a/lit-node-editor/src/ui/tree-view.ts b/lit-components/lit-node-editor/ui/tree-view.ts similarity index 100% rename from lit-node-editor/src/ui/tree-view.ts rename to lit-components/lit-node-editor/ui/tree-view.ts index e601867..0909acf 100644 --- a/lit-node-editor/src/ui/tree-view.ts +++ b/lit-components/lit-node-editor/ui/tree-view.ts @@ -1,6 +1,52 @@ import { css, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; +/** + * Tree view styles + */ +export const styles = css` + ul.tree { + width: 100%; + height: 100%; + overflow-x: scroll; + white-space: nowrap; + } + ul.tree, + ul.tree ul { + list-style: none; + margin: 0; + padding: 0; + } + ul.tree ul { + margin-left: 10px; + } + ul.tree li { + margin: 0; + padding: 0 7px; + line-height: 20px; + color: #369; + font-weight: bold; + border-left: 1px solid rgb(100, 100, 100); + } + ul.tree li:last-child { + border-left: none; + } + ul.tree li:before { + position: relative; + top: -0.3em; + height: 1em; + width: 12px; + color: white; + border-bottom: 1px solid rgb(100, 100, 100); + content: ""; + display: inline-block; + left: -7px; + } + ul.tree li:last-child:before { + border-left: 1px solid rgb(100, 100, 100); + } +`; + /** * A tree view component. */ @@ -48,52 +94,6 @@ export declare interface BaseTreeNode { collapsed: boolean; } -/** - * Tree view styles - */ -export const styles = css` - ul.tree { - width: 100%; - height: 100%; - overflow-x: scroll; - white-space: nowrap; - } - ul.tree, - ul.tree ul { - list-style: none; - margin: 0; - padding: 0; - } - ul.tree ul { - margin-left: 10px; - } - ul.tree li { - margin: 0; - padding: 0 7px; - line-height: 20px; - color: #369; - font-weight: bold; - border-left: 1px solid rgb(100, 100, 100); - } - ul.tree li:last-child { - border-left: none; - } - ul.tree li:before { - position: relative; - top: -0.3em; - height: 1em; - width: 12px; - color: white; - border-bottom: 1px solid rgb(100, 100, 100); - content: ""; - display: inline-block; - left: -7px; - } - ul.tree li:last-child:before { - border-left: 1px solid rgb(100, 100, 100); - } -`; - interface TemplateProps { tree: Tree; onSelect: (node: BaseTreeNode) => void; diff --git a/lit-components/lit-sheet-music/sheet-music.test.ts b/lit-components/lit-sheet-music/sheet-music.test.ts new file mode 100644 index 0000000..a0a5464 --- /dev/null +++ b/lit-components/lit-sheet-music/sheet-music.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./sheet-music"; + +describe("Lit Sheet Music Component", () => { + test("registers sheet-music custom element successfully", () => { + expect(customElements.get("sheet-music")).toBeDefined(); + }); + + test("mounts sheet-music successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("sheet-music"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-sheet-music/src/sheet-music.ts b/lit-components/lit-sheet-music/sheet-music.ts similarity index 100% rename from lit-sheet-music/src/sheet-music.ts rename to lit-components/lit-sheet-music/sheet-music.ts diff --git a/lit-starter-ts/src/my-element.ts b/lit-components/lit-starter-ts/my-element.ts similarity index 100% rename from lit-starter-ts/src/my-element.ts rename to lit-components/lit-starter-ts/my-element.ts diff --git a/lit-components/lit-starter-ts/starter.test.ts b/lit-components/lit-starter-ts/starter.test.ts new file mode 100644 index 0000000..f29a8aa --- /dev/null +++ b/lit-components/lit-starter-ts/starter.test.ts @@ -0,0 +1,52 @@ +import { describe, expect, test } from "vitest"; +import "./my-element"; + +describe("MyElement Component", () => { + test("registers my-element custom element successfully", () => { + expect(customElements.get("my-element")).toBeDefined(); + }); + + test("mounts and renders with default properties", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("my-element"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + + const h1 = element?.shadowRoot?.querySelector("h1"); + expect(h1?.textContent).toBe("Hello, World!"); + + const button = element?.shadowRoot?.querySelector("button"); + expect(button?.textContent?.trim()).toBe("Click Count: 1"); + }); + + test("handles name property change", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("my-element"); + const h1 = element?.shadowRoot?.querySelector("h1"); + expect(h1?.textContent).toBe("Hello, Vitest!"); + }); + + test("increments count on click and dispatches event", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("my-element"); + const button = element?.shadowRoot?.querySelector("button"); + + let eventDetail: number | null = null; + element?.addEventListener("count", (e: any) => { + eventDetail = e.detail; + }); + + button?.click(); + await window.happyDOM.whenAsyncComplete(); + + expect(element?.count).toBe(2); + expect(button?.textContent?.trim()).toBe("Click Count: 2"); + expect(eventDetail).toBe(2); + }); +}); diff --git a/lit-vscode-extension/src/extension.ts b/lit-components/lit-vscode-extension/extension.ts similarity index 100% rename from lit-vscode-extension/src/extension.ts rename to lit-components/lit-vscode-extension/extension.ts diff --git a/lit-vscode-extension/src/my-element.ts b/lit-components/lit-vscode-extension/my-element.ts similarity index 100% rename from lit-vscode-extension/src/my-element.ts rename to lit-components/lit-vscode-extension/my-element.ts diff --git a/lit-components/lit-vscode-extension/vscode.test.ts b/lit-components/lit-vscode-extension/vscode.test.ts new file mode 100644 index 0000000..bec424f --- /dev/null +++ b/lit-components/lit-vscode-extension/vscode.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./my-element"; + +describe("VSCode Webview Custom Element", () => { + test("registers my-element custom element successfully", () => { + expect(customElements.get("my-element")).toBeDefined(); + }); + + test("mounts custom webview element successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("my-element"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-wmr/public/index.html b/lit-components/lit-wmr/index.html similarity index 100% rename from lit-wmr/public/index.html rename to lit-components/lit-wmr/index.html diff --git a/lit-wmr/public/index.js b/lit-components/lit-wmr/index.js similarity index 100% rename from lit-wmr/public/index.js rename to lit-components/lit-wmr/index.js diff --git a/lit-wmr/public/simple-greeting.ts b/lit-components/lit-wmr/simple-greeting.ts similarity index 100% rename from lit-wmr/public/simple-greeting.ts rename to lit-components/lit-wmr/simple-greeting.ts diff --git a/lit-components/lit-wmr/wmr.test.ts b/lit-components/lit-wmr/wmr.test.ts new file mode 100644 index 0000000..11c6e89 --- /dev/null +++ b/lit-components/lit-wmr/wmr.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from "vitest"; +import "./simple-greeting"; + +describe("Lit WMR Components", () => { + test("registers simple-greeting custom element successfully", () => { + expect(customElements.get("simple-greeting")).toBeDefined(); + }); + + test("mounts simple-greeting successfully", async () => { + document.body.innerHTML = ''; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("simple-greeting"); + expect(element).toBeDefined(); + + // Assert against textContent to strip out Lit HTML comments and formatting tags + expect(element?.shadowRoot?.textContent).toContain("Hello, WMR!"); + }); +}); diff --git a/lit-components/test-support/mocks/empty.css b/lit-components/test-support/mocks/empty.css new file mode 100644 index 0000000..056cc9a --- /dev/null +++ b/lit-components/test-support/mocks/empty.css @@ -0,0 +1 @@ +/* Empty CSS Mock */ diff --git a/lit-components/test-support/mocks/monaco.ts b/lit-components/test-support/mocks/monaco.ts new file mode 100644 index 0000000..ce48a32 --- /dev/null +++ b/lit-components/test-support/mocks/monaco.ts @@ -0,0 +1,18 @@ +export const editor = { + create: () => ({ + dispose: () => {}, + getValue: () => "", + setValue: () => {}, + updateOptions: () => {}, + getModel: () => ({ + onDidChangeContent: () => ({ dispose: () => {} }), + }), + }), + setTheme: () => {}, +}; + +const monacoMock = { + editor, +}; + +export default monacoMock; \ No newline at end of file diff --git a/lit-components/test-support/mocks/opensheetmusicdisplay.ts b/lit-components/test-support/mocks/opensheetmusicdisplay.ts new file mode 100644 index 0000000..be23f70 --- /dev/null +++ b/lit-components/test-support/mocks/opensheetmusicdisplay.ts @@ -0,0 +1,6 @@ +export class OpenSheetMusicDisplay { + constructor() {} + load() { return Promise.resolve(); } + render() {} + zoom() {} +} \ No newline at end of file diff --git a/lit-components/test-support/mocks/orbitcontrols.ts b/lit-components/test-support/mocks/orbitcontrols.ts new file mode 100644 index 0000000..7fe88b3 --- /dev/null +++ b/lit-components/test-support/mocks/orbitcontrols.ts @@ -0,0 +1,5 @@ +export class OrbitControls { + update() {} + addEventListener() {} + removeEventListener() {} +} \ No newline at end of file diff --git a/lit-components/test-support/mocks/rxdb.ts b/lit-components/test-support/mocks/rxdb.ts new file mode 100644 index 0000000..437331e --- /dev/null +++ b/lit-components/test-support/mocks/rxdb.ts @@ -0,0 +1,27 @@ +import { Observable } from "rxjs"; + +export const addRxPlugin = () => {}; +export const createRxDatabase = async () => { + const todosCollection = { + $: new Observable((subscriber) => { + subscriber.next([]); + }), + find: () => ({ + $: new Observable((subscriber) => { + subscriber.next([]); + }), + exec: async () => [], + }), + insert: async (data) => data, + remove: async () => {}, + }; + + return { + addCollections: async (collections) => { + return { + todos: todosCollection, + }; + }, + todos: todosCollection, + }; +}; \ No newline at end of file diff --git a/lit-components/test-support/mocks/styles.ts b/lit-components/test-support/mocks/styles.ts new file mode 100644 index 0000000..9cf3c27 --- /dev/null +++ b/lit-components/test-support/mocks/styles.ts @@ -0,0 +1 @@ +export default ""; diff --git a/lit-components/test-support/mocks/three.ts b/lit-components/test-support/mocks/three.ts new file mode 100644 index 0000000..6b66054 --- /dev/null +++ b/lit-components/test-support/mocks/three.ts @@ -0,0 +1,79 @@ +export class WebGLRenderer { + domElement = document.createElement("div"); + setSize() {} + render() {} + dispose() {} + setAnimationLoop() {} + setClearColor() {} +} + +export class Scene { + add() {} + remove() {} +} + +export class PerspectiveCamera { + position = { set: () => {}, x: 0, y: 0, z: 0 }; + lookAt() {} + aspect = 1; + updateProjectionMatrix() {} +} + +export class AmbientLight {} +export class DirectionalLight { + position = { set: () => {} }; + shadow = { + mapSize: { width: 0, height: 0 }, + camera: { near: 0, far: 0, left: 0, right: 0, top: 0, bottom: 0 } + }; +} + +export class Mesh { + position = { set: () => {}, x: 0, y: 0, z: 0 }; + rotation = { x: 0, y: 0, z: 0 }; + scale = { set: () => {} }; + userData = {}; +} + +export class BoxGeometry {} +export class MeshStandardMaterial {} +export class MeshBasicMaterial {} +export class Color { + set() {} +} +export class Vector3 { + set() {} +} +export class Group { + add() {} + remove() {} + position = { set: () => {} }; +} +export class Object3D { + add() {} + remove() {} +} + +export class Raycaster { + setFromCamera() {} + intersectObjects() { return []; } +} + +const threeMock = { + WebGLRenderer, + Scene, + PerspectiveCamera, + AmbientLight, + DirectionalLight, + Mesh, + BoxGeometry, + MeshStandardMaterial, + MeshBasicMaterial, + Color, + Vector3, + Group, + Object3D, + Raycaster, +}; + +export default threeMock; \ No newline at end of file diff --git a/lit-components/test-support/mocks/tone.ts b/lit-components/test-support/mocks/tone.ts new file mode 100644 index 0000000..7293705 --- /dev/null +++ b/lit-components/test-support/mocks/tone.ts @@ -0,0 +1,16 @@ +export class Synth { + triggerAttackRelease() {} + toDestination() { return this; } +} + +export class PolySynth { + triggerAttackRelease() {} + toDestination() { return this; } +} + +const toneMock = { + Synth, + PolySynth, +}; + +export default toneMock; \ No newline at end of file diff --git a/lit-components/test-support/setup.ts b/lit-components/test-support/setup.ts new file mode 100644 index 0000000..f69f445 --- /dev/null +++ b/lit-components/test-support/setup.ts @@ -0,0 +1,67 @@ +import { vi } from "vitest"; + +if (typeof customElements !== "undefined") { + const originalDefine = customElements.define; + customElements.define = function (name, constructor, options) { + if (customElements.get(name)) { + return; + } + originalDefine.call(customElements, name, constructor, options); + }; +} + +if (typeof window !== "undefined") { + class ResizeObserverMock { + observe() {} + unobserve() {} + disconnect() {} + } + window.ResizeObserver = ResizeObserverMock; +} + +if (typeof HTMLCanvasElement !== "undefined") { + const dummyContext = { + measureText: () => ({ width: 0 }), + }; + const canvasContextProxy = new Proxy(dummyContext, { + get(target, prop) { + if (prop in target) { + return target[prop]; + } + return () => {}; + } + }); + + HTMLCanvasElement.prototype.getContext = function (type) { + if (type === "2d") { + return canvasContextProxy; + } + return null; + }; +} + +if (typeof document !== "undefined" && !document.execCommand) { + document.execCommand = function () { + return true; + }; +} + +vi.mock("@capacitor/status-bar", () => { + return { + StatusBar: { + setStyle: async () => {}, + show: async () => {}, + hide: async () => {}, + setOverlaysWebView: async () => {}, + }, + Style: { + Dark: "DARK", + Light: "LIGHT", + Default: "DEFAULT", + } + }; +}); + +vi.mock("pouchdb-adapter-idb", () => { + return {}; +}); \ No newline at end of file diff --git a/vite-rxdb-lit/src/components/app-bar.ts b/lit-components/vite-rxdb-lit/components/app-bar.ts similarity index 100% rename from vite-rxdb-lit/src/components/app-bar.ts rename to lit-components/vite-rxdb-lit/components/app-bar.ts diff --git a/vite-rxdb-lit/src/components/app-button.ts b/lit-components/vite-rxdb-lit/components/app-button.ts similarity index 100% rename from vite-rxdb-lit/src/components/app-button.ts rename to lit-components/vite-rxdb-lit/components/app-button.ts diff --git a/vite-rxdb-lit/src/components/app-dialog.ts b/lit-components/vite-rxdb-lit/components/app-dialog.ts similarity index 100% rename from vite-rxdb-lit/src/components/app-dialog.ts rename to lit-components/vite-rxdb-lit/components/app-dialog.ts diff --git a/vite-rxdb-lit/src/components/app-drawer.ts b/lit-components/vite-rxdb-lit/components/app-drawer.ts similarity index 100% rename from vite-rxdb-lit/src/components/app-drawer.ts rename to lit-components/vite-rxdb-lit/components/app-drawer.ts diff --git a/vite-rxdb-lit/src/components/app-scaffold.ts b/lit-components/vite-rxdb-lit/components/app-scaffold.ts similarity index 100% rename from vite-rxdb-lit/src/components/app-scaffold.ts rename to lit-components/vite-rxdb-lit/components/app-scaffold.ts diff --git a/vite-rxdb-lit/src/components/form-builder.ts b/lit-components/vite-rxdb-lit/components/form-builder.ts similarity index 100% rename from vite-rxdb-lit/src/components/form-builder.ts rename to lit-components/vite-rxdb-lit/components/form-builder.ts diff --git a/vite-rxdb-lit/src/components/future-builder.ts b/lit-components/vite-rxdb-lit/components/future-builder.ts similarity index 100% rename from vite-rxdb-lit/src/components/future-builder.ts rename to lit-components/vite-rxdb-lit/components/future-builder.ts diff --git a/vite-rxdb-lit/src/components/list-view.ts b/lit-components/vite-rxdb-lit/components/list-view.ts similarity index 100% rename from vite-rxdb-lit/src/components/list-view.ts rename to lit-components/vite-rxdb-lit/components/list-view.ts diff --git a/vite-rxdb-lit/src/components/loading.ts b/lit-components/vite-rxdb-lit/components/loading.ts similarity index 100% rename from vite-rxdb-lit/src/components/loading.ts rename to lit-components/vite-rxdb-lit/components/loading.ts diff --git a/vite-rxdb-lit/src/pages/todo.ts b/lit-components/vite-rxdb-lit/pages/todo.ts similarity index 100% rename from vite-rxdb-lit/src/pages/todo.ts rename to lit-components/vite-rxdb-lit/pages/todo.ts diff --git a/lit-components/vite-rxdb-lit/rxdb.test.ts b/lit-components/vite-rxdb-lit/rxdb.test.ts new file mode 100644 index 0000000..42e93ba --- /dev/null +++ b/lit-components/vite-rxdb-lit/rxdb.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from "vitest"; + +if (!customElements.get("todo-view")) { + customElements.define("todo-view", class extends HTMLElement {}); +} + +describe("RxDB Lit To-Do Element", () => { + test("registers todo-view custom element successfully", () => { + expect(customElements.get("todo-view")).toBeDefined(); + }); + + test("mounts todo-view container successfully", async () => { + document.body.innerHTML = ""; + await new Promise((r) => setTimeout(r, 10)); + + const element = document.body.querySelector("todo-view"); + expect(element).toBeDefined(); + }); +}); \ No newline at end of file diff --git a/vite-rxdb-lit/src/services/base.ts b/lit-components/vite-rxdb-lit/services/base.ts similarity index 100% rename from vite-rxdb-lit/src/services/base.ts rename to lit-components/vite-rxdb-lit/services/base.ts diff --git a/vite-rxdb-lit/src/services/database.ts b/lit-components/vite-rxdb-lit/services/database.ts similarity index 97% rename from vite-rxdb-lit/src/services/database.ts rename to lit-components/vite-rxdb-lit/services/database.ts index c5a7440..753cca7 100644 --- a/vite-rxdb-lit/src/services/database.ts +++ b/lit-components/vite-rxdb-lit/services/database.ts @@ -1,4 +1,4 @@ -import "@babel/polyfill"; +// import "@babel/polyfill"; import { addRxPlugin, diff --git a/vite-rxdb-lit/src/services/todos.ts b/lit-components/vite-rxdb-lit/services/todos.ts similarity index 100% rename from vite-rxdb-lit/src/services/todos.ts rename to lit-components/vite-rxdb-lit/services/todos.ts diff --git a/lit-draggable-dom/.gitignore b/lit-draggable-dom/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-draggable-dom/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-draggable-dom/.vscode/settings.json b/lit-draggable-dom/.vscode/settings.json deleted file mode 100644 index 1a5e011..0000000 --- a/lit-draggable-dom/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "cSpell.words": [ - "vite" - ] -} \ No newline at end of file diff --git a/lit-draggable-dom/README.md b/lit-draggable-dom/README.md deleted file mode 100644 index 2ad57aa..0000000 --- a/lit-draggable-dom/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Lit Draggable DOM - -[Lit](https://lit.dev) Example of how to take HTML Elements or SVG Elements as slots and render them on a canvas that can be dragged as a whole or individual items. - -You can try the demo [here](https://rodydavis.github.io/lit-draggable-dom/)! - -Here is the related [blog post](https://rodydavis.com/posts/lit-draggable-dom/). - -This uses [CSS 2D transforms and pointer capture events](https://developer.mozilla.org/en-US/docs/Web/API/Element/setPointerCapture) to efficiently render and move the elements. - -![](/screenshot.png) - -There is also an example on the Lit playground [here](https://lit.dev/playground/#project=W3sibmFtZSI6ImxpdC1jc3MtY2FudmFzLnRzIiwiY29udGVudCI6ImltcG9ydCB7IGh0bWwsIGNzcywgTGl0RWxlbWVudCB9IGZyb20gXCJsaXRcIjtcbmltcG9ydCB7IGN1c3RvbUVsZW1lbnQsIHF1ZXJ5IH0gZnJvbSBcImxpdC9kZWNvcmF0b3JzLmpzXCI7XG5cbnR5cGUgRHJhZ1R5cGUgPSBcIm5vbmVcIiB8IFwiY2FudmFzXCIgfCBcImVsZW1lbnRcIjtcbnR5cGUgU3VwcG9ydGVkTm9kZSA9IEhUTUxFbGVtZW50IHwgU1ZHRWxlbWVudDtcblxuQGN1c3RvbUVsZW1lbnQoXCJjc3MtY2FudmFzXCIpXG5leHBvcnQgY2xhc3MgQ1NTQ2FudmFzIGV4dGVuZHMgTGl0RWxlbWVudCB7XG4gIEBxdWVyeShcIm1haW5cIikgcm9vdCE6IEhUTUxFbGVtZW50O1xuICBAcXVlcnkoXCIjY2hpbGRyZW5cIikgY29udGFpbmVyITogSFRNTEVsZW1lbnQ7XG4gIEBxdWVyeShcImNhbnZhc1wiKSBjYW52YXMhOiBIVE1MQ2FudmFzRWxlbWVudDtcbiAgZHJhZ1R5cGU6IERyYWdUeXBlID0gXCJub25lXCI7XG4gIG9mZnNldDogT2Zmc2V0ID0geyB4OiAwLCB5OiAwIH07XG4gIHBvaW50ZXJNYXA6IE1hcDxudW1iZXIsIFBvaW50ZXJEYXRhPiA9IG5ldyBNYXAoKTtcblxuICBzdGF0aWMgc3R5bGVzID0gY3NzYFxuICAgIDpob3N0IHtcbiAgICAgIC0tb2Zmc2V0LXg6IDA7XG4gICAgICAtLW9mZnNldC15OiAwO1xuICAgICAgLS1ncmlkLWJhY2tncm91bmQtY29sb3I6IHdoaXRlO1xuICAgICAgLS1ncmlkLWNvbG9yOiBibGFjaztcbiAgICAgIC0tZ3JpZC1zaXplOiA0MHB4O1xuICAgICAgLS1ncmlkLWRvdC1zaXplOiAxcHg7XG4gICAgfVxuICAgIG1haW4ge1xuICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICB9XG4gICAgY2FudmFzIHtcbiAgICAgIGJhY2tncm91bmQtc2l6ZTogdmFyKC0tZ3JpZC1zaXplKSB2YXIoLS1ncmlkLXNpemUpO1xuICAgICAgYmFja2dyb3VuZC1pbWFnZTogcmFkaWFsLWdyYWRpZW50KFxuICAgICAgICBjaXJjbGUsXG4gICAgICAgIHZhcigtLWdyaWQtY29sb3IpIHZhcigtLWdyaWQtZG90LXNpemUpLFxuICAgICAgICB2YXIoLS1ncmlkLWJhY2tncm91bmQtY29sb3IpIHZhcigtLWdyaWQtZG90LXNpemUpXG4gICAgICApO1xuICAgICAgYmFja2dyb3VuZC1wb3NpdGlvbjogdmFyKC0tb2Zmc2V0LXgpIHZhcigtLW9mZnNldC15KTtcbiAgICAgIHotaW5kZXg6IDA7XG4gICAgfVxuICAgIC5mdWxsLXNpemUge1xuICAgICAgd2lkdGg6IDEwMCU7XG4gICAgICBoZWlnaHQ6IDEwMCU7XG4gICAgICBwb3NpdGlvbjogZml4ZWQ7XG4gICAgfVxuICAgIC5jaGlsZCB7XG4gICAgICAtLWR4OiAwcHg7XG4gICAgICAtLWR5OiAwcHg7XG4gICAgICBwb3NpdGlvbjogZml4ZWQ7XG4gICAgICBmbGV4LXNocmluazogMTtcbiAgICAgIHotaW5kZXg6IHZhcigtLWxheWVyLCAwKTtcbiAgICAgIHRyYW5zZm9ybTogdHJhbnNsYXRlKHZhcigtLWR4KSwgdmFyKC0tZHkpKTtcbiAgICB9XG4gICAgQG1lZGlhIChwcmVmZXJzLWNvbG9yLXNjaGVtZTogZGFyaykge1xuICAgICAgbWFpbiB7XG4gICAgICAgIC0tZ3JpZC1iYWNrZ3JvdW5kLWNvbG9yOiBibGFjaztcbiAgICAgICAgLS1ncmlkLWNvbG9yOiBncmV5O1xuICAgICAgfVxuICAgIH1cbiAgYDtcblxuICByZW5kZXIoKSB7XG4gICAgY29uc29sZS5sb2coXCJyZW5kZXJcIik7XG4gICAgcmV0dXJuIGh0bWxgXG4gICAgICA8bWFpbiBjbGFzcz1cImZ1bGwtc2l6ZVwiPlxuICAgICAgICA8Y2FudmFzIGNsYXNzPVwiZnVsbC1zaXplXCI-PC9jYW52YXM-XG4gICAgICAgIDxkaXYgaWQ9XCJjaGlsZHJlblwiIGNsYXNzPVwiZnVsbC1zaXplXCI-PC9kaXY-XG4gICAgICA8L21haW4-XG4gICAgYDtcbiAgfVxuXG4gIGhhbmRsZURvd24oZXZlbnQ6IFBvaW50ZXJFdmVudCwgdHlwZTogRHJhZ1R5cGUpIHtcbiAgICBpZiAodGhpcy5kcmFnVHlwZSA9PT0gXCJub25lXCIpIHtcbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB0aGlzLmRyYWdUeXBlID0gdHlwZTtcbiAgICAgIChldmVudC50YXJnZXQgYXMgRWxlbWVudCkuc2V0UG9pbnRlckNhcHR1cmUoZXZlbnQucG9pbnRlcklkKTtcbiAgICAgIHRoaXMucG9pbnRlck1hcC5zZXQoZXZlbnQucG9pbnRlcklkLCB7XG4gICAgICAgIGlkOiBldmVudC5wb2ludGVySWQsXG4gICAgICAgIHN0YXJ0UG9zOiB7IHg6IGV2ZW50LmNsaWVudFgsIHk6IGV2ZW50LmNsaWVudFkgfSxcbiAgICAgICAgY3VycmVudFBvczogeyB4OiBldmVudC5jbGllbnRYLCB5OiBldmVudC5jbGllbnRZIH0sXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBoYW5kbGVNb3ZlKFxuICAgIGV2ZW50OiBQb2ludGVyRXZlbnQsXG4gICAgdHlwZTogRHJhZ1R5cGUsXG4gICAgb25Nb3ZlOiAoZGVsdGE6IE9mZnNldCkgPT4gdm9pZFxuICApIHtcbiAgICBpZiAodGhpcy5kcmFnVHlwZSA9PT0gdHlwZSkge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGNvbnN0IHNhdmVkID0gdGhpcy5wb2ludGVyTWFwLmdldChldmVudC5wb2ludGVySWQpITtcbiAgICAgIGNvbnN0IGN1cnJlbnQgPSB7IC4uLnNhdmVkLmN1cnJlbnRQb3MgfTtcbiAgICAgIHNhdmVkLmN1cnJlbnRQb3MgPSB7IHg6IGV2ZW50LmNsaWVudFgsIHk6IGV2ZW50LmNsaWVudFkgfTtcbiAgICAgIGNvbnN0IGRlbHRhID0ge1xuICAgICAgICB4OiBzYXZlZC5jdXJyZW50UG9zLnggLSBjdXJyZW50LngsXG4gICAgICAgIHk6IHNhdmVkLmN1cnJlbnRQb3MueSAtIGN1cnJlbnQueSxcbiAgICAgIH07XG4gICAgICBvbk1vdmUoZGVsdGEpO1xuICAgIH1cbiAgfVxuXG4gIGhhbmRsZVVwKGV2ZW50OiBQb2ludGVyRXZlbnQpIHtcbiAgICB0aGlzLmRyYWdUeXBlID0gXCJub25lXCI7XG4gICAgKGV2ZW50LnRhcmdldCBhcyBFbGVtZW50KS5yZWxlYXNlUG9pbnRlckNhcHR1cmUoZXZlbnQucG9pbnRlcklkKTtcbiAgfVxuXG4gIG1vdmVDYW52YXMoZGVsdGE6IE9mZnNldCkge1xuICAgIHRoaXMub2Zmc2V0LnggKz0gZGVsdGEueDtcbiAgICB0aGlzLm9mZnNldC55ICs9IGRlbHRhLnk7XG4gICAgdGhpcy5yb290LnN0eWxlLnNldFByb3BlcnR5KFwiLS1vZmZzZXQteFwiLCBgJHt0aGlzLm9mZnNldC54fXB4YCk7XG4gICAgdGhpcy5yb290LnN0eWxlLnNldFByb3BlcnR5KFwiLS1vZmZzZXQteVwiLCBgJHt0aGlzLm9mZnNldC55fXB4YCk7XG4gIH1cblxuICBtb3ZlRWxlbWVudChjaGlsZDogU3VwcG9ydGVkTm9kZSwgZGVsdGE6IE9mZnNldCkge1xuICAgIGNvbnN0IGdldE51bWJlciA9IChrZXk6IFwiLS1keFwiIHwgXCItLWR5XCIsIGZhbGxiYWNrOiBudW1iZXIpID0-IHtcbiAgICAgIGNvbnN0IHNhdmVkID0gY2hpbGQuc3R5bGUuZ2V0UHJvcGVydHlWYWx1ZShrZXkpO1xuICAgICAgaWYgKHNhdmVkLmxlbmd0aCA-IDApIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQoc2F2ZWQucmVwbGFjZShcInB4XCIsIFwiXCIpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxsYmFjaztcbiAgICB9O1xuICAgIGNvbnN0IGR4ID0gZ2V0TnVtYmVyKFwiLS1keFwiLCAwKSArIGRlbHRhLng7XG4gICAgY29uc3QgZHkgPSBnZXROdW1iZXIoXCItLWR5XCIsIDApICsgZGVsdGEueTtcbiAgICBjaGlsZC5zdHlsZS50cmFuc2Zvcm0gPSBgdHJhbnNsYXRlKCR7ZHh9cHgsICR7ZHl9cHgpYDtcbiAgICBjaGlsZC5zdHlsZS5zZXRQcm9wZXJ0eShcIi0tZHhcIiwgYCR7ZHh9cHhgKTtcbiAgICBjaGlsZC5zdHlsZS5zZXRQcm9wZXJ0eShcIi0tZHlcIiwgYCR7ZHl9cHhgKTtcbiAgfVxuXG4gIGFzeW5jIGZpcnN0VXBkYXRlZCgpIHtcbiAgICBjb25zdCBpdGVtcyA9IEFycmF5LmZyb20odGhpcy5jaGlsZE5vZGVzKTtcbiAgICBsZXQgaSA9IDA7XG4gICAgZm9yIChjb25zdCBub2RlIG9mIGl0ZW1zKSB7XG4gICAgICBpZiAobm9kZSBpbnN0YW5jZW9mIFNWR0VsZW1lbnQgfHwgbm9kZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7XG4gICAgICAgIGNvbnN0IGNoaWxkID0gbm9kZSBhcyBTdXBwb3J0ZWROb2RlO1xuICAgICAgICBjaGlsZC5jbGFzc0xpc3QuYWRkKFwiY2hpbGRcIik7XG4gICAgICAgIGNoaWxkLnN0eWxlLnNldFByb3BlcnR5KFwiLS1sYXllclwiLCBgJHtpfWApO1xuICAgICAgICB0aGlzLmNvbnRhaW5lci5hcHBlbmQoY2hpbGQpO1xuICAgICAgICBjaGlsZC5hZGRFdmVudExpc3RlbmVyKFwicG9pbnRlcmRvd25cIiwgKGU6IGFueSkgPT4ge1xuICAgICAgICAgIHRoaXMuaGFuZGxlRG93bihlLCBcImVsZW1lbnRcIik7XG4gICAgICAgIH0pO1xuICAgICAgICBjaGlsZC5hZGRFdmVudExpc3RlbmVyKFwicG9pbnRlcm1vdmVcIiwgKGU6IGFueSkgPT4ge1xuICAgICAgICAgIHRoaXMuaGFuZGxlTW92ZShlLCBcImVsZW1lbnRcIiwgKGRlbHRhKSA9PiB7XG4gICAgICAgICAgICB0aGlzLm1vdmVFbGVtZW50KGNoaWxkLCBkZWx0YSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBpKys7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucmVxdWVzdFVwZGF0ZSgpO1xuICAgIHRoaXMucm9vdC5hZGRFdmVudExpc3RlbmVyKFwicG9pbnRlcmRvd25cIiwgKGU6IGFueSkgPT4ge1xuICAgICAgdGhpcy5oYW5kbGVEb3duKGUsIFwiY2FudmFzXCIpO1xuICAgIH0pO1xuICAgIHRoaXMucm9vdC5hZGRFdmVudExpc3RlbmVyKFwicG9pbnRlcm1vdmVcIiwgKGU6IGFueSkgPT4ge1xuICAgICAgdGhpcy5oYW5kbGVNb3ZlKGUsIFwiY2FudmFzXCIsIChkZWx0YSkgPT4ge1xuICAgICAgICB0aGlzLm1vdmVDYW52YXMoZGVsdGEpO1xuICAgICAgICBmb3IgKGNvbnN0IG5vZGUgb2YgQXJyYXkuZnJvbSh0aGlzLmNvbnRhaW5lci5jaGlsZHJlbikpIHtcbiAgICAgICAgICBpZiAobm9kZSBpbnN0YW5jZW9mIFNWR0VsZW1lbnQgfHwgbm9kZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLm1vdmVFbGVtZW50KG5vZGUsIGRlbHRhKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIHRoaXMucm9vdC5hZGRFdmVudExpc3RlbmVyKFwicG9pbnRlcnVwXCIsIChlOiBhbnkpID0-IHtcbiAgICAgIHRoaXMuaGFuZGxlVXAoZSk7XG4gICAgfSk7XG4gIH1cbn1cblxuaW50ZXJmYWNlIE9mZnNldCB7XG4gIHg6IG51bWJlcjtcbiAgeTogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgUG9pbnRlckRhdGEge1xuICBpZDogbnVtYmVyO1xuICBzdGFydFBvczogT2Zmc2V0O1xuICBjdXJyZW50UG9zOiBPZmZzZXQ7XG59XG4ifSx7Im5hbWUiOiJpbmRleC5odG1sIiwiY29udGVudCI6IjwhRE9DVFlQRSBodG1sPlxuPGh0bWwgbGFuZz1cImVuXCI-XG4gIDxoZWFkPlxuICAgIDxtZXRhIGNoYXJzZXQ9XCJVVEYtOFwiIC8-XG4gICAgPGxpbmsgcmVsPVwiaWNvblwiIHR5cGU9XCJpbWFnZS9zdmcreG1sXCIgaHJlZj1cIi9zcmMvZmF2aWNvbi5zdmdcIiAvPlxuICAgIDxtZXRhIG5hbWU9XCJ2aWV3cG9ydFwiIGNvbnRlbnQ9XCJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MS4wXCIgLz5cbiAgICA8dGl0bGU-TGl0IENTUyBDYW52YXM8L3RpdGxlPlxuICAgIDxzdHlsZT5cbiAgICAgIGJvZHkge1xuICAgICAgICBtYXJnaW46IDA7XG4gICAgICAgIHBhZGRpbmc6IDA7XG4gICAgICAgIHdpZHRoOiAxMDAlO1xuICAgICAgICBoZWlnaHQ6IDEwMHZoO1xuICAgICAgfVxuICAgIDwvc3R5bGU-XG4gICAgPHNjcmlwdCB0eXBlPVwibW9kdWxlXCIgc3JjPVwiLi9saXQtY3NzLWNhbnZhcy5qc1wiPjwvc2NyaXB0PlxuICA8L2hlYWQ-XG4gIDxib2R5PlxuICAgIDxjc3MtY2FudmFzPlxuICAgICAgPGltZ1xuICAgICAgICBzcmM9XCJodHRwczovL2xpdC5kZXYvaW1hZ2VzL2xvZ28uc3ZnXCJcbiAgICAgICAgYWx0PVwiTGl0IExvZ29cIlxuICAgICAgICB3aWR0aD1cIjUwMFwiXG4gICAgICAgIGhlaWdodD1cIjMzM1wiXG4gICAgICAgIHN0eWxlPVwiLS1keDogNTkuNDkwOXB4OyAtLWR5OiAzMi44NDI5cHhcIlxuICAgICAgLz5cbiAgICAgIDxzdmcgd2lkdGg9XCI0MDBcIiBoZWlnaHQ9XCIxMTBcIiBzdHlsZT1cIi0tZHg6IDIzMC4wNTdweDsgLS1keTogMzMuNjI1N3B4XCI-XG4gICAgICAgIDxyZWN0XG4gICAgICAgICAgd2lkdGg9XCI0MDBcIlxuICAgICAgICAgIGhlaWdodD1cIjEwMFwiXG4gICAgICAgICAgc3R5bGU9XCJmaWxsOiByZ2IoMCwgMCwgMjU1KTsgc3Ryb2tlLXdpZHRoOiAzOyBzdHJva2U6IHJnYigwLCAwLCAwKVwiXG4gICAgICAgIC8-XG4gICAgICA8L3N2Zz5cbiAgICAgIDxzdmcgaGVpZ2h0PVwiMTAwXCIgd2lkdGg9XCIxMDBcIj5cbiAgICAgICAgPGNpcmNsZVxuICAgICAgICAgIGN4PVwiNTBcIlxuICAgICAgICAgIGN5PVwiNTBcIlxuICAgICAgICAgIHI9XCI0MFwiXG4gICAgICAgICAgc3Ryb2tlPVwiYmxhY2tcIlxuICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjNcIlxuICAgICAgICAgIGZpbGw9XCJyZWRcIlxuICAgICAgICAvPlxuICAgICAgPC9zdmc-XG4gICAgPC9jc3MtY2FudmFzPlxuICA8L2JvZHk-XG48L2h0bWw-XG4ifV0). diff --git a/lit-draggable-dom/index.html b/lit-draggable-dom/index.html deleted file mode 100644 index 85e9861..0000000 --- a/lit-draggable-dom/index.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - Lit Draggable DOM - - - - - - Lit Logo - - - - - - - - - diff --git a/lit-draggable-dom/screenshot.png b/lit-draggable-dom/screenshot.png deleted file mode 100644 index e9c3ebc..0000000 Binary files a/lit-draggable-dom/screenshot.png and /dev/null differ diff --git a/lit-draggable-dom/src/favicon.svg b/lit-draggable-dom/src/favicon.svg deleted file mode 100644 index 2c3a23d..0000000 --- a/lit-draggable-dom/src/favicon.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lit-draggable-dom/src/vite-env.d.ts b/lit-draggable-dom/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-draggable-dom/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-draggable-dom/tsconfig.json b/lit-draggable-dom/tsconfig.json deleted file mode 100644 index d17e916..0000000 --- a/lit-draggable-dom/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/lit-file-based-routing/.gitignore b/lit-file-based-routing/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-file-based-routing/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-file-based-routing/README.md b/lit-file-based-routing/README.md deleted file mode 100644 index 756d185..0000000 --- a/lit-file-based-routing/README.md +++ /dev/null @@ -1,243 +0,0 @@ -[![Demo](https://github.com/rodydavis/lit-file-based-routing/actions/workflows/ci.yml/badge.svg)](https://github.com/rodydavis/lit-file-based-routing/actions/workflows/ci.yml) - -# Lit File Based Routing - -Lit router for nested layouts and file based routing. Similar to https://remix.run/ but at client side. - -[Demo](https://rodydavis.github.io/lit-file-based-routing/#/dashboard/) - -[Package](/lit-file-router/) - -Archived in favor of: https://github.com/rodydavis/vscode-router-generator - -## Features - -- File based routing -- Nested layout - -## Defining a root layout - -To layout navigation once you will want to define a root layout that all pages can inherit from. - -```js -import { html, css, LitElement } from "lit"; -import { customElement } from "lit/decorators.js"; - -@customElement("root-module") -export class RootModule extends LitElement { - static styles = css` - main { - display: flex; - flex-direction: row; - height: 100vh; - width: 100%; - } - aside { - display: flex; - flex-direction: column; - background-color: whitesmoke; - padding: 8px; - } - section { - flex: 1; - } - `; - - render() { - return html` -
- -
-
- `; - } -} - -``` - -## Defining a base layout - -You can define a base layout with the root name. For example: `dashboard.ts` - -```ts -import { html, css, LitElement } from "lit"; -import { customElement } from "lit/decorators.js"; - -@customElement("dashboard-module") -export class DashboardModule extends LitElement { - static styles = css` - header { - height: 40px; - background-color: orange; - color: white; - display: flex; - flex-direction: row; - align-items: center; - padding-left: 10px; - padding-right: 10px; - justify-content: space-between; - } - `; - - render() { - return html`
-
- Dashboard - -
-
-
`; - } -} - -``` - -If you notice the `` is used for the nested layout. - -## Defining the index route - -You can define the index route for when there are no args needed. For example: `dashboard/index.ts` - -```ts -import { html, css, LitElement } from "lit"; -import { customElement } from "lit/decorators.js"; - -@customElement("dashboard-default") -export class DashboardDefault extends LitElement { - static styles = css``; - - render() { - return html`
Default Dashboard
`; - } -} - -``` - -Since this is a nested layout all you need to do is provide the component and it will inherit from the parent layout (dashboard.ts). - -## Defining a named arg - -You can define a named arg for a route if there is something that does not need data fetched for. For example: `/dashboard/overview.ts` - -```ts -import { html, css, LitElement } from "lit"; -import { customElement } from "lit/decorators.js"; - -@customElement("overview-module") -export class OverviewModule extends LitElement { - static styles = css``; - - render() { - return html`
Overview
`; - } -} - -``` - -This is also just a component. - -## Defining a dynamic arg - -Sometimes the arg is generated at runtime or needs to be pulled from a database. For example: `dashboard/account/:id.ts` - -```ts -import { html, css, LitElement } from "lit"; -import { customElement, property } from "lit/decorators.js"; - -@customElement("account-details") -export class AccountDetails extends LitElement { - static styles = css``; - - @property({ type: String }) id = ""; - - render() { - return html`
User ID: ${this.id}
`; - } -} - -``` - -You can see we set the file name with a prefix of `:` to define an arg to look for and match against. This will be provided in a map. - -## Usage - -If you install the package locally you can run `node lit-file-router` to have `src/generated-app.ts` added as a file when it analyzes the `src/pages/` directory. - -```html - - - - -``` - -### Dynamic Imports - -You can have the components load async with dynamic imports using the following command: - -`node lit-file-router --dynamic-imports=true` - -By default it will use static imports and have everything loaded at runtime. - -### Data caching and loader function - -You can export a loader function that will be used to set data on the component: - -```js -import { html, css, LitElement } from "lit"; -import { customElement, property } from "lit/decorators.js"; - -export async function loader( - route: string, - args: { [key: string]: any } -): Promise { - await new Promise((resolve) => setTimeout(resolve, 1000)); - const id = args["id"]!; - return { - id, - name: "Name: " + id, - email: route, - }; -} - -@customElement("account-details") -export class AccountDetails extends LitElement { - static styles = css``; - - @property({ type: String }) id = ""; - @property({ type: Object }) data!: AccountData; - - render() { - return html`
User ID: ${this.data.id}
`; - } -} - -interface AccountData { - id: string; - name: string; - email: string; -} - -``` - -This will call the function to load the data before rendering starts. - -If you want to enable caching you can add the following command: - -`node lit-file-router --cache-all` - -It is off by default but it will cache the data from the loader function for the component and route and will pass the cached data from memory to the component. - -## Loading state - -You can pass show a progress indicator at the bottom by passing a loading arg: - -`node lit-file-router --show-loading=true` - -It is off by default, but this is useful for heavy requests that would hang the UI. diff --git a/lit-file-based-routing/index.html b/lit-file-based-routing/index.html deleted file mode 100644 index b108728..0000000 --- a/lit-file-based-routing/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - Vite + Lit App - - - - - - - diff --git a/lit-file-based-routing/lit-file-router/.gitignore b/lit-file-based-routing/lit-file-router/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-file-based-routing/lit-file-router/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-file-based-routing/lit-file-router/package-lock.json b/lit-file-based-routing/lit-file-router/package-lock.json deleted file mode 100644 index da22849..0000000 --- a/lit-file-based-routing/lit-file-router/package-lock.json +++ /dev/null @@ -1,269 +0,0 @@ -{ - "name": "lit-file-router", - "version": "0.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/node": { - "version": "17.0.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz", - "integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==", - "dev": true - }, - "esbuild": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz", - "integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==", - "dev": true, - "requires": { - "esbuild-android-arm64": "0.13.15", - "esbuild-darwin-64": "0.13.15", - "esbuild-darwin-arm64": "0.13.15", - "esbuild-freebsd-64": "0.13.15", - "esbuild-freebsd-arm64": "0.13.15", - "esbuild-linux-32": "0.13.15", - "esbuild-linux-64": "0.13.15", - "esbuild-linux-arm": "0.13.15", - "esbuild-linux-arm64": "0.13.15", - "esbuild-linux-mips64le": "0.13.15", - "esbuild-linux-ppc64le": "0.13.15", - "esbuild-netbsd-64": "0.13.15", - "esbuild-openbsd-64": "0.13.15", - "esbuild-sunos-64": "0.13.15", - "esbuild-windows-32": "0.13.15", - "esbuild-windows-64": "0.13.15", - "esbuild-windows-arm64": "0.13.15" - } - }, - "esbuild-android-arm64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz", - "integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz", - "integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz", - "integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz", - "integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz", - "integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz", - "integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz", - "integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz", - "integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz", - "integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz", - "integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz", - "integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz", - "integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz", - "integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz", - "integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz", - "integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz", - "integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.13.15", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz", - "integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==", - "dev": true, - "optional": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dev": true, - "requires": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - } - }, - "resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", - "dev": true, - "requires": { - "is-core-module": "^2.8.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "rollup": { - "version": "2.63.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz", - "integrity": "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", - "dev": true - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "typescript": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", - "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", - "dev": true - }, - "vite": { - "version": "2.7.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.7.10.tgz", - "integrity": "sha512-KEY96ntXUid1/xJihJbgmLZx7QSC2D4Tui0FdS0Old5OokYzFclcofhtxtjDdGOk/fFpPbHv9yw88+rB93Tb8w==", - "dev": true, - "requires": { - "esbuild": "^0.13.12", - "fsevents": "~2.3.2", - "postcss": "^8.4.5", - "resolve": "^1.20.0", - "rollup": "^2.59.0" - } - } - } -} diff --git a/lit-file-based-routing/lit-file-router/package.json b/lit-file-based-routing/lit-file-router/package.json deleted file mode 100644 index 97569b5..0000000 --- a/lit-file-based-routing/lit-file-router/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "module", - "name": "lit-file-router", - "version": "0.0.0", - "main": "dist/index.js", - "types": "types/index.d.ts", - "files": [ - "dist", - "types" - ], - "scripts": { - "preinstall": "npm run build", - "build": "tsc" - }, - "dependencies": {}, - "devDependencies": { - "@types/node": "^17.0.8", - "typescript": "^4.4.4" - } -} \ No newline at end of file diff --git a/lit-file-based-routing/lit-file-router/src/analyze-page.ts b/lit-file-based-routing/lit-file-router/src/analyze-page.ts deleted file mode 100644 index 855274a..0000000 --- a/lit-file-based-routing/lit-file-router/src/analyze-page.ts +++ /dev/null @@ -1,56 +0,0 @@ -export function analyzePage(path: string, content: string): WebComponent[] { - const components: WebComponent[] = []; - // Check for export function loader( or export async function loader( - let hasLoader = false; - const lines = content.split("\n"); - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if ( - line.includes("export function loader(") || - line.includes("export async function loader(") - ) { - hasLoader = true; - break; - } - } - // Look for @customElement decorator and get the value - const regex = /@customElement\("([^"]+)"\)/g; - const matches = content.match(regex); - if (matches) { - for (const match of matches) { - const result = match.match(/@customElement\("([^"]+)"\)/); - if (result) { - const name = result[1]; - components.push({ - name, - path, - hasLoader, - }); - } - } - } - // Look for customElements.define() and get the value - const regex2 = /customElements\.define\("([^"]+)"/g; - const matches2 = content.match(regex2); - if (matches2) { - for (const match of matches2) { - const result = match.match(/customElements\.define\("([^"]+)"/); - if (result) { - const name = result[1]; - components.push({ - name, - path, - hasLoader, - }); - } - } - } - return components; -} - -export interface WebComponent { - name: string; - path: string; - alias?: string; - hasLoader: boolean; -} diff --git a/lit-file-based-routing/lit-file-router/src/generate-app.ts b/lit-file-based-routing/lit-file-router/src/generate-app.ts deleted file mode 100644 index 1e8a475..0000000 --- a/lit-file-based-routing/lit-file-router/src/generate-app.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { WebComponent } from "./analyze-page"; -import { StringBuilder } from "./string-builder"; - -export function generateApp( - sb: StringBuilder, - components: WebComponent[], - options: { staticImports: boolean; cacheAll: boolean; showLoading: boolean } -) { - sb.writeln(`import { html, css, LitElement } from "lit";`); - sb.writeln( - `import { customElement, property, state } from "lit/decorators.js";` - ); - sb.writeln(); - sb.writeAll([ - '@customElement("generated-app")', - "export class GeneratedApp extends LitElement {", - " static styles = css`", - " main {", - " width: 100%;", - " height: 100%;", - " }", - ...(options.showLoading - ? [ - " progress {", - " position: absolute;", - " bottom: 0;", - " width: calc(100% - 1rem);", - " z-index: 1;", - " left: 0.5rem;", - " right: 0.5rem;", - " }", - ] - : []), - " `;", - "", - " @property() hash = 'true';", - " @property() base = '/';", - ...(options.showLoading ? [" @state() loading = false;"] : []), - " @property() route = this.getCurrentRoute();", - " @state() child = document.createElement('main');", - "", - ]); - if (options.cacheAll) { - sb.writeln(" dataCache = new Map();"); - } - sb.writeln(" components: Map = new Map(["); - for (const component of components) { - let path = component.path.replace("./src/pages/", "/"); - path = path.replace(".ts", ""); - path = path.replace(".js", ""); - path = path.replace("/index", "/"); - // Check if path contains . and convert to / - if (path.indexOf(".") > -1) { - path = path.split(".").join("/"); - } - if (path == "/root") path = ""; - // sb.writeln(` ["${path}", "${component.name}"],`);] - sb.writeln(` ["${path}", { - component: "${component.name}",`); - const componentImportPath = component.path - .replace("./src/", "./") - .replace(".ts", ".js"); - if (component.hasLoader) { - if (options.staticImports) { - sb.writeln(` loadData: async () => { - return ${component.alias}.loader; - },`); - } else { - sb.writeln(` loadData: async () => { - const {loader} = await import("${componentImportPath}"); - return loader; - },`); - } - } else { - sb.writeln(` loadData: async () => null,`); - } - if (options.staticImports) { - sb.writeln(` loadImport: async () => ${component.alias}, - }],`); - } else { - sb.writeln(` loadImport: () => import("${componentImportPath}"), - }],`); - } - } - sb.writeAll([ - " ]);", - "", - " firstUpdated() {", - ' window.addEventListener("hashchange", () => {', - " const oldRoute = this.route;", - " this.route = this.getCurrentRoute();", - " this.updateTree(oldRoute);", - " });", - " this.updateTree();", - " }", - "", - " render() {", - " return html` ${this.child} `;", - " }", - "", - " refresh() {", - " return this.updateTree();", - " }", - "", - " private async updateTree(oldRoute?:string) {", - " this.checkForIndex();", - " if (oldRoute) {", - " // TODO: Get delta between old and new route", - " }", - ...(options.showLoading - ? [ - ' const loadingElem = document.createElement("progress");', - " this.child.appendChild(loadingElem);", - ] - : []), - " const tree = await this.renderTree();", - " // Remove children", - " while (this.child.firstChild) {", - " this.child.removeChild(this.child.firstChild);", - " }", - " // Add new children", - " if (tree) this.child.appendChild(tree);", - " this.requestUpdate();", - " }", - "", - " private async renderTree() {", - " let _route = this.route;", - " const args = this.getArgsForRoute(_route);", - " const elements: Element[] = [];", - ' if (_route !== "/") {', - " while (_route.length > 0) {", - " const newChild = await this.getComponent(_route, args);", - " if (!newChild && _route === this.route) {", - ' const noChild = await this.getComponent("/404", args);', - " if (noChild) elements.push(noChild);", - " break;", - " }", - " if (newChild) elements.push(newChild);", - ' const parts = _route.split("/");', - " parts.pop();", - ' _route = parts.join("/");', - ' if (_route === "/") break;', - " }", - ' } else if (_route === "/") {', - ' const indexChild = await this.getComponent("/", args);', - " if (indexChild) elements.push(indexChild);", - " } else {", - ' const noChild = await this.getComponent("/404", args);', - " if (noChild) elements.push(noChild);", - " }", - ' const rootChild = await this.getComponent("", args);', - " if (rootChild) elements.push(rootChild);", - " let idx = elements.length - 1;", - " while (idx >= 1) {", - " const parent = elements[idx];", - " const child = elements[idx - 1];", - " if (child && parent) {", - " parent.appendChild(child);", - " }", - " idx--;", - " }", - " return elements.pop();", - " }", - "", - " private async getComponent(", - " path: string,", - " args: RegExpMatchArray | null", - " ) {", - " const applyArgs = (value: string, apply: boolean, data?: any) => {", - " const elem = document.createElement(value);", - " if (apply && args?.groups) {", - " for (const [key, value] of Object.entries(args.groups)) {", - " elem.setAttribute(key, value);", - " }", - " }", - " if (data) (elem as any).data = data;", - " return elem;", - " };", - " for (const [key, value] of Array.from(this.components.entries())) {", - " const hasArgs = path.match(fixRegex(key)) !== null;", - " if (key === path || path.match(fixRegex(key)) !== null) {", - ...(options.cacheAll - ? [ - " const cacheKey = `${path}:${value.component}`;", - " if (this.dataCache.has(cacheKey)) {", - " const data = this.dataCache.get(cacheKey)!;", - ...(options.staticImports - ? [] - : [" await value.loadImport();"]), - " return applyArgs(value.component, hasArgs, data);", - " }", - ] - : []), - " const getLoader = await value.loadData();", - " if (getLoader) {", - " const componentData = await getLoader(this.route, args ? Object(args)['groups'] : {});", - ...(options.cacheAll - ? [" this.dataCache.set(cacheKey, componentData);"] - : []), - ...(options.staticImports ? [] : [" await value.loadImport();"]), - " return applyArgs(value.component, hasArgs, componentData);", - " }", - ...(options.staticImports ? [] : [" await value.loadImport();"]), - " return applyArgs(value.component, hasArgs);", - " }", - " }", - " return null;", - " }", - "", - " private getArgsForRoute(route: string): RegExpMatchArray | null {", - " for (const key of Array.from(this.components.keys())) {", - " const regMatch = route.match(fixRegex(key));", - " if (regMatch !== null) return regMatch;", - " }", - " return null;", - " }", - "", - " private checkForIndex() {", - ' if (this.route === "" || this.route === "/") location.hash = "#/";', - ' if (this.route.endsWith("/")) return;', - " const indexArgs = this.getArgsForRoute(`${this.route}/`);", - " if (indexArgs !== null) {", - " location.hash = `#${this.route}/`;", - " }", - " }", - "", - " private getCurrentRoute() {", - ' let route = "/";', - ' if (this.hash === "true" && window.location.hash.length > 0) {', - " route = window.location.hash.slice(1);", - ' } else if (this.hash === "false") {', - ' const baseUrl = this.getAttribute("base") ?? "";', - " route = window.location.pathname.slice(baseUrl.length);", - " }", - " console.debug(`current route: ${route}`);", - " return route;", - " }", - "}", - "", - "function fixRegex(route: string): RegExp {", - ' const variableRegex = "[a-zA-Z0-9_-]+";', - " const nameWithParameters = route.replace(", - " new RegExp(`:(${variableRegex})`),", - " (match) => {", - " const groupName = match.slice(1);", - " return `(?<${groupName}>[a-zA-Z0-9_\\\\-.,:;+*^%$@!]+)`;", - " }", - " );", - " return new RegExp(`^${nameWithParameters}$`);", - "}", - "", - "interface Route {", - " component: string;", - " loadImport: () => Promise;", - " loadData: () => Promise;", - "}", - "", - "type RouteLoader = (", - " route: string,", - " args: { [key: string]: any }", - ") => Promise;", - ]); - sb.writeln(); -} diff --git a/lit-file-based-routing/lit-file-router/src/index.ts b/lit-file-based-routing/lit-file-router/src/index.ts deleted file mode 100644 index ee3c439..0000000 --- a/lit-file-based-routing/lit-file-router/src/index.ts +++ /dev/null @@ -1,91 +0,0 @@ -import * as fs from "fs"; -import { analyzePage, WebComponent } from "./analyze-page.js"; -import { generateApp } from "./generate-app.js"; -import { StringBuilder } from "./string-builder.js"; - -let inputDir = "./src/pages"; -let outputFile = "./src/generated-app.ts"; -let staticImports = true; -let cacheAll = false; -let showLoading = false; - -const args = process.argv.slice(2); -if (args.length == 0) { - analyzePages(); -} else { - // Check for -dynamic-imports=false - const noDynamicImports = args.indexOf("--dynamic-imports=false") !== -1; - staticImports = noDynamicImports; - // Check for --input-dir= - const inputDirArg = args.find((arg) => arg.startsWith("--input-dir=")); - if (inputDirArg) { - inputDir = inputDirArg.replace("--input-dir=", ""); - } - // Check for --output-file= - const outputFileArg = args.find((arg) => arg.startsWith("--output-file=")); - if (outputFileArg) { - outputFile = outputFileArg.replace("--output-file=", ""); - } - // Check for --cache-all - const cacheAllArg = args.find((arg) => arg.startsWith("--cache-all")); - if (cacheAllArg) { - cacheAll = true; - } - // Check for --show-loading=false - const showLoadingArg = args.find((arg) => - arg.startsWith("--show-loading=true") - ); - showLoading = showLoadingArg ? true : false; - analyzePages(); -} - -function readPagesDirectory( - dir: string, - pages: { path: string; content: string }[] -) { - const files = fs.readdirSync(dir); - for (const file of files) { - if (fs.statSync(`${dir}/${file}`).isDirectory()) { - readPagesDirectory(`${dir}/${file}`, pages); - } else { - const path = `${dir}/${file}`; - const content = fs.readFileSync(path, "utf8"); - pages.push({ path, content }); - } - } -} - -async function analyzePages() { - const sb = new StringBuilder(); - // sb.writeln("// @ts-nocheck"); - // sb.writeln(); - let i = 0; - if (staticImports) { - sb.writeln(`// Page Routes`); - } - const components: WebComponent[] = []; - const pages: { path: string; content: string }[] = []; - readPagesDirectory(inputDir, pages); - for (const { path, content } of pages) { - // Add import - const results = analyzePage(path, content); - if (results.length > 0) { - const c = results[0]; - if (staticImports) { - const filePath = path.replace("./src/", "./"); - const jsPath = filePath.replace(".ts", ".js"); - c.alias = `route${i}`; - sb.writeln(`import * as ${c.alias} from "${jsPath}";`); - // if (c.hasLoader) { - // sb.writeln(`import {loader as ${c.alias}Loader} from "${jsPath}";`); - // } - } - components.push(c); - } - i++; - } - sb.writeln(); - generateApp(sb, components, { staticImports, cacheAll, showLoading }); - const output = sb.toString(); - fs.writeFileSync(outputFile, output); -} diff --git a/lit-file-based-routing/lit-file-router/src/string-builder.ts b/lit-file-based-routing/lit-file-router/src/string-builder.ts deleted file mode 100644 index f67f7c9..0000000 --- a/lit-file-based-routing/lit-file-router/src/string-builder.ts +++ /dev/null @@ -1,20 +0,0 @@ -export class StringBuilder { - private _lines: string[] = []; - - write(line: string = ""): void { - this._lines.push(line); - } - - writeln(line: string = ""): void { - this._lines.push(line); - this._lines.push("\n"); - } - - writeAll(lines: string[]): void { - this._lines.push(lines.join("\n")); - } - - toString(): string { - return this._lines.join(""); - } -} diff --git a/lit-file-based-routing/lit-file-router/tsconfig.json b/lit-file-based-routing/lit-file-router/tsconfig.json deleted file mode 100644 index d99140e..0000000 --- a/lit-file-based-routing/lit-file-router/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": false, - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/lit-file-based-routing/src/favicon.svg b/lit-file-based-routing/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-file-based-routing/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-file-based-routing/src/vite-env.d.ts b/lit-file-based-routing/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-file-based-routing/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-file-based-routing/tsconfig.json b/lit-file-based-routing/tsconfig.json deleted file mode 100644 index 2aac243..0000000 --- a/lit-file-based-routing/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": [ - "es2017", - "dom", - "dom.iterable" - ], - "declaration": true, - // "emitDeclarationOnly": true, - "esModuleInterop": true, - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [] -} \ No newline at end of file diff --git a/lit-force-graph/.gitignore b/lit-force-graph/.gitignore deleted file mode 100644 index a547bf3..0000000 --- a/lit-force-graph/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/lit-force-graph/README.md b/lit-force-graph/README.md deleted file mode 100644 index 774b6a3..0000000 --- a/lit-force-graph/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Lit Force Graph - -[![Demo](https://github.com/rodydavis/lit-force-graph/actions/workflows/ci.yml/badge.svg)](https://github.com/rodydavis/lit-force-graph/actions/workflows/ci.yml) - -[Lit](https://lit.dev) Example of how to take a json graph file and render it in 2D or 3D. - -You can try the demo [here](https://rodydavis.github.io/lit-force-graph/)! - -Here is the related [blog post](https://rodydavis.com/posts/lit-force-graph/). - -## Screenshots - -![](/screenshots/2d-light.png) -![](/screenshots/2d-dark.png) -![](/screenshots/3d-light.png) -![](/screenshots/3d-dark.png) diff --git a/lit-force-graph/index.html b/lit-force-graph/index.html deleted file mode 100644 index f04d3bf..0000000 --- a/lit-force-graph/index.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - Lit Force Graph - - - - - - - - - diff --git a/lit-force-graph/public/style.css b/lit-force-graph/public/style.css deleted file mode 100644 index 911c507..0000000 --- a/lit-force-graph/public/style.css +++ /dev/null @@ -1,31 +0,0 @@ -body { - margin: 0; - padding: 0; - overflow: hidden; - font-size: 12px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - position: relative; - width: 100%; - height: 100%; -} - -lit-force-graph { - width: 100%; - height: 100vh; -} - -:root { - --graph-background-color: #eee; - --graph-foreground-color: #000; - --graph-line-color: rgb(90, 90, 90); - --graph-node-color: rgb(218, 14, 14); -} - -@media (prefers-color-scheme: dark) { - :root { - --graph-background-color: #000; - --graph-foreground-color: #fafafa; - --graph-line-color: rgb(214, 214, 214); - --graph-node-color: rgb(228, 8, 8); - } -} diff --git a/lit-force-graph/screenshots/2d-dark.png b/lit-force-graph/screenshots/2d-dark.png deleted file mode 100644 index 2f1a0d1..0000000 Binary files a/lit-force-graph/screenshots/2d-dark.png and /dev/null differ diff --git a/lit-force-graph/screenshots/2d-light.png b/lit-force-graph/screenshots/2d-light.png deleted file mode 100644 index 8cd08c9..0000000 Binary files a/lit-force-graph/screenshots/2d-light.png and /dev/null differ diff --git a/lit-force-graph/screenshots/3d-dark.png b/lit-force-graph/screenshots/3d-dark.png deleted file mode 100644 index 849e527..0000000 Binary files a/lit-force-graph/screenshots/3d-dark.png and /dev/null differ diff --git a/lit-force-graph/screenshots/3d-light.png b/lit-force-graph/screenshots/3d-light.png deleted file mode 100644 index 613cfce..0000000 Binary files a/lit-force-graph/screenshots/3d-light.png and /dev/null differ diff --git a/lit-force-graph/src/favicon.svg b/lit-force-graph/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-force-graph/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-force-graph/src/modes/mode-ar.ts b/lit-force-graph/src/modes/mode-ar.ts deleted file mode 100644 index fc0ece0..0000000 --- a/lit-force-graph/src/modes/mode-ar.ts +++ /dev/null @@ -1,16 +0,0 @@ -import "aframe"; -import "@ar-js-org/ar.js"; -import ForceGraph from "3d-force-graph-ar"; -import { RenderContext } from "../classes/context.js"; - -export function renderAR(context: RenderContext) { - const graph = ForceGraph(); - const style = getComputedStyle(context.element); - // const lineColor = style.getPropertyValue("--graph-line-color").trim(); - // const bgColor = style.getPropertyValue("--graph-background-color").trim(); - graph(context.element) - .graphData(context.data) - .width(Number(style.width.slice(0, -2))) - .height(Number(style.height.slice(0, -2))) - .cooldownTicks(100); -} diff --git a/lit-force-graph/src/modes/mode-vr.ts b/lit-force-graph/src/modes/mode-vr.ts deleted file mode 100644 index 5274a2b..0000000 --- a/lit-force-graph/src/modes/mode-vr.ts +++ /dev/null @@ -1,15 +0,0 @@ -import ForceGraph from "3d-force-graph-vr"; -import { RenderContext } from "../classes/context.js"; - -export function renderVR(context: RenderContext) { - const graph = ForceGraph(); - const style = getComputedStyle(context.element); - // const lineColor = style.getPropertyValue("--graph-line-color").trim(); - // const bgColor = style.getPropertyValue("--graph-background-color").trim(); - graph(context.element) - .graphData(context.data) - .width(Number(style.width.slice(0, -2))) - .height(Number(style.height.slice(0, -2))) - .showNavInfo(false) - .cooldownTicks(100); -} diff --git a/lit-force-graph/src/vite-env.d.ts b/lit-force-graph/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-force-graph/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-force-graph/tsconfig.json b/lit-force-graph/tsconfig.json deleted file mode 100644 index 03ecaf4..0000000 --- a/lit-force-graph/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false - }, - "include": ["src/**/*.ts"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/lit-force-graph/tsconfig.node.json b/lit-force-graph/tsconfig.node.json deleted file mode 100644 index e993792..0000000 --- a/lit-force-graph/tsconfig.node.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "esnext", - "moduleResolution": "node" - }, - "include": ["vite.config.ts"] -} diff --git a/lit-force-graph/types/classes/context.d.ts b/lit-force-graph/types/classes/context.d.ts deleted file mode 100644 index 00aa350..0000000 --- a/lit-force-graph/types/classes/context.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { GraphData, GraphNode } from "./graph"; -export interface RenderContext { - data: GraphData; - element: HTMLElement; - onHover: (node?: GraphNode) => void; -} -export type Renderer = (context: RenderContext) => void; diff --git a/lit-force-graph/types/classes/graph.d.ts b/lit-force-graph/types/classes/graph.d.ts deleted file mode 100644 index 204f297..0000000 --- a/lit-force-graph/types/classes/graph.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -export declare class Graph { - private ids; - private graph; - addNode(node: GraphNode): GraphNode; - addLink(link: GraphLink): GraphLink; - toJSON(): GraphData; -} -export interface GraphNode { - id: string; - name?: string; - group?: string; - value?: T; -} -export interface GraphLink { - source: string; - target: string; - name?: string; - value?: T; -} -export interface GraphData { - name?: string; - description?: string; - nodes: GraphNode[]; - links: GraphLink[]; -} diff --git a/lit-force-graph/types/lit-force-graph.d.ts b/lit-force-graph/types/lit-force-graph.d.ts deleted file mode 100644 index ab178f3..0000000 --- a/lit-force-graph/types/lit-force-graph.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { LitElement } from "lit"; -import { Renderer } from "./classes/context"; -import { GraphData, GraphNode } from "./classes/graph"; -export declare const tagName = "lit-force-graph"; -export declare class LitForceGraph extends LitElement { - static styles: import("lit").CSSResult; - graph: HTMLElement; - src: string; - mode: string; - data?: GraphData; - hovered?: GraphNode; - renderers: Map; - render(): import("lit").TemplateResult<1>; - firstUpdated(): Promise; - /** - * Set the graph data and update the renderer - * - * @param data Graph JSON - */ - setData(data: GraphData): void; - private refresh; - private onChangeMode; - private onDrop; - attributeChangedCallback(name: string, _old: string | null, value: string | null): void; -} -declare global { - interface HTMLElementTagNameMap { - "lit-force-graph": LitForceGraph; - } -} diff --git a/lit-force-graph/types/modes/mode-2d.d.ts b/lit-force-graph/types/modes/mode-2d.d.ts deleted file mode 100644 index ed80f27..0000000 --- a/lit-force-graph/types/modes/mode-2d.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { RenderContext } from "../classes/context"; -export declare function render(context: RenderContext): void; diff --git a/lit-force-graph/types/modes/mode-3d.d.ts b/lit-force-graph/types/modes/mode-3d.d.ts deleted file mode 100644 index e2d05b2..0000000 --- a/lit-force-graph/types/modes/mode-3d.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { RenderContext } from "../classes/context.js"; -export declare function render(context: RenderContext): void; diff --git a/lit-force-graph/types/modes/mode-ar.d.ts b/lit-force-graph/types/modes/mode-ar.d.ts deleted file mode 100644 index d118f29..0000000 --- a/lit-force-graph/types/modes/mode-ar.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import "aframe"; -import "@ar-js-org/ar.js"; -import { RenderContext } from "../classes/context.js"; -export declare function renderAR(context: RenderContext): void; diff --git a/lit-force-graph/types/modes/mode-vr.d.ts b/lit-force-graph/types/modes/mode-vr.d.ts deleted file mode 100644 index 6e2a47a..0000000 --- a/lit-force-graph/types/modes/mode-vr.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { RenderContext } from "../classes/context.js"; -export declare function renderVR(context: RenderContext): void; diff --git a/lit-html-editor/.gitignore b/lit-html-editor/.gitignore deleted file mode 100644 index 6afafb3..0000000 --- a/lit-html-editor/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local -test.html \ No newline at end of file diff --git a/lit-html-editor/.vscode/settings.json b/lit-html-editor/.vscode/settings.json deleted file mode 100644 index 88a6999..0000000 --- a/lit-html-editor/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "cSpell.words": [ - "contenteditable" - ] -} \ No newline at end of file diff --git a/lit-html-editor/README.md b/lit-html-editor/README.md deleted file mode 100644 index e7bb4e9..0000000 --- a/lit-html-editor/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Lit Html Editor - -Rich text editor built with [Lit](https://lit.dev) based on [this](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content#example_a_simple_but_complete_rich_text_editor) example. - -You can try the demo [here](https://rodydavis.github.io/lit-html-editor/)! - -This used the contenteditable property that browsers support for full document editing and text formatting. - -![](/screenshot.png) - -There is also an example on the Lit playground [here](https://lit.dev/playground/#project=W3sibmFtZSI6InJpY2gtdGV4dC1lZGl0b3IudHMiLCJjb250ZW50IjoiaW1wb3J0IHsgTGl0RWxlbWVudCwgaHRtbCwgY3VzdG9tRWxlbWVudCwgY3NzLCBzdGF0ZSB9IGZyb20gXCJsaXQtZWxlbWVudFwiO1xuXG5pbXBvcnQgXCJAbWF0ZXJpYWwvbXdjLWljb24tYnV0dG9uXCI7XG5cbkBjdXN0b21FbGVtZW50KFwicmljaC10ZXh0LWVkaXRvclwiKVxuZXhwb3J0IGNsYXNzIFJpY2hUZXh0RWRpdG9yIGV4dGVuZHMgTGl0RWxlbWVudCB7XG4gIEBzdGF0ZSgpIGNvbnRlbnQ6IHN0cmluZyA9IFwiXCI7XG4gIEBzdGF0ZSgpIHJvb3Q6IEVsZW1lbnQgfCBudWxsID0gbnVsbDtcblxuICBzdGF0aWMgc3R5bGVzID0gY3NzYFxuICAgIDpob3N0IHtcbiAgICAgIC0tZWRpdG9yLXdpZHRoOiA2MDBweDtcbiAgICAgIC0tZWRpdG9yLWhlaWdodDogNjAwcHg7XG4gICAgICAtLWVkaXRvci1iYWNrZ3JvdW5kOiAjZjFmMWYxO1xuICAgICAgLS1lZGl0b3ItdG9vbGJhci1oZWlnaHQ6IDMzcHg7XG4gICAgICAtLWVkaXRvci10b29sYmFyLWJhY2tncm91bmQ6IGJsYWNrO1xuICAgICAgLS1lZGl0b3ItdG9vbGJhci1vbi1iYWNrZ3JvdW5kOiB3aGl0ZTtcbiAgICAgIC0tZWRpdG9yLXRvb2xiYXItb24tYWN0aXZlLWJhY2tncm91bmQ6ICNhNGE0YTQ7XG4gICAgfVxuICAgIG1haW4ge1xuICAgICAgd2lkdGg6IHZhcigtLWVkaXRvci13aWR0aCk7XG4gICAgICBoZWlnaHQ6IHZhcigtLWVkaXRvci1oZWlnaHQpO1xuICAgICAgZGlzcGxheTogZ3JpZDtcbiAgICAgIGdyaWQtdGVtcGxhdGUtYXJlYXM6XG4gICAgICAgIFwidG9vbGJhciB0b29sYmFyXCJcbiAgICAgICAgXCJlZGl0b3IgZWRpdG9yXCI7XG4gICAgICBncmlkLXRlbXBsYXRlLXJvd3M6IHZhcigtLWVkaXRvci10b29sYmFyLWhlaWdodCkgYXV0bztcbiAgICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogYXV0byBhdXRvO1xuICAgIH1cbiAgICAjZWRpdG9yLWFjdGlvbnMge1xuICAgICAgZ3JpZC1hcmVhOiB0b29sYmFyO1xuICAgICAgd2lkdGg6IHZhcigtLWVkaXRvci13aWR0aCk7XG4gICAgICBoZWlnaHQ6IHZhcigtLWVkaXRvci10b29sYmFyLWhlaWdodCk7XG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1lZGl0b3ItdG9vbGJhci1iYWNrZ3JvdW5kKTtcbiAgICAgIGNvbG9yOiB2YXIoLS1lZGl0b3ItdG9vbGJhci1vbi1iYWNrZ3JvdW5kKTtcbiAgICAgIG92ZXJzY3JvbGwtYmVoYXZpb3I6IGNvbnRhaW47XG4gICAgICBvdmVyZmxvdy15OiBhdXRvO1xuICAgICAgLW1zLW92ZXJmbG93LXN0eWxlOiBub25lO1xuICAgICAgc2Nyb2xsYmFyLXdpZHRoOiBub25lO1xuICAgIH1cbiAgICAjZWRpdG9yLWFjdGlvbnM6Oi13ZWJraXQtc2Nyb2xsYmFyIHtcbiAgICAgIGRpc3BsYXk6IG5vbmU7XG4gICAgfVxuICAgICNlZGl0b3Ige1xuICAgICAgd2lkdGg6IHZhcigtLWVkaXRvci13aWR0aCk7XG4gICAgICBncmlkLWFyZWE6IGVkaXRvcjtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWVkaXRvci1iYWNrZ3JvdW5kKTtcbiAgICB9XG4gICAgI3Rvb2xiYXIge1xuICAgICAgd2lkdGg6IDEwODBweDtcbiAgICAgIGhlaWdodDogdmFyKC0tZWRpdG9yLXRvb2xiYXItaGVpZ2h0KTtcbiAgICB9XG4gICAgW2NvbnRlbnRlZGl0YWJsZV0ge1xuICAgICAgb3V0bGluZTogMHB4IHNvbGlkIHRyYW5zcGFyZW50O1xuICAgIH1cbiAgICAjdG9vbGJhciA-IG13Yy1pY29uLWJ1dHRvbiB7XG4gICAgICBjb2xvcjogdmFyKC0tZWRpdG9yLXRvb2xiYXItb24tYmFja2dyb3VuZCk7XG4gICAgICAtLW1kYy1pY29uLXNpemU6IDIwcHg7XG4gICAgICAtLW1kYy1pY29uLWJ1dHRvbi1zaXplOiAzMHB4O1xuICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgIH1cbiAgICAjdG9vbGJhciA-IC5hY3RpdmUge1xuICAgICAgY29sb3I6IHZhcigtLWVkaXRvci10b29sYmFyLW9uLWFjdGl2ZS1iYWNrZ3JvdW5kKTtcbiAgICB9XG4gICAgc2VsZWN0IHtcbiAgICAgIG1hcmdpbi10b3A6IDVweDtcbiAgICAgIGhlaWdodDogY2FsYyh2YXIoLS1lZGl0b3ItdG9vbGJhci1oZWlnaHQpIC0gMTBweCk7XG4gICAgfVxuICAgIGlucHV0W3R5cGU9XCJjb2xvclwiXSB7XG4gICAgICBoZWlnaHQ6IGNhbGModmFyKC0tZWRpdG9yLXRvb2xiYXItaGVpZ2h0KSAtIDE1cHgpO1xuICAgICAgLXdlYmtpdC1hcHBlYXJhbmNlOiBub25lO1xuICAgICAgYm9yZGVyOiBub25lO1xuICAgICAgd2lkdGg6IDIycHg7XG4gICAgfVxuICAgIGlucHV0W3R5cGU9XCJjb2xvclwiXTo6LXdlYmtpdC1jb2xvci1zd2F0Y2gtd3JhcHBlciB7XG4gICAgICBwYWRkaW5nOiAwO1xuICAgIH1cbiAgICBpbnB1dFt0eXBlPVwiY29sb3JcIl06Oi13ZWJraXQtY29sb3Itc3dhdGNoIHtcbiAgICAgIGJvcmRlcjogbm9uZTtcbiAgICB9XG4gIGA7XG5cbiAgcmVuZGVyKCkge1xuICAgIHJldHVybiBodG1sYDxtYWluPlxuICAgICAgPGlucHV0IGlkPVwiYmdcIiB0eXBlPVwiY29sb3JcIiBzdHlsZT0nZGlzcGxheTpub25lJyAvPlxuICAgICAgPGlucHV0IGlkPVwiZmdcIiB0eXBlPVwiY29sb3JcIiBzdHlsZT0nZGlzcGxheTpub25lJyAvPlxuICAgICAgPGRpdiBpZD1cImVkaXRvci1hY3Rpb25zXCI-XG4gICAgICAgIDxkaXYgaWQ9XCJ0b29sYmFyXCI-XG4gICAgICAgICAgJHt0b29sYmFyKHRoaXMuc2hhZG93Um9vdCEsIHRoaXMuZ2V0U2VsZWN0aW9uKCksIChjb21tYW5kLCB2YWwpID0-IHtcbiAgICAgICAgICAgIGRvY3VtZW50LmV4ZWNDb21tYW5kKGNvbW1hbmQsIGZhbHNlLCB2YWwpO1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJjb21tYW5kXCIsIGNvbW1hbmQsIHZhbCk7XG4gICAgICAgICAgfSl9XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY-XG4gICAgICA8ZGl2IGlkPVwiZWRpdG9yXCI-JHt0aGlzLnJvb3R9PC9kaXY-XG4gICAgPC9tYWluPiBgO1xuICB9XG5cbiAgYXN5bmMgZmlyc3RVcGRhdGVkKCkge1xuICAgIGNvbnN0IGVsZW0gPSB0aGlzLnBhcmVudEVsZW1lbnQhLnF1ZXJ5U2VsZWN0b3IoXCJyaWNoLXRleHQtZWRpdG9yIHRlbXBsYXRlXCIpO1xuICAgIHRoaXMuY29udGVudCA9IGVsZW0_LmlubmVySFRNTCA_PyBcIlwiO1xuICAgIHRoaXMucmVzZXQoKTtcbiAgfVxuXG4gIHJlc2V0KCkge1xuICAgIGNvbnN0IHBhcnNlciA9IG5ldyBET01QYXJzZXIoKTtcbiAgICBjb25zdCBkb2MgPSBwYXJzZXIucGFyc2VGcm9tU3RyaW5nKHRoaXMuY29udGVudCwgXCJ0ZXh0L2h0bWxcIik7XG4gICAgZG9jdW1lbnQuZXhlY0NvbW1hbmQoXCJkZWZhdWx0UGFyYWdyYXBoU2VwYXJhdG9yXCIsIGZhbHNlLCBcImJyXCIpO1xuICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJzZWxlY3Rpb25jaGFuZ2VcIiwgKCkgPT4ge1xuICAgICAgdGhpcy5yZXF1ZXN0VXBkYXRlKCk7XG4gICAgfSk7XG4gICAgY29uc3Qgcm9vdCA9IGRvYy5xdWVyeVNlbGVjdG9yKFwiYm9keVwiKTtcbiAgICByb290IS5zZXRBdHRyaWJ1dGUoXCJjb250ZW50ZWRpdGFibGVcIiwgXCJ0cnVlXCIpO1xuICAgIHRoaXMucm9vdCA9IHJvb3Q7XG4gIH1cblxuICBnZXRTZWxlY3Rpb24oKTogU2VsZWN0aW9uIHwgbnVsbCB7XG4gICAgaWYgKHRoaXMuc2hhZG93Um9vdD8uZ2V0U2VsZWN0aW9uKSByZXR1cm4gdGhpcy5zaGFkb3dSb290Py5nZXRTZWxlY3Rpb24oKTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG5mdW5jdGlvbiB0b29sYmFyKFxuICBzaGFkb3dSb290OiBTaGFkb3dSb290LFxuICBzZWxlY3Rpb246IFNlbGVjdGlvbiB8IG51bGwsXG4gIGNvbW1hbmQ6IChjOiBzdHJpbmcsIHZhbDogc3RyaW5nIHwgdW5kZWZpbmVkKSA9PiB2b2lkXG4pIHtcbiAgY29uc3QgdGFnczogc3RyaW5nW10gPSBbXTtcbiAgaWYgKHNlbGVjdGlvbj8udHlwZSA9PT0gXCJSYW5nZVwiKSB7XG4gICAgLy8gQHRzLWlnbm9yZVxuICAgIGxldCBwYXJlbnROb2RlID0gc2VsZWN0aW9uPy5iYXNlTm9kZTtcbiAgICBpZiAocGFyZW50Tm9kZSkge1xuICAgICAgY29uc3QgY2hlY2tOb2RlID0gKCkgPT4ge1xuICAgICAgICBjb25zdCBwYXJlbnRUYWdOYW1lID0gcGFyZW50Tm9kZT8udGFnTmFtZT8udG9Mb3dlckNhc2UoKT8udHJpbSgpO1xuICAgICAgICBpZiAocGFyZW50VGFnTmFtZSkgdGFncy5wdXNoKHBhcmVudFRhZ05hbWUpO1xuICAgICAgfTtcbiAgICAgIHdoaWxlIChwYXJlbnROb2RlICE9IG51bGwpIHtcbiAgICAgICAgY2hlY2tOb2RlKCk7XG4gICAgICAgIHBhcmVudE5vZGUgPSBwYXJlbnROb2RlPy5wYXJlbnROb2RlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGNvbW1hbmRzOiB7XG4gICAgaWNvbjogc3RyaW5nO1xuICAgIGNvbW1hbmQ6IHN0cmluZyB8ICgoKSA9PiB2b2lkKTtcbiAgICBhY3RpdmU_OiBib29sZWFuO1xuICAgIHR5cGU_OiBzdHJpbmc7XG4gICAgdmFsdWVzPzogeyB2YWx1ZTogc3RyaW5nOyBuYW1lOiBzdHJpbmc7IGZvbnQ_OiBib29sZWFuIH1bXTtcbiAgICBjb21tYW5kX3ZhbHVlPzogc3RyaW5nO1xuICB9W10gPSBbXG4gICAge1xuICAgICAgaWNvbjogXCJmb3JtYXRfY2xlYXJcIixcbiAgICAgIGNvbW1hbmQ6IFwicmVtb3ZlRm9ybWF0XCIsXG4gICAgfSxcblxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X2JvbGRcIixcbiAgICAgIGNvbW1hbmQ6IFwiYm9sZFwiLFxuICAgICAgYWN0aXZlOiB0YWdzLmluY2x1ZGVzKFwiYlwiKSxcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X2l0YWxpY1wiLFxuICAgICAgY29tbWFuZDogXCJpdGFsaWNcIixcbiAgICAgIGFjdGl2ZTogdGFncy5pbmNsdWRlcyhcImlcIiksXG4gICAgfSxcbiAgICB7XG4gICAgICBpY29uOiBcImZvcm1hdF91bmRlcmxpbmVkXCIsXG4gICAgICBjb21tYW5kOiBcInVuZGVybGluZVwiLFxuICAgICAgYWN0aXZlOiB0YWdzLmluY2x1ZGVzKFwidVwiKSxcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X2FsaWduX2xlZnRcIixcbiAgICAgIGNvbW1hbmQ6IFwianVzdGlmeWxlZnRcIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X2FsaWduX2NlbnRlclwiLFxuICAgICAgY29tbWFuZDogXCJqdXN0aWZ5Y2VudGVyXCIsXG4gICAgfSxcbiAgICB7XG4gICAgICBpY29uOiBcImZvcm1hdF9hbGlnbl9yaWdodFwiLFxuICAgICAgY29tbWFuZDogXCJqdXN0aWZ5cmlnaHRcIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X2xpc3RfbnVtYmVyZWRcIixcbiAgICAgIGNvbW1hbmQ6IFwiaW5zZXJ0b3JkZXJlZGxpc3RcIixcbiAgICAgIGFjdGl2ZTogdGFncy5pbmNsdWRlcyhcIm9sXCIpLFxuICAgIH0sXG4gICAge1xuICAgICAgaWNvbjogXCJmb3JtYXRfbGlzdF9idWxsZXRlZFwiLFxuICAgICAgY29tbWFuZDogXCJpbnNlcnR1bm9yZGVyZWRsaXN0XCIsXG4gICAgICBhY3RpdmU6IHRhZ3MuaW5jbHVkZXMoXCJ1bFwiKSxcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X3F1b3RlXCIsXG4gICAgICBjb21tYW5kOiBcImZvcm1hdGJsb2NrXCIsXG4gICAgICBjb21tYW5kX3ZhbHVlOiBcImJsb2NrcXVvdGVcIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X2luZGVudF9kZWNyZWFzZVwiLFxuICAgICAgY29tbWFuZDogXCJvdXRkZW50XCIsXG4gICAgfSxcbiAgICB7XG4gICAgICBpY29uOiBcImZvcm1hdF9pbmRlbnRfaW5jcmVhc2VcIixcbiAgICAgIGNvbW1hbmQ6IFwiaW5kZW50XCIsXG4gICAgfSxcbiAgICB0YWdzLmluY2x1ZGVzKFwiYVwiKVxuICAgICAgPyB7IGljb246IFwibGlua19vZmZcIiwgY29tbWFuZDogXCJ1bmxpbmtcIiB9XG4gICAgICA6IHtcbiAgICAgICAgICBpY29uOiBcImFkZF9saW5rXCIsXG4gICAgICAgICAgY29tbWFuZDogKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgbmV3TGluayA9IHByb21wdChcIldyaXRlIHRoZSBVUkwgaGVyZVwiLCBcImh0dHA6Ly9cIik7XG4gICAgICAgICAgICBpZiAobmV3TGluayAmJiBuZXdMaW5rICE9IFwiXCIgJiYgbmV3TGluayAhPSBcImh0dHA6Ly9cIikge1xuICAgICAgICAgICAgICBjb21tYW5kKFwiY3JlYXRlbGlua1wiLCBuZXdMaW5rKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X2NvbG9yX3RleHRcIixcbiAgICAgIGNvbW1hbmQ6ICgpID0-IHtcbiAgICAgICAgY29uc3QgaW5wdXQgPSBzaGFkb3dSb290LnF1ZXJ5U2VsZWN0b3IoXCIjZmdcIikhIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG4gICAgICAgIGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoXCJpbnB1dFwiLCAoZTogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3QgdmFsID0gZS50YXJnZXQudmFsdWU7XG4gICAgICAgICAgY29tbWFuZChcImZvcmVjb2xvclwiLCB2YWwpO1xuICAgICAgICB9KTtcbiAgICAgICAgaW5wdXQuY2xpY2soKTtcbiAgICAgIH0sXG4gICAgICB0eXBlOiBcImNvbG9yXCIsXG4gICAgfSxcbiAgICB7XG4gICAgICBpY29uOiBcImJvcmRlcl9jb2xvclwiLFxuICAgICAgY29tbWFuZDogKCkgPT4ge1xuICAgICAgICBjb25zdCBpbnB1dCA9IHNoYWRvd1Jvb3QucXVlcnlTZWxlY3RvcihcIiNiZ1wiKSEgYXMgSFRNTElucHV0RWxlbWVudDtcbiAgICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImlucHV0XCIsIChlOiBhbnkpID0-IHtcbiAgICAgICAgICBjb25zdCB2YWwgPSBlLnRhcmdldC52YWx1ZTtcbiAgICAgICAgICBjb21tYW5kKFwiYmFja2NvbG9yXCIsIHZhbCk7XG4gICAgICAgIH0pO1xuICAgICAgICBpbnB1dC5jbGljaygpO1xuICAgICAgfSxcbiAgICAgIHR5cGU6IFwiY29sb3JcIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwidGl0bGVcIixcbiAgICAgIGNvbW1hbmQ6IFwiZm9ybWF0YmxvY2tcIixcbiAgICAgIHZhbHVlczogW1xuICAgICAgICB7IG5hbWU6IFwiTm9ybWFsIFRleHRcIiwgdmFsdWU6IFwiLS1cIiB9LFxuICAgICAgICB7IG5hbWU6IFwiSGVhZGluZyAxXCIsIHZhbHVlOiBcImgxXCIgfSxcbiAgICAgICAgeyBuYW1lOiBcIkhlYWRpbmcgMlwiLCB2YWx1ZTogXCJoMlwiIH0sXG4gICAgICAgIHsgbmFtZTogXCJIZWFkaW5nIDNcIiwgdmFsdWU6IFwiaDNcIiB9LFxuICAgICAgICB7IG5hbWU6IFwiSGVhZGluZyA0XCIsIHZhbHVlOiBcImg0XCIgfSxcbiAgICAgICAgeyBuYW1lOiBcIkhlYWRpbmcgNVwiLCB2YWx1ZTogXCJoNVwiIH0sXG4gICAgICAgIHsgbmFtZTogXCJIZWFkaW5nIDZcIiwgdmFsdWU6IFwiaDZcIiB9LFxuICAgICAgICB7IG5hbWU6IFwiUGFyYWdyYXBoXCIsIHZhbHVlOiBcInBcIiB9LFxuICAgICAgICB7IG5hbWU6IFwiUHJlLUZvcm1hdHRlZFwiLCB2YWx1ZTogXCJwcmVcIiB9LFxuICAgICAgXSxcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwidGV4dF9mb3JtYXRcIixcbiAgICAgIGNvbW1hbmQ6IFwiZm9udG5hbWVcIixcbiAgICAgIHZhbHVlczogW1xuICAgICAgICB7IG5hbWU6IFwiRm9udCBOYW1lXCIsIHZhbHVlOiBcIi0tXCIgfSxcbiAgICAgICAgLi4uWy4uLmNoZWNrRm9udHMoKV0ubWFwKChmKSA9PiAoe1xuICAgICAgICAgIG5hbWU6IGYsXG4gICAgICAgICAgdmFsdWU6IGYsXG4gICAgICAgICAgZm9udDogdHJ1ZSxcbiAgICAgICAgfSkpLFxuICAgICAgXSxcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwiZm9ybWF0X3NpemVcIixcbiAgICAgIGNvbW1hbmQ6IFwiZm9udHNpemVcIixcbiAgICAgIHZhbHVlczogW1xuICAgICAgICB7IG5hbWU6IFwiRm9udCBTaXplXCIsIHZhbHVlOiBcIi0tXCIgfSxcbiAgICAgICAgeyBuYW1lOiBcIlZlcnkgU21hbGxcIiwgdmFsdWU6IFwiMVwiIH0sXG4gICAgICAgIHsgbmFtZTogXCJTbWFsbFwiLCB2YWx1ZTogXCIyXCIgfSxcbiAgICAgICAgeyBuYW1lOiBcIk5vcm1hbFwiLCB2YWx1ZTogXCIzXCIgfSxcbiAgICAgICAgeyBuYW1lOiBcIk1lZGl1bSBMYXJnZVwiLCB2YWx1ZTogXCI0XCIgfSxcbiAgICAgICAgeyBuYW1lOiBcIkxhcmdlXCIsIHZhbHVlOiBcIjVcIiB9LFxuICAgICAgICB7IG5hbWU6IFwiVmVyeSBMYXJnZVwiLCB2YWx1ZTogXCI2XCIgfSxcbiAgICAgICAgeyBuYW1lOiBcIk1heGltdW1cIiwgdmFsdWU6IFwiN1wiIH0sXG4gICAgICBdLFxuICAgIH0sXG4gICAge1xuICAgICAgaWNvbjogXCJ1bmRvXCIsXG4gICAgICBjb21tYW5kOiBcInVuZG9cIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGljb246IFwicmVkb1wiLFxuICAgICAgY29tbWFuZDogXCJyZWRvXCIsXG4gICAgfSxcbiAgICB7XG4gICAgICBpY29uOiBcImNvbnRlbnRfY3V0XCIsXG4gICAgICBjb21tYW5kOiBcImN1dFwiLFxuICAgIH0sXG4gICAge1xuICAgICAgaWNvbjogXCJjb250ZW50X2NvcHlcIixcbiAgICAgIGNvbW1hbmQ6IFwiY29weVwiLFxuICAgIH0sXG4gICAge1xuICAgICAgaWNvbjogXCJjb250ZW50X3Bhc3RlXCIsXG4gICAgICBjb21tYW5kOiBcInBhc3RlXCIsXG4gICAgfSxcbiAgXTtcblxuICByZXR1cm4gaHRtbGBcbiAgICAke2NvbW1hbmRzLm1hcCgobikgPT4ge1xuICAgICAgY29uc3QgZWxlbSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJtd2MtaWNvbi1idXR0b25cIik7XG4gICAgICBlbGVtLnNldEF0dHJpYnV0ZShcImljb25cIiwgbi5pY29uKTtcbiAgICAgIGVsZW0uY2xhc3NOYW1lID0gbi5hY3RpdmUgPyBcImFjdGl2ZVwiIDogXCJpbmFjdGl2ZVwiO1xuICAgICAgZWxlbS5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgKCkgPT4ge1xuICAgICAgICBpZiAobi52YWx1ZXMpIHtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygbi5jb21tYW5kID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgY29tbWFuZChuLmNvbW1hbmQsIG4uY29tbWFuZF92YWx1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbi5jb21tYW5kKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIGh0bWxgXG4gICAgICAgICR7bi52YWx1ZXNcbiAgICAgICAgICA_IGh0bWxgIDxzZWxlY3RcbiAgICAgICAgICAgICAgaWQ9XCIke24uaWNvbn1cIlxuICAgICAgICAgICAgICBAY2hhbmdlPSR7KGU6IGFueSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhbCA9IGUudGFyZ2V0LnZhbHVlO1xuICAgICAgICAgICAgICAgIGlmICh2YWwgPT09IFwiLS1cIikge1xuICAgICAgICAgICAgICAgICAgY29tbWFuZChcInJlbW92ZUZvcm1hdFwiLCB1bmRlZmluZWQpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIG4uY29tbWFuZCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgY29tbWFuZChuLmNvbW1hbmQsIHZhbCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9fVxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAke24udmFsdWVzLm1hcChcbiAgICAgICAgICAgICAgICAodikgPT4gaHRtbGAgPG9wdGlvbiB2YWx1ZT0ke3YudmFsdWV9PiR7di5uYW1lfTwvb3B0aW9uPmBcbiAgICAgICAgICAgICAgKX1cbiAgICAgICAgICAgIDwvc2VsZWN0PmBcbiAgICAgICAgICA6IGh0bWxgICR7ZWxlbX1gfVxuICAgICAgYDtcbiAgICB9KX1cbiAgYDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNoZWNrRm9udHMoKTogc3RyaW5nW10ge1xuICBjb25zdCBmb250Q2hlY2sgPSBuZXcgU2V0KFxuICAgIFtcbiAgICAgIC8vIFdpbmRvd3MgMTBcbiAgICAgIFwiQXJpYWxcIixcbiAgICAgIFwiQXJpYWwgQmxhY2tcIixcbiAgICAgIFwiQmFobnNjaHJpZnRcIixcbiAgICAgIFwiQ2FsaWJyaVwiLFxuICAgICAgXCJDYW1icmlhXCIsXG4gICAgICBcIkNhbWJyaWEgTWF0aFwiLFxuICAgICAgXCJDYW5kYXJhXCIsXG4gICAgICBcIkNvbWljIFNhbnMgTVNcIixcbiAgICAgIFwiQ29uc29sYXNcIixcbiAgICAgIFwiQ29uc3RhbnRpYVwiLFxuICAgICAgXCJDb3JiZWxcIixcbiAgICAgIFwiQ291cmllciBOZXdcIixcbiAgICAgIFwiRWJyaW1hXCIsXG4gICAgICBcIkZyYW5rbGluIEdvdGhpYyBNZWRpdW1cIixcbiAgICAgIFwiR2FicmlvbGFcIixcbiAgICAgIFwiR2FkdWdpXCIsXG4gICAgICBcIkdlb3JnaWFcIixcbiAgICAgIFwiSG9sb0xlbnMgTURMMiBBc3NldHNcIixcbiAgICAgIFwiSW1wYWN0XCIsXG4gICAgICBcIkluayBGcmVlXCIsXG4gICAgICBcIkphdmFuZXNlIFRleHRcIixcbiAgICAgIFwiTGVlbGF3YWRlZSBVSVwiLFxuICAgICAgXCJMdWNpZGEgQ29uc29sZVwiLFxuICAgICAgXCJMdWNpZGEgU2FucyBVbmljb2RlXCIsXG4gICAgICBcIk1hbGd1biBHb3RoaWNcIixcbiAgICAgIFwiTWFybGV0dFwiLFxuICAgICAgXCJNaWNyb3NvZnQgSGltYWxheWFcIixcbiAgICAgIFwiTWljcm9zb2Z0IEpoZW5nSGVpXCIsXG4gICAgICBcIk1pY3Jvc29mdCBOZXcgVGFpIEx1ZVwiLFxuICAgICAgXCJNaWNyb3NvZnQgUGhhZ3NQYVwiLFxuICAgICAgXCJNaWNyb3NvZnQgU2FucyBTZXJpZlwiLFxuICAgICAgXCJNaWNyb3NvZnQgVGFpIExlXCIsXG4gICAgICBcIk1pY3Jvc29mdCBZYUhlaVwiLFxuICAgICAgXCJNaWNyb3NvZnQgWWkgQmFpdGlcIixcbiAgICAgIFwiTWluZ0xpVS1FeHRCXCIsXG4gICAgICBcIk1vbmdvbGlhbiBCYWl0aVwiLFxuICAgICAgXCJNUyBHb3RoaWNcIixcbiAgICAgIFwiTVYgQm9saVwiLFxuICAgICAgXCJNeWFubWFyIFRleHRcIixcbiAgICAgIFwiTmlybWFsYSBVSVwiLFxuICAgICAgXCJQYWxhdGlubyBMaW5vdHlwZVwiLFxuICAgICAgXCJTZWdvZSBNREwyIEFzc2V0c1wiLFxuICAgICAgXCJTZWdvZSBQcmludFwiLFxuICAgICAgXCJTZWdvZSBTY3JpcHRcIixcbiAgICAgIFwiU2Vnb2UgVUlcIixcbiAgICAgIFwiU2Vnb2UgVUkgSGlzdG9yaWNcIixcbiAgICAgIFwiU2Vnb2UgVUkgRW1vamlcIixcbiAgICAgIFwiU2Vnb2UgVUkgU3ltYm9sXCIsXG4gICAgICBcIlNpbVN1blwiLFxuICAgICAgXCJTaXRrYVwiLFxuICAgICAgXCJTeWxmYWVuXCIsXG4gICAgICBcIlN5bWJvbFwiLFxuICAgICAgXCJUYWhvbWFcIixcbiAgICAgIFwiVGltZXMgTmV3IFJvbWFuXCIsXG4gICAgICBcIlRyZWJ1Y2hldCBNU1wiLFxuICAgICAgXCJWZXJkYW5hXCIsXG4gICAgICBcIldlYmRpbmdzXCIsXG4gICAgICBcIldpbmdkaW5nc1wiLFxuICAgICAgXCJZdSBHb3RoaWNcIixcbiAgICAgIC8vIG1hY09TXG4gICAgICBcIkFtZXJpY2FuIFR5cGV3cml0ZXJcIixcbiAgICAgIFwiQW5kYWxlIE1vbm9cIixcbiAgICAgIFwiQXJpYWxcIixcbiAgICAgIFwiQXJpYWwgQmxhY2tcIixcbiAgICAgIFwiQXJpYWwgTmFycm93XCIsXG4gICAgICBcIkFyaWFsIFJvdW5kZWQgTVQgQm9sZFwiLFxuICAgICAgXCJBcmlhbCBVbmljb2RlIE1TXCIsXG4gICAgICBcIkF2ZW5pclwiLFxuICAgICAgXCJBdmVuaXIgTmV4dFwiLFxuICAgICAgXCJBdmVuaXIgTmV4dCBDb25kZW5zZWRcIixcbiAgICAgIFwiQmFza2VydmlsbGVcIixcbiAgICAgIFwiQmlnIENhc2xvblwiLFxuICAgICAgXCJCb2RvbmkgNzJcIixcbiAgICAgIFwiQm9kb25pIDcyIE9sZHN0eWxlXCIsXG4gICAgICBcIkJvZG9uaSA3MiBTbWFsbGNhcHNcIixcbiAgICAgIFwiQnJhZGxleSBIYW5kXCIsXG4gICAgICBcIkJydXNoIFNjcmlwdCBNVFwiLFxuICAgICAgXCJDaGFsa2JvYXJkXCIsXG4gICAgICBcIkNoYWxrYm9hcmQgU0VcIixcbiAgICAgIFwiQ2hhbGtkdXN0ZXJcIixcbiAgICAgIFwiQ2hhcnRlclwiLFxuICAgICAgXCJDb2NoaW5cIixcbiAgICAgIFwiQ29taWMgU2FucyBNU1wiLFxuICAgICAgXCJDb3BwZXJwbGF0ZVwiLFxuICAgICAgXCJDb3VyaWVyXCIsXG4gICAgICBcIkNvdXJpZXIgTmV3XCIsXG4gICAgICBcIkRpZG90XCIsXG4gICAgICBcIkRJTiBBbHRlcm5hdGVcIixcbiAgICAgIFwiRElOIENvbmRlbnNlZFwiLFxuICAgICAgXCJGdXR1cmFcIixcbiAgICAgIFwiR2VuZXZhXCIsXG4gICAgICBcIkdlb3JnaWFcIixcbiAgICAgIFwiR2lsbCBTYW5zXCIsXG4gICAgICBcIkhlbHZldGljYVwiLFxuICAgICAgXCJIZWx2ZXRpY2EgTmV1ZVwiLFxuICAgICAgXCJIZXJjdWxhbnVtXCIsXG4gICAgICBcIkhvZWZsZXIgVGV4dFwiLFxuICAgICAgXCJJbXBhY3RcIixcbiAgICAgIFwiTHVjaWRhIEdyYW5kZVwiLFxuICAgICAgXCJMdW1pbmFyaVwiLFxuICAgICAgXCJNYXJrZXIgRmVsdFwiLFxuICAgICAgXCJNZW5sb1wiLFxuICAgICAgXCJNaWNyb3NvZnQgU2FucyBTZXJpZlwiLFxuICAgICAgXCJNb25hY29cIixcbiAgICAgIFwiTm90ZXdvcnRoeVwiLFxuICAgICAgXCJPcHRpbWFcIixcbiAgICAgIFwiUGFsYXRpbm9cIixcbiAgICAgIFwiUGFweXJ1c1wiLFxuICAgICAgXCJQaG9zcGhhdGVcIixcbiAgICAgIFwiUm9ja3dlbGxcIixcbiAgICAgIFwiU2F2b3llIExFVFwiLFxuICAgICAgXCJTaWduUGFpbnRlclwiLFxuICAgICAgXCJTa2lhXCIsXG4gICAgICBcIlNuZWxsIFJvdW5kaGFuZFwiLFxuICAgICAgXCJUYWhvbWFcIixcbiAgICAgIFwiVGltZXNcIixcbiAgICAgIFwiVGltZXMgTmV3IFJvbWFuXCIsXG4gICAgICBcIlRyYXR0YXRlbGxvXCIsXG4gICAgICBcIlRyZWJ1Y2hldCBNU1wiLFxuICAgICAgXCJWZXJkYW5hXCIsXG4gICAgICBcIlphcGZpbm9cIixcbiAgICBdLnNvcnQoKVxuICApO1xuICBjb25zdCBmb250QXZhaWxhYmxlID0gbmV3IFNldDxzdHJpbmc-KCk7XG4gIC8vIEB0cy1pZ25vcmVcbiAgZm9yIChjb25zdCBmb250IG9mIGZvbnRDaGVjay52YWx1ZXMoKSkge1xuICAgIC8vIEB0cy1pZ25vcmVcbiAgICBpZiAoZG9jdW1lbnQuZm9udHMuY2hlY2soYDEycHggXCIke2ZvbnR9XCJgKSkge1xuICAgICAgZm9udEF2YWlsYWJsZS5hZGQoZm9udCk7XG4gICAgfVxuICB9XG4gIC8vIEB0cy1pZ25vcmVcbiAgcmV0dXJuIGZvbnRBdmFpbGFibGUudmFsdWVzKCk7XG59XG4ifSx7Im5hbWUiOiJpbmRleC5odG1sIiwiY29udGVudCI6IjwhRE9DVFlQRSBodG1sPlxuPGh0bWwgbGFuZz1cImVuXCI-XG4gIDxoZWFkPlxuICAgIDxtZXRhIGNoYXJzZXQ9XCJVVEYtOFwiIC8-XG4gICAgPGxpbmsgcmVsPVwiaWNvblwiIHR5cGU9XCJpbWFnZS9zdmcreG1sXCIgaHJlZj1cIi9zcmMvZmF2aWNvbi5zdmdcIiAvPlxuICAgIDxtZXRhIG5hbWU9XCJ2aWV3cG9ydFwiIGNvbnRlbnQ9XCJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MS4wXCIgLz5cbiAgICA8bGlua1xuICAgICAgaHJlZj1cImh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzP2ZhbWlseT1NYXRlcmlhbCtJY29ucyZkaXNwbGF5PWJsb2NrXCJcbiAgICAgIHJlbD1cInN0eWxlc2hlZXRcIlxuICAgIC8-XG4gICAgPHRpdGxlPkxpdCBIVE1MIEVkaXRvcjwvdGl0bGU-XG4gICAgPHNjcmlwdCB0eXBlPVwibW9kdWxlXCIgc3JjPVwiLi9yaWNoLXRleHQtZWRpdG9yLmpzXCI-PC9zY3JpcHQ-XG4gICAgPHN0eWxlPlxuICAgICAgYm9keSB7XG4gICAgICAgIHdpZHRoOiAxMDAlO1xuICAgICAgICBoZWlnaHQ6IDEwMHZoO1xuICAgICAgICBwYWRkaW5nOiAwO1xuICAgICAgICBtYXJnaW46IDA7XG4gICAgICB9XG4gICAgICByaWNoLXRleHQtZWRpdG9yIHtcbiAgICAgICAgLS1lZGl0b3Itd2lkdGg6IDEwMCU7XG4gICAgICAgIC0tZWRpdG9yLWhlaWdodDogMTAwdmg7XG4gICAgICB9XG4gICAgPC9zdHlsZT5cbiAgPC9oZWFkPlxuICA8Ym9keT5cbiAgICA8cmljaC10ZXh0LWVkaXRvcj5cbiAgICAgIDx0ZW1wbGF0ZT5cbiAgICAgICAgPGgxPkhlYWRsaW5lIDE8L2gxPlxuICAgICAgICA8cD5UaGlzIGlzIGEgcGFyYWdyYXBoLjwvcD5cbiAgICAgICAgPHA-XG4gICAgICAgICAgPHNwYW4gc3R5bGU9XCJiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAwLCAwKVwiXG4gICAgICAgICAgICA-PGZvbnQgY29sb3I9XCIjZmZmZmZmXCI-U3R5bGVkIFRleHQ8L2ZvbnQ-PC9zcGFuXG4gICAgICAgICAgPlxuICAgICAgICA8L3A-XG4gICAgICA8L3RlbXBsYXRlPlxuICAgIDwvcmljaC10ZXh0LWVkaXRvcj5cbiAgPC9ib2R5PlxuPC9odG1sPlxuIn1d). diff --git a/lit-html-editor/index.html b/lit-html-editor/index.html deleted file mode 100644 index f21a7cc..0000000 --- a/lit-html-editor/index.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - Lit HTML Editor - - - - - - - - - diff --git a/lit-html-editor/screenshot.png b/lit-html-editor/screenshot.png deleted file mode 100644 index c3ebe52..0000000 Binary files a/lit-html-editor/screenshot.png and /dev/null differ diff --git a/lit-html-editor/src/favicon.svg b/lit-html-editor/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-html-editor/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-html-editor/src/vite-env.d.ts b/lit-html-editor/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-html-editor/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-html-editor/tsconfig.json b/lit-html-editor/tsconfig.json deleted file mode 100644 index 2f58488..0000000 --- a/lit-html-editor/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": [ - "es2017", - "dom", - "dom.iterable" - ], - "declaration": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [] -} \ No newline at end of file diff --git a/lit-html-table/.gitattributes b/lit-html-table/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/lit-html-table/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/lit-html-table/.gitignore b/lit-html-table/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-html-table/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-html-table/README.md b/lit-html-table/README.md deleted file mode 100644 index 4b51d28..0000000 --- a/lit-html-table/README.md +++ /dev/null @@ -1,20 +0,0 @@ -## JSON to HTML Table - -[![Demo](https://github.com/rodydavis/lit-html-table/actions/workflows/ci.yml/badge.svg)](https://github.com/rodydavis/lit-html-table/actions/workflows/ci.yml) - -Online demo can be found [here](https://rodydavis.github.io/lit-html-table/). - -Blog post [here](https://rodydavis.com/posts/lit-html-table/). - -- Json to HTML Table -- JSON from url -- Inline JSON -- No Dependencies -- Editable table -- Lit - - - - - -There is also an example on the Lit playground [here](https://lit.dev/playground/#project=W3sibmFtZSI6ImxpdC1odG1sLXRhYmxlLnRzIiwiY29udGVudCI6ImltcG9ydCB7IGh0bWwsIGNzcywgTGl0RWxlbWVudCB9IGZyb20gXCJsaXRcIjtcbmltcG9ydCB7IGN1c3RvbUVsZW1lbnQsIHByb3BlcnR5IH0gZnJvbSBcImxpdC9kZWNvcmF0b3JzLmpzXCI7XG5cbnR5cGUgT2JqZWN0RGF0YSA9IHsgW2tleTogc3RyaW5nXTogYW55IH07XG5cbkBjdXN0b21FbGVtZW50KFwibGl0LWh0bWwtdGFibGVcIilcbmV4cG9ydCBjbGFzcyBMaXRIdG1sVGFibGUgZXh0ZW5kcyBMaXRFbGVtZW50IHtcbiAgQHByb3BlcnR5KCkgc3JjID0gXCJcIjtcblxuICBkYXRhPzogT2JqZWN0RGF0YVtdO1xuXG4gIHN0YXRpYyBzdHlsZXMgPSBjc3NgXG4gICAgdHIge1xuICAgICAgdGV4dC1hbGlnbjogdmFyKC0tdGFibGUtdHItdGV4dC1hbGlnbiwgbGVmdCk7XG4gICAgICB2ZXJ0aWNhbC1hbGlnbjogdmFyKC0tdGFibGUtdHItdmVydGljYWwtYWxpZ24sIHRvcCk7XG4gICAgICBwYWRkaW5nOiB2YXIoLS10YWJsZS10ci1wYWRkaW5nLCAxMHB4KTtcbiAgICB9XG4gIGA7XG5cbiAgcmVuZGVyKCkge1xuICAgIC8vIENoZWNrIGlmIGRhdGEgaXMgbG9hZGVkXG4gICAgaWYgKCF0aGlzLmRhdGEpIHtcbiAgICAgIHJldHVybiBodG1sYDxzbG90IG5hbWU9XCJsb2FkaW5nXCI-TG9hZGluZy4uLjwvc2xvdD5gO1xuICAgIH1cbiAgICAvLyBDaGVjayBpZiBpdGVtcyBhcmUgbm90IGVtcHR5XG4gICAgaWYgKHRoaXMuZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBodG1sYDxzbG90IG5hbWU9XCJlbXB0eVwiPk5vIEl0ZW1zIEZvdW5kITwvc2xvdD5gO1xuICAgIH1cbiAgICAvLyBDb252ZXJ0IEpTT04gdG8gSFRNTCBUYWJsZVxuICAgIHJldHVybiBodG1sYFxuICAgICAgPHRhYmxlPlxuICAgICAgICA8dGhlYWQ-XG4gICAgICAgICAgPHRyPlxuICAgICAgICAgICAgJHtPYmplY3Qua2V5cyh0aGlzLmRhdGFbMF0pLm1hcCgoa2V5KSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBrZXkucmVwbGFjZSgvXFxiKFthLXpdKS9nLCAoXywgdmFsKSA9PlxuICAgICAgICAgICAgICAgIHZhbC50b1VwcGVyQ2FzZSgpXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIHJldHVybiBodG1sYDx0aD5cbiAgICAgICAgICAgICAgICA8c2xvdCBuYW1lPVwiJHtrZXl9XCI-JHtuYW1lfTwvc2xvdD5cbiAgICAgICAgICAgICAgPC90aD5gO1xuICAgICAgICAgICAgfSl9XG4gICAgICAgICAgPC90cj5cbiAgICAgICAgPC90aGVhZD5cbiAgICAgICAgPHRib2R5PlxuICAgICAgICAgICR7dGhpcy5kYXRhLm1hcCgoaXRlbSkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIGh0bWxgXG4gICAgICAgICAgICAgIDx0cj5cbiAgICAgICAgICAgICAgICAke09iamVjdC52YWx1ZXMoaXRlbSkubWFwKCh2YWwpID0-IHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBodG1sYDx0ZD4ke3ZhbH08L3RkPmA7XG4gICAgICAgICAgICAgICAgfSl9XG4gICAgICAgICAgICAgIDwvdHI-XG4gICAgICAgICAgICBgO1xuICAgICAgICAgIH0pfVxuICAgICAgICA8L3Rib2R5PlxuICAgICAgPC90YWJsZT5cbiAgICBgO1xuICB9XG5cbiAgYXN5bmMgZmlyc3RVcGRhdGVkKCkge1xuICAgIGF3YWl0IHRoaXMuZmV0Y2hEYXRhKCk7XG4gIH1cblxuICBhc3luYyBmZXRjaERhdGEoKSB7XG4gICAgbGV0IF9kYXRhOiBhbnk7XG4gICAgaWYgKHRoaXMuc3JjLmxlbmd0aCA-IDApIHtcbiAgICAgIF9kYXRhID0gYXdhaXQgZmV0Y2godGhpcy5zcmMpLnRoZW4oKHJlcykgPT4gcmVzLmpzb24oKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGVsZW0gPSB0aGlzLnBhcmVudEVsZW1lbnQ_LnF1ZXJ5U2VsZWN0b3IoXG4gICAgICAgICdzY3JpcHRbdHlwZT1cImFwcGxpY2F0aW9uL2pzb25cIl0nXG4gICAgICApIGFzIEhUTUxTY3JpcHRFbGVtZW50O1xuICAgICAgaWYgKGVsZW0pIF9kYXRhID0gSlNPTi5wYXJzZShlbGVtLmlubmVySFRNTCk7XG4gICAgfVxuICAgIF9kYXRhID8_PSBbXTtcbiAgICB0aGlzLmRhdGEgPSB0aGlzLnRyYW5zZm9ybShfZGF0YSk7XG4gICAgdGhpcy5yZXF1ZXN0VXBkYXRlKCk7XG4gIH1cblxuICB0cmFuc2Zvcm0oZGF0YTogYW55KSB7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cbn1cbiJ9LHsibmFtZSI6ImluZGV4Lmh0bWwiLCJjb250ZW50IjoiPCFET0NUWVBFIGh0bWw-XG48aHRtbCBsYW5nPVwiZW5cIj5cblxuPGhlYWQ-XG4gIDxtZXRhIGNoYXJzZXQ9XCJVVEYtOFwiIC8-XG4gIDxsaW5rIHJlbD1cImljb25cIiB0eXBlPVwiaW1hZ2Uvc3ZnK3htbFwiIGhyZWY9XCIvc3JjL2Zhdmljb24uc3ZnXCIgLz5cbiAgPG1ldGEgbmFtZT1cInZpZXdwb3J0XCIgY29udGVudD1cIndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjBcIiAvPlxuICA8dGl0bGU-SlNPTiB0byBMaXQgSFRNTCBUYWJsZTwvdGl0bGU-XG4gIDxzY3JpcHQgdHlwZT1cIm1vZHVsZVwiIHNyYz1cIi4vbGl0LWh0bWwtdGFibGUuanNcIj48L3NjcmlwdD5cbjwvaGVhZD5cblxuPGJvZHk-XG4gIDxsaXQtaHRtbC10YWJsZSBzcmM9XCJodHRwczovL2pzb25wbGFjZWhvbGRlci50eXBpY29kZS5jb20vcG9zdHNcIj5cbiAgICA8IS0tIDxzcGFuIHNsb3Q9XCJ0aXRsZVwiIHN0eWxlPVwiY29sb3I6IHJlZDtcIj5UaXRsZTwvc3Bhbj4gLS0-XG4gICAgPCEtLSA8c2NyaXB0IHR5cGU9XCJhcHBsaWNhdGlvbi9qc29uXCI-XG4gICAgICBbXG4gICAgICAgIHtcbiAgICAgICAgICBcImlkXCI6IFwiMFwiLFxuICAgICAgICAgIFwibmFtZVwiOiBcIkZpcnN0IEl0ZW1cIlxuICAgICAgICB9XG4gICAgICBdXG4gICAgPC9zY3JpcHQ-IC0tPlxuICA8L2xpdC1odG1sLXRhYmxlPlxuXG48L2JvZHk-XG5cbjwvaHRtbD4ifV0). diff --git a/lit-html-table/doc/editor.png b/lit-html-table/doc/editor.png deleted file mode 100644 index 8f8e5a5..0000000 Binary files a/lit-html-table/doc/editor.png and /dev/null differ diff --git a/lit-html-table/doc/finished.png b/lit-html-table/doc/finished.png deleted file mode 100644 index 8516026..0000000 Binary files a/lit-html-table/doc/finished.png and /dev/null differ diff --git a/lit-html-table/index.html b/lit-html-table/index.html deleted file mode 100644 index 2846e5b..0000000 --- a/lit-html-table/index.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - JSON to Lit HTML Table - - - - - - - - - - - - \ No newline at end of file diff --git a/lit-html-table/src/favicon.svg b/lit-html-table/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-html-table/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-html-table/src/lit-html-table.ts b/lit-html-table/src/lit-html-table.ts deleted file mode 100644 index 5836760..0000000 --- a/lit-html-table/src/lit-html-table.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { html, css, LitElement } from "lit"; -import { customElement, property } from "lit/decorators.js"; - -type ObjectData = { [key: string]: any }; - -@customElement("lit-html-table") -export class LitHtmlTable extends LitElement { - @property() src = ""; - @property({ type: Boolean }) editable = false; - - values?: ObjectData[]; - - static styles = css` - tr { - text-align: var(--table-tr-text-align, left); - vertical-align: var(--table-tr-vertical-align, top); - padding: var(--table-tr-padding, 10px); - } - td > input { - border: none; - } - `; - - render() { - // Check if data is loaded - if (!this.values) { - return html`Loading...`; - } - // Check if items are not empty - if (this.values.length === 0) { - return html`No Items Found!`; - } - // Convert JSON to HTML Table - return html` - - - - ${Object.keys(this.values[0]).map((key) => { - const name = key.replace(/\b([a-z])/g, (_, val) => - val.toUpperCase() - ); - return html``; - })} - - - - ${this.values.map((item, index) => { - return html` - - ${Object.entries(item).map((row) => { - return html``; - })} - - `; - })} - -
- ${name} -
- ${this.editable - ? html` { - const value = e.target.value; - const key = row[0]; - const current = this.values![index]; - current[key] = value; - this.values![index] = current; - this.requestUpdate(); - this.dispatchEvent( - new CustomEvent("input-cell", { - detail: { - index: index, - data: current, - }, - }) - ); - }} - />` - : html`${row[1]}`} -
- `; - } - - async firstUpdated() { - await this.fetchData(); - } - - async fetchData() { - let _data: any; - if (this.src.length > 0) { - _data = await fetch(this.src).then((res) => res.json()); - } else { - const elem = this.parentElement?.querySelector( - 'script[type="application/json"]' - ) as HTMLScriptElement; - if (elem) _data = JSON.parse(elem.innerHTML); - } - _data ??= []; - this.values = this.transform(_data); - this.requestUpdate(); - } - - transform(data: any) { - return data; - } -} diff --git a/lit-html-table/src/vite-env.d.ts b/lit-html-table/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-html-table/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-html-table/tsconfig.json b/lit-html-table/tsconfig.json deleted file mode 100644 index d17e916..0000000 --- a/lit-html-table/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/lit-modules/.gitignore b/lit-modules/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-modules/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-modules/.vscode/typescript.code-snippets b/lit-modules/.vscode/typescript.code-snippets deleted file mode 100644 index a00ccf7..0000000 --- a/lit-modules/.vscode/typescript.code-snippets +++ /dev/null @@ -1,72 +0,0 @@ -{ - "Create Example Lit Module": { - "prefix": "lit-module-example", - "body": [ - "import { html, css, LitElement } from \"lit\";", - "import { customElement, property } from \"lit/decorators.js\";", - "", - "export const $1ModuleStyles = [css`", - " .welcome {", - " font-size: 2em;", - " text-align: center;", - " }", - "`;]", - "", - "export interface ${1/(.*)/${1:/capitalize}/}ModuleProps {", - " name: string;", - " $2", - "}", - "", - "export function $1ModuleTemplate(props: ${1/(.*)/${1:/capitalize}/}ModuleProps) {", - " return html`
Hello ${props.name}!
`;", - "}", - "", - "@customElement(\"$1-module\")", - "export class ${1/(.*)/${1:/capitalize}/}Module extends LitElement implements ${1/(.*)/${1:/capitalize}/}ModuleProps {", - " static styles = $1ModuleStyles;", - "", - " @property({ type: String }) name = \"World\";", - "", - " render() {", - " return $1ModuleTemplate(this);", - " }", - "}", - "", - ], - "description": "Create an example of a reusable lit module" - }, - "Create Lit Module": { - "prefix": "lit-module", - "body": [ - "import { html, css, LitElement } from \"lit\";", - "import { customElement, property } from \"lit/decorators.js\";", - "", - "export const $1ModuleStyles = [css`", - " ${2:main} {", - " $5", - " }", - "`;]", - "", - "export interface ${1/(.*)/${1:/capitalize}/}ModuleProps {", - " $3", - "}", - "", - "export function $1ModuleTemplate(props: ${1/(.*)/${1:/capitalize}/}ModuleProps) {", - " return html`<${2:main}>$6`;", - "}", - "", - "@customElement(\"$1-module\")", - "export class ${1/(.*)/${1:/capitalize}/}Module extends LitElement implements ${1/(.*)/${1:/capitalize}/}ModuleProps {", - " static styles = $1ModuleStyles;", - "", - " $4", - "", - " render() {", - " return $1ModuleTemplate(this);", - " }", - "}", - "", - ], - "description": "Create a reuseable lit module" - } -} diff --git a/lit-modules/README.md b/lit-modules/README.md deleted file mode 100644 index ea99ccc..0000000 --- a/lit-modules/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Lit Modules - -Experimenting with Lit Modules using reactive controllers, typed props and template sharing for easier data binding. - -There is also a VSCode snippet I created in the repo that will trigger with `lit-module` and `lit-module-example`. - -Depending on how you import the module you can use it as a web component, raw html template or css result. diff --git a/lit-modules/index.html b/lit-modules/index.html deleted file mode 100644 index 65d13e8..0000000 --- a/lit-modules/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - Lit Modules - - - - - - - diff --git a/lit-modules/src/favicon.svg b/lit-modules/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-modules/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-modules/src/vite-env.d.ts b/lit-modules/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-modules/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-modules/styles.css b/lit-modules/styles.css deleted file mode 100644 index ea1e941..0000000 --- a/lit-modules/styles.css +++ /dev/null @@ -1,4 +0,0 @@ -body { - margin: 0; - padding: 0; -} diff --git a/lit-modules/tsconfig.json b/lit-modules/tsconfig.json deleted file mode 100644 index 8957a2f..0000000 --- a/lit-modules/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/lit-native/src/native.test.ts b/lit-native/src/native.test.ts new file mode 100644 index 0000000..8a50cb0 --- /dev/null +++ b/lit-native/src/native.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./my-element"; + +describe("Lit Native Custom Element", () => { + test("registers my-element custom element successfully", () => { + expect(customElements.get("my-element")).toBeDefined(); + }); + + test("mounts my-element container successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("my-element"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/lit-native/tsconfig.json b/lit-native/tsconfig.json deleted file mode 100644 index d17e916..0000000 --- a/lit-native/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/lit-node-editor/.gitignore b/lit-node-editor/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-node-editor/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-node-editor/README.md b/lit-node-editor/README.md deleted file mode 100644 index d9df472..0000000 --- a/lit-node-editor/README.md +++ /dev/null @@ -1,7 +0,0 @@ -[![Demo](https://github.com/rodydavis/lit-node-editor/actions/workflows/ci.yml/badge.svg)](https://github.com/rodydavis/lit-node-editor/actions/workflows/ci.yml) - -# Node Editor - -Node editor built with canvas api, simple graph data structure and included transforms for scale, pan and move. - -You can try the demo [here](https://rodydavis.github.io/lit-node-editor/)! diff --git a/lit-node-editor/index.html b/lit-node-editor/index.html deleted file mode 100644 index c508f3d..0000000 --- a/lit-node-editor/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Node Editor - - - - - - diff --git a/lit-node-editor/src/favicon.svg b/lit-node-editor/src/favicon.svg deleted file mode 100644 index 2c3a23d..0000000 --- a/lit-node-editor/src/favicon.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lit-node-editor/src/vite-env.d.ts b/lit-node-editor/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-node-editor/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-node-editor/tsconfig.json b/lit-node-editor/tsconfig.json deleted file mode 100644 index 8c4af55..0000000 --- a/lit-node-editor/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "target": "ES2017", - "lib": [ - "es2017", - "dom", - "dom.iterable" - ], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [] -} \ No newline at end of file diff --git a/lit-sheet-music/.gitignore b/lit-sheet-music/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/lit-sheet-music/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/lit-sheet-music/.vscode/settings.json b/lit-sheet-music/.vscode/settings.json deleted file mode 100644 index 8ad09b6..0000000 --- a/lit-sheet-music/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "cSpell.words": [ - "IOSMD", - "autobeam", - "opensheetmusicdisplay" - ] -} \ No newline at end of file diff --git a/lit-sheet-music/README.md b/lit-sheet-music/README.md deleted file mode 100644 index a769ab1..0000000 --- a/lit-sheet-music/README.md +++ /dev/null @@ -1,11 +0,0 @@ -[![Demo](https://github.com/rodydavis/lit-sheet-music/actions/workflows/ci.yml/badge.svg)](https://github.com/rodydavis/lit-sheet-music/actions/workflows/ci.yml) - -# Lit Sheet Music - -Render sheet music using [opensheetmusicdisplay](https://github.com/opensheetmusicdisplay/opensheetmusicdisplay) built with [Lit](https://lit.dev). - -You can try the demo [here](https://rodydavis.github.io/lit-sheet-music/)! - -You can read more about how to write music xml [here](https://www.musicxml.com/). - -![](/screenshot.png) diff --git a/lit-sheet-music/index.html b/lit-sheet-music/index.html deleted file mode 100644 index e8984bf..0000000 --- a/lit-sheet-music/index.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - Lit Sheet Music - - - - - - - - - - - \ No newline at end of file diff --git a/lit-sheet-music/screenshot.png b/lit-sheet-music/screenshot.png deleted file mode 100644 index 0b79988..0000000 Binary files a/lit-sheet-music/screenshot.png and /dev/null differ diff --git a/lit-sheet-music/src/favicon.svg b/lit-sheet-music/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-sheet-music/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-sheet-music/src/vite-env.d.ts b/lit-sheet-music/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-sheet-music/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-sheet-music/tsconfig.json b/lit-sheet-music/tsconfig.json deleted file mode 100644 index d17e916..0000000 --- a/lit-sheet-music/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/lit-showcase/index.html b/lit-showcase/index.html new file mode 100644 index 0000000..1589be2 --- /dev/null +++ b/lit-showcase/index.html @@ -0,0 +1,1022 @@ + + + + + + Lit Web Components Showcase + + + + + + + + +
+ + +
+ + +
+
+ +

Lit Showcase Hub

+

Explore a rich collection of modular Lit Web Components, prototypes, interactive instruments, databases, and custom UI modules. Select any example from the sidebar to preview natively or in a sandbox.

+
+
+
20
+
Projects
+
+
+
Natively
+
Rendered
+
+
+
Vitest
+
Colocated
+
+
+
+
+ + +
+
+
+ + Project Name +
+
+ + + + 🌐 Open Direct +
+
+ + +
+ +
+ + +
+ +
+
+
+ +
+ + + + diff --git a/lit-starter-ts/.gitignore b/lit-starter-ts/.gitignore deleted file mode 100644 index 36a66c6..0000000 --- a/lit-starter-ts/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? -types \ No newline at end of file diff --git a/lit-starter-ts/.vscode/extensions.json b/lit-starter-ts/.vscode/extensions.json deleted file mode 100644 index d1f5a50..0000000 --- a/lit-starter-ts/.vscode/extensions.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. - // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - // List of extensions which should be recommended for users of this workspace. - "recommendations": [ - "runem.lit-plugin" - ], - // List of extensions recommended by VS Code that should not be recommended for users of this workspace. - "unwantedRecommendations": [] -} \ No newline at end of file diff --git a/lit-starter-ts/README.md b/lit-starter-ts/README.md deleted file mode 100644 index a8589f4..0000000 --- a/lit-starter-ts/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Lit Starter TypeScript - -[![Demo](https://github.com/rodydavis/lit-starter-ts/actions/workflows/demo.yml/badge.svg)](https://github.com/rodydavis/lit-starter-ts/actions/workflows/demo.yml) -[![Tests](https://github.com/rodydavis/lit-starter-ts/actions/workflows/tests.yml/badge.svg)](https://github.com/rodydavis/lit-starter-ts/actions/workflows/tests.yml) - -## Features - -- Live Demo: https://rodydavis.github.io/lit-starter-ts/ -- Tests with [vitest](https://vitest.dev/) -- Bundler with [vite](https://vitejs.dev/) diff --git a/lit-starter-ts/index.html b/lit-starter-ts/index.html deleted file mode 100644 index 5362e1e..0000000 --- a/lit-starter-ts/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + Lit App - - - - - - diff --git a/lit-starter-ts/src/favicon.svg b/lit-starter-ts/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-starter-ts/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-starter-ts/src/vite-env.d.ts b/lit-starter-ts/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-starter-ts/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-starter-ts/test/my-element.test.ts b/lit-starter-ts/test/my-element.test.ts deleted file mode 100644 index 2dc381a..0000000 --- a/lit-starter-ts/test/my-element.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { IWindow } from "happy-dom"; -import { beforeEach, describe, expect, it, vi } from "vitest"; - -import "../src/my-element"; - -declare global { - interface Window extends IWindow {} -} - -describe("Button with increment", async () => { - beforeEach(async () => { - document.body.innerHTML = ''; - await window.happyDOM.whenAsyncComplete(); - await new Promise((resolve) => setTimeout(resolve, 0)); - }); - - function getInsideButton(): HTMLElement | null | undefined { - return document.body - .querySelector("my-element") - ?.shadowRoot?.querySelector("button"); - } - - it("should increment the count on each click", () => { - getInsideButton()?.click(); - expect(getInsideButton()?.innerText).toContain("1"); - }); - - it("should show name props", () => { - getInsideButton(); - expect( - document.body.querySelector("my-element")?.shadowRoot?.innerHTML - ).toContain("World"); - }); - - it("should dispatch count event on button click", () => { - const spyClick = vi.fn(); - - document.querySelector("my-element")!.addEventListener("count", spyClick); - - getInsideButton()?.click(); - - expect(spyClick).toHaveBeenCalled(); - }); -}); diff --git a/lit-starter-ts/tsconfig.json b/lit-starter-ts/tsconfig.json deleted file mode 100644 index b910c8e..0000000 --- a/lit-starter-ts/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": [ - "es2017", - "dom", - "dom.iterable" - ], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "isolatedModules": true, - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false, - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts", - "test/*.test.ts" - ], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] -} \ No newline at end of file diff --git a/lit-starter-ts/tsconfig.node.json b/lit-starter-ts/tsconfig.node.json deleted file mode 100644 index e993792..0000000 --- a/lit-starter-ts/tsconfig.node.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "esnext", - "moduleResolution": "node" - }, - "include": ["vite.config.ts"] -} diff --git a/lit-vscode-extension/.gitignore b/lit-vscode-extension/.gitignore deleted file mode 100644 index a619799..0000000 --- a/lit-vscode-extension/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local -build \ No newline at end of file diff --git a/lit-vscode-extension/.vscode/extensions.json b/lit-vscode-extension/.vscode/extensions.json deleted file mode 100644 index af51550..0000000 --- a/lit-vscode-extension/.vscode/extensions.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. - // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - - // List of extensions which should be recommended for users of this workspace. - "recommendations": [ - "dbaeumer.vscode-eslint" - ] -} \ No newline at end of file diff --git a/lit-vscode-extension/.vscode/launch.json b/lit-vscode-extension/.vscode/launch.json deleted file mode 100644 index 147a886..0000000 --- a/lit-vscode-extension/.vscode/launch.json +++ /dev/null @@ -1,18 +0,0 @@ -// A launch configuration that compiles the extension and then opens it inside a new window -// Use IntelliSense to learn about possible attributes. -// Hover to view descriptions of existing attributes. -// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Run Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}"], - "outFiles": ["${workspaceFolder}/build/**/*.js"], - "preLaunchTask": "npm: compile" - } - ] -} diff --git a/lit-vscode-extension/.vscode/settings.json b/lit-vscode-extension/.vscode/settings.json deleted file mode 100644 index e3ebdaf..0000000 --- a/lit-vscode-extension/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "editor.insertSpaces": false, - "cSpell.words": [ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - ] -} \ No newline at end of file diff --git a/lit-vscode-extension/README.md b/lit-vscode-extension/README.md deleted file mode 100644 index 0105e28..0000000 --- a/lit-vscode-extension/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Lit VSCode Extension Example - -Example of how to use a [Lit](https://lit.dev) web component and render it in a [VSCode extension](https://code.visualstudio.com/api/extension-guides/webview) with 2 way communication. - -![](/screenshot.png) - -## Getting Started - -- Open this example in VS Code 1.49+ -- `npm install` -- `npm run compile` -- `F5` to start debugging diff --git a/lit-vscode-extension/index.html b/lit-vscode-extension/index.html deleted file mode 100644 index b0a8d49..0000000 --- a/lit-vscode-extension/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - Lit Example - - - - -

This is child content

-
- - diff --git a/lit-vscode-extension/screenshot.png b/lit-vscode-extension/screenshot.png deleted file mode 100644 index bd55445..0000000 Binary files a/lit-vscode-extension/screenshot.png and /dev/null differ diff --git a/lit-vscode-extension/src/favicon.svg b/lit-vscode-extension/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/lit-vscode-extension/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/lit-vscode-extension/src/vite-env.d.ts b/lit-vscode-extension/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/lit-vscode-extension/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/lit-vscode-extension/tsconfig.json b/lit-vscode-extension/tsconfig.json deleted file mode 100644 index 5248563..0000000 --- a/lit-vscode-extension/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "lib": [ - "ESNext", - "DOM" - ], - "moduleResolution": "Node", - "strict": true, - "sourceMap": true, - "resolveJsonModule": true, - "experimentalDecorators": true, - "esModuleInterop": true, - "noEmit": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "outDir": "dist" - }, - "include": [ - "./src" - ], - "exclude": [ - "node_modules", - ".vscode-test" - ] -} \ No newline at end of file diff --git a/lit-wmr/.gitignore b/lit-wmr/.gitignore deleted file mode 100644 index bff902b..0000000 --- a/lit-wmr/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.cache -node_modules -dist -stats.html diff --git a/lit-wmr/README.md b/lit-wmr/README.md deleted file mode 100644 index 9776f65..0000000 --- a/lit-wmr/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Lit + WMR - -Minimal example of [Lit](https://lit.dev/) and [WMR](https://wmr.dev/). - -## Known Issues - -- Typescript decorators not working: [#892](https://github.com/preactjs/wmr/issues/892) \ No newline at end of file diff --git a/lit-wmr/tsconfig.json b/lit-wmr/tsconfig.json deleted file mode 100644 index 5f7984a..0000000 --- a/lit-wmr/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "jsx": "preserve", - "jsxFactory": "preact.h", - "jsxFragmentFactory": "preact.Fragment", - "allowJs": true, - "checkJs": true, - // "strict": true, - "noEmit": true, - "moduleResolution": "node", - "target": "ESNext", - "module": "esnext", - "resolveJsonModule": true, - "allowSyntheticDefaultImports": true, - "downlevelIteration": true, - "experimentalDecorators": true - }, - "include": ["node_modules/wmr/types.d.ts", "**/*"], - "typeAcquisition": { - "enable": true - } -} diff --git a/lit-wmr/wmr.config.mjs b/lit-wmr/wmr.config.mjs deleted file mode 100644 index 7b00402..0000000 --- a/lit-wmr/wmr.config.mjs +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'wmr'; - -// Full list of options: https://wmr.dev/docs/configuration -export default defineConfig({ - /* Your configuration here */ -}); diff --git a/package.json b/package.json index fd22b34..01ddfa0 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "test": "vitest run" }, "dependencies": { "@ar-js-org/ar.js": "^3.4.0-alpha-rc2", diff --git a/restore_tests.js b/restore_tests.js new file mode 100644 index 0000000..e5f32ad --- /dev/null +++ b/restore_tests.js @@ -0,0 +1,44 @@ +import fs from 'fs'; +import { dirname, resolve } from 'path'; + +const logPath = '/Users/rodydavis/.gemini/antigravity/brain/20700412-712a-4368-aa77-83fa63f6db89/.system_generated/logs/overview.txt'; +if (!fs.existsSync(logPath)) { + console.error("Log file not found:", logPath); + process.exit(1); +} + +const content = fs.readFileSync(logPath, 'utf8'); +const lines = content.split('\n'); + +// Track the latest code content for each target file +const filesMap = new Map(); + +for (const line of lines) { + if (!line.trim()) continue; + try { + const data = JSON.parse(line); + if (!data.tool_calls) continue; + for (const call of data.tool_calls) { + if (call.name === 'write_to_file') { + const { TargetFile, CodeContent } = call.args; + if (TargetFile && TargetFile.includes('tests/')) { + const absolutePath = resolve(TargetFile); + filesMap.set(absolutePath, CodeContent); + } + } + } + } catch (e) { + // Ignore parsing errors + } +} + +let restoredCount = 0; +for (const [absolutePath, codeContent] of filesMap.entries()) { + const dir = dirname(absolutePath); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(absolutePath, codeContent, 'utf8'); + console.log(`Restored: ${absolutePath}`); + restoredCount++; +} + +console.log(`Successfully restored ${restoredCount} test support files.`); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7c96ea9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "node", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "useDefineForClassFields": false, + "strict": false, + "skipLibCheck": true, + "esModuleInterop": true + }, + "include": ["**/*.ts"] +} diff --git a/vite-lit-capacitor/electron/tsconfig.json b/vite-lit-capacitor/electron/tsconfig.json deleted file mode 100644 index 07371cf..0000000 --- a/vite-lit-capacitor/electron/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compileOnSave": true, - "include": ["./src/**/*", "./capacitor.config.ts", "./capacitor.config.js"], - "compilerOptions": { - "outDir": "./build", - "importHelpers": true, - "target": "ES2017", - "module": "CommonJS", - "moduleResolution": "node", - "esModuleInterop": true, - "typeRoots": ["./node_modules/@types"], - "allowJs": true, - "rootDir": "." - } -} diff --git a/vite-lit-capacitor/src/capacitor.test.ts b/vite-lit-capacitor/src/capacitor.test.ts new file mode 100644 index 0000000..2ad5b3c --- /dev/null +++ b/vite-lit-capacitor/src/capacitor.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./my-element"; + +describe("Capacitor Hybrid Element", () => { + test("registers my-element custom element successfully", () => { + expect(customElements.get("my-element")).toBeDefined(); + }); + + test("mounts capacitor custom element successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("my-element"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/vite-lit-capacitor/tsconfig.json b/vite-lit-capacitor/tsconfig.json deleted file mode 100644 index 0162200..0000000 --- a/vite-lit-capacitor/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": [ - "es2017", - "dom", - "dom.iterable" - ], - "declaration": true, - "outDir": "./web/js", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "useDefineForClassFields": false - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [] -} \ No newline at end of file diff --git a/vite-lit-element-starter/src/starter.test.ts b/vite-lit-element-starter/src/starter.test.ts new file mode 100644 index 0000000..e62da63 --- /dev/null +++ b/vite-lit-element-starter/src/starter.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from "vitest"; +import "./my-element"; + +describe("Vite Lit Element Starter", () => { + test("registers my-element custom element successfully", () => { + expect(customElements.get("my-element")).toBeDefined(); + }); + + test("mounts starter element successfully", async () => { + document.body.innerHTML = ""; + await window.happyDOM.whenAsyncComplete(); + + const element = document.body.querySelector("my-element"); + expect(element).toBeDefined(); + expect(element?.shadowRoot).toBeDefined(); + }); +}); diff --git a/vite-lit-element-starter/tsconfig.json b/vite-lit-element-starter/tsconfig.json deleted file mode 100644 index ce99226..0000000 --- a/vite-lit-element-starter/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": ["es2017", "dom", "dom.iterable"], - "types": ["vite/client"], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*.ts"], - "exclude": [] -} diff --git a/vite-rxdb-lit/.gitignore b/vite-rxdb-lit/.gitignore deleted file mode 100644 index 759ef53..0000000 --- a/vite-rxdb-lit/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_Store -dist -types -*.local diff --git a/vite-rxdb-lit/.vscode/settings.json b/vite-rxdb-lit/.vscode/settings.json deleted file mode 100644 index 6c7c62d..0000000 --- a/vite-rxdb-lit/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "cSpell.words": [ - "rxdb", - "todos" - ] -} \ No newline at end of file diff --git a/vite-rxdb-lit/README.md b/vite-rxdb-lit/README.md deleted file mode 100644 index 75dd6ae..0000000 --- a/vite-rxdb-lit/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Vite + RxDB + Lit - -Minimal example to get RxDB running with vite. - -Online demo [here](https://rodydavis.github.io/vite-rxdb-lit/). - -## Supports - -- Lit -- Vite -- Typescript -- MWC -- RxDB -- RxJS - -## Getting Started - -1. `npm i` - -2. Development: `npm run dev` - -3. Production: `npm run build` \ No newline at end of file diff --git a/vite-rxdb-lit/index.html b/vite-rxdb-lit/index.html deleted file mode 100644 index fe9795f..0000000 --- a/vite-rxdb-lit/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - Vite + RxDb + Lit - - - - - - - diff --git a/vite-rxdb-lit/src/favicon.svg b/vite-rxdb-lit/src/favicon.svg deleted file mode 100644 index de4aedd..0000000 --- a/vite-rxdb-lit/src/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/vite-rxdb-lit/src/vite-env.d.ts b/vite-rxdb-lit/src/vite-env.d.ts deleted file mode 100644 index 11f02fe..0000000 --- a/vite-rxdb-lit/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/vite-rxdb-lit/style.css b/vite-rxdb-lit/style.css deleted file mode 100644 index e1d5b3c..0000000 --- a/vite-rxdb-lit/style.css +++ /dev/null @@ -1,12 +0,0 @@ -@import url(https://fonts.googleapis.com/css?family=Material+Icons&display=block); - -html, -body { - padding: 0; - margin: 0; -} - -:root { - --mdc-theme-primary: rgb(0, 0, 0); - --mdc-theme-on-primary: rgb(255, 255, 255); -} diff --git a/vite-rxdb-lit/tsconfig.json b/vite-rxdb-lit/tsconfig.json deleted file mode 100644 index 4b0048e..0000000 --- a/vite-rxdb-lit/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "module": "esnext", - "lib": [ - "es2017", - "dom", - "dom.iterable" - ], - "declaration": true, - "emitDeclarationOnly": true, - "outDir": "./types", - "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [] -} \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index d953de8..9fd3b16 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,12 +7,13 @@ const require = createRequire(import.meta.url); function getHtmlEntries() { const entries = { - main: resolve(__dirname, 'index.html') + root: resolve(__dirname, 'index.html'), + main: resolve(__dirname, 'lit-showcase/index.html') }; const rootDirs = fs.readdirSync(__dirname); for (const dir of rootDirs) { - if (['.git', '.github', 'node_modules', 'dist'].includes(dir)) continue; + if (['.git', '.github', 'node_modules', 'dist', 'lit-components', 'lit-showcase', 'tests'].includes(dir)) continue; const fullPath = resolve(__dirname, dir); if (!fs.statSync(fullPath).isDirectory()) continue; @@ -162,6 +163,52 @@ export default defineConfig({ 'lit-element/decorators': 'lit-element/decorators.js' } }, + esbuild: { + // Globally enforce useDefineForClassFields: false to prevent class property shadowing + // in all TS files across both dev server, Vitest, and production builds. + tsconfigRaw: { + compilerOptions: { + useDefineForClassFields: false + } + } + }, + optimizeDeps: { + // Explicitly pre-bundle Lit core, decorators, directives and MWC components together + // to prevent duplicate framework instances and update queue mismatches in Dev server. + include: [ + 'lit', + 'lit/decorators.js', + 'lit/directives/ref.js', + 'lit-element', + '@material/mwc-button', + '@material/mwc-dialog', + '@material/mwc-drawer', + '@material/mwc-icon', + '@material/mwc-icon-button', + '@material/mwc-list', + '@material/mwc-textfield', + '@material/mwc-top-app-bar-fixed' + ] + }, + test: { + environment: 'happy-dom', + globals: true, + setupFiles: [resolve(__dirname, 'lit-components/test-support/setup.ts')], + include: ['**/*.test.ts', '**/*.spec.ts'], + // Use full process forks pool instead of threads to prevent V8 out-of-memory overhead during tests + pool: 'forks', + isolate: true, + alias: [ + { find: 'monaco-editor/min/vs/editor/editor.main.css', replacement: resolve(__dirname, 'lit-components/test-support/mocks/styles.ts') }, + { find: /^monaco-editor\/esm\/vs\/.*/, replacement: resolve(__dirname, 'lit-components/test-support/mocks/monaco.ts') }, + { find: 'monaco-editor', replacement: resolve(__dirname, 'lit-components/test-support/mocks/monaco.ts') }, + { find: 'three/examples/jsm/controls/OrbitControls', replacement: resolve(__dirname, 'lit-components/test-support/mocks/orbitcontrols.ts') }, + { find: 'three', replacement: resolve(__dirname, 'lit-components/test-support/mocks/three.ts') }, + { find: 'tone', replacement: resolve(__dirname, 'lit-components/test-support/mocks/tone.ts') }, + { find: 'opensheetmusicdisplay', replacement: resolve(__dirname, 'lit-components/test-support/mocks/opensheetmusicdisplay.ts') }, + { find: 'rxdb', replacement: resolve(__dirname, 'lit-components/test-support/mocks/rxdb.ts') } + ] + }, build: { outDir: 'dist', emptyOutDir: true,